diff options
Diffstat (limited to 'drivers')
728 files changed, 47636 insertions, 28092 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index dd1eea90f67f..9705fc986da9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -138,7 +138,6 @@ config ACPI_REV_OVERRIDE_POSSIBLE config ACPI_EC_DEBUGFS tristate "EC read/write access through /sys/kernel/debug/ec" - default n help Say N to disable Embedded Controller /sys/kernel/debug interface @@ -283,7 +282,6 @@ config ACPI_PROCESSOR config ACPI_IPMI tristate "IPMI" depends on IPMI_HANDLER - default n help This driver enables the ACPI to access the BMC controller. And it uses the IPMI request/response message to communicate with BMC @@ -361,7 +359,6 @@ config ACPI_TABLE_UPGRADE config ACPI_DEBUG bool "Debug Statements" - default n help The ACPI subsystem can produce debug output. Saying Y enables this output and increases the kernel size by around 50K. @@ -374,7 +371,6 @@ config ACPI_DEBUG config ACPI_PCI_SLOT bool "PCI slot detection driver" depends on SYSFS - default n help This driver creates entries in /sys/bus/pci/slots/ for all PCI slots in the system. This can help correlate PCI bus addresses, @@ -436,7 +432,6 @@ config ACPI_HED config ACPI_CUSTOM_METHOD tristate "Allow ACPI methods to be inserted/replaced at run time" depends on DEBUG_FS - default n help This debug facility allows ACPI AML methods to be inserted and/or replaced without rebooting the system. For details refer to: @@ -481,7 +476,6 @@ config ACPI_EXTLOG tristate "Extended Error Log support" depends on X86_MCE && X86_LOCAL_APIC && EDAC select UEFI_CPER - default n help Certain usages such as Predictive Failure Analysis (PFA) require more information about the error than what can be described in diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c index 1b64419e2fec..712fd31674a6 100644 --- a/drivers/acpi/acpi_ipmi.c +++ b/drivers/acpi/acpi_ipmi.c @@ -46,7 +46,7 @@ struct acpi_ipmi_device { spinlock_t tx_msg_lock; acpi_handle handle; struct device *dev; - ipmi_user_t user_interface; + struct ipmi_user *user_interface; int ipmi_ifnum; /* IPMI interface number */ long curr_msgid; bool dead; @@ -125,7 +125,7 @@ ipmi_dev_alloc(int iface, struct device *dev, acpi_handle handle) { struct acpi_ipmi_device *ipmi_device; int err; - ipmi_user_t user; + struct ipmi_user *user; ipmi_device = kzalloc(sizeof(*ipmi_device), GFP_KERNEL); if (!ipmi_device) diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c index cf4fc0161164..e43cb71b6972 100644 --- a/drivers/acpi/acpi_lpit.c +++ b/drivers/acpi/acpi_lpit.c @@ -117,11 +117,17 @@ static void lpit_update_residency(struct lpit_residency_info *info, if (!info->iomem_addr) return; + if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) + return; + /* Silently fail, if cpuidle attribute group is not present */ sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj, &dev_attr_low_power_idle_system_residency_us.attr, "cpuidle"); } else if (info->gaddr.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { + if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) + return; + /* Silently fail, if cpuidle attribute group is not present */ sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj, &dev_attr_low_power_idle_cpu_residency_us.attr, diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index bf64cfa30feb..b9bda06d344d 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/mutex.h> +#include <linux/pci.h> #include <linux/platform_device.h> #include <linux/platform_data/clk-lpss.h> #include <linux/platform_data/x86/pmc_atom.h> @@ -83,6 +84,7 @@ struct lpss_device_desc { size_t prv_size_override; struct property_entry *properties; void (*setup)(struct lpss_private_data *pdata); + bool resume_from_noirq; }; static const struct lpss_device_desc lpss_dma_desc = { @@ -99,6 +101,9 @@ struct lpss_private_data { u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; }; +/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */ +static u32 pmc_atom_d3_mask = 0xfe000ffe; + /* LPSS run time quirks */ static unsigned int lpss_quirks; @@ -175,6 +180,21 @@ static void byt_pwm_setup(struct lpss_private_data *pdata) static void byt_i2c_setup(struct lpss_private_data *pdata) { + const char *uid_str = acpi_device_uid(pdata->adev); + acpi_handle handle = pdata->adev->handle; + unsigned long long shared_host = 0; + acpi_status status; + long uid = 0; + + /* Expected to always be true, but better safe then sorry */ + if (uid_str) + uid = simple_strtol(uid_str, NULL, 10); + + /* Detect I2C bus shared with PUNIT and ignore its d3 status */ + status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); + if (ACPI_SUCCESS(status) && shared_host && uid) + pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1)); + lpss_deassert_reset(pdata); if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset)) @@ -274,12 +294,14 @@ static const struct lpss_device_desc byt_i2c_dev_desc = { .flags = LPSS_CLK | LPSS_SAVE_CTX, .prv_offset = 0x800, .setup = byt_i2c_setup, + .resume_from_noirq = true, }; static const struct lpss_device_desc bsw_i2c_dev_desc = { .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, .prv_offset = 0x800, .setup = byt_i2c_setup, + .resume_from_noirq = true, }; static const struct lpss_device_desc bsw_spi_dev_desc = { @@ -292,7 +314,7 @@ static const struct lpss_device_desc bsw_spi_dev_desc = { #define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } static const struct x86_cpu_id lpss_cpu_ids[] = { - ICPU(INTEL_FAM6_ATOM_SILVERMONT1), /* Valleyview, Bay Trail */ + ICPU(INTEL_FAM6_ATOM_SILVERMONT), /* Valleyview, Bay Trail */ ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */ {} }; @@ -327,9 +349,11 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { { "INT33FC", }, /* Braswell LPSS devices */ + { "80862286", LPSS_ADDR(lpss_dma_desc) }, { "80862288", LPSS_ADDR(bsw_pwm_dev_desc) }, { "8086228A", LPSS_ADDR(bsw_uart_dev_desc) }, { "8086228E", LPSS_ADDR(bsw_spi_dev_desc) }, + { "808622C0", LPSS_ADDR(lpss_dma_desc) }, { "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) }, /* Broadwell LPSS devices */ @@ -451,26 +475,35 @@ struct lpss_device_links { */ static const struct lpss_device_links lpss_device_links[] = { {"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME}, + {"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME}, + {"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME}, }; -static bool hid_uid_match(const char *hid1, const char *uid1, +static bool hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2) { - return !strcmp(hid1, hid2) && uid1 && uid2 && !strcmp(uid1, uid2); + const char *hid1 = acpi_device_hid(adev); + const char *uid1 = acpi_device_uid(adev); + + if (strcmp(hid1, hid2)) + return false; + + if (!uid2) + return true; + + return uid1 && !strcmp(uid1, uid2); } static bool acpi_lpss_is_supplier(struct acpi_device *adev, const struct lpss_device_links *link) { - return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev), - link->supplier_hid, link->supplier_uid); + return hid_uid_match(adev, link->supplier_hid, link->supplier_uid); } static bool acpi_lpss_is_consumer(struct acpi_device *adev, const struct lpss_device_links *link) { - return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev), - link->consumer_hid, link->consumer_uid); + return hid_uid_match(adev, link->consumer_hid, link->consumer_uid); } struct hid_uid { @@ -486,18 +519,23 @@ static int match_hid_uid(struct device *dev, void *data) if (!adev) return 0; - return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev), - id->hid, id->uid); + return hid_uid_match(adev, id->hid, id->uid); } static struct device *acpi_lpss_find_device(const char *hid, const char *uid) { + struct device *dev; + struct hid_uid data = { .hid = hid, .uid = uid, }; - return bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid); + dev = bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid); + if (dev) + return dev; + + return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid); } static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) @@ -892,7 +930,7 @@ static void lpss_iosf_enter_d3_state(void) * Here we read the values related to LPSS power island, i.e. LPSS * devices, excluding both LPSS DMA controllers, along with SCC domain. */ - u32 func_dis, d3_sts_0, pmc_status, pmc_mask = 0xfe000ffe; + u32 func_dis, d3_sts_0, pmc_status; int ret; ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis); @@ -910,7 +948,7 @@ static void lpss_iosf_enter_d3_state(void) * Shutdown both LPSS DMA controllers if and only if all other devices * are already in D3hot. */ - pmc_status = (~(d3_sts_0 | func_dis)) & pmc_mask; + pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask; if (pmc_status) goto exit; @@ -1004,7 +1042,7 @@ static int acpi_lpss_resume(struct device *dev) } #ifdef CONFIG_PM_SLEEP -static int acpi_lpss_suspend_late(struct device *dev) +static int acpi_lpss_do_suspend_late(struct device *dev) { int ret; @@ -1015,12 +1053,62 @@ static int acpi_lpss_suspend_late(struct device *dev) return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); } -static int acpi_lpss_resume_early(struct device *dev) +static int acpi_lpss_suspend_late(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + + if (pdata->dev_desc->resume_from_noirq) + return 0; + + return acpi_lpss_do_suspend_late(dev); +} + +static int acpi_lpss_suspend_noirq(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + + if (pdata->dev_desc->resume_from_noirq) { + ret = acpi_lpss_do_suspend_late(dev); + if (ret) + return ret; + } + + return acpi_subsys_suspend_noirq(dev); +} + +static int acpi_lpss_do_resume_early(struct device *dev) { int ret = acpi_lpss_resume(dev); return ret ? ret : pm_generic_resume_early(dev); } + +static int acpi_lpss_resume_early(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + + if (pdata->dev_desc->resume_from_noirq) + return 0; + + return acpi_lpss_do_resume_early(dev); +} + +static int acpi_lpss_resume_noirq(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + + ret = acpi_subsys_resume_noirq(dev); + if (ret) + return ret; + + if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq) + ret = acpi_lpss_do_resume_early(dev); + + return ret; +} + #endif /* CONFIG_PM_SLEEP */ static int acpi_lpss_runtime_suspend(struct device *dev) @@ -1050,8 +1138,8 @@ static struct dev_pm_domain acpi_lpss_pm_domain = { .complete = acpi_subsys_complete, .suspend = acpi_subsys_suspend, .suspend_late = acpi_lpss_suspend_late, - .suspend_noirq = acpi_subsys_suspend_noirq, - .resume_noirq = acpi_subsys_resume_noirq, + .suspend_noirq = acpi_lpss_suspend_noirq, + .resume_noirq = acpi_lpss_resume_noirq, .resume_early = acpi_lpss_resume_early, .freeze = acpi_subsys_freeze, .freeze_late = acpi_subsys_freeze_late, diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 552c1f725b6c..a47676a55b84 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -70,6 +70,7 @@ static void power_saving_mwait_init(void) #if defined(CONFIG_X86) switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_HYGON: case X86_VENDOR_AMD: case X86_VENDOR_INTEL: /* diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 449d86d39965..fc447410ae4d 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -643,7 +643,7 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle, status = acpi_get_type(handle, &acpi_type); if (ACPI_FAILURE(status)) - return false; + return status; switch (acpi_type) { case ACPI_TYPE_PROCESSOR: @@ -663,11 +663,12 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle, } processor_validated_ids_update(uid); - return true; + return AE_OK; err: + /* Exit on error, but don't abort the namespace walk */ acpi_handle_info(handle, "Invalid processor object\n"); - return false; + return AE_OK; } diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index e99c4ed7e677..33a4bcdaa4d7 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -52,6 +52,201 @@ struct acpi_tad_driver_data { u32 capabilities; }; +struct acpi_tad_rt { + u16 year; /* 1900 - 9999 */ + u8 month; /* 1 - 12 */ + u8 day; /* 1 - 31 */ + u8 hour; /* 0 - 23 */ + u8 minute; /* 0 - 59 */ + u8 second; /* 0 - 59 */ + u8 valid; /* 0 (failed) or 1 (success) for reads, 0 for writes */ + u16 msec; /* 1 - 1000 */ + s16 tz; /* -1440 to 1440 or 2047 (unspecified) */ + u8 daylight; + u8 padding[3]; /* must be 0 */ +} __packed; + +static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt) +{ + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object args[] = { + { .type = ACPI_TYPE_BUFFER, }, + }; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + unsigned long long retval; + acpi_status status; + + if (rt->year < 1900 || rt->year > 9999 || + rt->month < 1 || rt->month > 12 || + rt->hour > 23 || rt->minute > 59 || rt->second > 59 || + rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) || + rt->daylight > 3) + return -ERANGE; + + args[0].buffer.pointer = (u8 *)rt; + args[0].buffer.length = sizeof(*rt); + + pm_runtime_get_sync(dev); + + status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval); + + pm_runtime_put_sync(dev); + + if (ACPI_FAILURE(status) || retval) + return -EIO; + + return 0; +} + +static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt) +{ + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER }; + union acpi_object *out_obj; + struct acpi_tad_rt *data; + acpi_status status; + int ret = -EIO; + + pm_runtime_get_sync(dev); + + status = acpi_evaluate_object(handle, "_GRT", NULL, &output); + + pm_runtime_put_sync(dev); + + if (ACPI_FAILURE(status)) + goto out_free; + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) + goto out_free; + + if (out_obj->buffer.length != sizeof(*rt)) + goto out_free; + + data = (struct acpi_tad_rt *)(out_obj->buffer.pointer); + if (!data->valid) + goto out_free; + + memcpy(rt, data, sizeof(*rt)); + ret = 0; + +out_free: + ACPI_FREE(output.pointer); + return ret; +} + +static char *acpi_tad_rt_next_field(char *s, int *val) +{ + char *p; + + p = strchr(s, ':'); + if (!p) + return NULL; + + *p = '\0'; + if (kstrtoint(s, 10, val)) + return NULL; + + return p + 1; +} + +static ssize_t time_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_tad_rt rt; + char *str, *s; + int val, ret = -ENODATA; + + str = kmemdup_nul(buf, count, GFP_KERNEL); + if (!str) + return -ENOMEM; + + s = acpi_tad_rt_next_field(str, &val); + if (!s) + goto out_free; + + rt.year = val; + + s = acpi_tad_rt_next_field(s, &val); + if (!s) + goto out_free; + + rt.month = val; + + s = acpi_tad_rt_next_field(s, &val); + if (!s) + goto out_free; + + rt.day = val; + + s = acpi_tad_rt_next_field(s, &val); + if (!s) + goto out_free; + + rt.hour = val; + + s = acpi_tad_rt_next_field(s, &val); + if (!s) + goto out_free; + + rt.minute = val; + + s = acpi_tad_rt_next_field(s, &val); + if (!s) + goto out_free; + + rt.second = val; + + s = acpi_tad_rt_next_field(s, &val); + if (!s) + goto out_free; + + rt.tz = val; + + if (kstrtoint(s, 10, &val)) + goto out_free; + + rt.daylight = val; + + rt.valid = 0; + rt.msec = 0; + memset(rt.padding, 0, 3); + + ret = acpi_tad_set_real_time(dev, &rt); + +out_free: + kfree(str); + return ret ? ret : count; +} + +static ssize_t time_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct acpi_tad_rt rt; + int ret; + + ret = acpi_tad_get_real_time(dev, &rt); + if (ret) + return ret; + + return sprintf(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n", + rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second, + rt.tz, rt.daylight); +} + +static DEVICE_ATTR(time, S_IRUSR | S_IWUSR, time_show, time_store); + +static struct attribute *acpi_tad_time_attrs[] = { + &dev_attr_time.attr, + NULL, +}; +static const struct attribute_group acpi_tad_time_attr_group = { + .attrs = acpi_tad_time_attrs, +}; + static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id, u32 value) { @@ -448,6 +643,12 @@ static int acpi_tad_probe(struct platform_device *pdev) goto fail; } + if (caps & ACPI_TAD_RT) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group); + if (ret) + goto fail; + } + return 0; fail: diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 71f6f2624deb..b14621da5413 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -65,6 +65,7 @@ acpi-y += \ exresnte.o \ exresolv.o \ exresop.o \ + exserial.o \ exstore.o \ exstoren.o \ exstorob.o \ diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 704bebbd35b0..b412aa909907 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -229,6 +229,8 @@ acpi_ev_default_region_setup(acpi_handle handle, acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj); +u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); + /* * evsci - SCI (System Control Interrupt) handling/dispatch */ diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 9613b0115dad..c5b2be0b6613 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -124,6 +124,9 @@ acpi_ex_trace_point(acpi_trace_event_type type, * exfield - ACPI AML (p-code) execution - field manipulation */ acpi_status +acpi_ex_get_protocol_buffer_length(u32 protocol_id, u32 *return_length); + +acpi_status acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc, u32 buffer_length, u32 * datum_count); @@ -268,6 +271,26 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info); /* + * exserial - field_unit support for serial address spaces + */ +acpi_status +acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc, + union acpi_operand_object **return_buffer); + +acpi_status +acpi_ex_write_serial_bus(union acpi_operand_object *source_desc, + union acpi_operand_object *obj_desc, + union acpi_operand_object **return_buffer); + +acpi_status +acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer); + +acpi_status +acpi_ex_write_gpio(union acpi_operand_object *source_desc, + union acpi_operand_object *obj_desc, + union acpi_operand_object **return_buffer); + +/* * exsystem - Interface to OS services */ acpi_status diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 0f28a38a43ea..99b0da899109 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -395,9 +395,9 @@ struct acpi_simple_repair_info { /* Info for running the _REG methods */ struct acpi_reg_walk_info { - acpi_adr_space_type space_id; u32 function; u32 reg_run_count; + acpi_adr_space_type space_id; }; /***************************************************************************** diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 250dba02bab6..6c05355447c1 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -432,15 +432,15 @@ typedef enum { */ typedef enum { AML_FIELD_ATTRIB_QUICK = 0x02, - AML_FIELD_ATTRIB_SEND_RCV = 0x04, + AML_FIELD_ATTRIB_SEND_RECEIVE = 0x04, AML_FIELD_ATTRIB_BYTE = 0x06, AML_FIELD_ATTRIB_WORD = 0x08, AML_FIELD_ATTRIB_BLOCK = 0x0A, - AML_FIELD_ATTRIB_MULTIBYTE = 0x0B, - AML_FIELD_ATTRIB_WORD_CALL = 0x0C, - AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D, + AML_FIELD_ATTRIB_BYTES = 0x0B, + AML_FIELD_ATTRIB_PROCESS_CALL = 0x0C, + AML_FIELD_ATTRIB_BLOCK_PROCESS_CALL = 0x0D, AML_FIELD_ATTRIB_RAW_BYTES = 0x0E, - AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F + AML_FIELD_ATTRIB_RAW_PROCESS_BYTES = 0x0F } AML_ACCESS_ATTRIBUTE; /* Bit fields in the AML method_flags byte */ diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index e9fb0bf3c8d2..78f9de260d5f 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -417,6 +417,10 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, ACPI_FORMAT_UINT64(obj_desc->region.address), obj_desc->region.length)); + status = acpi_ut_add_address_range(obj_desc->region.space_id, + obj_desc->region.address, + obj_desc->region.length, node); + /* Now the address and length are valid for this opregion */ obj_desc->region.flags |= AOPOBJ_DATA_VALID; diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 70c2bd169f66..49decca4e08f 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -653,6 +653,19 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, ACPI_FUNCTION_TRACE(ev_execute_reg_methods); + /* + * These address spaces do not need a call to _REG, since the ACPI + * specification defines them as: "must always be accessible". Since + * they never change state (never become unavailable), no need to ever + * call _REG on them. Also, a data_table is not a "real" address space, + * so do not call _REG. September 2018. + */ + if ((space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) || + (space_id == ACPI_ADR_SPACE_SYSTEM_IO) || + (space_id == ACPI_ADR_SPACE_DATA_TABLE)) { + return_VOID; + } + info.space_id = space_id; info.function = function; info.reg_run_count = 0; @@ -714,8 +727,8 @@ acpi_ev_reg_run(acpi_handle obj_handle, } /* - * We only care about regions.and objects that are allowed to have address - * space handlers + * We only care about regions and objects that are allowed to have + * address space handlers */ if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { return (AE_OK); diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 39284deedd88..17df5dacd43c 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -16,9 +16,6 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evrgnini") -/* Local prototypes */ -static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); - /******************************************************************************* * * FUNCTION: acpi_ev_system_memory_region_setup @@ -33,7 +30,6 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); * DESCRIPTION: Setup a system_memory operation region * ******************************************************************************/ - acpi_status acpi_ev_system_memory_region_setup(acpi_handle handle, u32 function, @@ -313,7 +309,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, * ******************************************************************************/ -static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) +u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) { acpi_status status; struct acpi_pnp_device_id *hid; diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 091415b14fbf..3b3a25d9f0e6 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -193,7 +193,6 @@ acpi_remove_address_space_handler(acpi_handle device, */ region_obj = handler_obj->address_space.region_list; - } /* Remove this Handler object from the list */ diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index b272c329d45d..e5798f15793a 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /****************************************************************************** * - * Module Name: exfield - ACPI AML (p-code) execution - field manipulation + * Module Name: exfield - AML execution - field_unit read/write * * Copyright (C) 2000 - 2018, Intel Corp. * @@ -16,64 +16,62 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exfield") -/* Local prototypes */ -static u32 -acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length); +/* + * This table maps the various Attrib protocols to the byte transfer + * length. Used for the generic serial bus. + */ +#define ACPI_INVALID_PROTOCOL_ID 0x80 +#define ACPI_MAX_PROTOCOL_ID 0x0F +const u8 acpi_protocol_lengths[] = { + ACPI_INVALID_PROTOCOL_ID, /* 0 - reserved */ + ACPI_INVALID_PROTOCOL_ID, /* 1 - reserved */ + 0x00, /* 2 - ATTRIB_QUICK */ + ACPI_INVALID_PROTOCOL_ID, /* 3 - reserved */ + 0x01, /* 4 - ATTRIB_SEND_RECEIVE */ + ACPI_INVALID_PROTOCOL_ID, /* 5 - reserved */ + 0x01, /* 6 - ATTRIB_BYTE */ + ACPI_INVALID_PROTOCOL_ID, /* 7 - reserved */ + 0x02, /* 8 - ATTRIB_WORD */ + ACPI_INVALID_PROTOCOL_ID, /* 9 - reserved */ + 0xFF, /* A - ATTRIB_BLOCK */ + 0xFF, /* B - ATTRIB_BYTES */ + 0x02, /* C - ATTRIB_PROCESS_CALL */ + 0xFF, /* D - ATTRIB_BLOCK_PROCESS_CALL */ + 0xFF, /* E - ATTRIB_RAW_BYTES */ + 0xFF /* F - ATTRIB_RAW_PROCESS_BYTES */ +}; /******************************************************************************* * - * FUNCTION: acpi_ex_get_serial_access_length + * FUNCTION: acpi_ex_get_protocol_buffer_length * - * PARAMETERS: accessor_type - The type of the protocol indicated by region + * PARAMETERS: protocol_id - The type of the protocol indicated by region * field access attributes - * access_length - The access length of the region field + * return_length - Where the protocol byte transfer length is + * returned * - * RETURN: Decoded access length + * RETURN: Status and decoded byte transfer length * * DESCRIPTION: This routine returns the length of the generic_serial_bus * protocol bytes * ******************************************************************************/ -static u32 -acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length) +acpi_status +acpi_ex_get_protocol_buffer_length(u32 protocol_id, u32 *return_length) { - u32 length; - - switch (accessor_type) { - case AML_FIELD_ATTRIB_QUICK: - - length = 0; - break; - - case AML_FIELD_ATTRIB_SEND_RCV: - case AML_FIELD_ATTRIB_BYTE: - - length = 1; - break; - - case AML_FIELD_ATTRIB_WORD: - case AML_FIELD_ATTRIB_WORD_CALL: - - length = 2; - break; - case AML_FIELD_ATTRIB_MULTIBYTE: - case AML_FIELD_ATTRIB_RAW_BYTES: - case AML_FIELD_ATTRIB_RAW_PROCESS: + if ((protocol_id > ACPI_MAX_PROTOCOL_ID) || + (acpi_protocol_lengths[protocol_id] == ACPI_INVALID_PROTOCOL_ID)) { + ACPI_ERROR((AE_INFO, + "Invalid Field/AccessAs protocol ID: 0x%4.4X", + protocol_id)); - length = access_length; - break; - - case AML_FIELD_ATTRIB_BLOCK: - case AML_FIELD_ATTRIB_BLOCK_CALL: - default: - - length = ACPI_GSBUS_BUFFER_SIZE - 2; - break; + return (AE_AML_PROTOCOL); } - return (length); + *return_length = acpi_protocol_lengths[protocol_id]; + return (AE_OK); } /******************************************************************************* @@ -98,10 +96,8 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, { acpi_status status; union acpi_operand_object *buffer_desc; - acpi_size length; void *buffer; - u32 function; - u16 accessor_type; + u32 buffer_length; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); @@ -132,60 +128,11 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, ACPI_ADR_SPACE_GSBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { - /* - * This is an SMBus, GSBus or IPMI read. We must create a buffer to - * hold the data and then directly access the region handler. - * - * Note: SMBus and GSBus protocol value is passed in upper 16-bits - * of Function - */ - if (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_SMBUS) { - length = ACPI_SMBUS_BUFFER_SIZE; - function = - ACPI_READ | (obj_desc->field.attribute << 16); - } else if (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_GSBUS) { - accessor_type = obj_desc->field.attribute; - length = - acpi_ex_get_serial_access_length(accessor_type, - obj_desc->field. - access_length); - - /* - * Add additional 2 bytes for the generic_serial_bus data buffer: - * - * Status; (Byte 0 of the data buffer) - * Length; (Byte 1 of the data buffer) - * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) - */ - length += 2; - function = ACPI_READ | (accessor_type << 16); - } else { /* IPMI */ - - length = ACPI_IPMI_BUFFER_SIZE; - function = ACPI_READ; - } - - buffer_desc = acpi_ut_create_buffer_object(length); - if (!buffer_desc) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Lock entire transaction if requested */ - - acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); - - /* Call the region handler for the read */ - status = acpi_ex_access_region(obj_desc, 0, - ACPI_CAST_PTR(u64, - buffer_desc-> - buffer.pointer), - function); + /* SMBus, GSBus, IPMI serial */ - acpi_ex_release_global_lock(obj_desc->common_field.field_flags); - goto exit; + status = acpi_ex_read_serial_bus(obj_desc, ret_buffer_desc); + return_ACPI_STATUS(status); } /* @@ -198,14 +145,14 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, * * Note: Field.length is in bits. */ - length = + buffer_length = (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); - if (length > acpi_gbl_integer_byte_width) { + if (buffer_length > acpi_gbl_integer_byte_width) { /* Field is too large for an Integer, create a Buffer instead */ - buffer_desc = acpi_ut_create_buffer_object(length); + buffer_desc = acpi_ut_create_buffer_object(buffer_length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -218,47 +165,24 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NO_MEMORY); } - length = acpi_gbl_integer_byte_width; + buffer_length = acpi_gbl_integer_byte_width; buffer = &buffer_desc->integer.value; } if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) { - /* - * For GPIO (general_purpose_io), the Address will be the bit offset - * from the previous Connection() operator, making it effectively a - * pin number index. The bit_length is the length of the field, which - * is thus the number of pins. - */ - ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "GPIO FieldRead [FROM]: Pin %u Bits %u\n", - obj_desc->field.pin_number_index, - obj_desc->field.bit_length)); - - /* Lock entire transaction if requested */ - acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + /* General Purpose I/O */ - /* Perform the write */ - - status = - acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, - ACPI_READ); - - acpi_ex_release_global_lock(obj_desc->common_field.field_flags); - if (ACPI_FAILURE(status)) { - acpi_ut_remove_reference(buffer_desc); - } else { - *ret_buffer_desc = buffer_desc; - } - return_ACPI_STATUS(status); + status = acpi_ex_read_gpio(obj_desc, buffer); + goto exit; } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, obj_desc->common.type, buffer, - (u32) length)); + buffer_length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", obj_desc->common_field.bit_length, @@ -271,7 +195,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, /* Read from the field */ - status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); + status = acpi_ex_extract_from_field(obj_desc, buffer, buffer_length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); exit: @@ -304,11 +228,8 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, union acpi_operand_object **result_desc) { acpi_status status; - u32 length; + u32 buffer_length; void *buffer; - union acpi_operand_object *buffer_desc; - u32 function; - u16 accessor_type; ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); @@ -331,130 +252,25 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_SMBUS - || obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_GSBUS - || obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_IPMI)) { - /* - * This is an SMBus, GSBus or IPMI write. We will bypass the entire - * field mechanism and handoff the buffer directly to the handler. - * For these address spaces, the buffer is bi-directional; on a - * write, return data is returned in the same buffer. - * - * Source must be a buffer of sufficient size: - * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or - * ACPI_IPMI_BUFFER_SIZE. - * - * Note: SMBus and GSBus protocol type is passed in upper 16-bits - * of Function - */ - if (source_desc->common.type != ACPI_TYPE_BUFFER) { - ACPI_ERROR((AE_INFO, - "SMBus/IPMI/GenericSerialBus write requires " - "Buffer, found type %s", - acpi_ut_get_object_type_name(source_desc))); - - return_ACPI_STATUS(AE_AML_OPERAND_TYPE); - } - - if (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_SMBUS) { - length = ACPI_SMBUS_BUFFER_SIZE; - function = - ACPI_WRITE | (obj_desc->field.attribute << 16); - } else if (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_GSBUS) { - accessor_type = obj_desc->field.attribute; - length = - acpi_ex_get_serial_access_length(accessor_type, - obj_desc->field. - access_length); - - /* - * Add additional 2 bytes for the generic_serial_bus data buffer: - * - * Status; (Byte 0 of the data buffer) - * Length; (Byte 1 of the data buffer) - * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) - */ - length += 2; - function = ACPI_WRITE | (accessor_type << 16); - } else { /* IPMI */ - - length = ACPI_IPMI_BUFFER_SIZE; - function = ACPI_WRITE; - } - - if (source_desc->buffer.length < length) { - ACPI_ERROR((AE_INFO, - "SMBus/IPMI/GenericSerialBus write requires " - "Buffer of length %u, found length %u", - length, source_desc->buffer.length)); - - return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); - } - - /* Create the bi-directional buffer */ - - buffer_desc = acpi_ut_create_buffer_object(length); - if (!buffer_desc) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - buffer = buffer_desc->buffer.pointer; - memcpy(buffer, source_desc->buffer.pointer, length); - - /* Lock entire transaction if requested */ + ACPI_ADR_SPACE_GPIO)) { - acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + /* General Purpose I/O */ - /* - * Perform the write (returns status and perhaps data in the - * same buffer) - */ - status = - acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function); - acpi_ex_release_global_lock(obj_desc->common_field.field_flags); - - *result_desc = buffer_desc; + status = acpi_ex_write_gpio(source_desc, obj_desc, result_desc); return_ACPI_STATUS(status); } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_GPIO)) { - /* - * For GPIO (general_purpose_io), we will bypass the entire field - * mechanism and handoff the bit address and bit width directly to - * the handler. The Address will be the bit offset - * from the previous Connection() operator, making it effectively a - * pin number index. The bit_length is the length of the field, which - * is thus the number of pins. - */ - if (source_desc->common.type != ACPI_TYPE_INTEGER) { - return_ACPI_STATUS(AE_AML_OPERAND_TYPE); - } - - ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", - acpi_ut_get_type_name(source_desc->common. - type), - source_desc->common.type, - (u32)source_desc->integer.value, - obj_desc->field.pin_number_index, - obj_desc->field.bit_length)); - - buffer = &source_desc->integer.value; - - /* Lock entire transaction if requested */ - - acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + ACPI_ADR_SPACE_SMBUS + || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS + || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_IPMI)) { - /* Perform the write */ + /* SMBus, GSBus, IPMI serial */ status = - acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, - ACPI_WRITE); - acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + acpi_ex_write_serial_bus(source_desc, obj_desc, + result_desc); return_ACPI_STATUS(status); } @@ -464,23 +280,22 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, case ACPI_TYPE_INTEGER: buffer = &source_desc->integer.value; - length = sizeof(source_desc->integer.value); + buffer_length = sizeof(source_desc->integer.value); break; case ACPI_TYPE_BUFFER: buffer = source_desc->buffer.pointer; - length = source_desc->buffer.length; + buffer_length = source_desc->buffer.length; break; case ACPI_TYPE_STRING: buffer = source_desc->string.pointer; - length = source_desc->string.length; + buffer_length = source_desc->string.length; break; default: - return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } @@ -488,7 +303,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", source_desc, acpi_ut_get_type_name(source_desc->common.type), - source_desc->common.type, buffer, length)); + source_desc->common.type, buffer, buffer_length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", @@ -505,8 +320,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, /* Write to the field */ - status = acpi_ex_insert_into_field(obj_desc, buffer, length); + status = acpi_ex_insert_into_field(obj_desc, buffer, buffer_length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); - return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/exserial.c b/drivers/acpi/acpica/exserial.c new file mode 100644 index 000000000000..0d42f30e5b25 --- /dev/null +++ b/drivers/acpi/acpica/exserial.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/****************************************************************************** + * + * Module Name: exserial - field_unit support for serial address spaces + * + * Copyright (C) 2000 - 2018, Intel Corp. + * + *****************************************************************************/ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" + +#define _COMPONENT ACPI_EXECUTER +ACPI_MODULE_NAME("exserial") + +/******************************************************************************* + * + * FUNCTION: acpi_ex_read_gpio + * + * PARAMETERS: obj_desc - The named field to read + * buffer - Where the return data is returnd + * + * RETURN: Status + * + * DESCRIPTION: Read from a named field that references a Generic Serial Bus + * field + * + ******************************************************************************/ +acpi_status acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ex_read_gpio, obj_desc); + + /* + * For GPIO (general_purpose_io), the Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The bit_length is the length of the field, which + * is thus the number of pins. + */ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "GPIO FieldRead [FROM]: Pin %u Bits %u\n", + obj_desc->field.pin_number_index, + obj_desc->field.bit_length)); + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* Perform the read */ + + status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ); + + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_write_gpio + * + * PARAMETERS: source_desc - Contains data to write. Expect to be + * an Integer object. + * obj_desc - The named field + * result_desc - Where the return value is returned, if any + * + * RETURN: Status + * + * DESCRIPTION: Write to a named field that references a General Purpose I/O + * field. + * + ******************************************************************************/ + +acpi_status +acpi_ex_write_gpio(union acpi_operand_object *source_desc, + union acpi_operand_object *obj_desc, + union acpi_operand_object **return_buffer) +{ + acpi_status status; + void *buffer; + + ACPI_FUNCTION_TRACE_PTR(ex_write_gpio, obj_desc); + + /* + * For GPIO (general_purpose_io), we will bypass the entire field + * mechanism and handoff the bit address and bit width directly to + * the handler. The Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The bit_length is the length of the field, which + * is thus the number of pins. + */ + if (source_desc->common.type != ACPI_TYPE_INTEGER) { + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } + + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X [TO]: Pin %u Bits %u\n", + acpi_ut_get_type_name(source_desc->common.type), + source_desc->common.type, + (u32)source_desc->integer.value, + obj_desc->field.pin_number_index, + obj_desc->field.bit_length)); + + buffer = &source_desc->integer.value; + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* Perform the write */ + + status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_WRITE); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_read_serial_bus + * + * PARAMETERS: obj_desc - The named field to read + * return_buffer - Where the return value is returned, if any + * + * RETURN: Status + * + * DESCRIPTION: Read from a named field that references a serial bus + * (SMBus, IPMI, or GSBus). + * + ******************************************************************************/ + +acpi_status +acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc, + union acpi_operand_object **return_buffer) +{ + acpi_status status; + u32 buffer_length; + union acpi_operand_object *buffer_desc; + u32 function; + u16 accessor_type; + + ACPI_FUNCTION_TRACE_PTR(ex_read_serial_bus, obj_desc); + + /* + * This is an SMBus, GSBus or IPMI read. We must create a buffer to + * hold the data and then directly access the region handler. + * + * Note: SMBus and GSBus protocol value is passed in upper 16-bits + * of Function + * + * Common buffer format: + * Status; (Byte 0 of the data buffer) + * Length; (Byte 1 of the data buffer) + * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) + */ + switch (obj_desc->field.region_obj->region.space_id) { + case ACPI_ADR_SPACE_SMBUS: + + buffer_length = ACPI_SMBUS_BUFFER_SIZE; + function = ACPI_READ | (obj_desc->field.attribute << 16); + break; + + case ACPI_ADR_SPACE_IPMI: + + buffer_length = ACPI_IPMI_BUFFER_SIZE; + function = ACPI_READ; + break; + + case ACPI_ADR_SPACE_GSBUS: + + accessor_type = obj_desc->field.attribute; + if (accessor_type == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES) { + ACPI_ERROR((AE_INFO, + "Invalid direct read using bidirectional write-then-read protocol")); + + return_ACPI_STATUS(AE_AML_PROTOCOL); + } + + status = + acpi_ex_get_protocol_buffer_length(accessor_type, + &buffer_length); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, + "Invalid protocol ID for GSBus: 0x%4.4X", + accessor_type)); + + return_ACPI_STATUS(status); + } + + /* Add header length to get the full size of the buffer */ + + buffer_length += ACPI_SERIAL_HEADER_SIZE; + function = ACPI_READ | (accessor_type << 16); + break; + + default: + return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); + } + + /* Create the local transfer buffer that is returned to the caller */ + + buffer_desc = acpi_ut_create_buffer_object(buffer_length); + if (!buffer_desc) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* Call the region handler for the write-then-read */ + + status = acpi_ex_access_region(obj_desc, 0, + ACPI_CAST_PTR(u64, + buffer_desc->buffer. + pointer), function); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + + *return_buffer = buffer_desc; + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_write_serial_bus + * + * PARAMETERS: source_desc - Contains data to write + * obj_desc - The named field + * return_buffer - Where the return value is returned, if any + * + * RETURN: Status + * + * DESCRIPTION: Write to a named field that references a serial bus + * (SMBus, IPMI, GSBus). + * + ******************************************************************************/ + +acpi_status +acpi_ex_write_serial_bus(union acpi_operand_object *source_desc, + union acpi_operand_object *obj_desc, + union acpi_operand_object **return_buffer) +{ + acpi_status status; + u32 buffer_length; + u32 data_length; + void *buffer; + union acpi_operand_object *buffer_desc; + u32 function; + u16 accessor_type; + + ACPI_FUNCTION_TRACE_PTR(ex_write_serial_bus, obj_desc); + + /* + * This is an SMBus, GSBus or IPMI write. We will bypass the entire + * field mechanism and handoff the buffer directly to the handler. + * For these address spaces, the buffer is bidirectional; on a + * write, return data is returned in the same buffer. + * + * Source must be a buffer of sufficient size, these are fixed size: + * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. + * + * Note: SMBus and GSBus protocol type is passed in upper 16-bits + * of Function + * + * Common buffer format: + * Status; (Byte 0 of the data buffer) + * Length; (Byte 1 of the data buffer) + * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) + */ + if (source_desc->common.type != ACPI_TYPE_BUFFER) { + ACPI_ERROR((AE_INFO, + "SMBus/IPMI/GenericSerialBus write requires " + "Buffer, found type %s", + acpi_ut_get_object_type_name(source_desc))); + + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } + + switch (obj_desc->field.region_obj->region.space_id) { + case ACPI_ADR_SPACE_SMBUS: + + buffer_length = ACPI_SMBUS_BUFFER_SIZE; + data_length = ACPI_SMBUS_DATA_SIZE; + function = ACPI_WRITE | (obj_desc->field.attribute << 16); + break; + + case ACPI_ADR_SPACE_IPMI: + + buffer_length = ACPI_IPMI_BUFFER_SIZE; + data_length = ACPI_IPMI_DATA_SIZE; + function = ACPI_WRITE; + break; + + case ACPI_ADR_SPACE_GSBUS: + + accessor_type = obj_desc->field.attribute; + status = + acpi_ex_get_protocol_buffer_length(accessor_type, + &buffer_length); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, + "Invalid protocol ID for GSBus: 0x%4.4X", + accessor_type)); + + return_ACPI_STATUS(status); + } + + /* Add header length to get the full size of the buffer */ + + buffer_length += ACPI_SERIAL_HEADER_SIZE; + data_length = source_desc->buffer.pointer[1]; + function = ACPI_WRITE | (accessor_type << 16); + break; + + default: + return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); + } + +#if 0 + OBSOLETE ? + /* Check for possible buffer overflow */ + if (data_length > source_desc->buffer.length) { + ACPI_ERROR((AE_INFO, + "Length in buffer header (%u)(%u) is greater than " + "the physical buffer length (%u) and will overflow", + data_length, buffer_length, + source_desc->buffer.length)); + + return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); + } +#endif + + /* Create the transfer/bidirectional/return buffer */ + + buffer_desc = acpi_ut_create_buffer_object(buffer_length); + if (!buffer_desc) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Copy the input buffer data to the transfer buffer */ + + buffer = buffer_desc->buffer.pointer; + memcpy(buffer, source_desc->buffer.pointer, data_length); + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* + * Perform the write (returns status and perhaps data in the + * same buffer) + */ + status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + + *return_buffer = buffer_desc; + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 34fc2f7476ed..0fa01c9e353e 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -147,7 +147,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, * future. Use of this option can cause problems with AML code that * depends upon in-order immediate execution of module-level code. */ - if (acpi_gbl_group_module_level_code && + if (!acpi_gbl_execute_tables_as_methods && (walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) && ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { /* @@ -417,6 +417,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) union acpi_parse_object *op = NULL; /* current op */ struct acpi_parse_state *parser_state; u8 *aml_op_start = NULL; + u8 opcode_length; ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); @@ -540,8 +541,19 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) "Skip parsing opcode %s", acpi_ps_get_opcode_name (walk_state->opcode))); + + /* + * Determine the opcode length before skipping the opcode. + * An opcode can be 1 byte or 2 bytes in length. + */ + opcode_length = 1; + if ((walk_state->opcode & 0xFF00) == + AML_EXTENDED_OPCODE) { + opcode_length = 2; + } walk_state->parser_state.aml = - walk_state->aml + 1; + walk_state->aml + opcode_length; + walk_state->parser_state.aml = acpi_ps_get_next_package_end (&walk_state->parser_state); diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 2f40f71c06db..9011297552af 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -69,8 +69,7 @@ acpi_status ACPI_INIT_FUNCTION acpi_load_tables(void) "While loading namespace from ACPI tables")); } - if (acpi_gbl_execute_tables_as_methods - || !acpi_gbl_group_module_level_code) { + if (acpi_gbl_execute_tables_as_methods) { /* * If the module-level code support is enabled, initialize the objects * in the namespace that remain uninitialized. This runs the executable diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 08f26db2da7e..2a361e22d38d 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -1428,7 +1428,7 @@ static int __init iort_add_platform_device(struct acpi_iort_node *node, return 0; dma_deconfigure: - acpi_dma_deconfigure(&pdev->dev); + arch_teardown_dma_ops(&pdev->dev); dev_put: platform_device_put(pdev); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d2e29a19890d..bb3d96dea6db 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1054,15 +1054,17 @@ void __init acpi_early_init(void) goto error0; } - if (!acpi_gbl_execute_tables_as_methods && - acpi_gbl_group_module_level_code) { - status = acpi_load_tables(); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX - "Unable to load the System Description Tables\n"); - goto error0; - } - } + /* + * ACPI 2.0 requires the EC driver to be loaded and work before + * the EC device is found in the namespace (i.e. before + * acpi_load_tables() is called). + * + * This is accomplished by looking for the ECDT table, and getting + * the EC parameters out of that. + * + * Ignore the result. Not having an ECDT is not fatal. + */ + status = acpi_ec_ecdt_probe(); #ifdef CONFIG_X86 if (!acpi_ioapic) { @@ -1133,25 +1135,11 @@ static int __init acpi_bus_init(void) acpi_os_initialize1(); - /* - * ACPI 2.0 requires the EC driver to be loaded and work before - * the EC device is found in the namespace (i.e. before - * acpi_load_tables() is called). - * - * This is accomplished by looking for the ECDT table, and getting - * the EC parameters out of that. - */ - status = acpi_ec_ecdt_probe(); - /* Ignore result. Not having an ECDT is not fatal. */ - - if (acpi_gbl_execute_tables_as_methods || - !acpi_gbl_group_module_level_code) { - status = acpi_load_tables(); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX - "Unable to load the System Description Tables\n"); - goto error1; - } + status = acpi_load_tables(); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX + "Unable to load the System Description Tables\n"); + goto error1; } status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE); diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index d9ce4b162e2c..217a782c3e55 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1061,9 +1061,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *highest_reg, *lowest_reg, - *lowest_non_linear_reg, *nominal_reg, + *lowest_non_linear_reg, *nominal_reg, *guaranteed_reg, *low_freq_reg = NULL, *nom_freq_reg = NULL; - u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0; + u64 high, low, guaranteed, nom, min_nonlinear, low_f = 0, nom_f = 0; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0, regs_in_pcc = 0; @@ -1079,6 +1079,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ]; nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ]; + guaranteed_reg = &cpc_desc->cpc_regs[GUARANTEED_PERF]; /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || @@ -1107,6 +1108,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) cpc_read(cpunum, nominal_reg, &nom); perf_caps->nominal_perf = nom; + cpc_read(cpunum, guaranteed_reg, &guaranteed); + perf_caps->guaranteed_perf = guaranteed; + cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear); perf_caps->lowest_nonlinear_perf = min_nonlinear; diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index e967c1173ba3..4451877f83b6 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -92,8 +92,7 @@ static int __init acpi_custom_method_init(void) static void __exit acpi_custom_method_exit(void) { - if (cm_dentry) - debugfs_remove(cm_dentry); + debugfs_remove(cm_dentry); } module_init(acpi_custom_method_init); diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 3be1433853bf..12ba2bee8789 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -320,7 +320,7 @@ static int acpi_platform_notify(struct device *dev) if (!adev) goto out; - if (dev->bus == &platform_bus_type) + if (dev_is_platform(dev)) acpi_configure_pmsi_domain(dev); if (type && type->setup) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 8df9abfa947b..b48874b8e1ea 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -617,15 +617,18 @@ void acpi_os_stall(u32 us) } /* - * Support ACPI 3.0 AML Timer operand - * Returns 64-bit free-running, monotonically increasing timer - * with 100ns granularity + * Support ACPI 3.0 AML Timer operand. Returns a 64-bit free-running, + * monotonically increasing timer with 100ns granularity. Do not use + * ktime_get() to implement this function because this function may get + * called after timekeeping has been suspended. Note: calling this function + * after timekeeping has been suspended may lead to unexpected results + * because when timekeeping is suspended the jiffies counter is not + * incremented. See also timekeeping_suspend(). */ u64 acpi_os_get_timer(void) { - u64 time_ns = ktime_to_ns(ktime_get()); - do_div(time_ns, 100); - return time_ns; + return (get_jiffies_64() - INITIAL_JIFFIES) * + (ACPI_100NSEC_PER_SEC / HZ); } acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width) @@ -1129,6 +1132,7 @@ void acpi_os_wait_events_complete(void) flush_workqueue(kacpid_wq); flush_workqueue(kacpi_notify_wq); } +EXPORT_SYMBOL(acpi_os_wait_events_complete); struct acpi_hp_work { struct work_struct work; diff --git a/drivers/acpi/pmic/intel_pmic_bxtwc.c b/drivers/acpi/pmic/intel_pmic_bxtwc.c index 886ac8b93cd0..bd7621edd60b 100644 --- a/drivers/acpi/pmic/intel_pmic_bxtwc.c +++ b/drivers/acpi/pmic/intel_pmic_bxtwc.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * intel_pmic_bxtwc.c - Intel BXT WhiskeyCove PMIC operation region driver + * Intel BXT WhiskeyCove PMIC operation region driver * * Copyright (C) 2015 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/init.h> diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c index f6d73a243d80..7ccd7d9660bc 100644 --- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c +++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Dollar Cove TI PMIC operation region driver * Copyright (C) 2014 Intel Corporation. All rights reserved. diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c index 9912422c8185..078b0448f30a 100644 --- a/drivers/acpi/pmic/intel_pmic_chtwc.c +++ b/drivers/acpi/pmic/intel_pmic_chtwc.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Intel CHT Whiskey Cove PMIC operation region driver * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> * * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/acpi.h> diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c index 22c9e374c923..a0f411a6e5ac 100644 --- a/drivers/acpi/pmic/intel_pmic_crc.c +++ b/drivers/acpi/pmic/intel_pmic_crc.c @@ -1,23 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * intel_pmic_crc.c - Intel CrystalCove PMIC operation region driver + * Intel CrystalCove PMIC operation region driver * * Copyright (C) 2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ -#include <linux/init.h> #include <linux/acpi.h> +#include <linux/init.h> #include <linux/mfd/intel_soc_pmic.h> -#include <linux/regmap.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include "intel_pmic.h" #define PWR_SOURCE_SELECT BIT(1) diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 316e55174aa9..aadc86db804c 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -1,23 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver + * XPower AXP288 PMIC operation region driver * * Copyright (C) 2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ -#include <linux/init.h> #include <linux/acpi.h> +#include <linux/init.h> #include <linux/mfd/axp20x.h> -#include <linux/regmap.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include "intel_pmic.h" #define XPOWER_GPADC_LOW 0x5b diff --git a/drivers/acpi/pmic/tps68470_pmic.c b/drivers/acpi/pmic/tps68470_pmic.c index a083de507009..ebd03e472955 100644 --- a/drivers/acpi/pmic/tps68470_pmic.c +++ b/drivers/acpi/pmic/tps68470_pmic.c @@ -10,8 +10,8 @@ */ #include <linux/acpi.h> -#include <linux/mfd/tps68470.h> #include <linux/init.h> +#include <linux/mfd/tps68470.h> #include <linux/platform_device.h> #include <linux/regmap.h> diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index d1e26cb599bf..da031b1df6f5 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -338,9 +338,6 @@ static struct acpi_pptt_cache *acpi_find_cache_node(struct acpi_table_header *ta return found; } -/* total number of attributes checked by the properties code */ -#define PPTT_CHECKED_ATTRIBUTES 4 - /** * update_cache_properties() - Update cacheinfo for the given processor * @this_leaf: Kernel cache info structure being updated @@ -357,25 +354,15 @@ static void update_cache_properties(struct cacheinfo *this_leaf, struct acpi_pptt_cache *found_cache, struct acpi_pptt_processor *cpu_node) { - int valid_flags = 0; - this_leaf->fw_token = cpu_node; - if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID) { + if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID) this_leaf->size = found_cache->size; - valid_flags++; - } - if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID) { + if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID) this_leaf->coherency_line_size = found_cache->line_size; - valid_flags++; - } - if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID) { + if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID) this_leaf->number_of_sets = found_cache->number_of_sets; - valid_flags++; - } - if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID) { + if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID) this_leaf->ways_of_associativity = found_cache->associativity; - valid_flags++; - } if (found_cache->flags & ACPI_PPTT_WRITE_POLICY_VALID) { switch (found_cache->attributes & ACPI_PPTT_MASK_WRITE_POLICY) { case ACPI_PPTT_CACHE_POLICY_WT: @@ -402,11 +389,17 @@ static void update_cache_properties(struct cacheinfo *this_leaf, } } /* - * If the above flags are valid, and the cache type is NOCACHE - * update the cache type as well. + * If cache type is NOCACHE, then the cache hasn't been specified + * via other mechanisms. Update the type if a cache type has been + * provided. + * + * Note, we assume such caches are unified based on conventional system + * design and known examples. Significant work is required elsewhere to + * fully support data/instruction only type caches which are only + * specified in PPTT. */ if (this_leaf->type == CACHE_TYPE_NOCACHE && - valid_flags == PPTT_CHECKED_ATTRIBUTES) + found_cache->flags & ACPI_PPTT_CACHE_TYPE_VALID) this_leaf->type = CACHE_TYPE_UNIFIED; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index abb559cd28d7..b2131c4ea124 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -205,6 +205,7 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr, static void tsc_check_state(int state) { switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_HYGON: case X86_VENDOR_AMD: case X86_VENDOR_INTEL: case X86_VENDOR_CENTAUR: diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 295b59271189..96c5e27967f4 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -441,9 +441,13 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) /* * The spec requires that bit 4 always be 1. If it's not set, assume - * that the implementation doesn't support an SBS charger + * that the implementation doesn't support an SBS charger. + * + * And on some MacBooks a status of 0xffff is always returned, no + * matter whether the charger is plugged in or not, which is also + * wrong, so ignore the SBS charger for those too. */ - if (!((status >> 4) & 0x1)) + if (!((status >> 4) & 0x1) || status == 0xffff) return -ENODEV; sbs->charger_present = (status >> 15) & 0x1; diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 7a3431018e0a..5008ead4609a 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -196,6 +196,7 @@ int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc) hc->callback = NULL; hc->context = NULL; mutex_unlock(&hc->lock); + acpi_os_wait_events_complete(); return 0; } @@ -292,6 +293,7 @@ static int acpi_smbus_hc_remove(struct acpi_device *device) hc = acpi_driver_data(device); acpi_ec_remove_query_handler(hc->ec, hc->query_bit); + acpi_os_wait_events_complete(); kfree(hc); device->driver_data = NULL; return 0; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e1b6231cfa1c..bd1c59fb0e17 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1469,16 +1469,6 @@ int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) } EXPORT_SYMBOL_GPL(acpi_dma_configure); -/** - * acpi_dma_deconfigure - Tear-down DMA configuration for the device. - * @dev: The pointer to the device - */ -void acpi_dma_deconfigure(struct device *dev) -{ - arch_teardown_dma_ops(dev); -} -EXPORT_SYMBOL_GPL(acpi_dma_deconfigure); - static void acpi_init_coherency(struct acpi_device *adev) { unsigned long long cca = 0; @@ -1550,6 +1540,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) */ static const struct acpi_device_id i2c_multi_instantiate_ids[] = { {"BSG1160", }, + {"INT33FE", }, {} }; diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c index 51b4cf9f25da..bb1984f6c9fe 100644 --- a/drivers/acpi/x86/apple.c +++ b/drivers/acpi/x86/apple.c @@ -62,7 +62,7 @@ void acpi_extract_apple_properties(struct acpi_device *adev) if (!numprops) goto out_free; - valid = kcalloc(BITS_TO_LONGS(numprops), sizeof(long), GFP_KERNEL); + valid = bitmap_zalloc(numprops, GFP_KERNEL); if (!valid) goto out_free; @@ -137,5 +137,5 @@ void acpi_extract_apple_properties(struct acpi_device *adev) out_free: ACPI_FREE(props); - kfree(valid); + bitmap_free(valid); } diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index 06c31ec3cc70..9a8e286dd86f 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -54,7 +54,7 @@ static const struct always_present_id always_present_ids[] = { * Bay / Cherry Trail PWM directly poked by GPU driver in win10, * but Linux uses a separate PWM driver, harmless if not used. */ - ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1), {}), + ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT), {}), ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}), /* * The INT0002 device is necessary to clear wakeup interrupt sources diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 39b181d6bd0d..4ca7a6b4eaae 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -33,7 +33,6 @@ if ATA config ATA_NONSTANDARD bool - default n config ATA_VERBOSE_ERROR bool "Verbose ATA error reporting" @@ -62,7 +61,6 @@ config ATA_ACPI config SATA_ZPODD bool "SATA Zero Power Optical Disc Drive (ZPODD) support" depends on ATA_ACPI && PM - default n help This option adds support for SATA Zero Power Optical Disc Drive (ZPODD). It requires both the ODD and the platform @@ -121,7 +119,8 @@ config SATA_AHCI_PLATFORM config AHCI_BRCM tristate "Broadcom AHCI SATA support" - depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP + depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP || \ + ARCH_BCM_63XX help This option enables support for the AHCI SATA3 controller found on Broadcom SoC's. diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 6a1515f0da40..ef356e70e6de 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -352,6 +352,8 @@ struct ahci_host_priv { struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ struct reset_control *rsts; /* Optional */ struct regulator **target_pwrs; /* Optional */ + struct regulator *ahci_regulator;/* Optional */ + struct regulator *phy_regulator;/* Optional */ /* * If platform uses PHYs. There is a 1:1 relation between the port number and * the PHY position in this array. diff --git a/drivers/ata/ahci_brcm.c b/drivers/ata/ahci_brcm.c index f3d557777d82..fba5a3044c8a 100644 --- a/drivers/ata/ahci_brcm.c +++ b/drivers/ata/ahci_brcm.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/string.h> #include "ahci.h" @@ -94,6 +95,7 @@ struct brcm_ahci_priv { u32 port_mask; u32 quirks; enum brcm_ahci_version version; + struct reset_control *rcdev; }; static inline u32 brcm_sata_readreg(void __iomem *addr) @@ -381,6 +383,7 @@ static struct scsi_host_template ahci_platform_sht = { static const struct of_device_id ahci_of_match[] = { {.compatible = "brcm,bcm7425-ahci", .data = (void *)BRCM_SATA_BCM7425}, {.compatible = "brcm,bcm7445-ahci", .data = (void *)BRCM_SATA_BCM7445}, + {.compatible = "brcm,bcm63138-ahci", .data = (void *)BRCM_SATA_BCM7445}, {.compatible = "brcm,bcm-nsp-ahci", .data = (void *)BRCM_SATA_NSP}, {}, }; @@ -411,6 +414,11 @@ static int brcm_ahci_probe(struct platform_device *pdev) if (IS_ERR(priv->top_ctrl)) return PTR_ERR(priv->top_ctrl); + /* Reset is optional depending on platform */ + priv->rcdev = devm_reset_control_get(&pdev->dev, "ahci"); + if (!IS_ERR_OR_NULL(priv->rcdev)) + reset_control_deassert(priv->rcdev); + if ((priv->version == BRCM_SATA_BCM7425) || (priv->version == BRCM_SATA_NSP)) { priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ; diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 46f0bd75eff7..cf1e0e18a7a9 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -33,6 +33,13 @@ static const struct ata_port_info ahci_port_info = { .port_ops = &ahci_platform_ops, }; +static const struct ata_port_info ahci_port_info_nolpm = { + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_LPM, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + static struct scsi_host_template ahci_platform_sht = { AHCI_SHT(DRV_NAME), }; @@ -41,6 +48,7 @@ static int ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; + const struct ata_port_info *port; int rc; hpriv = ahci_platform_get_resources(pdev, @@ -58,7 +66,11 @@ static int ahci_probe(struct platform_device *pdev) if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ; - rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, + port = acpi_device_get_match_data(dev); + if (!port) + port = &ahci_port_info; + + rc = ahci_platform_init_host(pdev, hpriv, port, &ahci_platform_sht); if (rc) goto disable_resources; @@ -85,6 +97,7 @@ static const struct of_device_id ahci_of_match[] = { MODULE_DEVICE_TABLE(of, ahci_of_match); static const struct acpi_device_id ahci_acpi_match[] = { + { "APMC0D33", (unsigned long)&ahci_port_info_nolpm }, { ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) }, {}, }; diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index 631610b72aa5..911710643305 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -181,7 +181,7 @@ static int ahci_sunxi_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; int rc; - hpriv = ahci_platform_get_resources(pdev, 0); + hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); @@ -250,6 +250,7 @@ static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend, static const struct of_device_id ahci_sunxi_of_match[] = { { .compatible = "allwinner,sun4i-a10-ahci", }, + { .compatible = "allwinner,sun8i-r40-ahci", }, { }, }; MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match); diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index c92c10d55374..4b900fc659f7 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -139,7 +139,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); * ahci_platform_enable_regulators - Enable regulators * @hpriv: host private area to store config values * - * This function enables all the regulators found in + * This function enables all the regulators found in controller and * hpriv->target_pwrs, if any. If a regulator fails to be enabled, it * disables all the regulators already enabled in reverse order and * returns an error. @@ -151,6 +151,18 @@ int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv) { int rc, i; + if (hpriv->ahci_regulator) { + rc = regulator_enable(hpriv->ahci_regulator); + if (rc) + return rc; + } + + if (hpriv->phy_regulator) { + rc = regulator_enable(hpriv->phy_regulator); + if (rc) + goto disable_ahci_pwrs; + } + for (i = 0; i < hpriv->nports; i++) { if (!hpriv->target_pwrs[i]) continue; @@ -167,6 +179,11 @@ disable_target_pwrs: if (hpriv->target_pwrs[i]) regulator_disable(hpriv->target_pwrs[i]); + if (hpriv->phy_regulator) + regulator_disable(hpriv->phy_regulator); +disable_ahci_pwrs: + if (hpriv->ahci_regulator) + regulator_disable(hpriv->ahci_regulator); return rc; } EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators); @@ -175,7 +192,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators); * ahci_platform_disable_regulators - Disable regulators * @hpriv: host private area to store config values * - * This function disables all regulators found in hpriv->target_pwrs. + * This function disables all regulators found in hpriv->target_pwrs and + * AHCI controller. */ void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv) { @@ -186,6 +204,11 @@ void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv) continue; regulator_disable(hpriv->target_pwrs[i]); } + + if (hpriv->ahci_regulator) + regulator_disable(hpriv->ahci_regulator); + if (hpriv->phy_regulator) + regulator_disable(hpriv->phy_regulator); } EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators); /** @@ -303,8 +326,8 @@ static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port, /* No PHY support. Check if PHY is required. */ if (of_find_property(node, "phys", NULL)) { dev_err(dev, - "couldn't get PHY in node %s: ENOSYS\n", - node->name); + "couldn't get PHY in node %pOFn: ENOSYS\n", + node); break; } /* fall through */ @@ -316,8 +339,8 @@ static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port, default: dev_err(dev, - "couldn't get PHY in node %s: %d\n", - node->name, rc); + "couldn't get PHY in node %pOFn: %d\n", + node, rc); break; } @@ -351,6 +374,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, * * 1) mmio registers (IORESOURCE_MEM 0, mandatory) * 2) regulator for controlling the targets power (optional) + * regulator for controlling the AHCI controller (optional) * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, * or for non devicetree enabled platforms a single clock * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional) @@ -408,6 +432,24 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev, hpriv->clks[i] = clk; } + hpriv->ahci_regulator = devm_regulator_get_optional(dev, "ahci"); + if (IS_ERR(hpriv->ahci_regulator)) { + rc = PTR_ERR(hpriv->ahci_regulator); + if (rc == -EPROBE_DEFER) + goto err_out; + rc = 0; + hpriv->ahci_regulator = NULL; + } + + hpriv->phy_regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(hpriv->phy_regulator)) { + rc = PTR_ERR(hpriv->phy_regulator); + if (rc == -EPROBE_DEFER) + goto err_out; + rc = 0; + hpriv->phy_regulator = NULL; + } + if (flags & AHCI_PLATFORM_GET_RESETS) { hpriv->rsts = devm_reset_control_array_get_optional_shared(dev); if (IS_ERR(hpriv->rsts)) { diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 1984fc78c750..3d4887d0e84a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -639,8 +639,8 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) if (args[0] == ATA_CMD_SMART) { /* hack -- ide driver does this too */ scsi_cmd[6] = args[3]; scsi_cmd[8] = args[1]; - scsi_cmd[10] = 0x4f; - scsi_cmd[12] = 0xc2; + scsi_cmd[10] = ATA_SMART_LBAM_PASS; + scsi_cmd[12] = ATA_SMART_LBAH_PASS; } else { scsi_cmd[6] = args[1]; } diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 4d49fd3c927b..843bb200a1ee 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -279,7 +279,7 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id) const struct ata_port_info *ppi[] = { &info, &info }; /* SB600 doesn't have secondary port wired */ - if((pdev->device == PCI_DEVICE_ID_ATI_IXP600_IDE)) + if (pdev->device == PCI_DEVICE_ID_ATI_IXP600_IDE) ppi[1] = &ata_dummy_port_info; return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL, diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index 0a550190955a..cc6d06c1b2c7 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -659,7 +659,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) * start of new transfer. */ drv_data->dma_rx_data.port = EP93XX_DMA_IDE; - drv_data->dma_rx_data.direction = DMA_FROM_DEVICE; + drv_data->dma_rx_data.direction = DMA_DEV_TO_MEM; drv_data->dma_rx_data.name = "ep93xx-pata-rx"; drv_data->dma_rx_channel = dma_request_channel(mask, ep93xx_pata_dma_filter, &drv_data->dma_rx_data); @@ -667,7 +667,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) return; drv_data->dma_tx_data.port = EP93XX_DMA_IDE; - drv_data->dma_tx_data.direction = DMA_TO_DEVICE; + drv_data->dma_tx_data.direction = DMA_MEM_TO_DEV; drv_data->dma_tx_data.name = "ep93xx-pata-tx"; drv_data->dma_tx_channel = dma_request_channel(mask, ep93xx_pata_dma_filter, &drv_data->dma_tx_data); @@ -678,7 +678,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) /* Configure receive channel direction and source address */ memset(&conf, 0, sizeof(conf)); - conf.direction = DMA_FROM_DEVICE; + conf.direction = DMA_DEV_TO_MEM; conf.src_addr = drv_data->udma_in_phys; conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) { @@ -689,7 +689,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data) /* Configure transmit channel direction and destination address */ memset(&conf, 0, sizeof(conf)); - conf.direction = DMA_TO_DEVICE; + conf.direction = DMA_MEM_TO_DEV; conf.dst_addr = drv_data->udma_out_phys; conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) { diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index f1a42f0f1ded..9ad93ea42fdc 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -62,20 +62,15 @@ static void hd44780_strobe_gpio(struct hd44780 *hd) /* write to an LCD panel register in 8 bit GPIO mode */ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) { - int values[10]; /* for DATA[0-7], RS, RW */ - unsigned int i, n; - - for (i = 0; i < 8; i++) - values[PIN_DATA0 + i] = !!(val & BIT(i)); - values[PIN_CTRL_RS] = rs; - n = 9; - if (hd->pins[PIN_CTRL_RW]) { - values[PIN_CTRL_RW] = 0; - n++; - } + DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */ + unsigned int n; + + values[0] = val; + __assign_bit(8, values, rs); + n = hd->pins[PIN_CTRL_RW] ? 10 : 9; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values); hd44780_strobe_gpio(hd); } @@ -83,32 +78,25 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) /* write to an LCD panel register in 4 bit GPIO mode */ static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) { - int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ - unsigned int i, n; + DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */ + unsigned int n; /* High nibble + RS, RW */ - for (i = 4; i < 8; i++) - values[PIN_DATA0 + i] = !!(val & BIT(i)); - values[PIN_CTRL_RS] = rs; - n = 5; - if (hd->pins[PIN_CTRL_RW]) { - values[PIN_CTRL_RW] = 0; - n++; - } + values[0] = val >> 4; + __assign_bit(4, values, rs); + n = hd->pins[PIN_CTRL_RW] ? 6 : 5; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], - &values[PIN_DATA4]); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values); hd44780_strobe_gpio(hd); /* Low nibble */ - for (i = 0; i < 4; i++) - values[PIN_DATA4 + i] = !!(val & BIT(i)); + values[0] &= ~0x0fUL; + values[0] |= val & 0x0f; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], - &values[PIN_DATA4]); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values); hd44780_strobe_gpio(hd); } @@ -155,23 +143,16 @@ static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd) /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */ static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd) { - int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ + DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */ struct hd44780 *hd = lcd->drvdata; - unsigned int i, n; + unsigned int n; /* Command nibble + RS, RW */ - for (i = 0; i < 4; i++) - values[PIN_DATA4 + i] = !!(cmd & BIT(i)); - values[PIN_CTRL_RS] = 0; - n = 5; - if (hd->pins[PIN_CTRL_RW]) { - values[PIN_CTRL_RW] = 0; - n++; - } + values[0] = cmd & 0x0f; + n = hd->pins[PIN_CTRL_RW] ? 6 : 5; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], - &values[PIN_DATA4]); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values); hd44780_strobe_gpio(hd); } diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index e7cb0c6ade81..edfcf8d982e4 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/sched/topology.h> +#include <linux/cpuset.h> DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; @@ -47,6 +48,9 @@ static ssize_t cpu_capacity_show(struct device *dev, return sprintf(buf, "%lu\n", topology_get_cpu_scale(NULL, cpu->dev.id)); } +static void update_topology_flags_workfn(struct work_struct *work); +static DECLARE_WORK(update_topology_flags_work, update_topology_flags_workfn); + static ssize_t cpu_capacity_store(struct device *dev, struct device_attribute *attr, const char *buf, @@ -72,6 +76,8 @@ static ssize_t cpu_capacity_store(struct device *dev, topology_set_cpu_scale(i, new_capacity); mutex_unlock(&cpu_scale_mutex); + schedule_work(&update_topology_flags_work); + return count; } @@ -96,6 +102,25 @@ static int register_cpu_capacity_sysctl(void) } subsys_initcall(register_cpu_capacity_sysctl); +static int update_topology; + +int topology_update_cpu_topology(void) +{ + return update_topology; +} + +/* + * Updating the sched_domains can't be done directly from cpufreq callbacks + * due to locking, so queue the work for later. + */ +static void update_topology_flags_workfn(struct work_struct *work) +{ + update_topology = 1; + rebuild_sched_domains(); + pr_debug("sched_domain hierarchy rebuilt, flags updated\n"); + update_topology = 0; +} + static u32 capacity_scale; static u32 *raw_capacity; @@ -201,6 +226,7 @@ init_cpu_capacity_callback(struct notifier_block *nb, if (cpumask_empty(cpus_to_visit)) { topology_normalize_cpu_scale(); + schedule_work(&update_topology_flags_work); free_raw_capacity(); pr_debug("cpu_capacity: parsing done\n"); schedule_work(&parsing_done_work); diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 5d5b5988e88b..cf78fa6d470d 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -615,6 +615,8 @@ static int cache_add_dev(unsigned int cpu) this_leaf = this_cpu_ci->info_list + i; if (this_leaf->disable_sysfs) continue; + if (this_leaf->type == CACHE_TYPE_NOCACHE) + break; cache_groups = cache_get_attribute_groups(this_leaf); ci_dev = cpu_device_create(parent, this_leaf, cache_groups, "index%1u", i); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index edfc9f0b1180..169412ee4ae8 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -480,9 +480,11 @@ re_probe: if (ret) goto pinctrl_bind_failed; - ret = dma_configure(dev); - if (ret) - goto dma_failed; + if (dev->bus->dma_configure) { + ret = dev->bus->dma_configure(dev); + if (ret) + goto dma_failed; + } if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", @@ -537,7 +539,7 @@ re_probe: goto done; probe_failed: - dma_deconfigure(dev); + arch_teardown_dma_ops(dev); dma_failed: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, @@ -966,7 +968,7 @@ static void __device_release_driver(struct device *dev, struct device *parent) drv->remove(dev); device_links_driver_cleanup(dev); - dma_deconfigure(dev); + arch_teardown_dma_ops(dev); devres_release_all(dev); dev->driver = NULL; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index dff82a3c2caa..23cf4427f425 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -1180,7 +1180,7 @@ int __init platform_bus_init(void) } #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK -u64 dma_get_required_mask(struct device *dev) +static u64 dma_default_get_required_mask(struct device *dev) { u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); @@ -1198,6 +1198,15 @@ u64 dma_get_required_mask(struct device *dev) } return mask; } + +u64 dma_get_required_mask(struct device *dev) +{ + const struct dma_map_ops *ops = get_dma_ops(dev); + + if (ops->get_required_mask) + return ops->get_required_mask(dev); + return dma_default_get_required_mask(dev); +} EXPORT_SYMBOL_GPL(dma_get_required_mask); #endif diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 4b5714199490..7f38a92b444a 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -467,6 +467,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, return -EAGAIN; } + /* Default to shallowest state. */ + if (!genpd->gov) + genpd->state_idx = 0; + if (genpd->power_off) { int ret; @@ -1687,6 +1691,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd, ret = genpd_set_default_power_state(genpd); if (ret) return ret; + } else if (!gov) { + pr_warn("%s : no governor for states\n", genpd->name); } device_initialize(&genpd->dev); @@ -2478,8 +2484,8 @@ static int genpd_iterate_idle_states(struct device_node *dn, * * Returns the device states parsed from the OF node. The memory for the states * is allocated by this function and is the responsibility of the caller to - * free the memory after use. If no domain idle states is found it returns - * -EINVAL and in case of errors, a negative error code. + * free the memory after use. If any or zero compatible domain idle states is + * found it returns 0 and in case of errors, a negative error code is returned. */ int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n) @@ -2488,8 +2494,14 @@ int of_genpd_parse_idle_states(struct device_node *dn, int ret; ret = genpd_iterate_idle_states(dn, NULL); - if (ret <= 0) - return ret < 0 ? ret : -EINVAL; + if (ret < 0) + return ret; + + if (!ret) { + *states = NULL; + *n = 0; + return 0; + } st = kcalloc(ret, sizeof(*st), GFP_KERNEL); if (!st) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a6bf34d6394e..a98fced9bff8 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -94,11 +94,13 @@ struct regmap { bool (*readable_reg)(struct device *dev, unsigned int reg); bool (*volatile_reg)(struct device *dev, unsigned int reg); bool (*precious_reg)(struct device *dev, unsigned int reg); + bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg); bool (*readable_noinc_reg)(struct device *dev, unsigned int reg); const struct regmap_access_table *wr_table; const struct regmap_access_table *rd_table; const struct regmap_access_table *volatile_table; const struct regmap_access_table *precious_table; + const struct regmap_access_table *wr_noinc_table; const struct regmap_access_table *rd_noinc_table; int (*reg_read)(void *context, unsigned int reg, unsigned int *val); @@ -149,7 +151,7 @@ struct regmap { /* if set, converts bulk read to single read */ bool use_single_read; - /* if set, converts bulk read to single read */ + /* if set, converts bulk write to single write */ bool use_single_write; /* if set, the device supports multi write mode */ bool can_multi_write; @@ -183,6 +185,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg); bool regmap_readable(struct regmap *map, unsigned int reg); bool regmap_volatile(struct regmap *map, unsigned int reg); bool regmap_precious(struct regmap *map, unsigned int reg); +bool regmap_writeable_noinc(struct regmap *map, unsigned int reg); bool regmap_readable_noinc(struct regmap *map, unsigned int reg); int _regmap_write(struct regmap *map, unsigned int reg, diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 0360a90ad6b6..4f822e087def 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -35,6 +35,16 @@ */ #undef LOG_DEVICE +#ifdef LOG_DEVICE +static inline bool regmap_should_log(struct regmap *map) +{ + return (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0); +} +#else +static inline bool regmap_should_log(struct regmap *map) { return false; } +#endif + + static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change, bool force_write); @@ -168,6 +178,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg) return false; } +bool regmap_writeable_noinc(struct regmap *map, unsigned int reg) +{ + if (map->writeable_noinc_reg) + return map->writeable_noinc_reg(map->dev, reg); + + if (map->wr_noinc_table) + return regmap_check_range_table(map, reg, map->wr_noinc_table); + + return true; +} + bool regmap_readable_noinc(struct regmap *map, unsigned int reg) { if (map->readable_noinc_reg) @@ -762,8 +783,8 @@ struct regmap *__regmap_init(struct device *dev, map->reg_stride_order = ilog2(map->reg_stride); else map->reg_stride_order = -1; - map->use_single_read = config->use_single_rw || !bus || !bus->read; - map->use_single_write = config->use_single_rw || !bus || !bus->write; + map->use_single_read = config->use_single_read || !bus || !bus->read; + map->use_single_write = config->use_single_write || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; if (bus) { map->max_raw_read = bus->max_raw_read; @@ -777,11 +798,13 @@ struct regmap *__regmap_init(struct device *dev, map->rd_table = config->rd_table; map->volatile_table = config->volatile_table; map->precious_table = config->precious_table; + map->wr_noinc_table = config->wr_noinc_table; map->rd_noinc_table = config->rd_noinc_table; map->writeable_reg = config->writeable_reg; map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; + map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; map->cache_type = config->cache_type; @@ -1298,6 +1321,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; + map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; map->cache_type = config->cache_type; @@ -1755,10 +1779,8 @@ int _regmap_write(struct regmap *map, unsigned int reg, } } -#ifdef LOG_DEVICE - if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + if (regmap_should_log(map)) dev_info(map->dev, "%x <= %x\n", reg, val); -#endif trace_regmap_reg_write(map, reg, val); @@ -1898,6 +1920,69 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_raw_write); /** + * regmap_noinc_write(): Write data from a register without incrementing the + * register number + * + * @map: Register map to write to + * @reg: Register to write to + * @val: Pointer to data buffer + * @val_len: Length of output buffer in bytes. + * + * The regmap API usually assumes that bulk bus write operations will write a + * range of registers. Some devices have certain registers for which a write + * operation can write to an internal FIFO. + * + * The target register must be volatile but registers after it can be + * completely unrelated cacheable registers. + * + * This will attempt multiple writes as required to write val_len bytes. + * + * A value of zero will be returned on success, a negative errno will be + * returned in error cases. + */ +int regmap_noinc_write(struct regmap *map, unsigned int reg, + const void *val, size_t val_len) +{ + size_t write_len; + int ret; + + if (!map->bus) + return -EINVAL; + if (!map->bus->write) + return -ENOTSUPP; + if (val_len % map->format.val_bytes) + return -EINVAL; + if (!IS_ALIGNED(reg, map->reg_stride)) + return -EINVAL; + if (val_len == 0) + return -EINVAL; + + map->lock(map->lock_arg); + + if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg)) { + ret = -EINVAL; + goto out_unlock; + } + + while (val_len) { + if (map->max_raw_write && map->max_raw_write < val_len) + write_len = map->max_raw_write; + else + write_len = val_len; + ret = _regmap_raw_write(map, reg, val, write_len); + if (ret) + goto out_unlock; + val = ((u8 *)val) + write_len; + val_len -= write_len; + } + +out_unlock: + map->unlock(map->lock_arg); + return ret; +} +EXPORT_SYMBOL_GPL(regmap_noinc_write); + +/** * regmap_field_update_bits_base() - Perform a read/modify/write cycle a * register field. * @@ -2450,10 +2535,8 @@ static int _regmap_read(struct regmap *map, unsigned int reg, ret = map->reg_read(context, reg, val); if (ret == 0) { -#ifdef LOG_DEVICE - if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + if (regmap_should_log(map)) dev_info(map->dev, "%x => %x\n", reg, *val); -#endif trace_regmap_reg_read(map, reg, *val); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c deleted file mode 100644 index 581312ac375f..000000000000 --- a/drivers/block/DAC960.c +++ /dev/null @@ -1,7229 +0,0 @@ -/* - - Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - - Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com> - Portions Copyright 2002 by Mylex (An IBM Business Unit) - - This program is free software; you may redistribute and/or modify it under - the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for complete details. - -*/ - - -#define DAC960_DriverVersion "2.5.49" -#define DAC960_DriverDate "21 Aug 2007" - - -#include <linux/compiler.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/miscdevice.h> -#include <linux/blkdev.h> -#include <linux/bio.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/genhd.h> -#include <linux/hdreg.h> -#include <linux/blkpg.h> -#include <linux/dma-mapping.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/reboot.h> -#include <linux/spinlock.h> -#include <linux/timer.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/jiffies.h> -#include <linux/random.h> -#include <linux/scatterlist.h> -#include <asm/io.h> -#include <linux/uaccess.h> -#include "DAC960.h" - -#define DAC960_GAM_MINOR 252 - - -static DEFINE_MUTEX(DAC960_mutex); -static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers]; -static int DAC960_ControllerCount; -static struct proc_dir_entry *DAC960_ProcDirectoryEntry; - -static long disk_size(DAC960_Controller_T *p, int drive_nr) -{ - if (p->FirmwareType == DAC960_V1_Controller) { - if (drive_nr >= p->LogicalDriveCount) - return 0; - return p->V1.LogicalDriveInformation[drive_nr]. - LogicalDriveSize; - } else { - DAC960_V2_LogicalDeviceInfo_T *i = - p->V2.LogicalDeviceInformation[drive_nr]; - if (i == NULL) - return 0; - return i->ConfigurableDeviceSize; - } -} - -static int DAC960_open(struct block_device *bdev, fmode_t mode) -{ - struct gendisk *disk = bdev->bd_disk; - DAC960_Controller_T *p = disk->queue->queuedata; - int drive_nr = (long)disk->private_data; - int ret = -ENXIO; - - mutex_lock(&DAC960_mutex); - if (p->FirmwareType == DAC960_V1_Controller) { - if (p->V1.LogicalDriveInformation[drive_nr]. - LogicalDriveState == DAC960_V1_LogicalDrive_Offline) - goto out; - } else { - DAC960_V2_LogicalDeviceInfo_T *i = - p->V2.LogicalDeviceInformation[drive_nr]; - if (!i || i->LogicalDeviceState == DAC960_V2_LogicalDevice_Offline) - goto out; - } - - check_disk_change(bdev); - - if (!get_capacity(p->disks[drive_nr])) - goto out; - ret = 0; -out: - mutex_unlock(&DAC960_mutex); - return ret; -} - -static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct gendisk *disk = bdev->bd_disk; - DAC960_Controller_T *p = disk->queue->queuedata; - int drive_nr = (long)disk->private_data; - - if (p->FirmwareType == DAC960_V1_Controller) { - geo->heads = p->V1.GeometryTranslationHeads; - geo->sectors = p->V1.GeometryTranslationSectors; - geo->cylinders = p->V1.LogicalDriveInformation[drive_nr]. - LogicalDriveSize / (geo->heads * geo->sectors); - } else { - DAC960_V2_LogicalDeviceInfo_T *i = - p->V2.LogicalDeviceInformation[drive_nr]; - switch (i->DriveGeometry) { - case DAC960_V2_Geometry_128_32: - geo->heads = 128; - geo->sectors = 32; - break; - case DAC960_V2_Geometry_255_63: - geo->heads = 255; - geo->sectors = 63; - break; - default: - DAC960_Error("Illegal Logical Device Geometry %d\n", - p, i->DriveGeometry); - return -EINVAL; - } - - geo->cylinders = i->ConfigurableDeviceSize / - (geo->heads * geo->sectors); - } - - return 0; -} - -static unsigned int DAC960_check_events(struct gendisk *disk, - unsigned int clearing) -{ - DAC960_Controller_T *p = disk->queue->queuedata; - int drive_nr = (long)disk->private_data; - - if (!p->LogicalDriveInitiallyAccessible[drive_nr]) - return DISK_EVENT_MEDIA_CHANGE; - return 0; -} - -static int DAC960_revalidate_disk(struct gendisk *disk) -{ - DAC960_Controller_T *p = disk->queue->queuedata; - int unit = (long)disk->private_data; - - set_capacity(disk, disk_size(p, unit)); - return 0; -} - -static const struct block_device_operations DAC960_BlockDeviceOperations = { - .owner = THIS_MODULE, - .open = DAC960_open, - .getgeo = DAC960_getgeo, - .check_events = DAC960_check_events, - .revalidate_disk = DAC960_revalidate_disk, -}; - - -/* - DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name, - Copyright Notice, and Electronic Mail Address. -*/ - -static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller) -{ - DAC960_Announce("***** DAC960 RAID Driver Version " - DAC960_DriverVersion " of " - DAC960_DriverDate " *****\n", Controller); - DAC960_Announce("Copyright 1998-2001 by Leonard N. Zubkoff " - "<lnz@dandelion.com>\n", Controller); -} - - -/* - DAC960_Failure prints a standardized error message, and then returns false. -*/ - -static bool DAC960_Failure(DAC960_Controller_T *Controller, - unsigned char *ErrorMessage) -{ - DAC960_Error("While configuring DAC960 PCI RAID Controller at\n", - Controller); - if (Controller->IO_Address == 0) - DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " - "PCI Address 0x%X\n", Controller, - Controller->Bus, Controller->Device, - Controller->Function, Controller->PCI_Address); - else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " - "0x%X PCI Address 0x%X\n", Controller, - Controller->Bus, Controller->Device, - Controller->Function, Controller->IO_Address, - Controller->PCI_Address); - DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage); - return false; -} - -/* - init_dma_loaf() and slice_dma_loaf() are helper functions for - aggregating the dma-mapped memory for a well-known collection of - data structures that are of different lengths. - - These routines don't guarantee any alignment. The caller must - include any space needed for alignment in the sizes of the structures - that are passed in. - */ - -static bool init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf, - size_t len) -{ - void *cpu_addr; - dma_addr_t dma_handle; - - cpu_addr = pci_alloc_consistent(dev, len, &dma_handle); - if (cpu_addr == NULL) - return false; - - loaf->cpu_free = loaf->cpu_base = cpu_addr; - loaf->dma_free =loaf->dma_base = dma_handle; - loaf->length = len; - memset(cpu_addr, 0, len); - return true; -} - -static void *slice_dma_loaf(struct dma_loaf *loaf, size_t len, - dma_addr_t *dma_handle) -{ - void *cpu_end = loaf->cpu_free + len; - void *cpu_addr = loaf->cpu_free; - - BUG_ON(cpu_end > loaf->cpu_base + loaf->length); - *dma_handle = loaf->dma_free; - loaf->cpu_free = cpu_end; - loaf->dma_free += len; - return cpu_addr; -} - -static void free_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf_handle) -{ - if (loaf_handle->cpu_base != NULL) - pci_free_consistent(dev, loaf_handle->length, - loaf_handle->cpu_base, loaf_handle->dma_base); -} - - -/* - DAC960_CreateAuxiliaryStructures allocates and initializes the auxiliary - data structures for Controller. It returns true on success and false on - failure. -*/ - -static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) -{ - int CommandAllocationLength, CommandAllocationGroupSize; - int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount; - void *AllocationPointer = NULL; - void *ScatterGatherCPU = NULL; - dma_addr_t ScatterGatherDMA; - struct dma_pool *ScatterGatherPool; - void *RequestSenseCPU = NULL; - dma_addr_t RequestSenseDMA; - struct dma_pool *RequestSensePool = NULL; - - if (Controller->FirmwareType == DAC960_V1_Controller) - { - CommandAllocationLength = offsetof(DAC960_Command_T, V1.EndMarker); - CommandAllocationGroupSize = DAC960_V1_CommandAllocationGroupSize; - ScatterGatherPool = dma_pool_create("DAC960_V1_ScatterGather", - &Controller->PCIDevice->dev, - DAC960_V1_ScatterGatherLimit * sizeof(DAC960_V1_ScatterGatherSegment_T), - sizeof(DAC960_V1_ScatterGatherSegment_T), 0); - if (ScatterGatherPool == NULL) - return DAC960_Failure(Controller, - "AUXILIARY STRUCTURE CREATION (SG)"); - Controller->ScatterGatherPool = ScatterGatherPool; - } - else - { - CommandAllocationLength = offsetof(DAC960_Command_T, V2.EndMarker); - CommandAllocationGroupSize = DAC960_V2_CommandAllocationGroupSize; - ScatterGatherPool = dma_pool_create("DAC960_V2_ScatterGather", - &Controller->PCIDevice->dev, - DAC960_V2_ScatterGatherLimit * sizeof(DAC960_V2_ScatterGatherSegment_T), - sizeof(DAC960_V2_ScatterGatherSegment_T), 0); - if (ScatterGatherPool == NULL) - return DAC960_Failure(Controller, - "AUXILIARY STRUCTURE CREATION (SG)"); - RequestSensePool = dma_pool_create("DAC960_V2_RequestSense", - &Controller->PCIDevice->dev, sizeof(DAC960_SCSI_RequestSense_T), - sizeof(int), 0); - if (RequestSensePool == NULL) { - dma_pool_destroy(ScatterGatherPool); - return DAC960_Failure(Controller, - "AUXILIARY STRUCTURE CREATION (SG)"); - } - Controller->ScatterGatherPool = ScatterGatherPool; - Controller->V2.RequestSensePool = RequestSensePool; - } - Controller->CommandAllocationGroupSize = CommandAllocationGroupSize; - Controller->FreeCommands = NULL; - for (CommandIdentifier = 1; - CommandIdentifier <= Controller->DriverQueueDepth; - CommandIdentifier++) - { - DAC960_Command_T *Command; - if (--CommandsRemaining <= 0) - { - CommandsRemaining = - Controller->DriverQueueDepth - CommandIdentifier + 1; - if (CommandsRemaining > CommandAllocationGroupSize) - CommandsRemaining = CommandAllocationGroupSize; - CommandGroupByteCount = - CommandsRemaining * CommandAllocationLength; - AllocationPointer = kzalloc(CommandGroupByteCount, GFP_ATOMIC); - if (AllocationPointer == NULL) - return DAC960_Failure(Controller, - "AUXILIARY STRUCTURE CREATION"); - } - Command = (DAC960_Command_T *) AllocationPointer; - AllocationPointer += CommandAllocationLength; - Command->CommandIdentifier = CommandIdentifier; - Command->Controller = Controller; - Command->Next = Controller->FreeCommands; - Controller->FreeCommands = Command; - Controller->Commands[CommandIdentifier-1] = Command; - ScatterGatherCPU = dma_pool_alloc(ScatterGatherPool, GFP_ATOMIC, - &ScatterGatherDMA); - if (ScatterGatherCPU == NULL) - return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION"); - - if (RequestSensePool != NULL) { - RequestSenseCPU = dma_pool_alloc(RequestSensePool, GFP_ATOMIC, - &RequestSenseDMA); - if (RequestSenseCPU == NULL) { - dma_pool_free(ScatterGatherPool, ScatterGatherCPU, - ScatterGatherDMA); - return DAC960_Failure(Controller, - "AUXILIARY STRUCTURE CREATION"); - } - } - if (Controller->FirmwareType == DAC960_V1_Controller) { - Command->cmd_sglist = Command->V1.ScatterList; - Command->V1.ScatterGatherList = - (DAC960_V1_ScatterGatherSegment_T *)ScatterGatherCPU; - Command->V1.ScatterGatherListDMA = ScatterGatherDMA; - sg_init_table(Command->cmd_sglist, DAC960_V1_ScatterGatherLimit); - } else { - Command->cmd_sglist = Command->V2.ScatterList; - Command->V2.ScatterGatherList = - (DAC960_V2_ScatterGatherSegment_T *)ScatterGatherCPU; - Command->V2.ScatterGatherListDMA = ScatterGatherDMA; - Command->V2.RequestSense = - (DAC960_SCSI_RequestSense_T *)RequestSenseCPU; - Command->V2.RequestSenseDMA = RequestSenseDMA; - sg_init_table(Command->cmd_sglist, DAC960_V2_ScatterGatherLimit); - } - } - return true; -} - - -/* - DAC960_DestroyAuxiliaryStructures deallocates the auxiliary data - structures for Controller. -*/ - -static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller) -{ - int i; - struct dma_pool *ScatterGatherPool = Controller->ScatterGatherPool; - struct dma_pool *RequestSensePool = NULL; - void *ScatterGatherCPU; - dma_addr_t ScatterGatherDMA; - void *RequestSenseCPU; - dma_addr_t RequestSenseDMA; - DAC960_Command_T *CommandGroup = NULL; - - - if (Controller->FirmwareType == DAC960_V2_Controller) - RequestSensePool = Controller->V2.RequestSensePool; - - Controller->FreeCommands = NULL; - for (i = 0; i < Controller->DriverQueueDepth; i++) - { - DAC960_Command_T *Command = Controller->Commands[i]; - - if (Command == NULL) - continue; - - if (Controller->FirmwareType == DAC960_V1_Controller) { - ScatterGatherCPU = (void *)Command->V1.ScatterGatherList; - ScatterGatherDMA = Command->V1.ScatterGatherListDMA; - RequestSenseCPU = NULL; - RequestSenseDMA = (dma_addr_t)0; - } else { - ScatterGatherCPU = (void *)Command->V2.ScatterGatherList; - ScatterGatherDMA = Command->V2.ScatterGatherListDMA; - RequestSenseCPU = (void *)Command->V2.RequestSense; - RequestSenseDMA = Command->V2.RequestSenseDMA; - } - if (ScatterGatherCPU != NULL) - dma_pool_free(ScatterGatherPool, ScatterGatherCPU, ScatterGatherDMA); - if (RequestSenseCPU != NULL) - dma_pool_free(RequestSensePool, RequestSenseCPU, RequestSenseDMA); - - if ((Command->CommandIdentifier - % Controller->CommandAllocationGroupSize) == 1) { - /* - * We can't free the group of commands until all of the - * request sense and scatter gather dma structures are free. - * Remember the beginning of the group, but don't free it - * until we've reached the beginning of the next group. - */ - kfree(CommandGroup); - CommandGroup = Command; - } - Controller->Commands[i] = NULL; - } - kfree(CommandGroup); - - if (Controller->CombinedStatusBuffer != NULL) - { - kfree(Controller->CombinedStatusBuffer); - Controller->CombinedStatusBuffer = NULL; - Controller->CurrentStatusBuffer = NULL; - } - - dma_pool_destroy(ScatterGatherPool); - if (Controller->FirmwareType == DAC960_V1_Controller) - return; - - dma_pool_destroy(RequestSensePool); - - for (i = 0; i < DAC960_MaxLogicalDrives; i++) { - kfree(Controller->V2.LogicalDeviceInformation[i]); - Controller->V2.LogicalDeviceInformation[i] = NULL; - } - - for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++) - { - kfree(Controller->V2.PhysicalDeviceInformation[i]); - Controller->V2.PhysicalDeviceInformation[i] = NULL; - kfree(Controller->V2.InquiryUnitSerialNumber[i]); - Controller->V2.InquiryUnitSerialNumber[i] = NULL; - } -} - - -/* - DAC960_V1_ClearCommand clears critical fields of Command for DAC960 V1 - Firmware Controllers. -*/ - -static inline void DAC960_V1_ClearCommand(DAC960_Command_T *Command) -{ - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - memset(CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T)); - Command->V1.CommandStatus = 0; -} - - -/* - DAC960_V2_ClearCommand clears critical fields of Command for DAC960 V2 - Firmware Controllers. -*/ - -static inline void DAC960_V2_ClearCommand(DAC960_Command_T *Command) -{ - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T)); - Command->V2.CommandStatus = 0; -} - - -/* - DAC960_AllocateCommand allocates a Command structure from Controller's - free list. During driver initialization, a special initialization command - has been placed on the free list to guarantee that command allocation can - never fail. -*/ - -static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T - *Controller) -{ - DAC960_Command_T *Command = Controller->FreeCommands; - if (Command == NULL) return NULL; - Controller->FreeCommands = Command->Next; - Command->Next = NULL; - return Command; -} - - -/* - DAC960_DeallocateCommand deallocates Command, returning it to Controller's - free list. -*/ - -static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - - Command->Request = NULL; - Command->Next = Controller->FreeCommands; - Controller->FreeCommands = Command; -} - - -/* - DAC960_WaitForCommand waits for a wake_up on Controller's Command Wait Queue. -*/ - -static void DAC960_WaitForCommand(DAC960_Controller_T *Controller) -{ - spin_unlock_irq(&Controller->queue_lock); - __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands); - spin_lock_irq(&Controller->queue_lock); -} - -/* - DAC960_GEM_QueueCommand queues Command for DAC960 GEM Series Controllers. -*/ - -static void DAC960_GEM_QueueCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandMailbox_T *NextCommandMailbox = - Controller->V2.NextCommandMailbox; - - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - DAC960_GEM_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); - - if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 || - Controller->V2.PreviousCommandMailbox2->Words[0] == 0) - DAC960_GEM_MemoryMailboxNewCommand(ControllerBaseAddress); - - Controller->V2.PreviousCommandMailbox2 = - Controller->V2.PreviousCommandMailbox1; - Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox; - - if (++NextCommandMailbox > Controller->V2.LastCommandMailbox) - NextCommandMailbox = Controller->V2.FirstCommandMailbox; - - Controller->V2.NextCommandMailbox = NextCommandMailbox; -} - -/* - DAC960_BA_QueueCommand queues Command for DAC960 BA Series Controllers. -*/ - -static void DAC960_BA_QueueCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandMailbox_T *NextCommandMailbox = - Controller->V2.NextCommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - DAC960_BA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); - if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 || - Controller->V2.PreviousCommandMailbox2->Words[0] == 0) - DAC960_BA_MemoryMailboxNewCommand(ControllerBaseAddress); - Controller->V2.PreviousCommandMailbox2 = - Controller->V2.PreviousCommandMailbox1; - Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox; - if (++NextCommandMailbox > Controller->V2.LastCommandMailbox) - NextCommandMailbox = Controller->V2.FirstCommandMailbox; - Controller->V2.NextCommandMailbox = NextCommandMailbox; -} - - -/* - DAC960_LP_QueueCommand queues Command for DAC960 LP Series Controllers. -*/ - -static void DAC960_LP_QueueCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandMailbox_T *NextCommandMailbox = - Controller->V2.NextCommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - DAC960_LP_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); - if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 || - Controller->V2.PreviousCommandMailbox2->Words[0] == 0) - DAC960_LP_MemoryMailboxNewCommand(ControllerBaseAddress); - Controller->V2.PreviousCommandMailbox2 = - Controller->V2.PreviousCommandMailbox1; - Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox; - if (++NextCommandMailbox > Controller->V2.LastCommandMailbox) - NextCommandMailbox = Controller->V2.FirstCommandMailbox; - Controller->V2.NextCommandMailbox = NextCommandMailbox; -} - - -/* - DAC960_LA_QueueCommandDualMode queues Command for DAC960 LA Series - Controllers with Dual Mode Firmware. -*/ - -static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandMailbox_T *NextCommandMailbox = - Controller->V1.NextCommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); - if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 || - Controller->V1.PreviousCommandMailbox2->Words[0] == 0) - DAC960_LA_MemoryMailboxNewCommand(ControllerBaseAddress); - Controller->V1.PreviousCommandMailbox2 = - Controller->V1.PreviousCommandMailbox1; - Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox; - if (++NextCommandMailbox > Controller->V1.LastCommandMailbox) - NextCommandMailbox = Controller->V1.FirstCommandMailbox; - Controller->V1.NextCommandMailbox = NextCommandMailbox; -} - - -/* - DAC960_LA_QueueCommandSingleMode queues Command for DAC960 LA Series - Controllers with Single Mode Firmware. -*/ - -static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandMailbox_T *NextCommandMailbox = - Controller->V1.NextCommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); - if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 || - Controller->V1.PreviousCommandMailbox2->Words[0] == 0) - DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress); - Controller->V1.PreviousCommandMailbox2 = - Controller->V1.PreviousCommandMailbox1; - Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox; - if (++NextCommandMailbox > Controller->V1.LastCommandMailbox) - NextCommandMailbox = Controller->V1.FirstCommandMailbox; - Controller->V1.NextCommandMailbox = NextCommandMailbox; -} - - -/* - DAC960_PG_QueueCommandDualMode queues Command for DAC960 PG Series - Controllers with Dual Mode Firmware. -*/ - -static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandMailbox_T *NextCommandMailbox = - Controller->V1.NextCommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); - if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 || - Controller->V1.PreviousCommandMailbox2->Words[0] == 0) - DAC960_PG_MemoryMailboxNewCommand(ControllerBaseAddress); - Controller->V1.PreviousCommandMailbox2 = - Controller->V1.PreviousCommandMailbox1; - Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox; - if (++NextCommandMailbox > Controller->V1.LastCommandMailbox) - NextCommandMailbox = Controller->V1.FirstCommandMailbox; - Controller->V1.NextCommandMailbox = NextCommandMailbox; -} - - -/* - DAC960_PG_QueueCommandSingleMode queues Command for DAC960 PG Series - Controllers with Single Mode Firmware. -*/ - -static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandMailbox_T *NextCommandMailbox = - Controller->V1.NextCommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); - if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 || - Controller->V1.PreviousCommandMailbox2->Words[0] == 0) - DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress); - Controller->V1.PreviousCommandMailbox2 = - Controller->V1.PreviousCommandMailbox1; - Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox; - if (++NextCommandMailbox > Controller->V1.LastCommandMailbox) - NextCommandMailbox = Controller->V1.FirstCommandMailbox; - Controller->V1.NextCommandMailbox = NextCommandMailbox; -} - - -/* - DAC960_PD_QueueCommand queues Command for DAC960 PD Series Controllers. -*/ - -static void DAC960_PD_QueueCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - while (DAC960_PD_MailboxFullP(ControllerBaseAddress)) - udelay(1); - DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox); - DAC960_PD_NewCommand(ControllerBaseAddress); -} - - -/* - DAC960_P_QueueCommand queues Command for DAC960 P Series Controllers. -*/ - -static void DAC960_P_QueueCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier; - switch (CommandMailbox->Common.CommandOpcode) - { - case DAC960_V1_Enquiry: - CommandMailbox->Common.CommandOpcode = DAC960_V1_Enquiry_Old; - break; - case DAC960_V1_GetDeviceState: - CommandMailbox->Common.CommandOpcode = DAC960_V1_GetDeviceState_Old; - break; - case DAC960_V1_Read: - CommandMailbox->Common.CommandOpcode = DAC960_V1_Read_Old; - DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox); - break; - case DAC960_V1_Write: - CommandMailbox->Common.CommandOpcode = DAC960_V1_Write_Old; - DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox); - break; - case DAC960_V1_ReadWithScatterGather: - CommandMailbox->Common.CommandOpcode = - DAC960_V1_ReadWithScatterGather_Old; - DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox); - break; - case DAC960_V1_WriteWithScatterGather: - CommandMailbox->Common.CommandOpcode = - DAC960_V1_WriteWithScatterGather_Old; - DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox); - break; - default: - break; - } - while (DAC960_PD_MailboxFullP(ControllerBaseAddress)) - udelay(1); - DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox); - DAC960_PD_NewCommand(ControllerBaseAddress); -} - - -/* - DAC960_ExecuteCommand executes Command and waits for completion. -*/ - -static void DAC960_ExecuteCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - DECLARE_COMPLETION_ONSTACK(Completion); - unsigned long flags; - Command->Completion = &Completion; - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_QueueCommand(Command); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - - if (in_interrupt()) - return; - wait_for_completion(&Completion); -} - - -/* - DAC960_V1_ExecuteType3 executes a DAC960 V1 Firmware Controller Type 3 - Command and waits for completion. It returns true on success and false - on failure. -*/ - -static bool DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller, - DAC960_V1_CommandOpcode_T CommandOpcode, - dma_addr_t DataDMA) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->Type3.CommandOpcode = CommandOpcode; - CommandMailbox->Type3.BusAddress = DataDMA; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V1.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V1_NormalCompletion); -} - - -/* - DAC960_V1_ExecuteTypeB executes a DAC960 V1 Firmware Controller Type 3B - Command and waits for completion. It returns true on success and false - on failure. -*/ - -static bool DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller, - DAC960_V1_CommandOpcode_T CommandOpcode, - unsigned char CommandOpcode2, - dma_addr_t DataDMA) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->Type3B.CommandOpcode = CommandOpcode; - CommandMailbox->Type3B.CommandOpcode2 = CommandOpcode2; - CommandMailbox->Type3B.BusAddress = DataDMA; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V1.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V1_NormalCompletion); -} - - -/* - DAC960_V1_ExecuteType3D executes a DAC960 V1 Firmware Controller Type 3D - Command and waits for completion. It returns true on success and false - on failure. -*/ - -static bool DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller, - DAC960_V1_CommandOpcode_T CommandOpcode, - unsigned char Channel, - unsigned char TargetID, - dma_addr_t DataDMA) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->Type3D.CommandOpcode = CommandOpcode; - CommandMailbox->Type3D.Channel = Channel; - CommandMailbox->Type3D.TargetID = TargetID; - CommandMailbox->Type3D.BusAddress = DataDMA; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V1.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V1_NormalCompletion); -} - - -/* - DAC960_V2_GeneralInfo executes a DAC960 V2 Firmware General Information - Reading IOCTL Command and waits for completion. It returns true on success - and false on failure. - - Return data in The controller's HealthStatusBuffer, which is dma-able memory -*/ - -static bool DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->Common.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->Common.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->Common.DataTransferSize = sizeof(DAC960_V2_HealthStatusBuffer_T); - CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_GetHealthStatus; - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.HealthStatusBufferDMA; - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->Common.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); -} - - -/* - DAC960_V2_ControllerInfo executes a DAC960 V2 Firmware Controller - Information Reading IOCTL Command and waits for completion. It returns - true on success and false on failure. - - Data is returned in the controller's V2.NewControllerInformation dma-able - memory buffer. -*/ - -static bool DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->ControllerInfo.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->ControllerInfo.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->ControllerInfo.DataTransferSize = sizeof(DAC960_V2_ControllerInfo_T); - CommandMailbox->ControllerInfo.ControllerNumber = 0; - CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo; - CommandMailbox->ControllerInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewControllerInformationDMA; - CommandMailbox->ControllerInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->ControllerInfo.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); -} - - -/* - DAC960_V2_LogicalDeviceInfo executes a DAC960 V2 Firmware Controller Logical - Device Information Reading IOCTL Command and waits for completion. It - returns true on success and false on failure. - - Data is returned in the controller's V2.NewLogicalDeviceInformation -*/ - -static bool DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller, - unsigned short LogicalDeviceNumber) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->LogicalDeviceInfo.CommandOpcode = - DAC960_V2_IOCTL; - CommandMailbox->LogicalDeviceInfo.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->LogicalDeviceInfo.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->LogicalDeviceInfo.DataTransferSize = - sizeof(DAC960_V2_LogicalDeviceInfo_T); - CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = - LogicalDeviceNumber; - CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = DAC960_V2_GetLogicalDeviceInfoValid; - CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewLogicalDeviceInformationDMA; - CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->LogicalDeviceInfo.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); -} - - -/* - DAC960_V2_PhysicalDeviceInfo executes a DAC960 V2 Firmware Controller "Read - Physical Device Information" IOCTL Command and waits for completion. It - returns true on success and false on failure. - - The Channel, TargetID, LogicalUnit arguments should be 0 the first time - this function is called for a given controller. This will return data - for the "first" device on that controller. The returned data includes a - Channel, TargetID, LogicalUnit that can be passed in to this routine to - get data for the NEXT device on that controller. - - Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able - memory buffer. - -*/ - -static bool DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller, - unsigned char Channel, - unsigned char TargetID, - unsigned char LogicalUnit) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->PhysicalDeviceInfo.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->PhysicalDeviceInfo.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->PhysicalDeviceInfo.DataTransferSize = - sizeof(DAC960_V2_PhysicalDeviceInfo_T); - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel; - CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = - DAC960_V2_GetPhysicalDeviceInfoValid; - CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewPhysicalDeviceInformationDMA; - CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->PhysicalDeviceInfo.DataTransferSize; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); -} - - -static void DAC960_V2_ConstructNewUnitSerialNumber( - DAC960_Controller_T *Controller, - DAC960_V2_CommandMailbox_T *CommandMailbox, int Channel, int TargetID, - int LogicalUnit) -{ - CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10_Passthru; - CommandMailbox->SCSI_10.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->SCSI_10.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->SCSI_10.DataTransferSize = - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = LogicalUnit; - CommandMailbox->SCSI_10.PhysicalDevice.TargetID = TargetID; - CommandMailbox->SCSI_10.PhysicalDevice.Channel = Channel; - CommandMailbox->SCSI_10.CDBLength = 6; - CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */ - CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */ - CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */ - CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */ - CommandMailbox->SCSI_10.SCSI_CDB[4] = - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */ - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewInquiryUnitSerialNumberDMA; - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->SCSI_10.DataTransferSize; -} - - -/* - DAC960_V2_NewUnitSerialNumber executes an SCSI pass-through - Inquiry command to a SCSI device identified by Channel number, - Target id, Logical Unit Number. This function Waits for completion - of the command. - - The return data includes Unit Serial Number information for the - specified device. - - Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able - memory buffer. -*/ - -static bool DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller, - int Channel, int TargetID, int LogicalUnit) -{ - DAC960_Command_T *Command; - DAC960_V2_CommandMailbox_T *CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - - Command = DAC960_AllocateCommand(Controller); - CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - - DAC960_V2_ConstructNewUnitSerialNumber(Controller, CommandMailbox, - Channel, TargetID, LogicalUnit); - - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); -} - - -/* - DAC960_V2_DeviceOperation executes a DAC960 V2 Firmware Controller Device - Operation IOCTL Command and waits for completion. It returns true on - success and false on failure. -*/ - -static bool DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller, - DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode, - DAC960_V2_OperationDevice_T - OperationDevice) -{ - DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->DeviceOperation.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->DeviceOperation.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->DeviceOperation.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->DeviceOperation.IOCTL_Opcode = IOCTL_Opcode; - CommandMailbox->DeviceOperation.OperationDevice = OperationDevice; - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - DAC960_DeallocateCommand(Command); - return (CommandStatus == DAC960_V2_NormalCompletion); -} - - -/* - DAC960_V1_EnableMemoryMailboxInterface enables the Memory Mailbox Interface - for DAC960 V1 Firmware Controllers. - - PD and P controller types have no memory mailbox, but still need the - other dma mapped memory. -*/ - -static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T - *Controller) -{ - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_HardwareType_T hw_type = Controller->HardwareType; - struct pci_dev *PCI_Device = Controller->PCIDevice; - struct dma_loaf *DmaPages = &Controller->DmaPages; - size_t DmaPagesSize; - size_t CommandMailboxesSize; - size_t StatusMailboxesSize; - - DAC960_V1_CommandMailbox_T *CommandMailboxesMemory; - dma_addr_t CommandMailboxesMemoryDMA; - - DAC960_V1_StatusMailbox_T *StatusMailboxesMemory; - dma_addr_t StatusMailboxesMemoryDMA; - - DAC960_V1_CommandMailbox_T CommandMailbox; - DAC960_V1_CommandStatus_T CommandStatus; - int TimeoutCounter; - int i; - - memset(&CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T)); - - if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) - return DAC960_Failure(Controller, "DMA mask out of range"); - - if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) { - CommandMailboxesSize = 0; - StatusMailboxesSize = 0; - } else { - CommandMailboxesSize = DAC960_V1_CommandMailboxCount * sizeof(DAC960_V1_CommandMailbox_T); - StatusMailboxesSize = DAC960_V1_StatusMailboxCount * sizeof(DAC960_V1_StatusMailbox_T); - } - DmaPagesSize = CommandMailboxesSize + StatusMailboxesSize + - sizeof(DAC960_V1_DCDB_T) + sizeof(DAC960_V1_Enquiry_T) + - sizeof(DAC960_V1_ErrorTable_T) + sizeof(DAC960_V1_EventLogEntry_T) + - sizeof(DAC960_V1_RebuildProgress_T) + - sizeof(DAC960_V1_LogicalDriveInformationArray_T) + - sizeof(DAC960_V1_BackgroundInitializationStatus_T) + - sizeof(DAC960_V1_DeviceState_T) + sizeof(DAC960_SCSI_Inquiry_T) + - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - - if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize)) - return false; - - - if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) - goto skip_mailboxes; - - CommandMailboxesMemory = slice_dma_loaf(DmaPages, - CommandMailboxesSize, &CommandMailboxesMemoryDMA); - - /* These are the base addresses for the command memory mailbox array */ - Controller->V1.FirstCommandMailbox = CommandMailboxesMemory; - Controller->V1.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA; - - CommandMailboxesMemory += DAC960_V1_CommandMailboxCount - 1; - Controller->V1.LastCommandMailbox = CommandMailboxesMemory; - Controller->V1.NextCommandMailbox = Controller->V1.FirstCommandMailbox; - Controller->V1.PreviousCommandMailbox1 = Controller->V1.LastCommandMailbox; - Controller->V1.PreviousCommandMailbox2 = - Controller->V1.LastCommandMailbox - 1; - - /* These are the base addresses for the status memory mailbox array */ - StatusMailboxesMemory = slice_dma_loaf(DmaPages, - StatusMailboxesSize, &StatusMailboxesMemoryDMA); - - Controller->V1.FirstStatusMailbox = StatusMailboxesMemory; - Controller->V1.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA; - StatusMailboxesMemory += DAC960_V1_StatusMailboxCount - 1; - Controller->V1.LastStatusMailbox = StatusMailboxesMemory; - Controller->V1.NextStatusMailbox = Controller->V1.FirstStatusMailbox; - -skip_mailboxes: - Controller->V1.MonitoringDCDB = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_DCDB_T), - &Controller->V1.MonitoringDCDB_DMA); - - Controller->V1.NewEnquiry = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_Enquiry_T), - &Controller->V1.NewEnquiryDMA); - - Controller->V1.NewErrorTable = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_ErrorTable_T), - &Controller->V1.NewErrorTableDMA); - - Controller->V1.EventLogEntry = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_EventLogEntry_T), - &Controller->V1.EventLogEntryDMA); - - Controller->V1.RebuildProgress = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_RebuildProgress_T), - &Controller->V1.RebuildProgressDMA); - - Controller->V1.NewLogicalDriveInformation = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_LogicalDriveInformationArray_T), - &Controller->V1.NewLogicalDriveInformationDMA); - - Controller->V1.BackgroundInitializationStatus = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_BackgroundInitializationStatus_T), - &Controller->V1.BackgroundInitializationStatusDMA); - - Controller->V1.NewDeviceState = slice_dma_loaf(DmaPages, - sizeof(DAC960_V1_DeviceState_T), - &Controller->V1.NewDeviceStateDMA); - - Controller->V1.NewInquiryStandardData = slice_dma_loaf(DmaPages, - sizeof(DAC960_SCSI_Inquiry_T), - &Controller->V1.NewInquiryStandardDataDMA); - - Controller->V1.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), - &Controller->V1.NewInquiryUnitSerialNumberDMA); - - if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) - return true; - - /* Enable the Memory Mailbox Interface. */ - Controller->V1.DualModeMemoryMailboxInterface = true; - CommandMailbox.TypeX.CommandOpcode = 0x2B; - CommandMailbox.TypeX.CommandIdentifier = 0; - CommandMailbox.TypeX.CommandOpcode2 = 0x14; - CommandMailbox.TypeX.CommandMailboxesBusAddress = - Controller->V1.FirstCommandMailboxDMA; - CommandMailbox.TypeX.StatusMailboxesBusAddress = - Controller->V1.FirstStatusMailboxDMA; -#define TIMEOUT_COUNT 1000000 - - for (i = 0; i < 2; i++) - switch (Controller->HardwareType) - { - case DAC960_LA_Controller: - TimeoutCounter = TIMEOUT_COUNT; - while (--TimeoutCounter >= 0) - { - if (!DAC960_LA_HardwareMailboxFullP(ControllerBaseAddress)) - break; - udelay(10); - } - if (TimeoutCounter < 0) return false; - DAC960_LA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); - DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress); - TimeoutCounter = TIMEOUT_COUNT; - while (--TimeoutCounter >= 0) - { - if (DAC960_LA_HardwareMailboxStatusAvailableP( - ControllerBaseAddress)) - break; - udelay(10); - } - if (TimeoutCounter < 0) return false; - CommandStatus = DAC960_LA_ReadStatusRegister(ControllerBaseAddress); - DAC960_LA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); - DAC960_LA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); - if (CommandStatus == DAC960_V1_NormalCompletion) return true; - Controller->V1.DualModeMemoryMailboxInterface = false; - CommandMailbox.TypeX.CommandOpcode2 = 0x10; - break; - case DAC960_PG_Controller: - TimeoutCounter = TIMEOUT_COUNT; - while (--TimeoutCounter >= 0) - { - if (!DAC960_PG_HardwareMailboxFullP(ControllerBaseAddress)) - break; - udelay(10); - } - if (TimeoutCounter < 0) return false; - DAC960_PG_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); - DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress); - - TimeoutCounter = TIMEOUT_COUNT; - while (--TimeoutCounter >= 0) - { - if (DAC960_PG_HardwareMailboxStatusAvailableP( - ControllerBaseAddress)) - break; - udelay(10); - } - if (TimeoutCounter < 0) return false; - CommandStatus = DAC960_PG_ReadStatusRegister(ControllerBaseAddress); - DAC960_PG_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); - DAC960_PG_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); - if (CommandStatus == DAC960_V1_NormalCompletion) return true; - Controller->V1.DualModeMemoryMailboxInterface = false; - CommandMailbox.TypeX.CommandOpcode2 = 0x10; - break; - default: - DAC960_Failure(Controller, "Unknown Controller Type\n"); - break; - } - return false; -} - - -/* - DAC960_V2_EnableMemoryMailboxInterface enables the Memory Mailbox Interface - for DAC960 V2 Firmware Controllers. - - Aggregate the space needed for the controller's memory mailbox and - the other data structures that will be targets of dma transfers with - the controller. Allocate a dma-mapped region of memory to hold these - structures. Then, save CPU pointers and dma_addr_t values to reference - the structures that are contained in that region. -*/ - -static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T - *Controller) -{ - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - struct pci_dev *PCI_Device = Controller->PCIDevice; - struct dma_loaf *DmaPages = &Controller->DmaPages; - size_t DmaPagesSize; - size_t CommandMailboxesSize; - size_t StatusMailboxesSize; - - DAC960_V2_CommandMailbox_T *CommandMailboxesMemory; - dma_addr_t CommandMailboxesMemoryDMA; - - DAC960_V2_StatusMailbox_T *StatusMailboxesMemory; - dma_addr_t StatusMailboxesMemoryDMA; - - DAC960_V2_CommandMailbox_T *CommandMailbox; - dma_addr_t CommandMailboxDMA; - DAC960_V2_CommandStatus_T CommandStatus; - - if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(64)) && - pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) - return DAC960_Failure(Controller, "DMA mask out of range"); - - /* This is a temporary dma mapping, used only in the scope of this function */ - CommandMailbox = pci_alloc_consistent(PCI_Device, - sizeof(DAC960_V2_CommandMailbox_T), &CommandMailboxDMA); - if (CommandMailbox == NULL) - return false; - - CommandMailboxesSize = DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T); - StatusMailboxesSize = DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T); - DmaPagesSize = - CommandMailboxesSize + StatusMailboxesSize + - sizeof(DAC960_V2_HealthStatusBuffer_T) + - sizeof(DAC960_V2_ControllerInfo_T) + - sizeof(DAC960_V2_LogicalDeviceInfo_T) + - sizeof(DAC960_V2_PhysicalDeviceInfo_T) + - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T) + - sizeof(DAC960_V2_Event_T) + - sizeof(DAC960_V2_PhysicalToLogicalDevice_T); - - if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize)) { - pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T), - CommandMailbox, CommandMailboxDMA); - return false; - } - - CommandMailboxesMemory = slice_dma_loaf(DmaPages, - CommandMailboxesSize, &CommandMailboxesMemoryDMA); - - /* These are the base addresses for the command memory mailbox array */ - Controller->V2.FirstCommandMailbox = CommandMailboxesMemory; - Controller->V2.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA; - - CommandMailboxesMemory += DAC960_V2_CommandMailboxCount - 1; - Controller->V2.LastCommandMailbox = CommandMailboxesMemory; - Controller->V2.NextCommandMailbox = Controller->V2.FirstCommandMailbox; - Controller->V2.PreviousCommandMailbox1 = Controller->V2.LastCommandMailbox; - Controller->V2.PreviousCommandMailbox2 = - Controller->V2.LastCommandMailbox - 1; - - /* These are the base addresses for the status memory mailbox array */ - StatusMailboxesMemory = slice_dma_loaf(DmaPages, - StatusMailboxesSize, &StatusMailboxesMemoryDMA); - - Controller->V2.FirstStatusMailbox = StatusMailboxesMemory; - Controller->V2.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA; - StatusMailboxesMemory += DAC960_V2_StatusMailboxCount - 1; - Controller->V2.LastStatusMailbox = StatusMailboxesMemory; - Controller->V2.NextStatusMailbox = Controller->V2.FirstStatusMailbox; - - Controller->V2.HealthStatusBuffer = slice_dma_loaf(DmaPages, - sizeof(DAC960_V2_HealthStatusBuffer_T), - &Controller->V2.HealthStatusBufferDMA); - - Controller->V2.NewControllerInformation = slice_dma_loaf(DmaPages, - sizeof(DAC960_V2_ControllerInfo_T), - &Controller->V2.NewControllerInformationDMA); - - Controller->V2.NewLogicalDeviceInformation = slice_dma_loaf(DmaPages, - sizeof(DAC960_V2_LogicalDeviceInfo_T), - &Controller->V2.NewLogicalDeviceInformationDMA); - - Controller->V2.NewPhysicalDeviceInformation = slice_dma_loaf(DmaPages, - sizeof(DAC960_V2_PhysicalDeviceInfo_T), - &Controller->V2.NewPhysicalDeviceInformationDMA); - - Controller->V2.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), - &Controller->V2.NewInquiryUnitSerialNumberDMA); - - Controller->V2.Event = slice_dma_loaf(DmaPages, - sizeof(DAC960_V2_Event_T), - &Controller->V2.EventDMA); - - Controller->V2.PhysicalToLogicalDevice = slice_dma_loaf(DmaPages, - sizeof(DAC960_V2_PhysicalToLogicalDevice_T), - &Controller->V2.PhysicalToLogicalDeviceDMA); - - /* - Enable the Memory Mailbox Interface. - - I don't know why we can't just use one of the memory mailboxes - we just allocated to do this, instead of using this temporary one. - Try this change later. - */ - memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T)); - CommandMailbox->SetMemoryMailbox.CommandIdentifier = 1; - CommandMailbox->SetMemoryMailbox.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->SetMemoryMailbox.CommandControlBits.NoAutoRequestSense = true; - CommandMailbox->SetMemoryMailbox.FirstCommandMailboxSizeKB = - (DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T)) >> 10; - CommandMailbox->SetMemoryMailbox.FirstStatusMailboxSizeKB = - (DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T)) >> 10; - CommandMailbox->SetMemoryMailbox.SecondCommandMailboxSizeKB = 0; - CommandMailbox->SetMemoryMailbox.SecondStatusMailboxSizeKB = 0; - CommandMailbox->SetMemoryMailbox.RequestSenseSize = 0; - CommandMailbox->SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox; - CommandMailbox->SetMemoryMailbox.HealthStatusBufferSizeKB = 1; - CommandMailbox->SetMemoryMailbox.HealthStatusBufferBusAddress = - Controller->V2.HealthStatusBufferDMA; - CommandMailbox->SetMemoryMailbox.FirstCommandMailboxBusAddress = - Controller->V2.FirstCommandMailboxDMA; - CommandMailbox->SetMemoryMailbox.FirstStatusMailboxBusAddress = - Controller->V2.FirstStatusMailboxDMA; - switch (Controller->HardwareType) - { - case DAC960_GEM_Controller: - while (DAC960_GEM_HardwareMailboxFullP(ControllerBaseAddress)) - udelay(1); - DAC960_GEM_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); - DAC960_GEM_HardwareMailboxNewCommand(ControllerBaseAddress); - while (!DAC960_GEM_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) - udelay(1); - CommandStatus = DAC960_GEM_ReadCommandStatus(ControllerBaseAddress); - DAC960_GEM_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); - DAC960_GEM_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); - break; - case DAC960_BA_Controller: - while (DAC960_BA_HardwareMailboxFullP(ControllerBaseAddress)) - udelay(1); - DAC960_BA_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); - DAC960_BA_HardwareMailboxNewCommand(ControllerBaseAddress); - while (!DAC960_BA_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) - udelay(1); - CommandStatus = DAC960_BA_ReadCommandStatus(ControllerBaseAddress); - DAC960_BA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); - DAC960_BA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); - break; - case DAC960_LP_Controller: - while (DAC960_LP_HardwareMailboxFullP(ControllerBaseAddress)) - udelay(1); - DAC960_LP_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); - DAC960_LP_HardwareMailboxNewCommand(ControllerBaseAddress); - while (!DAC960_LP_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) - udelay(1); - CommandStatus = DAC960_LP_ReadCommandStatus(ControllerBaseAddress); - DAC960_LP_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); - DAC960_LP_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); - break; - default: - DAC960_Failure(Controller, "Unknown Controller Type\n"); - CommandStatus = DAC960_V2_AbormalCompletion; - break; - } - pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T), - CommandMailbox, CommandMailboxDMA); - return (CommandStatus == DAC960_V2_NormalCompletion); -} - - -/* - DAC960_V1_ReadControllerConfiguration reads the Configuration Information - from DAC960 V1 Firmware Controllers and initializes the Controller structure. -*/ - -static bool DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T - *Controller) -{ - DAC960_V1_Enquiry2_T *Enquiry2; - dma_addr_t Enquiry2DMA; - DAC960_V1_Config2_T *Config2; - dma_addr_t Config2DMA; - int LogicalDriveNumber, Channel, TargetID; - struct dma_loaf local_dma; - - if (!init_dma_loaf(Controller->PCIDevice, &local_dma, - sizeof(DAC960_V1_Enquiry2_T) + sizeof(DAC960_V1_Config2_T))) - return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION"); - - Enquiry2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Enquiry2_T), &Enquiry2DMA); - Config2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Config2_T), &Config2DMA); - - if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry, - Controller->V1.NewEnquiryDMA)) { - free_dma_loaf(Controller->PCIDevice, &local_dma); - return DAC960_Failure(Controller, "ENQUIRY"); - } - memcpy(&Controller->V1.Enquiry, Controller->V1.NewEnquiry, - sizeof(DAC960_V1_Enquiry_T)); - - if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry2, Enquiry2DMA)) { - free_dma_loaf(Controller->PCIDevice, &local_dma); - return DAC960_Failure(Controller, "ENQUIRY2"); - } - - if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_ReadConfig2, Config2DMA)) { - free_dma_loaf(Controller->PCIDevice, &local_dma); - return DAC960_Failure(Controller, "READ CONFIG2"); - } - - if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_GetLogicalDriveInformation, - Controller->V1.NewLogicalDriveInformationDMA)) { - free_dma_loaf(Controller->PCIDevice, &local_dma); - return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION"); - } - memcpy(&Controller->V1.LogicalDriveInformation, - Controller->V1.NewLogicalDriveInformation, - sizeof(DAC960_V1_LogicalDriveInformationArray_T)); - - for (Channel = 0; Channel < Enquiry2->ActualChannels; Channel++) - for (TargetID = 0; TargetID < Enquiry2->MaxTargets; TargetID++) { - if (!DAC960_V1_ExecuteType3D(Controller, DAC960_V1_GetDeviceState, - Channel, TargetID, - Controller->V1.NewDeviceStateDMA)) { - free_dma_loaf(Controller->PCIDevice, &local_dma); - return DAC960_Failure(Controller, "GET DEVICE STATE"); - } - memcpy(&Controller->V1.DeviceState[Channel][TargetID], - Controller->V1.NewDeviceState, sizeof(DAC960_V1_DeviceState_T)); - } - /* - Initialize the Controller Model Name and Full Model Name fields. - */ - switch (Enquiry2->HardwareID.SubModel) - { - case DAC960_V1_P_PD_PU: - if (Enquiry2->SCSICapability.BusSpeed == DAC960_V1_Ultra) - strcpy(Controller->ModelName, "DAC960PU"); - else strcpy(Controller->ModelName, "DAC960PD"); - break; - case DAC960_V1_PL: - strcpy(Controller->ModelName, "DAC960PL"); - break; - case DAC960_V1_PG: - strcpy(Controller->ModelName, "DAC960PG"); - break; - case DAC960_V1_PJ: - strcpy(Controller->ModelName, "DAC960PJ"); - break; - case DAC960_V1_PR: - strcpy(Controller->ModelName, "DAC960PR"); - break; - case DAC960_V1_PT: - strcpy(Controller->ModelName, "DAC960PT"); - break; - case DAC960_V1_PTL0: - strcpy(Controller->ModelName, "DAC960PTL0"); - break; - case DAC960_V1_PRL: - strcpy(Controller->ModelName, "DAC960PRL"); - break; - case DAC960_V1_PTL1: - strcpy(Controller->ModelName, "DAC960PTL1"); - break; - case DAC960_V1_1164P: - strcpy(Controller->ModelName, "DAC1164P"); - break; - default: - free_dma_loaf(Controller->PCIDevice, &local_dma); - return DAC960_Failure(Controller, "MODEL VERIFICATION"); - } - strcpy(Controller->FullModelName, "Mylex "); - strcat(Controller->FullModelName, Controller->ModelName); - /* - Initialize the Controller Firmware Version field and verify that it - is a supported firmware version. The supported firmware versions are: - - DAC1164P 5.06 and above - DAC960PTL/PRL/PJ/PG 4.06 and above - DAC960PU/PD/PL 3.51 and above - DAC960PU/PD/PL/P 2.73 and above - */ -#if defined(CONFIG_ALPHA) - /* - DEC Alpha machines were often equipped with DAC960 cards that were - OEMed from Mylex, and had their own custom firmware. Version 2.70, - the last custom FW revision to be released by DEC for these older - controllers, appears to work quite well with this driver. - - Cards tested successfully were several versions each of the PD and - PU, called by DEC the KZPSC and KZPAC, respectively, and having - the Manufacturer Numbers (from Mylex), usually on a sticker on the - back of the board, of: - - KZPSC: D040347 (1-channel) or D040348 (2-channel) or D040349 (3-channel) - KZPAC: D040395 (1-channel) or D040396 (2-channel) or D040397 (3-channel) - */ -# define FIRMWARE_27X "2.70" -#else -# define FIRMWARE_27X "2.73" -#endif - - if (Enquiry2->FirmwareID.MajorVersion == 0) - { - Enquiry2->FirmwareID.MajorVersion = - Controller->V1.Enquiry.MajorFirmwareVersion; - Enquiry2->FirmwareID.MinorVersion = - Controller->V1.Enquiry.MinorFirmwareVersion; - Enquiry2->FirmwareID.FirmwareType = '0'; - Enquiry2->FirmwareID.TurnID = 0; - } - snprintf(Controller->FirmwareVersion, sizeof(Controller->FirmwareVersion), - "%d.%02d-%c-%02d", - Enquiry2->FirmwareID.MajorVersion, - Enquiry2->FirmwareID.MinorVersion, - Enquiry2->FirmwareID.FirmwareType, - Enquiry2->FirmwareID.TurnID); - if (!((Controller->FirmwareVersion[0] == '5' && - strcmp(Controller->FirmwareVersion, "5.06") >= 0) || - (Controller->FirmwareVersion[0] == '4' && - strcmp(Controller->FirmwareVersion, "4.06") >= 0) || - (Controller->FirmwareVersion[0] == '3' && - strcmp(Controller->FirmwareVersion, "3.51") >= 0) || - (Controller->FirmwareVersion[0] == '2' && - strcmp(Controller->FirmwareVersion, FIRMWARE_27X) >= 0))) - { - DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION"); - DAC960_Error("Firmware Version = '%s'\n", Controller, - Controller->FirmwareVersion); - free_dma_loaf(Controller->PCIDevice, &local_dma); - return false; - } - /* - Initialize the Controller Channels, Targets, Memory Size, and SAF-TE - Enclosure Management Enabled fields. - */ - Controller->Channels = Enquiry2->ActualChannels; - Controller->Targets = Enquiry2->MaxTargets; - Controller->MemorySize = Enquiry2->MemorySize >> 20; - Controller->V1.SAFTE_EnclosureManagementEnabled = - (Enquiry2->FaultManagementType == DAC960_V1_SAFTE); - /* - Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive - Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and - Driver Scatter/Gather Limit. The Driver Queue Depth must be at most one - less than the Controller Queue Depth to allow for an automatic drive - rebuild operation. - */ - Controller->ControllerQueueDepth = Controller->V1.Enquiry.MaxCommands; - Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1; - if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth) - Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth; - Controller->LogicalDriveCount = - Controller->V1.Enquiry.NumberOfLogicalDrives; - Controller->MaxBlocksPerCommand = Enquiry2->MaxBlocksPerCommand; - Controller->ControllerScatterGatherLimit = Enquiry2->MaxScatterGatherEntries; - Controller->DriverScatterGatherLimit = - Controller->ControllerScatterGatherLimit; - if (Controller->DriverScatterGatherLimit > DAC960_V1_ScatterGatherLimit) - Controller->DriverScatterGatherLimit = DAC960_V1_ScatterGatherLimit; - /* - Initialize the Stripe Size, Segment Size, and Geometry Translation. - */ - Controller->V1.StripeSize = Config2->BlocksPerStripe * Config2->BlockFactor - >> (10 - DAC960_BlockSizeBits); - Controller->V1.SegmentSize = Config2->BlocksPerCacheLine * Config2->BlockFactor - >> (10 - DAC960_BlockSizeBits); - switch (Config2->DriveGeometry) - { - case DAC960_V1_Geometry_128_32: - Controller->V1.GeometryTranslationHeads = 128; - Controller->V1.GeometryTranslationSectors = 32; - break; - case DAC960_V1_Geometry_255_63: - Controller->V1.GeometryTranslationHeads = 255; - Controller->V1.GeometryTranslationSectors = 63; - break; - default: - free_dma_loaf(Controller->PCIDevice, &local_dma); - return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY"); - } - /* - Initialize the Background Initialization Status. - */ - if ((Controller->FirmwareVersion[0] == '4' && - strcmp(Controller->FirmwareVersion, "4.08") >= 0) || - (Controller->FirmwareVersion[0] == '5' && - strcmp(Controller->FirmwareVersion, "5.08") >= 0)) - { - Controller->V1.BackgroundInitializationStatusSupported = true; - DAC960_V1_ExecuteType3B(Controller, - DAC960_V1_BackgroundInitializationControl, 0x20, - Controller-> - V1.BackgroundInitializationStatusDMA); - memcpy(&Controller->V1.LastBackgroundInitializationStatus, - Controller->V1.BackgroundInitializationStatus, - sizeof(DAC960_V1_BackgroundInitializationStatus_T)); - } - /* - Initialize the Logical Drive Initially Accessible flag. - */ - for (LogicalDriveNumber = 0; - LogicalDriveNumber < Controller->LogicalDriveCount; - LogicalDriveNumber++) - if (Controller->V1.LogicalDriveInformation - [LogicalDriveNumber].LogicalDriveState != - DAC960_V1_LogicalDrive_Offline) - Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true; - Controller->V1.LastRebuildStatus = DAC960_V1_NoRebuildOrCheckInProgress; - free_dma_loaf(Controller->PCIDevice, &local_dma); - return true; -} - - -/* - DAC960_V2_ReadControllerConfiguration reads the Configuration Information - from DAC960 V2 Firmware Controllers and initializes the Controller structure. -*/ - -static bool DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T - *Controller) -{ - DAC960_V2_ControllerInfo_T *ControllerInfo = - &Controller->V2.ControllerInformation; - unsigned short LogicalDeviceNumber = 0; - int ModelNameLength; - - /* Get data into dma-able area, then copy into permanent location */ - if (!DAC960_V2_NewControllerInfo(Controller)) - return DAC960_Failure(Controller, "GET CONTROLLER INFO"); - memcpy(ControllerInfo, Controller->V2.NewControllerInformation, - sizeof(DAC960_V2_ControllerInfo_T)); - - - if (!DAC960_V2_GeneralInfo(Controller)) - return DAC960_Failure(Controller, "GET HEALTH STATUS"); - - /* - Initialize the Controller Model Name and Full Model Name fields. - */ - ModelNameLength = sizeof(ControllerInfo->ControllerName); - if (ModelNameLength > sizeof(Controller->ModelName)-1) - ModelNameLength = sizeof(Controller->ModelName)-1; - memcpy(Controller->ModelName, ControllerInfo->ControllerName, - ModelNameLength); - ModelNameLength--; - while (Controller->ModelName[ModelNameLength] == ' ' || - Controller->ModelName[ModelNameLength] == '\0') - ModelNameLength--; - Controller->ModelName[++ModelNameLength] = '\0'; - strcpy(Controller->FullModelName, "Mylex "); - strcat(Controller->FullModelName, Controller->ModelName); - /* - Initialize the Controller Firmware Version field. - */ - sprintf(Controller->FirmwareVersion, "%d.%02d-%02d", - ControllerInfo->FirmwareMajorVersion, - ControllerInfo->FirmwareMinorVersion, - ControllerInfo->FirmwareTurnNumber); - if (ControllerInfo->FirmwareMajorVersion == 6 && - ControllerInfo->FirmwareMinorVersion == 0 && - ControllerInfo->FirmwareTurnNumber < 1) - { - DAC960_Info("FIRMWARE VERSION %s DOES NOT PROVIDE THE CONTROLLER\n", - Controller, Controller->FirmwareVersion); - DAC960_Info("STATUS MONITORING FUNCTIONALITY NEEDED BY THIS DRIVER.\n", - Controller); - DAC960_Info("PLEASE UPGRADE TO VERSION 6.00-01 OR ABOVE.\n", - Controller); - } - /* - Initialize the Controller Channels, Targets, and Memory Size. - */ - Controller->Channels = ControllerInfo->NumberOfPhysicalChannelsPresent; - Controller->Targets = - ControllerInfo->MaximumTargetsPerChannel - [ControllerInfo->NumberOfPhysicalChannelsPresent-1]; - Controller->MemorySize = ControllerInfo->MemorySizeMB; - /* - Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive - Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and - Driver Scatter/Gather Limit. The Driver Queue Depth must be at most one - less than the Controller Queue Depth to allow for an automatic drive - rebuild operation. - */ - Controller->ControllerQueueDepth = ControllerInfo->MaximumParallelCommands; - Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1; - if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth) - Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth; - Controller->LogicalDriveCount = ControllerInfo->LogicalDevicesPresent; - Controller->MaxBlocksPerCommand = - ControllerInfo->MaximumDataTransferSizeInBlocks; - Controller->ControllerScatterGatherLimit = - ControllerInfo->MaximumScatterGatherEntries; - Controller->DriverScatterGatherLimit = - Controller->ControllerScatterGatherLimit; - if (Controller->DriverScatterGatherLimit > DAC960_V2_ScatterGatherLimit) - Controller->DriverScatterGatherLimit = DAC960_V2_ScatterGatherLimit; - /* - Initialize the Logical Device Information. - */ - while (true) - { - DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo = - Controller->V2.NewLogicalDeviceInformation; - DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo; - DAC960_V2_PhysicalDevice_T PhysicalDevice; - - if (!DAC960_V2_NewLogicalDeviceInfo(Controller, LogicalDeviceNumber)) - break; - LogicalDeviceNumber = NewLogicalDeviceInfo->LogicalDeviceNumber; - if (LogicalDeviceNumber >= DAC960_MaxLogicalDrives) { - DAC960_Error("DAC960: Logical Drive Number %d not supported\n", - Controller, LogicalDeviceNumber); - break; - } - if (NewLogicalDeviceInfo->DeviceBlockSizeInBytes != DAC960_BlockSize) { - DAC960_Error("DAC960: Logical Drive Block Size %d not supported\n", - Controller, NewLogicalDeviceInfo->DeviceBlockSizeInBytes); - LogicalDeviceNumber++; - continue; - } - PhysicalDevice.Controller = 0; - PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel; - PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID; - PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit; - Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] = - PhysicalDevice; - if (NewLogicalDeviceInfo->LogicalDeviceState != - DAC960_V2_LogicalDevice_Offline) - Controller->LogicalDriveInitiallyAccessible[LogicalDeviceNumber] = true; - LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), - GFP_ATOMIC); - if (LogicalDeviceInfo == NULL) - return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION"); - Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] = - LogicalDeviceInfo; - memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo, - sizeof(DAC960_V2_LogicalDeviceInfo_T)); - LogicalDeviceNumber++; - } - return true; -} - - -/* - DAC960_ReportControllerConfiguration reports the Configuration Information - for Controller. -*/ - -static bool DAC960_ReportControllerConfiguration(DAC960_Controller_T - *Controller) -{ - DAC960_Info("Configuring Mylex %s PCI RAID Controller\n", - Controller, Controller->ModelName); - DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n", - Controller, Controller->FirmwareVersion, - Controller->Channels, Controller->MemorySize); - DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ", - Controller, Controller->Bus, - Controller->Device, Controller->Function); - if (Controller->IO_Address == 0) - DAC960_Info("Unassigned\n", Controller); - else DAC960_Info("0x%X\n", Controller, Controller->IO_Address); - DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n", - Controller, Controller->PCI_Address, - (unsigned long) Controller->BaseAddress, - Controller->IRQ_Channel); - DAC960_Info(" Controller Queue Depth: %d, " - "Maximum Blocks per Command: %d\n", - Controller, Controller->ControllerQueueDepth, - Controller->MaxBlocksPerCommand); - DAC960_Info(" Driver Queue Depth: %d, " - "Scatter/Gather Limit: %d of %d Segments\n", - Controller, Controller->DriverQueueDepth, - Controller->DriverScatterGatherLimit, - Controller->ControllerScatterGatherLimit); - if (Controller->FirmwareType == DAC960_V1_Controller) - { - DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, " - "BIOS Geometry: %d/%d\n", Controller, - Controller->V1.StripeSize, - Controller->V1.SegmentSize, - Controller->V1.GeometryTranslationHeads, - Controller->V1.GeometryTranslationSectors); - if (Controller->V1.SAFTE_EnclosureManagementEnabled) - DAC960_Info(" SAF-TE Enclosure Management Enabled\n", Controller); - } - return true; -} - - -/* - DAC960_V1_ReadDeviceConfiguration reads the Device Configuration Information - for DAC960 V1 Firmware Controllers by requesting the SCSI Inquiry and SCSI - Inquiry Unit Serial Number information for each device connected to - Controller. -*/ - -static bool DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T - *Controller) -{ - struct dma_loaf local_dma; - - dma_addr_t DCDBs_dma[DAC960_V1_MaxChannels]; - DAC960_V1_DCDB_T *DCDBs_cpu[DAC960_V1_MaxChannels]; - - dma_addr_t SCSI_Inquiry_dma[DAC960_V1_MaxChannels]; - DAC960_SCSI_Inquiry_T *SCSI_Inquiry_cpu[DAC960_V1_MaxChannels]; - - dma_addr_t SCSI_NewInquiryUnitSerialNumberDMA[DAC960_V1_MaxChannels]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *SCSI_NewInquiryUnitSerialNumberCPU[DAC960_V1_MaxChannels]; - - struct completion Completions[DAC960_V1_MaxChannels]; - unsigned long flags; - int Channel, TargetID; - - if (!init_dma_loaf(Controller->PCIDevice, &local_dma, - DAC960_V1_MaxChannels*(sizeof(DAC960_V1_DCDB_T) + - sizeof(DAC960_SCSI_Inquiry_T) + - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)))) - return DAC960_Failure(Controller, - "DMA ALLOCATION FAILED IN ReadDeviceConfiguration"); - - for (Channel = 0; Channel < Controller->Channels; Channel++) { - DCDBs_cpu[Channel] = slice_dma_loaf(&local_dma, - sizeof(DAC960_V1_DCDB_T), DCDBs_dma + Channel); - SCSI_Inquiry_cpu[Channel] = slice_dma_loaf(&local_dma, - sizeof(DAC960_SCSI_Inquiry_T), - SCSI_Inquiry_dma + Channel); - SCSI_NewInquiryUnitSerialNumberCPU[Channel] = slice_dma_loaf(&local_dma, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), - SCSI_NewInquiryUnitSerialNumberDMA + Channel); - } - - for (TargetID = 0; TargetID < Controller->Targets; TargetID++) - { - /* - * For each channel, submit a probe for a device on that channel. - * The timeout interval for a device that is present is 10 seconds. - * With this approach, the timeout periods can elapse in parallel - * on each channel. - */ - for (Channel = 0; Channel < Controller->Channels; Channel++) - { - dma_addr_t NewInquiryStandardDataDMA = SCSI_Inquiry_dma[Channel]; - DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel]; - dma_addr_t DCDB_dma = DCDBs_dma[Channel]; - DAC960_Command_T *Command = Controller->Commands[Channel]; - struct completion *Completion = &Completions[Channel]; - - init_completion(Completion); - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - Command->Completion = Completion; - Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; - Command->V1.CommandMailbox.Type3.BusAddress = DCDB_dma; - DCDB->Channel = Channel; - DCDB->TargetID = TargetID; - DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; - DCDB->EarlyStatus = false; - DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds; - DCDB->NoAutomaticRequestSense = false; - DCDB->DisconnectPermitted = true; - DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->BusAddress = NewInquiryStandardDataDMA; - DCDB->CDBLength = 6; - DCDB->TransferLengthHigh4 = 0; - DCDB->SenseLength = sizeof(DCDB->SenseData); - DCDB->CDB[0] = 0x12; /* INQUIRY */ - DCDB->CDB[1] = 0; /* EVPD = 0 */ - DCDB->CDB[2] = 0; /* Page Code */ - DCDB->CDB[3] = 0; /* Reserved */ - DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->CDB[5] = 0; /* Control */ - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_QueueCommand(Command); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - } - /* - * Wait for the problems submitted in the previous loop - * to complete. On the probes that are successful, - * get the serial number of the device that was found. - */ - for (Channel = 0; Channel < Controller->Channels; Channel++) - { - DAC960_SCSI_Inquiry_T *InquiryStandardData = - &Controller->V1.InquiryStandardData[Channel][TargetID]; - DAC960_SCSI_Inquiry_T *NewInquiryStandardData = SCSI_Inquiry_cpu[Channel]; - dma_addr_t NewInquiryUnitSerialNumberDMA = - SCSI_NewInquiryUnitSerialNumberDMA[Channel]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber = - SCSI_NewInquiryUnitSerialNumberCPU[Channel]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID]; - DAC960_Command_T *Command = Controller->Commands[Channel]; - DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel]; - struct completion *Completion = &Completions[Channel]; - - wait_for_completion(Completion); - - if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) { - memset(InquiryStandardData, 0, sizeof(DAC960_SCSI_Inquiry_T)); - InquiryStandardData->PeripheralDeviceType = 0x1F; - continue; - } else - memcpy(InquiryStandardData, NewInquiryStandardData, sizeof(DAC960_SCSI_Inquiry_T)); - - /* Preserve Channel and TargetID values from the previous loop */ - Command->Completion = Completion; - DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->BusAddress = NewInquiryUnitSerialNumberDMA; - DCDB->SenseLength = sizeof(DCDB->SenseData); - DCDB->CDB[0] = 0x12; /* INQUIRY */ - DCDB->CDB[1] = 1; /* EVPD = 1 */ - DCDB->CDB[2] = 0x80; /* Page Code */ - DCDB->CDB[3] = 0; /* Reserved */ - DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->CDB[5] = 0; /* Control */ - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_QueueCommand(Command); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - wait_for_completion(Completion); - - if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) { - memset(InquiryUnitSerialNumber, 0, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - } else - memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - } - } - free_dma_loaf(Controller->PCIDevice, &local_dma); - return true; -} - - -/* - DAC960_V2_ReadDeviceConfiguration reads the Device Configuration Information - for DAC960 V2 Firmware Controllers by requesting the Physical Device - Information and SCSI Inquiry Unit Serial Number information for each - device connected to Controller. -*/ - -static bool DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T - *Controller) -{ - unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0; - unsigned short PhysicalDeviceIndex = 0; - - while (true) - { - DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo = - Controller->V2.NewPhysicalDeviceInformation; - DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber = - Controller->V2.NewInquiryUnitSerialNumber; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber; - - if (!DAC960_V2_NewPhysicalDeviceInfo(Controller, Channel, TargetID, LogicalUnit)) - break; - - PhysicalDeviceInfo = kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), - GFP_ATOMIC); - if (PhysicalDeviceInfo == NULL) - return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION"); - Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] = - PhysicalDeviceInfo; - memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo, - sizeof(DAC960_V2_PhysicalDeviceInfo_T)); - - InquiryUnitSerialNumber = kmalloc( - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); - if (InquiryUnitSerialNumber == NULL) { - kfree(PhysicalDeviceInfo); - return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION"); - } - Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex] = - InquiryUnitSerialNumber; - - Channel = NewPhysicalDeviceInfo->Channel; - TargetID = NewPhysicalDeviceInfo->TargetID; - LogicalUnit = NewPhysicalDeviceInfo->LogicalUnit; - - /* - Some devices do NOT have Unit Serial Numbers. - This command fails for them. But, we still want to - remember those devices are there. Construct a - UnitSerialNumber structure for the failure case. - */ - if (!DAC960_V2_NewInquiryUnitSerialNumber(Controller, Channel, TargetID, LogicalUnit)) { - memset(InquiryUnitSerialNumber, 0, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - } else - memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - - PhysicalDeviceIndex++; - LogicalUnit++; - } - return true; -} - - -/* - DAC960_SanitizeInquiryData sanitizes the Vendor, Model, Revision, and - Product Serial Number fields of the Inquiry Standard Data and Inquiry - Unit Serial Number structures. -*/ - -static void DAC960_SanitizeInquiryData(DAC960_SCSI_Inquiry_T - *InquiryStandardData, - DAC960_SCSI_Inquiry_UnitSerialNumber_T - *InquiryUnitSerialNumber, - unsigned char *Vendor, - unsigned char *Model, - unsigned char *Revision, - unsigned char *SerialNumber) -{ - int SerialNumberLength, i; - if (InquiryStandardData->PeripheralDeviceType == 0x1F) return; - for (i = 0; i < sizeof(InquiryStandardData->VendorIdentification); i++) - { - unsigned char VendorCharacter = - InquiryStandardData->VendorIdentification[i]; - Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~' - ? VendorCharacter : ' '); - } - Vendor[sizeof(InquiryStandardData->VendorIdentification)] = '\0'; - for (i = 0; i < sizeof(InquiryStandardData->ProductIdentification); i++) - { - unsigned char ModelCharacter = - InquiryStandardData->ProductIdentification[i]; - Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~' - ? ModelCharacter : ' '); - } - Model[sizeof(InquiryStandardData->ProductIdentification)] = '\0'; - for (i = 0; i < sizeof(InquiryStandardData->ProductRevisionLevel); i++) - { - unsigned char RevisionCharacter = - InquiryStandardData->ProductRevisionLevel[i]; - Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~' - ? RevisionCharacter : ' '); - } - Revision[sizeof(InquiryStandardData->ProductRevisionLevel)] = '\0'; - if (InquiryUnitSerialNumber->PeripheralDeviceType == 0x1F) return; - SerialNumberLength = InquiryUnitSerialNumber->PageLength; - if (SerialNumberLength > - sizeof(InquiryUnitSerialNumber->ProductSerialNumber)) - SerialNumberLength = sizeof(InquiryUnitSerialNumber->ProductSerialNumber); - for (i = 0; i < SerialNumberLength; i++) - { - unsigned char SerialNumberCharacter = - InquiryUnitSerialNumber->ProductSerialNumber[i]; - SerialNumber[i] = - (SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~' - ? SerialNumberCharacter : ' '); - } - SerialNumber[SerialNumberLength] = '\0'; -} - - -/* - DAC960_V1_ReportDeviceConfiguration reports the Device Configuration - Information for DAC960 V1 Firmware Controllers. -*/ - -static bool DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T - *Controller) -{ - int LogicalDriveNumber, Channel, TargetID; - DAC960_Info(" Physical Devices:\n", Controller); - for (Channel = 0; Channel < Controller->Channels; Channel++) - for (TargetID = 0; TargetID < Controller->Targets; TargetID++) - { - DAC960_SCSI_Inquiry_T *InquiryStandardData = - &Controller->V1.InquiryStandardData[Channel][TargetID]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID]; - DAC960_V1_DeviceState_T *DeviceState = - &Controller->V1.DeviceState[Channel][TargetID]; - DAC960_V1_ErrorTableEntry_T *ErrorEntry = - &Controller->V1.ErrorTable.ErrorTableEntries[Channel][TargetID]; - char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)]; - char Model[1+sizeof(InquiryStandardData->ProductIdentification)]; - char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)]; - char SerialNumber[1+sizeof(InquiryUnitSerialNumber - ->ProductSerialNumber)]; - if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue; - DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber, - Vendor, Model, Revision, SerialNumber); - DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n", - Controller, Channel, TargetID, (TargetID < 10 ? " " : ""), - Vendor, Model, Revision); - if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F) - DAC960_Info(" Serial Number: %s\n", Controller, SerialNumber); - if (DeviceState->Present && - DeviceState->DeviceType == DAC960_V1_DiskType) - { - if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0) - DAC960_Info(" Disk Status: %s, %u blocks, %d resets\n", - Controller, - (DeviceState->DeviceState == DAC960_V1_Device_Dead - ? "Dead" - : DeviceState->DeviceState - == DAC960_V1_Device_WriteOnly - ? "Write-Only" - : DeviceState->DeviceState - == DAC960_V1_Device_Online - ? "Online" : "Standby"), - DeviceState->DiskSize, - Controller->V1.DeviceResetCount[Channel][TargetID]); - else - DAC960_Info(" Disk Status: %s, %u blocks\n", Controller, - (DeviceState->DeviceState == DAC960_V1_Device_Dead - ? "Dead" - : DeviceState->DeviceState - == DAC960_V1_Device_WriteOnly - ? "Write-Only" - : DeviceState->DeviceState - == DAC960_V1_Device_Online - ? "Online" : "Standby"), - DeviceState->DiskSize); - } - if (ErrorEntry->ParityErrorCount > 0 || - ErrorEntry->SoftErrorCount > 0 || - ErrorEntry->HardErrorCount > 0 || - ErrorEntry->MiscErrorCount > 0) - DAC960_Info(" Errors - Parity: %d, Soft: %d, " - "Hard: %d, Misc: %d\n", Controller, - ErrorEntry->ParityErrorCount, - ErrorEntry->SoftErrorCount, - ErrorEntry->HardErrorCount, - ErrorEntry->MiscErrorCount); - } - DAC960_Info(" Logical Drives:\n", Controller); - for (LogicalDriveNumber = 0; - LogicalDriveNumber < Controller->LogicalDriveCount; - LogicalDriveNumber++) - { - DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation = - &Controller->V1.LogicalDriveInformation[LogicalDriveNumber]; - DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %u blocks, %s\n", - Controller, Controller->ControllerNumber, LogicalDriveNumber, - LogicalDriveInformation->RAIDLevel, - (LogicalDriveInformation->LogicalDriveState - == DAC960_V1_LogicalDrive_Online - ? "Online" - : LogicalDriveInformation->LogicalDriveState - == DAC960_V1_LogicalDrive_Critical - ? "Critical" : "Offline"), - LogicalDriveInformation->LogicalDriveSize, - (LogicalDriveInformation->WriteBack - ? "Write Back" : "Write Thru")); - } - return true; -} - - -/* - DAC960_V2_ReportDeviceConfiguration reports the Device Configuration - Information for DAC960 V2 Firmware Controllers. -*/ - -static bool DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T - *Controller) -{ - int PhysicalDeviceIndex, LogicalDriveNumber; - DAC960_Info(" Physical Devices:\n", Controller); - for (PhysicalDeviceIndex = 0; - PhysicalDeviceIndex < DAC960_V2_MaxPhysicalDevices; - PhysicalDeviceIndex++) - { - DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo = - Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex]; - DAC960_SCSI_Inquiry_T *InquiryStandardData = - (DAC960_SCSI_Inquiry_T *) &PhysicalDeviceInfo->SCSI_InquiryData; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex]; - char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)]; - char Model[1+sizeof(InquiryStandardData->ProductIdentification)]; - char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)]; - char SerialNumber[1+sizeof(InquiryUnitSerialNumber->ProductSerialNumber)]; - if (PhysicalDeviceInfo == NULL) break; - DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber, - Vendor, Model, Revision, SerialNumber); - DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n", - Controller, - PhysicalDeviceInfo->Channel, - PhysicalDeviceInfo->TargetID, - (PhysicalDeviceInfo->TargetID < 10 ? " " : ""), - Vendor, Model, Revision); - if (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers == 0) - DAC960_Info(" %sAsynchronous\n", Controller, - (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16 - ? "Wide " :"")); - else - DAC960_Info(" %sSynchronous at %d MB/sec\n", Controller, - (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16 - ? "Wide " :""), - (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers - * PhysicalDeviceInfo->NegotiatedDataWidthBits/8)); - if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F) - DAC960_Info(" Serial Number: %s\n", Controller, SerialNumber); - if (PhysicalDeviceInfo->PhysicalDeviceState == - DAC960_V2_Device_Unconfigured) - continue; - DAC960_Info(" Disk Status: %s, %u blocks\n", Controller, - (PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Online - ? "Online" - : PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Rebuild - ? "Rebuild" - : PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Missing - ? "Missing" - : PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Critical - ? "Critical" - : PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Dead - ? "Dead" - : PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_SuspectedDead - ? "Suspected-Dead" - : PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_CommandedOffline - ? "Commanded-Offline" - : PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Standby - ? "Standby" : "Unknown"), - PhysicalDeviceInfo->ConfigurableDeviceSize); - if (PhysicalDeviceInfo->ParityErrors == 0 && - PhysicalDeviceInfo->SoftErrors == 0 && - PhysicalDeviceInfo->HardErrors == 0 && - PhysicalDeviceInfo->MiscellaneousErrors == 0 && - PhysicalDeviceInfo->CommandTimeouts == 0 && - PhysicalDeviceInfo->Retries == 0 && - PhysicalDeviceInfo->Aborts == 0 && - PhysicalDeviceInfo->PredictedFailuresDetected == 0) - continue; - DAC960_Info(" Errors - Parity: %d, Soft: %d, " - "Hard: %d, Misc: %d\n", Controller, - PhysicalDeviceInfo->ParityErrors, - PhysicalDeviceInfo->SoftErrors, - PhysicalDeviceInfo->HardErrors, - PhysicalDeviceInfo->MiscellaneousErrors); - DAC960_Info(" Timeouts: %d, Retries: %d, " - "Aborts: %d, Predicted: %d\n", Controller, - PhysicalDeviceInfo->CommandTimeouts, - PhysicalDeviceInfo->Retries, - PhysicalDeviceInfo->Aborts, - PhysicalDeviceInfo->PredictedFailuresDetected); - } - DAC960_Info(" Logical Drives:\n", Controller); - for (LogicalDriveNumber = 0; - LogicalDriveNumber < DAC960_MaxLogicalDrives; - LogicalDriveNumber++) - { - DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = - Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; - static const unsigned char *ReadCacheStatus[] = { - "Read Cache Disabled", - "Read Cache Enabled", - "Read Ahead Enabled", - "Intelligent Read Ahead Enabled", - "-", "-", "-", "-" - }; - static const unsigned char *WriteCacheStatus[] = { - "Write Cache Disabled", - "Logical Device Read Only", - "Write Cache Enabled", - "Intelligent Write Cache Enabled", - "-", "-", "-", "-" - }; - unsigned char *GeometryTranslation; - if (LogicalDeviceInfo == NULL) continue; - switch (LogicalDeviceInfo->DriveGeometry) - { - case DAC960_V2_Geometry_128_32: - GeometryTranslation = "128/32"; - break; - case DAC960_V2_Geometry_255_63: - GeometryTranslation = "255/63"; - break; - default: - GeometryTranslation = "Invalid"; - DAC960_Error("Illegal Logical Device Geometry %d\n", - Controller, LogicalDeviceInfo->DriveGeometry); - break; - } - DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %u blocks\n", - Controller, Controller->ControllerNumber, LogicalDriveNumber, - LogicalDeviceInfo->RAIDLevel, - (LogicalDeviceInfo->LogicalDeviceState - == DAC960_V2_LogicalDevice_Online - ? "Online" - : LogicalDeviceInfo->LogicalDeviceState - == DAC960_V2_LogicalDevice_Critical - ? "Critical" : "Offline"), - LogicalDeviceInfo->ConfigurableDeviceSize); - DAC960_Info(" Logical Device %s, BIOS Geometry: %s\n", - Controller, - (LogicalDeviceInfo->LogicalDeviceControl - .LogicalDeviceInitialized - ? "Initialized" : "Uninitialized"), - GeometryTranslation); - if (LogicalDeviceInfo->StripeSize == 0) - { - if (LogicalDeviceInfo->CacheLineSize == 0) - DAC960_Info(" Stripe Size: N/A, " - "Segment Size: N/A\n", Controller); - else - DAC960_Info(" Stripe Size: N/A, " - "Segment Size: %dKB\n", Controller, - 1 << (LogicalDeviceInfo->CacheLineSize - 2)); - } - else - { - if (LogicalDeviceInfo->CacheLineSize == 0) - DAC960_Info(" Stripe Size: %dKB, " - "Segment Size: N/A\n", Controller, - 1 << (LogicalDeviceInfo->StripeSize - 2)); - else - DAC960_Info(" Stripe Size: %dKB, " - "Segment Size: %dKB\n", Controller, - 1 << (LogicalDeviceInfo->StripeSize - 2), - 1 << (LogicalDeviceInfo->CacheLineSize - 2)); - } - DAC960_Info(" %s, %s\n", Controller, - ReadCacheStatus[ - LogicalDeviceInfo->LogicalDeviceControl.ReadCache], - WriteCacheStatus[ - LogicalDeviceInfo->LogicalDeviceControl.WriteCache]); - if (LogicalDeviceInfo->SoftErrors > 0 || - LogicalDeviceInfo->CommandsFailed > 0 || - LogicalDeviceInfo->DeferredWriteErrors) - DAC960_Info(" Errors - Soft: %d, Failed: %d, " - "Deferred Write: %d\n", Controller, - LogicalDeviceInfo->SoftErrors, - LogicalDeviceInfo->CommandsFailed, - LogicalDeviceInfo->DeferredWriteErrors); - - } - return true; -} - -/* - DAC960_RegisterBlockDevice registers the Block Device structures - associated with Controller. -*/ - -static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) -{ - int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; - int n; - - /* - Register the Block Device Major Number for this DAC960 Controller. - */ - if (register_blkdev(MajorNumber, "dac960") < 0) - return false; - - for (n = 0; n < DAC960_MaxLogicalDrives; n++) { - struct gendisk *disk = Controller->disks[n]; - struct request_queue *RequestQueue; - - /* for now, let all request queues share controller's lock */ - RequestQueue = blk_init_queue(DAC960_RequestFunction,&Controller->queue_lock); - if (!RequestQueue) { - printk("DAC960: failure to allocate request queue\n"); - continue; - } - Controller->RequestQueue[n] = RequestQueue; - RequestQueue->queuedata = Controller; - blk_queue_max_segments(RequestQueue, Controller->DriverScatterGatherLimit); - blk_queue_max_hw_sectors(RequestQueue, Controller->MaxBlocksPerCommand); - disk->queue = RequestQueue; - sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n); - disk->major = MajorNumber; - disk->first_minor = n << DAC960_MaxPartitionsBits; - disk->fops = &DAC960_BlockDeviceOperations; - } - /* - Indicate the Block Device Registration completed successfully, - */ - return true; -} - - -/* - DAC960_UnregisterBlockDevice unregisters the Block Device structures - associated with Controller. -*/ - -static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller) -{ - int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; - int disk; - - /* does order matter when deleting gendisk and cleanup in request queue? */ - for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) { - del_gendisk(Controller->disks[disk]); - blk_cleanup_queue(Controller->RequestQueue[disk]); - Controller->RequestQueue[disk] = NULL; - } - - /* - Unregister the Block Device Major Number for this DAC960 Controller. - */ - unregister_blkdev(MajorNumber, "dac960"); -} - -/* - DAC960_ComputeGenericDiskInfo computes the values for the Generic Disk - Information Partition Sector Counts and Block Sizes. -*/ - -static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller) -{ - int disk; - for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) - set_capacity(Controller->disks[disk], disk_size(Controller, disk)); -} - -/* - DAC960_ReportErrorStatus reports Controller BIOS Messages passed through - the Error Status Register when the driver performs the BIOS handshaking. - It returns true for fatal errors and false otherwise. -*/ - -static bool DAC960_ReportErrorStatus(DAC960_Controller_T *Controller, - unsigned char ErrorStatus, - unsigned char Parameter0, - unsigned char Parameter1) -{ - switch (ErrorStatus) - { - case 0x00: - DAC960_Notice("Physical Device %d:%d Not Responding\n", - Controller, Parameter1, Parameter0); - break; - case 0x08: - if (Controller->DriveSpinUpMessageDisplayed) break; - DAC960_Notice("Spinning Up Drives\n", Controller); - Controller->DriveSpinUpMessageDisplayed = true; - break; - case 0x30: - DAC960_Notice("Configuration Checksum Error\n", Controller); - break; - case 0x60: - DAC960_Notice("Mirror Race Recovery Failed\n", Controller); - break; - case 0x70: - DAC960_Notice("Mirror Race Recovery In Progress\n", Controller); - break; - case 0x90: - DAC960_Notice("Physical Device %d:%d COD Mismatch\n", - Controller, Parameter1, Parameter0); - break; - case 0xA0: - DAC960_Notice("Logical Drive Installation Aborted\n", Controller); - break; - case 0xB0: - DAC960_Notice("Mirror Race On A Critical Logical Drive\n", Controller); - break; - case 0xD0: - DAC960_Notice("New Controller Configuration Found\n", Controller); - break; - case 0xF0: - DAC960_Error("Fatal Memory Parity Error for Controller at\n", Controller); - return true; - default: - DAC960_Error("Unknown Initialization Error %02X for Controller at\n", - Controller, ErrorStatus); - return true; - } - return false; -} - - -/* - * DAC960_DetectCleanup releases the resources that were allocated - * during DAC960_DetectController(). DAC960_DetectController can - * has several internal failure points, so not ALL resources may - * have been allocated. It's important to free only - * resources that HAVE been allocated. The code below always - * tests that the resource has been allocated before attempting to - * free it. - */ -static void DAC960_DetectCleanup(DAC960_Controller_T *Controller) -{ - int i; - - /* Free the memory mailbox, status, and related structures */ - free_dma_loaf(Controller->PCIDevice, &Controller->DmaPages); - if (Controller->MemoryMappedAddress) { - switch(Controller->HardwareType) - { - case DAC960_GEM_Controller: - DAC960_GEM_DisableInterrupts(Controller->BaseAddress); - break; - case DAC960_BA_Controller: - DAC960_BA_DisableInterrupts(Controller->BaseAddress); - break; - case DAC960_LP_Controller: - DAC960_LP_DisableInterrupts(Controller->BaseAddress); - break; - case DAC960_LA_Controller: - DAC960_LA_DisableInterrupts(Controller->BaseAddress); - break; - case DAC960_PG_Controller: - DAC960_PG_DisableInterrupts(Controller->BaseAddress); - break; - case DAC960_PD_Controller: - DAC960_PD_DisableInterrupts(Controller->BaseAddress); - break; - case DAC960_P_Controller: - DAC960_PD_DisableInterrupts(Controller->BaseAddress); - break; - } - iounmap(Controller->MemoryMappedAddress); - } - if (Controller->IRQ_Channel) - free_irq(Controller->IRQ_Channel, Controller); - if (Controller->IO_Address) - release_region(Controller->IO_Address, 0x80); - pci_disable_device(Controller->PCIDevice); - for (i = 0; (i < DAC960_MaxLogicalDrives) && Controller->disks[i]; i++) - put_disk(Controller->disks[i]); - DAC960_Controllers[Controller->ControllerNumber] = NULL; - kfree(Controller); -} - - -/* - DAC960_DetectController detects Mylex DAC960/AcceleRAID/eXtremeRAID - PCI RAID Controllers by interrogating the PCI Configuration Space for - Controller Type. -*/ - -static DAC960_Controller_T * -DAC960_DetectController(struct pci_dev *PCI_Device, - const struct pci_device_id *entry) -{ - struct DAC960_privdata *privdata = - (struct DAC960_privdata *)entry->driver_data; - irq_handler_t InterruptHandler = privdata->InterruptHandler; - unsigned int MemoryWindowSize = privdata->MemoryWindowSize; - DAC960_Controller_T *Controller = NULL; - unsigned char DeviceFunction = PCI_Device->devfn; - unsigned char ErrorStatus, Parameter0, Parameter1; - unsigned int IRQ_Channel; - void __iomem *BaseAddress; - int i; - - Controller = kzalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC); - if (Controller == NULL) { - DAC960_Error("Unable to allocate Controller structure for " - "Controller at\n", NULL); - return NULL; - } - Controller->ControllerNumber = DAC960_ControllerCount; - DAC960_Controllers[DAC960_ControllerCount++] = Controller; - Controller->Bus = PCI_Device->bus->number; - Controller->FirmwareType = privdata->FirmwareType; - Controller->HardwareType = privdata->HardwareType; - Controller->Device = DeviceFunction >> 3; - Controller->Function = DeviceFunction & 0x7; - Controller->PCIDevice = PCI_Device; - strcpy(Controller->FullModelName, "DAC960"); - - if (pci_enable_device(PCI_Device)) - goto Failure; - - switch (Controller->HardwareType) - { - case DAC960_GEM_Controller: - Controller->PCI_Address = pci_resource_start(PCI_Device, 0); - break; - case DAC960_BA_Controller: - Controller->PCI_Address = pci_resource_start(PCI_Device, 0); - break; - case DAC960_LP_Controller: - Controller->PCI_Address = pci_resource_start(PCI_Device, 0); - break; - case DAC960_LA_Controller: - Controller->PCI_Address = pci_resource_start(PCI_Device, 0); - break; - case DAC960_PG_Controller: - Controller->PCI_Address = pci_resource_start(PCI_Device, 0); - break; - case DAC960_PD_Controller: - Controller->IO_Address = pci_resource_start(PCI_Device, 0); - Controller->PCI_Address = pci_resource_start(PCI_Device, 1); - break; - case DAC960_P_Controller: - Controller->IO_Address = pci_resource_start(PCI_Device, 0); - Controller->PCI_Address = pci_resource_start(PCI_Device, 1); - break; - } - - pci_set_drvdata(PCI_Device, (void *)((long)Controller->ControllerNumber)); - for (i = 0; i < DAC960_MaxLogicalDrives; i++) { - Controller->disks[i] = alloc_disk(1<<DAC960_MaxPartitionsBits); - if (!Controller->disks[i]) - goto Failure; - Controller->disks[i]->private_data = (void *)((long)i); - } - init_waitqueue_head(&Controller->CommandWaitQueue); - init_waitqueue_head(&Controller->HealthStatusWaitQueue); - spin_lock_init(&Controller->queue_lock); - DAC960_AnnounceDriver(Controller); - /* - Map the Controller Register Window. - */ - if (MemoryWindowSize < PAGE_SIZE) - MemoryWindowSize = PAGE_SIZE; - Controller->MemoryMappedAddress = - ioremap_nocache(Controller->PCI_Address & PAGE_MASK, MemoryWindowSize); - Controller->BaseAddress = - Controller->MemoryMappedAddress + (Controller->PCI_Address & ~PAGE_MASK); - if (Controller->MemoryMappedAddress == NULL) - { - DAC960_Error("Unable to map Controller Register Window for " - "Controller at\n", Controller); - goto Failure; - } - BaseAddress = Controller->BaseAddress; - switch (Controller->HardwareType) - { - case DAC960_GEM_Controller: - DAC960_GEM_DisableInterrupts(BaseAddress); - DAC960_GEM_AcknowledgeHardwareMailboxStatus(BaseAddress); - udelay(1000); - while (DAC960_GEM_InitializationInProgressP(BaseAddress)) - { - if (DAC960_GEM_ReadErrorStatus(BaseAddress, &ErrorStatus, - &Parameter0, &Parameter1) && - DAC960_ReportErrorStatus(Controller, ErrorStatus, - Parameter0, Parameter1)) - goto Failure; - udelay(10); - } - if (!DAC960_V2_EnableMemoryMailboxInterface(Controller)) - { - DAC960_Error("Unable to Enable Memory Mailbox Interface " - "for Controller at\n", Controller); - goto Failure; - } - DAC960_GEM_EnableInterrupts(BaseAddress); - Controller->QueueCommand = DAC960_GEM_QueueCommand; - Controller->ReadControllerConfiguration = - DAC960_V2_ReadControllerConfiguration; - Controller->ReadDeviceConfiguration = - DAC960_V2_ReadDeviceConfiguration; - Controller->ReportDeviceConfiguration = - DAC960_V2_ReportDeviceConfiguration; - Controller->QueueReadWriteCommand = - DAC960_V2_QueueReadWriteCommand; - break; - case DAC960_BA_Controller: - DAC960_BA_DisableInterrupts(BaseAddress); - DAC960_BA_AcknowledgeHardwareMailboxStatus(BaseAddress); - udelay(1000); - while (DAC960_BA_InitializationInProgressP(BaseAddress)) - { - if (DAC960_BA_ReadErrorStatus(BaseAddress, &ErrorStatus, - &Parameter0, &Parameter1) && - DAC960_ReportErrorStatus(Controller, ErrorStatus, - Parameter0, Parameter1)) - goto Failure; - udelay(10); - } - if (!DAC960_V2_EnableMemoryMailboxInterface(Controller)) - { - DAC960_Error("Unable to Enable Memory Mailbox Interface " - "for Controller at\n", Controller); - goto Failure; - } - DAC960_BA_EnableInterrupts(BaseAddress); - Controller->QueueCommand = DAC960_BA_QueueCommand; - Controller->ReadControllerConfiguration = - DAC960_V2_ReadControllerConfiguration; - Controller->ReadDeviceConfiguration = - DAC960_V2_ReadDeviceConfiguration; - Controller->ReportDeviceConfiguration = - DAC960_V2_ReportDeviceConfiguration; - Controller->QueueReadWriteCommand = - DAC960_V2_QueueReadWriteCommand; - break; - case DAC960_LP_Controller: - DAC960_LP_DisableInterrupts(BaseAddress); - DAC960_LP_AcknowledgeHardwareMailboxStatus(BaseAddress); - udelay(1000); - while (DAC960_LP_InitializationInProgressP(BaseAddress)) - { - if (DAC960_LP_ReadErrorStatus(BaseAddress, &ErrorStatus, - &Parameter0, &Parameter1) && - DAC960_ReportErrorStatus(Controller, ErrorStatus, - Parameter0, Parameter1)) - goto Failure; - udelay(10); - } - if (!DAC960_V2_EnableMemoryMailboxInterface(Controller)) - { - DAC960_Error("Unable to Enable Memory Mailbox Interface " - "for Controller at\n", Controller); - goto Failure; - } - DAC960_LP_EnableInterrupts(BaseAddress); - Controller->QueueCommand = DAC960_LP_QueueCommand; - Controller->ReadControllerConfiguration = - DAC960_V2_ReadControllerConfiguration; - Controller->ReadDeviceConfiguration = - DAC960_V2_ReadDeviceConfiguration; - Controller->ReportDeviceConfiguration = - DAC960_V2_ReportDeviceConfiguration; - Controller->QueueReadWriteCommand = - DAC960_V2_QueueReadWriteCommand; - break; - case DAC960_LA_Controller: - DAC960_LA_DisableInterrupts(BaseAddress); - DAC960_LA_AcknowledgeHardwareMailboxStatus(BaseAddress); - udelay(1000); - while (DAC960_LA_InitializationInProgressP(BaseAddress)) - { - if (DAC960_LA_ReadErrorStatus(BaseAddress, &ErrorStatus, - &Parameter0, &Parameter1) && - DAC960_ReportErrorStatus(Controller, ErrorStatus, - Parameter0, Parameter1)) - goto Failure; - udelay(10); - } - if (!DAC960_V1_EnableMemoryMailboxInterface(Controller)) - { - DAC960_Error("Unable to Enable Memory Mailbox Interface " - "for Controller at\n", Controller); - goto Failure; - } - DAC960_LA_EnableInterrupts(BaseAddress); - if (Controller->V1.DualModeMemoryMailboxInterface) - Controller->QueueCommand = DAC960_LA_QueueCommandDualMode; - else Controller->QueueCommand = DAC960_LA_QueueCommandSingleMode; - Controller->ReadControllerConfiguration = - DAC960_V1_ReadControllerConfiguration; - Controller->ReadDeviceConfiguration = - DAC960_V1_ReadDeviceConfiguration; - Controller->ReportDeviceConfiguration = - DAC960_V1_ReportDeviceConfiguration; - Controller->QueueReadWriteCommand = - DAC960_V1_QueueReadWriteCommand; - break; - case DAC960_PG_Controller: - DAC960_PG_DisableInterrupts(BaseAddress); - DAC960_PG_AcknowledgeHardwareMailboxStatus(BaseAddress); - udelay(1000); - while (DAC960_PG_InitializationInProgressP(BaseAddress)) - { - if (DAC960_PG_ReadErrorStatus(BaseAddress, &ErrorStatus, - &Parameter0, &Parameter1) && - DAC960_ReportErrorStatus(Controller, ErrorStatus, - Parameter0, Parameter1)) - goto Failure; - udelay(10); - } - if (!DAC960_V1_EnableMemoryMailboxInterface(Controller)) - { - DAC960_Error("Unable to Enable Memory Mailbox Interface " - "for Controller at\n", Controller); - goto Failure; - } - DAC960_PG_EnableInterrupts(BaseAddress); - if (Controller->V1.DualModeMemoryMailboxInterface) - Controller->QueueCommand = DAC960_PG_QueueCommandDualMode; - else Controller->QueueCommand = DAC960_PG_QueueCommandSingleMode; - Controller->ReadControllerConfiguration = - DAC960_V1_ReadControllerConfiguration; - Controller->ReadDeviceConfiguration = - DAC960_V1_ReadDeviceConfiguration; - Controller->ReportDeviceConfiguration = - DAC960_V1_ReportDeviceConfiguration; - Controller->QueueReadWriteCommand = - DAC960_V1_QueueReadWriteCommand; - break; - case DAC960_PD_Controller: - if (!request_region(Controller->IO_Address, 0x80, - Controller->FullModelName)) { - DAC960_Error("IO port 0x%lx busy for Controller at\n", - Controller, Controller->IO_Address); - goto Failure; - } - DAC960_PD_DisableInterrupts(BaseAddress); - DAC960_PD_AcknowledgeStatus(BaseAddress); - udelay(1000); - while (DAC960_PD_InitializationInProgressP(BaseAddress)) - { - if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus, - &Parameter0, &Parameter1) && - DAC960_ReportErrorStatus(Controller, ErrorStatus, - Parameter0, Parameter1)) - goto Failure; - udelay(10); - } - if (!DAC960_V1_EnableMemoryMailboxInterface(Controller)) - { - DAC960_Error("Unable to allocate DMA mapped memory " - "for Controller at\n", Controller); - goto Failure; - } - DAC960_PD_EnableInterrupts(BaseAddress); - Controller->QueueCommand = DAC960_PD_QueueCommand; - Controller->ReadControllerConfiguration = - DAC960_V1_ReadControllerConfiguration; - Controller->ReadDeviceConfiguration = - DAC960_V1_ReadDeviceConfiguration; - Controller->ReportDeviceConfiguration = - DAC960_V1_ReportDeviceConfiguration; - Controller->QueueReadWriteCommand = - DAC960_V1_QueueReadWriteCommand; - break; - case DAC960_P_Controller: - if (!request_region(Controller->IO_Address, 0x80, - Controller->FullModelName)){ - DAC960_Error("IO port 0x%lx busy for Controller at\n", - Controller, Controller->IO_Address); - goto Failure; - } - DAC960_PD_DisableInterrupts(BaseAddress); - DAC960_PD_AcknowledgeStatus(BaseAddress); - udelay(1000); - while (DAC960_PD_InitializationInProgressP(BaseAddress)) - { - if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus, - &Parameter0, &Parameter1) && - DAC960_ReportErrorStatus(Controller, ErrorStatus, - Parameter0, Parameter1)) - goto Failure; - udelay(10); - } - if (!DAC960_V1_EnableMemoryMailboxInterface(Controller)) - { - DAC960_Error("Unable to allocate DMA mapped memory" - "for Controller at\n", Controller); - goto Failure; - } - DAC960_PD_EnableInterrupts(BaseAddress); - Controller->QueueCommand = DAC960_P_QueueCommand; - Controller->ReadControllerConfiguration = - DAC960_V1_ReadControllerConfiguration; - Controller->ReadDeviceConfiguration = - DAC960_V1_ReadDeviceConfiguration; - Controller->ReportDeviceConfiguration = - DAC960_V1_ReportDeviceConfiguration; - Controller->QueueReadWriteCommand = - DAC960_V1_QueueReadWriteCommand; - break; - } - /* - Acquire shared access to the IRQ Channel. - */ - IRQ_Channel = PCI_Device->irq; - if (request_irq(IRQ_Channel, InterruptHandler, IRQF_SHARED, - Controller->FullModelName, Controller) < 0) - { - DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n", - Controller, Controller->IRQ_Channel); - goto Failure; - } - Controller->IRQ_Channel = IRQ_Channel; - Controller->InitialCommand.CommandIdentifier = 1; - Controller->InitialCommand.Controller = Controller; - Controller->Commands[0] = &Controller->InitialCommand; - Controller->FreeCommands = &Controller->InitialCommand; - return Controller; - -Failure: - if (Controller->IO_Address == 0) - DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " - "PCI Address 0x%X\n", Controller, - Controller->Bus, Controller->Device, - Controller->Function, Controller->PCI_Address); - else - DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " - "0x%X PCI Address 0x%X\n", Controller, - Controller->Bus, Controller->Device, - Controller->Function, Controller->IO_Address, - Controller->PCI_Address); - DAC960_DetectCleanup(Controller); - DAC960_ControllerCount--; - return NULL; -} - -/* - DAC960_InitializeController initializes Controller. -*/ - -static bool -DAC960_InitializeController(DAC960_Controller_T *Controller) -{ - if (DAC960_ReadControllerConfiguration(Controller) && - DAC960_ReportControllerConfiguration(Controller) && - DAC960_CreateAuxiliaryStructures(Controller) && - DAC960_ReadDeviceConfiguration(Controller) && - DAC960_ReportDeviceConfiguration(Controller) && - DAC960_RegisterBlockDevice(Controller)) - { - /* - Initialize the Monitoring Timer. - */ - timer_setup(&Controller->MonitoringTimer, - DAC960_MonitoringTimerFunction, 0); - Controller->MonitoringTimer.expires = - jiffies + DAC960_MonitoringTimerInterval; - add_timer(&Controller->MonitoringTimer); - Controller->ControllerInitialized = true; - return true; - } - return false; -} - - -/* - DAC960_FinalizeController finalizes Controller. -*/ - -static void DAC960_FinalizeController(DAC960_Controller_T *Controller) -{ - if (Controller->ControllerInitialized) - { - unsigned long flags; - - /* - * Acquiring and releasing lock here eliminates - * a very low probability race. - * - * The code below allocates controller command structures - * from the free list without holding the controller lock. - * This is safe assuming there is no other activity on - * the controller at the time. - * - * But, there might be a monitoring command still - * in progress. Setting the Shutdown flag while holding - * the lock ensures that there is no monitoring command - * in the interrupt handler currently, and any monitoring - * commands that complete from this time on will NOT return - * their command structure to the free list. - */ - - spin_lock_irqsave(&Controller->queue_lock, flags); - Controller->ShutdownMonitoringTimer = 1; - spin_unlock_irqrestore(&Controller->queue_lock, flags); - - del_timer_sync(&Controller->MonitoringTimer); - if (Controller->FirmwareType == DAC960_V1_Controller) - { - DAC960_Notice("Flushing Cache...", Controller); - DAC960_V1_ExecuteType3(Controller, DAC960_V1_Flush, 0); - DAC960_Notice("done\n", Controller); - - if (Controller->HardwareType == DAC960_PD_Controller) - release_region(Controller->IO_Address, 0x80); - } - else - { - DAC960_Notice("Flushing Cache...", Controller); - DAC960_V2_DeviceOperation(Controller, DAC960_V2_PauseDevice, - DAC960_V2_RAID_Controller); - DAC960_Notice("done\n", Controller); - } - } - DAC960_UnregisterBlockDevice(Controller); - DAC960_DestroyAuxiliaryStructures(Controller); - DAC960_DestroyProcEntries(Controller); - DAC960_DetectCleanup(Controller); -} - - -/* - DAC960_Probe verifies controller's existence and - initializes the DAC960 Driver for that controller. -*/ - -static int -DAC960_Probe(struct pci_dev *dev, const struct pci_device_id *entry) -{ - int disk; - DAC960_Controller_T *Controller; - - if (DAC960_ControllerCount == DAC960_MaxControllers) - { - DAC960_Error("More than %d DAC960 Controllers detected - " - "ignoring from Controller at\n", - NULL, DAC960_MaxControllers); - return -ENODEV; - } - - Controller = DAC960_DetectController(dev, entry); - if (!Controller) - return -ENODEV; - - if (!DAC960_InitializeController(Controller)) { - DAC960_FinalizeController(Controller); - return -ENODEV; - } - - for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) { - set_capacity(Controller->disks[disk], disk_size(Controller, disk)); - add_disk(Controller->disks[disk]); - } - DAC960_CreateProcEntries(Controller); - return 0; -} - - -/* - DAC960_Finalize finalizes the DAC960 Driver. -*/ - -static void DAC960_Remove(struct pci_dev *PCI_Device) -{ - int Controller_Number = (long)pci_get_drvdata(PCI_Device); - DAC960_Controller_T *Controller = DAC960_Controllers[Controller_Number]; - if (Controller != NULL) - DAC960_FinalizeController(Controller); -} - - -/* - DAC960_V1_QueueReadWriteCommand prepares and queues a Read/Write Command for - DAC960 V1 Firmware Controllers. -*/ - -static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_ScatterGatherSegment_T *ScatterGatherList = - Command->V1.ScatterGatherList; - struct scatterlist *ScatterList = Command->V1.ScatterList; - - DAC960_V1_ClearCommand(Command); - - if (Command->SegmentCount == 1) - { - if (Command->DmaDirection == PCI_DMA_FROMDEVICE) - CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read; - else - CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write; - - CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; - CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; - CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; - CommandMailbox->Type5.BusAddress = - (DAC960_BusAddress32_T)sg_dma_address(ScatterList); - } - else - { - int i; - - if (Command->DmaDirection == PCI_DMA_FROMDEVICE) - CommandMailbox->Type5.CommandOpcode = DAC960_V1_ReadWithScatterGather; - else - CommandMailbox->Type5.CommandOpcode = DAC960_V1_WriteWithScatterGather; - - CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; - CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; - CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; - CommandMailbox->Type5.BusAddress = Command->V1.ScatterGatherListDMA; - - CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount; - - for (i = 0; i < Command->SegmentCount; i++, ScatterList++, ScatterGatherList++) { - ScatterGatherList->SegmentDataPointer = - (DAC960_BusAddress32_T)sg_dma_address(ScatterList); - ScatterGatherList->SegmentByteCount = - (DAC960_ByteCount32_T)sg_dma_len(ScatterList); - } - } - DAC960_QueueCommand(Command); -} - - -/* - DAC960_V2_QueueReadWriteCommand prepares and queues a Read/Write Command for - DAC960 V2 Firmware Controllers. -*/ - -static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - struct scatterlist *ScatterList = Command->V2.ScatterList; - - DAC960_V2_ClearCommand(Command); - - CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10; - CommandMailbox->SCSI_10.CommandControlBits.DataTransferControllerToHost = - (Command->DmaDirection == PCI_DMA_FROMDEVICE); - CommandMailbox->SCSI_10.DataTransferSize = - Command->BlockCount << DAC960_BlockSizeBits; - CommandMailbox->SCSI_10.RequestSenseBusAddress = Command->V2.RequestSenseDMA; - CommandMailbox->SCSI_10.PhysicalDevice = - Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber]; - CommandMailbox->SCSI_10.RequestSenseSize = sizeof(DAC960_SCSI_RequestSense_T); - CommandMailbox->SCSI_10.CDBLength = 10; - CommandMailbox->SCSI_10.SCSI_CDB[0] = - (Command->DmaDirection == PCI_DMA_FROMDEVICE ? 0x28 : 0x2A); - CommandMailbox->SCSI_10.SCSI_CDB[2] = Command->BlockNumber >> 24; - CommandMailbox->SCSI_10.SCSI_CDB[3] = Command->BlockNumber >> 16; - CommandMailbox->SCSI_10.SCSI_CDB[4] = Command->BlockNumber >> 8; - CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber; - CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8; - CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount; - - if (Command->SegmentCount == 1) - { - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - (DAC960_BusAddress64_T)sg_dma_address(ScatterList); - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->SCSI_10.DataTransferSize; - } - else - { - DAC960_V2_ScatterGatherSegment_T *ScatterGatherList; - int i; - - if (Command->SegmentCount > 2) - { - ScatterGatherList = Command->V2.ScatterGatherList; - CommandMailbox->SCSI_10.CommandControlBits - .AdditionalScatterGatherListMemory = true; - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ExtendedScatterGather.ScatterGatherList0Length = Command->SegmentCount; - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ExtendedScatterGather.ScatterGatherList0Address = - Command->V2.ScatterGatherListDMA; - } - else - ScatterGatherList = CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments; - - for (i = 0; i < Command->SegmentCount; i++, ScatterList++, ScatterGatherList++) { - ScatterGatherList->SegmentDataPointer = - (DAC960_BusAddress64_T)sg_dma_address(ScatterList); - ScatterGatherList->SegmentByteCount = - (DAC960_ByteCount64_T)sg_dma_len(ScatterList); - } - } - DAC960_QueueCommand(Command); -} - - -static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_queue *req_q) -{ - struct request *Request; - DAC960_Command_T *Command; - - while(1) { - Request = blk_peek_request(req_q); - if (!Request) - return 1; - - Command = DAC960_AllocateCommand(Controller); - if (Command == NULL) - return 0; - - if (rq_data_dir(Request) == READ) { - Command->DmaDirection = PCI_DMA_FROMDEVICE; - Command->CommandType = DAC960_ReadCommand; - } else { - Command->DmaDirection = PCI_DMA_TODEVICE; - Command->CommandType = DAC960_WriteCommand; - } - Command->Completion = Request->end_io_data; - Command->LogicalDriveNumber = (long)Request->rq_disk->private_data; - Command->BlockNumber = blk_rq_pos(Request); - Command->BlockCount = blk_rq_sectors(Request); - Command->Request = Request; - blk_start_request(Request); - Command->SegmentCount = blk_rq_map_sg(req_q, - Command->Request, Command->cmd_sglist); - /* pci_map_sg MAY change the value of SegCount */ - Command->SegmentCount = pci_map_sg(Controller->PCIDevice, Command->cmd_sglist, - Command->SegmentCount, Command->DmaDirection); - - DAC960_QueueReadWriteCommand(Command); - } -} - -/* - DAC960_ProcessRequest attempts to remove one I/O Request from Controller's - I/O Request Queue and queues it to the Controller. WaitForCommand is true if - this function should wait for a Command to become available if necessary. - This function returns true if an I/O Request was queued and false otherwise. -*/ -static void DAC960_ProcessRequest(DAC960_Controller_T *controller) -{ - int i; - - if (!controller->ControllerInitialized) - return; - - /* Do this better later! */ - for (i = controller->req_q_index; i < DAC960_MaxLogicalDrives; i++) { - struct request_queue *req_q = controller->RequestQueue[i]; - - if (req_q == NULL) - continue; - - if (!DAC960_process_queue(controller, req_q)) { - controller->req_q_index = i; - return; - } - } - - if (controller->req_q_index == 0) - return; - - for (i = 0; i < controller->req_q_index; i++) { - struct request_queue *req_q = controller->RequestQueue[i]; - - if (req_q == NULL) - continue; - - if (!DAC960_process_queue(controller, req_q)) { - controller->req_q_index = i; - return; - } - } -} - - -/* - DAC960_queue_partial_rw extracts one bio from the request already - associated with argument command, and construct a new command block to retry I/O - only on that bio. Queue that command to the controller. - - This function re-uses a previously-allocated Command, - there is no failure mode from trying to allocate a command. -*/ - -static void DAC960_queue_partial_rw(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - struct request *Request = Command->Request; - struct request_queue *req_q = Controller->RequestQueue[Command->LogicalDriveNumber]; - - if (Command->DmaDirection == PCI_DMA_FROMDEVICE) - Command->CommandType = DAC960_ReadRetryCommand; - else - Command->CommandType = DAC960_WriteRetryCommand; - - /* - * We could be more efficient with these mapping requests - * and map only the portions that we need. But since this - * code should almost never be called, just go with a - * simple coding. - */ - (void)blk_rq_map_sg(req_q, Command->Request, Command->cmd_sglist); - - (void)pci_map_sg(Controller->PCIDevice, Command->cmd_sglist, 1, Command->DmaDirection); - /* - * Resubmitting the request sector at a time is really tedious. - * But, this should almost never happen. So, we're willing to pay - * this price so that in the end, as much of the transfer is completed - * successfully as possible. - */ - Command->SegmentCount = 1; - Command->BlockNumber = blk_rq_pos(Request); - Command->BlockCount = 1; - DAC960_QueueReadWriteCommand(Command); - return; -} - -/* - DAC960_RequestFunction is the I/O Request Function for DAC960 Controllers. -*/ - -static void DAC960_RequestFunction(struct request_queue *RequestQueue) -{ - DAC960_ProcessRequest(RequestQueue->queuedata); -} - -/* - DAC960_ProcessCompletedBuffer performs completion processing for an - individual Buffer. -*/ - -static inline bool DAC960_ProcessCompletedRequest(DAC960_Command_T *Command, - bool SuccessfulIO) -{ - struct request *Request = Command->Request; - blk_status_t Error = SuccessfulIO ? BLK_STS_OK : BLK_STS_IOERR; - - pci_unmap_sg(Command->Controller->PCIDevice, Command->cmd_sglist, - Command->SegmentCount, Command->DmaDirection); - - if (!__blk_end_request(Request, Error, Command->BlockCount << 9)) { - if (Command->Completion) { - complete(Command->Completion); - Command->Completion = NULL; - } - return true; - } - return false; -} - -/* - DAC960_V1_ReadWriteError prints an appropriate error message for Command - when an error occurs on a Read or Write operation. -*/ - -static void DAC960_V1_ReadWriteError(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - unsigned char *CommandName = "UNKNOWN"; - switch (Command->CommandType) - { - case DAC960_ReadCommand: - case DAC960_ReadRetryCommand: - CommandName = "READ"; - break; - case DAC960_WriteCommand: - case DAC960_WriteRetryCommand: - CommandName = "WRITE"; - break; - case DAC960_MonitoringCommand: - case DAC960_ImmediateCommand: - case DAC960_QueuedCommand: - break; - } - switch (Command->V1.CommandStatus) - { - case DAC960_V1_IrrecoverableDataError: - DAC960_Error("Irrecoverable Data Error on %s:\n", - Controller, CommandName); - break; - case DAC960_V1_LogicalDriveNonexistentOrOffline: - DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n", - Controller, CommandName); - break; - case DAC960_V1_AccessBeyondEndOfLogicalDrive: - DAC960_Error("Attempt to Access Beyond End of Logical Drive " - "on %s:\n", Controller, CommandName); - break; - case DAC960_V1_BadDataEncountered: - DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName); - break; - default: - DAC960_Error("Unexpected Error Status %04X on %s:\n", - Controller, Command->V1.CommandStatus, CommandName); - break; - } - DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %u..%u\n", - Controller, Controller->ControllerNumber, - Command->LogicalDriveNumber, Command->BlockNumber, - Command->BlockNumber + Command->BlockCount - 1); -} - - -/* - DAC960_V1_ProcessCompletedCommand performs completion processing for Command - for DAC960 V1 Firmware Controllers. -*/ - -static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - DAC960_CommandType_T CommandType = Command->CommandType; - DAC960_V1_CommandOpcode_T CommandOpcode = - Command->V1.CommandMailbox.Common.CommandOpcode; - DAC960_V1_CommandStatus_T CommandStatus = Command->V1.CommandStatus; - - if (CommandType == DAC960_ReadCommand || - CommandType == DAC960_WriteCommand) - { - -#ifdef FORCE_RETRY_DEBUG - CommandStatus = DAC960_V1_IrrecoverableDataError; -#endif - - if (CommandStatus == DAC960_V1_NormalCompletion) { - - if (!DAC960_ProcessCompletedRequest(Command, true)) - BUG(); - - } else if (CommandStatus == DAC960_V1_IrrecoverableDataError || - CommandStatus == DAC960_V1_BadDataEncountered) - { - /* - * break the command down into pieces and resubmit each - * piece, hoping that some of them will succeed. - */ - DAC960_queue_partial_rw(Command); - return; - } - else - { - if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline) - DAC960_V1_ReadWriteError(Command); - - if (!DAC960_ProcessCompletedRequest(Command, false)) - BUG(); - } - } - else if (CommandType == DAC960_ReadRetryCommand || - CommandType == DAC960_WriteRetryCommand) - { - bool normal_completion; -#ifdef FORCE_RETRY_FAILURE_DEBUG - static int retry_count = 1; -#endif - /* - Perform completion processing for the portion that was - retried, and submit the next portion, if any. - */ - normal_completion = true; - if (CommandStatus != DAC960_V1_NormalCompletion) { - normal_completion = false; - if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline) - DAC960_V1_ReadWriteError(Command); - } - -#ifdef FORCE_RETRY_FAILURE_DEBUG - if (!(++retry_count % 10000)) { - printk("V1 error retry failure test\n"); - normal_completion = false; - DAC960_V1_ReadWriteError(Command); - } -#endif - - if (!DAC960_ProcessCompletedRequest(Command, normal_completion)) { - DAC960_queue_partial_rw(Command); - return; - } - } - - else if (CommandType == DAC960_MonitoringCommand) - { - if (Controller->ShutdownMonitoringTimer) - return; - if (CommandOpcode == DAC960_V1_Enquiry) - { - DAC960_V1_Enquiry_T *OldEnquiry = &Controller->V1.Enquiry; - DAC960_V1_Enquiry_T *NewEnquiry = Controller->V1.NewEnquiry; - unsigned int OldCriticalLogicalDriveCount = - OldEnquiry->CriticalLogicalDriveCount; - unsigned int NewCriticalLogicalDriveCount = - NewEnquiry->CriticalLogicalDriveCount; - if (NewEnquiry->NumberOfLogicalDrives > Controller->LogicalDriveCount) - { - int LogicalDriveNumber = Controller->LogicalDriveCount - 1; - while (++LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives) - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "Now Exists\n", Controller, - LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives; - DAC960_ComputeGenericDiskInfo(Controller); - } - if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount) - { - int LogicalDriveNumber = NewEnquiry->NumberOfLogicalDrives - 1; - while (++LogicalDriveNumber < Controller->LogicalDriveCount) - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "No Longer Exists\n", Controller, - LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives; - DAC960_ComputeGenericDiskInfo(Controller); - } - if (NewEnquiry->StatusFlags.DeferredWriteError != - OldEnquiry->StatusFlags.DeferredWriteError) - DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller, - (NewEnquiry->StatusFlags.DeferredWriteError - ? "TRUE" : "FALSE")); - if ((NewCriticalLogicalDriveCount > 0 || - NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) || - (NewEnquiry->OfflineLogicalDriveCount > 0 || - NewEnquiry->OfflineLogicalDriveCount != - OldEnquiry->OfflineLogicalDriveCount) || - (NewEnquiry->DeadDriveCount > 0 || - NewEnquiry->DeadDriveCount != - OldEnquiry->DeadDriveCount) || - (NewEnquiry->EventLogSequenceNumber != - OldEnquiry->EventLogSequenceNumber) || - Controller->MonitoringTimerCount == 0 || - time_after_eq(jiffies, Controller->SecondaryMonitoringTime - + DAC960_SecondaryMonitoringInterval)) - { - Controller->V1.NeedLogicalDriveInformation = true; - Controller->V1.NewEventLogSequenceNumber = - NewEnquiry->EventLogSequenceNumber; - Controller->V1.NeedErrorTableInformation = true; - Controller->V1.NeedDeviceStateInformation = true; - Controller->V1.StartDeviceStateScan = true; - Controller->V1.NeedBackgroundInitializationStatus = - Controller->V1.BackgroundInitializationStatusSupported; - Controller->SecondaryMonitoringTime = jiffies; - } - if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress || - NewEnquiry->RebuildFlag - == DAC960_V1_BackgroundRebuildInProgress || - OldEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress || - OldEnquiry->RebuildFlag == DAC960_V1_BackgroundRebuildInProgress) - { - Controller->V1.NeedRebuildProgress = true; - Controller->V1.RebuildProgressFirst = - (NewEnquiry->CriticalLogicalDriveCount < - OldEnquiry->CriticalLogicalDriveCount); - } - if (OldEnquiry->RebuildFlag == DAC960_V1_BackgroundCheckInProgress) - switch (NewEnquiry->RebuildFlag) - { - case DAC960_V1_NoStandbyRebuildOrCheckInProgress: - DAC960_Progress("Consistency Check Completed Successfully\n", - Controller); - break; - case DAC960_V1_StandbyRebuildInProgress: - case DAC960_V1_BackgroundRebuildInProgress: - break; - case DAC960_V1_BackgroundCheckInProgress: - Controller->V1.NeedConsistencyCheckProgress = true; - break; - case DAC960_V1_StandbyRebuildCompletedWithError: - DAC960_Progress("Consistency Check Completed with Error\n", - Controller); - break; - case DAC960_V1_BackgroundRebuildOrCheckFailed_DriveFailed: - DAC960_Progress("Consistency Check Failed - " - "Physical Device Failed\n", Controller); - break; - case DAC960_V1_BackgroundRebuildOrCheckFailed_LogicalDriveFailed: - DAC960_Progress("Consistency Check Failed - " - "Logical Drive Failed\n", Controller); - break; - case DAC960_V1_BackgroundRebuildOrCheckFailed_OtherCauses: - DAC960_Progress("Consistency Check Failed - Other Causes\n", - Controller); - break; - case DAC960_V1_BackgroundRebuildOrCheckSuccessfullyTerminated: - DAC960_Progress("Consistency Check Successfully Terminated\n", - Controller); - break; - } - else if (NewEnquiry->RebuildFlag - == DAC960_V1_BackgroundCheckInProgress) - Controller->V1.NeedConsistencyCheckProgress = true; - Controller->MonitoringAlertMode = - (NewEnquiry->CriticalLogicalDriveCount > 0 || - NewEnquiry->OfflineLogicalDriveCount > 0 || - NewEnquiry->DeadDriveCount > 0); - if (NewEnquiry->RebuildFlag > DAC960_V1_BackgroundCheckInProgress) - { - Controller->V1.PendingRebuildFlag = NewEnquiry->RebuildFlag; - Controller->V1.RebuildFlagPending = true; - } - memcpy(&Controller->V1.Enquiry, &Controller->V1.NewEnquiry, - sizeof(DAC960_V1_Enquiry_T)); - } - else if (CommandOpcode == DAC960_V1_PerformEventLogOperation) - { - static char - *DAC960_EventMessages[] = - { "killed because write recovery failed", - "killed because of SCSI bus reset failure", - "killed because of double check condition", - "killed because it was removed", - "killed because of gross error on SCSI chip", - "killed because of bad tag returned from drive", - "killed because of timeout on SCSI command", - "killed because of reset SCSI command issued from system", - "killed because busy or parity error count exceeded limit", - "killed because of 'kill drive' command from system", - "killed because of selection timeout", - "killed due to SCSI phase sequence error", - "killed due to unknown status" }; - DAC960_V1_EventLogEntry_T *EventLogEntry = - Controller->V1.EventLogEntry; - if (EventLogEntry->SequenceNumber == - Controller->V1.OldEventLogSequenceNumber) - { - unsigned char SenseKey = EventLogEntry->SenseKey; - unsigned char AdditionalSenseCode = - EventLogEntry->AdditionalSenseCode; - unsigned char AdditionalSenseCodeQualifier = - EventLogEntry->AdditionalSenseCodeQualifier; - if (SenseKey == DAC960_SenseKey_VendorSpecific && - AdditionalSenseCode == 0x80 && - AdditionalSenseCodeQualifier < - ARRAY_SIZE(DAC960_EventMessages)) - DAC960_Critical("Physical Device %d:%d %s\n", Controller, - EventLogEntry->Channel, - EventLogEntry->TargetID, - DAC960_EventMessages[ - AdditionalSenseCodeQualifier]); - else if (SenseKey == DAC960_SenseKey_UnitAttention && - AdditionalSenseCode == 0x29) - { - if (Controller->MonitoringTimerCount > 0) - Controller->V1.DeviceResetCount[EventLogEntry->Channel] - [EventLogEntry->TargetID]++; - } - else if (!(SenseKey == DAC960_SenseKey_NoSense || - (SenseKey == DAC960_SenseKey_NotReady && - AdditionalSenseCode == 0x04 && - (AdditionalSenseCodeQualifier == 0x01 || - AdditionalSenseCodeQualifier == 0x02)))) - { - DAC960_Critical("Physical Device %d:%d Error Log: " - "Sense Key = %X, ASC = %02X, ASCQ = %02X\n", - Controller, - EventLogEntry->Channel, - EventLogEntry->TargetID, - SenseKey, - AdditionalSenseCode, - AdditionalSenseCodeQualifier); - DAC960_Critical("Physical Device %d:%d Error Log: " - "Information = %02X%02X%02X%02X " - "%02X%02X%02X%02X\n", - Controller, - EventLogEntry->Channel, - EventLogEntry->TargetID, - EventLogEntry->Information[0], - EventLogEntry->Information[1], - EventLogEntry->Information[2], - EventLogEntry->Information[3], - EventLogEntry->CommandSpecificInformation[0], - EventLogEntry->CommandSpecificInformation[1], - EventLogEntry->CommandSpecificInformation[2], - EventLogEntry->CommandSpecificInformation[3]); - } - } - Controller->V1.OldEventLogSequenceNumber++; - } - else if (CommandOpcode == DAC960_V1_GetErrorTable) - { - DAC960_V1_ErrorTable_T *OldErrorTable = &Controller->V1.ErrorTable; - DAC960_V1_ErrorTable_T *NewErrorTable = Controller->V1.NewErrorTable; - int Channel, TargetID; - for (Channel = 0; Channel < Controller->Channels; Channel++) - for (TargetID = 0; TargetID < Controller->Targets; TargetID++) - { - DAC960_V1_ErrorTableEntry_T *NewErrorEntry = - &NewErrorTable->ErrorTableEntries[Channel][TargetID]; - DAC960_V1_ErrorTableEntry_T *OldErrorEntry = - &OldErrorTable->ErrorTableEntries[Channel][TargetID]; - if ((NewErrorEntry->ParityErrorCount != - OldErrorEntry->ParityErrorCount) || - (NewErrorEntry->SoftErrorCount != - OldErrorEntry->SoftErrorCount) || - (NewErrorEntry->HardErrorCount != - OldErrorEntry->HardErrorCount) || - (NewErrorEntry->MiscErrorCount != - OldErrorEntry->MiscErrorCount)) - DAC960_Critical("Physical Device %d:%d Errors: " - "Parity = %d, Soft = %d, " - "Hard = %d, Misc = %d\n", - Controller, Channel, TargetID, - NewErrorEntry->ParityErrorCount, - NewErrorEntry->SoftErrorCount, - NewErrorEntry->HardErrorCount, - NewErrorEntry->MiscErrorCount); - } - memcpy(&Controller->V1.ErrorTable, Controller->V1.NewErrorTable, - sizeof(DAC960_V1_ErrorTable_T)); - } - else if (CommandOpcode == DAC960_V1_GetDeviceState) - { - DAC960_V1_DeviceState_T *OldDeviceState = - &Controller->V1.DeviceState[Controller->V1.DeviceStateChannel] - [Controller->V1.DeviceStateTargetID]; - DAC960_V1_DeviceState_T *NewDeviceState = - Controller->V1.NewDeviceState; - if (NewDeviceState->DeviceState != OldDeviceState->DeviceState) - DAC960_Critical("Physical Device %d:%d is now %s\n", Controller, - Controller->V1.DeviceStateChannel, - Controller->V1.DeviceStateTargetID, - (NewDeviceState->DeviceState - == DAC960_V1_Device_Dead - ? "DEAD" - : NewDeviceState->DeviceState - == DAC960_V1_Device_WriteOnly - ? "WRITE-ONLY" - : NewDeviceState->DeviceState - == DAC960_V1_Device_Online - ? "ONLINE" : "STANDBY")); - if (OldDeviceState->DeviceState == DAC960_V1_Device_Dead && - NewDeviceState->DeviceState != DAC960_V1_Device_Dead) - { - Controller->V1.NeedDeviceInquiryInformation = true; - Controller->V1.NeedDeviceSerialNumberInformation = true; - Controller->V1.DeviceResetCount - [Controller->V1.DeviceStateChannel] - [Controller->V1.DeviceStateTargetID] = 0; - } - memcpy(OldDeviceState, NewDeviceState, - sizeof(DAC960_V1_DeviceState_T)); - } - else if (CommandOpcode == DAC960_V1_GetLogicalDriveInformation) - { - int LogicalDriveNumber; - for (LogicalDriveNumber = 0; - LogicalDriveNumber < Controller->LogicalDriveCount; - LogicalDriveNumber++) - { - DAC960_V1_LogicalDriveInformation_T *OldLogicalDriveInformation = - &Controller->V1.LogicalDriveInformation[LogicalDriveNumber]; - DAC960_V1_LogicalDriveInformation_T *NewLogicalDriveInformation = - &(*Controller->V1.NewLogicalDriveInformation)[LogicalDriveNumber]; - if (NewLogicalDriveInformation->LogicalDriveState != - OldLogicalDriveInformation->LogicalDriveState) - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "is now %s\n", Controller, - LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, - (NewLogicalDriveInformation->LogicalDriveState - == DAC960_V1_LogicalDrive_Online - ? "ONLINE" - : NewLogicalDriveInformation->LogicalDriveState - == DAC960_V1_LogicalDrive_Critical - ? "CRITICAL" : "OFFLINE")); - if (NewLogicalDriveInformation->WriteBack != - OldLogicalDriveInformation->WriteBack) - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "is now %s\n", Controller, - LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, - (NewLogicalDriveInformation->WriteBack - ? "WRITE BACK" : "WRITE THRU")); - } - memcpy(&Controller->V1.LogicalDriveInformation, - Controller->V1.NewLogicalDriveInformation, - sizeof(DAC960_V1_LogicalDriveInformationArray_T)); - } - else if (CommandOpcode == DAC960_V1_GetRebuildProgress) - { - unsigned int LogicalDriveNumber = - Controller->V1.RebuildProgress->LogicalDriveNumber; - unsigned int LogicalDriveSize = - Controller->V1.RebuildProgress->LogicalDriveSize; - unsigned int BlocksCompleted = - LogicalDriveSize - Controller->V1.RebuildProgress->RemainingBlocks; - if (CommandStatus == DAC960_V1_NoRebuildOrCheckInProgress && - Controller->V1.LastRebuildStatus == DAC960_V1_NormalCompletion) - CommandStatus = DAC960_V1_RebuildSuccessful; - switch (CommandStatus) - { - case DAC960_V1_NormalCompletion: - Controller->EphemeralProgressMessage = true; - DAC960_Progress("Rebuild in Progress: " - "Logical Drive %d (/dev/rd/c%dd%d) " - "%d%% completed\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, - (100 * (BlocksCompleted >> 7)) - / (LogicalDriveSize >> 7)); - Controller->EphemeralProgressMessage = false; - break; - case DAC960_V1_RebuildFailed_LogicalDriveFailure: - DAC960_Progress("Rebuild Failed due to " - "Logical Drive Failure\n", Controller); - break; - case DAC960_V1_RebuildFailed_BadBlocksOnOther: - DAC960_Progress("Rebuild Failed due to " - "Bad Blocks on Other Drives\n", Controller); - break; - case DAC960_V1_RebuildFailed_NewDriveFailed: - DAC960_Progress("Rebuild Failed due to " - "Failure of Drive Being Rebuilt\n", Controller); - break; - case DAC960_V1_NoRebuildOrCheckInProgress: - break; - case DAC960_V1_RebuildSuccessful: - DAC960_Progress("Rebuild Completed Successfully\n", Controller); - break; - case DAC960_V1_RebuildSuccessfullyTerminated: - DAC960_Progress("Rebuild Successfully Terminated\n", Controller); - break; - } - Controller->V1.LastRebuildStatus = CommandStatus; - if (CommandType != DAC960_MonitoringCommand && - Controller->V1.RebuildStatusPending) - { - Command->V1.CommandStatus = Controller->V1.PendingRebuildStatus; - Controller->V1.RebuildStatusPending = false; - } - else if (CommandType == DAC960_MonitoringCommand && - CommandStatus != DAC960_V1_NormalCompletion && - CommandStatus != DAC960_V1_NoRebuildOrCheckInProgress) - { - Controller->V1.PendingRebuildStatus = CommandStatus; - Controller->V1.RebuildStatusPending = true; - } - } - else if (CommandOpcode == DAC960_V1_RebuildStat) - { - unsigned int LogicalDriveNumber = - Controller->V1.RebuildProgress->LogicalDriveNumber; - unsigned int LogicalDriveSize = - Controller->V1.RebuildProgress->LogicalDriveSize; - unsigned int BlocksCompleted = - LogicalDriveSize - Controller->V1.RebuildProgress->RemainingBlocks; - if (CommandStatus == DAC960_V1_NormalCompletion) - { - Controller->EphemeralProgressMessage = true; - DAC960_Progress("Consistency Check in Progress: " - "Logical Drive %d (/dev/rd/c%dd%d) " - "%d%% completed\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, - (100 * (BlocksCompleted >> 7)) - / (LogicalDriveSize >> 7)); - Controller->EphemeralProgressMessage = false; - } - } - else if (CommandOpcode == DAC960_V1_BackgroundInitializationControl) - { - unsigned int LogicalDriveNumber = - Controller->V1.BackgroundInitializationStatus->LogicalDriveNumber; - unsigned int LogicalDriveSize = - Controller->V1.BackgroundInitializationStatus->LogicalDriveSize; - unsigned int BlocksCompleted = - Controller->V1.BackgroundInitializationStatus->BlocksCompleted; - switch (CommandStatus) - { - case DAC960_V1_NormalCompletion: - switch (Controller->V1.BackgroundInitializationStatus->Status) - { - case DAC960_V1_BackgroundInitializationInvalid: - break; - case DAC960_V1_BackgroundInitializationStarted: - DAC960_Progress("Background Initialization Started\n", - Controller); - break; - case DAC960_V1_BackgroundInitializationInProgress: - if (BlocksCompleted == - Controller->V1.LastBackgroundInitializationStatus. - BlocksCompleted && - LogicalDriveNumber == - Controller->V1.LastBackgroundInitializationStatus. - LogicalDriveNumber) - break; - Controller->EphemeralProgressMessage = true; - DAC960_Progress("Background Initialization in Progress: " - "Logical Drive %d (/dev/rd/c%dd%d) " - "%d%% completed\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, - (100 * (BlocksCompleted >> 7)) - / (LogicalDriveSize >> 7)); - Controller->EphemeralProgressMessage = false; - break; - case DAC960_V1_BackgroundInitializationSuspended: - DAC960_Progress("Background Initialization Suspended\n", - Controller); - break; - case DAC960_V1_BackgroundInitializationCancelled: - DAC960_Progress("Background Initialization Cancelled\n", - Controller); - break; - } - memcpy(&Controller->V1.LastBackgroundInitializationStatus, - Controller->V1.BackgroundInitializationStatus, - sizeof(DAC960_V1_BackgroundInitializationStatus_T)); - break; - case DAC960_V1_BackgroundInitSuccessful: - if (Controller->V1.BackgroundInitializationStatus->Status == - DAC960_V1_BackgroundInitializationInProgress) - DAC960_Progress("Background Initialization " - "Completed Successfully\n", Controller); - Controller->V1.BackgroundInitializationStatus->Status = - DAC960_V1_BackgroundInitializationInvalid; - break; - case DAC960_V1_BackgroundInitAborted: - if (Controller->V1.BackgroundInitializationStatus->Status == - DAC960_V1_BackgroundInitializationInProgress) - DAC960_Progress("Background Initialization Aborted\n", - Controller); - Controller->V1.BackgroundInitializationStatus->Status = - DAC960_V1_BackgroundInitializationInvalid; - break; - case DAC960_V1_NoBackgroundInitInProgress: - break; - } - } - else if (CommandOpcode == DAC960_V1_DCDB) - { - /* - This is a bit ugly. - - The InquiryStandardData and - the InquiryUntitSerialNumber information - retrieval operations BOTH use the DAC960_V1_DCDB - commands. the test above can't distinguish between - these two cases. - - Instead, we rely on the order of code later in this - function to ensure that DeviceInquiryInformation commands - are submitted before DeviceSerialNumber commands. - */ - if (Controller->V1.NeedDeviceInquiryInformation) - { - DAC960_SCSI_Inquiry_T *InquiryStandardData = - &Controller->V1.InquiryStandardData - [Controller->V1.DeviceStateChannel] - [Controller->V1.DeviceStateTargetID]; - if (CommandStatus != DAC960_V1_NormalCompletion) - { - memset(InquiryStandardData, 0, - sizeof(DAC960_SCSI_Inquiry_T)); - InquiryStandardData->PeripheralDeviceType = 0x1F; - } - else - memcpy(InquiryStandardData, - Controller->V1.NewInquiryStandardData, - sizeof(DAC960_SCSI_Inquiry_T)); - Controller->V1.NeedDeviceInquiryInformation = false; - } - else if (Controller->V1.NeedDeviceSerialNumberInformation) - { - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - &Controller->V1.InquiryUnitSerialNumber - [Controller->V1.DeviceStateChannel] - [Controller->V1.DeviceStateTargetID]; - if (CommandStatus != DAC960_V1_NormalCompletion) - { - memset(InquiryUnitSerialNumber, 0, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - } - else - memcpy(InquiryUnitSerialNumber, - Controller->V1.NewInquiryUnitSerialNumber, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - Controller->V1.NeedDeviceSerialNumberInformation = false; - } - } - /* - Begin submitting new monitoring commands. - */ - if (Controller->V1.NewEventLogSequenceNumber - - Controller->V1.OldEventLogSequenceNumber > 0) - { - Command->V1.CommandMailbox.Type3E.CommandOpcode = - DAC960_V1_PerformEventLogOperation; - Command->V1.CommandMailbox.Type3E.OperationType = - DAC960_V1_GetEventLogEntry; - Command->V1.CommandMailbox.Type3E.OperationQualifier = 1; - Command->V1.CommandMailbox.Type3E.SequenceNumber = - Controller->V1.OldEventLogSequenceNumber; - Command->V1.CommandMailbox.Type3E.BusAddress = - Controller->V1.EventLogEntryDMA; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.NeedErrorTableInformation) - { - Controller->V1.NeedErrorTableInformation = false; - Command->V1.CommandMailbox.Type3.CommandOpcode = - DAC960_V1_GetErrorTable; - Command->V1.CommandMailbox.Type3.BusAddress = - Controller->V1.NewErrorTableDMA; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.NeedRebuildProgress && - Controller->V1.RebuildProgressFirst) - { - Controller->V1.NeedRebuildProgress = false; - Command->V1.CommandMailbox.Type3.CommandOpcode = - DAC960_V1_GetRebuildProgress; - Command->V1.CommandMailbox.Type3.BusAddress = - Controller->V1.RebuildProgressDMA; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.NeedDeviceStateInformation) - { - if (Controller->V1.NeedDeviceInquiryInformation) - { - DAC960_V1_DCDB_T *DCDB = Controller->V1.MonitoringDCDB; - dma_addr_t DCDB_DMA = Controller->V1.MonitoringDCDB_DMA; - - dma_addr_t NewInquiryStandardDataDMA = - Controller->V1.NewInquiryStandardDataDMA; - - Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; - Command->V1.CommandMailbox.Type3.BusAddress = DCDB_DMA; - DCDB->Channel = Controller->V1.DeviceStateChannel; - DCDB->TargetID = Controller->V1.DeviceStateTargetID; - DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; - DCDB->EarlyStatus = false; - DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds; - DCDB->NoAutomaticRequestSense = false; - DCDB->DisconnectPermitted = true; - DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->BusAddress = NewInquiryStandardDataDMA; - DCDB->CDBLength = 6; - DCDB->TransferLengthHigh4 = 0; - DCDB->SenseLength = sizeof(DCDB->SenseData); - DCDB->CDB[0] = 0x12; /* INQUIRY */ - DCDB->CDB[1] = 0; /* EVPD = 0 */ - DCDB->CDB[2] = 0; /* Page Code */ - DCDB->CDB[3] = 0; /* Reserved */ - DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->CDB[5] = 0; /* Control */ - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.NeedDeviceSerialNumberInformation) - { - DAC960_V1_DCDB_T *DCDB = Controller->V1.MonitoringDCDB; - dma_addr_t DCDB_DMA = Controller->V1.MonitoringDCDB_DMA; - dma_addr_t NewInquiryUnitSerialNumberDMA = - Controller->V1.NewInquiryUnitSerialNumberDMA; - - Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; - Command->V1.CommandMailbox.Type3.BusAddress = DCDB_DMA; - DCDB->Channel = Controller->V1.DeviceStateChannel; - DCDB->TargetID = Controller->V1.DeviceStateTargetID; - DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; - DCDB->EarlyStatus = false; - DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds; - DCDB->NoAutomaticRequestSense = false; - DCDB->DisconnectPermitted = true; - DCDB->TransferLength = - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->BusAddress = NewInquiryUnitSerialNumberDMA; - DCDB->CDBLength = 6; - DCDB->TransferLengthHigh4 = 0; - DCDB->SenseLength = sizeof(DCDB->SenseData); - DCDB->CDB[0] = 0x12; /* INQUIRY */ - DCDB->CDB[1] = 1; /* EVPD = 1 */ - DCDB->CDB[2] = 0x80; /* Page Code */ - DCDB->CDB[3] = 0; /* Reserved */ - DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->CDB[5] = 0; /* Control */ - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.StartDeviceStateScan) - { - Controller->V1.DeviceStateChannel = 0; - Controller->V1.DeviceStateTargetID = 0; - Controller->V1.StartDeviceStateScan = false; - } - else if (++Controller->V1.DeviceStateTargetID == Controller->Targets) - { - Controller->V1.DeviceStateChannel++; - Controller->V1.DeviceStateTargetID = 0; - } - if (Controller->V1.DeviceStateChannel < Controller->Channels) - { - Controller->V1.NewDeviceState->DeviceState = - DAC960_V1_Device_Dead; - Command->V1.CommandMailbox.Type3D.CommandOpcode = - DAC960_V1_GetDeviceState; - Command->V1.CommandMailbox.Type3D.Channel = - Controller->V1.DeviceStateChannel; - Command->V1.CommandMailbox.Type3D.TargetID = - Controller->V1.DeviceStateTargetID; - Command->V1.CommandMailbox.Type3D.BusAddress = - Controller->V1.NewDeviceStateDMA; - DAC960_QueueCommand(Command); - return; - } - Controller->V1.NeedDeviceStateInformation = false; - } - if (Controller->V1.NeedLogicalDriveInformation) - { - Controller->V1.NeedLogicalDriveInformation = false; - Command->V1.CommandMailbox.Type3.CommandOpcode = - DAC960_V1_GetLogicalDriveInformation; - Command->V1.CommandMailbox.Type3.BusAddress = - Controller->V1.NewLogicalDriveInformationDMA; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.NeedRebuildProgress) - { - Controller->V1.NeedRebuildProgress = false; - Command->V1.CommandMailbox.Type3.CommandOpcode = - DAC960_V1_GetRebuildProgress; - Command->V1.CommandMailbox.Type3.BusAddress = - Controller->V1.RebuildProgressDMA; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.NeedConsistencyCheckProgress) - { - Controller->V1.NeedConsistencyCheckProgress = false; - Command->V1.CommandMailbox.Type3.CommandOpcode = - DAC960_V1_RebuildStat; - Command->V1.CommandMailbox.Type3.BusAddress = - Controller->V1.RebuildProgressDMA; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V1.NeedBackgroundInitializationStatus) - { - Controller->V1.NeedBackgroundInitializationStatus = false; - Command->V1.CommandMailbox.Type3B.CommandOpcode = - DAC960_V1_BackgroundInitializationControl; - Command->V1.CommandMailbox.Type3B.CommandOpcode2 = 0x20; - Command->V1.CommandMailbox.Type3B.BusAddress = - Controller->V1.BackgroundInitializationStatusDMA; - DAC960_QueueCommand(Command); - return; - } - Controller->MonitoringTimerCount++; - Controller->MonitoringTimer.expires = - jiffies + DAC960_MonitoringTimerInterval; - add_timer(&Controller->MonitoringTimer); - } - if (CommandType == DAC960_ImmediateCommand) - { - complete(Command->Completion); - Command->Completion = NULL; - return; - } - if (CommandType == DAC960_QueuedCommand) - { - DAC960_V1_KernelCommand_T *KernelCommand = Command->V1.KernelCommand; - KernelCommand->CommandStatus = Command->V1.CommandStatus; - Command->V1.KernelCommand = NULL; - if (CommandOpcode == DAC960_V1_DCDB) - Controller->V1.DirectCommandActive[KernelCommand->DCDB->Channel] - [KernelCommand->DCDB->TargetID] = - false; - DAC960_DeallocateCommand(Command); - KernelCommand->CompletionFunction(KernelCommand); - return; - } - /* - Queue a Status Monitoring Command to the Controller using the just - completed Command if one was deferred previously due to lack of a - free Command when the Monitoring Timer Function was called. - */ - if (Controller->MonitoringCommandDeferred) - { - Controller->MonitoringCommandDeferred = false; - DAC960_V1_QueueMonitoringCommand(Command); - return; - } - /* - Deallocate the Command. - */ - DAC960_DeallocateCommand(Command); - /* - Wake up any processes waiting on a free Command. - */ - wake_up(&Controller->CommandWaitQueue); -} - - -/* - DAC960_V2_ReadWriteError prints an appropriate error message for Command - when an error occurs on a Read or Write operation. -*/ - -static void DAC960_V2_ReadWriteError(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - static const unsigned char *SenseErrors[] = { - "NO SENSE", "RECOVERED ERROR", - "NOT READY", "MEDIUM ERROR", - "HARDWARE ERROR", "ILLEGAL REQUEST", - "UNIT ATTENTION", "DATA PROTECT", - "BLANK CHECK", "VENDOR-SPECIFIC", - "COPY ABORTED", "ABORTED COMMAND", - "EQUAL", "VOLUME OVERFLOW", - "MISCOMPARE", "RESERVED" - }; - unsigned char *CommandName = "UNKNOWN"; - switch (Command->CommandType) - { - case DAC960_ReadCommand: - case DAC960_ReadRetryCommand: - CommandName = "READ"; - break; - case DAC960_WriteCommand: - case DAC960_WriteRetryCommand: - CommandName = "WRITE"; - break; - case DAC960_MonitoringCommand: - case DAC960_ImmediateCommand: - case DAC960_QueuedCommand: - break; - } - DAC960_Error("Error Condition %s on %s:\n", Controller, - SenseErrors[Command->V2.RequestSense->SenseKey], CommandName); - DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %u..%u\n", - Controller, Controller->ControllerNumber, - Command->LogicalDriveNumber, Command->BlockNumber, - Command->BlockNumber + Command->BlockCount - 1); -} - - -/* - DAC960_V2_ReportEvent prints an appropriate message when a Controller Event - occurs. -*/ - -static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller, - DAC960_V2_Event_T *Event) -{ - DAC960_SCSI_RequestSense_T *RequestSense = - (DAC960_SCSI_RequestSense_T *) &Event->RequestSenseData; - unsigned char MessageBuffer[DAC960_LineBufferSize]; - static struct { int EventCode; unsigned char *EventMessage; } EventList[] = - { /* Physical Device Events (0x0000 - 0x007F) */ - { 0x0001, "P Online" }, - { 0x0002, "P Standby" }, - { 0x0005, "P Automatic Rebuild Started" }, - { 0x0006, "P Manual Rebuild Started" }, - { 0x0007, "P Rebuild Completed" }, - { 0x0008, "P Rebuild Cancelled" }, - { 0x0009, "P Rebuild Failed for Unknown Reasons" }, - { 0x000A, "P Rebuild Failed due to New Physical Device" }, - { 0x000B, "P Rebuild Failed due to Logical Drive Failure" }, - { 0x000C, "S Offline" }, - { 0x000D, "P Found" }, - { 0x000E, "P Removed" }, - { 0x000F, "P Unconfigured" }, - { 0x0010, "P Expand Capacity Started" }, - { 0x0011, "P Expand Capacity Completed" }, - { 0x0012, "P Expand Capacity Failed" }, - { 0x0013, "P Command Timed Out" }, - { 0x0014, "P Command Aborted" }, - { 0x0015, "P Command Retried" }, - { 0x0016, "P Parity Error" }, - { 0x0017, "P Soft Error" }, - { 0x0018, "P Miscellaneous Error" }, - { 0x0019, "P Reset" }, - { 0x001A, "P Active Spare Found" }, - { 0x001B, "P Warm Spare Found" }, - { 0x001C, "S Sense Data Received" }, - { 0x001D, "P Initialization Started" }, - { 0x001E, "P Initialization Completed" }, - { 0x001F, "P Initialization Failed" }, - { 0x0020, "P Initialization Cancelled" }, - { 0x0021, "P Failed because Write Recovery Failed" }, - { 0x0022, "P Failed because SCSI Bus Reset Failed" }, - { 0x0023, "P Failed because of Double Check Condition" }, - { 0x0024, "P Failed because Device Cannot Be Accessed" }, - { 0x0025, "P Failed because of Gross Error on SCSI Processor" }, - { 0x0026, "P Failed because of Bad Tag from Device" }, - { 0x0027, "P Failed because of Command Timeout" }, - { 0x0028, "P Failed because of System Reset" }, - { 0x0029, "P Failed because of Busy Status or Parity Error" }, - { 0x002A, "P Failed because Host Set Device to Failed State" }, - { 0x002B, "P Failed because of Selection Timeout" }, - { 0x002C, "P Failed because of SCSI Bus Phase Error" }, - { 0x002D, "P Failed because Device Returned Unknown Status" }, - { 0x002E, "P Failed because Device Not Ready" }, - { 0x002F, "P Failed because Device Not Found at Startup" }, - { 0x0030, "P Failed because COD Write Operation Failed" }, - { 0x0031, "P Failed because BDT Write Operation Failed" }, - { 0x0039, "P Missing at Startup" }, - { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" }, - { 0x003C, "P Temporarily Offline Device Automatically Made Online" }, - { 0x003D, "P Standby Rebuild Started" }, - /* Logical Device Events (0x0080 - 0x00FF) */ - { 0x0080, "M Consistency Check Started" }, - { 0x0081, "M Consistency Check Completed" }, - { 0x0082, "M Consistency Check Cancelled" }, - { 0x0083, "M Consistency Check Completed With Errors" }, - { 0x0084, "M Consistency Check Failed due to Logical Drive Failure" }, - { 0x0085, "M Consistency Check Failed due to Physical Device Failure" }, - { 0x0086, "L Offline" }, - { 0x0087, "L Critical" }, - { 0x0088, "L Online" }, - { 0x0089, "M Automatic Rebuild Started" }, - { 0x008A, "M Manual Rebuild Started" }, - { 0x008B, "M Rebuild Completed" }, - { 0x008C, "M Rebuild Cancelled" }, - { 0x008D, "M Rebuild Failed for Unknown Reasons" }, - { 0x008E, "M Rebuild Failed due to New Physical Device" }, - { 0x008F, "M Rebuild Failed due to Logical Drive Failure" }, - { 0x0090, "M Initialization Started" }, - { 0x0091, "M Initialization Completed" }, - { 0x0092, "M Initialization Cancelled" }, - { 0x0093, "M Initialization Failed" }, - { 0x0094, "L Found" }, - { 0x0095, "L Deleted" }, - { 0x0096, "M Expand Capacity Started" }, - { 0x0097, "M Expand Capacity Completed" }, - { 0x0098, "M Expand Capacity Failed" }, - { 0x0099, "L Bad Block Found" }, - { 0x009A, "L Size Changed" }, - { 0x009B, "L Type Changed" }, - { 0x009C, "L Bad Data Block Found" }, - { 0x009E, "L Read of Data Block in BDT" }, - { 0x009F, "L Write Back Data for Disk Block Lost" }, - { 0x00A0, "L Temporarily Offline RAID-5/3 Drive Made Online" }, - { 0x00A1, "L Temporarily Offline RAID-6/1/0/7 Drive Made Online" }, - { 0x00A2, "L Standby Rebuild Started" }, - /* Fault Management Events (0x0100 - 0x017F) */ - { 0x0140, "E Fan %d Failed" }, - { 0x0141, "E Fan %d OK" }, - { 0x0142, "E Fan %d Not Present" }, - { 0x0143, "E Power Supply %d Failed" }, - { 0x0144, "E Power Supply %d OK" }, - { 0x0145, "E Power Supply %d Not Present" }, - { 0x0146, "E Temperature Sensor %d Temperature Exceeds Safe Limit" }, - { 0x0147, "E Temperature Sensor %d Temperature Exceeds Working Limit" }, - { 0x0148, "E Temperature Sensor %d Temperature Normal" }, - { 0x0149, "E Temperature Sensor %d Not Present" }, - { 0x014A, "E Enclosure Management Unit %d Access Critical" }, - { 0x014B, "E Enclosure Management Unit %d Access OK" }, - { 0x014C, "E Enclosure Management Unit %d Access Offline" }, - /* Controller Events (0x0180 - 0x01FF) */ - { 0x0181, "C Cache Write Back Error" }, - { 0x0188, "C Battery Backup Unit Found" }, - { 0x0189, "C Battery Backup Unit Charge Level Low" }, - { 0x018A, "C Battery Backup Unit Charge Level OK" }, - { 0x0193, "C Installation Aborted" }, - { 0x0195, "C Battery Backup Unit Physically Removed" }, - { 0x0196, "C Memory Error During Warm Boot" }, - { 0x019E, "C Memory Soft ECC Error Corrected" }, - { 0x019F, "C Memory Hard ECC Error Corrected" }, - { 0x01A2, "C Battery Backup Unit Failed" }, - { 0x01AB, "C Mirror Race Recovery Failed" }, - { 0x01AC, "C Mirror Race on Critical Drive" }, - /* Controller Internal Processor Events */ - { 0x0380, "C Internal Controller Hung" }, - { 0x0381, "C Internal Controller Firmware Breakpoint" }, - { 0x0390, "C Internal Controller i960 Processor Specific Error" }, - { 0x03A0, "C Internal Controller StrongARM Processor Specific Error" }, - { 0, "" } }; - int EventListIndex = 0, EventCode; - unsigned char EventType, *EventMessage; - if (Event->EventCode == 0x1C && - RequestSense->SenseKey == DAC960_SenseKey_VendorSpecific && - (RequestSense->AdditionalSenseCode == 0x80 || - RequestSense->AdditionalSenseCode == 0x81)) - Event->EventCode = ((RequestSense->AdditionalSenseCode - 0x80) << 8) | - RequestSense->AdditionalSenseCodeQualifier; - while (true) - { - EventCode = EventList[EventListIndex].EventCode; - if (EventCode == Event->EventCode || EventCode == 0) break; - EventListIndex++; - } - EventType = EventList[EventListIndex].EventMessage[0]; - EventMessage = &EventList[EventListIndex].EventMessage[2]; - if (EventCode == 0) - { - DAC960_Critical("Unknown Controller Event Code %04X\n", - Controller, Event->EventCode); - return; - } - switch (EventType) - { - case 'P': - DAC960_Critical("Physical Device %d:%d %s\n", Controller, - Event->Channel, Event->TargetID, EventMessage); - break; - case 'L': - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller, - Event->LogicalUnit, Controller->ControllerNumber, - Event->LogicalUnit, EventMessage); - break; - case 'M': - DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller, - Event->LogicalUnit, Controller->ControllerNumber, - Event->LogicalUnit, EventMessage); - break; - case 'S': - if (RequestSense->SenseKey == DAC960_SenseKey_NoSense || - (RequestSense->SenseKey == DAC960_SenseKey_NotReady && - RequestSense->AdditionalSenseCode == 0x04 && - (RequestSense->AdditionalSenseCodeQualifier == 0x01 || - RequestSense->AdditionalSenseCodeQualifier == 0x02))) - break; - DAC960_Critical("Physical Device %d:%d %s\n", Controller, - Event->Channel, Event->TargetID, EventMessage); - DAC960_Critical("Physical Device %d:%d Request Sense: " - "Sense Key = %X, ASC = %02X, ASCQ = %02X\n", - Controller, - Event->Channel, - Event->TargetID, - RequestSense->SenseKey, - RequestSense->AdditionalSenseCode, - RequestSense->AdditionalSenseCodeQualifier); - DAC960_Critical("Physical Device %d:%d Request Sense: " - "Information = %02X%02X%02X%02X " - "%02X%02X%02X%02X\n", - Controller, - Event->Channel, - Event->TargetID, - RequestSense->Information[0], - RequestSense->Information[1], - RequestSense->Information[2], - RequestSense->Information[3], - RequestSense->CommandSpecificInformation[0], - RequestSense->CommandSpecificInformation[1], - RequestSense->CommandSpecificInformation[2], - RequestSense->CommandSpecificInformation[3]); - break; - case 'E': - if (Controller->SuppressEnclosureMessages) break; - sprintf(MessageBuffer, EventMessage, Event->LogicalUnit); - DAC960_Critical("Enclosure %d %s\n", Controller, - Event->TargetID, MessageBuffer); - break; - case 'C': - DAC960_Critical("Controller %s\n", Controller, EventMessage); - break; - default: - DAC960_Critical("Unknown Controller Event Code %04X\n", - Controller, Event->EventCode); - break; - } -} - - -/* - DAC960_V2_ReportProgress prints an appropriate progress message for - Logical Device Long Operations. -*/ - -static void DAC960_V2_ReportProgress(DAC960_Controller_T *Controller, - unsigned char *MessageString, - unsigned int LogicalDeviceNumber, - unsigned long BlocksCompleted, - unsigned long LogicalDeviceSize) -{ - Controller->EphemeralProgressMessage = true; - DAC960_Progress("%s in Progress: Logical Drive %d (/dev/rd/c%dd%d) " - "%d%% completed\n", Controller, - MessageString, - LogicalDeviceNumber, - Controller->ControllerNumber, - LogicalDeviceNumber, - (100 * (BlocksCompleted >> 7)) / (LogicalDeviceSize >> 7)); - Controller->EphemeralProgressMessage = false; -} - - -/* - DAC960_V2_ProcessCompletedCommand performs completion processing for Command - for DAC960 V2 Firmware Controllers. -*/ - -static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - DAC960_CommandType_T CommandType = Command->CommandType; - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_IOCTL_Opcode_T IOCTLOpcode = CommandMailbox->Common.IOCTL_Opcode; - DAC960_V2_CommandOpcode_T CommandOpcode = CommandMailbox->SCSI_10.CommandOpcode; - DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus; - - if (CommandType == DAC960_ReadCommand || - CommandType == DAC960_WriteCommand) - { - -#ifdef FORCE_RETRY_DEBUG - CommandStatus = DAC960_V2_AbormalCompletion; -#endif - Command->V2.RequestSense->SenseKey = DAC960_SenseKey_MediumError; - - if (CommandStatus == DAC960_V2_NormalCompletion) { - - if (!DAC960_ProcessCompletedRequest(Command, true)) - BUG(); - - } else if (Command->V2.RequestSense->SenseKey == DAC960_SenseKey_MediumError) - { - /* - * break the command down into pieces and resubmit each - * piece, hoping that some of them will succeed. - */ - DAC960_queue_partial_rw(Command); - return; - } - else - { - if (Command->V2.RequestSense->SenseKey != DAC960_SenseKey_NotReady) - DAC960_V2_ReadWriteError(Command); - /* - Perform completion processing for all buffers in this I/O Request. - */ - (void)DAC960_ProcessCompletedRequest(Command, false); - } - } - else if (CommandType == DAC960_ReadRetryCommand || - CommandType == DAC960_WriteRetryCommand) - { - bool normal_completion; - -#ifdef FORCE_RETRY_FAILURE_DEBUG - static int retry_count = 1; -#endif - /* - Perform completion processing for the portion that was - retried, and submit the next portion, if any. - */ - normal_completion = true; - if (CommandStatus != DAC960_V2_NormalCompletion) { - normal_completion = false; - if (Command->V2.RequestSense->SenseKey != DAC960_SenseKey_NotReady) - DAC960_V2_ReadWriteError(Command); - } - -#ifdef FORCE_RETRY_FAILURE_DEBUG - if (!(++retry_count % 10000)) { - printk("V2 error retry failure test\n"); - normal_completion = false; - DAC960_V2_ReadWriteError(Command); - } -#endif - - if (!DAC960_ProcessCompletedRequest(Command, normal_completion)) { - DAC960_queue_partial_rw(Command); - return; - } - } - else if (CommandType == DAC960_MonitoringCommand) - { - if (Controller->ShutdownMonitoringTimer) - return; - if (IOCTLOpcode == DAC960_V2_GetControllerInfo) - { - DAC960_V2_ControllerInfo_T *NewControllerInfo = - Controller->V2.NewControllerInformation; - DAC960_V2_ControllerInfo_T *ControllerInfo = - &Controller->V2.ControllerInformation; - Controller->LogicalDriveCount = - NewControllerInfo->LogicalDevicesPresent; - Controller->V2.NeedLogicalDeviceInformation = true; - Controller->V2.NeedPhysicalDeviceInformation = true; - Controller->V2.StartLogicalDeviceInformationScan = true; - Controller->V2.StartPhysicalDeviceInformationScan = true; - Controller->MonitoringAlertMode = - (NewControllerInfo->LogicalDevicesCritical > 0 || - NewControllerInfo->LogicalDevicesOffline > 0 || - NewControllerInfo->PhysicalDisksCritical > 0 || - NewControllerInfo->PhysicalDisksOffline > 0); - memcpy(ControllerInfo, NewControllerInfo, - sizeof(DAC960_V2_ControllerInfo_T)); - } - else if (IOCTLOpcode == DAC960_V2_GetEvent) - { - if (CommandStatus == DAC960_V2_NormalCompletion) { - DAC960_V2_ReportEvent(Controller, Controller->V2.Event); - } - Controller->V2.NextEventSequenceNumber++; - } - else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid && - CommandStatus == DAC960_V2_NormalCompletion) - { - DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo = - Controller->V2.NewPhysicalDeviceInformation; - unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex; - DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo = - Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex]; - unsigned int DeviceIndex; - while (PhysicalDeviceInfo != NULL && - (NewPhysicalDeviceInfo->Channel > - PhysicalDeviceInfo->Channel || - (NewPhysicalDeviceInfo->Channel == - PhysicalDeviceInfo->Channel && - (NewPhysicalDeviceInfo->TargetID > - PhysicalDeviceInfo->TargetID || - (NewPhysicalDeviceInfo->TargetID == - PhysicalDeviceInfo->TargetID && - NewPhysicalDeviceInfo->LogicalUnit > - PhysicalDeviceInfo->LogicalUnit))))) - { - DAC960_Critical("Physical Device %d:%d No Longer Exists\n", - Controller, - PhysicalDeviceInfo->Channel, - PhysicalDeviceInfo->TargetID); - Controller->V2.PhysicalDeviceInformation - [PhysicalDeviceIndex] = NULL; - Controller->V2.InquiryUnitSerialNumber - [PhysicalDeviceIndex] = NULL; - kfree(PhysicalDeviceInfo); - kfree(InquiryUnitSerialNumber); - for (DeviceIndex = PhysicalDeviceIndex; - DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1; - DeviceIndex++) - { - Controller->V2.PhysicalDeviceInformation[DeviceIndex] = - Controller->V2.PhysicalDeviceInformation[DeviceIndex+1]; - Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = - Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1]; - } - Controller->V2.PhysicalDeviceInformation - [DAC960_V2_MaxPhysicalDevices-1] = NULL; - Controller->V2.InquiryUnitSerialNumber - [DAC960_V2_MaxPhysicalDevices-1] = NULL; - PhysicalDeviceInfo = - Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex]; - InquiryUnitSerialNumber = - Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex]; - } - if (PhysicalDeviceInfo == NULL || - (NewPhysicalDeviceInfo->Channel != - PhysicalDeviceInfo->Channel) || - (NewPhysicalDeviceInfo->TargetID != - PhysicalDeviceInfo->TargetID) || - (NewPhysicalDeviceInfo->LogicalUnit != - PhysicalDeviceInfo->LogicalUnit)) - { - PhysicalDeviceInfo = - kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC); - InquiryUnitSerialNumber = - kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), - GFP_ATOMIC); - if (InquiryUnitSerialNumber == NULL || - PhysicalDeviceInfo == NULL) - { - kfree(InquiryUnitSerialNumber); - InquiryUnitSerialNumber = NULL; - kfree(PhysicalDeviceInfo); - PhysicalDeviceInfo = NULL; - } - DAC960_Critical("Physical Device %d:%d Now Exists%s\n", - Controller, - NewPhysicalDeviceInfo->Channel, - NewPhysicalDeviceInfo->TargetID, - (PhysicalDeviceInfo != NULL - ? "" : " - Allocation Failed")); - if (PhysicalDeviceInfo != NULL) - { - memset(PhysicalDeviceInfo, 0, - sizeof(DAC960_V2_PhysicalDeviceInfo_T)); - PhysicalDeviceInfo->PhysicalDeviceState = - DAC960_V2_Device_InvalidState; - memset(InquiryUnitSerialNumber, 0, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - for (DeviceIndex = DAC960_V2_MaxPhysicalDevices - 1; - DeviceIndex > PhysicalDeviceIndex; - DeviceIndex--) - { - Controller->V2.PhysicalDeviceInformation[DeviceIndex] = - Controller->V2.PhysicalDeviceInformation[DeviceIndex-1]; - Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = - Controller->V2.InquiryUnitSerialNumber[DeviceIndex-1]; - } - Controller->V2.PhysicalDeviceInformation - [PhysicalDeviceIndex] = - PhysicalDeviceInfo; - Controller->V2.InquiryUnitSerialNumber - [PhysicalDeviceIndex] = - InquiryUnitSerialNumber; - Controller->V2.NeedDeviceSerialNumberInformation = true; - } - } - if (PhysicalDeviceInfo != NULL) - { - if (NewPhysicalDeviceInfo->PhysicalDeviceState != - PhysicalDeviceInfo->PhysicalDeviceState) - DAC960_Critical( - "Physical Device %d:%d is now %s\n", Controller, - NewPhysicalDeviceInfo->Channel, - NewPhysicalDeviceInfo->TargetID, - (NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Online - ? "ONLINE" - : NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Rebuild - ? "REBUILD" - : NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Missing - ? "MISSING" - : NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Critical - ? "CRITICAL" - : NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Dead - ? "DEAD" - : NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_SuspectedDead - ? "SUSPECTED-DEAD" - : NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_CommandedOffline - ? "COMMANDED-OFFLINE" - : NewPhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Standby - ? "STANDBY" : "UNKNOWN")); - if ((NewPhysicalDeviceInfo->ParityErrors != - PhysicalDeviceInfo->ParityErrors) || - (NewPhysicalDeviceInfo->SoftErrors != - PhysicalDeviceInfo->SoftErrors) || - (NewPhysicalDeviceInfo->HardErrors != - PhysicalDeviceInfo->HardErrors) || - (NewPhysicalDeviceInfo->MiscellaneousErrors != - PhysicalDeviceInfo->MiscellaneousErrors) || - (NewPhysicalDeviceInfo->CommandTimeouts != - PhysicalDeviceInfo->CommandTimeouts) || - (NewPhysicalDeviceInfo->Retries != - PhysicalDeviceInfo->Retries) || - (NewPhysicalDeviceInfo->Aborts != - PhysicalDeviceInfo->Aborts) || - (NewPhysicalDeviceInfo->PredictedFailuresDetected != - PhysicalDeviceInfo->PredictedFailuresDetected)) - { - DAC960_Critical("Physical Device %d:%d Errors: " - "Parity = %d, Soft = %d, " - "Hard = %d, Misc = %d\n", - Controller, - NewPhysicalDeviceInfo->Channel, - NewPhysicalDeviceInfo->TargetID, - NewPhysicalDeviceInfo->ParityErrors, - NewPhysicalDeviceInfo->SoftErrors, - NewPhysicalDeviceInfo->HardErrors, - NewPhysicalDeviceInfo->MiscellaneousErrors); - DAC960_Critical("Physical Device %d:%d Errors: " - "Timeouts = %d, Retries = %d, " - "Aborts = %d, Predicted = %d\n", - Controller, - NewPhysicalDeviceInfo->Channel, - NewPhysicalDeviceInfo->TargetID, - NewPhysicalDeviceInfo->CommandTimeouts, - NewPhysicalDeviceInfo->Retries, - NewPhysicalDeviceInfo->Aborts, - NewPhysicalDeviceInfo - ->PredictedFailuresDetected); - } - if ((PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_Dead || - PhysicalDeviceInfo->PhysicalDeviceState - == DAC960_V2_Device_InvalidState) && - NewPhysicalDeviceInfo->PhysicalDeviceState - != DAC960_V2_Device_Dead) - Controller->V2.NeedDeviceSerialNumberInformation = true; - memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo, - sizeof(DAC960_V2_PhysicalDeviceInfo_T)); - } - NewPhysicalDeviceInfo->LogicalUnit++; - Controller->V2.PhysicalDeviceIndex++; - } - else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid) - { - unsigned int DeviceIndex; - for (DeviceIndex = Controller->V2.PhysicalDeviceIndex; - DeviceIndex < DAC960_V2_MaxPhysicalDevices; - DeviceIndex++) - { - DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo = - Controller->V2.PhysicalDeviceInformation[DeviceIndex]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - Controller->V2.InquiryUnitSerialNumber[DeviceIndex]; - if (PhysicalDeviceInfo == NULL) break; - DAC960_Critical("Physical Device %d:%d No Longer Exists\n", - Controller, - PhysicalDeviceInfo->Channel, - PhysicalDeviceInfo->TargetID); - Controller->V2.PhysicalDeviceInformation[DeviceIndex] = NULL; - Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = NULL; - kfree(PhysicalDeviceInfo); - kfree(InquiryUnitSerialNumber); - } - Controller->V2.NeedPhysicalDeviceInformation = false; - } - else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid && - CommandStatus == DAC960_V2_NormalCompletion) - { - DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo = - Controller->V2.NewLogicalDeviceInformation; - unsigned short LogicalDeviceNumber = - NewLogicalDeviceInfo->LogicalDeviceNumber; - DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = - Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber]; - if (LogicalDeviceInfo == NULL) - { - DAC960_V2_PhysicalDevice_T PhysicalDevice; - PhysicalDevice.Controller = 0; - PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel; - PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID; - PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit; - Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] = - PhysicalDevice; - LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), - GFP_ATOMIC); - Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] = - LogicalDeviceInfo; - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "Now Exists%s\n", Controller, - LogicalDeviceNumber, - Controller->ControllerNumber, - LogicalDeviceNumber, - (LogicalDeviceInfo != NULL - ? "" : " - Allocation Failed")); - if (LogicalDeviceInfo != NULL) - { - memset(LogicalDeviceInfo, 0, - sizeof(DAC960_V2_LogicalDeviceInfo_T)); - DAC960_ComputeGenericDiskInfo(Controller); - } - } - if (LogicalDeviceInfo != NULL) - { - unsigned long LogicalDeviceSize = - NewLogicalDeviceInfo->ConfigurableDeviceSize; - if (NewLogicalDeviceInfo->LogicalDeviceState != - LogicalDeviceInfo->LogicalDeviceState) - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "is now %s\n", Controller, - LogicalDeviceNumber, - Controller->ControllerNumber, - LogicalDeviceNumber, - (NewLogicalDeviceInfo->LogicalDeviceState - == DAC960_V2_LogicalDevice_Online - ? "ONLINE" - : NewLogicalDeviceInfo->LogicalDeviceState - == DAC960_V2_LogicalDevice_Critical - ? "CRITICAL" : "OFFLINE")); - if ((NewLogicalDeviceInfo->SoftErrors != - LogicalDeviceInfo->SoftErrors) || - (NewLogicalDeviceInfo->CommandsFailed != - LogicalDeviceInfo->CommandsFailed) || - (NewLogicalDeviceInfo->DeferredWriteErrors != - LogicalDeviceInfo->DeferredWriteErrors)) - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) Errors: " - "Soft = %d, Failed = %d, Deferred Write = %d\n", - Controller, LogicalDeviceNumber, - Controller->ControllerNumber, - LogicalDeviceNumber, - NewLogicalDeviceInfo->SoftErrors, - NewLogicalDeviceInfo->CommandsFailed, - NewLogicalDeviceInfo->DeferredWriteErrors); - if (NewLogicalDeviceInfo->ConsistencyCheckInProgress) - DAC960_V2_ReportProgress(Controller, - "Consistency Check", - LogicalDeviceNumber, - NewLogicalDeviceInfo - ->ConsistencyCheckBlockNumber, - LogicalDeviceSize); - else if (NewLogicalDeviceInfo->RebuildInProgress) - DAC960_V2_ReportProgress(Controller, - "Rebuild", - LogicalDeviceNumber, - NewLogicalDeviceInfo - ->RebuildBlockNumber, - LogicalDeviceSize); - else if (NewLogicalDeviceInfo->BackgroundInitializationInProgress) - DAC960_V2_ReportProgress(Controller, - "Background Initialization", - LogicalDeviceNumber, - NewLogicalDeviceInfo - ->BackgroundInitializationBlockNumber, - LogicalDeviceSize); - else if (NewLogicalDeviceInfo->ForegroundInitializationInProgress) - DAC960_V2_ReportProgress(Controller, - "Foreground Initialization", - LogicalDeviceNumber, - NewLogicalDeviceInfo - ->ForegroundInitializationBlockNumber, - LogicalDeviceSize); - else if (NewLogicalDeviceInfo->DataMigrationInProgress) - DAC960_V2_ReportProgress(Controller, - "Data Migration", - LogicalDeviceNumber, - NewLogicalDeviceInfo - ->DataMigrationBlockNumber, - LogicalDeviceSize); - else if (NewLogicalDeviceInfo->PatrolOperationInProgress) - DAC960_V2_ReportProgress(Controller, - "Patrol Operation", - LogicalDeviceNumber, - NewLogicalDeviceInfo - ->PatrolOperationBlockNumber, - LogicalDeviceSize); - if (LogicalDeviceInfo->BackgroundInitializationInProgress && - !NewLogicalDeviceInfo->BackgroundInitializationInProgress) - DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) " - "Background Initialization %s\n", - Controller, - LogicalDeviceNumber, - Controller->ControllerNumber, - LogicalDeviceNumber, - (NewLogicalDeviceInfo->LogicalDeviceControl - .LogicalDeviceInitialized - ? "Completed" : "Failed")); - memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo, - sizeof(DAC960_V2_LogicalDeviceInfo_T)); - } - Controller->V2.LogicalDriveFoundDuringScan - [LogicalDeviceNumber] = true; - NewLogicalDeviceInfo->LogicalDeviceNumber++; - } - else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid) - { - int LogicalDriveNumber; - for (LogicalDriveNumber = 0; - LogicalDriveNumber < DAC960_MaxLogicalDrives; - LogicalDriveNumber++) - { - DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = - Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; - if (LogicalDeviceInfo == NULL || - Controller->V2.LogicalDriveFoundDuringScan - [LogicalDriveNumber]) - continue; - DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " - "No Longer Exists\n", Controller, - LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - Controller->V2.LogicalDeviceInformation - [LogicalDriveNumber] = NULL; - kfree(LogicalDeviceInfo); - Controller->LogicalDriveInitiallyAccessible - [LogicalDriveNumber] = false; - DAC960_ComputeGenericDiskInfo(Controller); - } - Controller->V2.NeedLogicalDeviceInformation = false; - } - else if (CommandOpcode == DAC960_V2_SCSI_10_Passthru) - { - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - Controller->V2.InquiryUnitSerialNumber[Controller->V2.PhysicalDeviceIndex - 1]; - - if (CommandStatus != DAC960_V2_NormalCompletion) { - memset(InquiryUnitSerialNumber, - 0, sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - } else - memcpy(InquiryUnitSerialNumber, - Controller->V2.NewInquiryUnitSerialNumber, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - - Controller->V2.NeedDeviceSerialNumberInformation = false; - } - - if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber - - Controller->V2.NextEventSequenceNumber > 0) - { - CommandMailbox->GetEvent.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->GetEvent.DataTransferSize = sizeof(DAC960_V2_Event_T); - CommandMailbox->GetEvent.EventSequenceNumberHigh16 = - Controller->V2.NextEventSequenceNumber >> 16; - CommandMailbox->GetEvent.ControllerNumber = 0; - CommandMailbox->GetEvent.IOCTL_Opcode = - DAC960_V2_GetEvent; - CommandMailbox->GetEvent.EventSequenceNumberLow16 = - Controller->V2.NextEventSequenceNumber & 0xFFFF; - CommandMailbox->GetEvent.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.EventDMA; - CommandMailbox->GetEvent.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->GetEvent.DataTransferSize; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V2.NeedPhysicalDeviceInformation) - { - if (Controller->V2.NeedDeviceSerialNumberInformation) - { - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - Controller->V2.NewInquiryUnitSerialNumber; - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - - DAC960_V2_ConstructNewUnitSerialNumber(Controller, CommandMailbox, - Controller->V2.NewPhysicalDeviceInformation->Channel, - Controller->V2.NewPhysicalDeviceInformation->TargetID, - Controller->V2.NewPhysicalDeviceInformation->LogicalUnit - 1); - - - DAC960_QueueCommand(Command); - return; - } - if (Controller->V2.StartPhysicalDeviceInformationScan) - { - Controller->V2.PhysicalDeviceIndex = 0; - Controller->V2.NewPhysicalDeviceInformation->Channel = 0; - Controller->V2.NewPhysicalDeviceInformation->TargetID = 0; - Controller->V2.NewPhysicalDeviceInformation->LogicalUnit = 0; - Controller->V2.StartPhysicalDeviceInformationScan = false; - } - CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->PhysicalDeviceInfo.DataTransferSize = - sizeof(DAC960_V2_PhysicalDeviceInfo_T); - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = - Controller->V2.NewPhysicalDeviceInformation->LogicalUnit; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = - Controller->V2.NewPhysicalDeviceInformation->TargetID; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = - Controller->V2.NewPhysicalDeviceInformation->Channel; - CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = - DAC960_V2_GetPhysicalDeviceInfoValid; - CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewPhysicalDeviceInformationDMA; - CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->PhysicalDeviceInfo.DataTransferSize; - DAC960_QueueCommand(Command); - return; - } - if (Controller->V2.NeedLogicalDeviceInformation) - { - if (Controller->V2.StartLogicalDeviceInformationScan) - { - int LogicalDriveNumber; - for (LogicalDriveNumber = 0; - LogicalDriveNumber < DAC960_MaxLogicalDrives; - LogicalDriveNumber++) - Controller->V2.LogicalDriveFoundDuringScan - [LogicalDriveNumber] = false; - Controller->V2.NewLogicalDeviceInformation->LogicalDeviceNumber = 0; - Controller->V2.StartLogicalDeviceInformationScan = false; - } - CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->LogicalDeviceInfo.DataTransferSize = - sizeof(DAC960_V2_LogicalDeviceInfo_T); - CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = - Controller->V2.NewLogicalDeviceInformation->LogicalDeviceNumber; - CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = - DAC960_V2_GetLogicalDeviceInfoValid; - CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewLogicalDeviceInformationDMA; - CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->LogicalDeviceInfo.DataTransferSize; - DAC960_QueueCommand(Command); - return; - } - Controller->MonitoringTimerCount++; - Controller->MonitoringTimer.expires = - jiffies + DAC960_HealthStatusMonitoringInterval; - add_timer(&Controller->MonitoringTimer); - } - if (CommandType == DAC960_ImmediateCommand) - { - complete(Command->Completion); - Command->Completion = NULL; - return; - } - if (CommandType == DAC960_QueuedCommand) - { - DAC960_V2_KernelCommand_T *KernelCommand = Command->V2.KernelCommand; - KernelCommand->CommandStatus = CommandStatus; - KernelCommand->RequestSenseLength = Command->V2.RequestSenseLength; - KernelCommand->DataTransferLength = Command->V2.DataTransferResidue; - Command->V2.KernelCommand = NULL; - DAC960_DeallocateCommand(Command); - KernelCommand->CompletionFunction(KernelCommand); - return; - } - /* - Queue a Status Monitoring Command to the Controller using the just - completed Command if one was deferred previously due to lack of a - free Command when the Monitoring Timer Function was called. - */ - if (Controller->MonitoringCommandDeferred) - { - Controller->MonitoringCommandDeferred = false; - DAC960_V2_QueueMonitoringCommand(Command); - return; - } - /* - Deallocate the Command. - */ - DAC960_DeallocateCommand(Command); - /* - Wake up any processes waiting on a free Command. - */ - wake_up(&Controller->CommandWaitQueue); -} - -/* - DAC960_GEM_InterruptHandler handles hardware interrupts from DAC960 GEM Series - Controllers. -*/ - -static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier) -{ - DAC960_Controller_T *Controller = DeviceIdentifier; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V2_StatusMailbox_T *NextStatusMailbox; - unsigned long flags; - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_GEM_AcknowledgeInterrupt(ControllerBaseAddress); - NextStatusMailbox = Controller->V2.NextStatusMailbox; - while (NextStatusMailbox->Fields.CommandIdentifier > 0) - { - DAC960_V2_CommandIdentifier_T CommandIdentifier = - NextStatusMailbox->Fields.CommandIdentifier; - DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1]; - Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus; - Command->V2.RequestSenseLength = - NextStatusMailbox->Fields.RequestSenseLength; - Command->V2.DataTransferResidue = - NextStatusMailbox->Fields.DataTransferResidue; - NextStatusMailbox->Words[0] = 0; - if (++NextStatusMailbox > Controller->V2.LastStatusMailbox) - NextStatusMailbox = Controller->V2.FirstStatusMailbox; - DAC960_V2_ProcessCompletedCommand(Command); - } - Controller->V2.NextStatusMailbox = NextStatusMailbox; - /* - Attempt to remove additional I/O Requests from the Controller's - I/O Request Queue and queue them to the Controller. - */ - DAC960_ProcessRequest(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return IRQ_HANDLED; -} - -/* - DAC960_BA_InterruptHandler handles hardware interrupts from DAC960 BA Series - Controllers. -*/ - -static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier) -{ - DAC960_Controller_T *Controller = DeviceIdentifier; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V2_StatusMailbox_T *NextStatusMailbox; - unsigned long flags; - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_BA_AcknowledgeInterrupt(ControllerBaseAddress); - NextStatusMailbox = Controller->V2.NextStatusMailbox; - while (NextStatusMailbox->Fields.CommandIdentifier > 0) - { - DAC960_V2_CommandIdentifier_T CommandIdentifier = - NextStatusMailbox->Fields.CommandIdentifier; - DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1]; - Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus; - Command->V2.RequestSenseLength = - NextStatusMailbox->Fields.RequestSenseLength; - Command->V2.DataTransferResidue = - NextStatusMailbox->Fields.DataTransferResidue; - NextStatusMailbox->Words[0] = 0; - if (++NextStatusMailbox > Controller->V2.LastStatusMailbox) - NextStatusMailbox = Controller->V2.FirstStatusMailbox; - DAC960_V2_ProcessCompletedCommand(Command); - } - Controller->V2.NextStatusMailbox = NextStatusMailbox; - /* - Attempt to remove additional I/O Requests from the Controller's - I/O Request Queue and queue them to the Controller. - */ - DAC960_ProcessRequest(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return IRQ_HANDLED; -} - - -/* - DAC960_LP_InterruptHandler handles hardware interrupts from DAC960 LP Series - Controllers. -*/ - -static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier) -{ - DAC960_Controller_T *Controller = DeviceIdentifier; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V2_StatusMailbox_T *NextStatusMailbox; - unsigned long flags; - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_LP_AcknowledgeInterrupt(ControllerBaseAddress); - NextStatusMailbox = Controller->V2.NextStatusMailbox; - while (NextStatusMailbox->Fields.CommandIdentifier > 0) - { - DAC960_V2_CommandIdentifier_T CommandIdentifier = - NextStatusMailbox->Fields.CommandIdentifier; - DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1]; - Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus; - Command->V2.RequestSenseLength = - NextStatusMailbox->Fields.RequestSenseLength; - Command->V2.DataTransferResidue = - NextStatusMailbox->Fields.DataTransferResidue; - NextStatusMailbox->Words[0] = 0; - if (++NextStatusMailbox > Controller->V2.LastStatusMailbox) - NextStatusMailbox = Controller->V2.FirstStatusMailbox; - DAC960_V2_ProcessCompletedCommand(Command); - } - Controller->V2.NextStatusMailbox = NextStatusMailbox; - /* - Attempt to remove additional I/O Requests from the Controller's - I/O Request Queue and queue them to the Controller. - */ - DAC960_ProcessRequest(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return IRQ_HANDLED; -} - - -/* - DAC960_LA_InterruptHandler handles hardware interrupts from DAC960 LA Series - Controllers. -*/ - -static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier) -{ - DAC960_Controller_T *Controller = DeviceIdentifier; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_StatusMailbox_T *NextStatusMailbox; - unsigned long flags; - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_LA_AcknowledgeInterrupt(ControllerBaseAddress); - NextStatusMailbox = Controller->V1.NextStatusMailbox; - while (NextStatusMailbox->Fields.Valid) - { - DAC960_V1_CommandIdentifier_T CommandIdentifier = - NextStatusMailbox->Fields.CommandIdentifier; - DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1]; - Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus; - NextStatusMailbox->Word = 0; - if (++NextStatusMailbox > Controller->V1.LastStatusMailbox) - NextStatusMailbox = Controller->V1.FirstStatusMailbox; - DAC960_V1_ProcessCompletedCommand(Command); - } - Controller->V1.NextStatusMailbox = NextStatusMailbox; - /* - Attempt to remove additional I/O Requests from the Controller's - I/O Request Queue and queue them to the Controller. - */ - DAC960_ProcessRequest(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return IRQ_HANDLED; -} - - -/* - DAC960_PG_InterruptHandler handles hardware interrupts from DAC960 PG Series - Controllers. -*/ - -static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier) -{ - DAC960_Controller_T *Controller = DeviceIdentifier; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - DAC960_V1_StatusMailbox_T *NextStatusMailbox; - unsigned long flags; - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_PG_AcknowledgeInterrupt(ControllerBaseAddress); - NextStatusMailbox = Controller->V1.NextStatusMailbox; - while (NextStatusMailbox->Fields.Valid) - { - DAC960_V1_CommandIdentifier_T CommandIdentifier = - NextStatusMailbox->Fields.CommandIdentifier; - DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1]; - Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus; - NextStatusMailbox->Word = 0; - if (++NextStatusMailbox > Controller->V1.LastStatusMailbox) - NextStatusMailbox = Controller->V1.FirstStatusMailbox; - DAC960_V1_ProcessCompletedCommand(Command); - } - Controller->V1.NextStatusMailbox = NextStatusMailbox; - /* - Attempt to remove additional I/O Requests from the Controller's - I/O Request Queue and queue them to the Controller. - */ - DAC960_ProcessRequest(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return IRQ_HANDLED; -} - - -/* - DAC960_PD_InterruptHandler handles hardware interrupts from DAC960 PD Series - Controllers. -*/ - -static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier) -{ - DAC960_Controller_T *Controller = DeviceIdentifier; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - unsigned long flags; - - spin_lock_irqsave(&Controller->queue_lock, flags); - while (DAC960_PD_StatusAvailableP(ControllerBaseAddress)) - { - DAC960_V1_CommandIdentifier_T CommandIdentifier = - DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress); - DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1]; - Command->V1.CommandStatus = - DAC960_PD_ReadStatusRegister(ControllerBaseAddress); - DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress); - DAC960_PD_AcknowledgeStatus(ControllerBaseAddress); - DAC960_V1_ProcessCompletedCommand(Command); - } - /* - Attempt to remove additional I/O Requests from the Controller's - I/O Request Queue and queue them to the Controller. - */ - DAC960_ProcessRequest(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return IRQ_HANDLED; -} - - -/* - DAC960_P_InterruptHandler handles hardware interrupts from DAC960 P Series - Controllers. - - Translations of DAC960_V1_Enquiry and DAC960_V1_GetDeviceState rely - on the data having been placed into DAC960_Controller_T, rather than - an arbitrary buffer. -*/ - -static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel, - void *DeviceIdentifier) -{ - DAC960_Controller_T *Controller = DeviceIdentifier; - void __iomem *ControllerBaseAddress = Controller->BaseAddress; - unsigned long flags; - - spin_lock_irqsave(&Controller->queue_lock, flags); - while (DAC960_PD_StatusAvailableP(ControllerBaseAddress)) - { - DAC960_V1_CommandIdentifier_T CommandIdentifier = - DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress); - DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1]; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_CommandOpcode_T CommandOpcode = - CommandMailbox->Common.CommandOpcode; - Command->V1.CommandStatus = - DAC960_PD_ReadStatusRegister(ControllerBaseAddress); - DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress); - DAC960_PD_AcknowledgeStatus(ControllerBaseAddress); - switch (CommandOpcode) - { - case DAC960_V1_Enquiry_Old: - Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Enquiry; - DAC960_P_To_PD_TranslateEnquiry(Controller->V1.NewEnquiry); - break; - case DAC960_V1_GetDeviceState_Old: - Command->V1.CommandMailbox.Common.CommandOpcode = - DAC960_V1_GetDeviceState; - DAC960_P_To_PD_TranslateDeviceState(Controller->V1.NewDeviceState); - break; - case DAC960_V1_Read_Old: - Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Read; - DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox); - break; - case DAC960_V1_Write_Old: - Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Write; - DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox); - break; - case DAC960_V1_ReadWithScatterGather_Old: - Command->V1.CommandMailbox.Common.CommandOpcode = - DAC960_V1_ReadWithScatterGather; - DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox); - break; - case DAC960_V1_WriteWithScatterGather_Old: - Command->V1.CommandMailbox.Common.CommandOpcode = - DAC960_V1_WriteWithScatterGather; - DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox); - break; - default: - break; - } - DAC960_V1_ProcessCompletedCommand(Command); - } - /* - Attempt to remove additional I/O Requests from the Controller's - I/O Request Queue and queue them to the Controller. - */ - DAC960_ProcessRequest(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return IRQ_HANDLED; -} - - -/* - DAC960_V1_QueueMonitoringCommand queues a Monitoring Command to DAC960 V1 - Firmware Controllers. -*/ - -static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_MonitoringCommand; - CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry; - CommandMailbox->Type3.BusAddress = Controller->V1.NewEnquiryDMA; - DAC960_QueueCommand(Command); -} - - -/* - DAC960_V2_QueueMonitoringCommand queues a Monitoring Command to DAC960 V2 - Firmware Controllers. -*/ - -static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *Command) -{ - DAC960_Controller_T *Controller = Command->Controller; - DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_MonitoringCommand; - CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->ControllerInfo.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->ControllerInfo.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->ControllerInfo.DataTransferSize = - sizeof(DAC960_V2_ControllerInfo_T); - CommandMailbox->ControllerInfo.ControllerNumber = 0; - CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo; - CommandMailbox->ControllerInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewControllerInformationDMA; - CommandMailbox->ControllerInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->ControllerInfo.DataTransferSize; - DAC960_QueueCommand(Command); -} - - -/* - DAC960_MonitoringTimerFunction is the timer function for monitoring - the status of DAC960 Controllers. -*/ - -static void DAC960_MonitoringTimerFunction(struct timer_list *t) -{ - DAC960_Controller_T *Controller = from_timer(Controller, t, MonitoringTimer); - DAC960_Command_T *Command; - unsigned long flags; - - if (Controller->FirmwareType == DAC960_V1_Controller) - { - spin_lock_irqsave(&Controller->queue_lock, flags); - /* - Queue a Status Monitoring Command to Controller. - */ - Command = DAC960_AllocateCommand(Controller); - if (Command != NULL) - DAC960_V1_QueueMonitoringCommand(Command); - else Controller->MonitoringCommandDeferred = true; - spin_unlock_irqrestore(&Controller->queue_lock, flags); - } - else - { - DAC960_V2_ControllerInfo_T *ControllerInfo = - &Controller->V2.ControllerInformation; - unsigned int StatusChangeCounter = - Controller->V2.HealthStatusBuffer->StatusChangeCounter; - bool ForceMonitoringCommand = false; - if (time_after(jiffies, Controller->SecondaryMonitoringTime - + DAC960_SecondaryMonitoringInterval)) - { - int LogicalDriveNumber; - for (LogicalDriveNumber = 0; - LogicalDriveNumber < DAC960_MaxLogicalDrives; - LogicalDriveNumber++) - { - DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = - Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; - if (LogicalDeviceInfo == NULL) continue; - if (!LogicalDeviceInfo->LogicalDeviceControl - .LogicalDeviceInitialized) - { - ForceMonitoringCommand = true; - break; - } - } - Controller->SecondaryMonitoringTime = jiffies; - } - if (StatusChangeCounter == Controller->V2.StatusChangeCounter && - Controller->V2.HealthStatusBuffer->NextEventSequenceNumber - == Controller->V2.NextEventSequenceNumber && - (ControllerInfo->BackgroundInitializationsActive + - ControllerInfo->LogicalDeviceInitializationsActive + - ControllerInfo->PhysicalDeviceInitializationsActive + - ControllerInfo->ConsistencyChecksActive + - ControllerInfo->RebuildsActive + - ControllerInfo->OnlineExpansionsActive == 0 || - time_before(jiffies, Controller->PrimaryMonitoringTime - + DAC960_MonitoringTimerInterval)) && - !ForceMonitoringCommand) - { - Controller->MonitoringTimer.expires = - jiffies + DAC960_HealthStatusMonitoringInterval; - add_timer(&Controller->MonitoringTimer); - return; - } - Controller->V2.StatusChangeCounter = StatusChangeCounter; - Controller->PrimaryMonitoringTime = jiffies; - - spin_lock_irqsave(&Controller->queue_lock, flags); - /* - Queue a Status Monitoring Command to Controller. - */ - Command = DAC960_AllocateCommand(Controller); - if (Command != NULL) - DAC960_V2_QueueMonitoringCommand(Command); - else Controller->MonitoringCommandDeferred = true; - spin_unlock_irqrestore(&Controller->queue_lock, flags); - /* - Wake up any processes waiting on a Health Status Buffer change. - */ - wake_up(&Controller->HealthStatusWaitQueue); - } -} - -/* - DAC960_CheckStatusBuffer verifies that there is room to hold ByteCount - additional bytes in the Combined Status Buffer and grows the buffer if - necessary. It returns true if there is enough room and false otherwise. -*/ - -static bool DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller, - unsigned int ByteCount) -{ - unsigned char *NewStatusBuffer; - if (Controller->InitialStatusLength + 1 + - Controller->CurrentStatusLength + ByteCount + 1 <= - Controller->CombinedStatusBufferLength) - return true; - if (Controller->CombinedStatusBufferLength == 0) - { - unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize; - while (NewStatusBufferLength < ByteCount) - NewStatusBufferLength *= 2; - Controller->CombinedStatusBuffer = kmalloc(NewStatusBufferLength, - GFP_ATOMIC); - if (Controller->CombinedStatusBuffer == NULL) return false; - Controller->CombinedStatusBufferLength = NewStatusBufferLength; - return true; - } - NewStatusBuffer = kmalloc_array(2, Controller->CombinedStatusBufferLength, - GFP_ATOMIC); - if (NewStatusBuffer == NULL) - { - DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n", - Controller); - return false; - } - memcpy(NewStatusBuffer, Controller->CombinedStatusBuffer, - Controller->CombinedStatusBufferLength); - kfree(Controller->CombinedStatusBuffer); - Controller->CombinedStatusBuffer = NewStatusBuffer; - Controller->CombinedStatusBufferLength *= 2; - Controller->CurrentStatusBuffer = - &NewStatusBuffer[Controller->InitialStatusLength + 1]; - return true; -} - - -/* - DAC960_Message prints Driver Messages. -*/ - -static void DAC960_Message(DAC960_MessageLevel_T MessageLevel, - unsigned char *Format, - DAC960_Controller_T *Controller, - ...) -{ - static unsigned char Buffer[DAC960_LineBufferSize]; - static bool BeginningOfLine = true; - va_list Arguments; - int Length = 0; - va_start(Arguments, Controller); - Length = vsprintf(Buffer, Format, Arguments); - va_end(Arguments); - if (Controller == NULL) - printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], - DAC960_ControllerCount, Buffer); - else if (MessageLevel == DAC960_AnnounceLevel || - MessageLevel == DAC960_InfoLevel) - { - if (!Controller->ControllerInitialized) - { - if (DAC960_CheckStatusBuffer(Controller, Length)) - { - strcpy(&Controller->CombinedStatusBuffer - [Controller->InitialStatusLength], - Buffer); - Controller->InitialStatusLength += Length; - Controller->CurrentStatusBuffer = - &Controller->CombinedStatusBuffer - [Controller->InitialStatusLength + 1]; - } - if (MessageLevel == DAC960_AnnounceLevel) - { - static int AnnouncementLines = 0; - if (++AnnouncementLines <= 2) - printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], - Buffer); - } - else - { - if (BeginningOfLine) - { - if (Buffer[0] != '\n' || Length > 1) - printk("%sDAC960#%d: %s", - DAC960_MessageLevelMap[MessageLevel], - Controller->ControllerNumber, Buffer); - } - else printk("%s", Buffer); - } - } - else if (DAC960_CheckStatusBuffer(Controller, Length)) - { - strcpy(&Controller->CurrentStatusBuffer[ - Controller->CurrentStatusLength], Buffer); - Controller->CurrentStatusLength += Length; - } - } - else if (MessageLevel == DAC960_ProgressLevel) - { - strcpy(Controller->ProgressBuffer, Buffer); - Controller->ProgressBufferLength = Length; - if (Controller->EphemeralProgressMessage) - { - if (time_after_eq(jiffies, Controller->LastProgressReportTime - + DAC960_ProgressReportingInterval)) - { - printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], - Controller->ControllerNumber, Buffer); - Controller->LastProgressReportTime = jiffies; - } - } - else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], - Controller->ControllerNumber, Buffer); - } - else if (MessageLevel == DAC960_UserCriticalLevel) - { - strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength], - Buffer); - Controller->UserStatusLength += Length; - if (Buffer[0] != '\n' || Length > 1) - printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], - Controller->ControllerNumber, Buffer); - } - else - { - if (BeginningOfLine) - printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], - Controller->ControllerNumber, Buffer); - else printk("%s", Buffer); - } - BeginningOfLine = (Buffer[Length-1] == '\n'); -} - - -/* - DAC960_ParsePhysicalDevice parses spaces followed by a Physical Device - Channel:TargetID specification from a User Command string. It updates - Channel and TargetID and returns true on success and false on failure. -*/ - -static bool DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller, - char *UserCommandString, - unsigned char *Channel, - unsigned char *TargetID) -{ - char *NewUserCommandString = UserCommandString; - unsigned long XChannel, XTargetID; - while (*UserCommandString == ' ') UserCommandString++; - if (UserCommandString == NewUserCommandString) - return false; - XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10); - if (NewUserCommandString == UserCommandString || - *NewUserCommandString != ':' || - XChannel >= Controller->Channels) - return false; - UserCommandString = ++NewUserCommandString; - XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10); - if (NewUserCommandString == UserCommandString || - *NewUserCommandString != '\0' || - XTargetID >= Controller->Targets) - return false; - *Channel = XChannel; - *TargetID = XTargetID; - return true; -} - - -/* - DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number - specification from a User Command string. It updates LogicalDriveNumber and - returns true on success and false on failure. -*/ - -static bool DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller, - char *UserCommandString, - unsigned char *LogicalDriveNumber) -{ - char *NewUserCommandString = UserCommandString; - unsigned long XLogicalDriveNumber; - while (*UserCommandString == ' ') UserCommandString++; - if (UserCommandString == NewUserCommandString) - return false; - XLogicalDriveNumber = - simple_strtoul(UserCommandString, &NewUserCommandString, 10); - if (NewUserCommandString == UserCommandString || - *NewUserCommandString != '\0' || - XLogicalDriveNumber > DAC960_MaxLogicalDrives - 1) - return false; - *LogicalDriveNumber = XLogicalDriveNumber; - return true; -} - - -/* - DAC960_V1_SetDeviceState sets the Device State for a Physical Device for - DAC960 V1 Firmware Controllers. -*/ - -static void DAC960_V1_SetDeviceState(DAC960_Controller_T *Controller, - DAC960_Command_T *Command, - unsigned char Channel, - unsigned char TargetID, - DAC960_V1_PhysicalDeviceState_T - DeviceState, - const unsigned char *DeviceStateString) -{ - DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; - CommandMailbox->Type3D.CommandOpcode = DAC960_V1_StartDevice; - CommandMailbox->Type3D.Channel = Channel; - CommandMailbox->Type3D.TargetID = TargetID; - CommandMailbox->Type3D.DeviceState = DeviceState; - CommandMailbox->Type3D.Modifier = 0; - DAC960_ExecuteCommand(Command); - switch (Command->V1.CommandStatus) - { - case DAC960_V1_NormalCompletion: - DAC960_UserCritical("%s of Physical Device %d:%d Succeeded\n", Controller, - DeviceStateString, Channel, TargetID); - break; - case DAC960_V1_UnableToStartDevice: - DAC960_UserCritical("%s of Physical Device %d:%d Failed - " - "Unable to Start Device\n", Controller, - DeviceStateString, Channel, TargetID); - break; - case DAC960_V1_NoDeviceAtAddress: - DAC960_UserCritical("%s of Physical Device %d:%d Failed - " - "No Device at Address\n", Controller, - DeviceStateString, Channel, TargetID); - break; - case DAC960_V1_InvalidChannelOrTargetOrModifier: - DAC960_UserCritical("%s of Physical Device %d:%d Failed - " - "Invalid Channel or Target or Modifier\n", - Controller, DeviceStateString, Channel, TargetID); - break; - case DAC960_V1_ChannelBusy: - DAC960_UserCritical("%s of Physical Device %d:%d Failed - " - "Channel Busy\n", Controller, - DeviceStateString, Channel, TargetID); - break; - default: - DAC960_UserCritical("%s of Physical Device %d:%d Failed - " - "Unexpected Status %04X\n", Controller, - DeviceStateString, Channel, TargetID, - Command->V1.CommandStatus); - break; - } -} - - -/* - DAC960_V1_ExecuteUserCommand executes a User Command for DAC960 V1 Firmware - Controllers. -*/ - -static bool DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller, - unsigned char *UserCommand) -{ - DAC960_Command_T *Command; - DAC960_V1_CommandMailbox_T *CommandMailbox; - unsigned long flags; - unsigned char Channel, TargetID, LogicalDriveNumber; - - spin_lock_irqsave(&Controller->queue_lock, flags); - while ((Command = DAC960_AllocateCommand(Controller)) == NULL) - DAC960_WaitForCommand(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - Controller->UserStatusLength = 0; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox = &Command->V1.CommandMailbox; - if (strcmp(UserCommand, "flush-cache") == 0) - { - CommandMailbox->Type3.CommandOpcode = DAC960_V1_Flush; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Cache Flush Completed\n", Controller); - } - else if (strncmp(UserCommand, "kill", 4) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[4], - &Channel, &TargetID)) - { - DAC960_V1_DeviceState_T *DeviceState = - &Controller->V1.DeviceState[Channel][TargetID]; - if (DeviceState->Present && - DeviceState->DeviceType == DAC960_V1_DiskType && - DeviceState->DeviceState != DAC960_V1_Device_Dead) - DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID, - DAC960_V1_Device_Dead, "Kill"); - else DAC960_UserCritical("Kill of Physical Device %d:%d Illegal\n", - Controller, Channel, TargetID); - } - else if (strncmp(UserCommand, "make-online", 11) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[11], - &Channel, &TargetID)) - { - DAC960_V1_DeviceState_T *DeviceState = - &Controller->V1.DeviceState[Channel][TargetID]; - if (DeviceState->Present && - DeviceState->DeviceType == DAC960_V1_DiskType && - DeviceState->DeviceState == DAC960_V1_Device_Dead) - DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID, - DAC960_V1_Device_Online, "Make Online"); - else DAC960_UserCritical("Make Online of Physical Device %d:%d Illegal\n", - Controller, Channel, TargetID); - - } - else if (strncmp(UserCommand, "make-standby", 12) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[12], - &Channel, &TargetID)) - { - DAC960_V1_DeviceState_T *DeviceState = - &Controller->V1.DeviceState[Channel][TargetID]; - if (DeviceState->Present && - DeviceState->DeviceType == DAC960_V1_DiskType && - DeviceState->DeviceState == DAC960_V1_Device_Dead) - DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID, - DAC960_V1_Device_Standby, "Make Standby"); - else DAC960_UserCritical("Make Standby of Physical " - "Device %d:%d Illegal\n", - Controller, Channel, TargetID); - } - else if (strncmp(UserCommand, "rebuild", 7) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[7], - &Channel, &TargetID)) - { - CommandMailbox->Type3D.CommandOpcode = DAC960_V1_RebuildAsync; - CommandMailbox->Type3D.Channel = Channel; - CommandMailbox->Type3D.TargetID = TargetID; - DAC960_ExecuteCommand(Command); - switch (Command->V1.CommandStatus) - { - case DAC960_V1_NormalCompletion: - DAC960_UserCritical("Rebuild of Physical Device %d:%d Initiated\n", - Controller, Channel, TargetID); - break; - case DAC960_V1_AttemptToRebuildOnlineDrive: - DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - " - "Attempt to Rebuild Online or " - "Unresponsive Drive\n", - Controller, Channel, TargetID); - break; - case DAC960_V1_NewDiskFailedDuringRebuild: - DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - " - "New Disk Failed During Rebuild\n", - Controller, Channel, TargetID); - break; - case DAC960_V1_InvalidDeviceAddress: - DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - " - "Invalid Device Address\n", - Controller, Channel, TargetID); - break; - case DAC960_V1_RebuildOrCheckAlreadyInProgress: - DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - " - "Rebuild or Consistency Check Already " - "in Progress\n", Controller, Channel, TargetID); - break; - default: - DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - " - "Unexpected Status %04X\n", Controller, - Channel, TargetID, Command->V1.CommandStatus); - break; - } - } - else if (strncmp(UserCommand, "check-consistency", 17) == 0 && - DAC960_ParseLogicalDrive(Controller, &UserCommand[17], - &LogicalDriveNumber)) - { - CommandMailbox->Type3C.CommandOpcode = DAC960_V1_CheckConsistencyAsync; - CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber; - CommandMailbox->Type3C.AutoRestore = true; - DAC960_ExecuteCommand(Command); - switch (Command->V1.CommandStatus) - { - case DAC960_V1_NormalCompletion: - DAC960_UserCritical("Consistency Check of Logical Drive %d " - "(/dev/rd/c%dd%d) Initiated\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - break; - case DAC960_V1_DependentDiskIsDead: - DAC960_UserCritical("Consistency Check of Logical Drive %d " - "(/dev/rd/c%dd%d) Failed - " - "Dependent Physical Device is DEAD\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - break; - case DAC960_V1_InvalidOrNonredundantLogicalDrive: - DAC960_UserCritical("Consistency Check of Logical Drive %d " - "(/dev/rd/c%dd%d) Failed - " - "Invalid or Nonredundant Logical Drive\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - break; - case DAC960_V1_RebuildOrCheckAlreadyInProgress: - DAC960_UserCritical("Consistency Check of Logical Drive %d " - "(/dev/rd/c%dd%d) Failed - Rebuild or " - "Consistency Check Already in Progress\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber); - break; - default: - DAC960_UserCritical("Consistency Check of Logical Drive %d " - "(/dev/rd/c%dd%d) Failed - " - "Unexpected Status %04X\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, Command->V1.CommandStatus); - break; - } - } - else if (strcmp(UserCommand, "cancel-rebuild") == 0 || - strcmp(UserCommand, "cancel-consistency-check") == 0) - { - /* - the OldRebuildRateConstant is never actually used - once its value is retrieved from the controller. - */ - unsigned char *OldRebuildRateConstant; - dma_addr_t OldRebuildRateConstantDMA; - - OldRebuildRateConstant = pci_alloc_consistent( Controller->PCIDevice, - sizeof(char), &OldRebuildRateConstantDMA); - if (OldRebuildRateConstant == NULL) { - DAC960_UserCritical("Cancellation of Rebuild or " - "Consistency Check Failed - " - "Out of Memory", - Controller); - goto failure; - } - CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl; - CommandMailbox->Type3R.RebuildRateConstant = 0xFF; - CommandMailbox->Type3R.BusAddress = OldRebuildRateConstantDMA; - DAC960_ExecuteCommand(Command); - switch (Command->V1.CommandStatus) - { - case DAC960_V1_NormalCompletion: - DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n", - Controller); - break; - default: - DAC960_UserCritical("Cancellation of Rebuild or " - "Consistency Check Failed - " - "Unexpected Status %04X\n", - Controller, Command->V1.CommandStatus); - break; - } -failure: - pci_free_consistent(Controller->PCIDevice, sizeof(char), - OldRebuildRateConstant, OldRebuildRateConstantDMA); - } - else DAC960_UserCritical("Illegal User Command: '%s'\n", - Controller, UserCommand); - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_DeallocateCommand(Command); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return true; -} - - -/* - DAC960_V2_TranslatePhysicalDevice translates a Physical Device Channel and - TargetID into a Logical Device. It returns true on success and false - on failure. -*/ - -static bool DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command, - unsigned char Channel, - unsigned char TargetID, - unsigned short - *LogicalDeviceNumber) -{ - DAC960_V2_CommandMailbox_T SavedCommandMailbox, *CommandMailbox; - DAC960_Controller_T *Controller = Command->Controller; - - CommandMailbox = &Command->V2.CommandMailbox; - memcpy(&SavedCommandMailbox, CommandMailbox, - sizeof(DAC960_V2_CommandMailbox_T)); - - CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->PhysicalDeviceInfo.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->PhysicalDeviceInfo.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->PhysicalDeviceInfo.DataTransferSize = - sizeof(DAC960_V2_PhysicalToLogicalDevice_T); - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID; - CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel; - CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = - DAC960_V2_TranslatePhysicalToLogicalDevice; - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.PhysicalToLogicalDeviceDMA; - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->Common.DataTransferSize; - - DAC960_ExecuteCommand(Command); - *LogicalDeviceNumber = Controller->V2.PhysicalToLogicalDevice->LogicalDeviceNumber; - - memcpy(CommandMailbox, &SavedCommandMailbox, - sizeof(DAC960_V2_CommandMailbox_T)); - return (Command->V2.CommandStatus == DAC960_V2_NormalCompletion); -} - - -/* - DAC960_V2_ExecuteUserCommand executes a User Command for DAC960 V2 Firmware - Controllers. -*/ - -static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller, - unsigned char *UserCommand) -{ - DAC960_Command_T *Command; - DAC960_V2_CommandMailbox_T *CommandMailbox; - unsigned long flags; - unsigned char Channel, TargetID, LogicalDriveNumber; - unsigned short LogicalDeviceNumber; - - spin_lock_irqsave(&Controller->queue_lock, flags); - while ((Command = DAC960_AllocateCommand(Controller)) == NULL) - DAC960_WaitForCommand(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - Controller->UserStatusLength = 0; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox = &Command->V2.CommandMailbox; - CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->Common.CommandControlBits.DataTransferControllerToHost = true; - CommandMailbox->Common.CommandControlBits.NoAutoRequestSense = true; - if (strcmp(UserCommand, "flush-cache") == 0) - { - CommandMailbox->DeviceOperation.IOCTL_Opcode = DAC960_V2_PauseDevice; - CommandMailbox->DeviceOperation.OperationDevice = - DAC960_V2_RAID_Controller; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Cache Flush Completed\n", Controller); - } - else if (strncmp(UserCommand, "kill", 4) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[4], - &Channel, &TargetID) && - DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, - &LogicalDeviceNumber)) - { - CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber = - LogicalDeviceNumber; - CommandMailbox->SetDeviceState.IOCTL_Opcode = - DAC960_V2_SetDeviceState; - CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState = - DAC960_V2_Device_Dead; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Kill of Physical Device %d:%d %s\n", - Controller, Channel, TargetID, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Succeeded" : "Failed")); - } - else if (strncmp(UserCommand, "make-online", 11) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[11], - &Channel, &TargetID) && - DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, - &LogicalDeviceNumber)) - { - CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber = - LogicalDeviceNumber; - CommandMailbox->SetDeviceState.IOCTL_Opcode = - DAC960_V2_SetDeviceState; - CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState = - DAC960_V2_Device_Online; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Make Online of Physical Device %d:%d %s\n", - Controller, Channel, TargetID, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Succeeded" : "Failed")); - } - else if (strncmp(UserCommand, "make-standby", 12) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[12], - &Channel, &TargetID) && - DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, - &LogicalDeviceNumber)) - { - CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber = - LogicalDeviceNumber; - CommandMailbox->SetDeviceState.IOCTL_Opcode = - DAC960_V2_SetDeviceState; - CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState = - DAC960_V2_Device_Standby; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Make Standby of Physical Device %d:%d %s\n", - Controller, Channel, TargetID, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Succeeded" : "Failed")); - } - else if (strncmp(UserCommand, "rebuild", 7) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[7], - &Channel, &TargetID) && - DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, - &LogicalDeviceNumber)) - { - CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = - LogicalDeviceNumber; - CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = - DAC960_V2_RebuildDeviceStart; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n", - Controller, Channel, TargetID, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Initiated" : "Not Initiated")); - } - else if (strncmp(UserCommand, "cancel-rebuild", 14) == 0 && - DAC960_ParsePhysicalDevice(Controller, &UserCommand[14], - &Channel, &TargetID) && - DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID, - &LogicalDeviceNumber)) - { - CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = - LogicalDeviceNumber; - CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = - DAC960_V2_RebuildDeviceStop; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n", - Controller, Channel, TargetID, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Cancelled" : "Not Cancelled")); - } - else if (strncmp(UserCommand, "check-consistency", 17) == 0 && - DAC960_ParseLogicalDrive(Controller, &UserCommand[17], - &LogicalDriveNumber)) - { - CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber = - LogicalDriveNumber; - CommandMailbox->ConsistencyCheck.IOCTL_Opcode = - DAC960_V2_ConsistencyCheckStart; - CommandMailbox->ConsistencyCheck.RestoreConsistency = true; - CommandMailbox->ConsistencyCheck.InitializedAreaOnly = false; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Consistency Check of Logical Drive %d " - "(/dev/rd/c%dd%d) %s\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Initiated" : "Not Initiated")); - } - else if (strncmp(UserCommand, "cancel-consistency-check", 24) == 0 && - DAC960_ParseLogicalDrive(Controller, &UserCommand[24], - &LogicalDriveNumber)) - { - CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber = - LogicalDriveNumber; - CommandMailbox->ConsistencyCheck.IOCTL_Opcode = - DAC960_V2_ConsistencyCheckStop; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Consistency Check of Logical Drive %d " - "(/dev/rd/c%dd%d) %s\n", - Controller, LogicalDriveNumber, - Controller->ControllerNumber, - LogicalDriveNumber, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Cancelled" : "Not Cancelled")); - } - else if (strcmp(UserCommand, "perform-discovery") == 0) - { - CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_StartDiscovery; - DAC960_ExecuteCommand(Command); - DAC960_UserCritical("Discovery %s\n", Controller, - (Command->V2.CommandStatus - == DAC960_V2_NormalCompletion - ? "Initiated" : "Not Initiated")); - if (Command->V2.CommandStatus == DAC960_V2_NormalCompletion) - { - CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox->ControllerInfo.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->ControllerInfo.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->ControllerInfo.DataTransferSize = - sizeof(DAC960_V2_ControllerInfo_T); - CommandMailbox->ControllerInfo.ControllerNumber = 0; - CommandMailbox->ControllerInfo.IOCTL_Opcode = - DAC960_V2_GetControllerInfo; - /* - * How does this NOT race with the queued Monitoring - * usage of this structure? - */ - CommandMailbox->ControllerInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Controller->V2.NewControllerInformationDMA; - CommandMailbox->ControllerInfo.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->ControllerInfo.DataTransferSize; - while (1) { - DAC960_ExecuteCommand(Command); - if (!Controller->V2.NewControllerInformation->PhysicalScanActive) - break; - msleep(1000); - } - DAC960_UserCritical("Discovery Completed\n", Controller); - } - } - else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0) - Controller->SuppressEnclosureMessages = true; - else DAC960_UserCritical("Illegal User Command: '%s'\n", - Controller, UserCommand); - - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_DeallocateCommand(Command); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - return true; -} - -static int __maybe_unused dac960_proc_show(struct seq_file *m, void *v) -{ - unsigned char *StatusMessage = "OK\n"; - int ControllerNumber; - for (ControllerNumber = 0; - ControllerNumber < DAC960_ControllerCount; - ControllerNumber++) - { - DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) continue; - if (Controller->MonitoringAlertMode) - { - StatusMessage = "ALERT\n"; - break; - } - } - seq_puts(m, StatusMessage); - return 0; -} - -static int __maybe_unused dac960_initial_status_proc_show(struct seq_file *m, - void *v) -{ - DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private; - seq_printf(m, "%.*s", Controller->InitialStatusLength, Controller->CombinedStatusBuffer); - return 0; -} - -static int __maybe_unused dac960_current_status_proc_show(struct seq_file *m, - void *v) -{ - DAC960_Controller_T *Controller = (DAC960_Controller_T *) m->private; - unsigned char *StatusMessage = - "No Rebuild or Consistency Check in Progress\n"; - int ProgressMessageLength = strlen(StatusMessage); - if (jiffies != Controller->LastCurrentStatusTime) - { - Controller->CurrentStatusLength = 0; - DAC960_AnnounceDriver(Controller); - DAC960_ReportControllerConfiguration(Controller); - DAC960_ReportDeviceConfiguration(Controller); - if (Controller->ProgressBufferLength > 0) - ProgressMessageLength = Controller->ProgressBufferLength; - if (DAC960_CheckStatusBuffer(Controller, 2 + ProgressMessageLength)) - { - unsigned char *CurrentStatusBuffer = Controller->CurrentStatusBuffer; - CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; - CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; - if (Controller->ProgressBufferLength > 0) - strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength], - Controller->ProgressBuffer); - else - strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength], - StatusMessage); - Controller->CurrentStatusLength += ProgressMessageLength; - } - Controller->LastCurrentStatusTime = jiffies; - } - seq_printf(m, "%.*s", Controller->CurrentStatusLength, Controller->CurrentStatusBuffer); - return 0; -} - -static int dac960_user_command_proc_show(struct seq_file *m, void *v) -{ - DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private; - - seq_printf(m, "%.*s", Controller->UserStatusLength, Controller->UserStatusBuffer); - return 0; -} - -static int dac960_user_command_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, dac960_user_command_proc_show, PDE_DATA(inode)); -} - -static ssize_t dac960_user_command_proc_write(struct file *file, - const char __user *Buffer, - size_t Count, loff_t *pos) -{ - DAC960_Controller_T *Controller = PDE_DATA(file_inode(file)); - unsigned char CommandBuffer[80]; - int Length; - if (Count > sizeof(CommandBuffer)-1) return -EINVAL; - if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT; - CommandBuffer[Count] = '\0'; - Length = strlen(CommandBuffer); - if (Length > 0 && CommandBuffer[Length-1] == '\n') - CommandBuffer[--Length] = '\0'; - if (Controller->FirmwareType == DAC960_V1_Controller) - return (DAC960_V1_ExecuteUserCommand(Controller, CommandBuffer) - ? Count : -EBUSY); - else - return (DAC960_V2_ExecuteUserCommand(Controller, CommandBuffer) - ? Count : -EBUSY); -} - -static const struct file_operations dac960_user_command_proc_fops = { - .owner = THIS_MODULE, - .open = dac960_user_command_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = dac960_user_command_proc_write, -}; - -/* - DAC960_CreateProcEntries creates the /proc/rd/... entries for the - DAC960 Driver. -*/ - -static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller) -{ - struct proc_dir_entry *ControllerProcEntry; - - if (DAC960_ProcDirectoryEntry == NULL) { - DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL); - proc_create_single("status", 0, DAC960_ProcDirectoryEntry, - dac960_proc_show); - } - - snprintf(Controller->ControllerName, sizeof(Controller->ControllerName), - "c%d", Controller->ControllerNumber); - ControllerProcEntry = proc_mkdir(Controller->ControllerName, - DAC960_ProcDirectoryEntry); - proc_create_single_data("initial_status", 0, ControllerProcEntry, - dac960_initial_status_proc_show, Controller); - proc_create_single_data("current_status", 0, ControllerProcEntry, - dac960_current_status_proc_show, Controller); - proc_create_data("user_command", 0600, ControllerProcEntry, &dac960_user_command_proc_fops, Controller); - Controller->ControllerProcEntry = ControllerProcEntry; -} - - -/* - DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the - DAC960 Driver. -*/ - -static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller) -{ - if (Controller->ControllerProcEntry == NULL) - return; - remove_proc_entry("initial_status", Controller->ControllerProcEntry); - remove_proc_entry("current_status", Controller->ControllerProcEntry); - remove_proc_entry("user_command", Controller->ControllerProcEntry); - remove_proc_entry(Controller->ControllerName, DAC960_ProcDirectoryEntry); - Controller->ControllerProcEntry = NULL; -} - -#ifdef DAC960_GAM_MINOR - -static long DAC960_gam_get_controller_info(DAC960_ControllerInfo_T __user *UserSpaceControllerInfo) -{ - DAC960_ControllerInfo_T ControllerInfo; - DAC960_Controller_T *Controller; - int ControllerNumber; - long ErrorCode; - - if (UserSpaceControllerInfo == NULL) - ErrorCode = -EINVAL; - else ErrorCode = get_user(ControllerNumber, - &UserSpaceControllerInfo->ControllerNumber); - if (ErrorCode != 0) - goto out; - ErrorCode = -ENXIO; - if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) { - goto out; - } - Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - goto out; - memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); - ControllerInfo.ControllerNumber = ControllerNumber; - ControllerInfo.FirmwareType = Controller->FirmwareType; - ControllerInfo.Channels = Controller->Channels; - ControllerInfo.Targets = Controller->Targets; - ControllerInfo.PCI_Bus = Controller->Bus; - ControllerInfo.PCI_Device = Controller->Device; - ControllerInfo.PCI_Function = Controller->Function; - ControllerInfo.IRQ_Channel = Controller->IRQ_Channel; - ControllerInfo.PCI_Address = Controller->PCI_Address; - strcpy(ControllerInfo.ModelName, Controller->ModelName); - strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); - ErrorCode = (copy_to_user(UserSpaceControllerInfo, &ControllerInfo, - sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0); -out: - return ErrorCode; -} - -static long DAC960_gam_v1_execute_command(DAC960_V1_UserCommand_T __user *UserSpaceUserCommand) -{ - DAC960_V1_UserCommand_T UserCommand; - DAC960_Controller_T *Controller; - DAC960_Command_T *Command = NULL; - DAC960_V1_CommandOpcode_T CommandOpcode; - DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_DCDB_T DCDB; - DAC960_V1_DCDB_T *DCDB_IOBUF = NULL; - dma_addr_t DCDB_IOBUFDMA; - unsigned long flags; - int ControllerNumber, DataTransferLength; - unsigned char *DataTransferBuffer = NULL; - dma_addr_t DataTransferBufferDMA; - long ErrorCode; - - if (UserSpaceUserCommand == NULL) { - ErrorCode = -EINVAL; - goto out; - } - if (copy_from_user(&UserCommand, UserSpaceUserCommand, - sizeof(DAC960_V1_UserCommand_T))) { - ErrorCode = -EFAULT; - goto out; - } - ControllerNumber = UserCommand.ControllerNumber; - ErrorCode = -ENXIO; - if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) - goto out; - Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - goto out; - ErrorCode = -EINVAL; - if (Controller->FirmwareType != DAC960_V1_Controller) - goto out; - CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; - DataTransferLength = UserCommand.DataTransferLength; - if (CommandOpcode & 0x80) - goto out; - if (CommandOpcode == DAC960_V1_DCDB) - { - if (copy_from_user(&DCDB, UserCommand.DCDB, - sizeof(DAC960_V1_DCDB_T))) { - ErrorCode = -EFAULT; - goto out; - } - if (DCDB.Channel >= DAC960_V1_MaxChannels) - goto out; - if (!((DataTransferLength == 0 && - DCDB.Direction - == DAC960_V1_DCDB_NoDataTransfer) || - (DataTransferLength > 0 && - DCDB.Direction - == DAC960_V1_DCDB_DataTransferDeviceToSystem) || - (DataTransferLength < 0 && - DCDB.Direction - == DAC960_V1_DCDB_DataTransferSystemToDevice))) - goto out; - if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) - != abs(DataTransferLength)) - goto out; - DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice, - sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA); - if (DCDB_IOBUF == NULL) { - ErrorCode = -ENOMEM; - goto out; - } - } - ErrorCode = -ENOMEM; - if (DataTransferLength > 0) - { - DataTransferBuffer = pci_zalloc_consistent(Controller->PCIDevice, - DataTransferLength, - &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - goto out; - } - else if (DataTransferLength < 0) - { - DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, - -DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - goto out; - if (copy_from_user(DataTransferBuffer, - UserCommand.DataTransferBuffer, - -DataTransferLength)) { - ErrorCode = -EFAULT; - goto out; - } - } - if (CommandOpcode == DAC960_V1_DCDB) - { - spin_lock_irqsave(&Controller->queue_lock, flags); - while ((Command = DAC960_AllocateCommand(Controller)) == NULL) - DAC960_WaitForCommand(Controller); - while (Controller->V1.DirectCommandActive[DCDB.Channel] - [DCDB.TargetID]) - { - spin_unlock_irq(&Controller->queue_lock); - __wait_event(Controller->CommandWaitQueue, - !Controller->V1.DirectCommandActive - [DCDB.Channel][DCDB.TargetID]); - spin_lock_irq(&Controller->queue_lock); - } - Controller->V1.DirectCommandActive[DCDB.Channel] - [DCDB.TargetID] = true; - spin_unlock_irqrestore(&Controller->queue_lock, flags); - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox, - sizeof(DAC960_V1_CommandMailbox_T)); - Command->V1.CommandMailbox.Type3.BusAddress = DCDB_IOBUFDMA; - DCDB.BusAddress = DataTransferBufferDMA; - memcpy(DCDB_IOBUF, &DCDB, sizeof(DAC960_V1_DCDB_T)); - } - else - { - spin_lock_irqsave(&Controller->queue_lock, flags); - while ((Command = DAC960_AllocateCommand(Controller)) == NULL) - DAC960_WaitForCommand(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox, - sizeof(DAC960_V1_CommandMailbox_T)); - if (DataTransferBuffer != NULL) - Command->V1.CommandMailbox.Type3.BusAddress = - DataTransferBufferDMA; - } - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V1.CommandStatus; - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_DeallocateCommand(Command); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - if (DataTransferLength > 0) - { - if (copy_to_user(UserCommand.DataTransferBuffer, - DataTransferBuffer, DataTransferLength)) { - ErrorCode = -EFAULT; - goto Failure1; - } - } - if (CommandOpcode == DAC960_V1_DCDB) - { - /* - I don't believe Target or Channel in the DCDB_IOBUF - should be any different from the contents of DCDB. - */ - Controller->V1.DirectCommandActive[DCDB.Channel] - [DCDB.TargetID] = false; - if (copy_to_user(UserCommand.DCDB, DCDB_IOBUF, - sizeof(DAC960_V1_DCDB_T))) { - ErrorCode = -EFAULT; - goto Failure1; - } - } - ErrorCode = CommandStatus; - Failure1: - if (DataTransferBuffer != NULL) - pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength), - DataTransferBuffer, DataTransferBufferDMA); - if (DCDB_IOBUF != NULL) - pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), - DCDB_IOBUF, DCDB_IOBUFDMA); - out: - return ErrorCode; -} - -static long DAC960_gam_v2_execute_command(DAC960_V2_UserCommand_T __user *UserSpaceUserCommand) -{ - DAC960_V2_UserCommand_T UserCommand; - DAC960_Controller_T *Controller; - DAC960_Command_T *Command = NULL; - DAC960_V2_CommandMailbox_T *CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus; - unsigned long flags; - int ControllerNumber, DataTransferLength; - int DataTransferResidue, RequestSenseLength; - unsigned char *DataTransferBuffer = NULL; - dma_addr_t DataTransferBufferDMA; - unsigned char *RequestSenseBuffer = NULL; - dma_addr_t RequestSenseBufferDMA; - long ErrorCode = -EINVAL; - - if (UserSpaceUserCommand == NULL) - goto out; - if (copy_from_user(&UserCommand, UserSpaceUserCommand, - sizeof(DAC960_V2_UserCommand_T))) { - ErrorCode = -EFAULT; - goto out; - } - ErrorCode = -ENXIO; - ControllerNumber = UserCommand.ControllerNumber; - if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) - goto out; - Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - goto out; - if (Controller->FirmwareType != DAC960_V2_Controller){ - ErrorCode = -EINVAL; - goto out; - } - DataTransferLength = UserCommand.DataTransferLength; - ErrorCode = -ENOMEM; - if (DataTransferLength > 0) - { - DataTransferBuffer = pci_zalloc_consistent(Controller->PCIDevice, - DataTransferLength, - &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - goto out; - } - else if (DataTransferLength < 0) - { - DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, - -DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - goto out; - if (copy_from_user(DataTransferBuffer, - UserCommand.DataTransferBuffer, - -DataTransferLength)) { - ErrorCode = -EFAULT; - goto Failure2; - } - } - RequestSenseLength = UserCommand.RequestSenseLength; - if (RequestSenseLength > 0) - { - RequestSenseBuffer = pci_zalloc_consistent(Controller->PCIDevice, - RequestSenseLength, - &RequestSenseBufferDMA); - if (RequestSenseBuffer == NULL) - { - ErrorCode = -ENOMEM; - goto Failure2; - } - } - spin_lock_irqsave(&Controller->queue_lock, flags); - while ((Command = DAC960_AllocateCommand(Controller)) == NULL) - DAC960_WaitForCommand(Controller); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox = &Command->V2.CommandMailbox; - memcpy(CommandMailbox, &UserCommand.CommandMailbox, - sizeof(DAC960_V2_CommandMailbox_T)); - CommandMailbox->Common.CommandControlBits - .AdditionalScatterGatherListMemory = false; - CommandMailbox->Common.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->Common.DataTransferSize = 0; - CommandMailbox->Common.DataTransferPageNumber = 0; - memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0, - sizeof(DAC960_V2_DataTransferMemoryAddress_T)); - if (DataTransferLength != 0) - { - if (DataTransferLength > 0) - { - CommandMailbox->Common.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->Common.DataTransferSize = DataTransferLength; - } - else - { - CommandMailbox->Common.CommandControlBits - .DataTransferControllerToHost = false; - CommandMailbox->Common.DataTransferSize = -DataTransferLength; - } - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = DataTransferBufferDMA; - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->Common.DataTransferSize; - } - if (RequestSenseLength > 0) - { - CommandMailbox->Common.CommandControlBits - .NoAutoRequestSense = false; - CommandMailbox->Common.RequestSenseSize = RequestSenseLength; - CommandMailbox->Common.RequestSenseBusAddress = - RequestSenseBufferDMA; - } - DAC960_ExecuteCommand(Command); - CommandStatus = Command->V2.CommandStatus; - RequestSenseLength = Command->V2.RequestSenseLength; - DataTransferResidue = Command->V2.DataTransferResidue; - spin_lock_irqsave(&Controller->queue_lock, flags); - DAC960_DeallocateCommand(Command); - spin_unlock_irqrestore(&Controller->queue_lock, flags); - if (RequestSenseLength > UserCommand.RequestSenseLength) - RequestSenseLength = UserCommand.RequestSenseLength; - if (copy_to_user(&UserSpaceUserCommand->DataTransferLength, - &DataTransferResidue, - sizeof(DataTransferResidue))) { - ErrorCode = -EFAULT; - goto Failure2; - } - if (copy_to_user(&UserSpaceUserCommand->RequestSenseLength, - &RequestSenseLength, sizeof(RequestSenseLength))) { - ErrorCode = -EFAULT; - goto Failure2; - } - if (DataTransferLength > 0) - { - if (copy_to_user(UserCommand.DataTransferBuffer, - DataTransferBuffer, DataTransferLength)) { - ErrorCode = -EFAULT; - goto Failure2; - } - } - if (RequestSenseLength > 0) - { - if (copy_to_user(UserCommand.RequestSenseBuffer, - RequestSenseBuffer, RequestSenseLength)) { - ErrorCode = -EFAULT; - goto Failure2; - } - } - ErrorCode = CommandStatus; - Failure2: - pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength), - DataTransferBuffer, DataTransferBufferDMA); - if (RequestSenseBuffer != NULL) - pci_free_consistent(Controller->PCIDevice, RequestSenseLength, - RequestSenseBuffer, RequestSenseBufferDMA); -out: - return ErrorCode; -} - -static long DAC960_gam_v2_get_health_status(DAC960_V2_GetHealthStatus_T __user *UserSpaceGetHealthStatus) -{ - DAC960_V2_GetHealthStatus_T GetHealthStatus; - DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer; - DAC960_Controller_T *Controller; - int ControllerNumber; - long ErrorCode; - - if (UserSpaceGetHealthStatus == NULL) { - ErrorCode = -EINVAL; - goto out; - } - if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus, - sizeof(DAC960_V2_GetHealthStatus_T))) { - ErrorCode = -EFAULT; - goto out; - } - ErrorCode = -ENXIO; - ControllerNumber = GetHealthStatus.ControllerNumber; - if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) - goto out; - Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - goto out; - if (Controller->FirmwareType != DAC960_V2_Controller) { - ErrorCode = -EINVAL; - goto out; - } - if (copy_from_user(&HealthStatusBuffer, - GetHealthStatus.HealthStatusBuffer, - sizeof(DAC960_V2_HealthStatusBuffer_T))) { - ErrorCode = -EFAULT; - goto out; - } - ErrorCode = wait_event_interruptible_timeout(Controller->HealthStatusWaitQueue, - !(Controller->V2.HealthStatusBuffer->StatusChangeCounter - == HealthStatusBuffer.StatusChangeCounter && - Controller->V2.HealthStatusBuffer->NextEventSequenceNumber - == HealthStatusBuffer.NextEventSequenceNumber), - DAC960_MonitoringTimerInterval); - if (ErrorCode == -ERESTARTSYS) { - ErrorCode = -EINTR; - goto out; - } - if (copy_to_user(GetHealthStatus.HealthStatusBuffer, - Controller->V2.HealthStatusBuffer, - sizeof(DAC960_V2_HealthStatusBuffer_T))) - ErrorCode = -EFAULT; - else - ErrorCode = 0; - -out: - return ErrorCode; -} - -/* - * DAC960_gam_ioctl is the ioctl function for performing RAID operations. -*/ - -static long DAC960_gam_ioctl(struct file *file, unsigned int Request, - unsigned long Argument) -{ - long ErrorCode = 0; - void __user *argp = (void __user *)Argument; - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - - mutex_lock(&DAC960_mutex); - switch (Request) - { - case DAC960_IOCTL_GET_CONTROLLER_COUNT: - ErrorCode = DAC960_ControllerCount; - break; - case DAC960_IOCTL_GET_CONTROLLER_INFO: - ErrorCode = DAC960_gam_get_controller_info(argp); - break; - case DAC960_IOCTL_V1_EXECUTE_COMMAND: - ErrorCode = DAC960_gam_v1_execute_command(argp); - break; - case DAC960_IOCTL_V2_EXECUTE_COMMAND: - ErrorCode = DAC960_gam_v2_execute_command(argp); - break; - case DAC960_IOCTL_V2_GET_HEALTH_STATUS: - ErrorCode = DAC960_gam_v2_get_health_status(argp); - break; - default: - ErrorCode = -ENOTTY; - } - mutex_unlock(&DAC960_mutex); - return ErrorCode; -} - -static const struct file_operations DAC960_gam_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = DAC960_gam_ioctl, - .llseek = noop_llseek, -}; - -static struct miscdevice DAC960_gam_dev = { - DAC960_GAM_MINOR, - "dac960_gam", - &DAC960_gam_fops -}; - -static int DAC960_gam_init(void) -{ - int ret; - - ret = misc_register(&DAC960_gam_dev); - if (ret) - printk(KERN_ERR "DAC960_gam: can't misc_register on minor %d\n", DAC960_GAM_MINOR); - return ret; -} - -static void DAC960_gam_cleanup(void) -{ - misc_deregister(&DAC960_gam_dev); -} - -#endif /* DAC960_GAM_MINOR */ - -static struct DAC960_privdata DAC960_GEM_privdata = { - .HardwareType = DAC960_GEM_Controller, - .FirmwareType = DAC960_V2_Controller, - .InterruptHandler = DAC960_GEM_InterruptHandler, - .MemoryWindowSize = DAC960_GEM_RegisterWindowSize, -}; - - -static struct DAC960_privdata DAC960_BA_privdata = { - .HardwareType = DAC960_BA_Controller, - .FirmwareType = DAC960_V2_Controller, - .InterruptHandler = DAC960_BA_InterruptHandler, - .MemoryWindowSize = DAC960_BA_RegisterWindowSize, -}; - -static struct DAC960_privdata DAC960_LP_privdata = { - .HardwareType = DAC960_LP_Controller, - .FirmwareType = DAC960_V2_Controller, - .InterruptHandler = DAC960_LP_InterruptHandler, - .MemoryWindowSize = DAC960_LP_RegisterWindowSize, -}; - -static struct DAC960_privdata DAC960_LA_privdata = { - .HardwareType = DAC960_LA_Controller, - .FirmwareType = DAC960_V1_Controller, - .InterruptHandler = DAC960_LA_InterruptHandler, - .MemoryWindowSize = DAC960_LA_RegisterWindowSize, -}; - -static struct DAC960_privdata DAC960_PG_privdata = { - .HardwareType = DAC960_PG_Controller, - .FirmwareType = DAC960_V1_Controller, - .InterruptHandler = DAC960_PG_InterruptHandler, - .MemoryWindowSize = DAC960_PG_RegisterWindowSize, -}; - -static struct DAC960_privdata DAC960_PD_privdata = { - .HardwareType = DAC960_PD_Controller, - .FirmwareType = DAC960_V1_Controller, - .InterruptHandler = DAC960_PD_InterruptHandler, - .MemoryWindowSize = DAC960_PD_RegisterWindowSize, -}; - -static struct DAC960_privdata DAC960_P_privdata = { - .HardwareType = DAC960_P_Controller, - .FirmwareType = DAC960_V1_Controller, - .InterruptHandler = DAC960_P_InterruptHandler, - .MemoryWindowSize = DAC960_PD_RegisterWindowSize, -}; - -static const struct pci_device_id DAC960_id_table[] = { - { - .vendor = PCI_VENDOR_ID_MYLEX, - .device = PCI_DEVICE_ID_MYLEX_DAC960_GEM, - .subvendor = PCI_VENDOR_ID_MYLEX, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) &DAC960_GEM_privdata, - }, - { - .vendor = PCI_VENDOR_ID_MYLEX, - .device = PCI_DEVICE_ID_MYLEX_DAC960_BA, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) &DAC960_BA_privdata, - }, - { - .vendor = PCI_VENDOR_ID_MYLEX, - .device = PCI_DEVICE_ID_MYLEX_DAC960_LP, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) &DAC960_LP_privdata, - }, - { - .vendor = PCI_VENDOR_ID_DEC, - .device = PCI_DEVICE_ID_DEC_21285, - .subvendor = PCI_VENDOR_ID_MYLEX, - .subdevice = PCI_DEVICE_ID_MYLEX_DAC960_LA, - .driver_data = (unsigned long) &DAC960_LA_privdata, - }, - { - .vendor = PCI_VENDOR_ID_MYLEX, - .device = PCI_DEVICE_ID_MYLEX_DAC960_PG, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) &DAC960_PG_privdata, - }, - { - .vendor = PCI_VENDOR_ID_MYLEX, - .device = PCI_DEVICE_ID_MYLEX_DAC960_PD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) &DAC960_PD_privdata, - }, - { - .vendor = PCI_VENDOR_ID_MYLEX, - .device = PCI_DEVICE_ID_MYLEX_DAC960_P, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) &DAC960_P_privdata, - }, - {0, }, -}; - -MODULE_DEVICE_TABLE(pci, DAC960_id_table); - -static struct pci_driver DAC960_pci_driver = { - .name = "DAC960", - .id_table = DAC960_id_table, - .probe = DAC960_Probe, - .remove = DAC960_Remove, -}; - -static int __init DAC960_init_module(void) -{ - int ret; - - ret = pci_register_driver(&DAC960_pci_driver); -#ifdef DAC960_GAM_MINOR - if (!ret) - DAC960_gam_init(); -#endif - return ret; -} - -static void __exit DAC960_cleanup_module(void) -{ - int i; - -#ifdef DAC960_GAM_MINOR - DAC960_gam_cleanup(); -#endif - - for (i = 0; i < DAC960_ControllerCount; i++) { - DAC960_Controller_T *Controller = DAC960_Controllers[i]; - if (Controller == NULL) - continue; - DAC960_FinalizeController(Controller); - } - if (DAC960_ProcDirectoryEntry != NULL) { - remove_proc_entry("rd/status", NULL); - remove_proc_entry("rd", NULL); - } - DAC960_ControllerCount = 0; - pci_unregister_driver(&DAC960_pci_driver); -} - -module_init(DAC960_init_module); -module_exit(DAC960_cleanup_module); - -MODULE_LICENSE("GPL"); diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h deleted file mode 100644 index 1439e651928b..000000000000 --- a/drivers/block/DAC960.h +++ /dev/null @@ -1,4414 +0,0 @@ -/* - - Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - - Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com> - - This program is free software; you may redistribute and/or modify it under - the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for complete details. - - The author respectfully requests that any modifications to this software be - sent directly to him for evaluation and testing. - -*/ - - -/* - Define the maximum number of DAC960 Controllers supported by this driver. -*/ - -#define DAC960_MaxControllers 8 - - -/* - Define the maximum number of Controller Channels supported by DAC960 - V1 and V2 Firmware Controllers. -*/ - -#define DAC960_V1_MaxChannels 3 -#define DAC960_V2_MaxChannels 4 - - -/* - Define the maximum number of Targets per Channel supported by DAC960 - V1 and V2 Firmware Controllers. -*/ - -#define DAC960_V1_MaxTargets 16 -#define DAC960_V2_MaxTargets 128 - - -/* - Define the maximum number of Logical Drives supported by DAC960 - V1 and V2 Firmware Controllers. -*/ - -#define DAC960_MaxLogicalDrives 32 - - -/* - Define the maximum number of Physical Devices supported by DAC960 - V1 and V2 Firmware Controllers. -*/ - -#define DAC960_V1_MaxPhysicalDevices 45 -#define DAC960_V2_MaxPhysicalDevices 272 - -/* - Define a 32/64 bit I/O Address data type. -*/ - -typedef unsigned long DAC960_IO_Address_T; - - -/* - Define a 32/64 bit PCI Bus Address data type. -*/ - -typedef unsigned long DAC960_PCI_Address_T; - - -/* - Define a 32 bit Bus Address data type. -*/ - -typedef unsigned int DAC960_BusAddress32_T; - - -/* - Define a 64 bit Bus Address data type. -*/ - -typedef unsigned long long DAC960_BusAddress64_T; - - -/* - Define a 32 bit Byte Count data type. -*/ - -typedef unsigned int DAC960_ByteCount32_T; - - -/* - Define a 64 bit Byte Count data type. -*/ - -typedef unsigned long long DAC960_ByteCount64_T; - - -/* - dma_loaf is used by helper routines to divide a region of - dma mapped memory into smaller pieces, where those pieces - are not of uniform size. - */ - -struct dma_loaf { - void *cpu_base; - dma_addr_t dma_base; - size_t length; - void *cpu_free; - dma_addr_t dma_free; -}; - -/* - Define the SCSI INQUIRY Standard Data structure. -*/ - -typedef struct DAC960_SCSI_Inquiry -{ - unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ - unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ - unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ - bool RMB:1; /* Byte 1 Bit 7 */ - unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ - unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ - unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ - unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ - unsigned char :2; /* Byte 3 Bits 4-5 */ - bool TrmIOP:1; /* Byte 3 Bit 6 */ - bool AENC:1; /* Byte 3 Bit 7 */ - unsigned char AdditionalLength; /* Byte 4 */ - unsigned char :8; /* Byte 5 */ - unsigned char :8; /* Byte 6 */ - bool SftRe:1; /* Byte 7 Bit 0 */ - bool CmdQue:1; /* Byte 7 Bit 1 */ - bool :1; /* Byte 7 Bit 2 */ - bool Linked:1; /* Byte 7 Bit 3 */ - bool Sync:1; /* Byte 7 Bit 4 */ - bool WBus16:1; /* Byte 7 Bit 5 */ - bool WBus32:1; /* Byte 7 Bit 6 */ - bool RelAdr:1; /* Byte 7 Bit 7 */ - unsigned char VendorIdentification[8]; /* Bytes 8-15 */ - unsigned char ProductIdentification[16]; /* Bytes 16-31 */ - unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ -} -DAC960_SCSI_Inquiry_T; - - -/* - Define the SCSI INQUIRY Unit Serial Number structure. -*/ - -typedef struct DAC960_SCSI_Inquiry_UnitSerialNumber -{ - unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ - unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ - unsigned char PageCode; /* Byte 1 */ - unsigned char :8; /* Byte 2 */ - unsigned char PageLength; /* Byte 3 */ - unsigned char ProductSerialNumber[28]; /* Bytes 4-31 */ -} -DAC960_SCSI_Inquiry_UnitSerialNumber_T; - - -/* - Define the SCSI REQUEST SENSE Sense Key type. -*/ - -typedef enum -{ - DAC960_SenseKey_NoSense = 0x0, - DAC960_SenseKey_RecoveredError = 0x1, - DAC960_SenseKey_NotReady = 0x2, - DAC960_SenseKey_MediumError = 0x3, - DAC960_SenseKey_HardwareError = 0x4, - DAC960_SenseKey_IllegalRequest = 0x5, - DAC960_SenseKey_UnitAttention = 0x6, - DAC960_SenseKey_DataProtect = 0x7, - DAC960_SenseKey_BlankCheck = 0x8, - DAC960_SenseKey_VendorSpecific = 0x9, - DAC960_SenseKey_CopyAborted = 0xA, - DAC960_SenseKey_AbortedCommand = 0xB, - DAC960_SenseKey_Equal = 0xC, - DAC960_SenseKey_VolumeOverflow = 0xD, - DAC960_SenseKey_Miscompare = 0xE, - DAC960_SenseKey_Reserved = 0xF -} -__attribute__ ((packed)) -DAC960_SCSI_RequestSenseKey_T; - - -/* - Define the SCSI REQUEST SENSE structure. -*/ - -typedef struct DAC960_SCSI_RequestSense -{ - unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */ - bool Valid:1; /* Byte 0 Bit 7 */ - unsigned char SegmentNumber; /* Byte 1 */ - DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 2 Bits 0-3 */ - unsigned char :1; /* Byte 2 Bit 4 */ - bool ILI:1; /* Byte 2 Bit 5 */ - bool EOM:1; /* Byte 2 Bit 6 */ - bool Filemark:1; /* Byte 2 Bit 7 */ - unsigned char Information[4]; /* Bytes 3-6 */ - unsigned char AdditionalSenseLength; /* Byte 7 */ - unsigned char CommandSpecificInformation[4]; /* Bytes 8-11 */ - unsigned char AdditionalSenseCode; /* Byte 12 */ - unsigned char AdditionalSenseCodeQualifier; /* Byte 13 */ -} -DAC960_SCSI_RequestSense_T; - - -/* - Define the DAC960 V1 Firmware Command Opcodes. -*/ - -typedef enum -{ - /* I/O Commands */ - DAC960_V1_ReadExtended = 0x33, - DAC960_V1_WriteExtended = 0x34, - DAC960_V1_ReadAheadExtended = 0x35, - DAC960_V1_ReadExtendedWithScatterGather = 0xB3, - DAC960_V1_WriteExtendedWithScatterGather = 0xB4, - DAC960_V1_Read = 0x36, - DAC960_V1_ReadWithScatterGather = 0xB6, - DAC960_V1_Write = 0x37, - DAC960_V1_WriteWithScatterGather = 0xB7, - DAC960_V1_DCDB = 0x04, - DAC960_V1_DCDBWithScatterGather = 0x84, - DAC960_V1_Flush = 0x0A, - /* Controller Status Related Commands */ - DAC960_V1_Enquiry = 0x53, - DAC960_V1_Enquiry2 = 0x1C, - DAC960_V1_GetLogicalDriveElement = 0x55, - DAC960_V1_GetLogicalDriveInformation = 0x19, - DAC960_V1_IOPortRead = 0x39, - DAC960_V1_IOPortWrite = 0x3A, - DAC960_V1_GetSDStats = 0x3E, - DAC960_V1_GetPDStats = 0x3F, - DAC960_V1_PerformEventLogOperation = 0x72, - /* Device Related Commands */ - DAC960_V1_StartDevice = 0x10, - DAC960_V1_GetDeviceState = 0x50, - DAC960_V1_StopChannel = 0x13, - DAC960_V1_StartChannel = 0x12, - DAC960_V1_ResetChannel = 0x1A, - /* Commands Associated with Data Consistency and Errors */ - DAC960_V1_Rebuild = 0x09, - DAC960_V1_RebuildAsync = 0x16, - DAC960_V1_CheckConsistency = 0x0F, - DAC960_V1_CheckConsistencyAsync = 0x1E, - DAC960_V1_RebuildStat = 0x0C, - DAC960_V1_GetRebuildProgress = 0x27, - DAC960_V1_RebuildControl = 0x1F, - DAC960_V1_ReadBadBlockTable = 0x0B, - DAC960_V1_ReadBadDataTable = 0x25, - DAC960_V1_ClearBadDataTable = 0x26, - DAC960_V1_GetErrorTable = 0x17, - DAC960_V1_AddCapacityAsync = 0x2A, - DAC960_V1_BackgroundInitializationControl = 0x2B, - /* Configuration Related Commands */ - DAC960_V1_ReadConfig2 = 0x3D, - DAC960_V1_WriteConfig2 = 0x3C, - DAC960_V1_ReadConfigurationOnDisk = 0x4A, - DAC960_V1_WriteConfigurationOnDisk = 0x4B, - DAC960_V1_ReadConfiguration = 0x4E, - DAC960_V1_ReadBackupConfiguration = 0x4D, - DAC960_V1_WriteConfiguration = 0x4F, - DAC960_V1_AddConfiguration = 0x4C, - DAC960_V1_ReadConfigurationLabel = 0x48, - DAC960_V1_WriteConfigurationLabel = 0x49, - /* Firmware Upgrade Related Commands */ - DAC960_V1_LoadImage = 0x20, - DAC960_V1_StoreImage = 0x21, - DAC960_V1_ProgramImage = 0x22, - /* Diagnostic Commands */ - DAC960_V1_SetDiagnosticMode = 0x31, - DAC960_V1_RunDiagnostic = 0x32, - /* Subsystem Service Commands */ - DAC960_V1_GetSubsystemData = 0x70, - DAC960_V1_SetSubsystemParameters = 0x71, - /* Version 2.xx Firmware Commands */ - DAC960_V1_Enquiry_Old = 0x05, - DAC960_V1_GetDeviceState_Old = 0x14, - DAC960_V1_Read_Old = 0x02, - DAC960_V1_Write_Old = 0x03, - DAC960_V1_ReadWithScatterGather_Old = 0x82, - DAC960_V1_WriteWithScatterGather_Old = 0x83 -} -__attribute__ ((packed)) -DAC960_V1_CommandOpcode_T; - - -/* - Define the DAC960 V1 Firmware Command Identifier type. -*/ - -typedef unsigned char DAC960_V1_CommandIdentifier_T; - - -/* - Define the DAC960 V1 Firmware Command Status Codes. -*/ - -#define DAC960_V1_NormalCompletion 0x0000 /* Common */ -#define DAC960_V1_CheckConditionReceived 0x0002 /* Common */ -#define DAC960_V1_NoDeviceAtAddress 0x0102 /* Common */ -#define DAC960_V1_InvalidDeviceAddress 0x0105 /* Common */ -#define DAC960_V1_InvalidParameter 0x0105 /* Common */ -#define DAC960_V1_IrrecoverableDataError 0x0001 /* I/O */ -#define DAC960_V1_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */ -#define DAC960_V1_AccessBeyondEndOfLogicalDrive 0x0105 /* I/O */ -#define DAC960_V1_BadDataEncountered 0x010C /* I/O */ -#define DAC960_V1_DeviceBusy 0x0008 /* DCDB */ -#define DAC960_V1_DeviceNonresponsive 0x000E /* DCDB */ -#define DAC960_V1_CommandTerminatedAbnormally 0x000F /* DCDB */ -#define DAC960_V1_UnableToStartDevice 0x0002 /* Device */ -#define DAC960_V1_InvalidChannelOrTargetOrModifier 0x0105 /* Device */ -#define DAC960_V1_ChannelBusy 0x0106 /* Device */ -#define DAC960_V1_ChannelNotStopped 0x0002 /* Device */ -#define DAC960_V1_AttemptToRebuildOnlineDrive 0x0002 /* Consistency */ -#define DAC960_V1_RebuildBadBlocksEncountered 0x0003 /* Consistency */ -#define DAC960_V1_NewDiskFailedDuringRebuild 0x0004 /* Consistency */ -#define DAC960_V1_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */ -#define DAC960_V1_DependentDiskIsDead 0x0002 /* Consistency */ -#define DAC960_V1_InconsistentBlocksFound 0x0003 /* Consistency */ -#define DAC960_V1_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */ -#define DAC960_V1_NoRebuildOrCheckInProgress 0x0105 /* Consistency */ -#define DAC960_V1_RebuildInProgress_DataValid 0x0000 /* Consistency */ -#define DAC960_V1_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */ -#define DAC960_V1_RebuildFailed_BadBlocksOnOther 0x0003 /* Consistency */ -#define DAC960_V1_RebuildFailed_NewDriveFailed 0x0004 /* Consistency */ -#define DAC960_V1_RebuildSuccessful 0x0100 /* Consistency */ -#define DAC960_V1_RebuildSuccessfullyTerminated 0x0107 /* Consistency */ -#define DAC960_V1_BackgroundInitSuccessful 0x0100 /* Consistency */ -#define DAC960_V1_BackgroundInitAborted 0x0005 /* Consistency */ -#define DAC960_V1_NoBackgroundInitInProgress 0x0105 /* Consistency */ -#define DAC960_V1_AddCapacityInProgress 0x0004 /* Consistency */ -#define DAC960_V1_AddCapacityFailedOrSuspended 0x00F4 /* Consistency */ -#define DAC960_V1_Config2ChecksumError 0x0002 /* Configuration */ -#define DAC960_V1_ConfigurationSuspended 0x0106 /* Configuration */ -#define DAC960_V1_FailedToConfigureNVRAM 0x0105 /* Configuration */ -#define DAC960_V1_ConfigurationNotSavedStateChange 0x0106 /* Configuration */ -#define DAC960_V1_SubsystemNotInstalled 0x0001 /* Subsystem */ -#define DAC960_V1_SubsystemFailed 0x0002 /* Subsystem */ -#define DAC960_V1_SubsystemBusy 0x0106 /* Subsystem */ - -typedef unsigned short DAC960_V1_CommandStatus_T; - - -/* - Define the DAC960 V1 Firmware Enquiry Command reply structure. -*/ - -typedef struct DAC960_V1_Enquiry -{ - unsigned char NumberOfLogicalDrives; /* Byte 0 */ - unsigned int :24; /* Bytes 1-3 */ - unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */ - unsigned short FlashAge; /* Bytes 132-133 */ - struct { - bool DeferredWriteError:1; /* Byte 134 Bit 0 */ - bool BatteryLow:1; /* Byte 134 Bit 1 */ - unsigned char :6; /* Byte 134 Bits 2-7 */ - } StatusFlags; - unsigned char :8; /* Byte 135 */ - unsigned char MinorFirmwareVersion; /* Byte 136 */ - unsigned char MajorFirmwareVersion; /* Byte 137 */ - enum { - DAC960_V1_NoStandbyRebuildOrCheckInProgress = 0x00, - DAC960_V1_StandbyRebuildInProgress = 0x01, - DAC960_V1_BackgroundRebuildInProgress = 0x02, - DAC960_V1_BackgroundCheckInProgress = 0x03, - DAC960_V1_StandbyRebuildCompletedWithError = 0xFF, - DAC960_V1_BackgroundRebuildOrCheckFailed_DriveFailed = 0xF0, - DAC960_V1_BackgroundRebuildOrCheckFailed_LogicalDriveFailed = 0xF1, - DAC960_V1_BackgroundRebuildOrCheckFailed_OtherCauses = 0xF2, - DAC960_V1_BackgroundRebuildOrCheckSuccessfullyTerminated = 0xF3 - } __attribute__ ((packed)) RebuildFlag; /* Byte 138 */ - unsigned char MaxCommands; /* Byte 139 */ - unsigned char OfflineLogicalDriveCount; /* Byte 140 */ - unsigned char :8; /* Byte 141 */ - unsigned short EventLogSequenceNumber; /* Bytes 142-143 */ - unsigned char CriticalLogicalDriveCount; /* Byte 144 */ - unsigned int :24; /* Bytes 145-147 */ - unsigned char DeadDriveCount; /* Byte 148 */ - unsigned char :8; /* Byte 149 */ - unsigned char RebuildCount; /* Byte 150 */ - struct { - unsigned char :3; /* Byte 151 Bits 0-2 */ - bool BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */ - unsigned char :3; /* Byte 151 Bits 4-6 */ - unsigned char :1; /* Byte 151 Bit 7 */ - } MiscFlags; - struct { - unsigned char TargetID; - unsigned char Channel; - } DeadDrives[21]; /* Bytes 152-194 */ - unsigned char Reserved[62]; /* Bytes 195-255 */ -} -__attribute__ ((packed)) -DAC960_V1_Enquiry_T; - - -/* - Define the DAC960 V1 Firmware Enquiry2 Command reply structure. -*/ - -typedef struct DAC960_V1_Enquiry2 -{ - struct { - enum { - DAC960_V1_P_PD_PU = 0x01, - DAC960_V1_PL = 0x02, - DAC960_V1_PG = 0x10, - DAC960_V1_PJ = 0x11, - DAC960_V1_PR = 0x12, - DAC960_V1_PT = 0x13, - DAC960_V1_PTL0 = 0x14, - DAC960_V1_PRL = 0x15, - DAC960_V1_PTL1 = 0x16, - DAC960_V1_1164P = 0x20 - } __attribute__ ((packed)) SubModel; /* Byte 0 */ - unsigned char ActualChannels; /* Byte 1 */ - enum { - DAC960_V1_FiveChannelBoard = 0x01, - DAC960_V1_ThreeChannelBoard = 0x02, - DAC960_V1_TwoChannelBoard = 0x03, - DAC960_V1_ThreeChannelASIC_DAC = 0x04 - } __attribute__ ((packed)) Model; /* Byte 2 */ - enum { - DAC960_V1_EISA_Controller = 0x01, - DAC960_V1_MicroChannel_Controller = 0x02, - DAC960_V1_PCI_Controller = 0x03, - DAC960_V1_SCSItoSCSI_Controller = 0x08 - } __attribute__ ((packed)) ProductFamily; /* Byte 3 */ - } HardwareID; /* Bytes 0-3 */ - /* MajorVersion.MinorVersion-FirmwareType-TurnID */ - struct { - unsigned char MajorVersion; /* Byte 4 */ - unsigned char MinorVersion; /* Byte 5 */ - unsigned char TurnID; /* Byte 6 */ - char FirmwareType; /* Byte 7 */ - } FirmwareID; /* Bytes 4-7 */ - unsigned char :8; /* Byte 8 */ - unsigned int :24; /* Bytes 9-11 */ - unsigned char ConfiguredChannels; /* Byte 12 */ - unsigned char ActualChannels; /* Byte 13 */ - unsigned char MaxTargets; /* Byte 14 */ - unsigned char MaxTags; /* Byte 15 */ - unsigned char MaxLogicalDrives; /* Byte 16 */ - unsigned char MaxArms; /* Byte 17 */ - unsigned char MaxSpans; /* Byte 18 */ - unsigned char :8; /* Byte 19 */ - unsigned int :32; /* Bytes 20-23 */ - unsigned int MemorySize; /* Bytes 24-27 */ - unsigned int CacheSize; /* Bytes 28-31 */ - unsigned int FlashMemorySize; /* Bytes 32-35 */ - unsigned int NonVolatileMemorySize; /* Bytes 36-39 */ - struct { - enum { - DAC960_V1_RamType_DRAM = 0x0, - DAC960_V1_RamType_EDO = 0x1, - DAC960_V1_RamType_SDRAM = 0x2, - DAC960_V1_RamType_Last = 0x7 - } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */ - enum { - DAC960_V1_ErrorCorrection_None = 0x0, - DAC960_V1_ErrorCorrection_Parity = 0x1, - DAC960_V1_ErrorCorrection_ECC = 0x2, - DAC960_V1_ErrorCorrection_Last = 0x7 - } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */ - bool FastPageMode:1; /* Byte 40 Bit 6 */ - bool LowPowerMemory:1; /* Byte 40 Bit 7 */ - unsigned char :8; /* Bytes 41 */ - } MemoryType; - unsigned short ClockSpeed; /* Bytes 42-43 */ - unsigned short MemorySpeed; /* Bytes 44-45 */ - unsigned short HardwareSpeed; /* Bytes 46-47 */ - unsigned int :32; /* Bytes 48-51 */ - unsigned int :32; /* Bytes 52-55 */ - unsigned char :8; /* Byte 56 */ - unsigned char :8; /* Byte 57 */ - unsigned short :16; /* Bytes 58-59 */ - unsigned short MaxCommands; /* Bytes 60-61 */ - unsigned short MaxScatterGatherEntries; /* Bytes 62-63 */ - unsigned short MaxDriveCommands; /* Bytes 64-65 */ - unsigned short MaxIODescriptors; /* Bytes 66-67 */ - unsigned short MaxCombinedSectors; /* Bytes 68-69 */ - unsigned char Latency; /* Byte 70 */ - unsigned char :8; /* Byte 71 */ - unsigned char SCSITimeout; /* Byte 72 */ - unsigned char :8; /* Byte 73 */ - unsigned short MinFreeLines; /* Bytes 74-75 */ - unsigned int :32; /* Bytes 76-79 */ - unsigned int :32; /* Bytes 80-83 */ - unsigned char RebuildRateConstant; /* Byte 84 */ - unsigned char :8; /* Byte 85 */ - unsigned char :8; /* Byte 86 */ - unsigned char :8; /* Byte 87 */ - unsigned int :32; /* Bytes 88-91 */ - unsigned int :32; /* Bytes 92-95 */ - unsigned short PhysicalDriveBlockSize; /* Bytes 96-97 */ - unsigned short LogicalDriveBlockSize; /* Bytes 98-99 */ - unsigned short MaxBlocksPerCommand; /* Bytes 100-101 */ - unsigned short BlockFactor; /* Bytes 102-103 */ - unsigned short CacheLineSize; /* Bytes 104-105 */ - struct { - enum { - DAC960_V1_Narrow_8bit = 0x0, - DAC960_V1_Wide_16bit = 0x1, - DAC960_V1_Wide_32bit = 0x2 - } __attribute__ ((packed)) BusWidth:2; /* Byte 106 Bits 0-1 */ - enum { - DAC960_V1_Fast = 0x0, - DAC960_V1_Ultra = 0x1, - DAC960_V1_Ultra2 = 0x2 - } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */ - bool Differential:1; /* Byte 106 Bit 4 */ - unsigned char :3; /* Byte 106 Bits 5-7 */ - } SCSICapability; - unsigned char :8; /* Byte 107 */ - unsigned int :32; /* Bytes 108-111 */ - unsigned short FirmwareBuildNumber; /* Bytes 112-113 */ - enum { - DAC960_V1_AEMI = 0x01, - DAC960_V1_OEM1 = 0x02, - DAC960_V1_OEM2 = 0x04, - DAC960_V1_OEM3 = 0x08, - DAC960_V1_Conner = 0x10, - DAC960_V1_SAFTE = 0x20 - } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */ - unsigned char :8; /* Byte 115 */ - struct { - bool Clustering:1; /* Byte 116 Bit 0 */ - bool MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */ - bool ReadAhead:1; /* Byte 116 Bit 2 */ - bool BackgroundInitialization:1; /* Byte 116 Bit 3 */ - unsigned int :28; /* Bytes 116-119 */ - } FirmwareFeatures; - unsigned int :32; /* Bytes 120-123 */ - unsigned int :32; /* Bytes 124-127 */ -} -DAC960_V1_Enquiry2_T; - - -/* - Define the DAC960 V1 Firmware Logical Drive State type. -*/ - -typedef enum -{ - DAC960_V1_LogicalDrive_Online = 0x03, - DAC960_V1_LogicalDrive_Critical = 0x04, - DAC960_V1_LogicalDrive_Offline = 0xFF -} -__attribute__ ((packed)) -DAC960_V1_LogicalDriveState_T; - - -/* - Define the DAC960 V1 Firmware Logical Drive Information structure. -*/ - -typedef struct DAC960_V1_LogicalDriveInformation -{ - unsigned int LogicalDriveSize; /* Bytes 0-3 */ - DAC960_V1_LogicalDriveState_T LogicalDriveState; /* Byte 4 */ - unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */ - bool WriteBack:1; /* Byte 5 Bit 7 */ - unsigned short :16; /* Bytes 6-7 */ -} -DAC960_V1_LogicalDriveInformation_T; - - -/* - Define the DAC960 V1 Firmware Get Logical Drive Information Command - reply structure. -*/ - -typedef DAC960_V1_LogicalDriveInformation_T - DAC960_V1_LogicalDriveInformationArray_T[DAC960_MaxLogicalDrives]; - - -/* - Define the DAC960 V1 Firmware Perform Event Log Operation Types. -*/ - -typedef enum -{ - DAC960_V1_GetEventLogEntry = 0x00 -} -__attribute__ ((packed)) -DAC960_V1_PerformEventLogOpType_T; - - -/* - Define the DAC960 V1 Firmware Get Event Log Entry Command reply structure. -*/ - -typedef struct DAC960_V1_EventLogEntry -{ - unsigned char MessageType; /* Byte 0 */ - unsigned char MessageLength; /* Byte 1 */ - unsigned char TargetID:5; /* Byte 2 Bits 0-4 */ - unsigned char Channel:3; /* Byte 2 Bits 5-7 */ - unsigned char LogicalUnit:6; /* Byte 3 Bits 0-5 */ - unsigned char :2; /* Byte 3 Bits 6-7 */ - unsigned short SequenceNumber; /* Bytes 4-5 */ - unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */ - bool Valid:1; /* Byte 6 Bit 7 */ - unsigned char SegmentNumber; /* Byte 7 */ - DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 8 Bits 0-3 */ - unsigned char :1; /* Byte 8 Bit 4 */ - bool ILI:1; /* Byte 8 Bit 5 */ - bool EOM:1; /* Byte 8 Bit 6 */ - bool Filemark:1; /* Byte 8 Bit 7 */ - unsigned char Information[4]; /* Bytes 9-12 */ - unsigned char AdditionalSenseLength; /* Byte 13 */ - unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */ - unsigned char AdditionalSenseCode; /* Byte 18 */ - unsigned char AdditionalSenseCodeQualifier; /* Byte 19 */ - unsigned char Dummy[12]; /* Bytes 20-31 */ -} -DAC960_V1_EventLogEntry_T; - - -/* - Define the DAC960 V1 Firmware Physical Device State type. -*/ - -typedef enum -{ - DAC960_V1_Device_Dead = 0x00, - DAC960_V1_Device_WriteOnly = 0x02, - DAC960_V1_Device_Online = 0x03, - DAC960_V1_Device_Standby = 0x10 -} -__attribute__ ((packed)) -DAC960_V1_PhysicalDeviceState_T; - - -/* - Define the DAC960 V1 Firmware Get Device State Command reply structure. - The structure is padded by 2 bytes for compatibility with Version 2.xx - Firmware. -*/ - -typedef struct DAC960_V1_DeviceState -{ - bool Present:1; /* Byte 0 Bit 0 */ - unsigned char :7; /* Byte 0 Bits 1-7 */ - enum { - DAC960_V1_OtherType = 0x0, - DAC960_V1_DiskType = 0x1, - DAC960_V1_SequentialType = 0x2, - DAC960_V1_CDROM_or_WORM_Type = 0x3 - } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */ - bool :1; /* Byte 1 Bit 2 */ - bool Fast20:1; /* Byte 1 Bit 3 */ - bool Sync:1; /* Byte 1 Bit 4 */ - bool Fast:1; /* Byte 1 Bit 5 */ - bool Wide:1; /* Byte 1 Bit 6 */ - bool TaggedQueuingSupported:1; /* Byte 1 Bit 7 */ - DAC960_V1_PhysicalDeviceState_T DeviceState; /* Byte 2 */ - unsigned char :8; /* Byte 3 */ - unsigned char SynchronousMultiplier; /* Byte 4 */ - unsigned char SynchronousOffset:5; /* Byte 5 Bits 0-4 */ - unsigned char :3; /* Byte 5 Bits 5-7 */ - unsigned int DiskSize __attribute__ ((packed)); /* Bytes 6-9 */ - unsigned short :16; /* Bytes 10-11 */ -} -DAC960_V1_DeviceState_T; - - -/* - Define the DAC960 V1 Firmware Get Rebuild Progress Command reply structure. -*/ - -typedef struct DAC960_V1_RebuildProgress -{ - unsigned int LogicalDriveNumber; /* Bytes 0-3 */ - unsigned int LogicalDriveSize; /* Bytes 4-7 */ - unsigned int RemainingBlocks; /* Bytes 8-11 */ -} -DAC960_V1_RebuildProgress_T; - - -/* - Define the DAC960 V1 Firmware Background Initialization Status Command - reply structure. -*/ - -typedef struct DAC960_V1_BackgroundInitializationStatus -{ - unsigned int LogicalDriveSize; /* Bytes 0-3 */ - unsigned int BlocksCompleted; /* Bytes 4-7 */ - unsigned char Reserved1[12]; /* Bytes 8-19 */ - unsigned int LogicalDriveNumber; /* Bytes 20-23 */ - unsigned char RAIDLevel; /* Byte 24 */ - enum { - DAC960_V1_BackgroundInitializationInvalid = 0x00, - DAC960_V1_BackgroundInitializationStarted = 0x02, - DAC960_V1_BackgroundInitializationInProgress = 0x04, - DAC960_V1_BackgroundInitializationSuspended = 0x05, - DAC960_V1_BackgroundInitializationCancelled = 0x06 - } __attribute__ ((packed)) Status; /* Byte 25 */ - unsigned char Reserved2[6]; /* Bytes 26-31 */ -} -DAC960_V1_BackgroundInitializationStatus_T; - - -/* - Define the DAC960 V1 Firmware Error Table Entry structure. -*/ - -typedef struct DAC960_V1_ErrorTableEntry -{ - unsigned char ParityErrorCount; /* Byte 0 */ - unsigned char SoftErrorCount; /* Byte 1 */ - unsigned char HardErrorCount; /* Byte 2 */ - unsigned char MiscErrorCount; /* Byte 3 */ -} -DAC960_V1_ErrorTableEntry_T; - - -/* - Define the DAC960 V1 Firmware Get Error Table Command reply structure. -*/ - -typedef struct DAC960_V1_ErrorTable -{ - DAC960_V1_ErrorTableEntry_T - ErrorTableEntries[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; -} -DAC960_V1_ErrorTable_T; - - -/* - Define the DAC960 V1 Firmware Read Config2 Command reply structure. -*/ - -typedef struct DAC960_V1_Config2 -{ - unsigned char :1; /* Byte 0 Bit 0 */ - bool ActiveNegationEnabled:1; /* Byte 0 Bit 1 */ - unsigned char :5; /* Byte 0 Bits 2-6 */ - bool NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */ - bool StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */ - bool HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */ - bool NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */ - unsigned char :2; /* Byte 1 Bits 3-4 */ - bool AEMI_ARM:1; /* Byte 1 Bit 5 */ - bool AEMI_OFM:1; /* Byte 1 Bit 6 */ - unsigned char :1; /* Byte 1 Bit 7 */ - enum { - DAC960_V1_OEMID_Mylex = 0x00, - DAC960_V1_OEMID_IBM = 0x08, - DAC960_V1_OEMID_HP = 0x0A, - DAC960_V1_OEMID_DEC = 0x0C, - DAC960_V1_OEMID_Siemens = 0x10, - DAC960_V1_OEMID_Intel = 0x12 - } __attribute__ ((packed)) OEMID; /* Byte 2 */ - unsigned char OEMModelNumber; /* Byte 3 */ - unsigned char PhysicalSector; /* Byte 4 */ - unsigned char LogicalSector; /* Byte 5 */ - unsigned char BlockFactor; /* Byte 6 */ - bool ReadAheadEnabled:1; /* Byte 7 Bit 0 */ - bool LowBIOSDelay:1; /* Byte 7 Bit 1 */ - unsigned char :2; /* Byte 7 Bits 2-3 */ - bool ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */ - unsigned char :1; /* Byte 7 Bit 5 */ - bool ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */ - bool EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */ - unsigned char DefaultRebuildRate; /* Byte 8 */ - unsigned char :8; /* Byte 9 */ - unsigned char BlocksPerCacheLine; /* Byte 10 */ - unsigned char BlocksPerStripe; /* Byte 11 */ - struct { - enum { - DAC960_V1_Async = 0x0, - DAC960_V1_Sync_8MHz = 0x1, - DAC960_V1_Sync_5MHz = 0x2, - DAC960_V1_Sync_10or20MHz = 0x3 /* Byte 11 Bits 0-1 */ - } __attribute__ ((packed)) Speed:2; - bool Force8Bit:1; /* Byte 11 Bit 2 */ - bool DisableFast20:1; /* Byte 11 Bit 3 */ - unsigned char :3; /* Byte 11 Bits 4-6 */ - bool EnableTaggedQueuing:1; /* Byte 11 Bit 7 */ - } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */ - unsigned char SCSIInitiatorID; /* Byte 18 */ - unsigned char :8; /* Byte 19 */ - enum { - DAC960_V1_StartupMode_ControllerSpinUp = 0x00, - DAC960_V1_StartupMode_PowerOnSpinUp = 0x01 - } __attribute__ ((packed)) StartupMode; /* Byte 20 */ - unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */ - unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */ - unsigned char Reserved1[29]; /* Bytes 23-51 */ - bool BIOSDisabled:1; /* Byte 52 Bit 0 */ - bool CDROMBootEnabled:1; /* Byte 52 Bit 1 */ - unsigned char :3; /* Byte 52 Bits 2-4 */ - enum { - DAC960_V1_Geometry_128_32 = 0x0, - DAC960_V1_Geometry_255_63 = 0x1, - DAC960_V1_Geometry_Reserved1 = 0x2, - DAC960_V1_Geometry_Reserved2 = 0x3 - } __attribute__ ((packed)) DriveGeometry:2; /* Byte 52 Bits 5-6 */ - unsigned char :1; /* Byte 52 Bit 7 */ - unsigned char Reserved2[9]; /* Bytes 53-61 */ - unsigned short Checksum; /* Bytes 62-63 */ -} -DAC960_V1_Config2_T; - - -/* - Define the DAC960 V1 Firmware DCDB request structure. -*/ - -typedef struct DAC960_V1_DCDB -{ - unsigned char TargetID:4; /* Byte 0 Bits 0-3 */ - unsigned char Channel:4; /* Byte 0 Bits 4-7 */ - enum { - DAC960_V1_DCDB_NoDataTransfer = 0, - DAC960_V1_DCDB_DataTransferDeviceToSystem = 1, - DAC960_V1_DCDB_DataTransferSystemToDevice = 2, - DAC960_V1_DCDB_IllegalDataTransfer = 3 - } __attribute__ ((packed)) Direction:2; /* Byte 1 Bits 0-1 */ - bool EarlyStatus:1; /* Byte 1 Bit 2 */ - unsigned char :1; /* Byte 1 Bit 3 */ - enum { - DAC960_V1_DCDB_Timeout_24_hours = 0, - DAC960_V1_DCDB_Timeout_10_seconds = 1, - DAC960_V1_DCDB_Timeout_60_seconds = 2, - DAC960_V1_DCDB_Timeout_10_minutes = 3 - } __attribute__ ((packed)) Timeout:2; /* Byte 1 Bits 4-5 */ - bool NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */ - bool DisconnectPermitted:1; /* Byte 1 Bit 7 */ - unsigned short TransferLength; /* Bytes 2-3 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 4-7 */ - unsigned char CDBLength:4; /* Byte 8 Bits 0-3 */ - unsigned char TransferLengthHigh4:4; /* Byte 8 Bits 4-7 */ - unsigned char SenseLength; /* Byte 9 */ - unsigned char CDB[12]; /* Bytes 10-21 */ - unsigned char SenseData[64]; /* Bytes 22-85 */ - unsigned char Status; /* Byte 86 */ - unsigned char :8; /* Byte 87 */ -} -DAC960_V1_DCDB_T; - - -/* - Define the DAC960 V1 Firmware Scatter/Gather List Type 1 32 Bit Address - 32 Bit Byte Count structure. -*/ - -typedef struct DAC960_V1_ScatterGatherSegment -{ - DAC960_BusAddress32_T SegmentDataPointer; /* Bytes 0-3 */ - DAC960_ByteCount32_T SegmentByteCount; /* Bytes 4-7 */ -} -DAC960_V1_ScatterGatherSegment_T; - - -/* - Define the 13 Byte DAC960 V1 Firmware Command Mailbox structure. Bytes 13-15 - are not used. The Command Mailbox structure is padded to 16 bytes for - efficient access. -*/ - -typedef union DAC960_V1_CommandMailbox -{ - unsigned int Words[4]; /* Words 0-3 */ - unsigned char Bytes[16]; /* Bytes 0-15 */ - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned char Dummy[14]; /* Bytes 2-15 */ - } __attribute__ ((packed)) Common; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned char Dummy1[6]; /* Bytes 2-7 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */ - unsigned char Dummy2[4]; /* Bytes 12-15 */ - } __attribute__ ((packed)) Type3; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned char CommandOpcode2; /* Byte 2 */ - unsigned char Dummy1[5]; /* Bytes 3-7 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */ - unsigned char Dummy2[4]; /* Bytes 12-15 */ - } __attribute__ ((packed)) Type3B; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned char Dummy1[5]; /* Bytes 2-6 */ - unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */ - bool AutoRestore:1; /* Byte 7 Bit 7 */ - unsigned char Dummy2[8]; /* Bytes 8-15 */ - } __attribute__ ((packed)) Type3C; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned char Channel; /* Byte 2 */ - unsigned char TargetID; /* Byte 3 */ - DAC960_V1_PhysicalDeviceState_T DeviceState:5; /* Byte 4 Bits 0-4 */ - unsigned char Modifier:3; /* Byte 4 Bits 5-7 */ - unsigned char Dummy1[3]; /* Bytes 5-7 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */ - unsigned char Dummy2[4]; /* Bytes 12-15 */ - } __attribute__ ((packed)) Type3D; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - DAC960_V1_PerformEventLogOpType_T OperationType; /* Byte 2 */ - unsigned char OperationQualifier; /* Byte 3 */ - unsigned short SequenceNumber; /* Bytes 4-5 */ - unsigned char Dummy1[2]; /* Bytes 6-7 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */ - unsigned char Dummy2[4]; /* Bytes 12-15 */ - } __attribute__ ((packed)) Type3E; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned char Dummy1[2]; /* Bytes 2-3 */ - unsigned char RebuildRateConstant; /* Byte 4 */ - unsigned char Dummy2[3]; /* Bytes 5-7 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */ - unsigned char Dummy3[4]; /* Bytes 12-15 */ - } __attribute__ ((packed)) Type3R; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned short TransferLength; /* Bytes 2-3 */ - unsigned int LogicalBlockAddress; /* Bytes 4-7 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */ - unsigned char LogicalDriveNumber; /* Byte 12 */ - unsigned char Dummy[3]; /* Bytes 13-15 */ - } __attribute__ ((packed)) Type4; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - struct { - unsigned short TransferLength:11; /* Bytes 2-3 */ - unsigned char LogicalDriveNumber:5; /* Byte 3 Bits 3-7 */ - } __attribute__ ((packed)) LD; - unsigned int LogicalBlockAddress; /* Bytes 4-7 */ - DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */ - unsigned char ScatterGatherCount:6; /* Byte 12 Bits 0-5 */ - enum { - DAC960_V1_ScatterGather_32BitAddress_32BitByteCount = 0x0, - DAC960_V1_ScatterGather_32BitAddress_16BitByteCount = 0x1, - DAC960_V1_ScatterGather_32BitByteCount_32BitAddress = 0x2, - DAC960_V1_ScatterGather_16BitByteCount_32BitAddress = 0x3 - } __attribute__ ((packed)) ScatterGatherType:2; /* Byte 12 Bits 6-7 */ - unsigned char Dummy[3]; /* Bytes 13-15 */ - } __attribute__ ((packed)) Type5; - struct { - DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */ - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ - unsigned char CommandOpcode2; /* Byte 2 */ - unsigned char :8; /* Byte 3 */ - DAC960_BusAddress32_T CommandMailboxesBusAddress; /* Bytes 4-7 */ - DAC960_BusAddress32_T StatusMailboxesBusAddress; /* Bytes 8-11 */ - unsigned char Dummy[4]; /* Bytes 12-15 */ - } __attribute__ ((packed)) TypeX; -} -DAC960_V1_CommandMailbox_T; - - -/* - Define the DAC960 V2 Firmware Command Opcodes. -*/ - -typedef enum -{ - DAC960_V2_MemCopy = 0x01, - DAC960_V2_SCSI_10_Passthru = 0x02, - DAC960_V2_SCSI_255_Passthru = 0x03, - DAC960_V2_SCSI_10 = 0x04, - DAC960_V2_SCSI_256 = 0x05, - DAC960_V2_IOCTL = 0x20 -} -__attribute__ ((packed)) -DAC960_V2_CommandOpcode_T; - - -/* - Define the DAC960 V2 Firmware IOCTL Opcodes. -*/ - -typedef enum -{ - DAC960_V2_GetControllerInfo = 0x01, - DAC960_V2_GetLogicalDeviceInfoValid = 0x03, - DAC960_V2_GetPhysicalDeviceInfoValid = 0x05, - DAC960_V2_GetHealthStatus = 0x11, - DAC960_V2_GetEvent = 0x15, - DAC960_V2_StartDiscovery = 0x81, - DAC960_V2_SetDeviceState = 0x82, - DAC960_V2_RebuildDeviceStart = 0x88, - DAC960_V2_RebuildDeviceStop = 0x89, - DAC960_V2_ConsistencyCheckStart = 0x8C, - DAC960_V2_ConsistencyCheckStop = 0x8D, - DAC960_V2_SetMemoryMailbox = 0x8E, - DAC960_V2_PauseDevice = 0x92, - DAC960_V2_TranslatePhysicalToLogicalDevice = 0xC5 -} -__attribute__ ((packed)) -DAC960_V2_IOCTL_Opcode_T; - - -/* - Define the DAC960 V2 Firmware Command Identifier type. -*/ - -typedef unsigned short DAC960_V2_CommandIdentifier_T; - - -/* - Define the DAC960 V2 Firmware Command Status Codes. -*/ - -#define DAC960_V2_NormalCompletion 0x00 -#define DAC960_V2_AbormalCompletion 0x02 -#define DAC960_V2_DeviceBusy 0x08 -#define DAC960_V2_DeviceNonresponsive 0x0E -#define DAC960_V2_DeviceNonresponsive2 0x0F -#define DAC960_V2_DeviceRevervationConflict 0x18 - -typedef unsigned char DAC960_V2_CommandStatus_T; - - -/* - Define the DAC960 V2 Firmware Memory Type structure. -*/ - -typedef struct DAC960_V2_MemoryType -{ - enum { - DAC960_V2_MemoryType_Reserved = 0x00, - DAC960_V2_MemoryType_DRAM = 0x01, - DAC960_V2_MemoryType_EDRAM = 0x02, - DAC960_V2_MemoryType_EDO = 0x03, - DAC960_V2_MemoryType_SDRAM = 0x04, - DAC960_V2_MemoryType_Last = 0x1F - } __attribute__ ((packed)) MemoryType:5; /* Byte 0 Bits 0-4 */ - bool :1; /* Byte 0 Bit 5 */ - bool MemoryParity:1; /* Byte 0 Bit 6 */ - bool MemoryECC:1; /* Byte 0 Bit 7 */ -} -DAC960_V2_MemoryType_T; - - -/* - Define the DAC960 V2 Firmware Processor Type structure. -*/ - -typedef enum -{ - DAC960_V2_ProcessorType_i960CA = 0x01, - DAC960_V2_ProcessorType_i960RD = 0x02, - DAC960_V2_ProcessorType_i960RN = 0x03, - DAC960_V2_ProcessorType_i960RP = 0x04, - DAC960_V2_ProcessorType_NorthBay = 0x05, - DAC960_V2_ProcessorType_StrongArm = 0x06, - DAC960_V2_ProcessorType_i960RM = 0x07 -} -__attribute__ ((packed)) -DAC960_V2_ProcessorType_T; - - -/* - Define the DAC960 V2 Firmware Get Controller Info reply structure. -*/ - -typedef struct DAC960_V2_ControllerInfo -{ - unsigned char :8; /* Byte 0 */ - enum { - DAC960_V2_SCSI_Bus = 0x00, - DAC960_V2_Fibre_Bus = 0x01, - DAC960_V2_PCI_Bus = 0x03 - } __attribute__ ((packed)) BusInterfaceType; /* Byte 1 */ - enum { - DAC960_V2_DAC960E = 0x01, - DAC960_V2_DAC960M = 0x08, - DAC960_V2_DAC960PD = 0x10, - DAC960_V2_DAC960PL = 0x11, - DAC960_V2_DAC960PU = 0x12, - DAC960_V2_DAC960PE = 0x13, - DAC960_V2_DAC960PG = 0x14, - DAC960_V2_DAC960PJ = 0x15, - DAC960_V2_DAC960PTL0 = 0x16, - DAC960_V2_DAC960PR = 0x17, - DAC960_V2_DAC960PRL = 0x18, - DAC960_V2_DAC960PT = 0x19, - DAC960_V2_DAC1164P = 0x1A, - DAC960_V2_DAC960PTL1 = 0x1B, - DAC960_V2_EXR2000P = 0x1C, - DAC960_V2_EXR3000P = 0x1D, - DAC960_V2_AcceleRAID352 = 0x1E, - DAC960_V2_AcceleRAID170 = 0x1F, - DAC960_V2_AcceleRAID160 = 0x20, - DAC960_V2_DAC960S = 0x60, - DAC960_V2_DAC960SU = 0x61, - DAC960_V2_DAC960SX = 0x62, - DAC960_V2_DAC960SF = 0x63, - DAC960_V2_DAC960SS = 0x64, - DAC960_V2_DAC960FL = 0x65, - DAC960_V2_DAC960LL = 0x66, - DAC960_V2_DAC960FF = 0x67, - DAC960_V2_DAC960HP = 0x68, - DAC960_V2_RAIDBRICK = 0x69, - DAC960_V2_METEOR_FL = 0x6A, - DAC960_V2_METEOR_FF = 0x6B - } __attribute__ ((packed)) ControllerType; /* Byte 2 */ - unsigned char :8; /* Byte 3 */ - unsigned short BusInterfaceSpeedMHz; /* Bytes 4-5 */ - unsigned char BusWidthBits; /* Byte 6 */ - unsigned char FlashCodeTypeOrProductID; /* Byte 7 */ - unsigned char NumberOfHostPortsPresent; /* Byte 8 */ - unsigned char Reserved1[7]; /* Bytes 9-15 */ - unsigned char BusInterfaceName[16]; /* Bytes 16-31 */ - unsigned char ControllerName[16]; /* Bytes 32-47 */ - unsigned char Reserved2[16]; /* Bytes 48-63 */ - /* Firmware Release Information */ - unsigned char FirmwareMajorVersion; /* Byte 64 */ - unsigned char FirmwareMinorVersion; /* Byte 65 */ - unsigned char FirmwareTurnNumber; /* Byte 66 */ - unsigned char FirmwareBuildNumber; /* Byte 67 */ - unsigned char FirmwareReleaseDay; /* Byte 68 */ - unsigned char FirmwareReleaseMonth; /* Byte 69 */ - unsigned char FirmwareReleaseYearHigh2Digits; /* Byte 70 */ - unsigned char FirmwareReleaseYearLow2Digits; /* Byte 71 */ - /* Hardware Release Information */ - unsigned char HardwareRevision; /* Byte 72 */ - unsigned int :24; /* Bytes 73-75 */ - unsigned char HardwareReleaseDay; /* Byte 76 */ - unsigned char HardwareReleaseMonth; /* Byte 77 */ - unsigned char HardwareReleaseYearHigh2Digits; /* Byte 78 */ - unsigned char HardwareReleaseYearLow2Digits; /* Byte 79 */ - /* Hardware Manufacturing Information */ - unsigned char ManufacturingBatchNumber; /* Byte 80 */ - unsigned char :8; /* Byte 81 */ - unsigned char ManufacturingPlantNumber; /* Byte 82 */ - unsigned char :8; /* Byte 83 */ - unsigned char HardwareManufacturingDay; /* Byte 84 */ - unsigned char HardwareManufacturingMonth; /* Byte 85 */ - unsigned char HardwareManufacturingYearHigh2Digits; /* Byte 86 */ - unsigned char HardwareManufacturingYearLow2Digits; /* Byte 87 */ - unsigned char MaximumNumberOfPDDperXLD; /* Byte 88 */ - unsigned char MaximumNumberOfILDperXLD; /* Byte 89 */ - unsigned short NonvolatileMemorySizeKB; /* Bytes 90-91 */ - unsigned char MaximumNumberOfXLD; /* Byte 92 */ - unsigned int :24; /* Bytes 93-95 */ - /* Unique Information per Controller */ - unsigned char ControllerSerialNumber[16]; /* Bytes 96-111 */ - unsigned char Reserved3[16]; /* Bytes 112-127 */ - /* Vendor Information */ - unsigned int :24; /* Bytes 128-130 */ - unsigned char OEM_Code; /* Byte 131 */ - unsigned char VendorName[16]; /* Bytes 132-147 */ - /* Other Physical/Controller/Operation Information */ - bool BBU_Present:1; /* Byte 148 Bit 0 */ - bool ActiveActiveClusteringMode:1; /* Byte 148 Bit 1 */ - unsigned char :6; /* Byte 148 Bits 2-7 */ - unsigned char :8; /* Byte 149 */ - unsigned short :16; /* Bytes 150-151 */ - /* Physical Device Scan Information */ - bool PhysicalScanActive:1; /* Byte 152 Bit 0 */ - unsigned char :7; /* Byte 152 Bits 1-7 */ - unsigned char PhysicalDeviceChannelNumber; /* Byte 153 */ - unsigned char PhysicalDeviceTargetID; /* Byte 154 */ - unsigned char PhysicalDeviceLogicalUnit; /* Byte 155 */ - /* Maximum Command Data Transfer Sizes */ - unsigned short MaximumDataTransferSizeInBlocks; /* Bytes 156-157 */ - unsigned short MaximumScatterGatherEntries; /* Bytes 158-159 */ - /* Logical/Physical Device Counts */ - unsigned short LogicalDevicesPresent; /* Bytes 160-161 */ - unsigned short LogicalDevicesCritical; /* Bytes 162-163 */ - unsigned short LogicalDevicesOffline; /* Bytes 164-165 */ - unsigned short PhysicalDevicesPresent; /* Bytes 166-167 */ - unsigned short PhysicalDisksPresent; /* Bytes 168-169 */ - unsigned short PhysicalDisksCritical; /* Bytes 170-171 */ - unsigned short PhysicalDisksOffline; /* Bytes 172-173 */ - unsigned short MaximumParallelCommands; /* Bytes 174-175 */ - /* Channel and Target ID Information */ - unsigned char NumberOfPhysicalChannelsPresent; /* Byte 176 */ - unsigned char NumberOfVirtualChannelsPresent; /* Byte 177 */ - unsigned char NumberOfPhysicalChannelsPossible; /* Byte 178 */ - unsigned char NumberOfVirtualChannelsPossible; /* Byte 179 */ - unsigned char MaximumTargetsPerChannel[16]; /* Bytes 180-195 */ - unsigned char Reserved4[12]; /* Bytes 196-207 */ - /* Memory/Cache Information */ - unsigned short MemorySizeMB; /* Bytes 208-209 */ - unsigned short CacheSizeMB; /* Bytes 210-211 */ - unsigned int ValidCacheSizeInBytes; /* Bytes 212-215 */ - unsigned int DirtyCacheSizeInBytes; /* Bytes 216-219 */ - unsigned short MemorySpeedMHz; /* Bytes 220-221 */ - unsigned char MemoryDataWidthBits; /* Byte 222 */ - DAC960_V2_MemoryType_T MemoryType; /* Byte 223 */ - unsigned char CacheMemoryTypeName[16]; /* Bytes 224-239 */ - /* Execution Memory Information */ - unsigned short ExecutionMemorySizeMB; /* Bytes 240-241 */ - unsigned short ExecutionL2CacheSizeMB; /* Bytes 242-243 */ - unsigned char Reserved5[8]; /* Bytes 244-251 */ - unsigned short ExecutionMemorySpeedMHz; /* Bytes 252-253 */ - unsigned char ExecutionMemoryDataWidthBits; /* Byte 254 */ - DAC960_V2_MemoryType_T ExecutionMemoryType; /* Byte 255 */ - unsigned char ExecutionMemoryTypeName[16]; /* Bytes 256-271 */ - /* First CPU Type Information */ - unsigned short FirstProcessorSpeedMHz; /* Bytes 272-273 */ - DAC960_V2_ProcessorType_T FirstProcessorType; /* Byte 274 */ - unsigned char FirstProcessorCount; /* Byte 275 */ - unsigned char Reserved6[12]; /* Bytes 276-287 */ - unsigned char FirstProcessorName[16]; /* Bytes 288-303 */ - /* Second CPU Type Information */ - unsigned short SecondProcessorSpeedMHz; /* Bytes 304-305 */ - DAC960_V2_ProcessorType_T SecondProcessorType; /* Byte 306 */ - unsigned char SecondProcessorCount; /* Byte 307 */ - unsigned char Reserved7[12]; /* Bytes 308-319 */ - unsigned char SecondProcessorName[16]; /* Bytes 320-335 */ - /* Debugging/Profiling/Command Time Tracing Information */ - unsigned short CurrentProfilingDataPageNumber; /* Bytes 336-337 */ - unsigned short ProgramsAwaitingProfilingData; /* Bytes 338-339 */ - unsigned short CurrentCommandTimeTraceDataPageNumber; /* Bytes 340-341 */ - unsigned short ProgramsAwaitingCommandTimeTraceData; /* Bytes 342-343 */ - unsigned char Reserved8[8]; /* Bytes 344-351 */ - /* Error Counters on Physical Devices */ - unsigned short PhysicalDeviceBusResets; /* Bytes 352-353 */ - unsigned short PhysicalDeviceParityErrors; /* Bytes 355-355 */ - unsigned short PhysicalDeviceSoftErrors; /* Bytes 356-357 */ - unsigned short PhysicalDeviceCommandsFailed; /* Bytes 358-359 */ - unsigned short PhysicalDeviceMiscellaneousErrors; /* Bytes 360-361 */ - unsigned short PhysicalDeviceCommandTimeouts; /* Bytes 362-363 */ - unsigned short PhysicalDeviceSelectionTimeouts; /* Bytes 364-365 */ - unsigned short PhysicalDeviceRetriesDone; /* Bytes 366-367 */ - unsigned short PhysicalDeviceAbortsDone; /* Bytes 368-369 */ - unsigned short PhysicalDeviceHostCommandAbortsDone; /* Bytes 370-371 */ - unsigned short PhysicalDevicePredictedFailuresDetected; /* Bytes 372-373 */ - unsigned short PhysicalDeviceHostCommandsFailed; /* Bytes 374-375 */ - unsigned short PhysicalDeviceHardErrors; /* Bytes 376-377 */ - unsigned char Reserved9[6]; /* Bytes 378-383 */ - /* Error Counters on Logical Devices */ - unsigned short LogicalDeviceSoftErrors; /* Bytes 384-385 */ - unsigned short LogicalDeviceCommandsFailed; /* Bytes 386-387 */ - unsigned short LogicalDeviceHostCommandAbortsDone; /* Bytes 388-389 */ - unsigned short :16; /* Bytes 390-391 */ - /* Error Counters on Controller */ - unsigned short ControllerMemoryErrors; /* Bytes 392-393 */ - unsigned short ControllerHostCommandAbortsDone; /* Bytes 394-395 */ - unsigned int :32; /* Bytes 396-399 */ - /* Long Duration Activity Information */ - unsigned short BackgroundInitializationsActive; /* Bytes 400-401 */ - unsigned short LogicalDeviceInitializationsActive; /* Bytes 402-403 */ - unsigned short PhysicalDeviceInitializationsActive; /* Bytes 404-405 */ - unsigned short ConsistencyChecksActive; /* Bytes 406-407 */ - unsigned short RebuildsActive; /* Bytes 408-409 */ - unsigned short OnlineExpansionsActive; /* Bytes 410-411 */ - unsigned short PatrolActivitiesActive; /* Bytes 412-413 */ - unsigned short :16; /* Bytes 414-415 */ - /* Flash ROM Information */ - unsigned char FlashType; /* Byte 416 */ - unsigned char :8; /* Byte 417 */ - unsigned short FlashSizeMB; /* Bytes 418-419 */ - unsigned int FlashLimit; /* Bytes 420-423 */ - unsigned int FlashCount; /* Bytes 424-427 */ - unsigned int :32; /* Bytes 428-431 */ - unsigned char FlashTypeName[16]; /* Bytes 432-447 */ - /* Firmware Run Time Information */ - unsigned char RebuildRate; /* Byte 448 */ - unsigned char BackgroundInitializationRate; /* Byte 449 */ - unsigned char ForegroundInitializationRate; /* Byte 450 */ - unsigned char ConsistencyCheckRate; /* Byte 451 */ - unsigned int :32; /* Bytes 452-455 */ - unsigned int MaximumDP; /* Bytes 456-459 */ - unsigned int FreeDP; /* Bytes 460-463 */ - unsigned int MaximumIOP; /* Bytes 464-467 */ - unsigned int FreeIOP; /* Bytes 468-471 */ - unsigned short MaximumCombLengthInBlocks; /* Bytes 472-473 */ - unsigned short NumberOfConfigurationGroups; /* Bytes 474-475 */ - bool InstallationAbortStatus:1; /* Byte 476 Bit 0 */ - bool MaintenanceModeStatus:1; /* Byte 476 Bit 1 */ - unsigned int :24; /* Bytes 476-479 */ - unsigned char Reserved10[32]; /* Bytes 480-511 */ - unsigned char Reserved11[512]; /* Bytes 512-1023 */ -} -DAC960_V2_ControllerInfo_T; - - -/* - Define the DAC960 V2 Firmware Logical Device State type. -*/ - -typedef enum -{ - DAC960_V2_LogicalDevice_Online = 0x01, - DAC960_V2_LogicalDevice_Offline = 0x08, - DAC960_V2_LogicalDevice_Critical = 0x09 -} -__attribute__ ((packed)) -DAC960_V2_LogicalDeviceState_T; - - -/* - Define the DAC960 V2 Firmware Get Logical Device Info reply structure. -*/ - -typedef struct DAC960_V2_LogicalDeviceInfo -{ - unsigned char :8; /* Byte 0 */ - unsigned char Channel; /* Byte 1 */ - unsigned char TargetID; /* Byte 2 */ - unsigned char LogicalUnit; /* Byte 3 */ - DAC960_V2_LogicalDeviceState_T LogicalDeviceState; /* Byte 4 */ - unsigned char RAIDLevel; /* Byte 5 */ - unsigned char StripeSize; /* Byte 6 */ - unsigned char CacheLineSize; /* Byte 7 */ - struct { - enum { - DAC960_V2_ReadCacheDisabled = 0x0, - DAC960_V2_ReadCacheEnabled = 0x1, - DAC960_V2_ReadAheadEnabled = 0x2, - DAC960_V2_IntelligentReadAheadEnabled = 0x3, - DAC960_V2_ReadCache_Last = 0x7 - } __attribute__ ((packed)) ReadCache:3; /* Byte 8 Bits 0-2 */ - enum { - DAC960_V2_WriteCacheDisabled = 0x0, - DAC960_V2_LogicalDeviceReadOnly = 0x1, - DAC960_V2_WriteCacheEnabled = 0x2, - DAC960_V2_IntelligentWriteCacheEnabled = 0x3, - DAC960_V2_WriteCache_Last = 0x7 - } __attribute__ ((packed)) WriteCache:3; /* Byte 8 Bits 3-5 */ - bool :1; /* Byte 8 Bit 6 */ - bool LogicalDeviceInitialized:1; /* Byte 8 Bit 7 */ - } LogicalDeviceControl; /* Byte 8 */ - /* Logical Device Operations Status */ - bool ConsistencyCheckInProgress:1; /* Byte 9 Bit 0 */ - bool RebuildInProgress:1; /* Byte 9 Bit 1 */ - bool BackgroundInitializationInProgress:1; /* Byte 9 Bit 2 */ - bool ForegroundInitializationInProgress:1; /* Byte 9 Bit 3 */ - bool DataMigrationInProgress:1; /* Byte 9 Bit 4 */ - bool PatrolOperationInProgress:1; /* Byte 9 Bit 5 */ - unsigned char :2; /* Byte 9 Bits 6-7 */ - unsigned char RAID5WriteUpdate; /* Byte 10 */ - unsigned char RAID5Algorithm; /* Byte 11 */ - unsigned short LogicalDeviceNumber; /* Bytes 12-13 */ - /* BIOS Info */ - bool BIOSDisabled:1; /* Byte 14 Bit 0 */ - bool CDROMBootEnabled:1; /* Byte 14 Bit 1 */ - bool DriveCoercionEnabled:1; /* Byte 14 Bit 2 */ - bool WriteSameDisabled:1; /* Byte 14 Bit 3 */ - bool HBA_ModeEnabled:1; /* Byte 14 Bit 4 */ - enum { - DAC960_V2_Geometry_128_32 = 0x0, - DAC960_V2_Geometry_255_63 = 0x1, - DAC960_V2_Geometry_Reserved1 = 0x2, - DAC960_V2_Geometry_Reserved2 = 0x3 - } __attribute__ ((packed)) DriveGeometry:2; /* Byte 14 Bits 5-6 */ - bool SuperReadAheadEnabled:1; /* Byte 14 Bit 7 */ - unsigned char :8; /* Byte 15 */ - /* Error Counters */ - unsigned short SoftErrors; /* Bytes 16-17 */ - unsigned short CommandsFailed; /* Bytes 18-19 */ - unsigned short HostCommandAbortsDone; /* Bytes 20-21 */ - unsigned short DeferredWriteErrors; /* Bytes 22-23 */ - unsigned int :32; /* Bytes 24-27 */ - unsigned int :32; /* Bytes 28-31 */ - /* Device Size Information */ - unsigned short :16; /* Bytes 32-33 */ - unsigned short DeviceBlockSizeInBytes; /* Bytes 34-35 */ - unsigned int OriginalDeviceSize; /* Bytes 36-39 */ - unsigned int ConfigurableDeviceSize; /* Bytes 40-43 */ - unsigned int :32; /* Bytes 44-47 */ - unsigned char LogicalDeviceName[32]; /* Bytes 48-79 */ - unsigned char SCSI_InquiryData[36]; /* Bytes 80-115 */ - unsigned char Reserved1[12]; /* Bytes 116-127 */ - DAC960_ByteCount64_T LastReadBlockNumber; /* Bytes 128-135 */ - DAC960_ByteCount64_T LastWrittenBlockNumber; /* Bytes 136-143 */ - DAC960_ByteCount64_T ConsistencyCheckBlockNumber; /* Bytes 144-151 */ - DAC960_ByteCount64_T RebuildBlockNumber; /* Bytes 152-159 */ - DAC960_ByteCount64_T BackgroundInitializationBlockNumber; /* Bytes 160-167 */ - DAC960_ByteCount64_T ForegroundInitializationBlockNumber; /* Bytes 168-175 */ - DAC960_ByteCount64_T DataMigrationBlockNumber; /* Bytes 176-183 */ - DAC960_ByteCount64_T PatrolOperationBlockNumber; /* Bytes 184-191 */ - unsigned char Reserved2[64]; /* Bytes 192-255 */ -} -DAC960_V2_LogicalDeviceInfo_T; - - -/* - Define the DAC960 V2 Firmware Physical Device State type. -*/ - -typedef enum -{ - DAC960_V2_Device_Unconfigured = 0x00, - DAC960_V2_Device_Online = 0x01, - DAC960_V2_Device_Rebuild = 0x03, - DAC960_V2_Device_Missing = 0x04, - DAC960_V2_Device_Critical = 0x05, - DAC960_V2_Device_Dead = 0x08, - DAC960_V2_Device_SuspectedDead = 0x0C, - DAC960_V2_Device_CommandedOffline = 0x10, - DAC960_V2_Device_Standby = 0x21, - DAC960_V2_Device_InvalidState = 0xFF -} -__attribute__ ((packed)) -DAC960_V2_PhysicalDeviceState_T; - - -/* - Define the DAC960 V2 Firmware Get Physical Device Info reply structure. -*/ - -typedef struct DAC960_V2_PhysicalDeviceInfo -{ - unsigned char :8; /* Byte 0 */ - unsigned char Channel; /* Byte 1 */ - unsigned char TargetID; /* Byte 2 */ - unsigned char LogicalUnit; /* Byte 3 */ - /* Configuration Status Bits */ - bool PhysicalDeviceFaultTolerant:1; /* Byte 4 Bit 0 */ - bool PhysicalDeviceConnected:1; /* Byte 4 Bit 1 */ - bool PhysicalDeviceLocalToController:1; /* Byte 4 Bit 2 */ - unsigned char :5; /* Byte 4 Bits 3-7 */ - /* Multiple Host/Controller Status Bits */ - bool RemoteHostSystemDead:1; /* Byte 5 Bit 0 */ - bool RemoteControllerDead:1; /* Byte 5 Bit 1 */ - unsigned char :6; /* Byte 5 Bits 2-7 */ - DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState; /* Byte 6 */ - unsigned char NegotiatedDataWidthBits; /* Byte 7 */ - unsigned short NegotiatedSynchronousMegaTransfers; /* Bytes 8-9 */ - /* Multiported Physical Device Information */ - unsigned char NumberOfPortConnections; /* Byte 10 */ - unsigned char DriveAccessibilityBitmap; /* Byte 11 */ - unsigned int :32; /* Bytes 12-15 */ - unsigned char NetworkAddress[16]; /* Bytes 16-31 */ - unsigned short MaximumTags; /* Bytes 32-33 */ - /* Physical Device Operations Status */ - bool ConsistencyCheckInProgress:1; /* Byte 34 Bit 0 */ - bool RebuildInProgress:1; /* Byte 34 Bit 1 */ - bool MakingDataConsistentInProgress:1; /* Byte 34 Bit 2 */ - bool PhysicalDeviceInitializationInProgress:1; /* Byte 34 Bit 3 */ - bool DataMigrationInProgress:1; /* Byte 34 Bit 4 */ - bool PatrolOperationInProgress:1; /* Byte 34 Bit 5 */ - unsigned char :2; /* Byte 34 Bits 6-7 */ - unsigned char LongOperationStatus; /* Byte 35 */ - unsigned char ParityErrors; /* Byte 36 */ - unsigned char SoftErrors; /* Byte 37 */ - unsigned char HardErrors; /* Byte 38 */ - unsigned char MiscellaneousErrors; /* Byte 39 */ - unsigned char CommandTimeouts; /* Byte 40 */ - unsigned char Retries; /* Byte 41 */ - unsigned char Aborts; /* Byte 42 */ - unsigned char PredictedFailuresDetected; /* Byte 43 */ - unsigned int :32; /* Bytes 44-47 */ - unsigned short :16; /* Bytes 48-49 */ - unsigned short DeviceBlockSizeInBytes; /* Bytes 50-51 */ - unsigned int OriginalDeviceSize; /* Bytes 52-55 */ - unsigned int ConfigurableDeviceSize; /* Bytes 56-59 */ - unsigned int :32; /* Bytes 60-63 */ - unsigned char PhysicalDeviceName[16]; /* Bytes 64-79 */ - unsigned char Reserved1[16]; /* Bytes 80-95 */ - unsigned char Reserved2[32]; /* Bytes 96-127 */ - unsigned char SCSI_InquiryData[36]; /* Bytes 128-163 */ - unsigned char Reserved3[20]; /* Bytes 164-183 */ - unsigned char Reserved4[8]; /* Bytes 184-191 */ - DAC960_ByteCount64_T LastReadBlockNumber; /* Bytes 192-199 */ - DAC960_ByteCount64_T LastWrittenBlockNumber; /* Bytes 200-207 */ - DAC960_ByteCount64_T ConsistencyCheckBlockNumber; /* Bytes 208-215 */ - DAC960_ByteCount64_T RebuildBlockNumber; /* Bytes 216-223 */ - DAC960_ByteCount64_T MakingDataConsistentBlockNumber; /* Bytes 224-231 */ - DAC960_ByteCount64_T DeviceInitializationBlockNumber; /* Bytes 232-239 */ - DAC960_ByteCount64_T DataMigrationBlockNumber; /* Bytes 240-247 */ - DAC960_ByteCount64_T PatrolOperationBlockNumber; /* Bytes 248-255 */ - unsigned char Reserved5[256]; /* Bytes 256-511 */ -} -DAC960_V2_PhysicalDeviceInfo_T; - - -/* - Define the DAC960 V2 Firmware Health Status Buffer structure. -*/ - -typedef struct DAC960_V2_HealthStatusBuffer -{ - unsigned int MicrosecondsFromControllerStartTime; /* Bytes 0-3 */ - unsigned int MillisecondsFromControllerStartTime; /* Bytes 4-7 */ - unsigned int SecondsFrom1January1970; /* Bytes 8-11 */ - unsigned int :32; /* Bytes 12-15 */ - unsigned int StatusChangeCounter; /* Bytes 16-19 */ - unsigned int :32; /* Bytes 20-23 */ - unsigned int DebugOutputMessageBufferIndex; /* Bytes 24-27 */ - unsigned int CodedMessageBufferIndex; /* Bytes 28-31 */ - unsigned int CurrentTimeTracePageNumber; /* Bytes 32-35 */ - unsigned int CurrentProfilerPageNumber; /* Bytes 36-39 */ - unsigned int NextEventSequenceNumber; /* Bytes 40-43 */ - unsigned int :32; /* Bytes 44-47 */ - unsigned char Reserved1[16]; /* Bytes 48-63 */ - unsigned char Reserved2[64]; /* Bytes 64-127 */ -} -DAC960_V2_HealthStatusBuffer_T; - - -/* - Define the DAC960 V2 Firmware Get Event reply structure. -*/ - -typedef struct DAC960_V2_Event -{ - unsigned int EventSequenceNumber; /* Bytes 0-3 */ - unsigned int EventTime; /* Bytes 4-7 */ - unsigned int EventCode; /* Bytes 8-11 */ - unsigned char :8; /* Byte 12 */ - unsigned char Channel; /* Byte 13 */ - unsigned char TargetID; /* Byte 14 */ - unsigned char LogicalUnit; /* Byte 15 */ - unsigned int :32; /* Bytes 16-19 */ - unsigned int EventSpecificParameter; /* Bytes 20-23 */ - unsigned char RequestSenseData[40]; /* Bytes 24-63 */ -} -DAC960_V2_Event_T; - - -/* - Define the DAC960 V2 Firmware Command Control Bits structure. -*/ - -typedef struct DAC960_V2_CommandControlBits -{ - bool ForceUnitAccess:1; /* Byte 0 Bit 0 */ - bool DisablePageOut:1; /* Byte 0 Bit 1 */ - bool :1; /* Byte 0 Bit 2 */ - bool AdditionalScatterGatherListMemory:1; /* Byte 0 Bit 3 */ - bool DataTransferControllerToHost:1; /* Byte 0 Bit 4 */ - bool :1; /* Byte 0 Bit 5 */ - bool NoAutoRequestSense:1; /* Byte 0 Bit 6 */ - bool DisconnectProhibited:1; /* Byte 0 Bit 7 */ -} -DAC960_V2_CommandControlBits_T; - - -/* - Define the DAC960 V2 Firmware Command Timeout structure. -*/ - -typedef struct DAC960_V2_CommandTimeout -{ - unsigned char TimeoutValue:6; /* Byte 0 Bits 0-5 */ - enum { - DAC960_V2_TimeoutScale_Seconds = 0, - DAC960_V2_TimeoutScale_Minutes = 1, - DAC960_V2_TimeoutScale_Hours = 2, - DAC960_V2_TimeoutScale_Reserved = 3 - } __attribute__ ((packed)) TimeoutScale:2; /* Byte 0 Bits 6-7 */ -} -DAC960_V2_CommandTimeout_T; - - -/* - Define the DAC960 V2 Firmware Physical Device structure. -*/ - -typedef struct DAC960_V2_PhysicalDevice -{ - unsigned char LogicalUnit; /* Byte 0 */ - unsigned char TargetID; /* Byte 1 */ - unsigned char Channel:3; /* Byte 2 Bits 0-2 */ - unsigned char Controller:5; /* Byte 2 Bits 3-7 */ -} -__attribute__ ((packed)) -DAC960_V2_PhysicalDevice_T; - - -/* - Define the DAC960 V2 Firmware Logical Device structure. -*/ - -typedef struct DAC960_V2_LogicalDevice -{ - unsigned short LogicalDeviceNumber; /* Bytes 0-1 */ - unsigned char :3; /* Byte 2 Bits 0-2 */ - unsigned char Controller:5; /* Byte 2 Bits 3-7 */ -} -__attribute__ ((packed)) -DAC960_V2_LogicalDevice_T; - - -/* - Define the DAC960 V2 Firmware Operation Device type. -*/ - -typedef enum -{ - DAC960_V2_Physical_Device = 0x00, - DAC960_V2_RAID_Device = 0x01, - DAC960_V2_Physical_Channel = 0x02, - DAC960_V2_RAID_Channel = 0x03, - DAC960_V2_Physical_Controller = 0x04, - DAC960_V2_RAID_Controller = 0x05, - DAC960_V2_Configuration_Group = 0x10, - DAC960_V2_Enclosure = 0x11 -} -__attribute__ ((packed)) -DAC960_V2_OperationDevice_T; - - -/* - Define the DAC960 V2 Firmware Translate Physical To Logical Device structure. -*/ - -typedef struct DAC960_V2_PhysicalToLogicalDevice -{ - unsigned short LogicalDeviceNumber; /* Bytes 0-1 */ - unsigned short :16; /* Bytes 2-3 */ - unsigned char PreviousBootController; /* Byte 4 */ - unsigned char PreviousBootChannel; /* Byte 5 */ - unsigned char PreviousBootTargetID; /* Byte 6 */ - unsigned char PreviousBootLogicalUnit; /* Byte 7 */ -} -DAC960_V2_PhysicalToLogicalDevice_T; - - - -/* - Define the DAC960 V2 Firmware Scatter/Gather List Entry structure. -*/ - -typedef struct DAC960_V2_ScatterGatherSegment -{ - DAC960_BusAddress64_T SegmentDataPointer; /* Bytes 0-7 */ - DAC960_ByteCount64_T SegmentByteCount; /* Bytes 8-15 */ -} -DAC960_V2_ScatterGatherSegment_T; - - -/* - Define the DAC960 V2 Firmware Data Transfer Memory Address structure. -*/ - -typedef union DAC960_V2_DataTransferMemoryAddress -{ - DAC960_V2_ScatterGatherSegment_T ScatterGatherSegments[2]; /* Bytes 0-31 */ - struct { - unsigned short ScatterGatherList0Length; /* Bytes 0-1 */ - unsigned short ScatterGatherList1Length; /* Bytes 2-3 */ - unsigned short ScatterGatherList2Length; /* Bytes 4-5 */ - unsigned short :16; /* Bytes 6-7 */ - DAC960_BusAddress64_T ScatterGatherList0Address; /* Bytes 8-15 */ - DAC960_BusAddress64_T ScatterGatherList1Address; /* Bytes 16-23 */ - DAC960_BusAddress64_T ScatterGatherList2Address; /* Bytes 24-31 */ - } ExtendedScatterGather; -} -DAC960_V2_DataTransferMemoryAddress_T; - - -/* - Define the 64 Byte DAC960 V2 Firmware Command Mailbox structure. -*/ - -typedef union DAC960_V2_CommandMailbox -{ - unsigned int Words[16]; /* Words 0-15 */ - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - unsigned int :24; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - unsigned char Reserved[10]; /* Bytes 22-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } Common; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize; /* Bytes 4-7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char CDBLength; /* Byte 21 */ - unsigned char SCSI_CDB[10]; /* Bytes 22-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } SCSI_10; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize; /* Bytes 4-7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char CDBLength; /* Byte 21 */ - unsigned short :16; /* Bytes 22-23 */ - DAC960_BusAddress64_T SCSI_CDB_BusAddress; /* Bytes 24-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } SCSI_255; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - unsigned short :16; /* Bytes 16-17 */ - unsigned char ControllerNumber; /* Byte 18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - unsigned char Reserved[10]; /* Bytes 22-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } ControllerInfo; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - DAC960_V2_LogicalDevice_T LogicalDevice; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - unsigned char Reserved[10]; /* Bytes 22-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } LogicalDeviceInfo; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - unsigned char Reserved[10]; /* Bytes 22-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } PhysicalDeviceInfo; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - unsigned short EventSequenceNumberHigh16; /* Bytes 16-17 */ - unsigned char ControllerNumber; /* Byte 18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - unsigned short EventSequenceNumberLow16; /* Bytes 22-23 */ - unsigned char Reserved[8]; /* Bytes 24-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } GetEvent; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - DAC960_V2_LogicalDevice_T LogicalDevice; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - union { - DAC960_V2_LogicalDeviceState_T LogicalDeviceState; - DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState; - } DeviceState; /* Byte 22 */ - unsigned char Reserved[9]; /* Bytes 23-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } SetDeviceState; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - DAC960_V2_LogicalDevice_T LogicalDevice; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - bool RestoreConsistency:1; /* Byte 22 Bit 0 */ - bool InitializedAreaOnly:1; /* Byte 22 Bit 1 */ - unsigned char :6; /* Byte 22 Bits 2-7 */ - unsigned char Reserved[9]; /* Bytes 23-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } ConsistencyCheck; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - unsigned char FirstCommandMailboxSizeKB; /* Byte 4 */ - unsigned char FirstStatusMailboxSizeKB; /* Byte 5 */ - unsigned char SecondCommandMailboxSizeKB; /* Byte 6 */ - unsigned char SecondStatusMailboxSizeKB; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - unsigned int :24; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - unsigned char HealthStatusBufferSizeKB; /* Byte 22 */ - unsigned char :8; /* Byte 23 */ - DAC960_BusAddress64_T HealthStatusBufferBusAddress; /* Bytes 24-31 */ - DAC960_BusAddress64_T FirstCommandMailboxBusAddress; /* Bytes 32-39 */ - DAC960_BusAddress64_T FirstStatusMailboxBusAddress; /* Bytes 40-47 */ - DAC960_BusAddress64_T SecondCommandMailboxBusAddress; /* Bytes 48-55 */ - DAC960_BusAddress64_T SecondStatusMailboxBusAddress; /* Bytes 56-63 */ - } SetMemoryMailbox; - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */ - DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */ - DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */ - unsigned char DataTransferPageNumber; /* Byte 7 */ - DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */ - DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */ - DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */ - unsigned char RequestSenseSize; /* Byte 20 */ - unsigned char IOCTL_Opcode; /* Byte 21 */ - DAC960_V2_OperationDevice_T OperationDevice; /* Byte 22 */ - unsigned char Reserved[9]; /* Bytes 23-31 */ - DAC960_V2_DataTransferMemoryAddress_T - DataTransferMemoryAddress; /* Bytes 32-63 */ - } DeviceOperation; -} -DAC960_V2_CommandMailbox_T; - - -/* - Define the DAC960 Driver IOCTL requests. -*/ - -#define DAC960_IOCTL_GET_CONTROLLER_COUNT 0xDAC001 -#define DAC960_IOCTL_GET_CONTROLLER_INFO 0xDAC002 -#define DAC960_IOCTL_V1_EXECUTE_COMMAND 0xDAC003 -#define DAC960_IOCTL_V2_EXECUTE_COMMAND 0xDAC004 -#define DAC960_IOCTL_V2_GET_HEALTH_STATUS 0xDAC005 - - -/* - Define the DAC960_IOCTL_GET_CONTROLLER_INFO reply structure. -*/ - -typedef struct DAC960_ControllerInfo -{ - unsigned char ControllerNumber; - unsigned char FirmwareType; - unsigned char Channels; - unsigned char Targets; - unsigned char PCI_Bus; - unsigned char PCI_Device; - unsigned char PCI_Function; - unsigned char IRQ_Channel; - DAC960_PCI_Address_T PCI_Address; - unsigned char ModelName[20]; - unsigned char FirmwareVersion[12]; -} -DAC960_ControllerInfo_T; - - -/* - Define the User Mode DAC960_IOCTL_V1_EXECUTE_COMMAND request structure. -*/ - -typedef struct DAC960_V1_UserCommand -{ - unsigned char ControllerNumber; - DAC960_V1_CommandMailbox_T CommandMailbox; - int DataTransferLength; - void __user *DataTransferBuffer; - DAC960_V1_DCDB_T __user *DCDB; -} -DAC960_V1_UserCommand_T; - - -/* - Define the Kernel Mode DAC960_IOCTL_V1_EXECUTE_COMMAND request structure. -*/ - -typedef struct DAC960_V1_KernelCommand -{ - unsigned char ControllerNumber; - DAC960_V1_CommandMailbox_T CommandMailbox; - int DataTransferLength; - void *DataTransferBuffer; - DAC960_V1_DCDB_T *DCDB; - DAC960_V1_CommandStatus_T CommandStatus; - void (*CompletionFunction)(struct DAC960_V1_KernelCommand *); - void *CompletionData; -} -DAC960_V1_KernelCommand_T; - - -/* - Define the User Mode DAC960_IOCTL_V2_EXECUTE_COMMAND request structure. -*/ - -typedef struct DAC960_V2_UserCommand -{ - unsigned char ControllerNumber; - DAC960_V2_CommandMailbox_T CommandMailbox; - int DataTransferLength; - int RequestSenseLength; - void __user *DataTransferBuffer; - void __user *RequestSenseBuffer; -} -DAC960_V2_UserCommand_T; - - -/* - Define the Kernel Mode DAC960_IOCTL_V2_EXECUTE_COMMAND request structure. -*/ - -typedef struct DAC960_V2_KernelCommand -{ - unsigned char ControllerNumber; - DAC960_V2_CommandMailbox_T CommandMailbox; - int DataTransferLength; - int RequestSenseLength; - void *DataTransferBuffer; - void *RequestSenseBuffer; - DAC960_V2_CommandStatus_T CommandStatus; - void (*CompletionFunction)(struct DAC960_V2_KernelCommand *); - void *CompletionData; -} -DAC960_V2_KernelCommand_T; - - -/* - Define the User Mode DAC960_IOCTL_V2_GET_HEALTH_STATUS request structure. -*/ - -typedef struct DAC960_V2_GetHealthStatus -{ - unsigned char ControllerNumber; - DAC960_V2_HealthStatusBuffer_T __user *HealthStatusBuffer; -} -DAC960_V2_GetHealthStatus_T; - - -/* - Import the Kernel Mode IOCTL interface. -*/ - -extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument); - - -/* - DAC960_DriverVersion protects the private portion of this file. -*/ - -#ifdef DAC960_DriverVersion - - -/* - Define the maximum Driver Queue Depth and Controller Queue Depth supported - by DAC960 V1 and V2 Firmware Controllers. -*/ - -#define DAC960_MaxDriverQueueDepth 511 -#define DAC960_MaxControllerQueueDepth 512 - - -/* - Define the maximum number of Scatter/Gather Segments supported for any - DAC960 V1 and V2 Firmware controller. -*/ - -#define DAC960_V1_ScatterGatherLimit 33 -#define DAC960_V2_ScatterGatherLimit 128 - - -/* - Define the number of Command Mailboxes and Status Mailboxes used by the - DAC960 V1 and V2 Firmware Memory Mailbox Interface. -*/ - -#define DAC960_V1_CommandMailboxCount 256 -#define DAC960_V1_StatusMailboxCount 1024 -#define DAC960_V2_CommandMailboxCount 512 -#define DAC960_V2_StatusMailboxCount 512 - - -/* - Define the DAC960 Controller Monitoring Timer Interval. -*/ - -#define DAC960_MonitoringTimerInterval (10 * HZ) - - -/* - Define the DAC960 Controller Secondary Monitoring Interval. -*/ - -#define DAC960_SecondaryMonitoringInterval (60 * HZ) - - -/* - Define the DAC960 Controller Health Status Monitoring Interval. -*/ - -#define DAC960_HealthStatusMonitoringInterval (1 * HZ) - - -/* - Define the DAC960 Controller Progress Reporting Interval. -*/ - -#define DAC960_ProgressReportingInterval (60 * HZ) - - -/* - Define the maximum number of Partitions allowed for each Logical Drive. -*/ - -#define DAC960_MaxPartitions 8 -#define DAC960_MaxPartitionsBits 3 - -/* - Define the DAC960 Controller fixed Block Size and Block Size Bits. -*/ - -#define DAC960_BlockSize 512 -#define DAC960_BlockSizeBits 9 - - -/* - Define the number of Command structures that should be allocated as a - group to optimize kernel memory allocation. -*/ - -#define DAC960_V1_CommandAllocationGroupSize 11 -#define DAC960_V2_CommandAllocationGroupSize 29 - - -/* - Define the Controller Line Buffer, Progress Buffer, User Message, and - Initial Status Buffer sizes. -*/ - -#define DAC960_LineBufferSize 100 -#define DAC960_ProgressBufferSize 200 -#define DAC960_UserMessageSize 200 -#define DAC960_InitialStatusBufferSize (8192-32) - - -/* - Define the DAC960 Controller Firmware Types. -*/ - -typedef enum -{ - DAC960_V1_Controller = 1, - DAC960_V2_Controller = 2 -} -DAC960_FirmwareType_T; - - -/* - Define the DAC960 Controller Hardware Types. -*/ - -typedef enum -{ - DAC960_BA_Controller = 1, /* eXtremeRAID 2000 */ - DAC960_LP_Controller = 2, /* AcceleRAID 352 */ - DAC960_LA_Controller = 3, /* DAC1164P */ - DAC960_PG_Controller = 4, /* DAC960PTL/PJ/PG */ - DAC960_PD_Controller = 5, /* DAC960PU/PD/PL/P */ - DAC960_P_Controller = 6, /* DAC960PU/PD/PL/P */ - DAC960_GEM_Controller = 7, /* AcceleRAID 4/5/600 */ -} -DAC960_HardwareType_T; - - -/* - Define the Driver Message Levels. -*/ - -typedef enum DAC960_MessageLevel -{ - DAC960_AnnounceLevel = 0, - DAC960_InfoLevel = 1, - DAC960_NoticeLevel = 2, - DAC960_WarningLevel = 3, - DAC960_ErrorLevel = 4, - DAC960_ProgressLevel = 5, - DAC960_CriticalLevel = 6, - DAC960_UserCriticalLevel = 7 -} -DAC960_MessageLevel_T; - -static char - *DAC960_MessageLevelMap[] = - { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, - KERN_ERR, KERN_CRIT, KERN_CRIT, KERN_CRIT }; - - -/* - Define Driver Message macros. -*/ - -#define DAC960_Announce(Format, Arguments...) \ - DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments) - -#define DAC960_Info(Format, Arguments...) \ - DAC960_Message(DAC960_InfoLevel, Format, ##Arguments) - -#define DAC960_Notice(Format, Arguments...) \ - DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments) - -#define DAC960_Warning(Format, Arguments...) \ - DAC960_Message(DAC960_WarningLevel, Format, ##Arguments) - -#define DAC960_Error(Format, Arguments...) \ - DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments) - -#define DAC960_Progress(Format, Arguments...) \ - DAC960_Message(DAC960_ProgressLevel, Format, ##Arguments) - -#define DAC960_Critical(Format, Arguments...) \ - DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments) - -#define DAC960_UserCritical(Format, Arguments...) \ - DAC960_Message(DAC960_UserCriticalLevel, Format, ##Arguments) - - -struct DAC960_privdata { - DAC960_HardwareType_T HardwareType; - DAC960_FirmwareType_T FirmwareType; - irq_handler_t InterruptHandler; - unsigned int MemoryWindowSize; -}; - - -/* - Define the DAC960 V1 Firmware Controller Status Mailbox structure. -*/ - -typedef union DAC960_V1_StatusMailbox -{ - unsigned int Word; /* Word 0 */ - struct { - DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 0 */ - unsigned char :7; /* Byte 1 Bits 0-6 */ - bool Valid:1; /* Byte 1 Bit 7 */ - DAC960_V1_CommandStatus_T CommandStatus; /* Bytes 2-3 */ - } Fields; -} -DAC960_V1_StatusMailbox_T; - - -/* - Define the DAC960 V2 Firmware Controller Status Mailbox structure. -*/ - -typedef union DAC960_V2_StatusMailbox -{ - unsigned int Words[2]; /* Words 0-1 */ - struct { - DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */ - DAC960_V2_CommandStatus_T CommandStatus; /* Byte 2 */ - unsigned char RequestSenseLength; /* Byte 3 */ - int DataTransferResidue; /* Bytes 4-7 */ - } Fields; -} -DAC960_V2_StatusMailbox_T; - - -/* - Define the DAC960 Driver Command Types. -*/ - -typedef enum -{ - DAC960_ReadCommand = 1, - DAC960_WriteCommand = 2, - DAC960_ReadRetryCommand = 3, - DAC960_WriteRetryCommand = 4, - DAC960_MonitoringCommand = 5, - DAC960_ImmediateCommand = 6, - DAC960_QueuedCommand = 7 -} -DAC960_CommandType_T; - - -/* - Define the DAC960 Driver Command structure. -*/ - -typedef struct DAC960_Command -{ - int CommandIdentifier; - DAC960_CommandType_T CommandType; - struct DAC960_Controller *Controller; - struct DAC960_Command *Next; - struct completion *Completion; - unsigned int LogicalDriveNumber; - unsigned int BlockNumber; - unsigned int BlockCount; - unsigned int SegmentCount; - int DmaDirection; - struct scatterlist *cmd_sglist; - struct request *Request; - union { - struct { - DAC960_V1_CommandMailbox_T CommandMailbox; - DAC960_V1_KernelCommand_T *KernelCommand; - DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_ScatterGatherSegment_T *ScatterGatherList; - dma_addr_t ScatterGatherListDMA; - struct scatterlist ScatterList[DAC960_V1_ScatterGatherLimit]; - unsigned int EndMarker[0]; - } V1; - struct { - DAC960_V2_CommandMailbox_T CommandMailbox; - DAC960_V2_KernelCommand_T *KernelCommand; - DAC960_V2_CommandStatus_T CommandStatus; - unsigned char RequestSenseLength; - int DataTransferResidue; - DAC960_V2_ScatterGatherSegment_T *ScatterGatherList; - dma_addr_t ScatterGatherListDMA; - DAC960_SCSI_RequestSense_T *RequestSense; - dma_addr_t RequestSenseDMA; - struct scatterlist ScatterList[DAC960_V2_ScatterGatherLimit]; - unsigned int EndMarker[0]; - } V2; - } FW; -} -DAC960_Command_T; - - -/* - Define the DAC960 Driver Controller structure. -*/ - -typedef struct DAC960_Controller -{ - void __iomem *BaseAddress; - void __iomem *MemoryMappedAddress; - DAC960_FirmwareType_T FirmwareType; - DAC960_HardwareType_T HardwareType; - DAC960_IO_Address_T IO_Address; - DAC960_PCI_Address_T PCI_Address; - struct pci_dev *PCIDevice; - unsigned char ControllerNumber; - unsigned char ControllerName[4]; - unsigned char ModelName[20]; - unsigned char FullModelName[28]; - unsigned char FirmwareVersion[12]; - unsigned char Bus; - unsigned char Device; - unsigned char Function; - unsigned char IRQ_Channel; - unsigned char Channels; - unsigned char Targets; - unsigned char MemorySize; - unsigned char LogicalDriveCount; - unsigned short CommandAllocationGroupSize; - unsigned short ControllerQueueDepth; - unsigned short DriverQueueDepth; - unsigned short MaxBlocksPerCommand; - unsigned short ControllerScatterGatherLimit; - unsigned short DriverScatterGatherLimit; - unsigned int CombinedStatusBufferLength; - unsigned int InitialStatusLength; - unsigned int CurrentStatusLength; - unsigned int ProgressBufferLength; - unsigned int UserStatusLength; - struct dma_loaf DmaPages; - unsigned long MonitoringTimerCount; - unsigned long PrimaryMonitoringTime; - unsigned long SecondaryMonitoringTime; - unsigned long ShutdownMonitoringTimer; - unsigned long LastProgressReportTime; - unsigned long LastCurrentStatusTime; - bool ControllerInitialized; - bool MonitoringCommandDeferred; - bool EphemeralProgressMessage; - bool DriveSpinUpMessageDisplayed; - bool MonitoringAlertMode; - bool SuppressEnclosureMessages; - struct timer_list MonitoringTimer; - struct gendisk *disks[DAC960_MaxLogicalDrives]; - struct dma_pool *ScatterGatherPool; - DAC960_Command_T *FreeCommands; - unsigned char *CombinedStatusBuffer; - unsigned char *CurrentStatusBuffer; - struct request_queue *RequestQueue[DAC960_MaxLogicalDrives]; - int req_q_index; - spinlock_t queue_lock; - wait_queue_head_t CommandWaitQueue; - wait_queue_head_t HealthStatusWaitQueue; - DAC960_Command_T InitialCommand; - DAC960_Command_T *Commands[DAC960_MaxDriverQueueDepth]; - struct proc_dir_entry *ControllerProcEntry; - bool LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives]; - void (*QueueCommand)(DAC960_Command_T *Command); - bool (*ReadControllerConfiguration)(struct DAC960_Controller *); - bool (*ReadDeviceConfiguration)(struct DAC960_Controller *); - bool (*ReportDeviceConfiguration)(struct DAC960_Controller *); - void (*QueueReadWriteCommand)(DAC960_Command_T *Command); - union { - struct { - unsigned char GeometryTranslationHeads; - unsigned char GeometryTranslationSectors; - unsigned char PendingRebuildFlag; - unsigned short StripeSize; - unsigned short SegmentSize; - unsigned short NewEventLogSequenceNumber; - unsigned short OldEventLogSequenceNumber; - unsigned short DeviceStateChannel; - unsigned short DeviceStateTargetID; - bool DualModeMemoryMailboxInterface; - bool BackgroundInitializationStatusSupported; - bool SAFTE_EnclosureManagementEnabled; - bool NeedLogicalDriveInformation; - bool NeedErrorTableInformation; - bool NeedDeviceStateInformation; - bool NeedDeviceInquiryInformation; - bool NeedDeviceSerialNumberInformation; - bool NeedRebuildProgress; - bool NeedConsistencyCheckProgress; - bool NeedBackgroundInitializationStatus; - bool StartDeviceStateScan; - bool RebuildProgressFirst; - bool RebuildFlagPending; - bool RebuildStatusPending; - - dma_addr_t FirstCommandMailboxDMA; - DAC960_V1_CommandMailbox_T *FirstCommandMailbox; - DAC960_V1_CommandMailbox_T *LastCommandMailbox; - DAC960_V1_CommandMailbox_T *NextCommandMailbox; - DAC960_V1_CommandMailbox_T *PreviousCommandMailbox1; - DAC960_V1_CommandMailbox_T *PreviousCommandMailbox2; - - dma_addr_t FirstStatusMailboxDMA; - DAC960_V1_StatusMailbox_T *FirstStatusMailbox; - DAC960_V1_StatusMailbox_T *LastStatusMailbox; - DAC960_V1_StatusMailbox_T *NextStatusMailbox; - - DAC960_V1_DCDB_T *MonitoringDCDB; - dma_addr_t MonitoringDCDB_DMA; - - DAC960_V1_Enquiry_T Enquiry; - DAC960_V1_Enquiry_T *NewEnquiry; - dma_addr_t NewEnquiryDMA; - - DAC960_V1_ErrorTable_T ErrorTable; - DAC960_V1_ErrorTable_T *NewErrorTable; - dma_addr_t NewErrorTableDMA; - - DAC960_V1_EventLogEntry_T *EventLogEntry; - dma_addr_t EventLogEntryDMA; - - DAC960_V1_RebuildProgress_T *RebuildProgress; - dma_addr_t RebuildProgressDMA; - DAC960_V1_CommandStatus_T LastRebuildStatus; - DAC960_V1_CommandStatus_T PendingRebuildStatus; - - DAC960_V1_LogicalDriveInformationArray_T LogicalDriveInformation; - DAC960_V1_LogicalDriveInformationArray_T *NewLogicalDriveInformation; - dma_addr_t NewLogicalDriveInformationDMA; - - DAC960_V1_BackgroundInitializationStatus_T - *BackgroundInitializationStatus; - dma_addr_t BackgroundInitializationStatusDMA; - DAC960_V1_BackgroundInitializationStatus_T - LastBackgroundInitializationStatus; - - DAC960_V1_DeviceState_T - DeviceState[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; - DAC960_V1_DeviceState_T *NewDeviceState; - dma_addr_t NewDeviceStateDMA; - - DAC960_SCSI_Inquiry_T - InquiryStandardData[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; - DAC960_SCSI_Inquiry_T *NewInquiryStandardData; - dma_addr_t NewInquiryStandardDataDMA; - - DAC960_SCSI_Inquiry_UnitSerialNumber_T - InquiryUnitSerialNumber[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber; - dma_addr_t NewInquiryUnitSerialNumberDMA; - - int DeviceResetCount[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; - bool DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; - } V1; - struct { - unsigned int StatusChangeCounter; - unsigned int NextEventSequenceNumber; - unsigned int PhysicalDeviceIndex; - bool NeedLogicalDeviceInformation; - bool NeedPhysicalDeviceInformation; - bool NeedDeviceSerialNumberInformation; - bool StartLogicalDeviceInformationScan; - bool StartPhysicalDeviceInformationScan; - struct dma_pool *RequestSensePool; - - dma_addr_t FirstCommandMailboxDMA; - DAC960_V2_CommandMailbox_T *FirstCommandMailbox; - DAC960_V2_CommandMailbox_T *LastCommandMailbox; - DAC960_V2_CommandMailbox_T *NextCommandMailbox; - DAC960_V2_CommandMailbox_T *PreviousCommandMailbox1; - DAC960_V2_CommandMailbox_T *PreviousCommandMailbox2; - - dma_addr_t FirstStatusMailboxDMA; - DAC960_V2_StatusMailbox_T *FirstStatusMailbox; - DAC960_V2_StatusMailbox_T *LastStatusMailbox; - DAC960_V2_StatusMailbox_T *NextStatusMailbox; - - dma_addr_t HealthStatusBufferDMA; - DAC960_V2_HealthStatusBuffer_T *HealthStatusBuffer; - - DAC960_V2_ControllerInfo_T ControllerInformation; - DAC960_V2_ControllerInfo_T *NewControllerInformation; - dma_addr_t NewControllerInformationDMA; - - DAC960_V2_LogicalDeviceInfo_T - *LogicalDeviceInformation[DAC960_MaxLogicalDrives]; - DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInformation; - dma_addr_t NewLogicalDeviceInformationDMA; - - DAC960_V2_PhysicalDeviceInfo_T - *PhysicalDeviceInformation[DAC960_V2_MaxPhysicalDevices]; - DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInformation; - dma_addr_t NewPhysicalDeviceInformationDMA; - - DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber; - dma_addr_t NewInquiryUnitSerialNumberDMA; - DAC960_SCSI_Inquiry_UnitSerialNumber_T - *InquiryUnitSerialNumber[DAC960_V2_MaxPhysicalDevices]; - - DAC960_V2_Event_T *Event; - dma_addr_t EventDMA; - - DAC960_V2_PhysicalToLogicalDevice_T *PhysicalToLogicalDevice; - dma_addr_t PhysicalToLogicalDeviceDMA; - - DAC960_V2_PhysicalDevice_T - LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives]; - bool LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives]; - } V2; - } FW; - unsigned char ProgressBuffer[DAC960_ProgressBufferSize]; - unsigned char UserStatusBuffer[DAC960_UserMessageSize]; -} -DAC960_Controller_T; - - -/* - Simplify access to Firmware Version Dependent Data Structure Components - and Functions. -*/ - -#define V1 FW.V1 -#define V2 FW.V2 -#define DAC960_QueueCommand(Command) \ - (Controller->QueueCommand)(Command) -#define DAC960_ReadControllerConfiguration(Controller) \ - (Controller->ReadControllerConfiguration)(Controller) -#define DAC960_ReadDeviceConfiguration(Controller) \ - (Controller->ReadDeviceConfiguration)(Controller) -#define DAC960_ReportDeviceConfiguration(Controller) \ - (Controller->ReportDeviceConfiguration)(Controller) -#define DAC960_QueueReadWriteCommand(Command) \ - (Controller->QueueReadWriteCommand)(Command) - -/* - * dma_addr_writeql is provided to write dma_addr_t types - * to a 64-bit pci address space register. The controller - * will accept having the register written as two 32-bit - * values. - * - * In HIGHMEM kernels, dma_addr_t is a 64-bit value. - * without HIGHMEM, dma_addr_t is a 32-bit value. - * - * The compiler should always fix up the assignment - * to u.wq appropriately, depending upon the size of - * dma_addr_t. - */ -static inline -void dma_addr_writeql(dma_addr_t addr, void __iomem *write_address) -{ - union { - u64 wq; - uint wl[2]; - } u; - - u.wq = addr; - - writel(u.wl[0], write_address); - writel(u.wl[1], write_address + 4); -} - -/* - Define the DAC960 GEM Series Controller Interface Register Offsets. - */ - -#define DAC960_GEM_RegisterWindowSize 0x600 - -typedef enum -{ - DAC960_GEM_InboundDoorBellRegisterReadSetOffset = 0x214, - DAC960_GEM_InboundDoorBellRegisterClearOffset = 0x218, - DAC960_GEM_OutboundDoorBellRegisterReadSetOffset = 0x224, - DAC960_GEM_OutboundDoorBellRegisterClearOffset = 0x228, - DAC960_GEM_InterruptStatusRegisterOffset = 0x208, - DAC960_GEM_InterruptMaskRegisterReadSetOffset = 0x22C, - DAC960_GEM_InterruptMaskRegisterClearOffset = 0x230, - DAC960_GEM_CommandMailboxBusAddressOffset = 0x510, - DAC960_GEM_CommandStatusOffset = 0x518, - DAC960_GEM_ErrorStatusRegisterReadSetOffset = 0x224, - DAC960_GEM_ErrorStatusRegisterClearOffset = 0x228, -} -DAC960_GEM_RegisterOffsets_T; - -/* - Define the structure of the DAC960 GEM Series Inbound Door Bell - */ - -typedef union DAC960_GEM_InboundDoorBellRegister -{ - unsigned int All; - struct { - unsigned int :24; - bool HardwareMailboxNewCommand:1; - bool AcknowledgeHardwareMailboxStatus:1; - bool GenerateInterrupt:1; - bool ControllerReset:1; - bool MemoryMailboxNewCommand:1; - unsigned int :3; - } Write; - struct { - unsigned int :24; - bool HardwareMailboxFull:1; - bool InitializationInProgress:1; - unsigned int :6; - } Read; -} -DAC960_GEM_InboundDoorBellRegister_T; - -/* - Define the structure of the DAC960 GEM Series Outbound Door Bell Register. - */ -typedef union DAC960_GEM_OutboundDoorBellRegister -{ - unsigned int All; - struct { - unsigned int :24; - bool AcknowledgeHardwareMailboxInterrupt:1; - bool AcknowledgeMemoryMailboxInterrupt:1; - unsigned int :6; - } Write; - struct { - unsigned int :24; - bool HardwareMailboxStatusAvailable:1; - bool MemoryMailboxStatusAvailable:1; - unsigned int :6; - } Read; -} -DAC960_GEM_OutboundDoorBellRegister_T; - -/* - Define the structure of the DAC960 GEM Series Interrupt Mask Register. - */ -typedef union DAC960_GEM_InterruptMaskRegister -{ - unsigned int All; - struct { - unsigned int :16; - unsigned int :8; - unsigned int HardwareMailboxInterrupt:1; - unsigned int MemoryMailboxInterrupt:1; - unsigned int :6; - } Bits; -} -DAC960_GEM_InterruptMaskRegister_T; - -/* - Define the structure of the DAC960 GEM Series Error Status Register. - */ - -typedef union DAC960_GEM_ErrorStatusRegister -{ - unsigned int All; - struct { - unsigned int :24; - unsigned int :5; - bool ErrorStatusPending:1; - unsigned int :2; - } Bits; -} -DAC960_GEM_ErrorStatusRegister_T; - -/* - Define inline functions to provide an abstraction for reading and writing the - DAC960 GEM Series Controller Interface Registers. -*/ - -static inline -void DAC960_GEM_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset); -} - -static inline -void DAC960_GEM_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterClearOffset); -} - -static inline -void DAC960_GEM_GenerateInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.GenerateInterrupt = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset); -} - -static inline -void DAC960_GEM_ControllerReset(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.ControllerReset = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset); -} - -static inline -void DAC960_GEM_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset); -} - -static inline -bool DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readl(ControllerBaseAddress + - DAC960_GEM_InboundDoorBellRegisterReadSetOffset); - return InboundDoorBellRegister.Read.HardwareMailboxFull; -} - -static inline -bool DAC960_GEM_InitializationInProgressP(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readl(ControllerBaseAddress + - DAC960_GEM_InboundDoorBellRegisterReadSetOffset); - return InboundDoorBellRegister.Read.InitializationInProgress; -} - -static inline -void DAC960_GEM_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - writel(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset); -} - -static inline -void DAC960_GEM_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writel(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset); -} - -static inline -void DAC960_GEM_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writel(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset); -} - -static inline -bool DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readl(ControllerBaseAddress + - DAC960_GEM_OutboundDoorBellRegisterReadSetOffset); - return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; -} - -static inline -bool DAC960_GEM_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readl(ControllerBaseAddress + - DAC960_GEM_OutboundDoorBellRegisterReadSetOffset); - return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; -} - -static inline -void DAC960_GEM_EnableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0; - InterruptMaskRegister.Bits.HardwareMailboxInterrupt = true; - InterruptMaskRegister.Bits.MemoryMailboxInterrupt = true; - writel(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_GEM_InterruptMaskRegisterClearOffset); -} - -static inline -void DAC960_GEM_DisableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0; - InterruptMaskRegister.Bits.HardwareMailboxInterrupt = true; - InterruptMaskRegister.Bits.MemoryMailboxInterrupt = true; - writel(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_GEM_InterruptMaskRegisterReadSetOffset); -} - -static inline -bool DAC960_GEM_InterruptsEnabledP(void __iomem *ControllerBaseAddress) -{ - DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = - readl(ControllerBaseAddress + - DAC960_GEM_InterruptMaskRegisterReadSetOffset); - return !(InterruptMaskRegister.Bits.HardwareMailboxInterrupt || - InterruptMaskRegister.Bits.MemoryMailboxInterrupt); -} - -static inline -void DAC960_GEM_WriteCommandMailbox(DAC960_V2_CommandMailbox_T - *MemoryCommandMailbox, - DAC960_V2_CommandMailbox_T - *CommandMailbox) -{ - memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1], - sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int)); - wmb(); - MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0]; - mb(); -} - -static inline -void DAC960_GEM_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, - dma_addr_t CommandMailboxDMA) -{ - dma_addr_writeql(CommandMailboxDMA, - ControllerBaseAddress + - DAC960_GEM_CommandMailboxBusAddressOffset); -} - -static inline DAC960_V2_CommandIdentifier_T -DAC960_GEM_ReadCommandIdentifier(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset); -} - -static inline DAC960_V2_CommandStatus_T -DAC960_GEM_ReadCommandStatus(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset + 2); -} - -static inline bool -DAC960_GEM_ReadErrorStatus(void __iomem *ControllerBaseAddress, - unsigned char *ErrorStatus, - unsigned char *Parameter0, - unsigned char *Parameter1) -{ - DAC960_GEM_ErrorStatusRegister_T ErrorStatusRegister; - ErrorStatusRegister.All = - readl(ControllerBaseAddress + DAC960_GEM_ErrorStatusRegisterReadSetOffset); - if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false; - ErrorStatusRegister.Bits.ErrorStatusPending = false; - *ErrorStatus = ErrorStatusRegister.All; - *Parameter0 = - readb(ControllerBaseAddress + DAC960_GEM_CommandMailboxBusAddressOffset + 0); - *Parameter1 = - readb(ControllerBaseAddress + DAC960_GEM_CommandMailboxBusAddressOffset + 1); - writel(0x03000000, ControllerBaseAddress + - DAC960_GEM_ErrorStatusRegisterClearOffset); - return true; -} - -/* - Define the DAC960 BA Series Controller Interface Register Offsets. -*/ - -#define DAC960_BA_RegisterWindowSize 0x80 - -typedef enum -{ - DAC960_BA_InboundDoorBellRegisterOffset = 0x60, - DAC960_BA_OutboundDoorBellRegisterOffset = 0x61, - DAC960_BA_InterruptStatusRegisterOffset = 0x30, - DAC960_BA_InterruptMaskRegisterOffset = 0x34, - DAC960_BA_CommandMailboxBusAddressOffset = 0x50, - DAC960_BA_CommandStatusOffset = 0x58, - DAC960_BA_ErrorStatusRegisterOffset = 0x63 -} -DAC960_BA_RegisterOffsets_T; - - -/* - Define the structure of the DAC960 BA Series Inbound Door Bell Register. -*/ - -typedef union DAC960_BA_InboundDoorBellRegister -{ - unsigned char All; - struct { - bool HardwareMailboxNewCommand:1; /* Bit 0 */ - bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - bool GenerateInterrupt:1; /* Bit 2 */ - bool ControllerReset:1; /* Bit 3 */ - bool MemoryMailboxNewCommand:1; /* Bit 4 */ - unsigned char :3; /* Bits 5-7 */ - } Write; - struct { - bool HardwareMailboxEmpty:1; /* Bit 0 */ - bool InitializationNotInProgress:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Read; -} -DAC960_BA_InboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 BA Series Outbound Door Bell Register. -*/ - -typedef union DAC960_BA_OutboundDoorBellRegister -{ - unsigned char All; - struct { - bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Write; - struct { - bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ - bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Read; -} -DAC960_BA_OutboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 BA Series Interrupt Mask Register. -*/ - -typedef union DAC960_BA_InterruptMaskRegister -{ - unsigned char All; - struct { - unsigned int :2; /* Bits 0-1 */ - bool DisableInterrupts:1; /* Bit 2 */ - bool DisableInterruptsI2O:1; /* Bit 3 */ - unsigned int :4; /* Bits 4-7 */ - } Bits; -} -DAC960_BA_InterruptMaskRegister_T; - - -/* - Define the structure of the DAC960 BA Series Error Status Register. -*/ - -typedef union DAC960_BA_ErrorStatusRegister -{ - unsigned char All; - struct { - unsigned int :2; /* Bits 0-1 */ - bool ErrorStatusPending:1; /* Bit 2 */ - unsigned int :5; /* Bits 3-7 */ - } Bits; -} -DAC960_BA_ErrorStatusRegister_T; - - -/* - Define inline functions to provide an abstraction for reading and writing the - DAC960 BA Series Controller Interface Registers. -*/ - -static inline -void DAC960_BA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_BA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_BA_GenerateInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.GenerateInterrupt = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_BA_ControllerReset(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.ControllerReset = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_BA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset); - return !InboundDoorBellRegister.Read.HardwareMailboxEmpty; -} - -static inline -bool DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset); - return !InboundDoorBellRegister.Read.InitializationNotInProgress; -} - -static inline -void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_BA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; -} - -static inline -bool DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; -} - -static inline -void DAC960_BA_EnableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0xFF; - InterruptMaskRegister.Bits.DisableInterrupts = false; - InterruptMaskRegister.Bits.DisableInterruptsI2O = true; - writeb(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset); -} - -static inline -void DAC960_BA_DisableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0xFF; - InterruptMaskRegister.Bits.DisableInterrupts = true; - InterruptMaskRegister.Bits.DisableInterruptsI2O = true; - writeb(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset); -} - -static inline -bool DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) -{ - DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = - readb(ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset); - return !InterruptMaskRegister.Bits.DisableInterrupts; -} - -static inline -void DAC960_BA_WriteCommandMailbox(DAC960_V2_CommandMailbox_T - *MemoryCommandMailbox, - DAC960_V2_CommandMailbox_T - *CommandMailbox) -{ - memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1], - sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int)); - wmb(); - MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0]; - mb(); -} - - -static inline -void DAC960_BA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, - dma_addr_t CommandMailboxDMA) -{ - dma_addr_writeql(CommandMailboxDMA, - ControllerBaseAddress + - DAC960_BA_CommandMailboxBusAddressOffset); -} - -static inline DAC960_V2_CommandIdentifier_T -DAC960_BA_ReadCommandIdentifier(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset); -} - -static inline DAC960_V2_CommandStatus_T -DAC960_BA_ReadCommandStatus(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset + 2); -} - -static inline bool -DAC960_BA_ReadErrorStatus(void __iomem *ControllerBaseAddress, - unsigned char *ErrorStatus, - unsigned char *Parameter0, - unsigned char *Parameter1) -{ - DAC960_BA_ErrorStatusRegister_T ErrorStatusRegister; - ErrorStatusRegister.All = - readb(ControllerBaseAddress + DAC960_BA_ErrorStatusRegisterOffset); - if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false; - ErrorStatusRegister.Bits.ErrorStatusPending = false; - *ErrorStatus = ErrorStatusRegister.All; - *Parameter0 = - readb(ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset + 0); - *Parameter1 = - readb(ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset + 1); - writeb(0xFF, ControllerBaseAddress + DAC960_BA_ErrorStatusRegisterOffset); - return true; -} - - -/* - Define the DAC960 LP Series Controller Interface Register Offsets. -*/ - -#define DAC960_LP_RegisterWindowSize 0x80 - -typedef enum -{ - DAC960_LP_InboundDoorBellRegisterOffset = 0x20, - DAC960_LP_OutboundDoorBellRegisterOffset = 0x2C, - DAC960_LP_InterruptStatusRegisterOffset = 0x30, - DAC960_LP_InterruptMaskRegisterOffset = 0x34, - DAC960_LP_CommandMailboxBusAddressOffset = 0x10, - DAC960_LP_CommandStatusOffset = 0x18, - DAC960_LP_ErrorStatusRegisterOffset = 0x2E -} -DAC960_LP_RegisterOffsets_T; - - -/* - Define the structure of the DAC960 LP Series Inbound Door Bell Register. -*/ - -typedef union DAC960_LP_InboundDoorBellRegister -{ - unsigned char All; - struct { - bool HardwareMailboxNewCommand:1; /* Bit 0 */ - bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - bool GenerateInterrupt:1; /* Bit 2 */ - bool ControllerReset:1; /* Bit 3 */ - bool MemoryMailboxNewCommand:1; /* Bit 4 */ - unsigned char :3; /* Bits 5-7 */ - } Write; - struct { - bool HardwareMailboxFull:1; /* Bit 0 */ - bool InitializationInProgress:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Read; -} -DAC960_LP_InboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 LP Series Outbound Door Bell Register. -*/ - -typedef union DAC960_LP_OutboundDoorBellRegister -{ - unsigned char All; - struct { - bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Write; - struct { - bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ - bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Read; -} -DAC960_LP_OutboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 LP Series Interrupt Mask Register. -*/ - -typedef union DAC960_LP_InterruptMaskRegister -{ - unsigned char All; - struct { - unsigned int :2; /* Bits 0-1 */ - bool DisableInterrupts:1; /* Bit 2 */ - unsigned int :5; /* Bits 3-7 */ - } Bits; -} -DAC960_LP_InterruptMaskRegister_T; - - -/* - Define the structure of the DAC960 LP Series Error Status Register. -*/ - -typedef union DAC960_LP_ErrorStatusRegister -{ - unsigned char All; - struct { - unsigned int :2; /* Bits 0-1 */ - bool ErrorStatusPending:1; /* Bit 2 */ - unsigned int :5; /* Bits 3-7 */ - } Bits; -} -DAC960_LP_ErrorStatusRegister_T; - - -/* - Define inline functions to provide an abstraction for reading and writing the - DAC960 LP Series Controller Interface Registers. -*/ - -static inline -void DAC960_LP_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LP_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LP_GenerateInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.GenerateInterrupt = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LP_ControllerReset(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.ControllerReset = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LP_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset); - return InboundDoorBellRegister.Read.HardwareMailboxFull; -} - -static inline -bool DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset); - return InboundDoorBellRegister.Read.InitializationInProgress; -} - -static inline -void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LP_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; -} - -static inline -bool DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; -} - -static inline -void DAC960_LP_EnableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0xFF; - InterruptMaskRegister.Bits.DisableInterrupts = false; - writeb(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset); -} - -static inline -void DAC960_LP_DisableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0xFF; - InterruptMaskRegister.Bits.DisableInterrupts = true; - writeb(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset); -} - -static inline -bool DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress) -{ - DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = - readb(ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset); - return !InterruptMaskRegister.Bits.DisableInterrupts; -} - -static inline -void DAC960_LP_WriteCommandMailbox(DAC960_V2_CommandMailbox_T - *MemoryCommandMailbox, - DAC960_V2_CommandMailbox_T - *CommandMailbox) -{ - memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1], - sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int)); - wmb(); - MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0]; - mb(); -} - -static inline -void DAC960_LP_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, - dma_addr_t CommandMailboxDMA) -{ - dma_addr_writeql(CommandMailboxDMA, - ControllerBaseAddress + - DAC960_LP_CommandMailboxBusAddressOffset); -} - -static inline DAC960_V2_CommandIdentifier_T -DAC960_LP_ReadCommandIdentifier(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset); -} - -static inline DAC960_V2_CommandStatus_T -DAC960_LP_ReadCommandStatus(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset + 2); -} - -static inline bool -DAC960_LP_ReadErrorStatus(void __iomem *ControllerBaseAddress, - unsigned char *ErrorStatus, - unsigned char *Parameter0, - unsigned char *Parameter1) -{ - DAC960_LP_ErrorStatusRegister_T ErrorStatusRegister; - ErrorStatusRegister.All = - readb(ControllerBaseAddress + DAC960_LP_ErrorStatusRegisterOffset); - if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false; - ErrorStatusRegister.Bits.ErrorStatusPending = false; - *ErrorStatus = ErrorStatusRegister.All; - *Parameter0 = - readb(ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset + 0); - *Parameter1 = - readb(ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset + 1); - writeb(0xFF, ControllerBaseAddress + DAC960_LP_ErrorStatusRegisterOffset); - return true; -} - - -/* - Define the DAC960 LA Series Controller Interface Register Offsets. -*/ - -#define DAC960_LA_RegisterWindowSize 0x80 - -typedef enum -{ - DAC960_LA_InboundDoorBellRegisterOffset = 0x60, - DAC960_LA_OutboundDoorBellRegisterOffset = 0x61, - DAC960_LA_InterruptMaskRegisterOffset = 0x34, - DAC960_LA_CommandOpcodeRegisterOffset = 0x50, - DAC960_LA_CommandIdentifierRegisterOffset = 0x51, - DAC960_LA_MailboxRegister2Offset = 0x52, - DAC960_LA_MailboxRegister3Offset = 0x53, - DAC960_LA_MailboxRegister4Offset = 0x54, - DAC960_LA_MailboxRegister5Offset = 0x55, - DAC960_LA_MailboxRegister6Offset = 0x56, - DAC960_LA_MailboxRegister7Offset = 0x57, - DAC960_LA_MailboxRegister8Offset = 0x58, - DAC960_LA_MailboxRegister9Offset = 0x59, - DAC960_LA_MailboxRegister10Offset = 0x5A, - DAC960_LA_MailboxRegister11Offset = 0x5B, - DAC960_LA_MailboxRegister12Offset = 0x5C, - DAC960_LA_StatusCommandIdentifierRegOffset = 0x5D, - DAC960_LA_StatusRegisterOffset = 0x5E, - DAC960_LA_ErrorStatusRegisterOffset = 0x63 -} -DAC960_LA_RegisterOffsets_T; - - -/* - Define the structure of the DAC960 LA Series Inbound Door Bell Register. -*/ - -typedef union DAC960_LA_InboundDoorBellRegister -{ - unsigned char All; - struct { - bool HardwareMailboxNewCommand:1; /* Bit 0 */ - bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - bool GenerateInterrupt:1; /* Bit 2 */ - bool ControllerReset:1; /* Bit 3 */ - bool MemoryMailboxNewCommand:1; /* Bit 4 */ - unsigned char :3; /* Bits 5-7 */ - } Write; - struct { - bool HardwareMailboxEmpty:1; /* Bit 0 */ - bool InitializationNotInProgress:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Read; -} -DAC960_LA_InboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 LA Series Outbound Door Bell Register. -*/ - -typedef union DAC960_LA_OutboundDoorBellRegister -{ - unsigned char All; - struct { - bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Write; - struct { - bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ - bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Read; -} -DAC960_LA_OutboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 LA Series Interrupt Mask Register. -*/ - -typedef union DAC960_LA_InterruptMaskRegister -{ - unsigned char All; - struct { - unsigned char :2; /* Bits 0-1 */ - bool DisableInterrupts:1; /* Bit 2 */ - unsigned char :5; /* Bits 3-7 */ - } Bits; -} -DAC960_LA_InterruptMaskRegister_T; - - -/* - Define the structure of the DAC960 LA Series Error Status Register. -*/ - -typedef union DAC960_LA_ErrorStatusRegister -{ - unsigned char All; - struct { - unsigned int :2; /* Bits 0-1 */ - bool ErrorStatusPending:1; /* Bit 2 */ - unsigned int :5; /* Bits 3-7 */ - } Bits; -} -DAC960_LA_ErrorStatusRegister_T; - - -/* - Define inline functions to provide an abstraction for reading and writing the - DAC960 LA Series Controller Interface Registers. -*/ - -static inline -void DAC960_LA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LA_GenerateInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.GenerateInterrupt = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LA_ControllerReset(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.ControllerReset = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset); - return !InboundDoorBellRegister.Read.HardwareMailboxEmpty; -} - -static inline -bool DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset); - return !InboundDoorBellRegister.Read.InitializationNotInProgress; -} - -static inline -void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_LA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; -} - -static inline -bool DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; -} - -static inline -void DAC960_LA_EnableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0xFF; - InterruptMaskRegister.Bits.DisableInterrupts = false; - writeb(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset); -} - -static inline -void DAC960_LA_DisableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0xFF; - InterruptMaskRegister.Bits.DisableInterrupts = true; - writeb(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset); -} - -static inline -bool DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress) -{ - DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = - readb(ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset); - return !InterruptMaskRegister.Bits.DisableInterrupts; -} - -static inline -void DAC960_LA_WriteCommandMailbox(DAC960_V1_CommandMailbox_T - *MemoryCommandMailbox, - DAC960_V1_CommandMailbox_T - *CommandMailbox) -{ - MemoryCommandMailbox->Words[1] = CommandMailbox->Words[1]; - MemoryCommandMailbox->Words[2] = CommandMailbox->Words[2]; - MemoryCommandMailbox->Words[3] = CommandMailbox->Words[3]; - wmb(); - MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0]; - mb(); -} - -static inline -void DAC960_LA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, - DAC960_V1_CommandMailbox_T *CommandMailbox) -{ - writel(CommandMailbox->Words[0], - ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset); - writel(CommandMailbox->Words[1], - ControllerBaseAddress + DAC960_LA_MailboxRegister4Offset); - writel(CommandMailbox->Words[2], - ControllerBaseAddress + DAC960_LA_MailboxRegister8Offset); - writeb(CommandMailbox->Bytes[12], - ControllerBaseAddress + DAC960_LA_MailboxRegister12Offset); -} - -static inline DAC960_V1_CommandIdentifier_T -DAC960_LA_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) -{ - return readb(ControllerBaseAddress - + DAC960_LA_StatusCommandIdentifierRegOffset); -} - -static inline DAC960_V1_CommandStatus_T -DAC960_LA_ReadStatusRegister(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_LA_StatusRegisterOffset); -} - -static inline bool -DAC960_LA_ReadErrorStatus(void __iomem *ControllerBaseAddress, - unsigned char *ErrorStatus, - unsigned char *Parameter0, - unsigned char *Parameter1) -{ - DAC960_LA_ErrorStatusRegister_T ErrorStatusRegister; - ErrorStatusRegister.All = - readb(ControllerBaseAddress + DAC960_LA_ErrorStatusRegisterOffset); - if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false; - ErrorStatusRegister.Bits.ErrorStatusPending = false; - *ErrorStatus = ErrorStatusRegister.All; - *Parameter0 = - readb(ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset); - *Parameter1 = - readb(ControllerBaseAddress + DAC960_LA_CommandIdentifierRegisterOffset); - writeb(0xFF, ControllerBaseAddress + DAC960_LA_ErrorStatusRegisterOffset); - return true; -} - -/* - Define the DAC960 PG Series Controller Interface Register Offsets. -*/ - -#define DAC960_PG_RegisterWindowSize 0x2000 - -typedef enum -{ - DAC960_PG_InboundDoorBellRegisterOffset = 0x0020, - DAC960_PG_OutboundDoorBellRegisterOffset = 0x002C, - DAC960_PG_InterruptMaskRegisterOffset = 0x0034, - DAC960_PG_CommandOpcodeRegisterOffset = 0x1000, - DAC960_PG_CommandIdentifierRegisterOffset = 0x1001, - DAC960_PG_MailboxRegister2Offset = 0x1002, - DAC960_PG_MailboxRegister3Offset = 0x1003, - DAC960_PG_MailboxRegister4Offset = 0x1004, - DAC960_PG_MailboxRegister5Offset = 0x1005, - DAC960_PG_MailboxRegister6Offset = 0x1006, - DAC960_PG_MailboxRegister7Offset = 0x1007, - DAC960_PG_MailboxRegister8Offset = 0x1008, - DAC960_PG_MailboxRegister9Offset = 0x1009, - DAC960_PG_MailboxRegister10Offset = 0x100A, - DAC960_PG_MailboxRegister11Offset = 0x100B, - DAC960_PG_MailboxRegister12Offset = 0x100C, - DAC960_PG_StatusCommandIdentifierRegOffset = 0x1018, - DAC960_PG_StatusRegisterOffset = 0x101A, - DAC960_PG_ErrorStatusRegisterOffset = 0x103F -} -DAC960_PG_RegisterOffsets_T; - - -/* - Define the structure of the DAC960 PG Series Inbound Door Bell Register. -*/ - -typedef union DAC960_PG_InboundDoorBellRegister -{ - unsigned int All; - struct { - bool HardwareMailboxNewCommand:1; /* Bit 0 */ - bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ - bool GenerateInterrupt:1; /* Bit 2 */ - bool ControllerReset:1; /* Bit 3 */ - bool MemoryMailboxNewCommand:1; /* Bit 4 */ - unsigned int :27; /* Bits 5-31 */ - } Write; - struct { - bool HardwareMailboxFull:1; /* Bit 0 */ - bool InitializationInProgress:1; /* Bit 1 */ - unsigned int :30; /* Bits 2-31 */ - } Read; -} -DAC960_PG_InboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 PG Series Outbound Door Bell Register. -*/ - -typedef union DAC960_PG_OutboundDoorBellRegister -{ - unsigned int All; - struct { - bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ - bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ - unsigned int :30; /* Bits 2-31 */ - } Write; - struct { - bool HardwareMailboxStatusAvailable:1; /* Bit 0 */ - bool MemoryMailboxStatusAvailable:1; /* Bit 1 */ - unsigned int :30; /* Bits 2-31 */ - } Read; -} -DAC960_PG_OutboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 PG Series Interrupt Mask Register. -*/ - -typedef union DAC960_PG_InterruptMaskRegister -{ - unsigned int All; - struct { - unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */ - bool DisableInterrupts:1; /* Bit 2 */ - unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */ - unsigned int Reserved0:24; /* Bits 8-31 */ - } Bits; -} -DAC960_PG_InterruptMaskRegister_T; - - -/* - Define the structure of the DAC960 PG Series Error Status Register. -*/ - -typedef union DAC960_PG_ErrorStatusRegister -{ - unsigned char All; - struct { - unsigned int :2; /* Bits 0-1 */ - bool ErrorStatusPending:1; /* Bit 2 */ - unsigned int :5; /* Bits 3-7 */ - } Bits; -} -DAC960_PG_ErrorStatusRegister_T; - - -/* - Define inline functions to provide an abstraction for reading and writing the - DAC960 PG Series Controller Interface Registers. -*/ - -static inline -void DAC960_PG_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PG_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PG_GenerateInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.GenerateInterrupt = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PG_ControllerReset(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.ControllerReset = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PG_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; - writel(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readl(ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset); - return InboundDoorBellRegister.Read.HardwareMailboxFull; -} - -static inline -bool DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readl(ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset); - return InboundDoorBellRegister.Read.InitializationInProgress; -} - -static inline -void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - writel(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writel(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PG_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; - OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; - writel(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readl(ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; -} - -static inline -bool DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readl(ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; -} - -static inline -void DAC960_PG_EnableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0; - InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; - InterruptMaskRegister.Bits.DisableInterrupts = false; - InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; - writel(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset); -} - -static inline -void DAC960_PG_DisableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = 0; - InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; - InterruptMaskRegister.Bits.DisableInterrupts = true; - InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; - writel(InterruptMaskRegister.All, - ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset); -} - -static inline -bool DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress) -{ - DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister; - InterruptMaskRegister.All = - readl(ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset); - return !InterruptMaskRegister.Bits.DisableInterrupts; -} - -static inline -void DAC960_PG_WriteCommandMailbox(DAC960_V1_CommandMailbox_T - *MemoryCommandMailbox, - DAC960_V1_CommandMailbox_T - *CommandMailbox) -{ - MemoryCommandMailbox->Words[1] = CommandMailbox->Words[1]; - MemoryCommandMailbox->Words[2] = CommandMailbox->Words[2]; - MemoryCommandMailbox->Words[3] = CommandMailbox->Words[3]; - wmb(); - MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0]; - mb(); -} - -static inline -void DAC960_PG_WriteHardwareMailbox(void __iomem *ControllerBaseAddress, - DAC960_V1_CommandMailbox_T *CommandMailbox) -{ - writel(CommandMailbox->Words[0], - ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset); - writel(CommandMailbox->Words[1], - ControllerBaseAddress + DAC960_PG_MailboxRegister4Offset); - writel(CommandMailbox->Words[2], - ControllerBaseAddress + DAC960_PG_MailboxRegister8Offset); - writeb(CommandMailbox->Bytes[12], - ControllerBaseAddress + DAC960_PG_MailboxRegister12Offset); -} - -static inline DAC960_V1_CommandIdentifier_T -DAC960_PG_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) -{ - return readb(ControllerBaseAddress - + DAC960_PG_StatusCommandIdentifierRegOffset); -} - -static inline DAC960_V1_CommandStatus_T -DAC960_PG_ReadStatusRegister(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_PG_StatusRegisterOffset); -} - -static inline bool -DAC960_PG_ReadErrorStatus(void __iomem *ControllerBaseAddress, - unsigned char *ErrorStatus, - unsigned char *Parameter0, - unsigned char *Parameter1) -{ - DAC960_PG_ErrorStatusRegister_T ErrorStatusRegister; - ErrorStatusRegister.All = - readb(ControllerBaseAddress + DAC960_PG_ErrorStatusRegisterOffset); - if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false; - ErrorStatusRegister.Bits.ErrorStatusPending = false; - *ErrorStatus = ErrorStatusRegister.All; - *Parameter0 = - readb(ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset); - *Parameter1 = - readb(ControllerBaseAddress + DAC960_PG_CommandIdentifierRegisterOffset); - writeb(0, ControllerBaseAddress + DAC960_PG_ErrorStatusRegisterOffset); - return true; -} - -/* - Define the DAC960 PD Series Controller Interface Register Offsets. -*/ - -#define DAC960_PD_RegisterWindowSize 0x80 - -typedef enum -{ - DAC960_PD_CommandOpcodeRegisterOffset = 0x00, - DAC960_PD_CommandIdentifierRegisterOffset = 0x01, - DAC960_PD_MailboxRegister2Offset = 0x02, - DAC960_PD_MailboxRegister3Offset = 0x03, - DAC960_PD_MailboxRegister4Offset = 0x04, - DAC960_PD_MailboxRegister5Offset = 0x05, - DAC960_PD_MailboxRegister6Offset = 0x06, - DAC960_PD_MailboxRegister7Offset = 0x07, - DAC960_PD_MailboxRegister8Offset = 0x08, - DAC960_PD_MailboxRegister9Offset = 0x09, - DAC960_PD_MailboxRegister10Offset = 0x0A, - DAC960_PD_MailboxRegister11Offset = 0x0B, - DAC960_PD_MailboxRegister12Offset = 0x0C, - DAC960_PD_StatusCommandIdentifierRegOffset = 0x0D, - DAC960_PD_StatusRegisterOffset = 0x0E, - DAC960_PD_ErrorStatusRegisterOffset = 0x3F, - DAC960_PD_InboundDoorBellRegisterOffset = 0x40, - DAC960_PD_OutboundDoorBellRegisterOffset = 0x41, - DAC960_PD_InterruptEnableRegisterOffset = 0x43 -} -DAC960_PD_RegisterOffsets_T; - - -/* - Define the structure of the DAC960 PD Series Inbound Door Bell Register. -*/ - -typedef union DAC960_PD_InboundDoorBellRegister -{ - unsigned char All; - struct { - bool NewCommand:1; /* Bit 0 */ - bool AcknowledgeStatus:1; /* Bit 1 */ - bool GenerateInterrupt:1; /* Bit 2 */ - bool ControllerReset:1; /* Bit 3 */ - unsigned char :4; /* Bits 4-7 */ - } Write; - struct { - bool MailboxFull:1; /* Bit 0 */ - bool InitializationInProgress:1; /* Bit 1 */ - unsigned char :6; /* Bits 2-7 */ - } Read; -} -DAC960_PD_InboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 PD Series Outbound Door Bell Register. -*/ - -typedef union DAC960_PD_OutboundDoorBellRegister -{ - unsigned char All; - struct { - bool AcknowledgeInterrupt:1; /* Bit 0 */ - unsigned char :7; /* Bits 1-7 */ - } Write; - struct { - bool StatusAvailable:1; /* Bit 0 */ - unsigned char :7; /* Bits 1-7 */ - } Read; -} -DAC960_PD_OutboundDoorBellRegister_T; - - -/* - Define the structure of the DAC960 PD Series Interrupt Enable Register. -*/ - -typedef union DAC960_PD_InterruptEnableRegister -{ - unsigned char All; - struct { - bool EnableInterrupts:1; /* Bit 0 */ - unsigned char :7; /* Bits 1-7 */ - } Bits; -} -DAC960_PD_InterruptEnableRegister_T; - - -/* - Define the structure of the DAC960 PD Series Error Status Register. -*/ - -typedef union DAC960_PD_ErrorStatusRegister -{ - unsigned char All; - struct { - unsigned int :2; /* Bits 0-1 */ - bool ErrorStatusPending:1; /* Bit 2 */ - unsigned int :5; /* Bits 3-7 */ - } Bits; -} -DAC960_PD_ErrorStatusRegister_T; - - -/* - Define inline functions to provide an abstraction for reading and writing the - DAC960 PD Series Controller Interface Registers. -*/ - -static inline -void DAC960_PD_NewCommand(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.NewCommand = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PD_AcknowledgeStatus(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.AcknowledgeStatus = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PD_GenerateInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.GenerateInterrupt = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset); -} - -static inline -void DAC960_PD_ControllerReset(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = 0; - InboundDoorBellRegister.Write.ControllerReset = true; - writeb(InboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset); - return InboundDoorBellRegister.Read.MailboxFull; -} - -static inline -bool DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister; - InboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset); - return InboundDoorBellRegister.Read.InitializationInProgress; -} - -static inline -void DAC960_PD_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = 0; - OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true; - writeb(OutboundDoorBellRegister.All, - ControllerBaseAddress + DAC960_PD_OutboundDoorBellRegisterOffset); -} - -static inline -bool DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister; - OutboundDoorBellRegister.All = - readb(ControllerBaseAddress + DAC960_PD_OutboundDoorBellRegisterOffset); - return OutboundDoorBellRegister.Read.StatusAvailable; -} - -static inline -void DAC960_PD_EnableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; - InterruptEnableRegister.All = 0; - InterruptEnableRegister.Bits.EnableInterrupts = true; - writeb(InterruptEnableRegister.All, - ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset); -} - -static inline -void DAC960_PD_DisableInterrupts(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; - InterruptEnableRegister.All = 0; - InterruptEnableRegister.Bits.EnableInterrupts = false; - writeb(InterruptEnableRegister.All, - ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset); -} - -static inline -bool DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress) -{ - DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister; - InterruptEnableRegister.All = - readb(ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset); - return InterruptEnableRegister.Bits.EnableInterrupts; -} - -static inline -void DAC960_PD_WriteCommandMailbox(void __iomem *ControllerBaseAddress, - DAC960_V1_CommandMailbox_T *CommandMailbox) -{ - writel(CommandMailbox->Words[0], - ControllerBaseAddress + DAC960_PD_CommandOpcodeRegisterOffset); - writel(CommandMailbox->Words[1], - ControllerBaseAddress + DAC960_PD_MailboxRegister4Offset); - writel(CommandMailbox->Words[2], - ControllerBaseAddress + DAC960_PD_MailboxRegister8Offset); - writeb(CommandMailbox->Bytes[12], - ControllerBaseAddress + DAC960_PD_MailboxRegister12Offset); -} - -static inline DAC960_V1_CommandIdentifier_T -DAC960_PD_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress) -{ - return readb(ControllerBaseAddress - + DAC960_PD_StatusCommandIdentifierRegOffset); -} - -static inline DAC960_V1_CommandStatus_T -DAC960_PD_ReadStatusRegister(void __iomem *ControllerBaseAddress) -{ - return readw(ControllerBaseAddress + DAC960_PD_StatusRegisterOffset); -} - -static inline bool -DAC960_PD_ReadErrorStatus(void __iomem *ControllerBaseAddress, - unsigned char *ErrorStatus, - unsigned char *Parameter0, - unsigned char *Parameter1) -{ - DAC960_PD_ErrorStatusRegister_T ErrorStatusRegister; - ErrorStatusRegister.All = - readb(ControllerBaseAddress + DAC960_PD_ErrorStatusRegisterOffset); - if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false; - ErrorStatusRegister.Bits.ErrorStatusPending = false; - *ErrorStatus = ErrorStatusRegister.All; - *Parameter0 = - readb(ControllerBaseAddress + DAC960_PD_CommandOpcodeRegisterOffset); - *Parameter1 = - readb(ControllerBaseAddress + DAC960_PD_CommandIdentifierRegisterOffset); - writeb(0, ControllerBaseAddress + DAC960_PD_ErrorStatusRegisterOffset); - return true; -} - -static inline void DAC960_P_To_PD_TranslateEnquiry(void *Enquiry) -{ - memcpy(Enquiry + 132, Enquiry + 36, 64); - memset(Enquiry + 36, 0, 96); -} - -static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState) -{ - memcpy(DeviceState + 2, DeviceState + 3, 1); - memmove(DeviceState + 4, DeviceState + 5, 2); - memmove(DeviceState + 6, DeviceState + 8, 4); -} - -static inline -void DAC960_PD_To_P_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T - *CommandMailbox) -{ - int LogicalDriveNumber = CommandMailbox->Type5.LD.LogicalDriveNumber; - CommandMailbox->Bytes[3] &= 0x7; - CommandMailbox->Bytes[3] |= CommandMailbox->Bytes[7] << 6; - CommandMailbox->Bytes[7] = LogicalDriveNumber; -} - -static inline -void DAC960_P_To_PD_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T - *CommandMailbox) -{ - int LogicalDriveNumber = CommandMailbox->Bytes[7]; - CommandMailbox->Bytes[7] = CommandMailbox->Bytes[3] >> 6; - CommandMailbox->Bytes[3] &= 0x7; - CommandMailbox->Bytes[3] |= LogicalDriveNumber << 3; -} - - -/* - Define prototypes for the forward referenced DAC960 Driver Internal Functions. -*/ - -static void DAC960_FinalizeController(DAC960_Controller_T *); -static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *); -static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *); -static void DAC960_RequestFunction(struct request_queue *); -static irqreturn_t DAC960_BA_InterruptHandler(int, void *); -static irqreturn_t DAC960_LP_InterruptHandler(int, void *); -static irqreturn_t DAC960_LA_InterruptHandler(int, void *); -static irqreturn_t DAC960_PG_InterruptHandler(int, void *); -static irqreturn_t DAC960_PD_InterruptHandler(int, void *); -static irqreturn_t DAC960_P_InterruptHandler(int, void *); -static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *); -static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *); -static void DAC960_MonitoringTimerFunction(struct timer_list *); -static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *, - DAC960_Controller_T *, ...); -static void DAC960_CreateProcEntries(DAC960_Controller_T *); -static void DAC960_DestroyProcEntries(DAC960_Controller_T *); - -#endif /* DAC960_DriverVersion */ diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index d4913516823f..20bb4bfa4be6 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -121,18 +121,6 @@ source "drivers/block/mtip32xx/Kconfig" source "drivers/block/zram/Kconfig" -config BLK_DEV_DAC960 - tristate "Mylex DAC960/DAC1100 PCI RAID Controller support" - depends on PCI - help - This driver adds support for the Mylex DAC960, AcceleRAID, and - eXtremeRAID PCI RAID controllers. See the file - <file:Documentation/blockdev/README.DAC960> for further information - about this driver. - - To compile this driver as a module, choose M here: the - module will be called DAC960. - config BLK_DEV_UMEM tristate "Micro Memory MM5415 Battery Backed RAM support" depends on PCI @@ -461,7 +449,6 @@ config BLK_DEV_RBD select LIBCRC32C select CRYPTO_AES select CRYPTO - default n help Say Y here if you want include the Rados block device, which stripes a block device over objects stored in the Ceph distributed object diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 8566b188368b..a53cc1e3a2d3 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o obj-$(CONFIG_BLK_DEV_RAM) += brd.o obj-$(CONFIG_BLK_DEV_LOOP) += loop.o -obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_XILINX_SYSACE) += xsysace.o obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o obj-$(CONFIG_SUNVDC) += sunvdc.o diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 3aaf6af3ec23..bf996bd44cfc 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -61,10 +61,8 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/mutex.h> -#include <linux/amifdreg.h> -#include <linux/amifd.h> #include <linux/fs.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/elevator.h> #include <linux/interrupt.h> #include <linux/platform_device.h> @@ -87,6 +85,126 @@ */ /* + * CIAAPRA bits (read only) + */ + +#define DSKRDY (0x1<<5) /* disk ready when low */ +#define DSKTRACK0 (0x1<<4) /* head at track zero when low */ +#define DSKPROT (0x1<<3) /* disk protected when low */ +#define DSKCHANGE (0x1<<2) /* low when disk removed */ + +/* + * CIAAPRB bits (read/write) + */ + +#define DSKMOTOR (0x1<<7) /* motor on when low */ +#define DSKSEL3 (0x1<<6) /* select drive 3 when low */ +#define DSKSEL2 (0x1<<5) /* select drive 2 when low */ +#define DSKSEL1 (0x1<<4) /* select drive 1 when low */ +#define DSKSEL0 (0x1<<3) /* select drive 0 when low */ +#define DSKSIDE (0x1<<2) /* side selection: 0 = upper, 1 = lower */ +#define DSKDIREC (0x1<<1) /* step direction: 0=in, 1=out (to trk 0) */ +#define DSKSTEP (0x1) /* pulse low to step head 1 track */ + +/* + * DSKBYTR bits (read only) + */ + +#define DSKBYT (1<<15) /* register contains valid byte when set */ +#define DMAON (1<<14) /* disk DMA enabled */ +#define DISKWRITE (1<<13) /* disk write bit in DSKLEN enabled */ +#define WORDEQUAL (1<<12) /* DSKSYNC register match when true */ +/* bits 7-0 are data */ + +/* + * ADKCON/ADKCONR bits + */ + +#ifndef SETCLR +#define ADK_SETCLR (1<<15) /* control bit */ +#endif +#define ADK_PRECOMP1 (1<<14) /* precompensation selection */ +#define ADK_PRECOMP0 (1<<13) /* 00=none, 01=140ns, 10=280ns, 11=500ns */ +#define ADK_MFMPREC (1<<12) /* 0=GCR precomp., 1=MFM precomp. */ +#define ADK_WORDSYNC (1<<10) /* enable DSKSYNC auto DMA */ +#define ADK_MSBSYNC (1<<9) /* when 1, enable sync on MSbit (for GCR) */ +#define ADK_FAST (1<<8) /* bit cell: 0=2us (GCR), 1=1us (MFM) */ + +/* + * DSKLEN bits + */ + +#define DSKLEN_DMAEN (1<<15) +#define DSKLEN_WRITE (1<<14) + +/* + * INTENA/INTREQ bits + */ + +#define DSKINDEX (0x1<<4) /* DSKINDEX bit */ + +/* + * Misc + */ + +#define MFM_SYNC 0x4489 /* standard MFM sync value */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ +#define FD_FORMAT 0x4D /* format one track */ +#define FD_VERSION 0x10 /* get version code */ +#define FD_CONFIGURE 0x13 /* configure FIFO operation */ +#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */ + +#define FD_MAX_UNITS 4 /* Max. Number of drives */ +#define FLOPPY_MAX_SECTORS 22 /* Max. Number of sectors per track */ + +struct fd_data_type { + char *name; /* description of data type */ + int sects; /* sectors per track */ + int (*read_fkt)(int); /* read whole track */ + void (*write_fkt)(int); /* write whole track */ +}; + +struct fd_drive_type { + unsigned long code; /* code returned from drive */ + char *name; /* description of drive */ + unsigned int tracks; /* number of tracks */ + unsigned int heads; /* number of heads */ + unsigned int read_size; /* raw read size for one track */ + unsigned int write_size; /* raw write size for one track */ + unsigned int sect_mult; /* sectors and gap multiplier (HD = 2) */ + unsigned int precomp1; /* start track for precomp 1 */ + unsigned int precomp2; /* start track for precomp 2 */ + unsigned int step_delay; /* time (in ms) for delay after step */ + unsigned int settle_time; /* time to settle after dir change */ + unsigned int side_time; /* time needed to change sides */ +}; + +struct amiga_floppy_struct { + struct fd_drive_type *type; /* type of floppy for this unit */ + struct fd_data_type *dtype; /* type of floppy for this unit */ + int track; /* current track (-1 == unknown) */ + unsigned char *trackbuf; /* current track (kmaloc()'d */ + + int blocks; /* total # blocks on disk */ + + int changed; /* true when not known */ + int disk; /* disk in drive (-1 == unknown) */ + int motor; /* true when motor is at speed */ + int busy; /* true when drive is active */ + int dirty; /* true when trackbuf is not on disk */ + int status; /* current error code for unit */ + struct gendisk *gendisk; + struct blk_mq_tag_set tag_set; +}; + +/* * Error codes */ #define FD_OK 0 /* operation succeeded */ @@ -164,7 +282,6 @@ static volatile int selected = -1; /* currently selected drive */ static int writepending; static int writefromint; static char *raw_buf; -static int fdc_queue; static DEFINE_SPINLOCK(amiflop_lock); @@ -1337,76 +1454,20 @@ static int get_track(int drive, int track) return -1; } -/* - * Round-robin between our available drives, doing one request from each - */ -static struct request *set_next_request(void) -{ - struct request_queue *q; - int cnt = FD_MAX_UNITS; - struct request *rq = NULL; - - /* Find next queue we can dispatch from */ - fdc_queue = fdc_queue + 1; - if (fdc_queue == FD_MAX_UNITS) - fdc_queue = 0; - - for(cnt = FD_MAX_UNITS; cnt > 0; cnt--) { - - if (unit[fdc_queue].type->code == FD_NODRIVE) { - if (++fdc_queue == FD_MAX_UNITS) - fdc_queue = 0; - continue; - } - - q = unit[fdc_queue].gendisk->queue; - if (q) { - rq = blk_fetch_request(q); - if (rq) - break; - } - - if (++fdc_queue == FD_MAX_UNITS) - fdc_queue = 0; - } - - return rq; -} - -static void redo_fd_request(void) +static blk_status_t amiflop_rw_cur_segment(struct amiga_floppy_struct *floppy, + struct request *rq) { - struct request *rq; + int drive = floppy - unit; unsigned int cnt, block, track, sector; - int drive; - struct amiga_floppy_struct *floppy; char *data; - unsigned long flags; - blk_status_t err; - -next_req: - rq = set_next_request(); - if (!rq) { - /* Nothing left to do */ - return; - } - - floppy = rq->rq_disk->private_data; - drive = floppy - unit; -next_segment: - /* Here someone could investigate to be more efficient */ - for (cnt = 0, err = BLK_STS_OK; cnt < blk_rq_cur_sectors(rq); cnt++) { + for (cnt = 0; cnt < blk_rq_cur_sectors(rq); cnt++) { #ifdef DEBUG printk("fd: sector %ld + %d requested for %s\n", blk_rq_pos(rq), cnt, (rq_data_dir(rq) == READ) ? "read" : "write"); #endif block = blk_rq_pos(rq) + cnt; - if ((int)block > floppy->blocks) { - err = BLK_STS_IOERR; - break; - } - track = block / (floppy->dtype->sects * floppy->type->sect_mult); sector = block % (floppy->dtype->sects * floppy->type->sect_mult); data = bio_data(rq->bio) + 512 * cnt; @@ -1415,10 +1476,8 @@ next_segment: "0x%08lx\n", track, sector, data); #endif - if (get_track(drive, track) == -1) { - err = BLK_STS_IOERR; - break; - } + if (get_track(drive, track) == -1) + return BLK_STS_IOERR; if (rq_data_dir(rq) == READ) { memcpy(data, floppy->trackbuf + sector * 512, 512); @@ -1426,31 +1485,40 @@ next_segment: memcpy(floppy->trackbuf + sector * 512, data, 512); /* keep the drive spinning while writes are scheduled */ - if (!fd_motor_on(drive)) { - err = BLK_STS_IOERR; - break; - } + if (!fd_motor_on(drive)) + return BLK_STS_IOERR; /* * setup a callback to write the track buffer * after a short (1 tick) delay. */ - local_irq_save(flags); - floppy->dirty = 1; /* reset the timer */ mod_timer (flush_track_timer + drive, jiffies + 1); - local_irq_restore(flags); } } - if (__blk_end_request_cur(rq, err)) - goto next_segment; - goto next_req; + return BLK_STS_OK; } -static void do_fd_request(struct request_queue * q) +static blk_status_t amiflop_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - redo_fd_request(); + struct request *rq = bd->rq; + struct amiga_floppy_struct *floppy = rq->rq_disk->private_data; + blk_status_t err; + + if (!spin_trylock_irq(&amiflop_lock)) + return BLK_STS_DEV_RESOURCE; + + blk_mq_start_request(rq); + + do { + err = amiflop_rw_cur_segment(floppy, rq); + } while (blk_update_request(rq, err, blk_rq_cur_bytes(rq))); + blk_mq_end_request(rq, err); + + spin_unlock_irq(&amiflop_lock); + return BLK_STS_OK; } static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) @@ -1701,11 +1769,47 @@ static const struct block_device_operations floppy_fops = { .check_events = amiga_check_events, }; +static const struct blk_mq_ops amiflop_mq_ops = { + .queue_rq = amiflop_queue_rq, +}; + +static struct gendisk *fd_alloc_disk(int drive) +{ + struct gendisk *disk; + + disk = alloc_disk(1); + if (!disk) + goto out; + + disk->queue = blk_mq_init_sq_queue(&unit[drive].tag_set, &amiflop_mq_ops, + 2, BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(disk->queue)) { + disk->queue = NULL; + goto out_put_disk; + } + + unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL); + if (!unit[drive].trackbuf) + goto out_cleanup_queue; + + return disk; + +out_cleanup_queue: + blk_cleanup_queue(disk->queue); + disk->queue = NULL; + blk_mq_free_tag_set(&unit[drive].tag_set); +out_put_disk: + put_disk(disk); +out: + unit[drive].type->code = FD_NODRIVE; + return NULL; +} + static int __init fd_probe_drives(void) { int drive,drives,nomem; - printk(KERN_INFO "FD: probing units\nfound "); + pr_info("FD: probing units\nfound"); drives=0; nomem=0; for(drive=0;drive<FD_MAX_UNITS;drive++) { @@ -1713,27 +1817,17 @@ static int __init fd_probe_drives(void) fd_probe(drive); if (unit[drive].type->code == FD_NODRIVE) continue; - disk = alloc_disk(1); + + disk = fd_alloc_disk(drive); if (!disk) { - unit[drive].type->code = FD_NODRIVE; + pr_cont(" no mem for fd%d", drive); + nomem = 1; continue; } unit[drive].gendisk = disk; - - disk->queue = blk_init_queue(do_fd_request, &amiflop_lock); - if (!disk->queue) { - unit[drive].type->code = FD_NODRIVE; - continue; - } - drives++; - if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { - printk("no mem for "); - unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ - drives--; - nomem = 1; - } - printk("fd%d ",drive); + + pr_cont(" fd%d",drive); disk->major = FLOPPY_MAJOR; disk->first_minor = drive; disk->fops = &floppy_fops; @@ -1744,11 +1838,11 @@ static int __init fd_probe_drives(void) } if ((drives > 0) || (nomem == 0)) { if (drives == 0) - printk("no drives"); - printk("\n"); + pr_cont(" no drives"); + pr_cont("\n"); return drives; } - printk("\n"); + pr_cont("\n"); return -ENOMEM; } @@ -1831,30 +1925,6 @@ out_blkdev: return ret; } -#if 0 /* not safe to unload */ -static int __exit amiga_floppy_remove(struct platform_device *pdev) -{ - int i; - - for( i = 0; i < FD_MAX_UNITS; i++) { - if (unit[i].type->code != FD_NODRIVE) { - struct request_queue *q = unit[i].gendisk->queue; - del_gendisk(unit[i].gendisk); - put_disk(unit[i].gendisk); - kfree(unit[i].trackbuf); - if (q) - blk_cleanup_queue(q); - } - } - blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); - free_irq(IRQ_AMIGA_CIAA_TB, NULL); - free_irq(IRQ_AMIGA_DSKBLK, NULL); - custom.dmacon = DMAF_DISK; /* disable DMA */ - amiga_chip_free(raw_buf); - unregister_blkdev(FLOPPY_MAJOR, "fd"); -} -#endif - static struct platform_driver amiga_floppy_driver = { .driver = { .name = "amiga-floppy", diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index c0ebda1283cc..7ca76ed2e71a 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,4 +1,6 @@ /* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */ +#include <linux/blk-mq.h> + #define VERSION "85" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" @@ -164,6 +166,8 @@ struct aoedev { struct gendisk *gd; struct dentry *debugfs; struct request_queue *blkq; + struct list_head rq_list; + struct blk_mq_tag_set tag_set; struct hd_geometry geo; sector_t ssize; struct timer_list timer; @@ -201,7 +205,6 @@ int aoeblk_init(void); void aoeblk_exit(void); void aoeblk_gdalloc(void *); void aoedisk_rm_debugfs(struct aoedev *d); -void aoedisk_rm_sysfs(struct aoedev *d); int aoechr_init(void); void aoechr_exit(void); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 429ebb84b592..ed26b7287256 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -6,7 +6,7 @@ #include <linux/kernel.h> #include <linux/hdreg.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/backing-dev.h> #include <linux/fs.h> #include <linux/ioctl.h> @@ -177,10 +177,15 @@ static struct attribute *aoe_attrs[] = { NULL, }; -static const struct attribute_group attr_group = { +static const struct attribute_group aoe_attr_group = { .attrs = aoe_attrs, }; +static const struct attribute_group *aoe_attr_groups[] = { + &aoe_attr_group, + NULL, +}; + static const struct file_operations aoe_debugfs_fops = { .open = aoe_debugfs_open, .read = seq_read, @@ -220,17 +225,6 @@ aoedisk_rm_debugfs(struct aoedev *d) } static int -aoedisk_add_sysfs(struct aoedev *d) -{ - return sysfs_create_group(&disk_to_dev(d->gd)->kobj, &attr_group); -} -void -aoedisk_rm_sysfs(struct aoedev *d) -{ - sysfs_remove_group(&disk_to_dev(d->gd)->kobj, &attr_group); -} - -static int aoeblk_open(struct block_device *bdev, fmode_t mode) { struct aoedev *d = bdev->bd_disk->private_data; @@ -274,23 +268,25 @@ aoeblk_release(struct gendisk *disk, fmode_t mode) spin_unlock_irqrestore(&d->lock, flags); } -static void -aoeblk_request(struct request_queue *q) +static blk_status_t aoeblk_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - struct aoedev *d; - struct request *rq; + struct aoedev *d = hctx->queue->queuedata; + + spin_lock_irq(&d->lock); - d = q->queuedata; if ((d->flags & DEVFL_UP) == 0) { pr_info_ratelimited("aoe: device %ld.%d is not up\n", d->aoemajor, d->aoeminor); - while ((rq = blk_peek_request(q))) { - blk_start_request(rq); - aoe_end_request(d, rq, 1); - } - return; + spin_unlock_irq(&d->lock); + blk_mq_start_request(bd->rq); + return BLK_STS_IOERR; } + + list_add_tail(&bd->rq->queuelist, &d->rq_list); aoecmd_work(d); + spin_unlock_irq(&d->lock); + return BLK_STS_OK; } static int @@ -345,6 +341,10 @@ static const struct block_device_operations aoe_bdops = { .owner = THIS_MODULE, }; +static const struct blk_mq_ops aoeblk_mq_ops = { + .queue_rq = aoeblk_queue_rq, +}; + /* alloc_disk and add_disk can sleep */ void aoeblk_gdalloc(void *vp) @@ -353,9 +353,11 @@ aoeblk_gdalloc(void *vp) struct gendisk *gd; mempool_t *mp; struct request_queue *q; + struct blk_mq_tag_set *set; enum { KB = 1024, MB = KB * KB, READ_AHEAD = 2 * MB, }; ulong flags; int late = 0; + int err; spin_lock_irqsave(&d->lock, flags); if (d->flags & DEVFL_GDALLOC @@ -382,10 +384,25 @@ aoeblk_gdalloc(void *vp) d->aoemajor, d->aoeminor); goto err_disk; } - q = blk_init_queue(aoeblk_request, &d->lock); - if (q == NULL) { + + set = &d->tag_set; + set->ops = &aoeblk_mq_ops; + set->nr_hw_queues = 1; + set->queue_depth = 128; + set->numa_node = NUMA_NO_NODE; + set->flags = BLK_MQ_F_SHOULD_MERGE; + err = blk_mq_alloc_tag_set(set); + if (err) { + pr_err("aoe: cannot allocate tag set for %ld.%d\n", + d->aoemajor, d->aoeminor); + goto err_mempool; + } + + q = blk_mq_init_queue(set); + if (IS_ERR(q)) { pr_err("aoe: cannot allocate block queue for %ld.%d\n", d->aoemajor, d->aoeminor); + blk_mq_free_tag_set(set); goto err_mempool; } @@ -417,8 +434,7 @@ aoeblk_gdalloc(void *vp) spin_unlock_irqrestore(&d->lock, flags); - add_disk(gd); - aoedisk_add_sysfs(d); + device_add_disk(NULL, gd, aoe_attr_groups); aoedisk_add_debugfs(d); spin_lock_irqsave(&d->lock, flags); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 136dc507d020..bb2fba651bd2 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -7,7 +7,7 @@ #include <linux/ata.h> #include <linux/slab.h> #include <linux/hdreg.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/genhd.h> @@ -813,7 +813,7 @@ rexmit_timer(struct timer_list *timer) out: if ((d->flags & DEVFL_KICKME) && d->blkq) { d->flags &= ~DEVFL_KICKME; - d->blkq->request_fn(d->blkq); + blk_mq_run_hw_queues(d->blkq, true); } d->timer.expires = jiffies + TIMERTICK; @@ -857,10 +857,12 @@ nextbuf(struct aoedev *d) return d->ip.buf; rq = d->ip.rq; if (rq == NULL) { - rq = blk_peek_request(q); + rq = list_first_entry_or_null(&d->rq_list, struct request, + queuelist); if (rq == NULL) return NULL; - blk_start_request(rq); + list_del_init(&rq->queuelist); + blk_mq_start_request(rq); d->ip.rq = rq; d->ip.nxbio = rq->bio; rq->special = (void *) rqbiocnt(rq); @@ -1045,6 +1047,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) struct bio *bio; int bok; struct request_queue *q; + blk_status_t err = BLK_STS_OK; q = d->blkq; if (rq == d->ip.rq) @@ -1052,11 +1055,15 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) do { bio = rq->bio; bok = !fastfail && !bio->bi_status; - } while (__blk_end_request(rq, bok ? BLK_STS_OK : BLK_STS_IOERR, bio->bi_iter.bi_size)); + if (!bok) + err = BLK_STS_IOERR; + } while (blk_update_request(rq, bok ? BLK_STS_OK : BLK_STS_IOERR, bio->bi_iter.bi_size)); + + __blk_mq_end_request(rq, err); /* cf. http://lkml.org/lkml/2006/10/31/28 */ if (!fastfail) - __blk_run_queue(q); + blk_mq_run_hw_queues(q, true); } static void diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 41060e9cedf2..9063f8efbd3b 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -5,7 +5,7 @@ */ #include <linux/hdreg.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/netdevice.h> #include <linux/delay.h> #include <linux/slab.h> @@ -197,7 +197,6 @@ aoedev_downdev(struct aoedev *d) { struct aoetgt *t, **tt, **te; struct list_head *head, *pos, *nx; - struct request *rq; int i; d->flags &= ~DEVFL_UP; @@ -225,10 +224,11 @@ aoedev_downdev(struct aoedev *d) /* fast fail all pending I/O */ if (d->blkq) { - while ((rq = blk_peek_request(d->blkq))) { - blk_start_request(rq); - aoe_end_request(d, rq, 1); - } + /* UP is cleared, freeze+quiesce to insure all are errored */ + blk_mq_freeze_queue(d->blkq); + blk_mq_quiesce_queue(d->blkq); + blk_mq_unquiesce_queue(d->blkq); + blk_mq_unfreeze_queue(d->blkq); } if (d->gd) @@ -275,9 +275,9 @@ freedev(struct aoedev *d) del_timer_sync(&d->timer); if (d->gd) { aoedisk_rm_debugfs(d); - aoedisk_rm_sysfs(d); del_gendisk(d->gd); put_disk(d->gd); + blk_mq_free_tag_set(&d->tag_set); blk_cleanup_queue(d->blkq); } t = d->targets; @@ -464,6 +464,7 @@ aoedev_by_aoeaddr(ulong maj, int min, int do_alloc) d->ntargets = NTARGETS; INIT_WORK(&d->work, aoecmd_sleepwork); spin_lock_init(&d->lock); + INIT_LIST_HEAD(&d->rq_list); skb_queue_head_init(&d->skbpool); timer_setup(&d->timer, dummy_timer, 0); d->timer.expires = jiffies + HZ; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index dfb2c2622e5a..f88b4c26d422 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -66,13 +66,11 @@ #include <linux/fd.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/mutex.h> #include <linux/completion.h> #include <linux/wait.h> -#include <asm/atafd.h> -#include <asm/atafdreg.h> #include <asm/atariints.h> #include <asm/atari_stdma.h> #include <asm/atari_stram.h> @@ -83,7 +81,87 @@ static DEFINE_MUTEX(ataflop_mutex); static struct request *fd_request; -static int fdc_queue; + +/* + * WD1772 stuff + */ + +/* register codes */ + +#define FDCSELREG_STP (0x80) /* command/status register */ +#define FDCSELREG_TRA (0x82) /* track register */ +#define FDCSELREG_SEC (0x84) /* sector register */ +#define FDCSELREG_DTA (0x86) /* data register */ + +/* register names for FDC_READ/WRITE macros */ + +#define FDCREG_CMD 0 +#define FDCREG_STATUS 0 +#define FDCREG_TRACK 2 +#define FDCREG_SECTOR 4 +#define FDCREG_DATA 6 + +/* command opcodes */ + +#define FDCCMD_RESTORE (0x00) /* - */ +#define FDCCMD_SEEK (0x10) /* | */ +#define FDCCMD_STEP (0x20) /* | TYP 1 Commands */ +#define FDCCMD_STIN (0x40) /* | */ +#define FDCCMD_STOT (0x60) /* - */ +#define FDCCMD_RDSEC (0x80) /* - TYP 2 Commands */ +#define FDCCMD_WRSEC (0xa0) /* - " */ +#define FDCCMD_RDADR (0xc0) /* - */ +#define FDCCMD_RDTRA (0xe0) /* | TYP 3 Commands */ +#define FDCCMD_WRTRA (0xf0) /* - */ +#define FDCCMD_FORCI (0xd0) /* - TYP 4 Command */ + +/* command modifier bits */ + +#define FDCCMDADD_SR6 (0x00) /* step rate settings */ +#define FDCCMDADD_SR12 (0x01) +#define FDCCMDADD_SR2 (0x02) +#define FDCCMDADD_SR3 (0x03) +#define FDCCMDADD_V (0x04) /* verify */ +#define FDCCMDADD_H (0x08) /* wait for spin-up */ +#define FDCCMDADD_U (0x10) /* update track register */ +#define FDCCMDADD_M (0x10) /* multiple sector access */ +#define FDCCMDADD_E (0x04) /* head settling flag */ +#define FDCCMDADD_P (0x02) /* precompensation off */ +#define FDCCMDADD_A0 (0x01) /* DAM flag */ + +/* status register bits */ + +#define FDCSTAT_MOTORON (0x80) /* motor on */ +#define FDCSTAT_WPROT (0x40) /* write protected (FDCCMD_WR*) */ +#define FDCSTAT_SPINUP (0x20) /* motor speed stable (Type I) */ +#define FDCSTAT_DELDAM (0x20) /* sector has deleted DAM (Type II+III) */ +#define FDCSTAT_RECNF (0x10) /* record not found */ +#define FDCSTAT_CRC (0x08) /* CRC error */ +#define FDCSTAT_TR00 (0x04) /* Track 00 flag (Type I) */ +#define FDCSTAT_LOST (0x04) /* Lost Data (Type II+III) */ +#define FDCSTAT_IDX (0x02) /* Index status (Type I) */ +#define FDCSTAT_DRQ (0x02) /* DRQ status (Type II+III) */ +#define FDCSTAT_BUSY (0x01) /* FDC is busy */ + + +/* PSG Port A Bit Nr 0 .. Side Sel .. 0 -> Side 1 1 -> Side 2 */ +#define DSKSIDE (0x01) + +#define DSKDRVNONE (0x06) +#define DSKDRV0 (0x02) +#define DSKDRV1 (0x04) + +/* step rates */ +#define FDCSTEP_6 0x00 +#define FDCSTEP_12 0x01 +#define FDCSTEP_2 0x02 +#define FDCSTEP_3 0x03 + +struct atari_format_descr { + int track; /* to be formatted */ + int head; /* "" "" */ + int sect_offset; /* offset of first sector */ +}; /* Disk types: DD, HD, ED */ static struct atari_disk_type { @@ -221,6 +299,7 @@ static struct atari_floppy_struct { struct gendisk *disk; int ref; int type; + struct blk_mq_tag_set tag_set; } unit[FD_MAX_UNITS]; #define UD unit[drive] @@ -300,9 +379,6 @@ static int IsFormatting = 0, FormatError; static int UserSteprate[FD_MAX_UNITS] = { -1, -1 }; module_param_array(UserSteprate, int, NULL, 0); -/* Synchronization of FDC access. */ -static volatile int fdc_busy = 0; -static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); static DECLARE_COMPLETION(format_wait); static unsigned long changed_floppies = 0xff, fake_change = 0; @@ -362,7 +438,6 @@ static void fd_times_out(struct timer_list *unused); static void finish_fdc( void ); static void finish_fdc_done( int dummy ); static void setup_req_params( int drive ); -static void redo_fd_request( void); static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long param); static void fd_probe( int drive ); @@ -380,8 +455,11 @@ static DEFINE_TIMER(fd_timer, check_change); static void fd_end_request_cur(blk_status_t err) { - if (!__blk_end_request_cur(fd_request, err)) + if (!blk_update_request(fd_request, err, + blk_rq_cur_bytes(fd_request))) { + __blk_mq_end_request(fd_request, err); fd_request = NULL; + } } static inline void start_motor_off_timer(void) @@ -627,7 +705,6 @@ static void fd_error( void ) if (SelectedDrive != -1) SUD.track = -1; } - redo_fd_request(); } @@ -645,14 +722,15 @@ static void fd_error( void ) static int do_format(int drive, int type, struct atari_format_descr *desc) { + struct request_queue *q = unit[drive].disk->queue; unsigned char *p; int sect, nsect; unsigned long flags; + int ret; - DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n", - drive, desc->track, desc->head, desc->sect_offset )); + blk_mq_freeze_queue(q); + blk_mq_quiesce_queue(q); - wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0); local_irq_save(flags); stdma_lock(floppy_irq, NULL); atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */ @@ -661,16 +739,16 @@ static int do_format(int drive, int type, struct atari_format_descr *desc) if (type) { if (--type >= NUM_DISK_MINORS || minor2disktype[type].drive_types > DriveType) { - redo_fd_request(); - return -EINVAL; + ret = -EINVAL; + goto out; } type = minor2disktype[type].index; UDT = &atari_disk_type[type]; } if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) { - redo_fd_request(); - return -EINVAL; + ret = -EINVAL; + goto out; } nsect = UDT->spt; @@ -709,8 +787,11 @@ static int do_format(int drive, int type, struct atari_format_descr *desc) wait_for_completion(&format_wait); - redo_fd_request(); - return( FormatError ? -EIO : 0 ); + ret = FormatError ? -EIO : 0; +out: + blk_mq_unquiesce_queue(q); + blk_mq_unfreeze_queue(q); + return ret; } @@ -740,7 +821,6 @@ static void do_fd_action( int drive ) else { /* all sectors finished */ fd_end_request_cur(BLK_STS_OK); - redo_fd_request(); return; } } @@ -1145,7 +1225,6 @@ static void fd_rwsec_done1(int status) else { /* all sectors finished */ fd_end_request_cur(BLK_STS_OK); - redo_fd_request(); } return; @@ -1303,8 +1382,6 @@ static void finish_fdc_done( int dummy ) local_irq_save(flags); stdma_release(); - fdc_busy = 0; - wake_up( &fdc_wait ); local_irq_restore(flags); DPRINT(("finish_fdc() finished\n")); @@ -1394,59 +1471,34 @@ static void setup_req_params( int drive ) ReqTrack, ReqSector, (unsigned long)ReqData )); } -/* - * Round-robin between our available drives, doing one request from each - */ -static struct request *set_next_request(void) +static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - struct request_queue *q; - int old_pos = fdc_queue; - struct request *rq = NULL; - - do { - q = unit[fdc_queue].disk->queue; - if (++fdc_queue == FD_MAX_UNITS) - fdc_queue = 0; - if (q) { - rq = blk_fetch_request(q); - if (rq) { - rq->error_count = 0; - break; - } - } - } while (fdc_queue != old_pos); - - return rq; -} - + struct atari_floppy_struct *floppy = bd->rq->rq_disk->private_data; + int drive = floppy - unit; + int type = floppy->type; -static void redo_fd_request(void) -{ - int drive, type; - struct atari_floppy_struct *floppy; + spin_lock_irq(&ataflop_lock); + if (fd_request) { + spin_unlock_irq(&ataflop_lock); + return BLK_STS_DEV_RESOURCE; + } + if (!stdma_try_lock(floppy_irq, NULL)) { + spin_unlock_irq(&ataflop_lock); + return BLK_STS_RESOURCE; + } + fd_request = bd->rq; + blk_mq_start_request(fd_request); - DPRINT(("redo_fd_request: fd_request=%p dev=%s fd_request->sector=%ld\n", - fd_request, fd_request ? fd_request->rq_disk->disk_name : "", - fd_request ? blk_rq_pos(fd_request) : 0 )); + atari_disable_irq( IRQ_MFP_FDC ); IsFormatting = 0; -repeat: - if (!fd_request) { - fd_request = set_next_request(); - if (!fd_request) - goto the_end; - } - - floppy = fd_request->rq_disk->private_data; - drive = floppy - unit; - type = floppy->type; - if (!UD.connected) { /* drive not connected */ printk(KERN_ERR "Unknown Device: fd%d\n", drive ); fd_end_request_cur(BLK_STS_IOERR); - goto repeat; + goto out; } if (type == 0) { @@ -1462,23 +1514,18 @@ repeat: if (--type >= NUM_DISK_MINORS) { printk(KERN_WARNING "fd%d: invalid disk format", drive ); fd_end_request_cur(BLK_STS_IOERR); - goto repeat; + goto out; } if (minor2disktype[type].drive_types > DriveType) { printk(KERN_WARNING "fd%d: unsupported disk format", drive ); fd_end_request_cur(BLK_STS_IOERR); - goto repeat; + goto out; } type = minor2disktype[type].index; UDT = &atari_disk_type[type]; set_capacity(floppy->disk, UDT->blocks); UD.autoprobe = 0; } - - if (blk_rq_pos(fd_request) + 1 > UDT->blocks) { - fd_end_request_cur(BLK_STS_IOERR); - goto repeat; - } /* stop deselect timer */ del_timer( &motor_off_timer ); @@ -1490,22 +1537,13 @@ repeat: setup_req_params( drive ); do_fd_action( drive ); - return; - - the_end: - finish_fdc(); -} - - -void do_fd_request(struct request_queue * q) -{ - DPRINT(("do_fd_request for pid %d\n",current->pid)); - wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0); - stdma_lock(floppy_irq, NULL); - - atari_disable_irq( IRQ_MFP_FDC ); - redo_fd_request(); + if (bd->last) + finish_fdc(); atari_enable_irq( IRQ_MFP_FDC ); + +out: + spin_unlock_irq(&ataflop_lock); + return BLK_STS_OK; } static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, @@ -1583,7 +1621,6 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, /* what if type > 0 here? Overwrite specified entry ? */ if (type) { /* refuse to re-set a predefined type for now */ - redo_fd_request(); return -EINVAL; } @@ -1651,10 +1688,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, /* sanity check */ if (setprm.track != dtp->blocks/dtp->spt/2 || - setprm.head != 2) { - redo_fd_request(); + setprm.head != 2) return -EINVAL; - } UDT = dtp; set_capacity(floppy->disk, UDT->blocks); @@ -1910,6 +1945,10 @@ static const struct block_device_operations floppy_fops = { .revalidate_disk= floppy_revalidate, }; +static const struct blk_mq_ops ataflop_mq_ops = { + .queue_rq = ataflop_queue_rq, +}; + static struct kobject *floppy_find(dev_t dev, int *part, void *data) { int drive = *part & 3; @@ -1923,6 +1962,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) static int __init atari_floppy_init (void) { int i; + int ret; if (!MACH_IS_ATARI) /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */ @@ -1933,8 +1973,19 @@ static int __init atari_floppy_init (void) for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].disk = alloc_disk(1); - if (!unit[i].disk) - goto Enomem; + if (!unit[i].disk) { + ret = -ENOMEM; + goto err; + } + + unit[i].disk->queue = blk_mq_init_sq_queue(&unit[i].tag_set, + &ataflop_mq_ops, 2, + BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(unit[i].disk->queue)) { + ret = PTR_ERR(unit[i].disk->queue); + unit[i].disk->queue = NULL; + goto err; + } } if (UseTrackbuffer < 0) @@ -1951,7 +2002,8 @@ static int __init atari_floppy_init (void) DMABuffer = atari_stram_alloc(BUFFER_SIZE+512, "ataflop"); if (!DMABuffer) { printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n"); - goto Enomem; + ret = -ENOMEM; + goto err; } TrackBuffer = DMABuffer + 512; PhysDMABuffer = atari_stram_to_phys(DMABuffer); @@ -1966,10 +2018,6 @@ static int __init atari_floppy_init (void) sprintf(unit[i].disk->disk_name, "fd%d", i); unit[i].disk->fops = &floppy_fops; unit[i].disk->private_data = &unit[i]; - unit[i].disk->queue = blk_init_queue(do_fd_request, - &ataflop_lock); - if (!unit[i].disk->queue) - goto Enomem; set_capacity(unit[i].disk, MAX_DISK_SIZE * 2); add_disk(unit[i].disk); } @@ -1983,17 +2031,23 @@ static int __init atari_floppy_init (void) config_types(); return 0; -Enomem: - while (i--) { - struct request_queue *q = unit[i].disk->queue; - put_disk(unit[i].disk); - if (q) - blk_cleanup_queue(q); - } +err: + do { + struct gendisk *disk = unit[i].disk; + + if (disk) { + if (disk->queue) { + blk_cleanup_queue(disk->queue); + disk->queue = NULL; + } + blk_mq_free_tag_set(&unit[i].tag_set); + put_disk(unit[i].disk); + } + } while (i--); unregister_blkdev(FLOPPY_MAJOR, "fd"); - return -ENOMEM; + return ret; } #ifndef MODULE @@ -2040,11 +2094,10 @@ static void __exit atari_floppy_exit(void) int i; blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); for (i = 0; i < FD_MAX_UNITS; i++) { - struct request_queue *q = unit[i].disk->queue; - del_gendisk(unit[i].disk); + blk_cleanup_queue(unit[i].disk->queue); + blk_mq_free_tag_set(&unit[i].tag_set); put_disk(unit[i].disk); - blk_cleanup_queue(q); } unregister_blkdev(FLOPPY_MAJOR, "fd"); diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig index 87aab6910d2d..52d885cdccb5 100644 --- a/drivers/block/drbd/Kconfig +++ b/drivers/block/drbd/Kconfig @@ -11,7 +11,6 @@ config BLK_DEV_DRBD depends on PROC_FS && INET select LRU_CACHE select LIBCRC32C - default n help NOTE: In order to authenticate connections you have to select diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e35a234b0a8f..1e47db57b9d2 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -429,7 +429,7 @@ enum { __EE_CALL_AL_COMPLETE_IO, __EE_MAY_SET_IN_SYNC, - /* is this a TRIM aka REQ_DISCARD? */ + /* is this a TRIM aka REQ_OP_DISCARD? */ __EE_IS_TRIM, /* In case a barrier failed, @@ -724,10 +724,10 @@ struct drbd_connection { struct list_head transfer_log; /* all requests not yet fully processed */ struct crypto_shash *cram_hmac_tfm; - struct crypto_ahash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */ - struct crypto_ahash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */ - struct crypto_ahash *csums_tfm; - struct crypto_ahash *verify_tfm; + struct crypto_shash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */ + struct crypto_shash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */ + struct crypto_shash *csums_tfm; + struct crypto_shash *verify_tfm; void *int_dig_in; void *int_dig_vv; @@ -1531,8 +1531,9 @@ static inline void ov_out_of_sync_print(struct drbd_device *device) } -extern void drbd_csum_bio(struct crypto_ahash *, struct bio *, void *); -extern void drbd_csum_ee(struct crypto_ahash *, struct drbd_peer_request *, void *); +extern void drbd_csum_bio(struct crypto_shash *, struct bio *, void *); +extern void drbd_csum_ee(struct crypto_shash *, struct drbd_peer_request *, + void *); /* worker callbacks */ extern int w_e_end_data_req(struct drbd_work *, int); extern int w_e_end_rsdata_req(struct drbd_work *, int); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index ef8212a4b73e..55fd104f1ed4 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1377,7 +1377,7 @@ void drbd_send_ack_dp(struct drbd_peer_device *peer_device, enum drbd_packet cmd struct p_data *dp, int data_size) { if (peer_device->connection->peer_integrity_tfm) - data_size -= crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm); + data_size -= crypto_shash_digestsize(peer_device->connection->peer_integrity_tfm); _drbd_send_ack(peer_device, cmd, dp->sector, cpu_to_be32(data_size), dp->block_id); } @@ -1673,7 +1673,7 @@ static u32 bio_flags_to_wire(struct drbd_connection *connection, return bio->bi_opf & REQ_SYNC ? DP_RW_SYNC : 0; } -/* Used to send write or TRIM aka REQ_DISCARD requests +/* Used to send write or TRIM aka REQ_OP_DISCARD requests * R_PRIMARY -> Peer (P_DATA, P_TRIM) */ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req) @@ -1690,7 +1690,7 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request * sock = &peer_device->connection->data; p = drbd_prepare_command(peer_device, sock); digest_size = peer_device->connection->integrity_tfm ? - crypto_ahash_digestsize(peer_device->connection->integrity_tfm) : 0; + crypto_shash_digestsize(peer_device->connection->integrity_tfm) : 0; if (!p) return -EIO; @@ -1796,7 +1796,7 @@ int drbd_send_block(struct drbd_peer_device *peer_device, enum drbd_packet cmd, p = drbd_prepare_command(peer_device, sock); digest_size = peer_device->connection->integrity_tfm ? - crypto_ahash_digestsize(peer_device->connection->integrity_tfm) : 0; + crypto_shash_digestsize(peer_device->connection->integrity_tfm) : 0; if (!p) return -EIO; @@ -2557,11 +2557,11 @@ void conn_free_crypto(struct drbd_connection *connection) { drbd_free_sock(connection); - crypto_free_ahash(connection->csums_tfm); - crypto_free_ahash(connection->verify_tfm); + crypto_free_shash(connection->csums_tfm); + crypto_free_shash(connection->verify_tfm); crypto_free_shash(connection->cram_hmac_tfm); - crypto_free_ahash(connection->integrity_tfm); - crypto_free_ahash(connection->peer_integrity_tfm); + crypto_free_shash(connection->integrity_tfm); + crypto_free_shash(connection->peer_integrity_tfm); kfree(connection->int_dig_in); kfree(connection->int_dig_vv); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index b4f02768ba47..d15703b1ffe8 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2303,10 +2303,10 @@ check_net_options(struct drbd_connection *connection, struct net_conf *new_net_c } struct crypto { - struct crypto_ahash *verify_tfm; - struct crypto_ahash *csums_tfm; + struct crypto_shash *verify_tfm; + struct crypto_shash *csums_tfm; struct crypto_shash *cram_hmac_tfm; - struct crypto_ahash *integrity_tfm; + struct crypto_shash *integrity_tfm; }; static int @@ -2324,36 +2324,21 @@ alloc_shash(struct crypto_shash **tfm, char *tfm_name, int err_alg) return NO_ERROR; } -static int -alloc_ahash(struct crypto_ahash **tfm, char *tfm_name, int err_alg) -{ - if (!tfm_name[0]) - return NO_ERROR; - - *tfm = crypto_alloc_ahash(tfm_name, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(*tfm)) { - *tfm = NULL; - return err_alg; - } - - return NO_ERROR; -} - static enum drbd_ret_code alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf) { char hmac_name[CRYPTO_MAX_ALG_NAME]; enum drbd_ret_code rv; - rv = alloc_ahash(&crypto->csums_tfm, new_net_conf->csums_alg, + rv = alloc_shash(&crypto->csums_tfm, new_net_conf->csums_alg, ERR_CSUMS_ALG); if (rv != NO_ERROR) return rv; - rv = alloc_ahash(&crypto->verify_tfm, new_net_conf->verify_alg, + rv = alloc_shash(&crypto->verify_tfm, new_net_conf->verify_alg, ERR_VERIFY_ALG); if (rv != NO_ERROR) return rv; - rv = alloc_ahash(&crypto->integrity_tfm, new_net_conf->integrity_alg, + rv = alloc_shash(&crypto->integrity_tfm, new_net_conf->integrity_alg, ERR_INTEGRITY_ALG); if (rv != NO_ERROR) return rv; @@ -2371,9 +2356,9 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf) static void free_crypto(struct crypto *crypto) { crypto_free_shash(crypto->cram_hmac_tfm); - crypto_free_ahash(crypto->integrity_tfm); - crypto_free_ahash(crypto->csums_tfm); - crypto_free_ahash(crypto->verify_tfm); + crypto_free_shash(crypto->integrity_tfm); + crypto_free_shash(crypto->csums_tfm); + crypto_free_shash(crypto->verify_tfm); } int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) @@ -2450,17 +2435,17 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) rcu_assign_pointer(connection->net_conf, new_net_conf); if (!rsr) { - crypto_free_ahash(connection->csums_tfm); + crypto_free_shash(connection->csums_tfm); connection->csums_tfm = crypto.csums_tfm; crypto.csums_tfm = NULL; } if (!ovr) { - crypto_free_ahash(connection->verify_tfm); + crypto_free_shash(connection->verify_tfm); connection->verify_tfm = crypto.verify_tfm; crypto.verify_tfm = NULL; } - crypto_free_ahash(connection->integrity_tfm); + crypto_free_shash(connection->integrity_tfm); connection->integrity_tfm = crypto.integrity_tfm; if (connection->cstate >= C_WF_REPORT_PARAMS && connection->agreed_pro_version >= 100) /* Do this without trying to take connection->data.mutex again. */ diff --git a/drivers/block/drbd/drbd_protocol.h b/drivers/block/drbd/drbd_protocol.h index c3081f93051c..48dabbb21e11 100644 --- a/drivers/block/drbd/drbd_protocol.h +++ b/drivers/block/drbd/drbd_protocol.h @@ -57,7 +57,7 @@ enum drbd_packet { P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */ /* 0x2e to 0x30 reserved, used in drbd 9 */ - /* REQ_DISCARD. We used "discard" in different contexts before, + /* REQ_OP_DISCARD. We used "discard" in different contexts before, * which is why I chose TRIM here, to disambiguate. */ P_TRIM = 0x31, @@ -126,7 +126,7 @@ struct p_header100 { #define DP_UNPLUG 8 /* not used anymore */ #define DP_FUA 16 /* equals REQ_FUA */ #define DP_FLUSH 32 /* equals REQ_PREFLUSH */ -#define DP_DISCARD 64 /* equals REQ_DISCARD */ +#define DP_DISCARD 64 /* equals REQ_OP_DISCARD */ #define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */ #define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */ #define DP_WSAME 512 /* equiv. REQ_WRITE_SAME */ diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 75f6b47169e6..fc67fd853375 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1732,7 +1732,7 @@ static int receive_Barrier(struct drbd_connection *connection, struct packet_inf } /* quick wrapper in case payload size != request_size (write same) */ -static void drbd_csum_ee_size(struct crypto_ahash *h, +static void drbd_csum_ee_size(struct crypto_shash *h, struct drbd_peer_request *r, void *d, unsigned int payload_size) { @@ -1769,7 +1769,7 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector, digest_size = 0; if (!trim && peer_device->connection->peer_integrity_tfm) { - digest_size = crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm); + digest_size = crypto_shash_digestsize(peer_device->connection->peer_integrity_tfm); /* * FIXME: Receive the incoming digest into the receive buffer * here, together with its struct p_data? @@ -1905,7 +1905,7 @@ static int recv_dless_read(struct drbd_peer_device *peer_device, struct drbd_req digest_size = 0; if (peer_device->connection->peer_integrity_tfm) { - digest_size = crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm); + digest_size = crypto_shash_digestsize(peer_device->connection->peer_integrity_tfm); err = drbd_recv_all_warn(peer_device->connection, dig_in, digest_size); if (err) return err; @@ -3542,7 +3542,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in int p_proto, p_discard_my_data, p_two_primaries, cf; struct net_conf *nc, *old_net_conf, *new_net_conf = NULL; char integrity_alg[SHARED_SECRET_MAX] = ""; - struct crypto_ahash *peer_integrity_tfm = NULL; + struct crypto_shash *peer_integrity_tfm = NULL; void *int_dig_in = NULL, *int_dig_vv = NULL; p_proto = be32_to_cpu(p->protocol); @@ -3623,7 +3623,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in * change. */ - peer_integrity_tfm = crypto_alloc_ahash(integrity_alg, 0, CRYPTO_ALG_ASYNC); + peer_integrity_tfm = crypto_alloc_shash(integrity_alg, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(peer_integrity_tfm)) { peer_integrity_tfm = NULL; drbd_err(connection, "peer data-integrity-alg %s not supported\n", @@ -3631,7 +3631,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in goto disconnect; } - hash_size = crypto_ahash_digestsize(peer_integrity_tfm); + hash_size = crypto_shash_digestsize(peer_integrity_tfm); int_dig_in = kmalloc(hash_size, GFP_KERNEL); int_dig_vv = kmalloc(hash_size, GFP_KERNEL); if (!(int_dig_in && int_dig_vv)) { @@ -3661,7 +3661,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in mutex_unlock(&connection->resource->conf_update); mutex_unlock(&connection->data.mutex); - crypto_free_ahash(connection->peer_integrity_tfm); + crypto_free_shash(connection->peer_integrity_tfm); kfree(connection->int_dig_in); kfree(connection->int_dig_vv); connection->peer_integrity_tfm = peer_integrity_tfm; @@ -3679,7 +3679,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in disconnect_rcu_unlock: rcu_read_unlock(); disconnect: - crypto_free_ahash(peer_integrity_tfm); + crypto_free_shash(peer_integrity_tfm); kfree(int_dig_in); kfree(int_dig_vv); conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD); @@ -3691,15 +3691,16 @@ disconnect: * return: NULL (alg name was "") * ERR_PTR(error) if something goes wrong * or the crypto hash ptr, if it worked out ok. */ -static struct crypto_ahash *drbd_crypto_alloc_digest_safe(const struct drbd_device *device, +static struct crypto_shash *drbd_crypto_alloc_digest_safe( + const struct drbd_device *device, const char *alg, const char *name) { - struct crypto_ahash *tfm; + struct crypto_shash *tfm; if (!alg[0]) return NULL; - tfm = crypto_alloc_ahash(alg, 0, CRYPTO_ALG_ASYNC); + tfm = crypto_alloc_shash(alg, 0, 0); if (IS_ERR(tfm)) { drbd_err(device, "Can not allocate \"%s\" as %s (reason: %ld)\n", alg, name, PTR_ERR(tfm)); @@ -3752,8 +3753,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i struct drbd_device *device; struct p_rs_param_95 *p; unsigned int header_size, data_size, exp_max_sz; - struct crypto_ahash *verify_tfm = NULL; - struct crypto_ahash *csums_tfm = NULL; + struct crypto_shash *verify_tfm = NULL; + struct crypto_shash *csums_tfm = NULL; struct net_conf *old_net_conf, *new_net_conf = NULL; struct disk_conf *old_disk_conf = NULL, *new_disk_conf = NULL; const int apv = connection->agreed_pro_version; @@ -3900,14 +3901,14 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i if (verify_tfm) { strcpy(new_net_conf->verify_alg, p->verify_alg); new_net_conf->verify_alg_len = strlen(p->verify_alg) + 1; - crypto_free_ahash(peer_device->connection->verify_tfm); + crypto_free_shash(peer_device->connection->verify_tfm); peer_device->connection->verify_tfm = verify_tfm; drbd_info(device, "using verify-alg: \"%s\"\n", p->verify_alg); } if (csums_tfm) { strcpy(new_net_conf->csums_alg, p->csums_alg); new_net_conf->csums_alg_len = strlen(p->csums_alg) + 1; - crypto_free_ahash(peer_device->connection->csums_tfm); + crypto_free_shash(peer_device->connection->csums_tfm); peer_device->connection->csums_tfm = csums_tfm; drbd_info(device, "using csums-alg: \"%s\"\n", p->csums_alg); } @@ -3951,9 +3952,9 @@ disconnect: mutex_unlock(&connection->resource->conf_update); /* just for completeness: actually not needed, * as this is not reached if csums_tfm was ok. */ - crypto_free_ahash(csums_tfm); + crypto_free_shash(csums_tfm); /* but free the verify_tfm again, if csums_tfm did not work out */ - crypto_free_ahash(verify_tfm); + crypto_free_shash(verify_tfm); conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD); return -EIO; } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 19cac36e9737..1c4da17e902e 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -650,7 +650,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, case DISCARD_COMPLETED_NOTSUPP: case DISCARD_COMPLETED_WITH_ERROR: /* I'd rather not detach from local disk just because it - * failed a REQ_DISCARD. */ + * failed a REQ_OP_DISCARD. */ mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED); break; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index b8f77e83d456..99255d0c9e2f 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -152,7 +152,7 @@ void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(l do_wake = list_empty(block_id == ID_SYNCER ? &device->sync_ee : &device->active_ee); - /* FIXME do we want to detach for failed REQ_DISCARD? + /* FIXME do we want to detach for failed REQ_OP_DISCARD? * ((peer_req->flags & (EE_WAS_ERROR|EE_IS_TRIM)) == EE_WAS_ERROR) */ if (peer_req->flags & EE_WAS_ERROR) __drbd_chk_io_error(device, DRBD_WRITE_ERROR); @@ -295,60 +295,61 @@ void drbd_request_endio(struct bio *bio) complete_master_bio(device, &m); } -void drbd_csum_ee(struct crypto_ahash *tfm, struct drbd_peer_request *peer_req, void *digest) +void drbd_csum_ee(struct crypto_shash *tfm, struct drbd_peer_request *peer_req, void *digest) { - AHASH_REQUEST_ON_STACK(req, tfm); - struct scatterlist sg; + SHASH_DESC_ON_STACK(desc, tfm); struct page *page = peer_req->pages; struct page *tmp; unsigned len; + void *src; - ahash_request_set_tfm(req, tfm); - ahash_request_set_callback(req, 0, NULL, NULL); + desc->tfm = tfm; + desc->flags = 0; - sg_init_table(&sg, 1); - crypto_ahash_init(req); + crypto_shash_init(desc); + src = kmap_atomic(page); while ((tmp = page_chain_next(page))) { /* all but the last page will be fully used */ - sg_set_page(&sg, page, PAGE_SIZE, 0); - ahash_request_set_crypt(req, &sg, NULL, sg.length); - crypto_ahash_update(req); + crypto_shash_update(desc, src, PAGE_SIZE); + kunmap_atomic(src); page = tmp; + src = kmap_atomic(page); } /* and now the last, possibly only partially used page */ len = peer_req->i.size & (PAGE_SIZE - 1); - sg_set_page(&sg, page, len ?: PAGE_SIZE, 0); - ahash_request_set_crypt(req, &sg, digest, sg.length); - crypto_ahash_finup(req); - ahash_request_zero(req); + crypto_shash_update(desc, src, len ?: PAGE_SIZE); + kunmap_atomic(src); + + crypto_shash_final(desc, digest); + shash_desc_zero(desc); } -void drbd_csum_bio(struct crypto_ahash *tfm, struct bio *bio, void *digest) +void drbd_csum_bio(struct crypto_shash *tfm, struct bio *bio, void *digest) { - AHASH_REQUEST_ON_STACK(req, tfm); - struct scatterlist sg; + SHASH_DESC_ON_STACK(desc, tfm); struct bio_vec bvec; struct bvec_iter iter; - ahash_request_set_tfm(req, tfm); - ahash_request_set_callback(req, 0, NULL, NULL); + desc->tfm = tfm; + desc->flags = 0; - sg_init_table(&sg, 1); - crypto_ahash_init(req); + crypto_shash_init(desc); bio_for_each_segment(bvec, bio, iter) { - sg_set_page(&sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset); - ahash_request_set_crypt(req, &sg, NULL, sg.length); - crypto_ahash_update(req); + u8 *src; + + src = kmap_atomic(bvec.bv_page); + crypto_shash_update(desc, src + bvec.bv_offset, bvec.bv_len); + kunmap_atomic(src); + /* REQ_OP_WRITE_SAME has only one segment, * checksum the payload only once. */ if (bio_op(bio) == REQ_OP_WRITE_SAME) break; } - ahash_request_set_crypt(req, NULL, digest, 0); - crypto_ahash_final(req); - ahash_request_zero(req); + crypto_shash_final(desc, digest); + shash_desc_zero(desc); } /* MAYBE merge common code with w_e_end_ov_req */ @@ -367,7 +368,7 @@ static int w_e_send_csum(struct drbd_work *w, int cancel) if (unlikely((peer_req->flags & EE_WAS_ERROR) != 0)) goto out; - digest_size = crypto_ahash_digestsize(peer_device->connection->csums_tfm); + digest_size = crypto_shash_digestsize(peer_device->connection->csums_tfm); digest = kmalloc(digest_size, GFP_NOIO); if (digest) { sector_t sector = peer_req->i.sector; @@ -1205,7 +1206,7 @@ int w_e_end_csum_rs_req(struct drbd_work *w, int cancel) * a real fix would be much more involved, * introducing more locking mechanisms */ if (peer_device->connection->csums_tfm) { - digest_size = crypto_ahash_digestsize(peer_device->connection->csums_tfm); + digest_size = crypto_shash_digestsize(peer_device->connection->csums_tfm); D_ASSERT(device, digest_size == di->digest_size); digest = kmalloc(digest_size, GFP_NOIO); } @@ -1255,7 +1256,7 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel) if (unlikely(cancel)) goto out; - digest_size = crypto_ahash_digestsize(peer_device->connection->verify_tfm); + digest_size = crypto_shash_digestsize(peer_device->connection->verify_tfm); digest = kmalloc(digest_size, GFP_NOIO); if (!digest) { err = 1; /* terminate the connection in case the allocation failed */ @@ -1327,7 +1328,7 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel) di = peer_req->digest; if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { - digest_size = crypto_ahash_digestsize(peer_device->connection->verify_tfm); + digest_size = crypto_shash_digestsize(peer_device->connection->verify_tfm); digest = kmalloc(digest_size, GFP_NOIO); if (digest) { drbd_csum_ee(peer_device->connection->verify_tfm, peer_req, digest); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index f2b6f4da1034..a8cfa011c284 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -252,13 +252,13 @@ static int allowed_drive_mask = 0x33; static int irqdma_allocated; -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/blkpg.h> #include <linux/cdrom.h> /* for the compatibility eject ioctl */ #include <linux/completion.h> +static LIST_HEAD(floppy_reqs); static struct request *current_req; -static void do_fd_request(struct request_queue *q); static int set_next_request(void); #ifndef fd_get_dma_residue @@ -414,10 +414,10 @@ static struct floppy_drive_struct drive_state[N_DRIVE]; static struct floppy_write_errors write_errors[N_DRIVE]; static struct timer_list motor_off_timer[N_DRIVE]; static struct gendisk *disks[N_DRIVE]; +static struct blk_mq_tag_set tag_sets[N_DRIVE]; static struct block_device *opened_bdev[N_DRIVE]; static DEFINE_MUTEX(open_lock); static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; -static int fdc_queue; /* * This struct defines the different floppy types. @@ -2216,8 +2216,9 @@ static void floppy_end_request(struct request *req, blk_status_t error) /* current_count_sectors can be zero if transfer failed */ if (error) nr_sectors = blk_rq_cur_sectors(req); - if (__blk_end_request(req, error, nr_sectors << 9)) + if (blk_update_request(req, error, nr_sectors << 9)) return; + __blk_mq_end_request(req, error); /* We're done with the request */ floppy_off(drive); @@ -2797,27 +2798,14 @@ static int make_raw_rw_request(void) return 2; } -/* - * Round-robin between our available drives, doing one request from each - */ static int set_next_request(void) { - struct request_queue *q; - int old_pos = fdc_queue; - - do { - q = disks[fdc_queue]->queue; - if (++fdc_queue == N_DRIVE) - fdc_queue = 0; - if (q) { - current_req = blk_fetch_request(q); - if (current_req) { - current_req->error_count = 0; - break; - } - } - } while (fdc_queue != old_pos); - + current_req = list_first_entry_or_null(&floppy_reqs, struct request, + queuelist); + if (current_req) { + current_req->error_count = 0; + list_del_init(¤t_req->queuelist); + } return current_req != NULL; } @@ -2901,29 +2889,38 @@ static void process_fd_request(void) schedule_bh(redo_fd_request); } -static void do_fd_request(struct request_queue *q) +static blk_status_t floppy_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { + blk_mq_start_request(bd->rq); + if (WARN(max_buffer_sectors == 0, "VFS: %s called on non-open device\n", __func__)) - return; + return BLK_STS_IOERR; if (WARN(atomic_read(&usage_count) == 0, "warning: usage count=0, current_req=%p sect=%ld flags=%llx\n", current_req, (long)blk_rq_pos(current_req), (unsigned long long) current_req->cmd_flags)) - return; + return BLK_STS_IOERR; + + spin_lock_irq(&floppy_lock); + list_add_tail(&bd->rq->queuelist, &floppy_reqs); + spin_unlock_irq(&floppy_lock); if (test_and_set_bit(0, &fdc_busy)) { /* fdc busy, this new request will be treated when the current one is done */ is_alive(__func__, "old request running"); - return; + return BLK_STS_OK; } + command_status = FD_COMMAND_NONE; __reschedule_timeout(MAXTIMEOUT, "fd_request"); set_fdc(0); process_fd_request(); is_alive(__func__, ""); + return BLK_STS_OK; } static const struct cont_t poll_cont = { @@ -4486,6 +4483,10 @@ static struct platform_driver floppy_driver = { }, }; +static const struct blk_mq_ops floppy_mq_ops = { + .queue_rq = floppy_queue_rq, +}; + static struct platform_device floppy_device[N_DRIVE]; static bool floppy_available(int drive) @@ -4533,9 +4534,12 @@ static int __init do_floppy_init(void) goto out_put_disk; } - disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock); - if (!disks[drive]->queue) { - err = -ENOMEM; + disks[drive]->queue = blk_mq_init_sq_queue(&tag_sets[drive], + &floppy_mq_ops, 2, + BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(disks[drive]->queue)) { + err = PTR_ERR(disks[drive]->queue); + disks[drive]->queue = NULL; goto out_put_disk; } @@ -4679,7 +4683,7 @@ static int __init do_floppy_init(void) /* to be cleaned up... */ disks[drive]->private_data = (void *)(long)drive; disks[drive]->flags |= GENHD_FL_REMOVABLE; - device_add_disk(&floppy_device[drive].dev, disks[drive]); + device_add_disk(&floppy_device[drive].dev, disks[drive], NULL); } return 0; @@ -4708,6 +4712,7 @@ out_put_disk: del_timer_sync(&motor_off_timer[drive]); blk_cleanup_queue(disks[drive]->queue); disks[drive]->queue = NULL; + blk_mq_free_tag_set(&tag_sets[drive]); } put_disk(disks[drive]); } @@ -4935,6 +4940,7 @@ static void __exit floppy_module_exit(void) platform_device_unregister(&floppy_device[drive]); } blk_cleanup_queue(disks[drive]->queue); + blk_mq_free_tag_set(&tag_sets[drive]); /* * These disks have not called add_disk(). Don't put down diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ea9debf59b22..abad6d15f956 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -77,6 +77,7 @@ #include <linux/falloc.h> #include <linux/uio.h> #include <linux/ioprio.h> +#include <linux/blk-cgroup.h> #include "loop.h" @@ -1760,8 +1761,8 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, /* always use the first bio's css */ #ifdef CONFIG_BLK_CGROUP - if (cmd->use_aio && rq->bio && rq->bio->bi_css) { - cmd->css = rq->bio->bi_css; + if (cmd->use_aio && rq->bio && rq->bio->bi_blkg) { + cmd->css = &bio_blkcg(rq->bio)->css; css_get(cmd->css); } else #endif diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index d0666f5ce003..dfc8de6ce525 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -1862,11 +1862,9 @@ static int exec_drive_taskfile(struct driver_data *dd, if (IS_ERR(outbuf)) return PTR_ERR(outbuf); - outbuf_dma = pci_map_single(dd->pdev, - outbuf, - taskout, - DMA_TO_DEVICE); - if (pci_dma_mapping_error(dd->pdev, outbuf_dma)) { + outbuf_dma = dma_map_single(&dd->pdev->dev, outbuf, + taskout, DMA_TO_DEVICE); + if (dma_mapping_error(&dd->pdev->dev, outbuf_dma)) { err = -ENOMEM; goto abort; } @@ -1880,10 +1878,9 @@ static int exec_drive_taskfile(struct driver_data *dd, inbuf = NULL; goto abort; } - inbuf_dma = pci_map_single(dd->pdev, - inbuf, - taskin, DMA_FROM_DEVICE); - if (pci_dma_mapping_error(dd->pdev, inbuf_dma)) { + inbuf_dma = dma_map_single(&dd->pdev->dev, inbuf, + taskin, DMA_FROM_DEVICE); + if (dma_mapping_error(&dd->pdev->dev, inbuf_dma)) { err = -ENOMEM; goto abort; } @@ -2002,11 +1999,11 @@ static int exec_drive_taskfile(struct driver_data *dd, /* reclaim the DMA buffers.*/ if (inbuf_dma) - pci_unmap_single(dd->pdev, inbuf_dma, - taskin, DMA_FROM_DEVICE); + dma_unmap_single(&dd->pdev->dev, inbuf_dma, taskin, + DMA_FROM_DEVICE); if (outbuf_dma) - pci_unmap_single(dd->pdev, outbuf_dma, - taskout, DMA_TO_DEVICE); + dma_unmap_single(&dd->pdev->dev, outbuf_dma, taskout, + DMA_TO_DEVICE); inbuf_dma = 0; outbuf_dma = 0; @@ -2053,11 +2050,11 @@ static int exec_drive_taskfile(struct driver_data *dd, } abort: if (inbuf_dma) - pci_unmap_single(dd->pdev, inbuf_dma, - taskin, DMA_FROM_DEVICE); + dma_unmap_single(&dd->pdev->dev, inbuf_dma, taskin, + DMA_FROM_DEVICE); if (outbuf_dma) - pci_unmap_single(dd->pdev, outbuf_dma, - taskout, DMA_TO_DEVICE); + dma_unmap_single(&dd->pdev->dev, outbuf_dma, taskout, + DMA_TO_DEVICE); kfree(outbuf); kfree(inbuf); @@ -3861,7 +3858,7 @@ skip_create_disk: set_capacity(dd->disk, capacity); /* Enable the block device and add it to /dev */ - device_add_disk(&dd->pdev->dev, dd->disk); + device_add_disk(&dd->pdev->dev, dd->disk, NULL); dd->bdev = bdget_disk(dd->disk, 0); /* @@ -4216,18 +4213,10 @@ static int mtip_pci_probe(struct pci_dev *pdev, goto iomap_err; } - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - rv = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - - if (rv) { - rv = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)); - if (rv) { - dev_warn(&pdev->dev, - "64-bit DMA enable failed\n"); - goto setmask_err; - } - } + rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rv) { + dev_warn(&pdev->dev, "64-bit DMA enable failed\n"); + goto setmask_err; } /* Copy the info we may need later into the private data structure. */ diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c index 093b614d6524..e94591021682 100644 --- a/drivers/block/null_blk_main.c +++ b/drivers/block/null_blk_main.c @@ -606,20 +606,12 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait) static void end_cmd(struct nullb_cmd *cmd) { - struct request_queue *q = NULL; int queue_mode = cmd->nq->dev->queue_mode; - if (cmd->rq) - q = cmd->rq->q; - switch (queue_mode) { case NULL_Q_MQ: blk_mq_end_request(cmd->rq, cmd->error); return; - case NULL_Q_RQ: - INIT_LIST_HEAD(&cmd->rq->queuelist); - blk_end_request_all(cmd->rq, cmd->error); - break; case NULL_Q_BIO: cmd->bio->bi_status = cmd->error; bio_endio(cmd->bio); @@ -627,15 +619,6 @@ static void end_cmd(struct nullb_cmd *cmd) } free_cmd(cmd); - - /* Restart queue if needed, as we are freeing a tag */ - if (queue_mode == NULL_Q_RQ && blk_queue_stopped(q)) { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - blk_start_queue_async(q); - spin_unlock_irqrestore(q->queue_lock, flags); - } } static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) @@ -1136,25 +1119,14 @@ static void null_stop_queue(struct nullb *nullb) if (nullb->dev->queue_mode == NULL_Q_MQ) blk_mq_stop_hw_queues(q); - else { - spin_lock_irq(q->queue_lock); - blk_stop_queue(q); - spin_unlock_irq(q->queue_lock); - } } static void null_restart_queue_async(struct nullb *nullb) { struct request_queue *q = nullb->q; - unsigned long flags; if (nullb->dev->queue_mode == NULL_Q_MQ) blk_mq_start_stopped_hw_queues(q, true); - else { - spin_lock_irqsave(q->queue_lock, flags); - blk_start_queue_async(q); - spin_unlock_irqrestore(q->queue_lock, flags); - } } static bool cmd_report_zone(struct nullb *nullb, struct nullb_cmd *cmd) @@ -1197,17 +1169,8 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd) /* race with timer */ if (atomic_long_read(&nullb->cur_bytes) > 0) null_restart_queue_async(nullb); - if (dev->queue_mode == NULL_Q_RQ) { - struct request_queue *q = nullb->q; - - spin_lock_irq(q->queue_lock); - rq->rq_flags |= RQF_DONTPREP; - blk_requeue_request(q, rq); - spin_unlock_irq(q->queue_lock); - return BLK_STS_OK; - } else - /* requeue request */ - return BLK_STS_DEV_RESOURCE; + /* requeue request */ + return BLK_STS_DEV_RESOURCE; } } @@ -1278,9 +1241,6 @@ out: case NULL_Q_MQ: blk_mq_complete_request(cmd->rq); break; - case NULL_Q_RQ: - blk_complete_request(cmd->rq); - break; case NULL_Q_BIO: /* * XXX: no proper submitting cpu information available. @@ -1349,30 +1309,6 @@ static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio) return BLK_QC_T_NONE; } -static enum blk_eh_timer_return null_rq_timed_out_fn(struct request *rq) -{ - pr_info("null: rq %p timed out\n", rq); - __blk_complete_request(rq); - return BLK_EH_DONE; -} - -static int null_rq_prep_fn(struct request_queue *q, struct request *req) -{ - struct nullb *nullb = q->queuedata; - struct nullb_queue *nq = nullb_to_queue(nullb); - struct nullb_cmd *cmd; - - cmd = alloc_cmd(nq, 0); - if (cmd) { - cmd->rq = req; - req->special = cmd; - return BLKPREP_OK; - } - blk_stop_queue(q); - - return BLKPREP_DEFER; -} - static bool should_timeout_request(struct request *rq) { #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION @@ -1391,27 +1327,6 @@ static bool should_requeue_request(struct request *rq) return false; } -static void null_request_fn(struct request_queue *q) -{ - struct request *rq; - - while ((rq = blk_fetch_request(q)) != NULL) { - struct nullb_cmd *cmd = rq->special; - - /* just ignore the request */ - if (should_timeout_request(rq)) - continue; - if (should_requeue_request(rq)) { - blk_requeue_request(q, rq); - continue; - } - - spin_unlock_irq(q->queue_lock); - null_handle_cmd(cmd); - spin_lock_irq(q->queue_lock); - } -} - static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res) { pr_info("null: rq %p timed out\n", rq); @@ -1766,24 +1681,6 @@ static int null_add_dev(struct nullb_device *dev) rv = init_driver_queues(nullb); if (rv) goto out_cleanup_blk_queue; - } else { - nullb->q = blk_init_queue_node(null_request_fn, &nullb->lock, - dev->home_node); - if (!nullb->q) { - rv = -ENOMEM; - goto out_cleanup_queues; - } - - if (!null_setup_fault()) - goto out_cleanup_blk_queue; - - blk_queue_prep_rq(nullb->q, null_rq_prep_fn); - blk_queue_softirq_done(nullb->q, null_softirq_done_fn); - blk_queue_rq_timed_out(nullb->q, null_rq_timed_out_fn); - nullb->q->rq_timeout = 5 * HZ; - rv = init_driver_queues(nullb); - if (rv) - goto out_cleanup_blk_queue; } if (dev->mbps) { @@ -1865,6 +1762,10 @@ static int __init null_init(void) return -EINVAL; } + if (g_queue_mode == NULL_Q_RQ) { + pr_err("null_blk: legacy IO path no longer available\n"); + return -EINVAL; + } if (g_queue_mode == NULL_Q_MQ && g_use_per_node_hctx) { if (g_submit_queues != nr_online_nodes) { pr_warn("null_blk: submit_queues param is set to %u.\n", diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index a026211afb51..96670eefaeb2 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -137,7 +137,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include <linux/delay.h> #include <linux/cdrom.h> #include <linux/spinlock.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/mutex.h> #include <linux/uaccess.h> @@ -186,7 +186,8 @@ static int pcd_packet(struct cdrom_device_info *cdi, static int pcd_detect(void); static void pcd_probe_capabilities(void); static void do_pcd_read_drq(void); -static void do_pcd_request(struct request_queue * q); +static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd); static void do_pcd_read(void); struct pcd_unit { @@ -199,6 +200,8 @@ struct pcd_unit { char *name; /* pcd0, pcd1, etc */ struct cdrom_device_info info; /* uniform cdrom interface */ struct gendisk *disk; + struct blk_mq_tag_set tag_set; + struct list_head rq_list; }; static struct pcd_unit pcd[PCD_UNITS]; @@ -292,6 +295,10 @@ static const struct cdrom_device_ops pcd_dops = { CDC_CD_RW, }; +static const struct blk_mq_ops pcd_mq_ops = { + .queue_rq = pcd_queue_rq, +}; + static void pcd_init_units(void) { struct pcd_unit *cd; @@ -300,13 +307,19 @@ static void pcd_init_units(void) pcd_drive_count = 0; for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { struct gendisk *disk = alloc_disk(1); + if (!disk) continue; - disk->queue = blk_init_queue(do_pcd_request, &pcd_lock); - if (!disk->queue) { - put_disk(disk); + + disk->queue = blk_mq_init_sq_queue(&cd->tag_set, &pcd_mq_ops, + 1, BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(disk->queue)) { + disk->queue = NULL; continue; } + + INIT_LIST_HEAD(&cd->rq_list); + disk->queue->queuedata = cd; blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH); cd->disk = disk; cd->pi = &cd->pia; @@ -748,18 +761,18 @@ static int pcd_queue; static int set_next_request(void) { struct pcd_unit *cd; - struct request_queue *q; int old_pos = pcd_queue; do { cd = &pcd[pcd_queue]; - q = cd->present ? cd->disk->queue : NULL; if (++pcd_queue == PCD_UNITS) pcd_queue = 0; - if (q) { - pcd_req = blk_fetch_request(q); - if (pcd_req) - break; + if (cd->present && !list_empty(&cd->rq_list)) { + pcd_req = list_first_entry(&cd->rq_list, struct request, + queuelist); + list_del_init(&pcd_req->queuelist); + blk_mq_start_request(pcd_req); + break; } } while (pcd_queue != old_pos); @@ -768,33 +781,41 @@ static int set_next_request(void) static void pcd_request(void) { + struct pcd_unit *cd; + if (pcd_busy) return; - while (1) { - if (!pcd_req && !set_next_request()) - return; - if (rq_data_dir(pcd_req) == READ) { - struct pcd_unit *cd = pcd_req->rq_disk->private_data; - if (cd != pcd_current) - pcd_bufblk = -1; - pcd_current = cd; - pcd_sector = blk_rq_pos(pcd_req); - pcd_count = blk_rq_cur_sectors(pcd_req); - pcd_buf = bio_data(pcd_req->bio); - pcd_busy = 1; - ps_set_intr(do_pcd_read, NULL, 0, nice); - return; - } else { - __blk_end_request_all(pcd_req, BLK_STS_IOERR); - pcd_req = NULL; - } - } + if (!pcd_req && !set_next_request()) + return; + + cd = pcd_req->rq_disk->private_data; + if (cd != pcd_current) + pcd_bufblk = -1; + pcd_current = cd; + pcd_sector = blk_rq_pos(pcd_req); + pcd_count = blk_rq_cur_sectors(pcd_req); + pcd_buf = bio_data(pcd_req->bio); + pcd_busy = 1; + ps_set_intr(do_pcd_read, NULL, 0, nice); } -static void do_pcd_request(struct request_queue *q) +static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { + struct pcd_unit *cd = hctx->queue->queuedata; + + if (rq_data_dir(bd->rq) != READ) { + blk_mq_start_request(bd->rq); + return BLK_STS_IOERR; + } + + spin_lock_irq(&pcd_lock); + list_add_tail(&bd->rq->queuelist, &cd->rq_list); pcd_request(); + spin_unlock_irq(&pcd_lock); + + return BLK_STS_OK; } static inline void next_request(blk_status_t err) @@ -802,8 +823,10 @@ static inline void next_request(blk_status_t err) unsigned long saved_flags; spin_lock_irqsave(&pcd_lock, saved_flags); - if (!__blk_end_request_cur(pcd_req, err)) + if (!blk_update_request(pcd_req, err, blk_rq_cur_bytes(pcd_req))) { + __blk_mq_end_request(pcd_req, err); pcd_req = NULL; + } pcd_busy = 0; pcd_request(); spin_unlock_irqrestore(&pcd_lock, saved_flags); @@ -1011,6 +1034,7 @@ static void __exit pcd_exit(void) unregister_cdrom(&cd->info); } blk_cleanup_queue(cd->disk->queue); + blk_mq_free_tag_set(&cd->tag_set); put_disk(cd->disk); } unregister_blkdev(major, name); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 7cf947586fe4..ae4971e5d9a8 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -151,7 +151,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; #include <linux/delay.h> #include <linux/hdreg.h> #include <linux/cdrom.h> /* for the eject ioctl */ -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/blkpg.h> #include <linux/kernel.h> #include <linux/mutex.h> @@ -236,6 +236,8 @@ struct pd_unit { int alt_geom; char name[PD_NAMELEN]; /* pda, pdb, etc ... */ struct gendisk *gd; + struct blk_mq_tag_set tag_set; + struct list_head rq_list; }; static struct pd_unit pd[PD_UNITS]; @@ -399,9 +401,17 @@ static int set_next_request(void) if (++pd_queue == PD_UNITS) pd_queue = 0; if (q) { - pd_req = blk_fetch_request(q); - if (pd_req) - break; + struct pd_unit *disk = q->queuedata; + + if (list_empty(&disk->rq_list)) + continue; + + pd_req = list_first_entry(&disk->rq_list, + struct request, + queuelist); + list_del_init(&pd_req->queuelist); + blk_mq_start_request(pd_req); + break; } } while (pd_queue != old_pos); @@ -412,7 +422,6 @@ static void run_fsm(void) { while (1) { enum action res; - unsigned long saved_flags; int stop = 0; if (!phase) { @@ -433,19 +442,24 @@ static void run_fsm(void) } switch(res = phase()) { - case Ok: case Fail: + case Ok: case Fail: { + blk_status_t err; + + err = res == Ok ? 0 : BLK_STS_IOERR; pi_disconnect(pi_current); pd_claimed = 0; phase = NULL; - spin_lock_irqsave(&pd_lock, saved_flags); - if (!__blk_end_request_cur(pd_req, - res == Ok ? 0 : BLK_STS_IOERR)) { - if (!set_next_request()) - stop = 1; + spin_lock_irq(&pd_lock); + if (!blk_update_request(pd_req, err, + blk_rq_cur_bytes(pd_req))) { + __blk_mq_end_request(pd_req, err); + pd_req = NULL; + stop = !set_next_request(); } - spin_unlock_irqrestore(&pd_lock, saved_flags); + spin_unlock_irq(&pd_lock); if (stop) return; + } /* fall through */ case Hold: schedule_fsm(); @@ -505,11 +519,17 @@ static int pd_next_buf(void) if (pd_count) return 0; spin_lock_irqsave(&pd_lock, saved_flags); - __blk_end_request_cur(pd_req, 0); - pd_count = blk_rq_cur_sectors(pd_req); - pd_buf = bio_data(pd_req->bio); + if (!blk_update_request(pd_req, 0, blk_rq_cur_bytes(pd_req))) { + __blk_mq_end_request(pd_req, 0); + pd_req = NULL; + pd_count = 0; + pd_buf = NULL; + } else { + pd_count = blk_rq_cur_sectors(pd_req); + pd_buf = bio_data(pd_req->bio); + } spin_unlock_irqrestore(&pd_lock, saved_flags); - return 0; + return !pd_count; } static unsigned long pd_timeout; @@ -726,15 +746,21 @@ static enum action pd_identify(struct pd_unit *disk) /* end of io request engine */ -static void do_pd_request(struct request_queue * q) +static blk_status_t pd_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - if (pd_req) - return; - pd_req = blk_fetch_request(q); - if (!pd_req) - return; + struct pd_unit *disk = hctx->queue->queuedata; + + spin_lock_irq(&pd_lock); + if (!pd_req) { + pd_req = bd->rq; + blk_mq_start_request(pd_req); + } else + list_add_tail(&bd->rq->queuelist, &disk->rq_list); + spin_unlock_irq(&pd_lock); - schedule_fsm(); + run_fsm(); + return BLK_STS_OK; } static int pd_special_command(struct pd_unit *disk, @@ -847,23 +873,33 @@ static const struct block_device_operations pd_fops = { /* probing */ +static const struct blk_mq_ops pd_mq_ops = { + .queue_rq = pd_queue_rq, +}; + static void pd_probe_drive(struct pd_unit *disk) { - struct gendisk *p = alloc_disk(1 << PD_BITS); + struct gendisk *p; + + p = alloc_disk(1 << PD_BITS); if (!p) return; + strcpy(p->disk_name, disk->name); p->fops = &pd_fops; p->major = major; p->first_minor = (disk - pd) << PD_BITS; disk->gd = p; p->private_data = disk; - p->queue = blk_init_queue(do_pd_request, &pd_lock); - if (!p->queue) { - disk->gd = NULL; - put_disk(p); + + p->queue = blk_mq_init_sq_queue(&disk->tag_set, &pd_mq_ops, 2, + BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING); + if (IS_ERR(p->queue)) { + p->queue = NULL; return; } + + p->queue->queuedata = disk; blk_queue_max_hw_sectors(p->queue, cluster); blk_queue_bounce_limit(p->queue, BLK_BOUNCE_HIGH); @@ -895,6 +931,7 @@ static int pd_detect(void) disk->standby = parm[D_SBY]; if (parm[D_PRT]) pd_drive_count++; + INIT_LIST_HEAD(&disk->rq_list); } par_drv = pi_register_driver(name); @@ -972,6 +1009,7 @@ static void __exit pd_exit(void) disk->gd = NULL; del_gendisk(p); blk_cleanup_queue(p->queue); + blk_mq_free_tag_set(&disk->tag_set); put_disk(p); pi_release(disk->pi); } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index eef7a91f667d..e92e7a8eeeb2 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -152,7 +152,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY}; #include <linux/hdreg.h> #include <linux/cdrom.h> #include <linux/spinlock.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/blkpg.h> #include <linux/mutex.h> #include <linux/uaccess.h> @@ -206,7 +206,8 @@ module_param_array(drive3, int, NULL, 0); #define ATAPI_WRITE_10 0x2a static int pf_open(struct block_device *bdev, fmode_t mode); -static void do_pf_request(struct request_queue * q); +static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd); static int pf_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg); static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo); @@ -238,6 +239,8 @@ struct pf_unit { int present; /* device present ? */ char name[PF_NAMELEN]; /* pf0, pf1, ... */ struct gendisk *disk; + struct blk_mq_tag_set tag_set; + struct list_head rq_list; }; static struct pf_unit units[PF_UNITS]; @@ -277,6 +280,10 @@ static const struct block_device_operations pf_fops = { .check_events = pf_check_events, }; +static const struct blk_mq_ops pf_mq_ops = { + .queue_rq = pf_queue_rq, +}; + static void __init pf_init_units(void) { struct pf_unit *pf; @@ -284,14 +291,22 @@ static void __init pf_init_units(void) pf_drive_count = 0; for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) { - struct gendisk *disk = alloc_disk(1); + struct gendisk *disk; + + disk = alloc_disk(1); if (!disk) continue; - disk->queue = blk_init_queue(do_pf_request, &pf_spin_lock); - if (!disk->queue) { + + disk->queue = blk_mq_init_sq_queue(&pf->tag_set, &pf_mq_ops, + 1, BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(disk->queue)) { put_disk(disk); - return; + disk->queue = NULL; + continue; } + + INIT_LIST_HEAD(&pf->rq_list); + disk->queue->queuedata = pf; blk_queue_max_segments(disk->queue, cluster); blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH); pf->disk = disk; @@ -784,18 +799,18 @@ static int pf_queue; static int set_next_request(void) { struct pf_unit *pf; - struct request_queue *q; int old_pos = pf_queue; do { pf = &units[pf_queue]; - q = pf->present ? pf->disk->queue : NULL; if (++pf_queue == PF_UNITS) pf_queue = 0; - if (q) { - pf_req = blk_fetch_request(q); - if (pf_req) - break; + if (pf->present && !list_empty(&pf->rq_list)) { + pf_req = list_first_entry(&pf->rq_list, struct request, + queuelist); + list_del_init(&pf_req->queuelist); + blk_mq_start_request(pf_req); + break; } } while (pf_queue != old_pos); @@ -804,8 +819,12 @@ static int set_next_request(void) static void pf_end_request(blk_status_t err) { - if (pf_req && !__blk_end_request_cur(pf_req, err)) + if (!pf_req) + return; + if (!blk_update_request(pf_req, err, blk_rq_cur_bytes(pf_req))) { + __blk_mq_end_request(pf_req, err); pf_req = NULL; + } } static void pf_request(void) @@ -842,9 +861,17 @@ repeat: } } -static void do_pf_request(struct request_queue *q) +static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { + struct pf_unit *pf = hctx->queue->queuedata; + + spin_lock_irq(&pf_spin_lock); + list_add_tail(&bd->rq->queuelist, &pf->rq_list); pf_request(); + spin_unlock_irq(&pf_spin_lock); + + return BLK_STS_OK; } static int pf_next_buf(void) @@ -1024,6 +1051,7 @@ static void __exit pf_exit(void) continue; del_gendisk(pf->disk); blk_cleanup_queue(pf->disk->queue); + blk_mq_free_tag_set(&pf->tag_set); put_disk(pf->disk); pi_release(pf->pi); } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 6f1d25c1eb64..9381f4e3b221 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2645,7 +2645,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, */ if (pd->refcnt == 1) pkt_lock_door(pd, 0); - /* fallthru */ + /* fall through */ /* * forward selected CDROM ioctls to CD-ROM, for UDF */ diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index afe1508d82c6..4e1d9b31f60c 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -19,7 +19,7 @@ */ #include <linux/ata.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/slab.h> #include <linux/module.h> @@ -42,6 +42,7 @@ struct ps3disk_private { spinlock_t lock; /* Request queue spinlock */ struct request_queue *queue; + struct blk_mq_tag_set tag_set; struct gendisk *gendisk; unsigned int blocking_factor; struct request *req; @@ -118,8 +119,8 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, } } -static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, - struct request *req) +static blk_status_t ps3disk_submit_request_sg(struct ps3_storage_device *dev, + struct request *req) { struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); int write = rq_data_dir(req), res; @@ -158,16 +159,15 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, __LINE__, op, res); - __blk_end_request_all(req, BLK_STS_IOERR); - return 0; + return BLK_STS_IOERR; } priv->req = req; - return 1; + return BLK_STS_OK; } -static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, - struct request *req) +static blk_status_t ps3disk_submit_flush_request(struct ps3_storage_device *dev, + struct request *req) { struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); u64 res; @@ -180,50 +180,45 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n", __func__, __LINE__, res); - __blk_end_request_all(req, BLK_STS_IOERR); - return 0; + return BLK_STS_IOERR; } priv->req = req; - return 1; + return BLK_STS_OK; } -static void ps3disk_do_request(struct ps3_storage_device *dev, - struct request_queue *q) +static blk_status_t ps3disk_do_request(struct ps3_storage_device *dev, + struct request *req) { - struct request *req; - dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); - while ((req = blk_fetch_request(q))) { - switch (req_op(req)) { - case REQ_OP_FLUSH: - if (ps3disk_submit_flush_request(dev, req)) - return; - break; - case REQ_OP_READ: - case REQ_OP_WRITE: - if (ps3disk_submit_request_sg(dev, req)) - return; - break; - default: - blk_dump_rq_flags(req, DEVICE_NAME " bad request"); - __blk_end_request_all(req, BLK_STS_IOERR); - } + switch (req_op(req)) { + case REQ_OP_FLUSH: + return ps3disk_submit_flush_request(dev, req); + case REQ_OP_READ: + case REQ_OP_WRITE: + return ps3disk_submit_request_sg(dev, req); + default: + blk_dump_rq_flags(req, DEVICE_NAME " bad request"); + return BLK_STS_IOERR; } } -static void ps3disk_request(struct request_queue *q) +static blk_status_t ps3disk_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { + struct request_queue *q = hctx->queue; struct ps3_storage_device *dev = q->queuedata; struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + blk_status_t ret; - if (priv->req) { - dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); - return; - } + blk_mq_start_request(bd->rq); + + spin_lock_irq(&priv->lock); + ret = ps3disk_do_request(dev, bd->rq); + spin_unlock_irq(&priv->lock); - ps3disk_do_request(dev, q); + return ret; } static irqreturn_t ps3disk_interrupt(int irq, void *data) @@ -280,11 +275,11 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) } spin_lock(&priv->lock); - __blk_end_request_all(req, error); priv->req = NULL; - ps3disk_do_request(dev, priv->queue); + blk_mq_end_request(req, error); spin_unlock(&priv->lock); + blk_mq_run_hw_queues(priv->queue, true); return IRQ_HANDLED; } @@ -404,6 +399,10 @@ static unsigned long ps3disk_mask; static DEFINE_MUTEX(ps3disk_mask_mutex); +static const struct blk_mq_ops ps3disk_mq_ops = { + .queue_rq = ps3disk_queue_rq, +}; + static int ps3disk_probe(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); @@ -454,11 +453,12 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev) ps3disk_identify(dev); - queue = blk_init_queue(ps3disk_request, &priv->lock); - if (!queue) { - dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n", + queue = blk_mq_init_sq_queue(&priv->tag_set, &ps3disk_mq_ops, 1, + BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(queue)) { + dev_err(&dev->sbd.core, "%s:%u: blk_mq_init_queue failed\n", __func__, __LINE__); - error = -ENOMEM; + error = PTR_ERR(queue); goto fail_teardown; } @@ -500,11 +500,12 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev) gendisk->disk_name, priv->model, priv->raw_capacity >> 11, get_capacity(gendisk) >> 11); - device_add_disk(&dev->sbd.core, gendisk); + device_add_disk(&dev->sbd.core, gendisk, NULL); return 0; fail_cleanup_queue: blk_cleanup_queue(queue); + blk_mq_free_tag_set(&priv->tag_set); fail_teardown: ps3stor_teardown(dev); fail_free_bounce: @@ -530,6 +531,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev) mutex_unlock(&ps3disk_mask_mutex); del_gendisk(priv->gendisk); blk_cleanup_queue(priv->queue); + blk_mq_free_tag_set(&priv->tag_set); put_disk(priv->gendisk); dev_notice(&dev->sbd.core, "Synchronizing disk cache\n"); ps3disk_sync_cache(dev); diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 1e3d5de9d838..c0c50816a10b 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -769,7 +769,7 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev) dev_info(&dev->core, "%s: Using %lu MiB of GPU memory\n", gendisk->disk_name, get_capacity(gendisk) >> 11); - device_add_disk(&dev->core, gendisk); + device_add_disk(&dev->core, gendisk, NULL); return 0; fail_cleanup_queue: diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index f2c631ce793c..639051502181 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -782,7 +782,7 @@ static int rsxx_pci_probe(struct pci_dev *dev, pci_set_master(dev); pci_set_dma_max_seg_size(dev, RSXX_HW_BLK_SIZE); - st = pci_set_dma_mask(dev, DMA_BIT_MASK(64)); + st = dma_set_mask(&dev->dev, DMA_BIT_MASK(64)); if (st) { dev_err(CARD_TO_DEV(card), "No usable DMA configuration,aborting\n"); diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c index c148e83e4ed7..d9a8758682c9 100644 --- a/drivers/block/rsxx/cregs.c +++ b/drivers/block/rsxx/cregs.c @@ -276,7 +276,7 @@ static void creg_cmd_done(struct work_struct *work) st = -EIO; } - if ((cmd->op == CREG_OP_READ)) { + if (cmd->op == CREG_OP_READ) { unsigned int cnt8 = ioread32(card->regmap + CREG_CNT); /* Paranoid Sanity Checks */ diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index 1a92f9e65937..3894aa0f350b 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -226,7 +226,7 @@ int rsxx_attach_dev(struct rsxx_cardinfo *card) set_capacity(card->gendisk, card->size8 >> 9); else set_capacity(card->gendisk, 0); - device_add_disk(CARD_TO_DEV(card), card->gendisk); + device_add_disk(CARD_TO_DEV(card), card->gendisk, NULL); card->bdev_attached = 1; } diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 8fbc1bf6db3d..af9cf0215164 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -224,12 +224,12 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card) static void rsxx_free_dma(struct rsxx_dma_ctrl *ctrl, struct rsxx_dma *dma) { if (dma->cmd != HW_CMD_BLK_DISCARD) { - if (!pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { - pci_unmap_page(ctrl->card->dev, dma->dma_addr, + if (!dma_mapping_error(&ctrl->card->dev->dev, dma->dma_addr)) { + dma_unmap_page(&ctrl->card->dev->dev, dma->dma_addr, get_dma_size(dma), dma->cmd == HW_CMD_BLK_WRITE ? - PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); + DMA_TO_DEVICE : + DMA_FROM_DEVICE); } } @@ -438,23 +438,23 @@ static void rsxx_issue_dmas(struct rsxx_dma_ctrl *ctrl) if (dma->cmd != HW_CMD_BLK_DISCARD) { if (dma->cmd == HW_CMD_BLK_WRITE) - dir = PCI_DMA_TODEVICE; + dir = DMA_TO_DEVICE; else - dir = PCI_DMA_FROMDEVICE; + dir = DMA_FROM_DEVICE; /* - * The function pci_map_page is placed here because we + * The function dma_map_page is placed here because we * can only, by design, issue up to 255 commands to the * hardware at one time per DMA channel. So the maximum * amount of mapped memory would be 255 * 4 channels * * 4096 Bytes which is less than 2GB, the limit of a x8 - * Non-HWWD PCIe slot. This way the pci_map_page + * Non-HWWD PCIe slot. This way the dma_map_page * function should never fail because of a lack of * mappable memory. */ - dma->dma_addr = pci_map_page(ctrl->card->dev, dma->page, + dma->dma_addr = dma_map_page(&ctrl->card->dev->dev, dma->page, dma->pg_off, dma->sub_page.cnt << 9, dir); - if (pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { + if (dma_mapping_error(&ctrl->card->dev->dev, dma->dma_addr)) { push_tracker(ctrl->trackers, tag); rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); continue; @@ -776,10 +776,10 @@ bvec_err: /*----------------- DMA Engine Initialization & Setup -------------------*/ int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl) { - ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8, - &ctrl->status.dma_addr); - ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8, - &ctrl->cmd.dma_addr); + ctrl->status.buf = dma_alloc_coherent(&dev->dev, STATUS_BUFFER_SIZE8, + &ctrl->status.dma_addr, GFP_KERNEL); + ctrl->cmd.buf = dma_alloc_coherent(&dev->dev, COMMAND_BUFFER_SIZE8, + &ctrl->cmd.dma_addr, GFP_KERNEL); if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL) return -ENOMEM; @@ -962,12 +962,12 @@ failed_dma_setup: vfree(ctrl->trackers); if (ctrl->status.buf) - pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8, - ctrl->status.buf, - ctrl->status.dma_addr); + dma_free_coherent(&card->dev->dev, STATUS_BUFFER_SIZE8, + ctrl->status.buf, + ctrl->status.dma_addr); if (ctrl->cmd.buf) - pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8, - ctrl->cmd.buf, ctrl->cmd.dma_addr); + dma_free_coherent(&card->dev->dev, COMMAND_BUFFER_SIZE8, + ctrl->cmd.buf, ctrl->cmd.dma_addr); } return st; @@ -1023,10 +1023,10 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card) vfree(ctrl->trackers); - pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8, - ctrl->status.buf, ctrl->status.dma_addr); - pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8, - ctrl->cmd.buf, ctrl->cmd.dma_addr); + dma_free_coherent(&card->dev->dev, STATUS_BUFFER_SIZE8, + ctrl->status.buf, ctrl->status.dma_addr); + dma_free_coherent(&card->dev->dev, COMMAND_BUFFER_SIZE8, + ctrl->cmd.buf, ctrl->cmd.dma_addr); } } @@ -1059,11 +1059,11 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) card->ctrl[i].stats.reads_issued--; if (dma->cmd != HW_CMD_BLK_DISCARD) { - pci_unmap_page(card->dev, dma->dma_addr, + dma_unmap_page(&card->dev->dev, dma->dma_addr, get_dma_size(dma), dma->cmd == HW_CMD_BLK_WRITE ? - PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); + DMA_TO_DEVICE : + DMA_FROM_DEVICE); } list_add_tail(&dma->list, &issued_dmas[i]); diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 87b9e7fbf062..7c5fc6942f32 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -632,7 +632,7 @@ static bool skd_preop_sg_list(struct skd_device *skdev, * Map scatterlist to PCI bus addresses. * Note PCI might change the number of entries. */ - n_sg = pci_map_sg(skdev->pdev, sgl, n_sg, skreq->data_dir); + n_sg = dma_map_sg(&skdev->pdev->dev, sgl, n_sg, skreq->data_dir); if (n_sg <= 0) return false; @@ -682,7 +682,8 @@ static void skd_postop_sg_list(struct skd_device *skdev, skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr = skreq->sksg_dma_address + ((skreq->n_sg) * sizeof(struct fit_sg_descriptor)); - pci_unmap_sg(skdev->pdev, &skreq->sg[0], skreq->n_sg, skreq->data_dir); + dma_unmap_sg(&skdev->pdev->dev, &skreq->sg[0], skreq->n_sg, + skreq->data_dir); } /* @@ -1416,7 +1417,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev, case SKD_CHECK_STATUS_BUSY_IMMINENT: skd_log_skreq(skdev, skreq, "retry(busy)"); - blk_requeue_request(skdev->queue, req); + blk_mq_requeue_request(req, true); dev_info(&skdev->pdev->dev, "drive BUSY imminent\n"); skdev->state = SKD_DRVR_STATE_BUSY_IMMINENT; skdev->timer_countdown = SKD_TIMER_MINUTES(20); @@ -1426,7 +1427,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev, case SKD_CHECK_STATUS_REQUEUE_REQUEST: if ((unsigned long) ++req->special < SKD_MAX_RETRIES) { skd_log_skreq(skdev, skreq, "retry"); - blk_requeue_request(skdev->queue, req); + blk_mq_requeue_request(req, true); break; } /* fall through */ @@ -2632,8 +2633,8 @@ static int skd_cons_skcomp(struct skd_device *skdev) "comp pci_alloc, total bytes %zd entries %d\n", SKD_SKCOMP_SIZE, SKD_N_COMPLETION_ENTRY); - skcomp = pci_zalloc_consistent(skdev->pdev, SKD_SKCOMP_SIZE, - &skdev->cq_dma_address); + skcomp = dma_zalloc_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE, + &skdev->cq_dma_address, GFP_KERNEL); if (skcomp == NULL) { rc = -ENOMEM; @@ -2674,10 +2675,10 @@ static int skd_cons_skmsg(struct skd_device *skdev) skmsg->id = i + SKD_ID_FIT_MSG; - skmsg->msg_buf = pci_alloc_consistent(skdev->pdev, - SKD_N_FITMSG_BYTES, - &skmsg->mb_dma_address); - + skmsg->msg_buf = dma_alloc_coherent(&skdev->pdev->dev, + SKD_N_FITMSG_BYTES, + &skmsg->mb_dma_address, + GFP_KERNEL); if (skmsg->msg_buf == NULL) { rc = -ENOMEM; goto err_out; @@ -2971,8 +2972,8 @@ err_out: static void skd_free_skcomp(struct skd_device *skdev) { if (skdev->skcomp_table) - pci_free_consistent(skdev->pdev, SKD_SKCOMP_SIZE, - skdev->skcomp_table, skdev->cq_dma_address); + dma_free_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE, + skdev->skcomp_table, skdev->cq_dma_address); skdev->skcomp_table = NULL; skdev->cq_dma_address = 0; @@ -2991,8 +2992,8 @@ static void skd_free_skmsg(struct skd_device *skdev) skmsg = &skdev->skmsg_table[i]; if (skmsg->msg_buf != NULL) { - pci_free_consistent(skdev->pdev, SKD_N_FITMSG_BYTES, - skmsg->msg_buf, + dma_free_coherent(&skdev->pdev->dev, SKD_N_FITMSG_BYTES, + skmsg->msg_buf, skmsg->mb_dma_address); } skmsg->msg_buf = NULL; @@ -3104,7 +3105,7 @@ static int skd_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) static int skd_bdev_attach(struct device *parent, struct skd_device *skdev) { dev_dbg(&skdev->pdev->dev, "add_disk\n"); - device_add_disk(parent, skdev->disk); + device_add_disk(parent, skdev->disk, NULL); return 0; } @@ -3172,18 +3173,12 @@ static int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rc = pci_request_regions(pdev, DRV_NAME); if (rc) goto err_out; - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (!rc) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { - dev_err(&pdev->dev, "consistent DMA mask error %d\n", - rc); - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "DMA mask error %d\n", rc); - goto err_out_regions; - } + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) { + dev_err(&pdev->dev, "DMA mask error %d\n", rc); + goto err_out_regions; } if (!skd_major) { @@ -3367,20 +3362,12 @@ static int skd_pci_resume(struct pci_dev *pdev) rc = pci_request_regions(pdev, DRV_NAME); if (rc) goto err_out; - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (!rc) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { - - dev_err(&pdev->dev, "consistent DMA mask error %d\n", - rc); - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - - dev_err(&pdev->dev, "DMA mask error %d\n", rc); - goto err_out_regions; - } + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) { + dev_err(&pdev->dev, "DMA mask error %d\n", rc); + goto err_out_regions; } pci_set_master(pdev); diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index f68e9baffad7..b54fa6726303 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -857,7 +857,7 @@ static int probe_disk(struct vdc_port *port) port->vdisk_size, (port->vdisk_size >> (20 - 9)), port->vio.ver.major, port->vio.ver.minor); - device_add_disk(&port->vio.vdev->dev, g); + device_add_disk(&port->vio.vdev->dev, g, NULL); return 0; } diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 0e31884a9519..3fa6fcc34790 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -19,7 +19,7 @@ #include <linux/module.h> #include <linux/fd.h> #include <linux/slab.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/mutex.h> #include <linux/hdreg.h> #include <linux/kernel.h> @@ -190,6 +190,7 @@ struct floppy_state { int ref_count; struct gendisk *disk; + struct blk_mq_tag_set tag_set; /* parent controller */ @@ -211,7 +212,6 @@ enum head { struct swim_priv { struct swim __iomem *base; spinlock_t lock; - int fdc_queue; int floppy_count; struct floppy_state unit[FD_MAX_UNIT]; }; @@ -525,58 +525,36 @@ static blk_status_t floppy_read_sectors(struct floppy_state *fs, return 0; } -static struct request *swim_next_request(struct swim_priv *swd) +static blk_status_t swim_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - struct request_queue *q; - struct request *rq; - int old_pos = swd->fdc_queue; + struct floppy_state *fs = hctx->queue->queuedata; + struct swim_priv *swd = fs->swd; + struct request *req = bd->rq; + blk_status_t err; - do { - q = swd->unit[swd->fdc_queue].disk->queue; - if (++swd->fdc_queue == swd->floppy_count) - swd->fdc_queue = 0; - if (q) { - rq = blk_fetch_request(q); - if (rq) - return rq; - } - } while (swd->fdc_queue != old_pos); + if (!spin_trylock_irq(&swd->lock)) + return BLK_STS_DEV_RESOURCE; - return NULL; -} + blk_mq_start_request(req); -static void do_fd_request(struct request_queue *q) -{ - struct swim_priv *swd = q->queuedata; - struct request *req; - struct floppy_state *fs; + if (!fs->disk_in || rq_data_dir(req) == WRITE) { + err = BLK_STS_IOERR; + goto out; + } - req = swim_next_request(swd); - while (req) { - blk_status_t err = BLK_STS_IOERR; + do { + err = floppy_read_sectors(fs, blk_rq_pos(req), + blk_rq_cur_sectors(req), + bio_data(req->bio)); + } while (blk_update_request(req, err, blk_rq_cur_bytes(req))); + __blk_mq_end_request(req, err); - fs = req->rq_disk->private_data; - if (blk_rq_pos(req) >= fs->total_secs) - goto done; - if (!fs->disk_in) - goto done; - if (rq_data_dir(req) == WRITE && fs->write_protected) - goto done; + err = BLK_STS_OK; +out: + spin_unlock_irq(&swd->lock); + return err; - switch (rq_data_dir(req)) { - case WRITE: - /* NOT IMPLEMENTED */ - break; - case READ: - err = floppy_read_sectors(fs, blk_rq_pos(req), - blk_rq_cur_sectors(req), - bio_data(req->bio)); - break; - } - done: - if (!__blk_end_request_cur(req, err)) - req = swim_next_request(swd); - } } static struct floppy_struct floppy_type[4] = { @@ -823,6 +801,10 @@ static int swim_add_floppy(struct swim_priv *swd, enum drive_location location) return 0; } +static const struct blk_mq_ops swim_mq_ops = { + .queue_rq = swim_queue_rq, +}; + static int swim_floppy_init(struct swim_priv *swd) { int err; @@ -852,20 +834,25 @@ static int swim_floppy_init(struct swim_priv *swd) spin_lock_init(&swd->lock); for (drive = 0; drive < swd->floppy_count; drive++) { + struct request_queue *q; + swd->unit[drive].disk = alloc_disk(1); if (swd->unit[drive].disk == NULL) { err = -ENOMEM; goto exit_put_disks; } - swd->unit[drive].disk->queue = blk_init_queue(do_fd_request, - &swd->lock); - if (!swd->unit[drive].disk->queue) { - err = -ENOMEM; + + q = blk_mq_init_sq_queue(&swd->unit[drive].tag_set, &swim_mq_ops, + 2, BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(q)) { + err = PTR_ERR(q); goto exit_put_disks; } + + swd->unit[drive].disk->queue = q; blk_queue_bounce_limit(swd->unit[drive].disk->queue, BLK_BOUNCE_HIGH); - swd->unit[drive].disk->queue->queuedata = swd; + swd->unit[drive].disk->queue->queuedata = &swd->unit[drive]; swd->unit[drive].swd = swd; } @@ -887,8 +874,18 @@ static int swim_floppy_init(struct swim_priv *swd) exit_put_disks: unregister_blkdev(FLOPPY_MAJOR, "fd"); - while (drive--) - put_disk(swd->unit[drive].disk); + do { + struct gendisk *disk = swd->unit[drive].disk; + + if (disk) { + if (disk->queue) { + blk_cleanup_queue(disk->queue); + disk->queue = NULL; + } + blk_mq_free_tag_set(&swd->unit[drive].tag_set); + put_disk(disk); + } + } while (drive--); return err; } @@ -961,6 +958,7 @@ static int swim_remove(struct platform_device *dev) for (drive = 0; drive < swd->floppy_count; drive++) { del_gendisk(swd->unit[drive].disk); blk_cleanup_queue(swd->unit[drive].disk->queue); + blk_mq_free_tag_set(&swd->unit[drive].tag_set); put_disk(swd->unit[drive].disk); } diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 469541c1e51e..c1c676a33e4a 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -25,7 +25,7 @@ #include <linux/delay.h> #include <linux/fd.h> #include <linux/ioctl.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/module.h> @@ -206,6 +206,7 @@ struct floppy_state { char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)]; int index; struct request *cur_req; + struct blk_mq_tag_set tag_set; }; #define swim3_err(fmt, arg...) dev_err(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg) @@ -260,16 +261,15 @@ static int floppy_revalidate(struct gendisk *disk); static bool swim3_end_request(struct floppy_state *fs, blk_status_t err, unsigned int nr_bytes) { struct request *req = fs->cur_req; - int rc; swim3_dbg(" end request, err=%d nr_bytes=%d, cur_req=%p\n", err, nr_bytes, req); if (err) nr_bytes = blk_rq_cur_bytes(req); - rc = __blk_end_request(req, err, nr_bytes); - if (rc) + if (blk_update_request(req, err, nr_bytes)) return true; + __blk_mq_end_request(req, err); fs->cur_req = NULL; return false; } @@ -309,86 +309,58 @@ static int swim3_readbit(struct floppy_state *fs, int bit) return (stat & DATA) == 0; } -static void start_request(struct floppy_state *fs) +static blk_status_t swim3_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - struct request *req; + struct floppy_state *fs = hctx->queue->queuedata; + struct request *req = bd->rq; unsigned long x; - swim3_dbg("start request, initial state=%d\n", fs->state); - - if (fs->state == idle && fs->wanted) { - fs->state = available; - wake_up(&fs->wait); - return; + spin_lock_irq(&swim3_lock); + if (fs->cur_req || fs->state != idle) { + spin_unlock_irq(&swim3_lock); + return BLK_STS_DEV_RESOURCE; } - while (fs->state == idle) { - swim3_dbg("start request, idle loop, cur_req=%p\n", fs->cur_req); - if (!fs->cur_req) { - fs->cur_req = blk_fetch_request(disks[fs->index]->queue); - swim3_dbg(" fetched request %p\n", fs->cur_req); - if (!fs->cur_req) - break; - } - req = fs->cur_req; - - if (fs->mdev->media_bay && - check_media_bay(fs->mdev->media_bay) != MB_FD) { - swim3_dbg("%s", " media bay absent, dropping req\n"); - swim3_end_request(fs, BLK_STS_IOERR, 0); - continue; - } - -#if 0 /* This is really too verbose */ - swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", - req->rq_disk->disk_name, req->cmd, - (long)blk_rq_pos(req), blk_rq_sectors(req), - bio_data(req->bio)); - swim3_dbg(" current_nr_sectors=%u\n", - blk_rq_cur_sectors(req)); -#endif - - if (blk_rq_pos(req) >= fs->total_secs) { - swim3_dbg(" pos out of bounds (%ld, max is %ld)\n", - (long)blk_rq_pos(req), (long)fs->total_secs); - swim3_end_request(fs, BLK_STS_IOERR, 0); - continue; - } - if (fs->ejected) { - swim3_dbg("%s", " disk ejected\n"); + blk_mq_start_request(req); + fs->cur_req = req; + if (fs->mdev->media_bay && + check_media_bay(fs->mdev->media_bay) != MB_FD) { + swim3_dbg("%s", " media bay absent, dropping req\n"); + swim3_end_request(fs, BLK_STS_IOERR, 0); + goto out; + } + if (fs->ejected) { + swim3_dbg("%s", " disk ejected\n"); + swim3_end_request(fs, BLK_STS_IOERR, 0); + goto out; + } + if (rq_data_dir(req) == WRITE) { + if (fs->write_prot < 0) + fs->write_prot = swim3_readbit(fs, WRITE_PROT); + if (fs->write_prot) { + swim3_dbg("%s", " try to write, disk write protected\n"); swim3_end_request(fs, BLK_STS_IOERR, 0); - continue; + goto out; } - - if (rq_data_dir(req) == WRITE) { - if (fs->write_prot < 0) - fs->write_prot = swim3_readbit(fs, WRITE_PROT); - if (fs->write_prot) { - swim3_dbg("%s", " try to write, disk write protected\n"); - swim3_end_request(fs, BLK_STS_IOERR, 0); - continue; - } - } - - /* Do not remove the cast. blk_rq_pos(req) is now a - * sector_t and can be 64 bits, but it will never go - * past 32 bits for this driver anyway, so we can - * safely cast it down and not have to do a 64/32 - * division - */ - fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; - x = ((long)blk_rq_pos(req)) % fs->secpercyl; - fs->head = x / fs->secpertrack; - fs->req_sector = x % fs->secpertrack + 1; - fs->state = do_transfer; - fs->retries = 0; - - act(fs); } -} -static void do_fd_request(struct request_queue * q) -{ - start_request(q->queuedata); + /* + * Do not remove the cast. blk_rq_pos(req) is now a sector_t and can be + * 64 bits, but it will never go past 32 bits for this driver anyway, so + * we can safely cast it down and not have to do a 64/32 division + */ + fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; + x = ((long)blk_rq_pos(req)) % fs->secpercyl; + fs->head = x / fs->secpertrack; + fs->req_sector = x % fs->secpertrack + 1; + fs->state = do_transfer; + fs->retries = 0; + + act(fs); + +out: + spin_unlock_irq(&swim3_lock); + return BLK_STS_OK; } static void set_timeout(struct floppy_state *fs, int nticks, @@ -585,7 +557,6 @@ static void scan_timeout(struct timer_list *t) if (fs->retries > 5) { swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; - start_request(fs); } else { fs->state = jogging; act(fs); @@ -609,7 +580,6 @@ static void seek_timeout(struct timer_list *t) swim3_err("%s", "Seek timeout\n"); swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; - start_request(fs); spin_unlock_irqrestore(&swim3_lock, flags); } @@ -638,7 +608,6 @@ static void settle_timeout(struct timer_list *t) swim3_err("%s", "Seek settle timeout\n"); swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; - start_request(fs); unlock: spin_unlock_irqrestore(&swim3_lock, flags); } @@ -667,7 +636,6 @@ static void xfer_timeout(struct timer_list *t) (long)blk_rq_pos(fs->cur_req)); swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; - start_request(fs); spin_unlock_irqrestore(&swim3_lock, flags); } @@ -704,7 +672,6 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) if (fs->retries > 5) { swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; - start_request(fs); } else { fs->state = jogging; act(fs); @@ -796,7 +763,6 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) fs->state, rq_data_dir(req), intr, err); swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; - start_request(fs); break; } fs->retries = 0; @@ -813,8 +779,6 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) } else fs->state = idle; } - if (fs->state == idle) - start_request(fs); break; default: swim3_err("Don't know what to do in state %d\n", fs->state); @@ -862,14 +826,19 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state, static void release_drive(struct floppy_state *fs) { + struct request_queue *q = disks[fs->index]->queue; unsigned long flags; swim3_dbg("%s", "-> release drive\n"); spin_lock_irqsave(&swim3_lock, flags); fs->state = idle; - start_request(fs); spin_unlock_irqrestore(&swim3_lock, flags); + + blk_mq_freeze_queue(q); + blk_mq_quiesce_queue(q); + blk_mq_unquiesce_queue(q); + blk_mq_unfreeze_queue(q); } static int fd_eject(struct floppy_state *fs) @@ -1089,6 +1058,10 @@ static const struct block_device_operations floppy_fops = { .revalidate_disk= floppy_revalidate, }; +static const struct blk_mq_ops swim3_mq_ops = { + .queue_rq = swim3_queue_rq, +}; + static void swim3_mb_event(struct macio_dev* mdev, int mb_state) { struct floppy_state *fs = macio_get_drvdata(mdev); @@ -1202,47 +1175,63 @@ static int swim3_add_device(struct macio_dev *mdev, int index) static int swim3_attach(struct macio_dev *mdev, const struct of_device_id *match) { + struct floppy_state *fs; struct gendisk *disk; - int index, rc; + int rc; - index = floppy_count++; - if (index >= MAX_FLOPPIES) + if (floppy_count >= MAX_FLOPPIES) return -ENXIO; - /* Add the drive */ - rc = swim3_add_device(mdev, index); - if (rc) - return rc; - /* Now register that disk. Same comment about failure handling */ - disk = disks[index] = alloc_disk(1); - if (disk == NULL) - return -ENOMEM; - disk->queue = blk_init_queue(do_fd_request, &swim3_lock); - if (disk->queue == NULL) { - put_disk(disk); - return -ENOMEM; + if (floppy_count == 0) { + rc = register_blkdev(FLOPPY_MAJOR, "fd"); + if (rc) + return rc; } - blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH); - disk->queue->queuedata = &floppy_states[index]; - if (index == 0) { - /* If we failed, there isn't much we can do as the driver is still - * too dumb to remove the device, just bail out - */ - if (register_blkdev(FLOPPY_MAJOR, "fd")) - return 0; + fs = &floppy_states[floppy_count]; + + disk = alloc_disk(1); + if (disk == NULL) { + rc = -ENOMEM; + goto out_unregister; + } + + disk->queue = blk_mq_init_sq_queue(&fs->tag_set, &swim3_mq_ops, 2, + BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(disk->queue)) { + rc = PTR_ERR(disk->queue); + disk->queue = NULL; + goto out_put_disk; } + blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH); + disk->queue->queuedata = fs; + + rc = swim3_add_device(mdev, floppy_count); + if (rc) + goto out_cleanup_queue; disk->major = FLOPPY_MAJOR; - disk->first_minor = index; + disk->first_minor = floppy_count; disk->fops = &floppy_fops; - disk->private_data = &floppy_states[index]; + disk->private_data = fs; disk->flags |= GENHD_FL_REMOVABLE; - sprintf(disk->disk_name, "fd%d", index); + sprintf(disk->disk_name, "fd%d", floppy_count); set_capacity(disk, 2880); add_disk(disk); + disks[floppy_count++] = disk; return 0; + +out_cleanup_queue: + blk_cleanup_queue(disk->queue); + disk->queue = NULL; + blk_mq_free_tag_set(&fs->tag_set); +out_put_disk: + put_disk(disk); +out_unregister: + if (floppy_count == 0) + unregister_blkdev(FLOPPY_MAJOR, "fd"); + return rc; } static const struct of_device_id swim3_match[] = diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 4d90e5eba2f5..064b8c5c7a32 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -16,7 +16,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/compiler.h> @@ -197,7 +197,6 @@ enum { FL_NON_RAID = FW_VER_NON_RAID, FL_4PORT = FW_VER_4PORT, FL_FW_VER_MASK = (FW_VER_NON_RAID | FW_VER_4PORT), - FL_DAC = (1 << 16), FL_DYN_MAJOR = (1 << 17), }; @@ -244,6 +243,7 @@ struct carm_port { unsigned int port_no; struct gendisk *disk; struct carm_host *host; + struct blk_mq_tag_set tag_set; /* attached device characteristics */ u64 capacity; @@ -279,6 +279,7 @@ struct carm_host { unsigned int state; u32 fw_ver; + struct blk_mq_tag_set tag_set; struct request_queue *oob_q; unsigned int n_oob; @@ -750,7 +751,7 @@ static inline void carm_end_request_queued(struct carm_host *host, struct request *req = crq->rq; int rc; - __blk_end_request_all(req, error); + blk_mq_end_request(req, error); rc = carm_put_request(host, crq); assert(rc == 0); @@ -760,7 +761,7 @@ static inline void carm_push_q (struct carm_host *host, struct request_queue *q) { unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q; - blk_stop_queue(q); + blk_mq_stop_hw_queues(q); VPRINTK("STOPPED QUEUE %p\n", q); host->wait_q[idx] = q; @@ -785,7 +786,7 @@ static inline void carm_round_robin(struct carm_host *host) { struct request_queue *q = carm_pop_q(host); if (q) { - blk_start_queue(q); + blk_mq_start_hw_queues(q); VPRINTK("STARTED QUEUE %p\n", q); } } @@ -802,82 +803,86 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, } } -static void carm_oob_rq_fn(struct request_queue *q) +static blk_status_t carm_oob_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { + struct request_queue *q = hctx->queue; struct carm_host *host = q->queuedata; struct carm_request *crq; - struct request *rq; int rc; - while (1) { - DPRINTK("get req\n"); - rq = blk_fetch_request(q); - if (!rq) - break; + blk_mq_start_request(bd->rq); - crq = rq->special; - assert(crq != NULL); - assert(crq->rq == rq); + spin_lock_irq(&host->lock); - crq->n_elem = 0; + crq = bd->rq->special; + assert(crq != NULL); + assert(crq->rq == bd->rq); - DPRINTK("send req\n"); - rc = carm_send_msg(host, crq); - if (rc) { - blk_requeue_request(q, rq); - carm_push_q(host, q); - return; /* call us again later, eventually */ - } + crq->n_elem = 0; + + DPRINTK("send req\n"); + rc = carm_send_msg(host, crq); + if (rc) { + carm_push_q(host, q); + spin_unlock_irq(&host->lock); + return BLK_STS_DEV_RESOURCE; } + + spin_unlock_irq(&host->lock); + return BLK_STS_OK; } -static void carm_rq_fn(struct request_queue *q) +static blk_status_t carm_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { + struct request_queue *q = hctx->queue; struct carm_port *port = q->queuedata; struct carm_host *host = port->host; struct carm_msg_rw *msg; struct carm_request *crq; - struct request *rq; + struct request *rq = bd->rq; struct scatterlist *sg; int writing = 0, pci_dir, i, n_elem, rc; u32 tmp; unsigned int msg_size; -queue_one_request: - VPRINTK("get req\n"); - rq = blk_peek_request(q); - if (!rq) - return; + blk_mq_start_request(rq); + + spin_lock_irq(&host->lock); crq = carm_get_request(host); if (!crq) { carm_push_q(host, q); - return; /* call us again later, eventually */ + spin_unlock_irq(&host->lock); + return BLK_STS_DEV_RESOURCE; } crq->rq = rq; - blk_start_request(rq); - if (rq_data_dir(rq) == WRITE) { writing = 1; - pci_dir = PCI_DMA_TODEVICE; + pci_dir = DMA_TO_DEVICE; } else { - pci_dir = PCI_DMA_FROMDEVICE; + pci_dir = DMA_FROM_DEVICE; } /* get scatterlist from block layer */ sg = &crq->sg[0]; n_elem = blk_rq_map_sg(q, rq, sg); if (n_elem <= 0) { + /* request with no s/g entries? */ carm_end_rq(host, crq, BLK_STS_IOERR); - return; /* request with no s/g entries? */ + spin_unlock_irq(&host->lock); + return BLK_STS_IOERR; } /* map scatterlist to PCI bus addresses */ - n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir); + n_elem = dma_map_sg(&host->pdev->dev, sg, n_elem, pci_dir); if (n_elem <= 0) { + /* request with no s/g entries? */ carm_end_rq(host, crq, BLK_STS_IOERR); - return; /* request with no s/g entries? */ + spin_unlock_irq(&host->lock); + return BLK_STS_IOERR; } crq->n_elem = n_elem; crq->port = port; @@ -927,12 +932,13 @@ queue_one_request: rc = carm_send_msg(host, crq); if (rc) { carm_put_request(host, crq); - blk_requeue_request(q, rq); carm_push_q(host, q); - return; /* call us again later, eventually */ + spin_unlock_irq(&host->lock); + return BLK_STS_DEV_RESOURCE; } - goto queue_one_request; + spin_unlock_irq(&host->lock); + return BLK_STS_OK; } static void carm_handle_array_info(struct carm_host *host, @@ -1052,11 +1058,11 @@ static inline void carm_handle_rw(struct carm_host *host, VPRINTK("ENTER\n"); if (rq_data_dir(crq->rq) == WRITE) - pci_dir = PCI_DMA_TODEVICE; + pci_dir = DMA_TO_DEVICE; else - pci_dir = PCI_DMA_FROMDEVICE; + pci_dir = DMA_FROM_DEVICE; - pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir); + dma_unmap_sg(&host->pdev->dev, &crq->sg[0], crq->n_elem, pci_dir); carm_end_rq(host, crq, error); } @@ -1485,6 +1491,14 @@ static int carm_init_host(struct carm_host *host) return 0; } +static const struct blk_mq_ops carm_oob_mq_ops = { + .queue_rq = carm_oob_queue_rq, +}; + +static const struct blk_mq_ops carm_mq_ops = { + .queue_rq = carm_queue_rq, +}; + static int carm_init_disks(struct carm_host *host) { unsigned int i; @@ -1513,9 +1527,10 @@ static int carm_init_disks(struct carm_host *host) disk->fops = &carm_bd_ops; disk->private_data = port; - q = blk_init_queue(carm_rq_fn, &host->lock); - if (!q) { - rc = -ENOMEM; + q = blk_mq_init_sq_queue(&port->tag_set, &carm_mq_ops, + max_queue, BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(q)) { + rc = PTR_ERR(q); break; } disk->queue = q; @@ -1533,14 +1548,18 @@ static void carm_free_disks(struct carm_host *host) unsigned int i; for (i = 0; i < CARM_MAX_PORTS; i++) { - struct gendisk *disk = host->port[i].disk; + struct carm_port *port = &host->port[i]; + struct gendisk *disk = port->disk; + if (disk) { struct request_queue *q = disk->queue; if (disk->flags & GENHD_FL_UP) del_gendisk(disk); - if (q) + if (q) { + blk_mq_free_tag_set(&port->tag_set); blk_cleanup_queue(q); + } put_disk(disk); } } @@ -1548,8 +1567,8 @@ static void carm_free_disks(struct carm_host *host) static int carm_init_shm(struct carm_host *host) { - host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE, - &host->shm_dma); + host->shm = dma_alloc_coherent(&host->pdev->dev, CARM_SHM_SIZE, + &host->shm_dma, GFP_KERNEL); if (!host->shm) return -ENOMEM; @@ -1565,7 +1584,6 @@ static int carm_init_shm(struct carm_host *host) static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { struct carm_host *host; - unsigned int pci_dac; int rc; struct request_queue *q; unsigned int i; @@ -1580,28 +1598,12 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out; -#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (!rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n", - pci_name(pdev)); - goto err_out_regions; - } - pci_dac = 1; - } else { -#endif - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", - pci_name(pdev)); - goto err_out_regions; - } - pci_dac = 0; -#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ + rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", + pci_name(pdev)); + goto err_out_regions; } -#endif host = kzalloc(sizeof(*host), GFP_KERNEL); if (!host) { @@ -1612,7 +1614,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) } host->pdev = pdev; - host->flags = pci_dac ? FL_DAC : 0; spin_lock_init(&host->lock); INIT_WORK(&host->fsm_task, carm_fsm_task); init_completion(&host->probe_comp); @@ -1636,12 +1637,13 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iounmap; } - q = blk_init_queue(carm_oob_rq_fn, &host->lock); - if (!q) { + q = blk_mq_init_sq_queue(&host->tag_set, &carm_oob_mq_ops, 1, + BLK_MQ_F_NO_SCHED); + if (IS_ERR(q)) { printk(KERN_ERR DRV_NAME "(%s): OOB queue alloc failure\n", pci_name(pdev)); - rc = -ENOMEM; - goto err_out_pci_free; + rc = PTR_ERR(q); + goto err_out_dma_free; } host->oob_q = q; q->queuedata = host; @@ -1705,8 +1707,9 @@ err_out_free_majors: else if (host->major == 161) clear_bit(1, &carm_major_alloc); blk_cleanup_queue(host->oob_q); -err_out_pci_free: - pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); + blk_mq_free_tag_set(&host->tag_set); +err_out_dma_free: + dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma); err_out_iounmap: iounmap(host->mmio); err_out_kfree: @@ -1736,7 +1739,8 @@ static void carm_remove_one (struct pci_dev *pdev) else if (host->major == 161) clear_bit(1, &carm_major_alloc); blk_cleanup_queue(host->oob_q); - pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); + blk_mq_free_tag_set(&host->tag_set); + dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma); iounmap(host->mmio); kfree(host); pci_release_regions(pdev); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 5c7fb8cc4149..be3e3ab79950 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -363,12 +363,12 @@ static int add_bio(struct cardinfo *card) vec = bio_iter_iovec(bio, card->current_iter); - dma_handle = pci_map_page(card->dev, + dma_handle = dma_map_page(&card->dev->dev, vec.bv_page, vec.bv_offset, vec.bv_len, bio_op(bio) == REQ_OP_READ ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + DMA_FROM_DEVICE : DMA_TO_DEVICE); p = &card->mm_pages[card->Ready]; desc = &p->desc[p->cnt]; @@ -421,7 +421,7 @@ static void process_page(unsigned long data) struct cardinfo *card = (struct cardinfo *)data; unsigned int dma_status = card->dma_status; - spin_lock_bh(&card->lock); + spin_lock(&card->lock); if (card->Active < 0) goto out_unlock; page = &card->mm_pages[card->Active]; @@ -448,10 +448,10 @@ static void process_page(unsigned long data) page->iter = page->bio->bi_iter; } - pci_unmap_page(card->dev, desc->data_dma_handle, + dma_unmap_page(&card->dev->dev, desc->data_dma_handle, vec.bv_len, (control & DMASCR_TRANSFER_READ) ? - PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + DMA_TO_DEVICE : DMA_FROM_DEVICE); if (control & DMASCR_HARD_ERROR) { /* error */ bio->bi_status = BLK_STS_IOERR; @@ -496,7 +496,7 @@ static void process_page(unsigned long data) mm_start_io(card); } out_unlock: - spin_unlock_bh(&card->lock); + spin_unlock(&card->lock); while (return_bio) { struct bio *bio = return_bio; @@ -817,8 +817,8 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) dev_printk(KERN_INFO, &dev->dev, "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n"); - if (pci_set_dma_mask(dev, DMA_BIT_MASK(64)) && - pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&dev->dev, DMA_BIT_MASK(64)) && + dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) { dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n"); return -ENOMEM; } @@ -871,12 +871,10 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto failed_magic; } - card->mm_pages[0].desc = pci_alloc_consistent(card->dev, - PAGE_SIZE * 2, - &card->mm_pages[0].page_dma); - card->mm_pages[1].desc = pci_alloc_consistent(card->dev, - PAGE_SIZE * 2, - &card->mm_pages[1].page_dma); + card->mm_pages[0].desc = dma_alloc_coherent(&card->dev->dev, + PAGE_SIZE * 2, &card->mm_pages[0].page_dma, GFP_KERNEL); + card->mm_pages[1].desc = dma_alloc_coherent(&card->dev->dev, + PAGE_SIZE * 2, &card->mm_pages[1].page_dma, GFP_KERNEL); if (card->mm_pages[0].desc == NULL || card->mm_pages[1].desc == NULL) { dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n"); @@ -1002,13 +1000,13 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) failed_req_irq: failed_alloc: if (card->mm_pages[0].desc) - pci_free_consistent(card->dev, PAGE_SIZE*2, - card->mm_pages[0].desc, - card->mm_pages[0].page_dma); + dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, + card->mm_pages[0].desc, + card->mm_pages[0].page_dma); if (card->mm_pages[1].desc) - pci_free_consistent(card->dev, PAGE_SIZE*2, - card->mm_pages[1].desc, - card->mm_pages[1].page_dma); + dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, + card->mm_pages[1].desc, + card->mm_pages[1].page_dma); failed_magic: iounmap(card->csr_remap); failed_remap_csr: @@ -1027,11 +1025,11 @@ static void mm_pci_remove(struct pci_dev *dev) iounmap(card->csr_remap); if (card->mm_pages[0].desc) - pci_free_consistent(card->dev, PAGE_SIZE*2, + dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, card->mm_pages[0].desc, card->mm_pages[0].page_dma); if (card->mm_pages[1].desc) - pci_free_consistent(card->dev, PAGE_SIZE*2, + dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2, card->mm_pages[1].desc, card->mm_pages[1].page_dma); blk_cleanup_queue(card->queue); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 23752dc99b00..086c6bb12baa 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -351,8 +351,8 @@ static int minor_to_index(int minor) return minor >> PART_BITS; } -static ssize_t virtblk_serial_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t serial_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gendisk *disk = dev_to_disk(dev); int err; @@ -371,7 +371,7 @@ static ssize_t virtblk_serial_show(struct device *dev, return err; } -static DEVICE_ATTR(serial, 0444, virtblk_serial_show, NULL); +static DEVICE_ATTR_RO(serial); /* The queue's logical block size must be set before calling this */ static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize) @@ -545,8 +545,8 @@ static const char *const virtblk_cache_types[] = { }; static ssize_t -virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +cache_type_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct gendisk *disk = dev_to_disk(dev); struct virtio_blk *vblk = disk->private_data; @@ -564,8 +564,7 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, } static ssize_t -virtblk_cache_type_show(struct device *dev, struct device_attribute *attr, - char *buf) +cache_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct gendisk *disk = dev_to_disk(dev); struct virtio_blk *vblk = disk->private_data; @@ -575,12 +574,38 @@ virtblk_cache_type_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]); } -static const struct device_attribute dev_attr_cache_type_ro = - __ATTR(cache_type, 0444, - virtblk_cache_type_show, NULL); -static const struct device_attribute dev_attr_cache_type_rw = - __ATTR(cache_type, 0644, - virtblk_cache_type_show, virtblk_cache_type_store); +static DEVICE_ATTR_RW(cache_type); + +static struct attribute *virtblk_attrs[] = { + &dev_attr_serial.attr, + &dev_attr_cache_type.attr, + NULL, +}; + +static umode_t virtblk_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct gendisk *disk = dev_to_disk(dev); + struct virtio_blk *vblk = disk->private_data; + struct virtio_device *vdev = vblk->vdev; + + if (a == &dev_attr_cache_type.attr && + !virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) + return S_IRUGO; + + return a->mode; +} + +static const struct attribute_group virtblk_attr_group = { + .attrs = virtblk_attrs, + .is_visible = virtblk_attrs_are_visible, +}; + +static const struct attribute_group *virtblk_attr_groups[] = { + &virtblk_attr_group, + NULL, +}; static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx, unsigned int numa_node) @@ -780,24 +805,9 @@ static int virtblk_probe(struct virtio_device *vdev) virtblk_update_capacity(vblk, false); virtio_device_ready(vdev); - device_add_disk(&vdev->dev, vblk->disk); - err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial); - if (err) - goto out_del_disk; - - if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) - err = device_create_file(disk_to_dev(vblk->disk), - &dev_attr_cache_type_rw); - else - err = device_create_file(disk_to_dev(vblk->disk), - &dev_attr_cache_type_ro); - if (err) - goto out_del_disk; + device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); return 0; -out_del_disk: - del_gendisk(vblk->disk); - blk_cleanup_queue(vblk->disk->queue); out_free_tags: blk_mq_free_tag_set(&vblk->tag_set); out_put_disk: diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 429d20131c7e..9eea83ae01c6 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -2420,7 +2420,7 @@ static void blkfront_connect(struct blkfront_info *info) for (i = 0; i < info->nr_rings; i++) kick_pending_request_queues(&info->rinfo[i]); - device_add_disk(&info->xbdev->dev, info->gd); + device_add_disk(&info->xbdev->dev, info->gd, NULL); info->is_ready = 1; return; diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index c24589414c75..87ccef4bd69e 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -88,7 +88,7 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/mutex.h> #include <linux/ata.h> #include <linux/hdreg.h> @@ -209,6 +209,8 @@ struct ace_device { struct device *dev; struct request_queue *queue; struct gendisk *gd; + struct blk_mq_tag_set tag_set; + struct list_head rq_list; /* Inserted CF card parameters */ u16 cf_id[ATA_ID_WORDS]; @@ -462,18 +464,26 @@ static inline void ace_fsm_yieldirq(struct ace_device *ace) ace->fsm_continue_flag = 0; } +static bool ace_has_next_request(struct request_queue *q) +{ + struct ace_device *ace = q->queuedata; + + return !list_empty(&ace->rq_list); +} + /* Get the next read/write request; ending requests that we don't handle */ static struct request *ace_get_next_request(struct request_queue *q) { - struct request *req; + struct ace_device *ace = q->queuedata; + struct request *rq; - while ((req = blk_peek_request(q)) != NULL) { - if (!blk_rq_is_passthrough(req)) - break; - blk_start_request(req); - __blk_end_request_all(req, BLK_STS_IOERR); + rq = list_first_entry_or_null(&ace->rq_list, struct request, queuelist); + if (rq) { + list_del_init(&rq->queuelist); + blk_mq_start_request(rq); } - return req; + + return NULL; } static void ace_fsm_dostate(struct ace_device *ace) @@ -499,11 +509,11 @@ static void ace_fsm_dostate(struct ace_device *ace) /* Drop all in-flight and pending requests */ if (ace->req) { - __blk_end_request_all(ace->req, BLK_STS_IOERR); + blk_mq_end_request(ace->req, BLK_STS_IOERR); ace->req = NULL; } - while ((req = blk_fetch_request(ace->queue)) != NULL) - __blk_end_request_all(req, BLK_STS_IOERR); + while ((req = ace_get_next_request(ace->queue)) != NULL) + blk_mq_end_request(req, BLK_STS_IOERR); /* Drop back to IDLE state and notify waiters */ ace->fsm_state = ACE_FSM_STATE_IDLE; @@ -517,7 +527,7 @@ static void ace_fsm_dostate(struct ace_device *ace) switch (ace->fsm_state) { case ACE_FSM_STATE_IDLE: /* See if there is anything to do */ - if (ace->id_req_count || ace_get_next_request(ace->queue)) { + if (ace->id_req_count || ace_has_next_request(ace->queue)) { ace->fsm_iter_num++; ace->fsm_state = ACE_FSM_STATE_REQ_LOCK; mod_timer(&ace->stall_timer, jiffies + HZ); @@ -651,7 +661,6 @@ static void ace_fsm_dostate(struct ace_device *ace) ace->fsm_state = ACE_FSM_STATE_IDLE; break; } - blk_start_request(req); /* Okay, it's a data request, set it up for transfer */ dev_dbg(ace->dev, @@ -728,7 +737,8 @@ static void ace_fsm_dostate(struct ace_device *ace) } /* bio finished; is there another one? */ - if (__blk_end_request_cur(ace->req, BLK_STS_OK)) { + if (blk_update_request(ace->req, BLK_STS_OK, + blk_rq_cur_bytes(ace->req))) { /* dev_dbg(ace->dev, "next block; h=%u c=%u\n", * blk_rq_sectors(ace->req), * blk_rq_cur_sectors(ace->req)); @@ -854,17 +864,23 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id) /* --------------------------------------------------------------------- * Block ops */ -static void ace_request(struct request_queue * q) +static blk_status_t ace_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - struct request *req; - struct ace_device *ace; - - req = ace_get_next_request(q); + struct ace_device *ace = hctx->queue->queuedata; + struct request *req = bd->rq; - if (req) { - ace = req->rq_disk->private_data; - tasklet_schedule(&ace->fsm_tasklet); + if (blk_rq_is_passthrough(req)) { + blk_mq_start_request(req); + return BLK_STS_IOERR; } + + spin_lock_irq(&ace->lock); + list_add_tail(&req->queuelist, &ace->rq_list); + spin_unlock_irq(&ace->lock); + + tasklet_schedule(&ace->fsm_tasklet); + return BLK_STS_OK; } static unsigned int ace_check_events(struct gendisk *gd, unsigned int clearing) @@ -957,6 +973,10 @@ static const struct block_device_operations ace_fops = { .getgeo = ace_getgeo, }; +static const struct blk_mq_ops ace_mq_ops = { + .queue_rq = ace_queue_rq, +}; + /* -------------------------------------------------------------------- * SystemACE device setup/teardown code */ @@ -972,6 +992,7 @@ static int ace_setup(struct ace_device *ace) spin_lock_init(&ace->lock); init_completion(&ace->id_completion); + INIT_LIST_HEAD(&ace->rq_list); /* * Map the device @@ -989,9 +1010,15 @@ static int ace_setup(struct ace_device *ace) /* * Initialize the request queue */ - ace->queue = blk_init_queue(ace_request, &ace->lock); - if (ace->queue == NULL) + ace->queue = blk_mq_init_sq_queue(&ace->tag_set, &ace_mq_ops, 2, + BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(ace->queue)) { + rc = PTR_ERR(ace->queue); + ace->queue = NULL; goto err_blk_initq; + } + ace->queue->queuedata = ace; + blk_queue_logical_block_size(ace->queue, 512); blk_queue_bounce_limit(ace->queue, BLK_BOUNCE_HIGH); @@ -1066,6 +1093,7 @@ err_read: put_disk(ace->gd); err_alloc_disk: blk_cleanup_queue(ace->queue); + blk_mq_free_tag_set(&ace->tag_set); err_blk_initq: iounmap(ace->baseaddr); err_ioremap: @@ -1081,8 +1109,10 @@ static void ace_teardown(struct ace_device *ace) put_disk(ace->gd); } - if (ace->queue) + if (ace->queue) { blk_cleanup_queue(ace->queue); + blk_mq_free_tag_set(&ace->tag_set); + } tasklet_kill(&ace->fsm_tasklet); diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index d0c5bc4e0703..1106c076fa4b 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -31,7 +31,7 @@ #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/bitops.h> #include <linux/mutex.h> #include <linux/slab.h> @@ -66,43 +66,44 @@ static DEFINE_SPINLOCK(z2ram_lock); static struct gendisk *z2ram_gendisk; -static void do_z2_request(struct request_queue *q) +static blk_status_t z2_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { - struct request *req; - - req = blk_fetch_request(q); - while (req) { - unsigned long start = blk_rq_pos(req) << 9; - unsigned long len = blk_rq_cur_bytes(req); - blk_status_t err = BLK_STS_OK; - - if (start + len > z2ram_size) { - pr_err(DEVICE_NAME ": bad access: block=%llu, " - "count=%u\n", - (unsigned long long)blk_rq_pos(req), - blk_rq_cur_sectors(req)); - err = BLK_STS_IOERR; - goto done; - } - while (len) { - unsigned long addr = start & Z2RAM_CHUNKMASK; - unsigned long size = Z2RAM_CHUNKSIZE - addr; - void *buffer = bio_data(req->bio); - - if (len < size) - size = len; - addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ]; - if (rq_data_dir(req) == READ) - memcpy(buffer, (char *)addr, size); - else - memcpy((char *)addr, buffer, size); - start += size; - len -= size; - } - done: - if (!__blk_end_request_cur(req, err)) - req = blk_fetch_request(q); + struct request *req = bd->rq; + unsigned long start = blk_rq_pos(req) << 9; + unsigned long len = blk_rq_cur_bytes(req); + + blk_mq_start_request(req); + + if (start + len > z2ram_size) { + pr_err(DEVICE_NAME ": bad access: block=%llu, " + "count=%u\n", + (unsigned long long)blk_rq_pos(req), + blk_rq_cur_sectors(req)); + return BLK_STS_IOERR; + } + + spin_lock_irq(&z2ram_lock); + + while (len) { + unsigned long addr = start & Z2RAM_CHUNKMASK; + unsigned long size = Z2RAM_CHUNKSIZE - addr; + void *buffer = bio_data(req->bio); + + if (len < size) + size = len; + addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ]; + if (rq_data_dir(req) == READ) + memcpy(buffer, (char *)addr, size); + else + memcpy((char *)addr, buffer, size); + start += size; + len -= size; } + + spin_unlock_irq(&z2ram_lock); + blk_mq_end_request(req, BLK_STS_OK); + return BLK_STS_OK; } static void @@ -337,6 +338,11 @@ static struct kobject *z2_find(dev_t dev, int *part, void *data) } static struct request_queue *z2_queue; +static struct blk_mq_tag_set tag_set; + +static const struct blk_mq_ops z2_mq_ops = { + .queue_rq = z2_queue_rq, +}; static int __init z2_init(void) @@ -355,9 +361,13 @@ z2_init(void) if (!z2ram_gendisk) goto out_disk; - z2_queue = blk_init_queue(do_z2_request, &z2ram_lock); - if (!z2_queue) + z2_queue = blk_mq_init_sq_queue(&tag_set, &z2_mq_ops, 16, + BLK_MQ_F_SHOULD_MERGE); + if (IS_ERR(z2_queue)) { + ret = PTR_ERR(z2_queue); + z2_queue = NULL; goto out_queue; + } z2ram_gendisk->major = Z2RAM_MAJOR; z2ram_gendisk->first_minor = 0; @@ -387,6 +397,7 @@ static void __exit z2_exit(void) del_gendisk(z2ram_gendisk); put_disk(z2ram_gendisk); blk_cleanup_queue(z2_queue); + blk_mq_free_tag_set(&tag_set); if ( current_device != -1 ) { diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig index 635235759a0a..fcd055457364 100644 --- a/drivers/block/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -3,7 +3,6 @@ config ZRAM tristate "Compressed RAM block device support" depends on BLOCK && SYSFS && ZSMALLOC && CRYPTO select CRYPTO_LZO - default n help Creates virtual block devices called /dev/zramX (X = 0, 1, ...). Pages written to these disks are compressed and stored in memory @@ -18,7 +17,6 @@ config ZRAM config ZRAM_WRITEBACK bool "Write back incompressible page to backing device" depends on ZRAM - default n help With incompressible page, there is no memory saving to keep it in memory. Instead, write it out to backing device. diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index a1d6b5597c17..4879595200e1 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1636,6 +1636,11 @@ static const struct attribute_group zram_disk_attr_group = { .attrs = zram_disk_attrs, }; +static const struct attribute_group *zram_disk_attr_groups[] = { + &zram_disk_attr_group, + NULL, +}; + /* * Allocate and initialize new zram device. the function returns * '>= 0' device_id upon success, and negative value otherwise. @@ -1716,24 +1721,14 @@ static int zram_add(void) zram->disk->queue->backing_dev_info->capabilities |= (BDI_CAP_STABLE_WRITES | BDI_CAP_SYNCHRONOUS_IO); - add_disk(zram->disk); - - ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj, - &zram_disk_attr_group); - if (ret < 0) { - pr_err("Error creating sysfs group for device %d\n", - device_id); - goto out_free_disk; - } + device_add_disk(NULL, zram->disk, zram_disk_attr_groups); + strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor)); zram_debugfs_register(zram); pr_info("Added device: %s\n", zram->disk->disk_name); return device_id; -out_free_disk: - del_gendisk(zram->disk); - put_disk(zram->disk); out_free_queue: blk_cleanup_queue(queue); out_free_idr: @@ -1762,15 +1757,6 @@ static int zram_remove(struct zram *zram) mutex_unlock(&bdev->bd_mutex); zram_debugfs_unregister(zram); - /* - * Remove sysfs first, so no one will perform a disksize - * store while we destroy the devices. This also helps during - * hot_remove -- zram_reset_device() is the last holder of - * ->init_lock, no later/concurrent disksize_store() or any - * other sysfs handlers are possible. - */ - sysfs_remove_group(&disk_to_dev(zram->disk)->kobj, - &zram_disk_attr_group); /* Make sure all the pending I/O are finished */ fsync_bdev(bdev); diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c index 073fd9011154..9989ce904a37 100644 --- a/drivers/bus/ts-nbus.c +++ b/drivers/bus/ts-nbus.c @@ -110,13 +110,12 @@ static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction) */ static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus) { - int i; - int values[8]; + DECLARE_BITMAP(values, 8); - for (i = 0; i < 8; i++) - values[i] = 0; + values[0] = 0; - gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, values); + gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, + ts_nbus->data->info, values); gpiod_set_value_cansleep(ts_nbus->csn, 0); gpiod_set_value_cansleep(ts_nbus->strobe, 0); gpiod_set_value_cansleep(ts_nbus->ale, 0); @@ -157,16 +156,11 @@ static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val) static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte) { struct gpio_descs *gpios = ts_nbus->data; - int i; - int values[8]; + DECLARE_BITMAP(values, 8); - for (i = 0; i < 8; i++) - if (byte & BIT(i)) - values[i] = 1; - else - values[i] = 0; + values[0] = byte; - gpiod_set_array_value_cansleep(8, gpios->desc, values); + gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, values); } /* diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index a5d5a96479bf..614ecdbb4ab7 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -410,10 +410,10 @@ static int cdrom_get_disc_info(struct cdrom_device_info *cdi, * hack to have the capability flags defined const, while we can still * change it here without gcc complaining at every line. */ -#define ENSURE(call, bits) \ -do { \ - if (cdo->call == NULL) \ - *change_capability &= ~(bits); \ +#define ENSURE(cdo, call, bits) \ +do { \ + if (cdo->call == NULL) \ + WARN_ON_ONCE((cdo)->capability & (bits)); \ } while (0) /* @@ -589,7 +589,6 @@ int register_cdrom(struct cdrom_device_info *cdi) { static char banner_printed; const struct cdrom_device_ops *cdo = cdi->ops; - int *change_capability = (int *)&cdo->capability; /* hack */ cd_dbg(CD_OPEN, "entering register_cdrom\n"); @@ -601,16 +600,16 @@ int register_cdrom(struct cdrom_device_info *cdi) cdrom_sysctl_register(); } - ENSURE(drive_status, CDC_DRIVE_STATUS); + ENSURE(cdo, drive_status, CDC_DRIVE_STATUS); if (cdo->check_events == NULL && cdo->media_changed == NULL) - *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC); - ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); - ENSURE(lock_door, CDC_LOCK); - ENSURE(select_speed, CDC_SELECT_SPEED); - ENSURE(get_last_session, CDC_MULTI_SESSION); - ENSURE(get_mcn, CDC_MCN); - ENSURE(reset, CDC_RESET); - ENSURE(generic_packet, CDC_GENERIC_PACKET); + WARN_ON_ONCE(cdo->capability & (CDC_MEDIA_CHANGED | CDC_SELECT_DISC)); + ENSURE(cdo, tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); + ENSURE(cdo, lock_door, CDC_LOCK); + ENSURE(cdo, select_speed, CDC_SELECT_SPEED); + ENSURE(cdo, get_last_session, CDC_MULTI_SESSION); + ENSURE(cdo, get_mcn, CDC_MCN); + ENSURE(cdo, reset, CDC_RESET); + ENSURE(cdo, generic_packet, CDC_GENERIC_PACKET); cdi->mc_flags = 0; cdi->options = CDO_USE_FFLAGS; @@ -2445,7 +2444,7 @@ static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi, return -ENOSYS; if (arg != CDSL_CURRENT && arg != CDSL_NONE) { - if ((int)arg >= cdi->capacity) + if (arg >= cdi->capacity) return -EINVAL; } diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index ae3a7537cf0f..757e85b81879 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -31,12 +31,11 @@ #include <linux/cdrom.h> #include <linux/genhd.h> #include <linux/bio.h> -#include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/interrupt.h> #include <linux/device.h> #include <linux/mutex.h> #include <linux/wait.h> -#include <linux/workqueue.h> #include <linux/platform_device.h> #include <scsi/scsi.h> #include <asm/io.h> @@ -102,11 +101,6 @@ static int gdrom_major; static DECLARE_WAIT_QUEUE_HEAD(command_queue); static DECLARE_WAIT_QUEUE_HEAD(request_queue); -static DEFINE_SPINLOCK(gdrom_lock); -static void gdrom_readdisk_dma(struct work_struct *work); -static DECLARE_WORK(work, gdrom_readdisk_dma); -static LIST_HEAD(gdrom_deferred); - struct gdromtoc { unsigned int entry[99]; unsigned int first, last; @@ -122,6 +116,7 @@ static struct gdrom_unit { char disk_type; struct gdromtoc *toc; struct request_queue *gdrom_rq; + struct blk_mq_tag_set tag_set; } gd; struct gdrom_id { @@ -584,103 +579,83 @@ static int gdrom_set_interrupt_handlers(void) * 9 -> sectors >> 8 * 10 -> sectors */ -static void gdrom_readdisk_dma(struct work_struct *work) +static blk_status_t gdrom_readdisk_dma(struct request *req) { int block, block_cnt; blk_status_t err; struct packet_command *read_command; - struct list_head *elem, *next; - struct request *req; unsigned long timeout; - if (list_empty(&gdrom_deferred)) - return; read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL); if (!read_command) - return; /* get more memory later? */ + return BLK_STS_RESOURCE; + read_command->cmd[0] = 0x30; read_command->cmd[1] = 0x20; - spin_lock(&gdrom_lock); - list_for_each_safe(elem, next, &gdrom_deferred) { - req = list_entry(elem, struct request, queuelist); - spin_unlock(&gdrom_lock); - block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET; - block_cnt = blk_rq_sectors(req)/GD_TO_BLK; - __raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG); - __raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG); - __raw_writel(1, GDROM_DMA_DIRECTION_REG); - __raw_writel(1, GDROM_DMA_ENABLE_REG); - read_command->cmd[2] = (block >> 16) & 0xFF; - read_command->cmd[3] = (block >> 8) & 0xFF; - read_command->cmd[4] = block & 0xFF; - read_command->cmd[8] = (block_cnt >> 16) & 0xFF; - read_command->cmd[9] = (block_cnt >> 8) & 0xFF; - read_command->cmd[10] = block_cnt & 0xFF; - /* set for DMA */ - __raw_writeb(1, GDROM_ERROR_REG); - /* other registers */ - __raw_writeb(0, GDROM_SECNUM_REG); - __raw_writeb(0, GDROM_BCL_REG); - __raw_writeb(0, GDROM_BCH_REG); - __raw_writeb(0, GDROM_DSEL_REG); - __raw_writeb(0, GDROM_INTSEC_REG); - /* Wait for registers to reset after any previous activity */ - timeout = jiffies + HZ / 2; - while (gdrom_is_busy() && time_before(jiffies, timeout)) - cpu_relax(); - __raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG); - timeout = jiffies + HZ / 2; - /* Wait for packet command to finish */ - while (gdrom_is_busy() && time_before(jiffies, timeout)) - cpu_relax(); - gd.pending = 1; - gd.transfer = 1; - outsw(GDROM_DATA_REG, &read_command->cmd, 6); - timeout = jiffies + HZ / 2; - /* Wait for any pending DMA to finish */ - while (__raw_readb(GDROM_DMA_STATUS_REG) && - time_before(jiffies, timeout)) - cpu_relax(); - /* start transfer */ - __raw_writeb(1, GDROM_DMA_STATUS_REG); - wait_event_interruptible_timeout(request_queue, - gd.transfer == 0, GDROM_DEFAULT_TIMEOUT); - err = gd.transfer ? BLK_STS_IOERR : BLK_STS_OK; - gd.transfer = 0; - gd.pending = 0; - /* now seek to take the request spinlock - * before handling ending the request */ - spin_lock(&gdrom_lock); - list_del_init(&req->queuelist); - __blk_end_request_all(req, err); - } - spin_unlock(&gdrom_lock); + block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET; + block_cnt = blk_rq_sectors(req)/GD_TO_BLK; + __raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG); + __raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG); + __raw_writel(1, GDROM_DMA_DIRECTION_REG); + __raw_writel(1, GDROM_DMA_ENABLE_REG); + read_command->cmd[2] = (block >> 16) & 0xFF; + read_command->cmd[3] = (block >> 8) & 0xFF; + read_command->cmd[4] = block & 0xFF; + read_command->cmd[8] = (block_cnt >> 16) & 0xFF; + read_command->cmd[9] = (block_cnt >> 8) & 0xFF; + read_command->cmd[10] = block_cnt & 0xFF; + /* set for DMA */ + __raw_writeb(1, GDROM_ERROR_REG); + /* other registers */ + __raw_writeb(0, GDROM_SECNUM_REG); + __raw_writeb(0, GDROM_BCL_REG); + __raw_writeb(0, GDROM_BCH_REG); + __raw_writeb(0, GDROM_DSEL_REG); + __raw_writeb(0, GDROM_INTSEC_REG); + /* Wait for registers to reset after any previous activity */ + timeout = jiffies + HZ / 2; + while (gdrom_is_busy() && time_before(jiffies, timeout)) + cpu_relax(); + __raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG); + timeout = jiffies + HZ / 2; + /* Wait for packet command to finish */ + while (gdrom_is_busy() && time_before(jiffies, timeout)) + cpu_relax(); + gd.pending = 1; + gd.transfer = 1; + outsw(GDROM_DATA_REG, &read_command->cmd, 6); + timeout = jiffies + HZ / 2; + /* Wait for any pending DMA to finish */ + while (__raw_readb(GDROM_DMA_STATUS_REG) && + time_before(jiffies, timeout)) + cpu_relax(); + /* start transfer */ + __raw_writeb(1, GDROM_DMA_STATUS_REG); + wait_event_interruptible_timeout(request_queue, + gd.transfer == 0, GDROM_DEFAULT_TIMEOUT); + err = gd.transfer ? BLK_STS_IOERR : BLK_STS_OK; + gd.transfer = 0; + gd.pending = 0; + + blk_mq_end_request(req, err); kfree(read_command); + return BLK_STS_OK; } -static void gdrom_request(struct request_queue *rq) -{ - struct request *req; - - while ((req = blk_fetch_request(rq)) != NULL) { - switch (req_op(req)) { - case REQ_OP_READ: - /* - * Add to list of deferred work and then schedule - * workqueue. - */ - list_add_tail(&req->queuelist, &gdrom_deferred); - schedule_work(&work); - break; - case REQ_OP_WRITE: - pr_notice("Read only device - write request ignored\n"); - __blk_end_request_all(req, BLK_STS_IOERR); - break; - default: - printk(KERN_DEBUG "gdrom: Non-fs request ignored\n"); - __blk_end_request_all(req, BLK_STS_IOERR); - break; - } +static blk_status_t gdrom_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) +{ + blk_mq_start_request(bd->rq); + + switch (req_op(bd->rq)) { + case REQ_OP_READ: + return gdrom_readdisk_dma(bd->rq); + case REQ_OP_WRITE: + pr_notice("Read only device - write request ignored\n"); + return BLK_STS_IOERR; + default: + printk(KERN_DEBUG "gdrom: Non-fs request ignored\n"); + return BLK_STS_IOERR; } } @@ -768,6 +743,10 @@ static int probe_gdrom_setupqueue(void) return gdrom_init_dma_mode(); } +static const struct blk_mq_ops gdrom_mq_ops = { + .queue_rq = gdrom_queue_rq, +}; + /* * register this as a block device and as compliant with the * universal CD Rom driver interface @@ -811,11 +790,15 @@ static int probe_gdrom(struct platform_device *devptr) err = gdrom_set_interrupt_handlers(); if (err) goto probe_fail_cmdirq_register; - gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock); - if (!gd.gdrom_rq) { - err = -ENOMEM; + + gd.gdrom_rq = blk_mq_init_sq_queue(&gd.tag_set, &gdrom_mq_ops, 1, + BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING); + if (IS_ERR(gd.gdrom_rq)) { + rc = PTR_ERR(gd.gdrom_rq); + gd.gdrom_rq = NULL; goto probe_fail_requestq; } + blk_queue_bounce_limit(gd.gdrom_rq, BLK_BOUNCE_HIGH); err = probe_gdrom_setupqueue(); @@ -832,6 +815,7 @@ static int probe_gdrom(struct platform_device *devptr) probe_fail_toc: blk_cleanup_queue(gd.gdrom_rq); + blk_mq_free_tag_set(&gd.tag_set); probe_fail_requestq: free_irq(HW_EVENT_GDROM_DMA, &gd); free_irq(HW_EVENT_GDROM_CMD, &gd); @@ -849,8 +833,8 @@ probe_fail_no_mem: static int remove_gdrom(struct platform_device *devptr) { - flush_work(&work); blk_cleanup_queue(gd.gdrom_rq); + blk_mq_free_tag_set(&gd.tag_set); free_irq(HW_EVENT_GDROM_CMD, &gd); free_irq(HW_EVENT_GDROM_DMA, &gd); del_gendisk(gd.disk); diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 97d6856c9c0f..f3f216cdf686 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -8,6 +8,8 @@ * Author: Rocky Craig <first.last@hp.com> */ +#define DEBUG /* So dev_dbg() is always available. */ + #include <linux/kernel.h> /* For printk. */ #include <linux/string.h> #include <linux/module.h> @@ -215,11 +217,11 @@ static int bt_start_transaction(struct si_sm_data *bt, return IPMI_NOT_IN_MY_STATE_ERR; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); - printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); + dev_dbg(bt->io->dev, "+++++++++++++++++ New command\n"); + dev_dbg(bt->io->dev, "NetFn/LUN CMD [%d data]:", size - 2); for (i = 0; i < size; i ++) - printk(" %02x", data[i]); - printk("\n"); + pr_cont(" %02x", data[i]); + pr_cont("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ bt->write_data[1] = *data; /* NetFn/LUN */ @@ -260,10 +262,10 @@ static int bt_get_result(struct si_sm_data *bt, memcpy(data + 2, bt->read_data + 4, msg_len - 2); if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: result %d bytes:", msg_len); + dev_dbg(bt->io->dev, "result %d bytes:", msg_len); for (i = 0; i < msg_len; i++) - printk(" %02x", data[i]); - printk("\n"); + pr_cont(" %02x", data[i]); + pr_cont("\n"); } return msg_len; } @@ -274,8 +276,7 @@ static int bt_get_result(struct si_sm_data *bt, static void reset_flags(struct si_sm_data *bt) { if (bt_debug) - printk(KERN_WARNING "IPMI BT: flag reset %s\n", - status2txt(BT_STATUS)); + dev_dbg(bt->io->dev, "flag reset %s\n", status2txt(BT_STATUS)); if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); /* force clear */ BT_CONTROL(BT_CLR_WR_PTR); /* always reset */ @@ -301,14 +302,14 @@ static void drain_BMC2HOST(struct si_sm_data *bt) BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */ BT_CONTROL(BT_CLR_RD_PTR); /* always reset */ if (bt_debug) - printk(KERN_WARNING "IPMI BT: stale response %s; ", + dev_dbg(bt->io->dev, "stale response %s; ", status2txt(BT_STATUS)); size = BMC2HOST; for (i = 0; i < size ; i++) BMC2HOST; BT_CONTROL(BT_H_BUSY); /* now clear */ if (bt_debug) - printk("drained %d bytes\n", size + 1); + pr_cont("drained %d bytes\n", size + 1); } static inline void write_all_bytes(struct si_sm_data *bt) @@ -316,11 +317,11 @@ static inline void write_all_bytes(struct si_sm_data *bt) int i; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", + dev_dbg(bt->io->dev, "write %d bytes seq=0x%02X", bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++) - printk(" %02x", bt->write_data[i]); - printk("\n"); + pr_cont(" %02x", bt->write_data[i]); + pr_cont("\n"); } for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]); @@ -340,8 +341,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) { if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "BT: bad raw rsp len=%d\n", - bt->read_count); + dev_dbg(bt->io->dev, + "bad raw rsp len=%d\n", bt->read_count); bt->truncated = 1; return 1; /* let next XACTION START clean it up */ } @@ -352,13 +353,13 @@ static inline int read_all_bytes(struct si_sm_data *bt) if (bt_debug & BT_DEBUG_MSG) { int max = bt->read_count; - printk(KERN_WARNING "BT: got %d bytes seq=0x%02X", - max, bt->read_data[2]); + dev_dbg(bt->io->dev, + "got %d bytes seq=0x%02X", max, bt->read_data[2]); if (max > 16) max = 16; for (i = 0; i < max; i++) - printk(KERN_CONT " %02x", bt->read_data[i]); - printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ..."); + pr_cont(" %02x", bt->read_data[i]); + pr_cont("%s\n", bt->read_count == max ? "" : " ..."); } /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ @@ -368,10 +369,11 @@ static inline int read_all_bytes(struct si_sm_data *bt) return 1; if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "IPMI BT: bad packet: " - "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", - bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3], - bt->read_data[1], bt->read_data[2], bt->read_data[3]); + dev_dbg(bt->io->dev, + "IPMI BT: bad packet: want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", + bt->write_data[1] | 0x04, bt->write_data[2], + bt->write_data[3], + bt->read_data[1], bt->read_data[2], bt->read_data[3]); return 0; } @@ -394,8 +396,8 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, break; } - printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ - reason, STATE2TXT, STATUS2TXT); + dev_warn(bt->io->dev, "IPMI BT: %s in %s %s ", /* open-ended line */ + reason, STATE2TXT, STATUS2TXT); /* * Per the IPMI spec, retries are based on the sequence number @@ -403,20 +405,20 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, */ (bt->error_retries)++; if (bt->error_retries < bt->BT_CAP_retries) { - printk("%d retries left\n", + pr_cont("%d retries left\n", bt->BT_CAP_retries - bt->error_retries); bt->state = BT_STATE_RESTART; return SI_SM_CALL_WITHOUT_DELAY; } - printk(KERN_WARNING "failed %d retries, sending error response\n", - bt->BT_CAP_retries); + dev_warn(bt->io->dev, "failed %d retries, sending error response\n", + bt->BT_CAP_retries); if (!bt->nonzero_status) - printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); + dev_err(bt->io->dev, "stuck, try power cycle\n"); /* this is most likely during insmod */ else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) { - printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n"); + dev_warn(bt->io->dev, "BT reset (takes 5 secs)\n"); bt->state = BT_STATE_RESET1; return SI_SM_CALL_WITHOUT_DELAY; } @@ -452,7 +454,7 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) status = BT_STATUS; bt->nonzero_status |= status; if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) { - printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", + dev_dbg(bt->io->dev, "BT: %s %s TO=%ld - %ld\n", STATE2TXT, STATUS2TXT, bt->timeout, diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 1a486aec99b6..effab11887ca 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -818,8 +818,7 @@ static void ipmi_new_smi(int if_num, struct device *device) entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { - printk(KERN_ERR "ipmi_devintf: Unable to create the" - " ipmi class device link\n"); + pr_err("ipmi_devintf: Unable to create the ipmi class device link\n"); return; } entry->dev = dev; @@ -861,18 +860,18 @@ static int __init init_ipmi_devintf(void) if (ipmi_major < 0) return -EINVAL; - printk(KERN_INFO "ipmi device interface\n"); + pr_info("ipmi device interface\n"); ipmi_class = class_create(THIS_MODULE, "ipmi"); if (IS_ERR(ipmi_class)) { - printk(KERN_ERR "ipmi: can't register device class\n"); + pr_err("ipmi: can't register device class\n"); return PTR_ERR(ipmi_class); } rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops); if (rv < 0) { class_destroy(ipmi_class); - printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major); + pr_err("ipmi: can't get major %d\n", ipmi_major); return rv; } @@ -884,7 +883,7 @@ static int __init init_ipmi_devintf(void) if (rv) { unregister_chrdev(ipmi_major, DEVICE_NAME); class_destroy(ipmi_class); - printk(KERN_WARNING "ipmi: can't register smi watcher\n"); + pr_warn("ipmi: can't register smi watcher\n"); return rv; } diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c index e2c143861b1e..249880457b17 100644 --- a/drivers/char/ipmi/ipmi_dmi.c +++ b/drivers/char/ipmi/ipmi_dmi.c @@ -4,6 +4,9 @@ * allow autoloading of the IPMI drive based on SMBIOS entries. */ +#define pr_fmt(fmt) "%s" fmt, "ipmi:dmi: " +#define dev_fmt pr_fmt + #include <linux/ipmi.h> #include <linux/init.h> #include <linux/dmi.h> @@ -41,7 +44,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, unsigned int num_r = 1, size; struct property_entry p[5]; unsigned int pidx = 0; - char *name, *override; + char *name; int rv; enum si_type si_type; struct ipmi_dmi_info *info; @@ -49,11 +52,9 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, memset(p, 0, sizeof(p)); name = "dmi-ipmi-si"; - override = "ipmi_si"; switch (type) { case IPMI_DMI_TYPE_SSIF: name = "dmi-ipmi-ssif"; - override = "ipmi_ssif"; offset = 1; size = 1; si_type = SI_TYPE_INVALID; @@ -71,7 +72,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, si_type = SI_SMIC; break; default: - pr_err("ipmi:dmi: Invalid IPMI type: %d\n", type); + pr_err("Invalid IPMI type: %d\n", type); return; } @@ -83,7 +84,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) { - pr_warn("ipmi:dmi: Could not allocate dmi info\n"); + pr_warn("Could not allocate dmi info\n"); } else { info->si_type = si_type; info->flags = flags; @@ -95,13 +96,9 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, pdev = platform_device_alloc(name, ipmi_dmi_nr); if (!pdev) { - pr_err("ipmi:dmi: Error allocation IPMI platform device\n"); + pr_err("Error allocation IPMI platform device\n"); return; } - pdev->driver_override = kasprintf(GFP_KERNEL, "%s", - override); - if (!pdev->driver_override) - goto err; if (type == IPMI_DMI_TYPE_SSIF) { p[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", base_addr); @@ -141,22 +138,20 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, rv = platform_device_add_resources(pdev, r, num_r); if (rv) { - dev_err(&pdev->dev, - "ipmi:dmi: Unable to add resources: %d\n", rv); + dev_err(&pdev->dev, "Unable to add resources: %d\n", rv); goto err; } add_properties: rv = platform_device_add_properties(pdev, p); if (rv) { - dev_err(&pdev->dev, - "ipmi:dmi: Unable to add properties: %d\n", rv); + dev_err(&pdev->dev, "Unable to add properties: %d\n", rv); goto err; } rv = platform_device_add(pdev); if (rv) { - dev_err(&pdev->dev, "ipmi:dmi: Unable to add device: %d\n", rv); + dev_err(&pdev->dev, "Unable to add device: %d\n", rv); goto err; } @@ -217,6 +212,10 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm) slave_addr = data[DMI_IPMI_SLAVEADDR]; memcpy(&base_addr, data + DMI_IPMI_ADDR, sizeof(unsigned long)); + if (!base_addr) { + pr_err("Base address is zero, assuming no IPMI interface\n"); + return; + } if (len >= DMI_IPMI_VER2_LENGTH) { if (type == IPMI_DMI_TYPE_SSIF) { offset = 0; @@ -263,7 +262,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm) offset = 16; break; default: - pr_err("ipmi:dmi: Invalid offset: 0\n"); + pr_err("Invalid offset: 0\n"); return; } } diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index f4ea9f47230a..2e7cda08b079 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -274,8 +274,8 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, if (kcs_debug & KCS_DEBUG_MSG) { printk(KERN_DEBUG "start_kcs_transaction -"); for (i = 0; i < size; i++) - printk(" %02x", (unsigned char) (data [i])); - printk("\n"); + pr_cont(" %02x", data[i]); + pr_cont("\n"); } kcs->error_retries = 0; memcpy(kcs->write_data, data, size); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 7fc9612070a1..a74ce885b541 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -11,6 +11,9 @@ * Copyright 2002 MontaVista Software Inc. */ +#define pr_fmt(fmt) "%s" fmt, "IPMI message handler: " +#define dev_fmt pr_fmt + #include <linux/module.h> #include <linux/errno.h> #include <linux/poll.h> @@ -30,8 +33,6 @@ #include <linux/workqueue.h> #include <linux/uuid.h> -#define PFX "IPMI message handler: " - #define IPMI_DRIVER_VERSION "39.2" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); @@ -1343,7 +1344,7 @@ int ipmi_set_my_LUN(struct ipmi_user *user, user->intf->addrinfo[channel].lun = LUN & 0x3; release_ipmi_user(user, index); - return 0; + return rv; } EXPORT_SYMBOL(ipmi_set_my_LUN); @@ -1474,8 +1475,7 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; if (intf->event_msg_printed) { - dev_warn(intf->si_dev, - PFX "Event queue no longer full\n"); + dev_warn(intf->si_dev, "Event queue no longer full\n"); intf->event_msg_printed = 0; } @@ -2276,16 +2276,15 @@ static void bmc_device_id_handler(struct ipmi_smi *intf, || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) || (msg->msg.cmd != IPMI_GET_DEVICE_ID_CMD)) { dev_warn(intf->si_dev, - PFX "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n", - msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd); + "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n", + msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd); return; } rv = ipmi_demangle_device_id(msg->msg.netfn, msg->msg.cmd, msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id); if (rv) { - dev_warn(intf->si_dev, - PFX "device id demangle failed: %d\n", rv); + dev_warn(intf->si_dev, "device id demangle failed: %d\n", rv); intf->bmc->dyn_id_set = 0; } else { /* @@ -2908,8 +2907,7 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, mutex_unlock(&bmc->dyn_mutex); dev_info(intf->si_dev, - "ipmi: interfacing existing BMC (man_id: 0x%6.6x," - " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", + "interfacing existing BMC (man_id: 0x%6.6x, prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", bmc->id.manufacturer_id, bmc->id.product_id, bmc->id.device_id); @@ -2948,7 +2946,7 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, rv = platform_device_register(&bmc->pdev); if (rv) { dev_err(intf->si_dev, - PFX " Unable to register bmc device: %d\n", + "Unable to register bmc device: %d\n", rv); goto out_list_del; } @@ -2966,8 +2964,7 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, */ rv = sysfs_create_link(&intf->si_dev->kobj, &bmc->pdev.dev.kobj, "bmc"); if (rv) { - dev_err(intf->si_dev, - PFX "Unable to create bmc symlink: %d\n", rv); + dev_err(intf->si_dev, "Unable to create bmc symlink: %d\n", rv); goto out_put_bmc; } @@ -2976,8 +2973,8 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", intf_num); if (!intf->my_dev_name) { rv = -ENOMEM; - dev_err(intf->si_dev, - PFX "Unable to allocate link from BMC: %d\n", rv); + dev_err(intf->si_dev, "Unable to allocate link from BMC: %d\n", + rv); goto out_unlink1; } @@ -2986,8 +2983,8 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, if (rv) { kfree(intf->my_dev_name); intf->my_dev_name = NULL; - dev_err(intf->si_dev, - PFX "Unable to create symlink to bmc: %d\n", rv); + dev_err(intf->si_dev, "Unable to create symlink to bmc: %d\n", + rv); goto out_free_my_dev_name; } @@ -3071,7 +3068,7 @@ static void guid_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) if (msg->msg.data_len < 17) { bmc->dyn_guid_set = 0; dev_warn(intf->si_dev, - PFX "The GUID response from the BMC was too short, it was %d but should have been 17. Assuming GUID is not available.\n", + "The GUID response from the BMC was too short, it was %d but should have been 17. Assuming GUID is not available.\n", msg->msg.data_len); goto out; } @@ -3195,7 +3192,7 @@ channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) if (rv) { /* Got an error somehow, just give up. */ dev_warn(intf->si_dev, - PFX "Error sending channel information for channel %d: %d\n", + "Error sending channel information for channel %d: %d\n", intf->curr_channel, rv); intf->channel_list = intf->wchannels + set; @@ -4075,7 +4072,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf, * message. */ dev_warn(intf->si_dev, - PFX "Event queue full, discarding incoming events\n"); + "Event queue full, discarding incoming events\n"); intf->event_msg_printed = 1; } @@ -4094,7 +4091,7 @@ static int handle_bmc_rsp(struct ipmi_smi *intf, recv_msg = (struct ipmi_recv_msg *) msg->user_data; if (recv_msg == NULL) { dev_warn(intf->si_dev, - "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vender for assistance\n"); + "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vendor for assistance.\n"); return 0; } @@ -4130,7 +4127,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf, if (msg->rsp_size < 2) { /* Message is too small to be correct. */ dev_warn(intf->si_dev, - PFX "BMC returned to small a message for netfn %x cmd %x, got %d bytes\n", + "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n", (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size); /* Generate an error response for the message. */ @@ -4145,7 +4142,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf, * marginally correct. */ dev_warn(intf->si_dev, - PFX "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n", + "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n", (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp[0] >> 2, msg->rsp[1]); @@ -5035,11 +5032,11 @@ static int ipmi_init_msghandler(void) rv = driver_register(&ipmidriver.driver); if (rv) { - pr_err(PFX "Could not register IPMI driver\n"); + pr_err("Could not register IPMI driver\n"); return rv; } - pr_info("ipmi message handler version " IPMI_DRIVER_VERSION "\n"); + pr_info("version " IPMI_DRIVER_VERSION "\n"); timer_setup(&ipmi_timer, ipmi_timeout, 0); mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); @@ -5086,10 +5083,10 @@ static void __exit cleanup_ipmi(void) /* Check for buffer leaks. */ count = atomic_read(&smi_msg_inuse_count); if (count != 0) - pr_warn(PFX "SMI message count %d at exit\n", count); + pr_warn("SMI message count %d at exit\n", count); count = atomic_read(&recv_msg_inuse_count); if (count != 0) - pr_warn(PFX "recv message count %d at exit\n", count); + pr_warn("recv message count %d at exit\n", count); } module_exit(cleanup_ipmi); diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index e96500372ce2..da22a8cbe68e 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -19,7 +19,7 @@ struct ipmi_smi_powernv { u64 interface_id; - ipmi_smi_t intf; + struct ipmi_smi *intf; unsigned int irq; /** @@ -33,7 +33,7 @@ struct ipmi_smi_powernv { struct opal_ipmi_msg *opal_msg; }; -static int ipmi_powernv_start_processing(void *send_info, ipmi_smi_t intf) +static int ipmi_powernv_start_processing(void *send_info, struct ipmi_smi *intf) { struct ipmi_smi_powernv *smi = send_info; diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index f6e19410dc57..bc3a18daf97a 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -11,6 +11,9 @@ * * Copyright 2002,2004 MontaVista Software Inc. */ + +#define pr_fmt(fmt) "IPMI poweroff: " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/proc_fs.h> @@ -21,8 +24,6 @@ #include <linux/ipmi.h> #include <linux/ipmi_smi.h> -#define PFX "IPMI poweroff: " - static void ipmi_po_smi_gone(int if_num); static void ipmi_po_new_smi(int if_num, struct device *device); @@ -192,7 +193,7 @@ static void pps_poweroff_atca(struct ipmi_user *user) smi_addr.channel = IPMI_BMC_CHANNEL; smi_addr.lun = 0; - printk(KERN_INFO PFX "PPS powerdown hook used"); + pr_info("PPS powerdown hook used\n"); send_msg.netfn = IPMI_NETFN_OEM; send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; @@ -201,10 +202,9 @@ static void pps_poweroff_atca(struct ipmi_user *user) rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); - if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { - printk(KERN_ERR PFX "Unable to send ATCA ," - " IPMI error 0x%x\n", rv); - } + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) + pr_err("Unable to send ATCA, IPMI error 0x%x\n", rv); + return; } @@ -234,12 +234,10 @@ static int ipmi_atca_detect(struct ipmi_user *user) (struct ipmi_addr *) &smi_addr, &send_msg); - printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", - mfg_id, prod_id); + pr_info("ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id); if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { - printk(KERN_INFO PFX - "Installing Pigeon Point Systems Poweroff Hook\n"); + pr_info("Installing Pigeon Point Systems Poweroff Hook\n"); atca_oem_poweroff_hook = pps_poweroff_atca; } return !rv; @@ -259,7 +257,7 @@ static void ipmi_poweroff_atca(struct ipmi_user *user) smi_addr.channel = IPMI_BMC_CHANNEL; smi_addr.lun = 0; - printk(KERN_INFO PFX "Powering down via ATCA power command\n"); + pr_info("Powering down via ATCA power command\n"); /* * Power down @@ -282,8 +280,8 @@ static void ipmi_poweroff_atca(struct ipmi_user *user) * return code */ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { - printk(KERN_ERR PFX "Unable to send ATCA powerdown message," - " IPMI error 0x%x\n", rv); + pr_err("Unable to send ATCA powerdown message, IPMI error 0x%x\n", + rv); goto out; } @@ -334,7 +332,7 @@ static void ipmi_poweroff_cpi1(struct ipmi_user *user) smi_addr.channel = IPMI_BMC_CHANNEL; smi_addr.lun = 0; - printk(KERN_INFO PFX "Powering down via CPI1 power command\n"); + pr_info("Powering down via CPI1 power command\n"); /* * Get IPMI ipmb address @@ -482,7 +480,7 @@ static void ipmi_poweroff_chassis(struct ipmi_user *user) smi_addr.lun = 0; powercyclefailed: - printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", + pr_info("Powering %s via IPMI chassis control command\n", (poweroff_powercycle ? "cycle" : "down")); /* @@ -502,14 +500,14 @@ static void ipmi_poweroff_chassis(struct ipmi_user *user) if (rv) { if (poweroff_powercycle) { /* power cycle failed, default to power down */ - printk(KERN_ERR PFX "Unable to send chassis power " \ - "cycle message, IPMI error 0x%x\n", rv); + pr_err("Unable to send chassis power cycle message, IPMI error 0x%x\n", + rv); poweroff_powercycle = 0; goto powercyclefailed; } - printk(KERN_ERR PFX "Unable to send chassis power " \ - "down message, IPMI error 0x%x\n", rv); + pr_err("Unable to send chassis power down message, IPMI error 0x%x\n", + rv); } } @@ -571,8 +569,7 @@ static void ipmi_po_new_smi(int if_num, struct device *device) rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); if (rv) { - printk(KERN_ERR PFX "could not create IPMI user, error %d\n", - rv); + pr_err("could not create IPMI user, error %d\n", rv); return; } @@ -594,14 +591,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device) (struct ipmi_addr *) &smi_addr, &send_msg); if (rv) { - printk(KERN_ERR PFX "Unable to send IPMI get device id info," - " IPMI error 0x%x\n", rv); + pr_err("Unable to send IPMI get device id info, IPMI error 0x%x\n", + rv); goto out_err; } if (halt_recv_msg.msg.data_len < 12) { - printk(KERN_ERR PFX "(chassis) IPMI get device id info too," - " short, was %d bytes, needed %d bytes\n", + pr_err("(chassis) IPMI get device id info too short, was %d bytes, needed %d bytes\n", halt_recv_msg.msg.data_len, 12); goto out_err; } @@ -622,14 +618,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device) } out_err: - printk(KERN_ERR PFX "Unable to find a poweroff function that" - " will work, giving up\n"); + pr_err("Unable to find a poweroff function that will work, giving up\n"); ipmi_destroy_user(ipmi_user); return; found: - printk(KERN_INFO PFX "Found a %s style poweroff function\n", - poweroff_functions[i].platform_type); + pr_info("Found a %s style poweroff function\n", + poweroff_functions[i].platform_type); specific_poweroff_func = poweroff_functions[i].poweroff_func; old_poweroff_func = pm_power_off; pm_power_off = ipmi_poweroff_function; @@ -692,16 +687,15 @@ static int __init ipmi_poweroff_init(void) { int rv; - printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -" - " IPMI Powerdown via sys_reboot.\n"); + pr_info("Copyright (C) 2004 MontaVista Software - IPMI Powerdown via sys_reboot\n"); if (poweroff_powercycle) - printk(KERN_INFO PFX "Power cycle is enabled.\n"); + pr_info("Power cycle is enabled\n"); #ifdef CONFIG_PROC_FS ipmi_table_header = register_sysctl_table(ipmi_root_table); if (!ipmi_table_header) { - printk(KERN_ERR PFX "Unable to register powercycle sysctl\n"); + pr_err("Unable to register powercycle sysctl\n"); rv = -ENOMEM; goto out_err; } @@ -712,7 +706,7 @@ static int __init ipmi_poweroff_init(void) #ifdef CONFIG_PROC_FS if (rv) { unregister_sysctl_table(ipmi_table_header); - printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); + pr_err("Unable to register SMI watcher: %d\n", rv); goto out_err; } @@ -735,8 +729,7 @@ static void __exit ipmi_poweroff_cleanup(void) if (ready) { rv = ipmi_destroy_user(ipmi_user); if (rv) - printk(KERN_ERR PFX "could not cleanup the IPMI" - " user: 0x%x\n", rv); + pr_err("could not cleanup the IPMI user: 0x%x\n", rv); pm_power_off = old_poweroff_func; } } diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c index 10219f24546b..487642809c58 100644 --- a/drivers/char/ipmi/ipmi_si_hardcode.c +++ b/drivers/char/ipmi/ipmi_si_hardcode.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0+ +#define pr_fmt(fmt) "ipmi_hardcode: " fmt + #include <linux/moduleparam.h> #include "ipmi_si.h" -#define PFX "ipmi_hardcode: " /* * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS. @@ -100,7 +101,7 @@ int ipmi_si_hardcode_find_bmc(void) continue; io.addr_source = SI_HARDCODED; - pr_info(PFX "probing via hardcoded address\n"); + pr_info("probing via hardcoded address\n"); if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { io.si_type = SI_KCS; @@ -109,7 +110,7 @@ int ipmi_si_hardcode_find_bmc(void) } else if (strcmp(si_type[i], "bt") == 0) { io.si_type = SI_BT; } else { - pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n", + pr_warn("Interface type specified for interface %d, was invalid: %s\n", i, si_type[i]); continue; } @@ -123,7 +124,7 @@ int ipmi_si_hardcode_find_bmc(void) io.addr_data = addrs[i]; io.addr_type = IPMI_MEM_ADDR_SPACE; } else { - pr_warn(PFX "Interface type specified for interface %d, but port and address were not set or set to zero.\n", + pr_warn("Interface type specified for interface %d, but port and address were not set or set to zero\n", i); continue; } diff --git a/drivers/char/ipmi/ipmi_si_hotmod.c b/drivers/char/ipmi/ipmi_si_hotmod.c index a98ca42a50b1..c0067fd0480d 100644 --- a/drivers/char/ipmi/ipmi_si_hotmod.c +++ b/drivers/char/ipmi/ipmi_si_hotmod.c @@ -5,12 +5,13 @@ * Handling for dynamically adding/removing IPMI devices through * a module parameter (and thus sysfs). */ + +#define pr_fmt(fmt) "ipmi_hotmod: " fmt + #include <linux/moduleparam.h> #include <linux/ipmi.h> #include "ipmi_si.h" -#define PFX "ipmi_hotmod: " - static int hotmod_handler(const char *val, const struct kernel_param *kp); module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); @@ -61,7 +62,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name, s = strchr(*curr, ','); if (!s) { - pr_warn(PFX "No hotmod %s given.\n", name); + pr_warn("No hotmod %s given\n", name); return -EINVAL; } *s = '\0'; @@ -74,7 +75,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name, } } - pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr); + pr_warn("Invalid hotmod %s '%s'\n", name, *curr); return -EINVAL; } @@ -85,12 +86,12 @@ static int check_hotmod_int_op(const char *curr, const char *option, if (strcmp(curr, name) == 0) { if (!option) { - pr_warn(PFX "No option given for '%s'\n", curr); + pr_warn("No option given for '%s'\n", curr); return -EINVAL; } *val = simple_strtoul(option, &n, 0); if ((*n != '\0') || (*option == '\0')) { - pr_warn(PFX "Bad option given for '%s'\n", curr); + pr_warn("Bad option given for '%s'\n", curr); return -EINVAL; } return 1; @@ -160,7 +161,7 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp) } addr = simple_strtoul(curr, &n, 0); if ((*n != '\0') || (*curr == '\0')) { - pr_warn(PFX "Invalid hotmod address '%s'\n", curr); + pr_warn("Invalid hotmod address '%s'\n", curr); break; } @@ -203,7 +204,7 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp) continue; rv = -EINVAL; - pr_warn(PFX "Invalid hotmod option '%s'\n", curr); + pr_warn("Invalid hotmod option '%s'\n", curr); goto out; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 5faa917df1b6..677618e6f1f7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -19,6 +19,8 @@ * and drives the real SMI state machine. */ +#define pr_fmt(fmt) "ipmi_si: " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/sched.h> @@ -41,8 +43,6 @@ #include <linux/string.h> #include <linux/ctype.h> -#define PFX "ipmi_si: " - /* Measure times between events in the driver. */ #undef DEBUG_TIMING @@ -269,7 +269,7 @@ void debug_timestamp(char *msg) { struct timespec64 t; - getnstimeofday64(&t); + ktime_get_ts64(&t); pr_debug("**%s: %lld.%9.9ld\n", msg, (long long) t.tv_sec, t.tv_nsec); } #else @@ -961,12 +961,12 @@ static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result, if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY) ipmi_si_set_not_busy(busy_until); else if (!ipmi_si_is_busy(busy_until)) { - getnstimeofday64(busy_until); + ktime_get_ts64(busy_until); timespec64_add_ns(busy_until, max_busy_us*NSEC_PER_USEC); } else { struct timespec64 now; - getnstimeofday64(&now); + ktime_get_ts64(&now); if (unlikely(timespec64_compare(&now, busy_until) > 0)) { ipmi_si_set_not_busy(busy_until); return 0; @@ -1530,7 +1530,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) rv = wait_for_msg_done(smi_info); if (rv) { - pr_warn(PFX "Error getting response from get global enables command, the event buffer is not enabled.\n"); + pr_warn("Error getting response from get global enables command, the event buffer is not enabled\n"); goto out; } @@ -1541,7 +1541,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || resp[2] != 0) { - pr_warn(PFX "Invalid return from get global enables command, cannot enable the event buffer.\n"); + pr_warn("Invalid return from get global enables command, cannot enable the event buffer\n"); rv = -EINVAL; goto out; } @@ -1559,7 +1559,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) rv = wait_for_msg_done(smi_info); if (rv) { - pr_warn(PFX "Error getting response from set global, enables command, the event buffer is not enabled.\n"); + pr_warn("Error getting response from set global, enables command, the event buffer is not enabled\n"); goto out; } @@ -1569,7 +1569,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) if (resp_len < 3 || resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { - pr_warn(PFX "Invalid return from get global, enables command, not enable the event buffer.\n"); + pr_warn("Invalid return from get global, enables command, not enable the event buffer\n"); rv = -EINVAL; goto out; } @@ -1900,7 +1900,7 @@ int ipmi_si_add_smi(struct si_sm_io *io) } } - pr_info(PFX "Adding %s-specified %s state machine\n", + pr_info("Adding %s-specified %s state machine\n", ipmi_addr_src_to_str(new_smi->io.addr_source), si_to_str[new_smi->io.si_type]); @@ -1924,7 +1924,7 @@ static int try_smi_init(struct smi_info *new_smi) int i; char *init_name = NULL; - pr_info(PFX "Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n", + pr_info("Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n", ipmi_addr_src_to_str(new_smi->io.addr_source), si_to_str[new_smi->io.si_type], addr_space_to_str[new_smi->io.addr_type], @@ -1964,7 +1964,7 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->pdev = platform_device_alloc("ipmi_si", new_smi->si_num); if (!new_smi->pdev) { - pr_err(PFX "Unable to allocate platform device\n"); + pr_err("Unable to allocate platform device\n"); rv = -ENOMEM; goto out_err; } @@ -2097,7 +2097,7 @@ static int init_ipmi_si(void) if (initialized) return 0; - pr_info("IPMI System Interface driver.\n"); + pr_info("IPMI System Interface driver\n"); /* If the user gave us a device, they presumably want us to use it */ if (!ipmi_si_hardcode_find_bmc()) @@ -2151,7 +2151,7 @@ skip_fallback_noirq: if (unload_when_empty && list_empty(&smi_infos)) { mutex_unlock(&smi_infos_lock); cleanup_ipmi_si(); - pr_warn(PFX "Unable to find any System Interface(s)\n"); + pr_warn("Unable to find any System Interface(s)\n"); return -ENODEV; } else { mutex_unlock(&smi_infos_lock); diff --git a/drivers/char/ipmi/ipmi_si_mem_io.c b/drivers/char/ipmi/ipmi_si_mem_io.c index 1b869d530884..fd0ec8d6bf0e 100644 --- a/drivers/char/ipmi/ipmi_si_mem_io.c +++ b/drivers/char/ipmi/ipmi_si_mem_io.c @@ -51,7 +51,7 @@ static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) static void mem_outq(const struct si_sm_io *io, unsigned int offset, unsigned char b) { - writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); + writeq((u64)b << io->regshift, (io->addr)+(offset * io->regspacing)); } #endif diff --git a/drivers/char/ipmi/ipmi_si_pci.c b/drivers/char/ipmi/ipmi_si_pci.c index f54ca6869ed2..ce00c0da5866 100644 --- a/drivers/char/ipmi/ipmi_si_pci.c +++ b/drivers/char/ipmi/ipmi_si_pci.c @@ -4,12 +4,13 @@ * * Handling for IPMI devices on the PCI bus. */ + +#define pr_fmt(fmt) "ipmi_pci: " fmt + #include <linux/module.h> #include <linux/pci.h> #include "ipmi_si.h" -#define PFX "ipmi_pci: " - static bool pci_registered; static bool si_trypci = true; @@ -18,11 +19,6 @@ module_param_named(trypci, si_trypci, bool, 0); MODULE_PARM_DESC(trypci, "Setting this to zero will disable the" " default scan of the interfaces identified via pci"); -#define PCI_CLASS_SERIAL_IPMI 0x0c07 -#define PCI_CLASS_SERIAL_IPMI_SMIC 0x0c0700 -#define PCI_CLASS_SERIAL_IPMI_KCS 0x0c0701 -#define PCI_CLASS_SERIAL_IPMI_BT 0x0c0702 - #define PCI_DEVICE_ID_HP_MMC 0x121A static void ipmi_pci_cleanup(struct si_sm_io *io) @@ -45,8 +41,7 @@ static int ipmi_pci_probe_regspacing(struct si_sm_io *io) for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { io->regspacing = regspacing; if (io->io_setup(io)) { - dev_err(io->dev, - "Could not setup I/O space\n"); + dev_err(io->dev, "Could not setup I/O space\n"); return DEFAULT_REGSPACING; } /* write invalid cmd */ @@ -120,6 +115,8 @@ static int ipmi_pci_probe(struct pci_dev *pdev, } io.addr_data = pci_resource_start(pdev, 0); + io.dev = &pdev->dev; + io.regspacing = ipmi_pci_probe_regspacing(&io); io.regsize = DEFAULT_REGSIZE; io.regshift = 0; @@ -128,10 +125,8 @@ static int ipmi_pci_probe(struct pci_dev *pdev, if (io.irq) io.irq_setup = ipmi_std_irq_setup; - io.dev = &pdev->dev; - dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", - &pdev->resource[0], io.regsize, io.regspacing, io.irq); + &pdev->resource[0], io.regsize, io.regspacing, io.irq); rv = ipmi_si_add_smi(&io); if (rv) @@ -166,7 +161,7 @@ void ipmi_si_pci_init(void) if (si_trypci) { int rv = pci_register_driver(&ipmi_pci_driver); if (rv) - pr_err(PFX "Unable to register PCI driver: %d\n", rv); + pr_err("Unable to register PCI driver: %d\n", rv); else pci_registered = true; } diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index bf69927502bd..15cf819f884f 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -5,6 +5,10 @@ * Handling for platform devices in IPMI (ACPI, OF, and things * coming from the platform. */ + +#define pr_fmt(fmt) "ipmi_platform: " fmt +#define dev_fmt pr_fmt + #include <linux/types.h> #include <linux/module.h> #include <linux/of_device.h> @@ -15,8 +19,6 @@ #include "ipmi_si.h" #include "ipmi_dmi.h" -#define PFX "ipmi_platform: " - static bool si_tryplatform = true; #ifdef CONFIG_ACPI static bool si_tryacpi = true; @@ -158,7 +160,7 @@ static int platform_ipmi_probe(struct platform_device *pdev) memset(&io, 0, sizeof(io)); io.addr_source = addr_source; - dev_info(&pdev->dev, PFX "probing via %s\n", + dev_info(&pdev->dev, "probing via %s\n", ipmi_addr_src_to_str(addr_source)); switch (type) { @@ -236,25 +238,25 @@ static int of_ipmi_probe(struct platform_device *pdev) ret = of_address_to_resource(np, 0, &resource); if (ret) { - dev_warn(&pdev->dev, PFX "invalid address from OF\n"); + dev_warn(&pdev->dev, "invalid address from OF\n"); return ret; } regsize = of_get_property(np, "reg-size", &proplen); if (regsize && proplen != 4) { - dev_warn(&pdev->dev, PFX "invalid regsize from OF\n"); + dev_warn(&pdev->dev, "invalid regsize from OF\n"); return -EINVAL; } regspacing = of_get_property(np, "reg-spacing", &proplen); if (regspacing && proplen != 4) { - dev_warn(&pdev->dev, PFX "invalid regspacing from OF\n"); + dev_warn(&pdev->dev, "invalid regspacing from OF\n"); return -EINVAL; } regshift = of_get_property(np, "reg-shift", &proplen); if (regshift && proplen != 4) { - dev_warn(&pdev->dev, PFX "invalid regshift from OF\n"); + dev_warn(&pdev->dev, "invalid regshift from OF\n"); return -EINVAL; } @@ -326,7 +328,7 @@ static int acpi_ipmi_probe(struct platform_device *pdev) memset(&io, 0, sizeof(io)); io.addr_source = SI_ACPI; - dev_info(&pdev->dev, PFX "probing via ACPI\n"); + dev_info(&pdev->dev, "probing via ACPI\n"); io.addr_info.acpi_info.acpi_handle = handle; @@ -417,6 +419,11 @@ static int ipmi_remove(struct platform_device *pdev) return ipmi_si_remove_by_dev(&pdev->dev); } +static const struct platform_device_id si_plat_ids[] = { + { "dmi-ipmi-si", 0 }, + { } +}; + struct platform_driver ipmi_platform_driver = { .driver = { .name = DEVICE_NAME, @@ -425,13 +432,14 @@ struct platform_driver ipmi_platform_driver = { }, .probe = ipmi_probe, .remove = ipmi_remove, + .id_table = si_plat_ids }; void ipmi_si_platform_init(void) { int rv = platform_driver_register(&ipmi_platform_driver); if (rv) - pr_err(PFX "Unable to register driver: %d\n", rv); + pr_err("Unable to register driver: %d\n", rv); } void ipmi_si_platform_shutdown(void) diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index 466a5aac5298..b6225bba2532 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -132,8 +132,8 @@ static int start_smic_transaction(struct si_sm_data *smic, if (smic_debug & SMIC_DEBUG_MSG) { printk(KERN_DEBUG "start_smic_transaction -"); for (i = 0; i < size; i++) - printk(" %02x", (unsigned char) data[i]); - printk("\n"); + pr_cont(" %02x", data[i]); + pr_cont("\n"); } smic->error_retries = 0; memcpy(smic->write_data, data, size); @@ -154,8 +154,8 @@ static int smic_get_result(struct si_sm_data *smic, if (smic_debug & SMIC_DEBUG_MSG) { printk(KERN_DEBUG "smic_get result -"); for (i = 0; i < smic->read_pos; i++) - printk(" %02x", smic->read_data[i]); - printk("\n"); + pr_cont(" %02x", smic->read_data[i]); + pr_cont("\n"); } if (length < smic->read_pos) { smic->read_pos = length; @@ -212,8 +212,7 @@ static inline void start_error_recovery(struct si_sm_data *smic, char *reason) (smic->error_retries)++; if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) { if (smic_debug & SMIC_DEBUG_ENABLE) - printk(KERN_WARNING - "ipmi_smic_drv: smic hosed: %s\n", reason); + pr_warn("ipmi_smic_drv: smic hosed: %s\n", reason); smic->state = SMIC_HOSED; } else { smic->write_count = smic->orig_write_count; @@ -326,8 +325,7 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time) if (smic->state != SMIC_IDLE) { if (smic_debug & SMIC_DEBUG_STATES) printk(KERN_DEBUG - "smic_event - smic->smic_timeout = %ld," - " time = %ld\n", + "smic_event - smic->smic_timeout = %ld, time = %ld\n", smic->smic_timeout, time); /* * FIXME: smic_event is sometimes called with time > @@ -347,9 +345,7 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time) status = read_smic_status(smic); if (smic_debug & SMIC_DEBUG_STATES) - printk(KERN_DEBUG - "smic_event - state = %d, flags = 0x%02x," - " status = 0x%02x\n", + printk(KERN_DEBUG "smic_event - state = %d, flags = 0x%02x, status = 0x%02x\n", smic->state, flags, status); switch (smic->state) { @@ -440,8 +436,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time) data = read_smic_data(smic); if (data != 0) { if (smic_debug & SMIC_DEBUG_ENABLE) - printk(KERN_DEBUG - "SMIC_WRITE_END: data = %02x\n", data); + printk(KERN_DEBUG "SMIC_WRITE_END: data = %02x\n", + data); start_error_recovery(smic, "state = SMIC_WRITE_END, " "data != SUCCESS"); @@ -520,8 +516,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time) /* data register holds an error code */ if (data != 0) { if (smic_debug & SMIC_DEBUG_ENABLE) - printk(KERN_DEBUG - "SMIC_READ_END: data = %02x\n", data); + printk(KERN_DEBUG "SMIC_READ_END: data = %02x\n", + data); start_error_recovery(smic, "state = SMIC_READ_END, " "data != SUCCESS"); diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 29e67a80fb20..ca9528c4f183 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -27,6 +27,8 @@ * interface into the I2C driver, I believe. */ +#define pr_fmt(fmt) "ipmi_ssif: " fmt + #if defined(MODVERSIONS) #include <linux/modversions.h> #endif @@ -52,7 +54,6 @@ #include "ipmi_si_sm.h" #include "ipmi_dmi.h" -#define PFX "ipmi_ssif: " #define DEVICE_NAME "ipmi_ssif" #define IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD 0x57 @@ -60,6 +61,7 @@ #define SSIF_IPMI_REQUEST 2 #define SSIF_IPMI_MULTI_PART_REQUEST_START 6 #define SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE 7 +#define SSIF_IPMI_MULTI_PART_REQUEST_END 8 #define SSIF_IPMI_RESPONSE 3 #define SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE 9 @@ -271,6 +273,7 @@ struct ssif_info { /* Info from SSIF cmd */ unsigned char max_xmit_msg_size; unsigned char max_recv_msg_size; + bool cmd8_works; /* See test_multipart_messages() for details. */ unsigned int multi_support; int supports_pec; @@ -316,9 +319,8 @@ static void deliver_recv_msg(struct ssif_info *ssif_info, { if (msg->rsp_size < 0) { return_hosed_msg(ssif_info, msg); - pr_err(PFX - "Malformed message in deliver_recv_msg: rsp_size = %d\n", - msg->rsp_size); + pr_err("%s: Malformed message: rsp_size = %d\n", + __func__, msg->rsp_size); } else { ipmi_smi_msg_received(ssif_info->intf, msg); } @@ -606,8 +608,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, flags = ipmi_ssif_lock_cond(ssif_info, &oflags); ssif_info->waiting_alert = true; ssif_info->rtc_us_timer = SSIF_MSG_USEC; - mod_timer(&ssif_info->retry_timer, - jiffies + SSIF_MSG_JIFFIES); + if (!ssif_info->stopping) + mod_timer(&ssif_info->retry_timer, + jiffies + SSIF_MSG_JIFFIES); ipmi_ssif_unlock_cond(ssif_info, flags); return; } @@ -652,7 +655,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, if (len == 0) { result = -EIO; if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) - pr_info(PFX "Middle message with no data\n"); + pr_info("Middle message with no data\n"); goto continue_op; } @@ -696,8 +699,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, I2C_SMBUS_BLOCK_DATA); if (rv < 0) { if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) - pr_info(PFX - "Error from ssif_i2c_send\n"); + pr_info("Error from ssif_i2c_send\n"); result = -EIO; } else @@ -715,7 +717,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, continue_op: if (ssif_info->ssif_debug & SSIF_DEBUG_STATE) - pr_info(PFX "DONE 1: state = %d, result=%d.\n", + pr_info("DONE 1: state = %d, result=%d\n", ssif_info->ssif_state, result); flags = ipmi_ssif_lock_cond(ssif_info, &oflags); @@ -749,8 +751,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, */ ssif_info->ssif_state = SSIF_NORMAL; ipmi_ssif_unlock_cond(ssif_info, flags); - pr_warn(PFX "Error getting flags: %d %d, %x\n", - result, len, (len >= 3) ? data[2] : 0); + pr_warn("Error getting flags: %d %d, %x\n", + result, len, (len >= 3) ? data[2] : 0); } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || data[1] != IPMI_GET_MSG_FLAGS_CMD) { /* @@ -758,7 +760,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, * response to a previous command. */ ipmi_ssif_unlock_cond(ssif_info, flags); - pr_warn(PFX "Invalid response getting flags: %x %x\n", + pr_warn("Invalid response getting flags: %x %x\n", data[0], data[1]); } else { ssif_inc_stat(ssif_info, flag_fetches); @@ -771,11 +773,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, /* We cleared the flags. */ if ((result < 0) || (len < 3) || (data[2] != 0)) { /* Error clearing flags */ - pr_warn(PFX "Error clearing flags: %d %d, %x\n", - result, len, (len >= 3) ? data[2] : 0); + pr_warn("Error clearing flags: %d %d, %x\n", + result, len, (len >= 3) ? data[2] : 0); } else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) { - pr_warn(PFX "Invalid response clearing flags: %x %x\n", + pr_warn("Invalid response clearing flags: %x %x\n", data[0], data[1]); } ssif_info->ssif_state = SSIF_NORMAL; @@ -792,7 +794,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, handle_flags(ssif_info, flags); } else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || msg->rsp[1] != IPMI_READ_EVENT_MSG_BUFFER_CMD) { - pr_warn(PFX "Invalid response getting events: %x %x\n", + pr_warn("Invalid response getting events: %x %x\n", msg->rsp[0], msg->rsp[1]); msg->done(msg); /* Take off the event flag. */ @@ -815,7 +817,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, handle_flags(ssif_info, flags); } else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || msg->rsp[1] != IPMI_GET_MSG_CMD) { - pr_warn(PFX "Invalid response clearing flags: %x %x\n", + pr_warn("Invalid response clearing flags: %x %x\n", msg->rsp[0], msg->rsp[1]); msg->done(msg); @@ -842,7 +844,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ipmi_ssif_unlock_cond(ssif_info, flags); if (ssif_info->ssif_debug & SSIF_DEBUG_STATE) - pr_info(PFX "DONE 2: state = %d.\n", ssif_info->ssif_state); + pr_info("DONE 2: state = %d.\n", ssif_info->ssif_state); } static void msg_written_handler(struct ssif_info *ssif_info, int result, @@ -862,8 +864,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, ssif_inc_stat(ssif_info, send_errors); if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) - pr_info(PFX - "Out of retries in msg_written_handler\n"); + pr_info("%s: Out of retries\n", __func__); msg_done_handler(ssif_info, -EIO, NULL, 0); return; } @@ -887,32 +888,33 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, * in the SSIF_MULTI_n_PART case in the probe function * for details on the intricacies of this. */ - int left; + int left, to_write; unsigned char *data_to_send; + unsigned char cmd; ssif_inc_stat(ssif_info, sent_messages_parts); left = ssif_info->multi_len - ssif_info->multi_pos; - if (left > 32) - left = 32; + to_write = left; + if (to_write > 32) + to_write = 32; /* Length byte. */ - ssif_info->multi_data[ssif_info->multi_pos] = left; + ssif_info->multi_data[ssif_info->multi_pos] = to_write; data_to_send = ssif_info->multi_data + ssif_info->multi_pos; - ssif_info->multi_pos += left; - if (left < 32) - /* - * Write is finished. Note that we must end - * with a write of less than 32 bytes to - * complete the transaction, even if it is - * zero bytes. - */ + ssif_info->multi_pos += to_write; + cmd = SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE; + if (ssif_info->cmd8_works) { + if (left == to_write) { + cmd = SSIF_IPMI_MULTI_PART_REQUEST_END; + ssif_info->multi_data = NULL; + } + } else if (to_write < 32) { ssif_info->multi_data = NULL; + } rv = ssif_i2c_send(ssif_info, msg_written_handler, - I2C_SMBUS_WRITE, - SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE, - data_to_send, - I2C_SMBUS_BLOCK_DATA); + I2C_SMBUS_WRITE, cmd, + data_to_send, I2C_SMBUS_BLOCK_DATA); if (rv < 0) { /* request failed, just return the error. */ ssif_inc_stat(ssif_info, send_errors); @@ -939,8 +941,9 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, ssif_info->waiting_alert = true; ssif_info->retries_left = SSIF_RECV_RETRIES; ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; - mod_timer(&ssif_info->retry_timer, - jiffies + SSIF_MSG_PART_JIFFIES); + if (!ssif_info->stopping) + mod_timer(&ssif_info->retry_timer, + jiffies + SSIF_MSG_PART_JIFFIES); ipmi_ssif_unlock_cond(ssif_info, flags); } } @@ -1043,8 +1046,8 @@ static void sender(void *send_info, ktime_get_real_ts64(&t); pr_info("**Enqueue %02x %02x: %lld.%6.6ld\n", - msg->data[0], msg->data[1], - (long long) t.tv_sec, (long) t.tv_nsec / NSEC_PER_USEC); + msg->data[0], msg->data[1], + (long long)t.tv_sec, (long)t.tv_nsec / NSEC_PER_USEC); } } @@ -1244,6 +1247,24 @@ static int ssif_remove(struct i2c_client *client) return 0; } +static int read_response(struct i2c_client *client, unsigned char *resp) +{ + int ret = -ENODEV, retry_cnt = SSIF_RECV_RETRIES; + + while (retry_cnt > 0) { + ret = i2c_smbus_read_block_data(client, SSIF_IPMI_RESPONSE, + resp); + if (ret > 0) + break; + msleep(SSIF_MSG_MSEC); + retry_cnt--; + if (retry_cnt <= 0) + break; + } + + return ret; +} + static int do_cmd(struct i2c_client *client, int len, unsigned char *msg, int *resp_len, unsigned char *resp) { @@ -1260,26 +1281,16 @@ static int do_cmd(struct i2c_client *client, int len, unsigned char *msg, return -ENODEV; } - ret = -ENODEV; - retry_cnt = SSIF_RECV_RETRIES; - while (retry_cnt > 0) { - ret = i2c_smbus_read_block_data(client, SSIF_IPMI_RESPONSE, - resp); - if (ret > 0) - break; - msleep(SSIF_MSG_MSEC); - retry_cnt--; - if (retry_cnt <= 0) - break; - } - + ret = read_response(client, resp); if (ret > 0) { /* Validate that the response is correct. */ if (ret < 3 || (resp[0] != (msg[0] | (1 << 2))) || (resp[1] != msg[1])) ret = -EINVAL; - else { + else if (ret > IPMI_MAX_MSG_LENGTH) { + ret = -E2BIG; + } else { *resp_len = ret; ret = 0; } @@ -1391,6 +1402,121 @@ static int find_slave_address(struct i2c_client *client, int slave_addr) return slave_addr; } +static int start_multipart_test(struct i2c_client *client, + unsigned char *msg, bool do_middle) +{ + int retry_cnt = SSIF_SEND_RETRIES, ret; + +retry_write: + ret = i2c_smbus_write_block_data(client, + SSIF_IPMI_MULTI_PART_REQUEST_START, + 32, msg); + if (ret) { + retry_cnt--; + if (retry_cnt > 0) + goto retry_write; + dev_err(&client->dev, "Could not write multi-part start, though the BMC said it could handle it. Just limit sends to one part.\n"); + return ret; + } + + if (!do_middle) + return 0; + + ret = i2c_smbus_write_block_data(client, + SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE, + 32, msg + 32); + if (ret) { + dev_err(&client->dev, "Could not write multi-part middle, though the BMC said it could handle it. Just limit sends to one part.\n"); + return ret; + } + + return 0; +} + +static void test_multipart_messages(struct i2c_client *client, + struct ssif_info *ssif_info, + unsigned char *resp) +{ + unsigned char msg[65]; + int ret; + bool do_middle; + + if (ssif_info->max_xmit_msg_size <= 32) + return; + + do_middle = ssif_info->max_xmit_msg_size > 63; + + memset(msg, 0, sizeof(msg)); + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_GET_DEVICE_ID_CMD; + + /* + * The specification is all messed up dealing with sending + * multi-part messages. Per what the specification says, it + * is impossible to send a message that is a multiple of 32 + * bytes, except for 32 itself. It talks about a "start" + * transaction (cmd=6) that must be 32 bytes, "middle" + * transaction (cmd=7) that must be 32 bytes, and an "end" + * transaction. The "end" transaction is shown as cmd=7 in + * the text, but if that's the case there is no way to + * differentiate between a middle and end part except the + * length being less than 32. But there is a table at the far + * end of the section (that I had never noticed until someone + * pointed it out to me) that mentions it as cmd=8. + * + * After some thought, I think the example is wrong and the + * end transaction should be cmd=8. But some systems don't + * implement cmd=8, they use a zero-length end transaction, + * even though that violates the SMBus specification. + * + * So, to work around this, this code tests if cmd=8 works. + * If it does, then we use that. If not, it tests zero- + * byte end transactions. If that works, good. If not, + * we only allow 63-byte transactions max. + */ + + ret = start_multipart_test(client, msg, do_middle); + if (ret) + goto out_no_multi_part; + + ret = i2c_smbus_write_block_data(client, + SSIF_IPMI_MULTI_PART_REQUEST_END, + 1, msg + 64); + + if (!ret) + ret = read_response(client, resp); + + if (ret > 0) { + /* End transactions work, we are good. */ + ssif_info->cmd8_works = true; + return; + } + + ret = start_multipart_test(client, msg, do_middle); + if (ret) { + dev_err(&client->dev, "Second multipart test failed.\n"); + goto out_no_multi_part; + } + + ret = i2c_smbus_write_block_data(client, + SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE, + 0, msg + 64); + if (!ret) + ret = read_response(client, resp); + if (ret > 0) + /* Zero-size end parts work, use those. */ + return; + + /* Limit to 63 bytes and use a short middle command to mark the end. */ + if (ssif_info->max_xmit_msg_size > 63) + ssif_info->max_xmit_msg_size = 63; + return; + +out_no_multi_part: + ssif_info->max_xmit_msg_size = 32; + return; +} + /* * Global enables we care about. */ @@ -1435,9 +1561,9 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) slave_addr = find_slave_address(client, slave_addr); - pr_info(PFX "Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n", - ipmi_addr_src_to_str(ssif_info->addr_source), - client->addr, client->adapter->name, slave_addr); + pr_info("Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n", + ipmi_addr_src_to_str(ssif_info->addr_source), + client->addr, client->adapter->name, slave_addr); ssif_info->client = client; i2c_set_clientdata(client, ssif_info); @@ -1450,7 +1576,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) if (!rv && (len >= 3) && (resp[2] == 0)) { if (len < 7) { if (ssif_dbg_probe) - pr_info(PFX "SSIF info too short: %d\n", len); + pr_info("SSIF info too short: %d\n", len); goto no_support; } @@ -1477,26 +1603,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) break; case SSIF_MULTI_n_PART: - /* - * The specification is rather confusing at - * this point, but I think I understand what - * is meant. At least I have a workable - * solution. With multi-part messages, you - * cannot send a message that is a multiple of - * 32-bytes in length, because the start and - * middle messages are 32-bytes and the end - * message must be at least one byte. You - * can't fudge on an extra byte, that would - * screw up things like fru data writes. So - * we limit the length to 63 bytes. That way - * a 32-byte message gets sent as a single - * part. A larger message will be a 32-byte - * start and the next message is always going - * to be 1-31 bytes in length. Not ideal, but - * it should work. - */ - if (ssif_info->max_xmit_msg_size > 63) - ssif_info->max_xmit_msg_size = 63; + /* We take whatever size given, but do some testing. */ break; default: @@ -1506,8 +1613,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) } else { no_support: /* Assume no multi-part or PEC support */ - pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n", - rv, len, resp[2]); + pr_info("Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n", + rv, len, resp[2]); ssif_info->max_xmit_msg_size = 32; ssif_info->max_recv_msg_size = 32; @@ -1515,13 +1622,15 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ssif_info->supports_pec = 0; } + test_multipart_messages(client, ssif_info, resp); + /* Make sure the NMI timeout is cleared. */ msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; msg[2] = WDT_PRE_TIMEOUT_INT; rv = do_cmd(client, 3, msg, &len, resp); if (rv || (len < 3) || (resp[2] != 0)) - pr_warn(PFX "Unable to clear message flags: %d %d %2.2x\n", + pr_warn("Unable to clear message flags: %d %d %2.2x\n", rv, len, resp[2]); /* Attempt to enable the event buffer. */ @@ -1529,7 +1638,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; rv = do_cmd(client, 2, msg, &len, resp); if (rv || (len < 4) || (resp[2] != 0)) { - pr_warn(PFX "Error getting global enables: %d %d %2.2x\n", + pr_warn("Error getting global enables: %d %d %2.2x\n", rv, len, resp[2]); rv = 0; /* Not fatal */ goto found; @@ -1548,7 +1657,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF; rv = do_cmd(client, 3, msg, &len, resp); if (rv || (len < 2)) { - pr_warn(PFX "Error setting global enables: %d %d %2.2x\n", + pr_warn("Error setting global enables: %d %d %2.2x\n", rv, len, resp[2]); rv = 0; /* Not fatal */ goto found; @@ -1569,7 +1678,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR; rv = do_cmd(client, 3, msg, &len, resp); if (rv || (len < 2)) { - pr_warn(PFX "Error setting global enables: %d %d %2.2x\n", + pr_warn("Error setting global enables: %d %d %2.2x\n", rv, len, resp[2]); rv = 0; /* Not fatal */ goto found; @@ -1637,7 +1746,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) &ssif_info->client->dev, slave_addr); if (rv) { - pr_err(PFX "Unable to register device: error %d\n", rv); + pr_err("Unable to register device: error %d\n", rv); goto out_remove_attr; } @@ -1741,7 +1850,7 @@ static void free_ssif_clients(void) static unsigned short *ssif_address_list(void) { struct ssif_addr_info *info; - unsigned int count = 0, i; + unsigned int count = 0, i = 0; unsigned short *address_list; list_for_each_entry(info, &ssif_infos, link) @@ -1752,18 +1861,17 @@ static unsigned short *ssif_address_list(void) if (!address_list) return NULL; - i = 0; list_for_each_entry(info, &ssif_infos, link) { unsigned short addr = info->binfo.addr; int j; for (j = 0; j < i; j++) { if (address_list[j] == addr) - goto skip_addr; + /* Found a dup. */ + break; } - address_list[i] = addr; -skip_addr: - i++; + if (j == i) /* Didn't find it in the list. */ + address_list[i++] = addr; } address_list[i] = I2C_CLIENT_END; @@ -1790,7 +1898,7 @@ static int dmi_ipmi_probe(struct platform_device *pdev) rv = device_property_read_u16(&pdev->dev, "i2c-addr", &i2c_addr); if (rv) { - dev_warn(&pdev->dev, PFX "No i2c-addr property\n"); + dev_warn(&pdev->dev, "No i2c-addr property\n"); return -ENODEV; } @@ -1847,12 +1955,18 @@ static int ssif_platform_remove(struct platform_device *dev) return 0; } +static const struct platform_device_id ssif_plat_ids[] = { + { "dmi-ipmi-ssif", 0 }, + { } +}; + static struct platform_driver ipmi_driver = { .driver = { .name = DEVICE_NAME, }, .probe = ssif_platform_probe, .remove = ssif_platform_remove, + .id_table = ssif_plat_ids }; static int init_ipmi_ssif(void) @@ -1871,8 +1985,7 @@ static int init_ipmi_ssif(void) dbg[i], slave_addrs[i], SI_HARDCODED, NULL); if (rv) - pr_err(PFX - "Couldn't add hardcoded device at addr 0x%x\n", + pr_err("Couldn't add hardcoded device at addr 0x%x\n", addr[i]); } @@ -1883,7 +1996,7 @@ static int init_ipmi_ssif(void) if (ssif_trydmi) { rv = platform_driver_register(&ipmi_driver); if (rv) - pr_err(PFX "Unable to register driver: %d\n", rv); + pr_err("Unable to register driver: %d\n", rv); } ssif_i2c_driver.address_list = ssif_address_list(); @@ -1905,6 +2018,8 @@ static void cleanup_ipmi_ssif(void) i2c_del_driver(&ssif_i2c_driver); + kfree(ssif_i2c_driver.address_list); + platform_driver_unregister(&ipmi_driver); free_ssif_clients(); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index ca1c5c5109f0..2924a4bc4a32 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -11,6 +11,8 @@ * Copyright 2002 MontaVista Software Inc. */ +#define pr_fmt(fmt) "IPMI Watchdog: " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ipmi.h> @@ -50,8 +52,6 @@ #define HAVE_DIE_NMI #endif -#define PFX "IPMI Watchdog: " - /* * The IPMI command/response information for the watchdog timer. */ @@ -407,7 +407,7 @@ static int __ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, recv_msg, 1); if (rv) - pr_warn(PFX "set timeout error: %d\n", rv); + pr_warn("set timeout error: %d\n", rv); else if (send_heartbeat_now) *send_heartbeat_now = hbnow; @@ -530,7 +530,7 @@ static void panic_halt_ipmi_set_timeout(void) &send_heartbeat_now); if (rv) { atomic_sub(1, &panic_done_count); - pr_warn(PFX "Unable to extend the watchdog timeout."); + pr_warn("Unable to extend the watchdog timeout\n"); } else { if (send_heartbeat_now) panic_halt_ipmi_heartbeat(); @@ -573,7 +573,7 @@ restart: &recv_msg, 1); if (rv) { - pr_warn(PFX "heartbeat send failure: %d\n", rv); + pr_warn("heartbeat send failure: %d\n", rv); return rv; } @@ -583,7 +583,7 @@ restart: if (recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) { timeout_retries++; if (timeout_retries > 3) { - pr_err(PFX ": Unable to restore the IPMI watchdog's settings, giving up.\n"); + pr_err("Unable to restore the IPMI watchdog's settings, giving up\n"); rv = -EIO; goto out; } @@ -598,7 +598,7 @@ restart: */ rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); if (rv) { - pr_err(PFX ": Unable to send the command to set the watchdog's settings, giving up.\n"); + pr_err("Unable to send the command to set the watchdog's settings, giving up\n"); goto out; } @@ -876,8 +876,7 @@ static int ipmi_close(struct inode *ino, struct file *filep) _ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); mutex_unlock(&ipmi_watchdog_mutex); } else { - pr_crit(PFX - "Unexpected close, not stopping watchdog!\n"); + pr_crit("Unexpected close, not stopping watchdog!\n"); ipmi_heartbeat(); } clear_bit(0, &ipmi_wdog_open); @@ -911,9 +910,9 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, { if (msg->msg.cmd == IPMI_WDOG_RESET_TIMER && msg->msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) - pr_info(PFX "response: The IPMI controller appears to have been reset, will attempt to reinitialize the watchdog timer\n"); + pr_info("response: The IPMI controller appears to have been reset, will attempt to reinitialize the watchdog timer\n"); else if (msg->msg.data[0] != 0) - pr_err(PFX "response: Error %x on cmd %x\n", + pr_err("response: Error %x on cmd %x\n", msg->msg.data[0], msg->msg.cmd); @@ -985,7 +984,7 @@ static void ipmi_register_watchdog(int ipmi_intf) rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); if (rv < 0) { - pr_crit(PFX "Unable to register with ipmi\n"); + pr_crit("Unable to register with ipmi\n"); goto out; } @@ -993,7 +992,7 @@ static void ipmi_register_watchdog(int ipmi_intf) &ipmi_version_major, &ipmi_version_minor); if (rv) { - pr_warn(PFX "Unable to get IPMI version, assuming 1.0\n"); + pr_warn("Unable to get IPMI version, assuming 1.0\n"); ipmi_version_major = 1; ipmi_version_minor = 0; } @@ -1002,7 +1001,7 @@ static void ipmi_register_watchdog(int ipmi_intf) if (rv < 0) { ipmi_destroy_user(watchdog_user); watchdog_user = NULL; - pr_crit(PFX "Unable to register misc device\n"); + pr_crit("Unable to register misc device\n"); } #ifdef HAVE_DIE_NMI @@ -1024,7 +1023,7 @@ static void ipmi_register_watchdog(int ipmi_intf) rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); if (rv) { - pr_warn(PFX "Error starting timer to test NMI: 0x%x. The NMI pretimeout will likely not work\n", + pr_warn("Error starting timer to test NMI: 0x%x. The NMI pretimeout will likely not work\n", rv); rv = 0; goto out_restore; @@ -1033,7 +1032,7 @@ static void ipmi_register_watchdog(int ipmi_intf) msleep(1500); if (testing_nmi != 2) { - pr_warn(PFX "IPMI NMI didn't seem to occur. The NMI pretimeout will likely not work\n"); + pr_warn("IPMI NMI didn't seem to occur. The NMI pretimeout will likely not work\n"); } out_restore: testing_nmi = 0; @@ -1049,7 +1048,7 @@ static void ipmi_register_watchdog(int ipmi_intf) start_now = 0; /* Disable this function after first startup. */ ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); - pr_info(PFX "Starting now!\n"); + pr_info("Starting now!\n"); } else { /* Stop the timer now. */ ipmi_watchdog_state = WDOG_TIMEOUT_NONE; @@ -1086,7 +1085,7 @@ static void ipmi_unregister_watchdog(int ipmi_intf) /* Disconnect from IPMI. */ rv = ipmi_destroy_user(loc_user); if (rv) - pr_warn(PFX "error unlinking from IPMI: %d\n", rv); + pr_warn("error unlinking from IPMI: %d\n", rv); /* If it comes back, restart it properly. */ ipmi_start_timer_on_heartbeat = 1; @@ -1127,7 +1126,7 @@ ipmi_nmi(unsigned int val, struct pt_regs *regs) the timer. So do so. */ atomic_set(&pretimeout_since_last_heartbeat, 1); if (atomic_inc_and_test(&preop_panic_excl)) - nmi_panic(regs, PFX "pre-timeout"); + nmi_panic(regs, "pre-timeout"); } return NMI_HANDLED; @@ -1259,7 +1258,7 @@ static void check_parms(void) if (preaction_val == WDOG_PRETIMEOUT_NMI) { do_nmi = 1; if (preop_val == WDOG_PREOP_GIVE_DATA) { - pr_warn(PFX "Pretimeout op is to give data but NMI pretimeout is enabled, setting pretimeout op to none\n"); + pr_warn("Pretimeout op is to give data but NMI pretimeout is enabled, setting pretimeout op to none\n"); preop_op("preop_none", NULL); do_nmi = 0; } @@ -1268,7 +1267,7 @@ static void check_parms(void) rv = register_nmi_handler(NMI_UNKNOWN, ipmi_nmi, 0, "ipmi"); if (rv) { - pr_warn(PFX "Can't register nmi handler\n"); + pr_warn("Can't register nmi handler\n"); return; } else nmi_handler_registered = 1; @@ -1285,19 +1284,18 @@ static int __init ipmi_wdog_init(void) if (action_op(action, NULL)) { action_op("reset", NULL); - pr_info(PFX "Unknown action '%s', defaulting to reset\n", - action); + pr_info("Unknown action '%s', defaulting to reset\n", action); } if (preaction_op(preaction, NULL)) { preaction_op("pre_none", NULL); - pr_info(PFX "Unknown preaction '%s', defaulting to none\n", + pr_info("Unknown preaction '%s', defaulting to none\n", preaction); } if (preop_op(preop, NULL)) { preop_op("preop_none", NULL); - pr_info(PFX "Unknown preop '%s', defaulting to none\n", preop); + pr_info("Unknown preop '%s', defaulting to none\n", preop); } check_parms(); @@ -1311,11 +1309,11 @@ static int __init ipmi_wdog_init(void) unregister_nmi_handler(NMI_UNKNOWN, "ipmi"); #endif unregister_reboot_notifier(&wdog_reboot_notifier); - pr_warn(PFX "can't register smi watcher\n"); + pr_warn("can't register smi watcher\n"); return rv; } - pr_info(PFX "driver initialized\n"); + pr_info("driver initialized\n"); return 0; } diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index a219964cb770..809507bf8f1c 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -530,7 +530,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) DEBUGP(5, dev, "NumRecBytes is valid\n"); break; } - mdelay(10); + usleep_range(10000, 11000); } if (i == 100) { DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting " @@ -546,7 +546,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read); break; } - mdelay(10); + usleep_range(10000, 11000); } /* check whether it is a short PTS reply? */ diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index f80965407d3c..d5e43606339c 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -505,7 +505,7 @@ static void cm4040_reader_release(struct pcmcia_device *link) DEBUGP(3, dev, "-> cm4040_reader_release\n"); while (link->open) { - DEBUGP(3, dev, KERN_INFO MODULE_NAME ": delaying release " + DEBUGP(3, dev, MODULE_NAME ": delaying release " "until process has terminated\n"); wait_event(dev->devq, (link->open == 0)); } diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d8c7f5750cdb..9a7d4dc00b6e 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -319,6 +319,13 @@ static u64 notrace arm64_858921_read_cntvct_el0(void) } #endif +#ifdef CONFIG_ARM64_ERRATUM_1188873 +static u64 notrace arm64_1188873_read_cntvct_el0(void) +{ + return read_sysreg(cntvct_el0); +} +#endif + #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround); EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); @@ -408,6 +415,14 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = { .read_cntvct_el0 = arm64_858921_read_cntvct_el0, }, #endif +#ifdef CONFIG_ARM64_ERRATUM_1188873 + { + .match_type = ate_match_local_cap_id, + .id = (void *)ARM64_WORKAROUND_1188873, + .desc = "ARM erratum 1188873", + .read_cntvct_el0 = arm64_1188873_read_cntvct_el0, + }, +#endif }; typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index b61f4ec43e06..d62fd374d5c7 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -61,6 +61,7 @@ enum { #define INTEL_MSR_RANGE (0xffff) #define AMD_MSR_RANGE (0x7) +#define HYGON_MSR_RANGE (0x7) #define MSR_K7_HWCR_CPB_DIS (1ULL << 25) @@ -95,6 +96,7 @@ static bool boost_state(unsigned int cpu) rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi); msr = lo | ((u64)hi << 32); return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE); + case X86_VENDOR_HYGON: case X86_VENDOR_AMD: rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); msr = lo | ((u64)hi << 32); @@ -113,6 +115,7 @@ static int boost_set_msr(bool enable) msr_addr = MSR_IA32_MISC_ENABLE; msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE; break; + case X86_VENDOR_HYGON: case X86_VENDOR_AMD: msr_addr = MSR_K7_HWCR; msr_mask = MSR_K7_HWCR_CPB_DIS; @@ -225,6 +228,8 @@ static unsigned extract_msr(struct cpufreq_policy *policy, u32 msr) if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) msr &= AMD_MSR_RANGE; + else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) + msr &= HYGON_MSR_RANGE; else msr &= INTEL_MSR_RANGE; diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c index be926d9a66e5..4ac7c3cf34be 100644 --- a/drivers/cpufreq/amd_freq_sensitivity.c +++ b/drivers/cpufreq/amd_freq_sensitivity.c @@ -111,11 +111,16 @@ static int __init amd_freq_sensitivity_init(void) { u64 val; struct pci_dev *pcidev; + unsigned int pci_vendor; - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + pci_vendor = PCI_VENDOR_ID_AMD; + else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) + pci_vendor = PCI_VENDOR_ID_HYGON; + else return -ENODEV; - pcidev = pci_get_device(PCI_VENDOR_ID_AMD, + pcidev = pci_get_device(pci_vendor, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL); if (!pcidev) { diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 30f302149730..fd25c21cee72 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -428,7 +428,7 @@ MODULE_LICENSE("GPL"); late_initcall(cppc_cpufreq_init); -static const struct acpi_device_id cppc_acpi_ids[] = { +static const struct acpi_device_id cppc_acpi_ids[] __used = { {ACPI_PROCESSOR_DEVICE_HID, }, {} }; diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index fe14c57de6ca..b1c5468dca16 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -58,6 +58,7 @@ static const struct of_device_id whitelist[] __initconst = { { .compatible = "renesas,r8a73a4", }, { .compatible = "renesas,r8a7740", }, { .compatible = "renesas,r8a7743", }, + { .compatible = "renesas,r8a7744", }, { .compatible = "renesas,r8a7745", }, { .compatible = "renesas,r8a7778", }, { .compatible = "renesas,r8a7779", }, @@ -78,7 +79,10 @@ static const struct of_device_id whitelist[] __initconst = { { .compatible = "rockchip,rk3328", }, { .compatible = "rockchip,rk3366", }, { .compatible = "rockchip,rk3368", }, - { .compatible = "rockchip,rk3399", }, + { .compatible = "rockchip,rk3399", + .data = &(struct cpufreq_dt_platform_data) + { .have_governor_per_policy = true, }, + }, { .compatible = "st-ericsson,u8500", }, { .compatible = "st-ericsson,u8540", }, diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 0a9ebf00be46..e58bfcb1169e 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -32,6 +32,7 @@ struct private_data { struct device *cpu_dev; struct thermal_cooling_device *cdev; const char *reg_name; + bool have_static_opps; }; static struct freq_attr *cpufreq_dt_attr[] = { @@ -204,6 +205,15 @@ static int cpufreq_init(struct cpufreq_policy *policy) } } + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_put_regulator; + } + + priv->reg_name = name; + priv->opp_table = opp_table; + /* * Initialize OPP tables for all policy->cpus. They will be shared by * all CPUs which have marked their CPUs shared with OPP bindings. @@ -214,7 +224,8 @@ static int cpufreq_init(struct cpufreq_policy *policy) * * OPPs might be populated at runtime, don't check for error here */ - dev_pm_opp_of_cpumask_add_table(policy->cpus); + if (!dev_pm_opp_of_cpumask_add_table(policy->cpus)) + priv->have_static_opps = true; /* * But we need OPP table to function so if it is not there let's @@ -240,19 +251,10 @@ static int cpufreq_init(struct cpufreq_policy *policy) __func__, ret); } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto out_free_opp; - } - - priv->reg_name = name; - priv->opp_table = opp_table; - ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); if (ret) { dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); - goto out_free_priv; + goto out_free_opp; } priv->cpu_dev = cpu_dev; @@ -282,10 +284,11 @@ static int cpufreq_init(struct cpufreq_policy *policy) out_free_cpufreq_table: dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -out_free_priv: - kfree(priv); out_free_opp: - dev_pm_opp_of_cpumask_remove_table(policy->cpus); + if (priv->have_static_opps) + dev_pm_opp_of_cpumask_remove_table(policy->cpus); + kfree(priv); +out_put_regulator: if (name) dev_pm_opp_put_regulators(opp_table); out_put_clk: @@ -300,7 +303,8 @@ static int cpufreq_exit(struct cpufreq_policy *policy) cpufreq_cooling_unregister(priv->cdev); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); - dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); + if (priv->have_static_opps) + dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); if (priv->reg_name) dev_pm_opp_put_regulators(priv->opp_table); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f53fb41efb7b..7aa3dcad2175 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -403,7 +403,7 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_transition_begin); void cpufreq_freq_transition_end(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, int transition_failed) { - if (unlikely(WARN_ON(!policy->transition_ongoing))) + if (WARN_ON(!policy->transition_ongoing)) return; cpufreq_notify_post_transition(policy, freqs, transition_failed); diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index f20f20a77d4d..4268f87e99fc 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -80,8 +80,10 @@ static unsigned int cs_dbs_update(struct cpufreq_policy *policy) * changed in the meantime, so fall back to current frequency in that * case. */ - if (requested_freq > policy->max || requested_freq < policy->min) + if (requested_freq > policy->max || requested_freq < policy->min) { requested_freq = policy->cur; + dbs_info->requested_freq = requested_freq; + } freq_step = get_freq_step(cs_tuners, policy); @@ -92,7 +94,7 @@ static unsigned int cs_dbs_update(struct cpufreq_policy *policy) if (policy_dbs->idle_periods < UINT_MAX) { unsigned int freq_steps = policy_dbs->idle_periods * freq_step; - if (requested_freq > freq_steps) + if (requested_freq > policy->min + freq_steps) requested_freq -= freq_steps; else requested_freq = policy->min; diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index b2ff423ad7f8..8cfee0ab804b 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -12,6 +12,7 @@ #include <linux/cpu_cooling.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/nvmem-consumer.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/pm_opp.h> @@ -290,20 +291,32 @@ put_node: #define OCOTP_CFG3_6ULL_SPEED_792MHZ 0x2 #define OCOTP_CFG3_6ULL_SPEED_900MHZ 0x3 -static void imx6ul_opp_check_speed_grading(struct device *dev) +static int imx6ul_opp_check_speed_grading(struct device *dev) { - struct device_node *np; - void __iomem *base; u32 val; + int ret = 0; - np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp"); - if (!np) - return; + if (of_find_property(dev->of_node, "nvmem-cells", NULL)) { + ret = nvmem_cell_read_u32(dev, "speed_grade", &val); + if (ret) + return ret; + } else { + struct device_node *np; + void __iomem *base; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp"); + if (!np) + return -ENOENT; + + base = of_iomap(np, 0); + of_node_put(np); + if (!base) { + dev_err(dev, "failed to map ocotp\n"); + return -EFAULT; + } - base = of_iomap(np, 0); - if (!base) { - dev_err(dev, "failed to map ocotp\n"); - goto put_node; + val = readl_relaxed(base + OCOTP_CFG3); + iounmap(base); } /* @@ -314,7 +327,6 @@ static void imx6ul_opp_check_speed_grading(struct device *dev) * 2b'11: 900000000Hz on i.MX6ULL only; * We need to set the max speed of ARM according to fuse map. */ - val = readl_relaxed(base + OCOTP_CFG3); val >>= OCOTP_CFG3_SPEED_SHIFT; val &= 0x3; @@ -334,9 +346,7 @@ static void imx6ul_opp_check_speed_grading(struct device *dev) dev_warn(dev, "failed to disable 900MHz OPP\n"); } - iounmap(base); -put_node: - of_node_put(np); + return ret; } static int imx6q_cpufreq_probe(struct platform_device *pdev) @@ -394,10 +404,18 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) } if (of_machine_is_compatible("fsl,imx6ul") || - of_machine_is_compatible("fsl,imx6ull")) - imx6ul_opp_check_speed_grading(cpu_dev); - else + of_machine_is_compatible("fsl,imx6ull")) { + ret = imx6ul_opp_check_speed_grading(cpu_dev); + if (ret == -EPROBE_DEFER) + return ret; + if (ret) { + dev_err(cpu_dev, "failed to read ocotp: %d\n", + ret); + return ret; + } + } else { imx6q_opp_check_speed_grading(cpu_dev); + } /* Because we have added the OPPs here, we must free them */ free_opp = true; diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index b6a1aadaff9f..49c0abf2d48f 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -373,10 +373,28 @@ static void intel_pstate_set_itmt_prio(int cpu) } } } + +static int intel_pstate_get_cppc_guranteed(int cpu) +{ + struct cppc_perf_caps cppc_perf; + int ret; + + ret = cppc_get_perf_caps(cpu, &cppc_perf); + if (ret) + return ret; + + return cppc_perf.guaranteed_perf; +} + #else static void intel_pstate_set_itmt_prio(int cpu) { } + +static int intel_pstate_get_cppc_guranteed(int cpu) +{ + return -ENOTSUPP; +} #endif static void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy) @@ -699,9 +717,29 @@ static ssize_t show_energy_performance_preference( cpufreq_freq_attr_rw(energy_performance_preference); +static ssize_t show_base_frequency(struct cpufreq_policy *policy, char *buf) +{ + struct cpudata *cpu; + u64 cap; + int ratio; + + ratio = intel_pstate_get_cppc_guranteed(policy->cpu); + if (ratio <= 0) { + rdmsrl_on_cpu(policy->cpu, MSR_HWP_CAPABILITIES, &cap); + ratio = HWP_GUARANTEED_PERF(cap); + } + + cpu = all_cpu_data[policy->cpu]; + + return sprintf(buf, "%d\n", ratio * cpu->pstate.scaling); +} + +cpufreq_freq_attr_ro(base_frequency); + static struct freq_attr *hwp_cpufreq_attrs[] = { &energy_performance_preference, &energy_performance_available_preferences, + &base_frequency, NULL, }; @@ -1778,7 +1816,7 @@ static const struct pstate_funcs knl_funcs = { static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(INTEL_FAM6_SANDYBRIDGE, core_funcs), ICPU(INTEL_FAM6_SANDYBRIDGE_X, core_funcs), - ICPU(INTEL_FAM6_ATOM_SILVERMONT1, silvermont_funcs), + ICPU(INTEL_FAM6_ATOM_SILVERMONT, silvermont_funcs), ICPU(INTEL_FAM6_IVYBRIDGE, core_funcs), ICPU(INTEL_FAM6_HASWELL_CORE, core_funcs), ICPU(INTEL_FAM6_BROADWELL_CORE, core_funcs), @@ -1795,7 +1833,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_funcs), ICPU(INTEL_FAM6_XEON_PHI_KNM, knl_funcs), ICPU(INTEL_FAM6_ATOM_GOLDMONT, core_funcs), - ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, core_funcs), + ICPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS, core_funcs), ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs), {} }; diff --git a/drivers/cpufreq/mvebu-cpufreq.c b/drivers/cpufreq/mvebu-cpufreq.c index 31513bd42705..6d33a639f902 100644 --- a/drivers/cpufreq/mvebu-cpufreq.c +++ b/drivers/cpufreq/mvebu-cpufreq.c @@ -84,9 +84,10 @@ static int __init armada_xp_pmsu_cpufreq_init(void) ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0); if (ret) { + dev_pm_opp_remove(cpu_dev, clk_get_rate(clk)); clk_put(clk); dev_err(cpu_dev, "Failed to register OPPs\n"); - goto opp_register_failed; + return ret; } ret = dev_pm_opp_set_sharing_cpus(cpu_dev, @@ -99,11 +100,5 @@ static int __init armada_xp_pmsu_cpufreq_init(void) platform_device_register_simple("cpufreq-dt", -1, NULL, 0); return 0; - -opp_register_failed: - /* As registering has failed remove all the opp for all cpus */ - dev_pm_opp_cpumask_remove_table(cpu_possible_mask); - - return ret; } device_initcall(armada_xp_pmsu_cpufreq_init); diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 5d31c2db12a3..dbecd7667db2 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -611,8 +611,8 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") { id = of_alias_get_id(np, "dmc"); if (id < 0 || id >= ARRAY_SIZE(dmc_base)) { - pr_err("%s: failed to get alias of dmc node '%s'\n", - __func__, np->name); + pr_err("%s: failed to get alias of dmc node '%pOFn'\n", + __func__, np); of_node_put(np); return id; } diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c index 1f59966573aa..f1e09022b819 100644 --- a/drivers/cpufreq/tegra186-cpufreq.c +++ b/drivers/cpufreq/tegra186-cpufreq.c @@ -121,7 +121,7 @@ static struct cpufreq_frequency_table *init_vhint_table( void *virt; virt = dma_alloc_coherent(bpmp->dev, sizeof(*data), &phys, - GFP_KERNEL | GFP_DMA32); + GFP_KERNEL); if (!virt) return ERR_PTR(-ENOMEM); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 6df894d65d9e..4a97446f66d8 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -247,17 +247,17 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, if (!cpuidle_state_is_coupled(drv, index)) local_irq_enable(); - diff = ktime_us_delta(time_end, time_start); - if (diff > INT_MAX) - diff = INT_MAX; - - dev->last_residency = (int) diff; - if (entered_state >= 0) { - /* Update cpuidle counters */ - /* This can be moved to within driver enter routine + /* + * Update cpuidle counters + * This can be moved to within driver enter routine, * but that results in multiple copies of same code. */ + diff = ktime_us_delta(time_end, time_start); + if (diff > INT_MAX) + diff = INT_MAX; + + dev->last_residency = (int)diff; dev->states_usage[entered_state].time += dev->last_residency; dev->states_usage[entered_state].usage++; } else { diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 704880a6612a..f0dddc66af26 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -80,7 +80,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, last_state = &ldev->states[last_idx]; - last_residency = cpuidle_get_last_residency(dev) - drv->states[last_idx].exit_latency; + last_residency = dev->last_residency - drv->states[last_idx].exit_latency; /* consider promotion */ if (last_idx < drv->state_count - 1 && diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index e26a40971b26..575a68f31761 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -124,7 +124,6 @@ struct menu_device { int tick_wakeup; unsigned int next_timer_us; - unsigned int predicted_us; unsigned int bucket; unsigned int correction_factor[BUCKETS]; unsigned int intervals[INTERVALS]; @@ -197,10 +196,11 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); * of points is below a threshold. If it is... then use the * average of these 8 points as the estimated value. */ -static unsigned int get_typical_interval(struct menu_device *data) +static unsigned int get_typical_interval(struct menu_device *data, + unsigned int predicted_us) { int i, divisor; - unsigned int max, thresh, avg; + unsigned int min, max, thresh, avg; uint64_t sum, variance; thresh = UINT_MAX; /* Discard outliers above this value */ @@ -208,6 +208,7 @@ static unsigned int get_typical_interval(struct menu_device *data) again: /* First calculate the average of past intervals */ + min = UINT_MAX; max = 0; sum = 0; divisor = 0; @@ -218,8 +219,19 @@ again: divisor++; if (value > max) max = value; + + if (value < min) + min = value; } } + + /* + * If the result of the computation is going to be discarded anyway, + * avoid the computation altogether. + */ + if (min >= predicted_us) + return UINT_MAX; + if (divisor == INTERVALS) avg = sum >> INTERVAL_SHIFT; else @@ -286,10 +298,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, struct menu_device *data = this_cpu_ptr(&menu_devices); int latency_req = cpuidle_governor_latency_req(dev->cpu); int i; - int first_idx; int idx; unsigned int interactivity_req; - unsigned int expected_interval; + unsigned int predicted_us; unsigned long nr_iowaiters, cpu_load; ktime_t delta_next; @@ -298,50 +309,36 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, data->needs_update = 0; } - /* Special case when user has set very strict latency requirement */ - if (unlikely(latency_req == 0)) { - *stop_tick = false; - return 0; - } - /* determine the expected residency time, round up */ data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length(&delta_next)); get_iowait_load(&nr_iowaiters, &cpu_load); data->bucket = which_bucket(data->next_timer_us, nr_iowaiters); + if (unlikely(drv->state_count <= 1 || latency_req == 0) || + ((data->next_timer_us < drv->states[1].target_residency || + latency_req < drv->states[1].exit_latency) && + !drv->states[0].disabled && !dev->states_usage[0].disable)) { + /* + * In this case state[0] will be used no matter what, so return + * it right away and keep the tick running. + */ + *stop_tick = false; + return 0; + } + /* * Force the result of multiplication to be 64 bits even if both * operands are 32 bits. * Make sure to round up for half microseconds. */ - data->predicted_us = DIV_ROUND_CLOSEST_ULL((uint64_t)data->next_timer_us * + predicted_us = DIV_ROUND_CLOSEST_ULL((uint64_t)data->next_timer_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); - - expected_interval = get_typical_interval(data); - expected_interval = min(expected_interval, data->next_timer_us); - - first_idx = 0; - if (drv->states[0].flags & CPUIDLE_FLAG_POLLING) { - struct cpuidle_state *s = &drv->states[1]; - unsigned int polling_threshold; - - /* - * Default to a physical idle state, not to busy polling, unless - * a timer is going to trigger really really soon. - */ - polling_threshold = max_t(unsigned int, 20, s->target_residency); - if (data->next_timer_us > polling_threshold && - latency_req > s->exit_latency && !s->disabled && - !dev->states_usage[1].disable) - first_idx = 1; - } - /* * Use the lowest expected idle interval to pick the idle state. */ - data->predicted_us = min(data->predicted_us, expected_interval); + predicted_us = min(predicted_us, get_typical_interval(data, predicted_us)); if (tick_nohz_tick_stopped()) { /* @@ -352,34 +349,46 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * the known time till the closest timer event for the idle * state selection. */ - if (data->predicted_us < TICK_USEC) - data->predicted_us = ktime_to_us(delta_next); + if (predicted_us < TICK_USEC) + predicted_us = ktime_to_us(delta_next); } else { /* * Use the performance multiplier and the user-configurable * latency_req to determine the maximum exit latency. */ - interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load); + interactivity_req = predicted_us / performance_multiplier(nr_iowaiters, cpu_load); if (latency_req > interactivity_req) latency_req = interactivity_req; } - expected_interval = data->predicted_us; /* * Find the idle state with the lowest power while satisfying * our constraints. */ idx = -1; - for (i = first_idx; i < drv->state_count; i++) { + for (i = 0; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; struct cpuidle_state_usage *su = &dev->states_usage[i]; if (s->disabled || su->disable) continue; + if (idx == -1) idx = i; /* first enabled state */ - if (s->target_residency > data->predicted_us) { - if (data->predicted_us < TICK_USEC) + + if (s->target_residency > predicted_us) { + /* + * Use a physical idle state, not busy polling, unless + * a timer is going to trigger soon enough. + */ + if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) && + s->exit_latency <= latency_req && + s->target_residency <= data->next_timer_us) { + predicted_us = s->target_residency; + idx = i; + break; + } + if (predicted_us < TICK_USEC) break; if (!tick_nohz_tick_stopped()) { @@ -389,7 +398,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * tick in that case and let the governor run * again in the next iteration of the loop. */ - expected_interval = drv->states[idx].target_residency; + predicted_us = drv->states[idx].target_residency; break; } @@ -403,7 +412,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, s->target_residency <= ktime_to_us(delta_next)) idx = i; - goto out; + return idx; } if (s->exit_latency > latency_req) { /* @@ -412,7 +421,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * expected idle duration so that the tick is retained * as long as that target residency is low enough. */ - expected_interval = drv->states[idx].target_residency; + predicted_us = drv->states[idx].target_residency; break; } idx = i; @@ -426,7 +435,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * expected idle duration is shorter than the tick period length. */ if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || - expected_interval < TICK_USEC) && !tick_nohz_tick_stopped()) { + predicted_us < TICK_USEC) && !tick_nohz_tick_stopped()) { unsigned int delta_next_us = ktime_to_us(delta_next); *stop_tick = false; @@ -450,10 +459,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } } -out: - data->last_state_idx = idx; - - return data->last_state_idx; + return idx; } /** @@ -512,9 +518,19 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * duration predictor do a better job next time. */ measured_us = 9 * MAX_INTERESTING / 10; + } else if ((drv->states[last_idx].flags & CPUIDLE_FLAG_POLLING) && + dev->poll_time_limit) { + /* + * The CPU exited the "polling" state due to a time limit, so + * the idle duration prediction leading to the selection of that + * state was inaccurate. If a better prediction had been made, + * the CPU might have been woken up from idle by the next timer. + * Assume that to be the case. + */ + measured_us = data->next_timer_us; } else { /* measured value */ - measured_us = cpuidle_get_last_residency(dev); + measured_us = dev->last_residency; /* Deduct exit latency */ if (measured_us > 2 * target->exit_latency) diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c index 3f86d23c592e..85792d371add 100644 --- a/drivers/cpuidle/poll_state.c +++ b/drivers/cpuidle/poll_state.c @@ -9,7 +9,6 @@ #include <linux/sched/clock.h> #include <linux/sched/idle.h> -#define POLL_IDLE_TIME_LIMIT (TICK_NSEC / 16) #define POLL_IDLE_RELAX_COUNT 200 static int __cpuidle poll_idle(struct cpuidle_device *dev, @@ -17,8 +16,11 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev, { u64 time_start = local_clock(); + dev->poll_time_limit = false; + local_irq_enable(); if (!current_set_polling_and_test()) { + u64 limit = (u64)drv->states[1].target_residency * NSEC_PER_USEC; unsigned int loop_count = 0; while (!need_resched()) { @@ -27,8 +29,10 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev, continue; loop_count = 0; - if (local_clock() - time_start > POLL_IDLE_TIME_LIMIT) + if (local_clock() - time_start > limit) { + dev->poll_time_limit = true; break; + } } } current_clr_polling(); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index a8c4ce07fc9d..caa98a7fe392 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -73,6 +73,17 @@ config ZCRYPT + Crypto Express 2,3,4 or 5 Accelerator (CEXxA) + Crypto Express 4 or 5 EP11 Coprocessor (CEXxP) +config ZCRYPT_MULTIDEVNODES + bool "Support for multiple zcrypt device nodes" + default y + depends on S390 + depends on ZCRYPT + help + With this option enabled the zcrypt device driver can + provide multiple devices nodes in /dev. Each device + node can get customized to limit access and narrow + down the use of the available crypto hardware. + config PKEY tristate "Kernel API for protected key handling" depends on S390 diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 4c49bb1330b5..141413067b5c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -11,6 +11,7 @@ */ #include <linux/kernel.h> +#include <linux/kmod.h> #include <linux/sched.h> #include <linux/errno.h> #include <linux/err.h> @@ -28,9 +29,6 @@ #include <linux/of.h> #include "governor.h" -#define MAX(a,b) ((a > b) ? a : b) -#define MIN(a,b) ((a < b) ? a : b) - static struct class *devfreq_class; /* @@ -221,6 +219,49 @@ static struct devfreq_governor *find_devfreq_governor(const char *name) return ERR_PTR(-ENODEV); } +/** + * try_then_request_governor() - Try to find the governor and request the + * module if is not found. + * @name: name of the governor + * + * Search the list of devfreq governors and request the module and try again + * if is not found. This can happen when both drivers (the governor driver + * and the driver that call devfreq_add_device) are built as modules. + * devfreq_list_lock should be held by the caller. Returns the matched + * governor's pointer. + */ +static struct devfreq_governor *try_then_request_governor(const char *name) +{ + struct devfreq_governor *governor; + int err = 0; + + if (IS_ERR_OR_NULL(name)) { + pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); + return ERR_PTR(-EINVAL); + } + WARN(!mutex_is_locked(&devfreq_list_lock), + "devfreq_list_lock must be locked."); + + governor = find_devfreq_governor(name); + if (IS_ERR(governor)) { + mutex_unlock(&devfreq_list_lock); + + if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND, + DEVFREQ_NAME_LEN)) + err = request_module("governor_%s", "simpleondemand"); + else + err = request_module("governor_%s", name); + /* Restore previous state before return */ + mutex_lock(&devfreq_list_lock); + if (err) + return NULL; + + governor = find_devfreq_governor(name); + } + + return governor; +} + static int devfreq_notify_transition(struct devfreq *devfreq, struct devfreq_freqs *freqs, unsigned int state) { @@ -280,14 +321,14 @@ int update_devfreq(struct devfreq *devfreq) * max_freq * min_freq */ - max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq); - min_freq = MAX(devfreq->scaling_min_freq, devfreq->min_freq); + max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq); + min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq); - if (min_freq && freq < min_freq) { + if (freq < min_freq) { freq = min_freq; flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */ } - if (max_freq && freq > max_freq) { + if (freq > max_freq) { freq = max_freq; flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ } @@ -534,10 +575,6 @@ static void devfreq_dev_release(struct device *dev) list_del(&devfreq->node); mutex_unlock(&devfreq_list_lock); - if (devfreq->governor) - devfreq->governor->event_handler(devfreq, - DEVFREQ_GOV_STOP, NULL); - if (devfreq->profile->exit) devfreq->profile->exit(devfreq->dev.parent); @@ -646,9 +683,8 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_unlock(&devfreq->lock); mutex_lock(&devfreq_list_lock); - list_add(&devfreq->node, &devfreq_list); - governor = find_devfreq_governor(devfreq->governor_name); + governor = try_then_request_governor(devfreq->governor_name); if (IS_ERR(governor)) { dev_err(dev, "%s: Unable to find governor for the device\n", __func__); @@ -664,19 +700,20 @@ struct devfreq *devfreq_add_device(struct device *dev, __func__); goto err_init; } + + list_add(&devfreq->node, &devfreq_list); + mutex_unlock(&devfreq_list_lock); return devfreq; err_init: - list_del(&devfreq->node); mutex_unlock(&devfreq_list_lock); - device_unregister(&devfreq->dev); + devfreq_remove_device(devfreq); devfreq = NULL; err_dev: - if (devfreq) - kfree(devfreq); + kfree(devfreq); err_out: return ERR_PTR(err); } @@ -693,6 +730,9 @@ int devfreq_remove_device(struct devfreq *devfreq) if (!devfreq) return -EINVAL; + if (devfreq->governor) + devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_STOP, NULL); device_unregister(&devfreq->dev); return 0; @@ -991,7 +1031,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&devfreq_list_lock); - governor = find_devfreq_governor(str_governor); + governor = try_then_request_governor(str_governor); if (IS_ERR(governor)) { ret = PTR_ERR(governor); goto out; @@ -1126,17 +1166,26 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, struct devfreq *df = to_devfreq(dev); unsigned long value; int ret; - unsigned long max; ret = sscanf(buf, "%lu", &value); if (ret != 1) return -EINVAL; mutex_lock(&df->lock); - max = df->max_freq; - if (value && max && value > max) { - ret = -EINVAL; - goto unlock; + + if (value) { + if (value > df->max_freq) { + ret = -EINVAL; + goto unlock; + } + } else { + unsigned long *freq_table = df->profile->freq_table; + + /* Get minimum frequency according to sorting order */ + if (freq_table[0] < freq_table[df->profile->max_state - 1]) + value = freq_table[0]; + else + value = freq_table[df->profile->max_state - 1]; } df->min_freq = value; @@ -1152,7 +1201,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, { struct devfreq *df = to_devfreq(dev); - return sprintf(buf, "%lu\n", MAX(df->scaling_min_freq, df->min_freq)); + return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq)); } static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, @@ -1161,17 +1210,26 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, struct devfreq *df = to_devfreq(dev); unsigned long value; int ret; - unsigned long min; ret = sscanf(buf, "%lu", &value); if (ret != 1) return -EINVAL; mutex_lock(&df->lock); - min = df->min_freq; - if (value && min && value < min) { - ret = -EINVAL; - goto unlock; + + if (value) { + if (value < df->min_freq) { + ret = -EINVAL; + goto unlock; + } + } else { + unsigned long *freq_table = df->profile->freq_table; + + /* Get maximum frequency according to sorting order */ + if (freq_table[0] < freq_table[df->profile->max_state - 1]) + value = freq_table[df->profile->max_state - 1]; + else + value = freq_table[0]; } df->max_freq = value; @@ -1188,7 +1246,7 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, { struct devfreq *df = to_devfreq(dev); - return sprintf(buf, "%lu\n", MIN(df->scaling_max_freq, df->max_freq)); + return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq)); } static DEVICE_ATTR_RW(max_freq); diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index a9c64f0d3284..c61de0bdf053 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -535,8 +535,8 @@ static int of_get_devfreq_events(struct device_node *np, if (i == ARRAY_SIZE(ppmu_events)) { dev_warn(dev, - "don't know how to configure events : %s\n", - node->name); + "don't know how to configure events : %pOFn\n", + node); continue; } diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index cfc50a61a90d..f53339ca610f 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -25,6 +25,9 @@ #define DEVFREQ_GOV_SUSPEND 0x4 #define DEVFREQ_GOV_RESUME 0x5 +#define DEVFREQ_MIN_FREQ 0 +#define DEVFREQ_MAX_FREQ ULONG_MAX + /** * struct devfreq_governor - Devfreq policy governor * @node: list node - contains registered devfreq governors @@ -54,9 +57,6 @@ struct devfreq_governor { unsigned int event, void *data); }; -/* Caution: devfreq->lock must be locked before calling update_devfreq */ -extern int update_devfreq(struct devfreq *devfreq); - extern void devfreq_monitor_start(struct devfreq *devfreq); extern void devfreq_monitor_stop(struct devfreq *devfreq); extern void devfreq_monitor_suspend(struct devfreq *devfreq); diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index 4d23ecfbd948..ded429fd51be 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -20,10 +20,7 @@ static int devfreq_performance_func(struct devfreq *df, * target callback should be able to get floor value as * said in devfreq.h */ - if (!df->max_freq) - *freq = UINT_MAX; - else - *freq = df->max_freq; + *freq = DEVFREQ_MAX_FREQ; return 0; } diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 0c42f23249ef..9e8897f5ac42 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -20,7 +20,7 @@ static int devfreq_powersave_func(struct devfreq *df, * target callback should be able to get ceiling value as * said in devfreq.h */ - *freq = df->min_freq; + *freq = DEVFREQ_MIN_FREQ; return 0; } diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 28e0f2de7100..c0417f0e081e 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -27,7 +27,6 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; struct devfreq_simple_ondemand_data *data = df->data; - unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; err = devfreq_update_stats(df); if (err) @@ -47,7 +46,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Assume MAX if it is going to be divided by zero */ if (stat->total_time == 0) { - *freq = max; + *freq = DEVFREQ_MAX_FREQ; return 0; } @@ -60,13 +59,13 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Set MAX if it's busy enough */ if (stat->busy_time * 100 > stat->total_time * dfso_upthreshold) { - *freq = max; + *freq = DEVFREQ_MAX_FREQ; return 0; } /* Set MAX if we do not know the initial frequency */ if (stat->current_frequency == 0) { - *freq = max; + *freq = DEVFREQ_MAX_FREQ; return 0; } @@ -85,11 +84,6 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); *freq = (unsigned long) b; - if (df->min_freq && *freq < df->min_freq) - *freq = df->min_freq; - if (df->max_freq && *freq > df->max_freq) - *freq = df->max_freq; - return 0; } diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 080607c3f34d..378d84c011df 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -26,19 +26,11 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq) { struct userspace_data *data = df->data; - if (data->valid) { - unsigned long adjusted_freq = data->user_frequency; - - if (df->max_freq && adjusted_freq > df->max_freq) - adjusted_freq = df->max_freq; - - if (df->min_freq && adjusted_freq < df->min_freq) - adjusted_freq = df->min_freq; - - *freq = adjusted_freq; - } else { + if (data->valid) + *freq = data->user_frequency; + else *freq = df->previous_freq; /* No user freq specified yet */ - } + return 0; } diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 5762c3c383f2..ab7c5a937ab0 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -599,7 +599,8 @@ static const struct regmap_config s10_sdram_regmap_cfg = { .volatile_reg = s10_sdram_volatile_reg, .reg_read = s10_protected_reg_read, .reg_write = s10_protected_reg_write, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static int altr_s10_sdram_probe(struct platform_device *pdev) diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c index df28b65358d2..903a4f1fadcc 100644 --- a/drivers/edac/pnd2_edac.c +++ b/drivers/edac/pnd2_edac.c @@ -1541,7 +1541,7 @@ static struct dunit_ops dnv_ops = { static const struct x86_cpu_id pnd2_cpuids[] = { { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT, 0, (kernel_ulong_t)&apl_ops }, - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_DENVERTON, 0, (kernel_ulong_t)&dnv_ops }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT_X, 0, (kernel_ulong_t)&dnv_ops }, { } }; MODULE_DEVICE_TABLE(x86cpu, pnd2_cpuids); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 2a29dd9c986d..249eb70691b0 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -52,7 +52,8 @@ struct efi __read_mostly efi = { .properties_table = EFI_INVALID_TABLE_ADDR, .mem_attr_table = EFI_INVALID_TABLE_ADDR, .rng_seed = EFI_INVALID_TABLE_ADDR, - .tpm_log = EFI_INVALID_TABLE_ADDR + .tpm_log = EFI_INVALID_TABLE_ADDR, + .mem_reserve = EFI_INVALID_TABLE_ADDR, }; EXPORT_SYMBOL(efi); @@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, + {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, {NULL_GUID, NULL, NULL}, }; @@ -591,6 +593,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, early_memunmap(tbl, sizeof(*tbl)); } + if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) { + unsigned long prsv = efi.mem_reserve; + + while (prsv) { + struct linux_efi_memreserve *rsv; + + /* reserve the entry itself */ + memblock_reserve(prsv, sizeof(*rsv)); + + rsv = early_memremap(prsv, sizeof(*rsv)); + if (rsv == NULL) { + pr_err("Could not map UEFI memreserve entry!\n"); + return -ENOMEM; + } + + if (rsv->size) + memblock_reserve(rsv->base, rsv->size); + + prsv = rsv->next; + early_memunmap(rsv, sizeof(*rsv)); + } + } + return 0; } @@ -937,6 +962,38 @@ bool efi_is_table_address(unsigned long phys_addr) return false; } +static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock); + +int efi_mem_reserve_persistent(phys_addr_t addr, u64 size) +{ + struct linux_efi_memreserve *rsv, *parent; + + if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR) + return -ENODEV; + + rsv = kmalloc(sizeof(*rsv), GFP_KERNEL); + if (!rsv) + return -ENOMEM; + + parent = memremap(efi.mem_reserve, sizeof(*rsv), MEMREMAP_WB); + if (!parent) { + kfree(rsv); + return -ENOMEM; + } + + rsv->base = addr; + rsv->size = size; + + spin_lock(&efi_mem_reserve_persistent_lock); + rsv->next = parent->next; + parent->next = __pa(rsv); + spin_unlock(&efi_mem_reserve_persistent_lock); + + memunmap(parent); + + return 0; +} + #ifdef CONFIG_KEXEC static int update_efi_random_seed(struct notifier_block *nb, unsigned long code, void *unused) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 14c40a7750d1..c51627660dbb 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -16,7 +16,8 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -fpie \ $(DISABLE_STACKLEAK_PLUGIN) cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ - -fno-builtin -fpic -mno-single-pic-base + -fno-builtin -fpic \ + $(call cc-option,-mno-single-pic-base) cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 6920033de6d4..30ac0c975f8a 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -69,6 +69,31 @@ static struct screen_info *setup_graphics(efi_system_table_t *sys_table_arg) return si; } +void install_memreserve_table(efi_system_table_t *sys_table_arg) +{ + struct linux_efi_memreserve *rsv; + efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID; + efi_status_t status; + + status = efi_call_early(allocate_pool, EFI_LOADER_DATA, sizeof(*rsv), + (void **)&rsv); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table_arg, "Failed to allocate memreserve entry!\n"); + return; + } + + rsv->next = 0; + rsv->base = 0; + rsv->size = 0; + + status = efi_call_early(install_configuration_table, + &memreserve_table_guid, + rsv); + if (status != EFI_SUCCESS) + pr_efi_err(sys_table_arg, "Failed to install memreserve config table!\n"); +} + + /* * This function handles the architcture specific differences between arm and * arm64 regarding where the kernel image must be loaded and any memory that @@ -235,6 +260,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, } } + install_memreserve_table(sys_table); + new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(sys_table, handle, &new_fdt_addr, efi_get_max_fdt_addr(dram_base), diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index aa66cbf23512..a19d845bdb06 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -45,39 +45,7 @@ #define __efi_call_virt(f, args...) \ __efi_call_virt_pointer(efi.systab->runtime, f, args) -/* efi_runtime_service() function identifiers */ -enum efi_rts_ids { - GET_TIME, - SET_TIME, - GET_WAKEUP_TIME, - SET_WAKEUP_TIME, - GET_VARIABLE, - GET_NEXT_VARIABLE, - SET_VARIABLE, - QUERY_VARIABLE_INFO, - GET_NEXT_HIGH_MONO_COUNT, - UPDATE_CAPSULE, - QUERY_CAPSULE_CAPS, -}; - -/* - * efi_runtime_work: Details of EFI Runtime Service work - * @arg<1-5>: EFI Runtime Service function arguments - * @status: Status of executing EFI Runtime Service - * @efi_rts_id: EFI Runtime Service function identifier - * @efi_rts_comp: Struct used for handling completions - */ -struct efi_runtime_work { - void *arg1; - void *arg2; - void *arg3; - void *arg4; - void *arg5; - efi_status_t status; - struct work_struct work; - enum efi_rts_ids efi_rts_id; - struct completion efi_rts_comp; -}; +struct efi_runtime_work efi_rts_work; /* * efi_queue_work: Queue efi_runtime_service() and wait until it's done @@ -91,9 +59,13 @@ struct efi_runtime_work { */ #define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \ ({ \ - struct efi_runtime_work efi_rts_work; \ efi_rts_work.status = EFI_ABORTED; \ \ + if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \ + pr_warn_once("EFI Runtime Services are disabled!\n"); \ + goto exit; \ + } \ + \ init_completion(&efi_rts_work.efi_rts_comp); \ INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts); \ efi_rts_work.arg1 = _arg1; \ @@ -112,6 +84,8 @@ struct efi_runtime_work { else \ pr_err("Failed to queue work to efi_rts_wq.\n"); \ \ +exit: \ + efi_rts_work.efi_rts_id = NONE; \ efi_rts_work.status; \ }) @@ -184,18 +158,16 @@ static DEFINE_SEMAPHORE(efi_runtime_lock); */ static void efi_call_rts(struct work_struct *work) { - struct efi_runtime_work *efi_rts_work; void *arg1, *arg2, *arg3, *arg4, *arg5; efi_status_t status = EFI_NOT_FOUND; - efi_rts_work = container_of(work, struct efi_runtime_work, work); - arg1 = efi_rts_work->arg1; - arg2 = efi_rts_work->arg2; - arg3 = efi_rts_work->arg3; - arg4 = efi_rts_work->arg4; - arg5 = efi_rts_work->arg5; + arg1 = efi_rts_work.arg1; + arg2 = efi_rts_work.arg2; + arg3 = efi_rts_work.arg3; + arg4 = efi_rts_work.arg4; + arg5 = efi_rts_work.arg5; - switch (efi_rts_work->efi_rts_id) { + switch (efi_rts_work.efi_rts_id) { case GET_TIME: status = efi_call_virt(get_time, (efi_time_t *)arg1, (efi_time_cap_t *)arg2); @@ -253,8 +225,8 @@ static void efi_call_rts(struct work_struct *work) */ pr_err("Requested executing invalid EFI Runtime Service.\n"); } - efi_rts_work->status = status; - complete(&efi_rts_work->efi_rts_comp); + efi_rts_work.status = status; + complete(&efi_rts_work.efi_rts_comp); } static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) @@ -428,6 +400,7 @@ static void virt_efi_reset_system(int reset_type, "could not get exclusive access to the firmware\n"); return; } + efi_rts_work.efi_rts_id = RESET_SYSTEM; __efi_call_virt(reset_system, reset_type, status, data_size, data); up(&efi_runtime_lock); } diff --git a/drivers/firmware/efi/test/efi_test.c b/drivers/firmware/efi/test/efi_test.c index 41c48a1e8baa..769640940c9f 100644 --- a/drivers/firmware/efi/test/efi_test.c +++ b/drivers/firmware/efi/test/efi_test.c @@ -542,6 +542,30 @@ static long efi_runtime_get_nexthighmonocount(unsigned long arg) return 0; } +static long efi_runtime_reset_system(unsigned long arg) +{ + struct efi_resetsystem __user *resetsystem_user; + struct efi_resetsystem resetsystem; + void *data = NULL; + + resetsystem_user = (struct efi_resetsystem __user *)arg; + if (copy_from_user(&resetsystem, resetsystem_user, + sizeof(resetsystem))) + return -EFAULT; + if (resetsystem.data_size != 0) { + data = memdup_user((void *)resetsystem.data, + resetsystem.data_size); + if (IS_ERR(data)) + return PTR_ERR(data); + } + + efi.reset_system(resetsystem.reset_type, resetsystem.status, + resetsystem.data_size, (efi_char16_t *)data); + + kfree(data); + return 0; +} + static long efi_runtime_query_variableinfo(unsigned long arg) { struct efi_queryvariableinfo __user *queryvariableinfo_user; @@ -682,6 +706,9 @@ static long efi_test_ioctl(struct file *file, unsigned int cmd, case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES: return efi_runtime_query_capsulecaps(arg); + + case EFI_RUNTIME_RESET_SYSTEM: + return efi_runtime_reset_system(arg); } return -ENOTTY; diff --git a/drivers/firmware/efi/test/efi_test.h b/drivers/firmware/efi/test/efi_test.h index 9812c6a02b40..5f4818bf112f 100644 --- a/drivers/firmware/efi/test/efi_test.h +++ b/drivers/firmware/efi/test/efi_test.h @@ -81,6 +81,13 @@ struct efi_querycapsulecapabilities { efi_status_t *status; } __packed; +struct efi_resetsystem { + int reset_type; + efi_status_t status; + unsigned long data_size; + efi_char16_t *data; +} __packed; + #define EFI_RUNTIME_GET_VARIABLE \ _IOWR('p', 0x01, struct efi_getvariable) #define EFI_RUNTIME_SET_VARIABLE \ @@ -108,4 +115,7 @@ struct efi_querycapsulecapabilities { #define EFI_RUNTIME_QUERY_CAPSULECAPABILITIES \ _IOR('p', 0x0A, struct efi_querycapsulecapabilities) +#define EFI_RUNTIME_RESET_SYSTEM \ + _IOW('p', 0x0B, struct efi_resetsystem) + #endif /* _DRIVERS_FIRMWARE_EFI_TEST_H_ */ diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4f52c3a8ec99..833a1b51c948 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -200,6 +200,7 @@ config GPIO_EP93XX def_bool y depends on ARCH_EP93XX select GPIO_GENERIC + select GPIOLIB_IRQCHIP config GPIO_EXAR tristate "Support for GPIO pins on XR17V352/354/358" @@ -267,17 +268,6 @@ config GPIO_ICH If unsure, say N. -config GPIO_INGENIC - tristate "Ingenic JZ47xx SoCs GPIO support" - depends on OF - depends on MACH_INGENIC || COMPILE_TEST - select GPIOLIB_IRQCHIP - help - Say yes here to support the GPIO functionality present on the - JZ4740 and JZ4780 SoCs from Ingenic. - - If unsure, say N. - config GPIO_IOP tristate "Intel IOP GPIO" depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST @@ -439,6 +429,24 @@ config GPIO_REG A 32-bit single register GPIO fixed in/out implementation. This can be used to represent any register as a set of GPIO signals. +config GPIO_SIOX + tristate "SIOX GPIO support" + depends on SIOX + select GPIOLIB_IRQCHIP + help + Say yes here to support SIOX I/O devices. These are units connected + via a SIOX bus and have a number of fixed-direction I/O lines. + +config GPIO_SNPS_CREG + bool "Synopsys GPIO via CREG (Control REGisters) driver" + depends on ARC || COMPILE_TEST + depends on OF_GPIO + help + This driver supports GPIOs via CREG on various Synopsys SoCs. + This is a single-register MMIO GPIO driver for complex cases + where only several fields in register belong to GPIO lines and + each GPIO line owns a field with different length and on/off value. + config GPIO_SPEAR_SPICS bool "ST SPEAr13xx SPI Chip Select as GPIO support" depends on PLAT_SPEAR @@ -480,6 +488,7 @@ config GPIO_SYSCON config GPIO_TB10X bool + select GPIO_GENERIC select GENERIC_IRQ_CHIP select OF_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c256aff66a65..671c4477c951 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -3,8 +3,8 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG -obj-$(CONFIG_GPIOLIB) += devres.o obj-$(CONFIG_GPIOLIB) += gpiolib.o +obj-$(CONFIG_GPIOLIB) += gpiolib-devres.o obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o @@ -57,7 +57,6 @@ obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o -obj-$(CONFIG_GPIO_INGENIC) += gpio-ingenic.o obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT87) += gpio-it87.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o @@ -111,6 +110,7 @@ obj-$(CONFIG_GPIO_REG) += gpio-reg.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o +obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o @@ -125,6 +125,7 @@ obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o +obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 21452622d954..e321955782a1 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -172,7 +172,7 @@ static struct platform_driver adp5520_gpio_driver = { module_platform_driver(adp5520_gpio_driver); -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("GPIO ADP5520 Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:adp5520-gpio"); diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index da9781a2ef4a..cc33d8986ad3 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -494,6 +494,6 @@ static struct i2c_driver adp5588_gpio_driver = { module_i2c_driver(adp5588_gpio_driver); -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("GPIO ADP5588 Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index d0707fc23afd..c5536a509b59 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -373,6 +373,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) val = readl(reg_base + GPIO_INT_MASK(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MASK(bank_id)); + gpiochip_disable_irq(&kona_gpio->gpio_chip, gpio); raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -394,6 +395,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); + gpiochip_enable_irq(&kona_gpio->gpio_chip, gpio); raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -485,23 +487,15 @@ static void bcm_kona_gpio_irq_handler(struct irq_desc *desc) static int bcm_kona_gpio_irq_reqres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - int ret; - ret = gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq); - if (ret) { - dev_err(kona_gpio->gpio_chip.parent, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - return ret; - } - return 0; + return gpiochip_reqres_irq(&kona_gpio->gpio_chip, d->hwirq); } static void bcm_kona_gpio_irq_relres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - gpiochip_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); + gpiochip_relres_irq(&kona_gpio->gpio_chip, d->hwirq); } static struct irq_chip bcm_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 16c7f9f49416..af936dcca659 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -664,6 +664,18 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) struct brcmstb_gpio_bank *bank; struct gpio_chip *gc; + /* + * If bank_width is 0, then there is an empty bank in the + * register block. Special handling for this case. + */ + if (bank_width == 0) { + dev_dbg(dev, "Width 0 found: Empty bank @ %d\n", + num_banks); + num_banks++; + gpio_base += MAX_GPIO_PER_BANK; + continue; + } + bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); if (!bank) { err = -ENOMEM; @@ -740,9 +752,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) goto fail; } - dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n", - num_banks, priv->gpio_base, gpio_base - 1); - if (priv->parent_wake_irq && need_wakeup_event) pm_wakeup_event(dev, 0); diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c new file mode 100644 index 000000000000..8cbc94d0d424 --- /dev/null +++ b/drivers/gpio/gpio-creg-snps.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Synopsys CREG (Control REGisters) GPIO driver +// +// Copyright (C) 2018 Synopsys +// Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + +#include <linux/gpio/driver.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_platform.h> + +#define MAX_GPIO 32 + +struct creg_layout { + u8 ngpio; + u8 shift[MAX_GPIO]; + u8 on[MAX_GPIO]; + u8 off[MAX_GPIO]; + u8 bit_per_gpio[MAX_GPIO]; +}; + +struct creg_gpio { + struct gpio_chip gc; + void __iomem *regs; + spinlock_t lock; + const struct creg_layout *layout; +}; + +static void creg_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct creg_gpio *hcg = gpiochip_get_data(gc); + const struct creg_layout *layout = hcg->layout; + u32 reg, reg_shift, value; + unsigned long flags; + int i; + + value = val ? hcg->layout->on[offset] : hcg->layout->off[offset]; + + reg_shift = layout->shift[offset]; + for (i = 0; i < offset; i++) + reg_shift += layout->bit_per_gpio[i] + layout->shift[i]; + + spin_lock_irqsave(&hcg->lock, flags); + reg = readl(hcg->regs); + reg &= ~(GENMASK(layout->bit_per_gpio[i] - 1, 0) << reg_shift); + reg |= (value << reg_shift); + writel(reg, hcg->regs); + spin_unlock_irqrestore(&hcg->lock, flags); +} + +static int creg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) +{ + creg_gpio_set(gc, offset, val); + + return 0; +} + +static int creg_gpio_validate_pg(struct device *dev, struct creg_gpio *hcg, + int i) +{ + const struct creg_layout *layout = hcg->layout; + + if (layout->bit_per_gpio[i] < 1 || layout->bit_per_gpio[i] > 8) + return -EINVAL; + + /* Check that on valiue fits it's placeholder */ + if (GENMASK(31, layout->bit_per_gpio[i]) & layout->on[i]) + return -EINVAL; + + /* Check that off valiue fits it's placeholder */ + if (GENMASK(31, layout->bit_per_gpio[i]) & layout->off[i]) + return -EINVAL; + + if (layout->on[i] == layout->off[i]) + return -EINVAL; + + return 0; +} + +static int creg_gpio_validate(struct device *dev, struct creg_gpio *hcg, + u32 ngpios) +{ + u32 reg_len = 0; + int i; + + if (hcg->layout->ngpio < 1 || hcg->layout->ngpio > MAX_GPIO) + return -EINVAL; + + if (ngpios < 1 || ngpios > hcg->layout->ngpio) { + dev_err(dev, "ngpios must be in [1:%u]\n", hcg->layout->ngpio); + return -EINVAL; + } + + for (i = 0; i < hcg->layout->ngpio; i++) { + if (creg_gpio_validate_pg(dev, hcg, i)) + return -EINVAL; + + reg_len += hcg->layout->shift[i] + hcg->layout->bit_per_gpio[i]; + } + + /* Check that we fit in 32 bit register */ + if (reg_len > 32) + return -EINVAL; + + return 0; +} + +static const struct creg_layout hsdk_cs_ctl = { + .ngpio = 10, + .shift = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + .off = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + .on = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, + .bit_per_gpio = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 } +}; + +static const struct creg_layout axs10x_flsh_cs_ctl = { + .ngpio = 1, + .shift = { 0 }, + .off = { 1 }, + .on = { 3 }, + .bit_per_gpio = { 2 } +}; + +static const struct of_device_id creg_gpio_ids[] = { + { + .compatible = "snps,creg-gpio-axs10x", + .data = &axs10x_flsh_cs_ctl + }, { + .compatible = "snps,creg-gpio-hsdk", + .data = &hsdk_cs_ctl + }, { /* sentinel */ } +}; + +static int creg_gpio_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device *dev = &pdev->dev; + struct creg_gpio *hcg; + struct resource *mem; + u32 ngpios; + int ret; + + hcg = devm_kzalloc(dev, sizeof(struct creg_gpio), GFP_KERNEL); + if (!hcg) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcg->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(hcg->regs)) + return PTR_ERR(hcg->regs); + + match = of_match_node(creg_gpio_ids, pdev->dev.of_node); + hcg->layout = match->data; + if (!hcg->layout) + return -EINVAL; + + ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios); + if (ret) + return ret; + + ret = creg_gpio_validate(dev, hcg, ngpios); + if (ret) + return ret; + + spin_lock_init(&hcg->lock); + + hcg->gc.label = dev_name(dev); + hcg->gc.base = -1; + hcg->gc.ngpio = ngpios; + hcg->gc.set = creg_gpio_set; + hcg->gc.direction_output = creg_gpio_dir_out; + hcg->gc.of_node = dev->of_node; + + ret = devm_gpiochip_add_data(dev, &hcg->gc, hcg); + if (ret) + return ret; + + dev_info(dev, "GPIO controller with %d gpios probed\n", ngpios); + + return 0; +} + +static struct platform_driver creg_gpio_snps_driver = { + .driver = { + .name = "snps-creg-gpio", + .of_match_table = creg_gpio_ids, + }, + .probe = creg_gpio_probe, +}; +builtin_platform_driver(creg_gpio_snps_driver); diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index a5ece8ea79bc..5c1564fcc24e 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -9,6 +9,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ + #include <linux/gpio/driver.h> #include <linux/errno.h> #include <linux/kernel.h> @@ -24,6 +25,12 @@ #include <linux/platform_device.h> #include <linux/platform_data/gpio-davinci.h> #include <linux/irqchip/chained_irq.h> +#include <linux/spinlock.h> + +#include <asm-generic/gpio.h> + +#define MAX_REGS_BANKS 5 +#define MAX_INT_PER_BANK 32 struct davinci_gpio_regs { u32 dir; @@ -41,11 +48,31 @@ struct davinci_gpio_regs { typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ -#define MAX_LABEL_SIZE 20 static void __iomem *gpio_base; static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0}; +struct davinci_gpio_irq_data { + void __iomem *regs; + struct davinci_gpio_controller *chip; + int bank_num; +}; + +struct davinci_gpio_controller { + struct gpio_chip chip; + struct irq_domain *irq_domain; + /* Serialize access to GPIO registers */ + spinlock_t lock; + void __iomem *regs[MAX_REGS_BANKS]; + int gpio_unbanked; + int irqs[MAX_INT_PER_BANK]; +}; + +static inline u32 __gpio_mask(unsigned gpio) +{ + return 1 << (gpio % 32); +} + static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) { struct davinci_gpio_regs __iomem *g; @@ -166,14 +193,12 @@ of_err: static int davinci_gpio_probe(struct platform_device *pdev) { - static int ctrl_num, bank_base; - int gpio, bank, i, ret = 0; + int bank, i, ret = 0; unsigned int ngpio, nbank, nirq; struct davinci_gpio_controller *chips; struct davinci_gpio_platform_data *pdata; struct device *dev = &pdev->dev; struct resource *res; - char label[MAX_LABEL_SIZE]; pdata = davinci_gpio_get_pdata(pdev); if (!pdata) { @@ -207,10 +232,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) else nirq = DIV_ROUND_UP(ngpio, 16); - nbank = DIV_ROUND_UP(ngpio, 32); - chips = devm_kcalloc(dev, - nbank, sizeof(struct davinci_gpio_controller), - GFP_KERNEL); + chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL); if (!chips) return -ENOMEM; @@ -228,10 +250,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) } } - snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++); - chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL); - if (!chips->chip.label) - return -ENOMEM; + chips->chip.label = dev_name(dev); chips->chip.direction_input = davinci_direction_in; chips->chip.get = davinci_gpio_get; @@ -239,7 +258,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->chip.set = davinci_gpio_set; chips->chip.ngpio = ngpio; - chips->chip.base = bank_base; + chips->chip.base = -1; #ifdef CONFIG_OF_GPIO chips->chip.of_gpio_n_cells = 2; @@ -252,28 +271,21 @@ static int davinci_gpio_probe(struct platform_device *pdev) } #endif spin_lock_init(&chips->lock); - bank_base += ngpio; - for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++) + nbank = DIV_ROUND_UP(ngpio, 32); + for (bank = 0; bank < nbank; bank++) chips->regs[bank] = gpio_base + offset_array[bank]; ret = devm_gpiochip_add_data(dev, &chips->chip, chips); if (ret) - goto err; + return ret; platform_set_drvdata(pdev, chips); ret = davinci_gpio_irq_setup(pdev); if (ret) - goto err; + return ret; return 0; - -err: - /* Revert the static variable increments */ - ctrl_num--; - bank_base -= ngpio; - - return ret; } /*--------------------------------------------------------------------------*/ diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 45d384039e9b..71728d6e0bca 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Generic EP93xx GPIO handling * @@ -6,10 +7,6 @@ * * Based on code originally from: * linux/arch/arm/mach-ep93xx/core.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> @@ -19,16 +16,26 @@ #include <linux/irq.h> #include <linux/slab.h> #include <linux/gpio/driver.h> -/* FIXME: this is here for gpio_to_irq() - get rid of this! */ -#include <linux/gpio.h> +#include <linux/bitops.h> + +#define EP93XX_GPIO_F_INT_STATUS 0x5c +#define EP93XX_GPIO_A_INT_STATUS 0xa0 +#define EP93XX_GPIO_B_INT_STATUS 0xbc + +/* Maximum value for gpio line identifiers */ +#define EP93XX_GPIO_LINE_MAX 63 -#include <mach/hardware.h> -#include <mach/gpio-ep93xx.h> +/* Maximum value for irq capable line identifiers */ +#define EP93XX_GPIO_LINE_MAX_IRQ 23 -#define irq_to_gpio(irq) ((irq) - gpio_to_irq(0)) +/* + * Static mapping of GPIO bank F IRQS: + * F0..F7 (16..24) to irq 80..87. + */ +#define EP93XX_GPIO_F_IRQ_BASE 80 struct ep93xx_gpio { - void __iomem *mmio_base; + void __iomem *base; struct gpio_chip gc[8]; }; @@ -48,27 +55,45 @@ static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 }; static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 }; static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 }; -static void ep93xx_gpio_update_int_params(unsigned port) +static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, unsigned port) { BUG_ON(port > 2); - writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port])); + writeb_relaxed(0, epg->base + int_en_register_offset[port]); writeb_relaxed(gpio_int_type2[port], - EP93XX_GPIO_REG(int_type2_register_offset[port])); + epg->base + int_type2_register_offset[port]); writeb_relaxed(gpio_int_type1[port], - EP93XX_GPIO_REG(int_type1_register_offset[port])); + epg->base + int_type1_register_offset[port]); writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], - EP93XX_GPIO_REG(int_en_register_offset[port])); + epg->base + int_en_register_offset[port]); +} + +static int ep93xx_gpio_port(struct gpio_chip *gc) +{ + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + int port = 0; + + while (port < ARRAY_SIZE(epg->gc) && gc != &epg->gc[port]) + port++; + + /* This should not happen but is there as a last safeguard */ + if (port == ARRAY_SIZE(epg->gc)) { + pr_crit("can't find the GPIO port\n"); + return 0; + } + + return port; } -static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) +static void ep93xx_gpio_int_debounce(struct gpio_chip *gc, + unsigned int offset, bool enable) { - int line = irq_to_gpio(irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + int port = ep93xx_gpio_port(gc); + int port_mask = BIT(offset); if (enable) gpio_int_debounce[port] |= port_mask; @@ -76,29 +101,36 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) gpio_int_debounce[port] &= ~port_mask; writeb(gpio_int_debounce[port], - EP93XX_GPIO_REG(int_debounce_register_offset[port])); + epg->base + int_debounce_register_offset[port]); } static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc) { - unsigned char status; - int i; + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + unsigned long stat; + int offset; - status = readb(EP93XX_GPIO_A_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; - generic_handle_irq(gpio_irq); - } - } + chained_irq_enter(irqchip, desc); - status = readb(EP93XX_GPIO_B_INT_STATUS); - for (i = 0; i < 8; i++) { - if (status & (1 << i)) { - int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; - generic_handle_irq(gpio_irq); - } - } + /* + * Dispatch the IRQs to the irqdomain of each A and B + * gpiochip irqdomains depending on what has fired. + * The tricky part is that the IRQ line is shared + * between bank A and B and each has their own gpiochip. + */ + stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS); + for_each_set_bit(offset, &stat, 8) + generic_handle_irq(irq_find_mapping(epg->gc[0].irq.domain, + offset)); + + stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS); + for_each_set_bit(offset, &stat, 8) + generic_handle_irq(irq_find_mapping(epg->gc[1].irq.domain, + offset)); + + chained_irq_exit(irqchip, desc); } static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) @@ -106,60 +138,67 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) /* * map discontiguous hw irq range to continuous sw irq range: * - * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) + * IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7} */ + 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 gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; + int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx; + chained_irq_enter(irqchip, desc); generic_handle_irq(gpio_irq); + chained_irq_exit(irqchip, desc); } static void ep93xx_gpio_irq_ack(struct irq_data *d) { - int line = irq_to_gpio(d->irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + int port = ep93xx_gpio_port(gc); + int port_mask = BIT(d->irq & 7); if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { gpio_int_type2[port] ^= port_mask; /* switch edge direction */ - ep93xx_gpio_update_int_params(port); + ep93xx_gpio_update_int_params(epg, port); } - writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, epg->base + eoi_register_offset[port]); } static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) { - int line = irq_to_gpio(d->irq); - int port = line >> 3; - int port_mask = 1 << (line & 7); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + int port = ep93xx_gpio_port(gc); + int port_mask = BIT(d->irq & 7); if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) gpio_int_type2[port] ^= port_mask; /* switch edge direction */ gpio_int_unmasked[port] &= ~port_mask; - ep93xx_gpio_update_int_params(port); + ep93xx_gpio_update_int_params(epg, port); - writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, epg->base + eoi_register_offset[port]); } static void ep93xx_gpio_irq_mask(struct irq_data *d) { - int line = irq_to_gpio(d->irq); - int port = line >> 3; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + int port = ep93xx_gpio_port(gc); - gpio_int_unmasked[port] &= ~(1 << (line & 7)); - ep93xx_gpio_update_int_params(port); + gpio_int_unmasked[port] &= ~BIT(d->irq & 7); + ep93xx_gpio_update_int_params(epg, port); } static void ep93xx_gpio_irq_unmask(struct irq_data *d) { - int line = irq_to_gpio(d->irq); - int port = line >> 3; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + int port = ep93xx_gpio_port(gc); - gpio_int_unmasked[port] |= 1 << (line & 7); - ep93xx_gpio_update_int_params(port); + gpio_int_unmasked[port] |= BIT(d->irq & 7); + ep93xx_gpio_update_int_params(epg, port); } /* @@ -169,12 +208,14 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d) */ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) { - const int gpio = irq_to_gpio(d->irq); - const int port = gpio >> 3; - const int port_mask = 1 << (gpio & 7); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct ep93xx_gpio *epg = gpiochip_get_data(gc); + int port = ep93xx_gpio_port(gc); + int offset = d->irq & 7; + int port_mask = BIT(offset); irq_flow_handler_t handler; - gpio_direction_input(gpio); + gc->direction_input(gc, offset); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -200,7 +241,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) case IRQ_TYPE_EDGE_BOTH: gpio_int_type1[port] |= port_mask; /* set initial polarity based on current input level */ - if (gpio_get_value(gpio)) + if (gc->get(gc, offset)) gpio_int_type2[port] &= ~port_mask; /* falling */ else gpio_int_type2[port] |= port_mask; /* rising */ @@ -214,7 +255,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) gpio_int_enabled[port] |= port_mask; - ep93xx_gpio_update_int_params(port); + ep93xx_gpio_update_int_params(epg, port); return 0; } @@ -228,35 +269,53 @@ static struct irq_chip ep93xx_gpio_irq_chip = { .irq_set_type = ep93xx_gpio_irq_type, }; -static void ep93xx_gpio_init_irq(void) +static int ep93xx_gpio_init_irq(struct platform_device *pdev, + struct ep93xx_gpio *epg) { + int ab_parent_irq = platform_get_irq(pdev, 0); + struct device *dev = &pdev->dev; int gpio_irq; + int ret; + int i; - for (gpio_irq = gpio_to_irq(0); - gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { + /* The A bank */ + ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip, + 64, handle_level_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "Could not add irqchip 0\n"); + return ret; + } + gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip, + ab_parent_irq, + ep93xx_gpio_ab_irq_handler); + + /* The B bank */ + ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip, + 72, handle_level_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "Could not add irqchip 1\n"); + return ret; + } + gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip, + ab_parent_irq, + ep93xx_gpio_ab_irq_handler); + + /* The F bank */ + for (i = 0; i < 8; i++) { + gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i; + irq_set_chip_data(gpio_irq, &epg->gc[5]); irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, handle_level_irq); irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); } - irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, - ep93xx_gpio_ab_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO0MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO1MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO2MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO3MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO4MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO5MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO6MUX, - ep93xx_gpio_f_irq_handler); - irq_set_chained_handler(IRQ_EP93XX_GPIO7MUX, - ep93xx_gpio_f_irq_handler); + for (i = 1; i <= 8; i++) + irq_set_chained_handler_and_data(platform_get_irq(pdev, i), + ep93xx_gpio_f_irq_handler, + &epg->gc[i]); + return 0; } @@ -268,68 +327,54 @@ struct ep93xx_gpio_bank { int data; int dir; int base; - bool has_debounce; + bool has_irq; }; -#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _debounce) \ +#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \ { \ .label = _label, \ .data = _data, \ .dir = _dir, \ .base = _base, \ - .has_debounce = _debounce, \ + .has_irq = _has_irq, \ } static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = { - EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), - EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), + EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */ + EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */ EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false), EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false), EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false), - EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), + EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */ EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false), EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false), }; -static int ep93xx_gpio_set_config(struct gpio_chip *chip, unsigned offset, +static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset, unsigned long config) { - int gpio = chip->base + offset; - int irq = gpio_to_irq(gpio); u32 debounce; if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) return -ENOTSUPP; - if (irq < 0) - return -EINVAL; - debounce = pinconf_to_config_argument(config); - ep93xx_gpio_int_debounce(irq, debounce ? true : false); + ep93xx_gpio_int_debounce(gc, offset, debounce ? true : false); return 0; } -/* - * Map GPIO A0..A7 (0..7) to irq 64..71, - * B0..B7 (7..15) to irq 72..79, and - * F0..F7 (16..24) to irq 80..87. - */ -static int ep93xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset) { - int gpio = chip->base + offset; - - if (gpio > EP93XX_GPIO_LINE_MAX_IRQ) - return -EINVAL; - - return 64 + gpio; + return EP93XX_GPIO_F_IRQ_BASE + offset; } static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev, - void __iomem *mmio_base, struct ep93xx_gpio_bank *bank) + struct ep93xx_gpio *epg, + struct ep93xx_gpio_bank *bank) { - void __iomem *data = mmio_base + bank->data; - void __iomem *dir = mmio_base + bank->dir; + void __iomem *data = epg->base + bank->data; + void __iomem *dir = epg->base + bank->dir; int err; err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0); @@ -339,41 +384,41 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev, gc->label = bank->label; gc->base = bank->base; - if (bank->has_debounce) { + if (bank->has_irq) gc->set_config = ep93xx_gpio_set_config; - gc->to_irq = ep93xx_gpio_to_irq; - } - return devm_gpiochip_add_data(dev, gc, NULL); + return devm_gpiochip_add_data(dev, gc, epg); } static int ep93xx_gpio_probe(struct platform_device *pdev) { - struct ep93xx_gpio *ep93xx_gpio; + struct ep93xx_gpio *epg; struct resource *res; int i; struct device *dev = &pdev->dev; - ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL); - if (!ep93xx_gpio) + epg = devm_kzalloc(dev, sizeof(*epg), GFP_KERNEL); + if (!epg) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ep93xx_gpio->mmio_base)) - return PTR_ERR(ep93xx_gpio->mmio_base); + epg->base = devm_ioremap_resource(dev, res); + if (IS_ERR(epg->base)) + return PTR_ERR(epg->base); for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { - struct gpio_chip *gc = &ep93xx_gpio->gc[i]; + struct gpio_chip *gc = &epg->gc[i]; struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; - if (ep93xx_gpio_add_bank(gc, &pdev->dev, - ep93xx_gpio->mmio_base, bank)) + if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank)) dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", - bank->label); + bank->label); + /* Only bank F has especially funky IRQ handling */ + if (i == 5) + gc->to_irq = ep93xx_gpio_f_to_irq; } - ep93xx_gpio_init_irq(); + ep93xx_gpio_init_irq(pdev, epg); return 0; } diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 868bf8501560..95f578804b0e 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -15,6 +15,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/bitops.h> +#include <linux/clk.h> /* GPIO registers definition */ #define GPIO_DATA_OUT 0x00 @@ -40,11 +41,14 @@ * struct ftgpio_gpio - Gemini GPIO state container * @dev: containing device for this instance * @gc: gpiochip for this instance + * @base: remapped I/O-memory base + * @clk: silicon clock */ struct ftgpio_gpio { struct device *dev; struct gpio_chip gc; void __iomem *base; + struct clk *clk; }; static void ftgpio_gpio_ack_irq(struct irq_data *d) @@ -157,6 +161,73 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } +static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset, + unsigned long config) +{ + enum pin_config_param param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + struct ftgpio_gpio *g = gpiochip_get_data(gc); + unsigned long pclk_freq; + u32 deb_div; + u32 val; + + if (param != PIN_CONFIG_INPUT_DEBOUNCE) + return -ENOTSUPP; + + /* + * Debounce only works if interrupts are enabled. The manual + * states that if PCLK is 66 MHz, and this is set to 0x7D0, then + * PCLK is divided down to 33 kHz for the debounce timer. 0x7D0 is + * 2000 decimal, so what they mean is simply that the PCLK is + * divided by this value. + * + * As we get a debounce setting in microseconds, we calculate the + * desired period time and see if we can get a suitable debounce + * time. + */ + pclk_freq = clk_get_rate(g->clk); + deb_div = DIV_ROUND_CLOSEST(pclk_freq, arg); + + /* This register is only 24 bits wide */ + if (deb_div > (1 << 24)) + return -ENOTSUPP; + + dev_dbg(g->dev, "prescale divisor: %08x, resulting frequency %lu Hz\n", + deb_div, (pclk_freq/deb_div)); + + val = readl(g->base + GPIO_DEBOUNCE_PRESCALE); + if (val == deb_div) { + /* + * The debounce timer happens to already be set to the + * desireable value, what a coincidence! We can just enable + * debounce on this GPIO line and return. This happens more + * often than you think, for example when all GPIO keys + * on a system are requesting the same debounce interval. + */ + val = readl(g->base + GPIO_DEBOUNCE_EN); + val |= BIT(offset); + writel(val, g->base + GPIO_DEBOUNCE_EN); + return 0; + } + + val = readl(g->base + GPIO_DEBOUNCE_EN); + if (val) { + /* + * Oh no! Someone is already using the debounce with + * another setting than what we need. Bummer. + */ + return -ENOTSUPP; + } + + /* First come, first serve */ + writel(deb_div, g->base + GPIO_DEBOUNCE_PRESCALE); + /* Enable debounce */ + val |= BIT(offset); + writel(val, g->base + GPIO_DEBOUNCE_EN); + + return 0; +} + static int ftgpio_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -180,6 +251,19 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) if (irq <= 0) return irq ? irq : -EINVAL; + g->clk = devm_clk_get(dev, NULL); + if (!IS_ERR(g->clk)) { + ret = clk_prepare_enable(g->clk); + if (ret) + return ret; + } else if (PTR_ERR(g->clk) == -EPROBE_DEFER) { + /* + * Percolate deferrals, for anything else, + * just live without the clocking. + */ + return PTR_ERR(g->clk); + } + ret = bgpio_init(&g->gc, dev, 4, g->base + GPIO_DATA_IN, g->base + GPIO_DATA_SET, @@ -189,7 +273,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) 0); if (ret) { dev_err(dev, "unable to init generic GPIO\n"); - return ret; + goto dis_clk; } g->gc.label = "FTGPIO010"; g->gc.base = -1; @@ -197,28 +281,50 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) g->gc.owner = THIS_MODULE; /* ngpio is set by bgpio_init() */ + /* We need a silicon clock to do debounce */ + if (!IS_ERR(g->clk)) + g->gc.set_config = ftgpio_gpio_set_config; + ret = devm_gpiochip_add_data(dev, &g->gc, g); if (ret) - return ret; + goto dis_clk; /* Disable, unmask and clear all interrupts */ writel(0x0, g->base + GPIO_INT_EN); writel(0x0, g->base + GPIO_INT_MASK); writel(~0x0, g->base + GPIO_INT_CLR); + /* Clear any use of debounce */ + writel(0x0, g->base + GPIO_DEBOUNCE_EN); + ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip, 0, handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_info(dev, "could not add irqchip\n"); - return ret; + goto dis_clk; } gpiochip_set_chained_irqchip(&g->gc, &ftgpio_gpio_irqchip, irq, ftgpio_gpio_irq_handler); + platform_set_drvdata(pdev, g); dev_info(dev, "FTGPIO010 @%p registered\n", g->base); return 0; + +dis_clk: + if (!IS_ERR(g->clk)) + clk_disable_unprepare(g->clk); + return ret; +} + +static int ftgpio_gpio_remove(struct platform_device *pdev) +{ + struct ftgpio_gpio *g = platform_get_drvdata(pdev); + + if (!IS_ERR(g->clk)) + clk_disable_unprepare(g->clk); + return 0; } static const struct of_device_id ftgpio_gpio_of_match[] = { @@ -239,6 +345,7 @@ static struct platform_driver ftgpio_gpio_driver = { .name = "ftgpio010-gpio", .of_match_table = of_match_ptr(ftgpio_gpio_of_match), }, - .probe = ftgpio_gpio_probe, + .probe = ftgpio_gpio_probe, + .remove = ftgpio_gpio_remove, }; builtin_platform_driver(ftgpio_gpio_driver); diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index ad6e5b518669..9d3ac51a765c 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -189,7 +189,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) unsigned long flag; struct egpio_chip *egpio; struct egpio_info *ei; - unsigned bit; int pos; int reg; int shift; @@ -199,7 +198,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) egpio = gpiochip_get_data(chip); ei = dev_get_drvdata(egpio->dev); - bit = egpio_bit(ei, offset); pos = egpio_pos(ei, offset); reg = egpio->reg_start + pos; shift = pos << ei->reg_shift; @@ -334,7 +332,13 @@ static int __init egpio_probe(struct platform_device *pdev) ei->chip[i].is_out = pdata->chip[i].direction; ei->chip[i].dev = &(pdev->dev); chip = &(ei->chip[i].chip); - chip->label = "htc-egpio"; + chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "htc-egpio-%d", + i); + if (!chip->label) { + ret = -ENOMEM; + goto fail; + } chip->parent = &pdev->dev; chip->owner = THIS_MODULE; chip->get = egpio_get; diff --git a/drivers/gpio/gpio-ingenic.c b/drivers/gpio/gpio-ingenic.c deleted file mode 100644 index e738e384a5ca..000000000000 --- a/drivers/gpio/gpio-ingenic.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Ingenic JZ47xx GPIO driver - * - * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net> - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#include <linux/gpio/driver.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_irq.h> -#include <linux/pinctrl/consumer.h> -#include <linux/regmap.h> - -#define GPIO_PIN 0x00 -#define GPIO_MSK 0x20 - -#define JZ4740_GPIO_DATA 0x10 -#define JZ4740_GPIO_SELECT 0x50 -#define JZ4740_GPIO_DIR 0x60 -#define JZ4740_GPIO_TRIG 0x70 -#define JZ4740_GPIO_FLAG 0x80 - -#define JZ4770_GPIO_INT 0x10 -#define JZ4770_GPIO_PAT1 0x30 -#define JZ4770_GPIO_PAT0 0x40 -#define JZ4770_GPIO_FLAG 0x50 - -#define REG_SET(x) ((x) + 0x4) -#define REG_CLEAR(x) ((x) + 0x8) - -enum jz_version { - ID_JZ4740, - ID_JZ4770, - ID_JZ4780, -}; - -struct ingenic_gpio_chip { - struct regmap *map; - struct gpio_chip gc; - struct irq_chip irq_chip; - unsigned int irq, reg_base; - enum jz_version version; -}; - -static u32 gpio_ingenic_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg) -{ - unsigned int val; - - regmap_read(jzgc->map, jzgc->reg_base + reg, &val); - - return (u32) val; -} - -static void gpio_ingenic_set_bit(struct ingenic_gpio_chip *jzgc, - u8 reg, u8 offset, bool set) -{ - if (set) - reg = REG_SET(reg); - else - reg = REG_CLEAR(reg); - - regmap_write(jzgc->map, jzgc->reg_base + reg, BIT(offset)); -} - -static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset) -{ - unsigned int val = gpio_ingenic_read_reg(jzgc, GPIO_PIN); - - return !!(val & BIT(offset)); -} - -static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value) -{ - if (jzgc->version >= ID_JZ4770) - gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value); - else - gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value); -} - -static void irq_set_type(struct ingenic_gpio_chip *jzgc, - u8 offset, unsigned int type) -{ - u8 reg1, reg2; - - if (jzgc->version >= ID_JZ4770) { - reg1 = JZ4770_GPIO_PAT1; - reg2 = JZ4770_GPIO_PAT0; - } else { - reg1 = JZ4740_GPIO_TRIG; - reg2 = JZ4740_GPIO_DIR; - } - - switch (type) { - case IRQ_TYPE_EDGE_RISING: - gpio_ingenic_set_bit(jzgc, reg2, offset, true); - gpio_ingenic_set_bit(jzgc, reg1, offset, true); - break; - case IRQ_TYPE_EDGE_FALLING: - gpio_ingenic_set_bit(jzgc, reg2, offset, false); - gpio_ingenic_set_bit(jzgc, reg1, offset, true); - break; - case IRQ_TYPE_LEVEL_HIGH: - gpio_ingenic_set_bit(jzgc, reg2, offset, true); - gpio_ingenic_set_bit(jzgc, reg1, offset, false); - break; - case IRQ_TYPE_LEVEL_LOW: - default: - gpio_ingenic_set_bit(jzgc, reg2, offset, false); - gpio_ingenic_set_bit(jzgc, reg1, offset, false); - break; - } -} - -static void ingenic_gpio_irq_mask(struct irq_data *irqd) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - - gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true); -} - -static void ingenic_gpio_irq_unmask(struct irq_data *irqd) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - - gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false); -} - -static void ingenic_gpio_irq_enable(struct irq_data *irqd) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - int irq = irqd->hwirq; - - if (jzgc->version >= ID_JZ4770) - gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, true); - else - gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true); - - ingenic_gpio_irq_unmask(irqd); -} - -static void ingenic_gpio_irq_disable(struct irq_data *irqd) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - int irq = irqd->hwirq; - - ingenic_gpio_irq_mask(irqd); - - if (jzgc->version >= ID_JZ4770) - gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, false); - else - gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false); -} - -static void ingenic_gpio_irq_ack(struct irq_data *irqd) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - int irq = irqd->hwirq; - bool high; - - if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) { - /* - * Switch to an interrupt for the opposite edge to the one that - * triggered the interrupt being ACKed. - */ - high = gpio_get_value(jzgc, irq); - if (high) - irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING); - else - irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING); - } - - if (jzgc->version >= ID_JZ4770) - gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); - else - gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); -} - -static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - - switch (type) { - case IRQ_TYPE_EDGE_BOTH: - case IRQ_TYPE_EDGE_RISING: - case IRQ_TYPE_EDGE_FALLING: - irq_set_handler_locked(irqd, handle_edge_irq); - break; - case IRQ_TYPE_LEVEL_HIGH: - case IRQ_TYPE_LEVEL_LOW: - irq_set_handler_locked(irqd, handle_level_irq); - break; - default: - irq_set_handler_locked(irqd, handle_bad_irq); - } - - if (type == IRQ_TYPE_EDGE_BOTH) { - /* - * The hardware does not support interrupts on both edges. The - * best we can do is to set up a single-edge interrupt and then - * switch to the opposing edge when ACKing the interrupt. - */ - bool high = gpio_get_value(jzgc, irqd->hwirq); - - type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING; - } - - irq_set_type(jzgc, irqd->hwirq, type); - return 0; -} - -static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - - return irq_set_irq_wake(jzgc->irq, on); -} - -static void ingenic_gpio_irq_handler(struct irq_desc *desc) -{ - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data); - unsigned long flag, i; - - chained_irq_enter(irq_chip, desc); - - if (jzgc->version >= ID_JZ4770) - flag = gpio_ingenic_read_reg(jzgc, JZ4770_GPIO_FLAG); - else - flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG); - - for_each_set_bit(i, &flag, 32) - generic_handle_irq(irq_linear_revmap(gc->irq.domain, i)); - chained_irq_exit(irq_chip, desc); -} - -static void ingenic_gpio_set(struct gpio_chip *gc, - unsigned int offset, int value) -{ - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - - gpio_set_value(jzgc, offset, value); -} - -static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset) -{ - struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); - - return (int) gpio_get_value(jzgc, offset); -} - -static int ingenic_gpio_direction_input(struct gpio_chip *gc, - unsigned int offset) -{ - return pinctrl_gpio_direction_input(gc->base + offset); -} - -static int ingenic_gpio_direction_output(struct gpio_chip *gc, - unsigned int offset, int value) -{ - ingenic_gpio_set(gc, offset, value); - return pinctrl_gpio_direction_output(gc->base + offset); -} - -static const struct of_device_id ingenic_gpio_of_match[] = { - { .compatible = "ingenic,jz4740-gpio", .data = (void *)ID_JZ4740 }, - { .compatible = "ingenic,jz4770-gpio", .data = (void *)ID_JZ4770 }, - { .compatible = "ingenic,jz4780-gpio", .data = (void *)ID_JZ4780 }, - {}, -}; -MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match); - -static int ingenic_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct ingenic_gpio_chip *jzgc; - u32 bank; - int err; - - jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL); - if (!jzgc) - return -ENOMEM; - - jzgc->map = dev_get_drvdata(dev->parent); - if (!jzgc->map) { - dev_err(dev, "Cannot get parent regmap\n"); - return -ENXIO; - } - - err = of_property_read_u32(dev->of_node, "reg", &bank); - if (err) { - dev_err(dev, "Cannot read \"reg\" property: %i\n", err); - return err; - } - - jzgc->reg_base = bank * 0x100; - - jzgc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "GPIO%c", 'A' + bank); - if (!jzgc->gc.label) - return -ENOMEM; - - /* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY - * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN - * <linux/gpio/consumer.h> INSTEAD. - */ - jzgc->gc.base = bank * 32; - - jzgc->gc.ngpio = 32; - jzgc->gc.parent = dev; - jzgc->gc.of_node = dev->of_node; - jzgc->gc.owner = THIS_MODULE; - jzgc->version = (enum jz_version)of_device_get_match_data(dev); - - jzgc->gc.set = ingenic_gpio_set; - jzgc->gc.get = ingenic_gpio_get; - jzgc->gc.direction_input = ingenic_gpio_direction_input; - jzgc->gc.direction_output = ingenic_gpio_direction_output; - - if (of_property_read_bool(dev->of_node, "gpio-ranges")) { - jzgc->gc.request = gpiochip_generic_request; - jzgc->gc.free = gpiochip_generic_free; - } - - err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc); - if (err) - return err; - - jzgc->irq = irq_of_parse_and_map(dev->of_node, 0); - if (!jzgc->irq) - return -EINVAL; - - jzgc->irq_chip.name = jzgc->gc.label; - jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable; - jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable; - jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask; - jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask; - jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack; - jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type; - jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake; - jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND; - - err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0, - handle_level_irq, IRQ_TYPE_NONE); - if (err) - return err; - - gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip, - jzgc->irq, ingenic_gpio_irq_handler); - return 0; -} - -static int ingenic_gpio_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver ingenic_gpio_driver = { - .driver = { - .name = "gpio-ingenic", - .of_match_table = of_match_ptr(ingenic_gpio_of_match), - }, - .probe = ingenic_gpio_probe, - .remove = ingenic_gpio_remove, -}; - -static int __init ingenic_gpio_drv_register(void) -{ - return platform_driver_register(&ingenic_gpio_driver); -} -subsys_initcall(ingenic_gpio_drv_register); - -static void __exit ingenic_gpio_drv_unregister(void) -{ - platform_driver_unregister(&ingenic_gpio_driver); -} -module_exit(ingenic_gpio_drv_unregister); - -MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); -MODULE_DESCRIPTION("Ingenic JZ47xx GPIO driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index b5b9cb1fda50..9a8876abeb57 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -313,18 +313,21 @@ static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset, static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, struct gpio_desc **desc, + struct gpio_array *info, int value) { - int i, *values; + unsigned long *values; - values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL); + values = bitmap_alloc(ndescs, GFP_KERNEL); if (!values) return; - for (i = 0; i < ndescs; i++) - values[i] = value; + if (value) + bitmap_fill(values, ndescs); + else + bitmap_zero(values, ndescs); - gpiod_set_array_value_cansleep(ndescs, desc, values); + gpiod_set_array_value_cansleep(ndescs, desc, info, values); kfree(values); } @@ -397,7 +400,8 @@ static int max3191x_probe(struct spi_device *spi) if (max3191x->modesel_pins) gpiod_set_array_single_value_cansleep( max3191x->modesel_pins->ndescs, - max3191x->modesel_pins->desc, max3191x->mode); + max3191x->modesel_pins->desc, + max3191x->modesel_pins->info, max3191x->mode); max3191x->ignore_uv = device_property_read_bool(dev, "maxim,ignore-undervoltage"); diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 935292a30c99..50bdc29591c0 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Generic driver for memory-mapped GPIO controllers. * * Copyright 2008 MontaVista Software, Inc. * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`....... * ...`` ```````.. * ..The simplest form of a GPIO controller that the driver supports is`` diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index d66b7a768ecd..8269cffc2967 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -18,6 +18,7 @@ #include <linux/irq_sim.h> #include <linux/debugfs.h> #include <linux/uaccess.h> +#include <linux/property.h> #include "gpiolib.h" @@ -28,6 +29,8 @@ * of GPIO lines. */ #define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2) +/* Maximum of three properties + the sentinel. */ +#define GPIO_MOCKUP_MAX_PROP 4 #define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) @@ -59,13 +62,6 @@ struct gpio_mockup_dbgfs_private { int offset; }; -struct gpio_mockup_platform_data { - int base; - int ngpio; - int index; - bool named_lines; -}; - static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES]; static int gpio_mockup_num_ranges; module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400); @@ -255,26 +251,37 @@ static int gpio_mockup_name_lines(struct device *dev, static int gpio_mockup_probe(struct platform_device *pdev) { - struct gpio_mockup_platform_data *pdata; struct gpio_mockup_chip *chip; struct gpio_chip *gc; - int rv, base, ngpio; struct device *dev; - char *name; + const char *name; + int rv, base; + u16 ngpio; dev = &pdev->dev; - pdata = dev_get_platdata(dev); - base = pdata->base; - ngpio = pdata->ngpio; + + rv = device_property_read_u32(dev, "gpio-base", &base); + if (rv) + base = -1; + + rv = device_property_read_u16(dev, "nr-gpios", &ngpio); + if (rv) + return rv; + + rv = device_property_read_string(dev, "chip-name", &name); + if (rv) + name = NULL; chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - name = devm_kasprintf(dev, GFP_KERNEL, "%s-%c", - pdev->name, pdata->index); - if (!name) - return -ENOMEM; + if (!name) { + name = devm_kasprintf(dev, GFP_KERNEL, + "%s-%c", pdev->name, pdev->id + 'A'); + if (!name) + return -ENOMEM; + } gc = &chip->gc; gc->base = base; @@ -295,7 +302,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) if (!chip->lines) return -ENOMEM; - if (pdata->named_lines) { + if (device_property_read_bool(dev, "named-gpio-lines")) { rv = gpio_mockup_name_lines(dev, chip); if (rv) return rv; @@ -339,9 +346,11 @@ static void gpio_mockup_unregister_pdevs(void) static int __init gpio_mockup_init(void) { - int i, num_chips, err = 0, index = 'A'; - struct gpio_mockup_platform_data pdata; + struct property_entry properties[GPIO_MOCKUP_MAX_PROP]; + int i, prop, num_chips, err = 0, base; + struct platform_device_info pdevinfo; struct platform_device *pdev; + u16 ngpio; if ((gpio_mockup_num_ranges < 2) || (gpio_mockup_num_ranges % 2) || @@ -371,17 +380,28 @@ static int __init gpio_mockup_init(void) } for (i = 0; i < num_chips; i++) { - pdata.index = index++; - pdata.base = gpio_mockup_range_base(i); - pdata.ngpio = pdata.base < 0 - ? gpio_mockup_range_ngpio(i) - : gpio_mockup_range_ngpio(i) - pdata.base; - pdata.named_lines = gpio_mockup_named_lines; - - pdev = platform_device_register_resndata(NULL, - GPIO_MOCKUP_NAME, - i, NULL, 0, &pdata, - sizeof(pdata)); + memset(properties, 0, sizeof(properties)); + memset(&pdevinfo, 0, sizeof(pdevinfo)); + prop = 0; + + base = gpio_mockup_range_base(i); + if (base >= 0) + properties[prop++] = PROPERTY_ENTRY_U32("gpio-base", + base); + + ngpio = base < 0 ? gpio_mockup_range_ngpio(i) + : gpio_mockup_range_ngpio(i) - base; + properties[prop++] = PROPERTY_ENTRY_U16("nr-gpios", ngpio); + + if (gpio_mockup_named_lines) + properties[prop++] = PROPERTY_ENTRY_BOOL( + "named-gpio-lines"); + + pdevinfo.name = GPIO_MOCKUP_NAME; + pdevinfo.id = i; + pdevinfo.properties = properties; + + pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { gpio_mockup_err("error registering device"); platform_driver_unregister(&gpio_mockup_driver); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index df30490da820..ea874fd033a5 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -18,8 +18,6 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/gpio/driver.h> -/* FIXME: for gpio_get_value(), replace this by direct register read */ -#include <linux/gpio.h> #include <linux/module.h> #define MXS_SET 0x4 @@ -86,7 +84,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) port->both_edges &= ~pin_mask; switch (type) { case IRQ_TYPE_EDGE_BOTH: - val = gpio_get_value(port->gc.base + d->hwirq); + val = port->gc.get(&port->gc, d->hwirq); if (val) edge = GPIO_INT_FALL_EDGE; else diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index e81008678a38..9887c3db6e16 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -19,6 +19,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/cpu_pm.h> #include <linux/device.h> #include <linux/pm_runtime.h> #include <linux/pm.h> @@ -28,10 +29,10 @@ #include <linux/bitops.h> #include <linux/platform_data/gpio-omap.h> -#define OFF_MODE 1 #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF -static LIST_HEAD(omap_gpio_list); +#define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER BIT(2) +#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN BIT(1) struct gpio_regs { u32 irqenable1; @@ -48,6 +49,13 @@ struct gpio_regs { u32 debounce_en; }; +struct gpio_bank; + +struct gpio_omap_funcs { + void (*idle_enable_level_quirk)(struct gpio_bank *bank); + void (*idle_disable_level_quirk)(struct gpio_bank *bank); +}; + struct gpio_bank { struct list_head node; void __iomem *base; @@ -55,6 +63,7 @@ struct gpio_bank { u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; + struct gpio_omap_funcs funcs; u32 saved_datain; u32 level_mask; u32 toggle_mask; @@ -62,6 +71,8 @@ struct gpio_bank { raw_spinlock_t wa_lock; struct gpio_chip chip; struct clk *dbck; + struct notifier_block nb; + unsigned int is_suspended:1; u32 mod_usage; u32 irq_usage; u32 dbck_enable_mask; @@ -73,8 +84,8 @@ struct gpio_bank { int stride; u32 width; int context_loss_count; - int power_mode; bool workaround_enabled; + u32 quirks; void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); void (*set_dataout_multiple)(struct gpio_bank *bank, @@ -368,9 +379,18 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio, readl_relaxed(bank->base + bank->regs->fallingdetect); if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); - bank->context.wake_en = - readl_relaxed(bank->base + bank->regs->wkup_en); + /* Defer wkup_en register update until we idle? */ + if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) { + if (trigger) + bank->context.wake_en |= gpio_bit; + else + bank->context.wake_en &= ~gpio_bit; + } else { + omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, + trigger != 0); + bank->context.wake_en = + readl_relaxed(bank->base + bank->regs->wkup_en); + } } /* This part needs to be executed always for OMAP{34xx, 44xx} */ @@ -682,12 +702,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) struct gpio_bank *bank = gpiochip_get_data(chip); unsigned long flags; - /* - * If this is the first gpio_request for the bank, - * enable the bank module. - */ - if (!BANK_USED(bank)) - pm_runtime_get_sync(chip->parent); + pm_runtime_get_sync(chip->parent); raw_spin_lock_irqsave(&bank->lock, flags); omap_enable_gpio_module(bank, offset); @@ -711,12 +726,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) omap_disable_gpio_module(bank, offset); raw_spin_unlock_irqrestore(&bank->lock, flags); - /* - * If this is the last gpio to be freed in the bank, - * disable the bank module. - */ - if (!BANK_USED(bank)) - pm_runtime_put(chip->parent); + pm_runtime_put(chip->parent); } /* @@ -741,7 +751,9 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) if (WARN_ON(!isr_reg)) goto exit; - pm_runtime_get_sync(bank->chip.parent); + if (WARN_ONCE(!pm_runtime_active(bank->chip.parent), + "gpio irq%i while runtime suspended?\n", irq)) + return IRQ_NONE; while (1) { raw_spin_lock_irqsave(&bank->lock, lock_flags); @@ -792,7 +804,6 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) } } exit: - pm_runtime_put(bank->chip.parent); return IRQ_HANDLED; } @@ -841,20 +852,14 @@ static void omap_gpio_irq_bus_lock(struct irq_data *data) { struct gpio_bank *bank = omap_irq_data_get_bank(data); - if (!BANK_USED(bank)) - pm_runtime_get_sync(bank->chip.parent); + pm_runtime_get_sync(bank->chip.parent); } static void gpio_irq_bus_sync_unlock(struct irq_data *data) { struct gpio_bank *bank = omap_irq_data_get_bank(data); - /* - * If this is the last IRQ to be freed in the bank, - * disable the bank module. - */ - if (!BANK_USED(bank)) - pm_runtime_put(bank->chip.parent); + pm_runtime_put(bank->chip.parent); } static void omap_gpio_ack_irq(struct irq_data *d) @@ -899,6 +904,82 @@ static void omap_gpio_unmask_irq(struct irq_data *d) raw_spin_unlock_irqrestore(&bank->lock, flags); } +/* + * Only edges can generate a wakeup event to the PRCM. + * + * Therefore, ensure any wake-up capable GPIOs have + * edge-detection enabled before going idle to ensure a wakeup + * to the PRCM is generated on a GPIO transition. (c.f. 34xx + * NDA TRM 25.5.3.1) + * + * The normal values will be restored upon ->runtime_resume() + * by writing back the values saved in bank->context. + */ +static void __maybe_unused +omap2_gpio_enable_level_quirk(struct gpio_bank *bank) +{ + u32 wake_low, wake_hi; + + /* Enable additional edge detection for level gpios for idle */ + wake_low = bank->context.leveldetect0 & bank->context.wake_en; + if (wake_low) + writel_relaxed(wake_low | bank->context.fallingdetect, + bank->base + bank->regs->fallingdetect); + + wake_hi = bank->context.leveldetect1 & bank->context.wake_en; + if (wake_hi) + writel_relaxed(wake_hi | bank->context.risingdetect, + bank->base + bank->regs->risingdetect); +} + +static void __maybe_unused +omap2_gpio_disable_level_quirk(struct gpio_bank *bank) +{ + /* Disable edge detection for level gpios after idle */ + writel_relaxed(bank->context.fallingdetect, + bank->base + bank->regs->fallingdetect); + writel_relaxed(bank->context.risingdetect, + bank->base + bank->regs->risingdetect); +} + +/* + * On omap4 and later SoC variants a level interrupt with wkup_en + * enabled blocks the GPIO functional clock from idling until the GPIO + * instance has been reset. To avoid that, we must set wkup_en only for + * idle for level interrupts, and clear level registers for the duration + * of idle. The level interrupts will be still there on wakeup by their + * nature. + */ +static void __maybe_unused +omap4_gpio_enable_level_quirk(struct gpio_bank *bank) +{ + /* Update wake register for idle, edge bits might be already set */ + writel_relaxed(bank->context.wake_en, + bank->base + bank->regs->wkup_en); + + /* Clear level registers for idle */ + writel_relaxed(0, bank->base + bank->regs->leveldetect0); + writel_relaxed(0, bank->base + bank->regs->leveldetect1); +} + +static void __maybe_unused +omap4_gpio_disable_level_quirk(struct gpio_bank *bank) +{ + /* Restore level registers after idle */ + writel_relaxed(bank->context.leveldetect0, + bank->base + bank->regs->leveldetect0); + writel_relaxed(bank->context.leveldetect1, + bank->base + bank->regs->leveldetect1); + + /* Clear saved wkup_en for level, it will be set for next idle again */ + bank->context.wake_en &= ~(bank->context.leveldetect0 | + bank->context.leveldetect1); + + /* Update wake with only edge configuration */ + writel_relaxed(bank->context.wake_en, + bank->base + bank->regs->wkup_en); +} + /*---------------------------------------------------------------------*/ static int omap_mpuio_suspend_noirq(struct device *dev) @@ -1218,6 +1299,36 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) return ret; } +static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context); +static void omap_gpio_unidle(struct gpio_bank *bank); + +static int gpio_omap_cpu_notifier(struct notifier_block *nb, + unsigned long cmd, void *v) +{ + struct gpio_bank *bank; + unsigned long flags; + + bank = container_of(nb, struct gpio_bank, nb); + + raw_spin_lock_irqsave(&bank->lock, flags); + switch (cmd) { + case CPU_CLUSTER_PM_ENTER: + if (bank->is_suspended) + break; + omap_gpio_idle(bank, true); + break; + case CPU_CLUSTER_PM_ENTER_FAILED: + case CPU_CLUSTER_PM_EXIT: + if (bank->is_suspended) + break; + omap_gpio_unidle(bank); + break; + } + raw_spin_unlock_irqrestore(&bank->lock, flags); + + return NOTIFY_OK; +} + static const struct of_device_id omap_gpio_match[]; static int omap_gpio_probe(struct platform_device *pdev) @@ -1256,6 +1367,7 @@ static int omap_gpio_probe(struct platform_device *pdev) irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, irqc->name = dev_name(&pdev->dev); irqc->flags = IRQCHIP_MASK_ON_SUSPEND; + irqc->parent_device = dev; bank->irq = platform_get_irq(pdev, 0); if (bank->irq <= 0) { @@ -1270,6 +1382,7 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->chip.parent = dev; bank->chip.owner = THIS_MODULE; bank->dbck_flag = pdata->dbck_flag; + bank->quirks = pdata->quirks; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; bank->is_mpuio = pdata->is_mpuio; @@ -1278,6 +1391,7 @@ static int omap_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_OF_GPIO bank->chip.of_node = of_node_get(node); #endif + if (node) { if (!of_property_read_bool(node, "ti,gpio-always-on")) bank->loses_context = true; @@ -1298,6 +1412,18 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_set_gpio_dataout_mask_multiple; } + if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) { + bank->funcs.idle_enable_level_quirk = + omap4_gpio_enable_level_quirk; + bank->funcs.idle_disable_level_quirk = + omap4_gpio_disable_level_quirk; + } else if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) { + bank->funcs.idle_enable_level_quirk = + omap2_gpio_enable_level_quirk; + bank->funcs.idle_disable_level_quirk = + omap2_gpio_disable_level_quirk; + } + raw_spin_lock_init(&bank->lock); raw_spin_lock_init(&bank->wa_lock); @@ -1322,7 +1448,6 @@ static int omap_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bank); pm_runtime_enable(dev); - pm_runtime_irq_safe(dev); pm_runtime_get_sync(dev); if (bank->is_mpuio) @@ -1341,9 +1466,13 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_gpio_show_rev(bank); - pm_runtime_put(dev); + if (bank->funcs.idle_enable_level_quirk && + bank->funcs.idle_disable_level_quirk) { + bank->nb.notifier_call = gpio_omap_cpu_notifier; + cpu_pm_register_notifier(&bank->nb); + } - list_add_tail(&bank->node, &omap_gpio_list); + pm_runtime_put(dev); return 0; } @@ -1352,6 +1481,8 @@ static int omap_gpio_remove(struct platform_device *pdev) { struct gpio_bank *bank = platform_get_drvdata(pdev); + if (bank->nb.notifier_call) + cpu_pm_unregister_notifier(&bank->nb); list_del(&bank->node); gpiochip_remove(&bank->chip); pm_runtime_disable(&pdev->dev); @@ -1361,48 +1492,22 @@ static int omap_gpio_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_ARCH_OMAP2PLUS - -#if defined(CONFIG_PM) static void omap_gpio_restore_context(struct gpio_bank *bank); -static int omap_gpio_runtime_suspend(struct device *dev) +static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context) { - struct platform_device *pdev = to_platform_device(dev); - struct gpio_bank *bank = platform_get_drvdata(pdev); + struct device *dev = bank->chip.parent; u32 l1 = 0, l2 = 0; - unsigned long flags; - u32 wake_low, wake_hi; - raw_spin_lock_irqsave(&bank->lock, flags); - - /* - * Only edges can generate a wakeup event to the PRCM. - * - * Therefore, ensure any wake-up capable GPIOs have - * edge-detection enabled before going idle to ensure a wakeup - * to the PRCM is generated on a GPIO transition. (c.f. 34xx - * NDA TRM 25.5.3.1) - * - * The normal values will be restored upon ->runtime_resume() - * by writing back the values saved in bank->context. - */ - wake_low = bank->context.leveldetect0 & bank->context.wake_en; - if (wake_low) - writel_relaxed(wake_low | bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - wake_hi = bank->context.leveldetect1 & bank->context.wake_en; - if (wake_hi) - writel_relaxed(wake_hi | bank->context.risingdetect, - bank->base + bank->regs->risingdetect); + if (bank->funcs.idle_enable_level_quirk) + bank->funcs.idle_enable_level_quirk(bank); if (!bank->enabled_non_wakeup_gpios) goto update_gpio_context_count; - if (bank->power_mode != OFF_MODE) { - bank->power_mode = 0; + if (!may_lose_context) goto update_gpio_context_count; - } + /* * If going to OFF, remove triggering for all * non-wakeup GPIOs. Otherwise spurious IRQs will be @@ -1427,23 +1532,16 @@ update_gpio_context_count: bank->get_context_loss_count(dev); omap_gpio_dbck_disable(bank); - raw_spin_unlock_irqrestore(&bank->lock, flags); - - return 0; } static void omap_gpio_init_context(struct gpio_bank *p); -static int omap_gpio_runtime_resume(struct device *dev) +static void omap_gpio_unidle(struct gpio_bank *bank) { - struct platform_device *pdev = to_platform_device(dev); - struct gpio_bank *bank = platform_get_drvdata(pdev); + struct device *dev = bank->chip.parent; u32 l = 0, gen, gen0, gen1; - unsigned long flags; int c; - raw_spin_lock_irqsave(&bank->lock, flags); - /* * On the first resume during the probe, the context has not * been initialised and so initialise it now. Also initialise @@ -1459,16 +1557,8 @@ static int omap_gpio_runtime_resume(struct device *dev) omap_gpio_dbck_enable(bank); - /* - * In ->runtime_suspend(), level-triggered, wakeup-enabled - * GPIOs were set to edge trigger also in order to be able to - * generate a PRCM wakeup. Here we restore the - * pre-runtime_suspend() values for edge triggering. - */ - writel_relaxed(bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - writel_relaxed(bank->context.risingdetect, - bank->base + bank->regs->risingdetect); + if (bank->funcs.idle_disable_level_quirk) + bank->funcs.idle_disable_level_quirk(bank); if (bank->loses_context) { if (!bank->get_context_loss_count) { @@ -1478,16 +1568,13 @@ static int omap_gpio_runtime_resume(struct device *dev) if (c != bank->context_loss_count) { omap_gpio_restore_context(bank); } else { - raw_spin_unlock_irqrestore(&bank->lock, flags); - return 0; + return; } } } - if (!bank->workaround_enabled) { - raw_spin_unlock_irqrestore(&bank->lock, flags); - return 0; - } + if (!bank->workaround_enabled) + return; l = readl_relaxed(bank->base + bank->regs->datain); @@ -1540,41 +1627,8 @@ static int omap_gpio_runtime_resume(struct device *dev) } bank->workaround_enabled = false; - raw_spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} -#endif /* CONFIG_PM */ - -#if IS_BUILTIN(CONFIG_GPIO_OMAP) -void omap2_gpio_prepare_for_idle(int pwr_mode) -{ - struct gpio_bank *bank; - - list_for_each_entry(bank, &omap_gpio_list, node) { - if (!BANK_USED(bank) || !bank->loses_context) - continue; - - bank->power_mode = pwr_mode; - - pm_runtime_put_sync_suspend(bank->chip.parent); - } -} - -void omap2_gpio_resume_after_idle(void) -{ - struct gpio_bank *bank; - - list_for_each_entry(bank, &omap_gpio_list, node) { - if (!BANK_USED(bank) || !bank->loses_context) - continue; - - pm_runtime_get_sync(bank->chip.parent); - } } -#endif -#if defined(CONFIG_PM) static void omap_gpio_init_context(struct gpio_bank *p) { struct omap_gpio_reg_offs *regs = p->regs; @@ -1631,17 +1685,57 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) writel_relaxed(bank->context.irqenable2, bank->base + bank->regs->irqenable2); } -#endif /* CONFIG_PM */ -#else -#define omap_gpio_runtime_suspend NULL -#define omap_gpio_runtime_resume NULL -static inline void omap_gpio_init_context(struct gpio_bank *p) {} -#endif +static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + unsigned long flags; + int error = 0; + + raw_spin_lock_irqsave(&bank->lock, flags); + /* Must be idled only by CPU_CLUSTER_PM_ENTER? */ + if (bank->irq_usage) { + error = -EBUSY; + goto unlock; + } + omap_gpio_idle(bank, true); + bank->is_suspended = true; +unlock: + raw_spin_unlock_irqrestore(&bank->lock, flags); + + return error; +} + +static int __maybe_unused omap_gpio_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = platform_get_drvdata(pdev); + unsigned long flags; + int error = 0; + + raw_spin_lock_irqsave(&bank->lock, flags); + /* Must be unidled only by CPU_CLUSTER_PM_ENTER? */ + if (bank->irq_usage) { + error = -EBUSY; + goto unlock; + } + omap_gpio_unidle(bank); + bank->is_suspended = false; +unlock: + raw_spin_unlock_irqrestore(&bank->lock, flags); + + return error; +} + +#ifdef CONFIG_ARCH_OMAP2PLUS static const struct dev_pm_ops gpio_pm_ops = { SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, NULL) }; +#else +static const struct dev_pm_ops gpio_pm_ops; +#endif /* CONFIG_ARCH_OMAP2PLUS */ #if defined(CONFIG_OF) static struct omap_gpio_reg_offs omap2_gpio_regs = { @@ -1690,6 +1784,11 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .fallingdetect = OMAP4_GPIO_FALLINGDETECT, }; +/* + * Note that omap2 does not currently support idle modes with context loss so + * no need to add OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER quirk flag to save + * and restore context. + */ static const struct omap_gpio_platform_data omap2_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, @@ -1700,12 +1799,15 @@ static const struct omap_gpio_platform_data omap3_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = true, + .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER, }; static const struct omap_gpio_platform_data omap4_pdata = { .regs = &omap4_gpio_regs, .bank_width = 32, .dbck_flag = true, + .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER | + OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN, }; static const struct of_device_id omap_gpio_match[] = { diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index c18712dabf93..bfe4c5c9f41c 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -776,6 +776,9 @@ static int pxa_gpio_suspend(void) struct pxa_gpio_bank *c; int gpio; + if (!pchip) + return 0; + for_each_gpio_bank(gpio, c, pchip) { c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET); c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET); @@ -794,6 +797,9 @@ static void pxa_gpio_resume(void) struct pxa_gpio_bank *c; int gpio; + if (!pchip) + return; + for_each_gpio_bank(gpio, c, pchip) { /* restore level with set/clear */ writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET); diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 55cc61086d99..3c82bb3c2030 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -321,6 +321,9 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask, u32 val, bankmask; bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0); + if (chip->valid_mask) + bankmask &= chip->valid_mask[0]; + if (!bankmask) return; @@ -558,6 +561,9 @@ static int gpio_rcar_resume(struct device *dev) u32 mask; for (offset = 0; offset < p->gpio_chip.ngpio; offset++) { + if (!gpiochip_line_is_valid(&p->gpio_chip, offset)) + continue; + mask = BIT(offset); /* I/O pin */ if (!(p->bank_info.iointsel & mask)) { diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c new file mode 100644 index 000000000000..571b2a81c6de --- /dev/null +++ b/drivers/gpio/gpio-siox.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2015-2018 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de> + */ + +#include <linux/module.h> +#include <linux/siox.h> +#include <linux/gpio/driver.h> +#include <linux/of.h> + +struct gpio_siox_ddata { + struct gpio_chip gchip; + struct irq_chip ichip; + struct mutex lock; + u8 setdata[1]; + u8 getdata[3]; + + spinlock_t irqlock; + u32 irq_enable; + u32 irq_status; + u32 irq_type[20]; +}; + +/* + * Note that this callback only sets the value that is clocked out in the next + * cycle. + */ +static int gpio_siox_set_data(struct siox_device *sdevice, u8 status, u8 buf[]) +{ + struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev); + + mutex_lock(&ddata->lock); + buf[0] = ddata->setdata[0]; + mutex_unlock(&ddata->lock); + + return 0; +} + +static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) +{ + struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev); + size_t offset; + u32 trigger; + + mutex_lock(&ddata->lock); + + spin_lock_irq(&ddata->irqlock); + + for (offset = 0; offset < 12; ++offset) { + unsigned int bitpos = 11 - offset; + unsigned int gpiolevel = buf[bitpos / 8] & (1 << bitpos % 8); + unsigned int prev_level = + ddata->getdata[bitpos / 8] & (1 << (bitpos % 8)); + u32 irq_type = ddata->irq_type[offset]; + + if (gpiolevel) { + if ((irq_type & IRQ_TYPE_LEVEL_HIGH) || + ((irq_type & IRQ_TYPE_EDGE_RISING) && !prev_level)) + ddata->irq_status |= 1 << offset; + } else { + if ((irq_type & IRQ_TYPE_LEVEL_LOW) || + ((irq_type & IRQ_TYPE_EDGE_FALLING) && prev_level)) + ddata->irq_status |= 1 << offset; + } + } + + trigger = ddata->irq_status & ddata->irq_enable; + + spin_unlock_irq(&ddata->irqlock); + + ddata->getdata[0] = buf[0]; + ddata->getdata[1] = buf[1]; + ddata->getdata[2] = buf[2]; + + mutex_unlock(&ddata->lock); + + for (offset = 0; offset < 12; ++offset) { + if (trigger & (1 << offset)) { + struct irq_domain *irqdomain = ddata->gchip.irq.domain; + unsigned int irq = irq_find_mapping(irqdomain, offset); + + /* + * Conceptually handle_nested_irq should call the flow + * handler of the irq chip. But it doesn't, so we have + * to clean the irq_status here. + */ + spin_lock_irq(&ddata->irqlock); + ddata->irq_status &= ~(1 << offset); + spin_unlock_irq(&ddata->irqlock); + + handle_nested_irq(irq); + } + } + + return 0; +} + +static void gpio_siox_irq_ack(struct irq_data *d) +{ + struct irq_chip *ic = irq_data_get_irq_chip(d); + struct gpio_siox_ddata *ddata = + container_of(ic, struct gpio_siox_ddata, ichip); + + spin_lock_irq(&ddata->irqlock); + ddata->irq_status &= ~(1 << d->hwirq); + spin_unlock_irq(&ddata->irqlock); +} + +static void gpio_siox_irq_mask(struct irq_data *d) +{ + struct irq_chip *ic = irq_data_get_irq_chip(d); + struct gpio_siox_ddata *ddata = + container_of(ic, struct gpio_siox_ddata, ichip); + + spin_lock_irq(&ddata->irqlock); + ddata->irq_enable &= ~(1 << d->hwirq); + spin_unlock_irq(&ddata->irqlock); +} + +static void gpio_siox_irq_unmask(struct irq_data *d) +{ + struct irq_chip *ic = irq_data_get_irq_chip(d); + struct gpio_siox_ddata *ddata = + container_of(ic, struct gpio_siox_ddata, ichip); + + spin_lock_irq(&ddata->irqlock); + ddata->irq_enable |= 1 << d->hwirq; + spin_unlock_irq(&ddata->irqlock); +} + +static int gpio_siox_irq_set_type(struct irq_data *d, u32 type) +{ + struct irq_chip *ic = irq_data_get_irq_chip(d); + struct gpio_siox_ddata *ddata = + container_of(ic, struct gpio_siox_ddata, ichip); + + spin_lock_irq(&ddata->irqlock); + ddata->irq_type[d->hwirq] = type; + spin_unlock_irq(&ddata->irqlock); + + return 0; +} + +static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset) +{ + struct gpio_siox_ddata *ddata = + container_of(chip, struct gpio_siox_ddata, gchip); + int ret; + + mutex_lock(&ddata->lock); + + if (offset >= 12) { + unsigned int bitpos = 19 - offset; + + ret = ddata->setdata[0] & (1 << bitpos); + } else { + unsigned int bitpos = 11 - offset; + + ret = ddata->getdata[bitpos / 8] & (1 << (bitpos % 8)); + } + + mutex_unlock(&ddata->lock); + + return ret; +} + +static void gpio_siox_set(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct gpio_siox_ddata *ddata = + container_of(chip, struct gpio_siox_ddata, gchip); + u8 mask = 1 << (19 - offset); + + mutex_lock(&ddata->lock); + + if (value) + ddata->setdata[0] |= mask; + else + ddata->setdata[0] &= ~mask; + + mutex_unlock(&ddata->lock); +} + +static int gpio_siox_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset >= 12) + return -EINVAL; + + return 0; +} + +static int gpio_siox_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + if (offset < 12) + return -EINVAL; + + gpio_siox_set(chip, offset, value); + return 0; +} + +static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + if (offset < 12) + return 1; /* input */ + else + return 0; /* output */ +} + +static int gpio_siox_probe(struct siox_device *sdevice) +{ + struct gpio_siox_ddata *ddata; + int ret; + + ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + dev_set_drvdata(&sdevice->dev, ddata); + + mutex_init(&ddata->lock); + spin_lock_init(&ddata->irqlock); + + ddata->gchip.base = -1; + ddata->gchip.can_sleep = 1; + ddata->gchip.parent = &sdevice->dev; + ddata->gchip.owner = THIS_MODULE; + ddata->gchip.get = gpio_siox_get; + ddata->gchip.set = gpio_siox_set; + ddata->gchip.direction_input = gpio_siox_direction_input; + ddata->gchip.direction_output = gpio_siox_direction_output; + ddata->gchip.get_direction = gpio_siox_get_direction; + ddata->gchip.ngpio = 20; + + ddata->ichip.name = "siox-gpio"; + ddata->ichip.irq_ack = gpio_siox_irq_ack; + ddata->ichip.irq_mask = gpio_siox_irq_mask; + ddata->ichip.irq_unmask = gpio_siox_irq_unmask; + ddata->ichip.irq_set_type = gpio_siox_irq_set_type; + + ret = gpiochip_add(&ddata->gchip); + if (ret) { + dev_err(&sdevice->dev, + "Failed to register gpio chip (%d)\n", ret); + goto err_gpiochip; + } + + ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip, + 0, handle_level_irq, IRQ_TYPE_EDGE_RISING); + if (ret) { + dev_err(&sdevice->dev, + "Failed to register irq chip (%d)\n", ret); +err_gpiochip: + gpiochip_remove(&ddata->gchip); + } + + return ret; +} + +static int gpio_siox_remove(struct siox_device *sdevice) +{ + struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev); + + gpiochip_remove(&ddata->gchip); + return 0; +} + +static struct siox_driver gpio_siox_driver = { + .probe = gpio_siox_probe, + .remove = gpio_siox_remove, + .set_data = gpio_siox_set_data, + .get_data = gpio_siox_get_data, + .driver = { + .name = "gpio-siox", + }, +}; + +static int __init gpio_siox_init(void) +{ + return siox_driver_register(&gpio_siox_driver); +} +module_init(gpio_siox_init); + +static void __exit gpio_siox_exit(void) +{ + siox_driver_unregister(&gpio_siox_driver); +} +module_exit(gpio_siox_exit); + +MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); +MODULE_DESCRIPTION("SIOX gpio driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 87c18a544513..7f3da34c7874 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -122,7 +122,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) BIT(offs % SYSCON_REG_BITS)); } - priv->data->set(chip, offset, val); + chip->set(chip, offset, val); return 0; } diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index a12cd0b5c972..d5e5d19f4c0a 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -45,14 +45,12 @@ /** - * @spinlock: used for atomic read/modify/write of registers * @base: register base address * @domain: IRQ domain of GPIO generated interrupts managed by this controller * @irq: Interrupt line of parent interrupt controller * @gc: gpio_chip structure associated to this GPIO controller */ struct tb10x_gpio { - spinlock_t spinlock; void __iomem *base; struct irq_domain *domain; int irq; @@ -76,60 +74,14 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs, u32 r; unsigned long flags; - spin_lock_irqsave(&gpio->spinlock, flags); + spin_lock_irqsave(&gpio->gc.bgpio_lock, flags); r = tb10x_reg_read(gpio, offs); r = (r & ~mask) | (val & mask); tb10x_reg_write(gpio, offs, r); - spin_unlock_irqrestore(&gpio->spinlock, flags); -} - -static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) -{ - struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip); - int mask = BIT(offset); - int val = TB10X_GPIO_DIR_IN << offset; - - tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val); - - return 0; -} - -static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip); - int val; - - val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA); - - if (val & BIT(offset)) - return 1; - else - return 0; -} - -static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip); - int mask = BIT(offset); - int val = value << offset; - - tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DATA, mask, val); -} - -static int tb10x_gpio_direction_out(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip); - int mask = BIT(offset); - int val = TB10X_GPIO_DIR_OUT << offset; - - tb10x_gpio_set(chip, offset, value); - tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val); - - return 0; + spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags); } static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) @@ -169,72 +121,85 @@ static int tb10x_gpio_probe(struct platform_device *pdev) { struct tb10x_gpio *tb10x_gpio; struct resource *mem; - struct device_node *dn = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; int ret = -EBUSY; u32 ngpio; - if (!dn) + if (!np) return -EINVAL; - if (of_property_read_u32(dn, "abilis,ngpio", &ngpio)) + if (of_property_read_u32(np, "abilis,ngpio", &ngpio)) return -EINVAL; - tb10x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tb10x_gpio), GFP_KERNEL); + tb10x_gpio = devm_kzalloc(dev, sizeof(*tb10x_gpio), GFP_KERNEL); if (tb10x_gpio == NULL) return -ENOMEM; - spin_lock_init(&tb10x_gpio->spinlock); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tb10x_gpio->base = devm_ioremap_resource(&pdev->dev, mem); + tb10x_gpio->base = devm_ioremap_resource(dev, mem); if (IS_ERR(tb10x_gpio->base)) return PTR_ERR(tb10x_gpio->base); - tb10x_gpio->gc.label = - devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node); + tb10x_gpio->gc.label = + devm_kasprintf(dev, GFP_KERNEL, "%pOF", pdev->dev.of_node); if (!tb10x_gpio->gc.label) return -ENOMEM; - tb10x_gpio->gc.parent = &pdev->dev; - tb10x_gpio->gc.owner = THIS_MODULE; - tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in; - tb10x_gpio->gc.get = tb10x_gpio_get; - tb10x_gpio->gc.direction_output = tb10x_gpio_direction_out; - tb10x_gpio->gc.set = tb10x_gpio_set; - tb10x_gpio->gc.request = gpiochip_generic_request; - tb10x_gpio->gc.free = gpiochip_generic_free; - tb10x_gpio->gc.base = -1; - tb10x_gpio->gc.ngpio = ngpio; - tb10x_gpio->gc.can_sleep = false; - - - ret = devm_gpiochip_add_data(&pdev->dev, &tb10x_gpio->gc, tb10x_gpio); + /* + * Initialize generic GPIO with one single register for reading and setting + * the lines, no special set or clear registers and a data direction register + * wher 1 means "output". + */ + ret = bgpio_init(&tb10x_gpio->gc, dev, 4, + tb10x_gpio->base + OFFSET_TO_REG_DATA, + NULL, + NULL, + tb10x_gpio->base + OFFSET_TO_REG_DDR, + NULL, + 0); + if (ret) { + dev_err(dev, "unable to init generic GPIO\n"); + return ret; + } + tb10x_gpio->gc.base = -1; + tb10x_gpio->gc.parent = dev; + tb10x_gpio->gc.owner = THIS_MODULE; + /* + * ngpio is set by bgpio_init() but we override it, this .request() + * callback also overrides the one set up by generic GPIO. + */ + tb10x_gpio->gc.ngpio = ngpio; + tb10x_gpio->gc.request = gpiochip_generic_request; + tb10x_gpio->gc.free = gpiochip_generic_free; + + ret = devm_gpiochip_add_data(dev, &tb10x_gpio->gc, tb10x_gpio); if (ret < 0) { - dev_err(&pdev->dev, "Could not add gpiochip.\n"); + dev_err(dev, "Could not add gpiochip.\n"); return ret; } platform_set_drvdata(pdev, tb10x_gpio); - if (of_find_property(dn, "interrupt-controller", NULL)) { + if (of_find_property(np, "interrupt-controller", NULL)) { struct irq_chip_generic *gc; ret = platform_get_irq(pdev, 0); if (ret < 0) { - dev_err(&pdev->dev, "No interrupt specified.\n"); + dev_err(dev, "No interrupt specified.\n"); return ret; } tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq; tb10x_gpio->irq = ret; - ret = devm_request_irq(&pdev->dev, ret, tb10x_gpio_irq_cascade, + ret = devm_request_irq(dev, ret, tb10x_gpio_irq_cascade, IRQF_TRIGGER_NONE | IRQF_SHARED, - dev_name(&pdev->dev), tb10x_gpio); + dev_name(dev), tb10x_gpio); if (ret != 0) return ret; - tb10x_gpio->domain = irq_domain_add_linear(dn, + tb10x_gpio->domain = irq_domain_add_linear(np, tb10x_gpio->gc.ngpio, &irq_generic_chip_ops, NULL); if (!tb10x_gpio->domain) { diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c index b23c4d2429be..2eea98ff4ea3 100644 --- a/drivers/gpio/gpio-tps65086.c +++ b/drivers/gpio/gpio-tps65086.c @@ -1,20 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis <afd@ti.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 042b9a20781a..9b6cc74f47c8 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * TI TPS6586x GPIO driver * @@ -7,22 +8,10 @@ * Based on tps6586x.c * Copyright (c) 2010 CompuLab Ltd. * Mike Rapoport <mike@compulab.co.il> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/errno.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/mfd/tps6586x.h> diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index e63d7dabf78b..0c785b0fd161 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * TI TPS6591x GPIO driver * @@ -5,18 +6,12 @@ * * Author: Graeme Gregory <gg@slimlogic.co.uk> * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/errno.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/mfd/tps65910.h> diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index abc0798ef843..3ad68bd78282 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -1,23 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 /* * GPIO driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis <afd@ti.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the Arizona GPIO driver and the previous TPS65912 driver by * Margarita Olaya Cabrera <magi@slimlogic.co.uk> */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -40,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc, return ret; if (val & GPIO_CFG_MASK) - return GPIOF_DIR_OUT; + return 0; else - return GPIOF_DIR_IN; + return 1; } static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c index 6cfeba07f882..c91890488402 100644 --- a/drivers/gpio/gpio-ts5500.c +++ b/drivers/gpio/gpio-ts5500.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Digital I/O driver for Technologic Systems TS-5500 * @@ -16,17 +17,12 @@ * TS-5600: * Documentation: http://wiki.embeddedarm.com/wiki/TS-5600 * Blocks: LCD port (identical to TS-5500 LCD). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/platform_data/gpio-ts5500.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -318,7 +314,6 @@ static void ts5500_disable_irq(struct ts5500_priv *priv) static int ts5500_dio_probe(struct platform_device *pdev) { enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data; - struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; const char *name = dev_name(dev); struct ts5500_priv *priv; @@ -349,10 +344,6 @@ static int ts5500_dio_probe(struct platform_device *pdev) priv->gpio_chip.set = ts5500_gpio_set; priv->gpio_chip.to_irq = ts5500_gpio_to_irq; priv->gpio_chip.base = -1; - if (pdata) { - priv->gpio_chip.base = pdata->base; - priv->strap = pdata->strap; - } switch (block) { case TS5500_DIO1: diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 9b511df5450e..fbfb648d3502 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Access to GPIOs on TWL4030/TPS659x0 chips * @@ -9,20 +10,6 @@ * * Initial Code: * Andy Lowe / Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/module.h> @@ -30,7 +17,7 @@ #include <linux/interrupt.h> #include <linux/kthread.h> #include <linux/irq.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/irqdomain.h> @@ -167,6 +154,23 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) return ret; } +static int twl4030_get_gpio_direction(int gpio) +{ + u8 d_bnk = gpio >> 3; + u8 d_msk = BIT(gpio & 0x7); + u8 base = REG_GPIODATADIR1 + d_bnk; + int ret = 0; + + ret = gpio_twl4030_read(base); + if (ret < 0) + return ret; + + /* 1 = output, but gpiolib semantics are inverse so invert */ + ret = !(ret & d_msk); + + return ret; +} + static int twl4030_set_gpio_dataout(int gpio, int enable) { u8 d_bnk = gpio >> 3; @@ -372,6 +376,28 @@ static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) return ret; } +static int twl_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); + /* + * Default 0 = output + * LED GPIOs >= TWL4030_GPIO_MAX are always output + */ + int ret = 0; + + mutex_lock(&priv->mutex); + if (offset < TWL4030_GPIO_MAX) { + ret = twl4030_get_gpio_direction(offset); + if (ret) { + mutex_unlock(&priv->mutex); + return ret; + } + } + mutex_unlock(&priv->mutex); + + return ret; +} + static int twl_to_irq(struct gpio_chip *chip, unsigned offset) { struct gpio_twl4030_priv *priv = gpiochip_get_data(chip); @@ -387,8 +413,9 @@ static const struct gpio_chip template_chip = { .request = twl_request, .free = twl_free, .direction_input = twl_direction_in, - .get = twl_get, .direction_output = twl_direction_out, + .get_direction = twl_get_direction, + .get = twl_get, .set = twl_set, .to_irq = twl_to_irq, .can_sleep = true, diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index dadeacf43e0c..c845b2ff1f43 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Access to GPOs on TWL6040 chip * @@ -6,28 +7,15 @@ * Authors: * Sergio Aguirre <saaguirre@ti.com> * Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/module.h> #include <linux/init.h> #include <linux/kthread.h> #include <linux/irq.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/platform_device.h> +#include <linux/bitops.h> #include <linux/of.h> #include <linux/mfd/twl6040.h> @@ -41,7 +29,13 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) if (ret < 0) return ret; - return (ret >> offset) & 1; + return !!(ret & BIT(offset)); +} + +static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset) +{ + /* This means "out" */ + return 0; } static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, @@ -62,9 +56,9 @@ static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value) return; if (value) - gpoctl = ret | (1 << offset); + gpoctl = ret | BIT(offset); else - gpoctl = ret & ~(1 << offset); + gpoctl = ret & ~BIT(offset); twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl); } @@ -74,6 +68,7 @@ static struct gpio_chip twl6040gpo_chip = { .owner = THIS_MODULE, .get = twl6040gpo_get, .direction_output = twl6040gpo_direction_out, + .get_direction = twl6040gpo_get_direction, .set = twl6040gpo_set, .can_sleep = true, }; diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 7fdac9060979..74551cbdb2e8 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -12,7 +12,7 @@ * GNU General Public License for more details. */ -#include <linux/bitops.h> +#include <linux/bits.h> #include <linux/gpio/driver.h> #include <linux/irq.h> #include <linux/irqdomain.h> diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index d4ad6d0e02a2..5960396c8d9a 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -1,23 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale vf610 GPIO support through PORT and GPIO * * Copyright (c) 2014 Toradex AG. * * Author: Stefan Agner <stefan@agner.ch>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ - #include <linux/bitops.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index e6d1328dddfa..9b604f13e302 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Nano River Technologies viperboard GPIO lib driver * * (C) 2012 by Lemonage GmbH * Author: Lars Poeschel <poeschel@lemonage.de> * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/kernel.h> @@ -19,9 +14,8 @@ #include <linux/types.h> #include <linux/mutex.h> #include <linux/platform_device.h> - #include <linux/usb.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/mfd/viperboard.h> diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index 027699cec911..b13a49c89cc1 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -1,27 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Driver for NEC VR4100 series General-purpose I/O Unit. * * Copyright (C) 2002 MontaVista Software Inc. * Author: Yoichi Yuasa <source@mvista.com> * Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/errno.h> #include <linux/fs.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -384,44 +371,6 @@ static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir) return 0; } -int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull) -{ - u16 reg, mask; - unsigned long flags; - - if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO) - return -EPERM; - - if (pin >= 15) - return -EINVAL; - - mask = 1 << pin; - - spin_lock_irqsave(&giu_lock, flags); - - if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) { - reg = giu_read(GIUTERMUPDN); - if (pull == GPIO_PULL_UP) - reg |= mask; - else - reg &= ~mask; - giu_write(GIUTERMUPDN, reg); - - reg = giu_read(GIUUSEUPDN); - reg |= mask; - giu_write(GIUUSEUPDN, reg); - } else { - reg = giu_read(GIUUSEUPDN); - reg &= ~mask; - giu_write(GIUUSEUPDN, reg); - } - - spin_unlock_irqrestore(&giu_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown); - static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin) { u16 reg, mask; diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 98a6f1fcc561..4ff146ca32fe 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO * @@ -5,27 +6,10 @@ * Copyright (C) 2010 One Laptop per Child * Author: Harald Welte <HaraldWelte@viatech.com> * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * */ - #include <linux/kernel.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/platform_device.h> diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 324813e8304e..a3a32a77041f 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * gpiolib support for Wolfson WM831x PMICs * @@ -5,17 +6,12 @@ * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/mfd/core.h> #include <linux/platform_device.h> #include <linux/seq_file.h> diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index e46752e73dd9..460f0a4b04bd 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * gpiolib support for Wolfson WM835x PMICs * @@ -5,17 +6,12 @@ * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/mfd/core.h> #include <linux/platform_device.h> #include <linux/seq_file.h> diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index 1e35756ac55b..9af89cf7f6bc 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * gpiolib support for Wolfson WM8994 * @@ -5,17 +6,12 @@ * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/mfd/core.h> #include <linux/platform_device.h> #include <linux/seq_file.h> diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 8e4275eaa7d7..0a3607fd21af 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2003-2015 Broadcom Corporation * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/platform_device.h> #include <linux/of_device.h> #include <linux/module.h> diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c index f16c0427952e..43d3fa5f511a 100644 --- a/drivers/gpio/gpio-xtensa.c +++ b/drivers/gpio/gpio-xtensa.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2013 TangoTec Ltd. * Author: Baruch Siach <baruch@tkos.co.il> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for the Xtensa LX4 GPIO32 Option * * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22 @@ -30,7 +27,7 @@ #include <linux/err.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/bitops.h> #include <linux/platform_device.h> diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index 3926ce9c2840..57432397e5e5 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -16,7 +16,7 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> /* * Memory layout: diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 8b9d7e42c600..2b1a7b455aa8 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1,17 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ACPI helpers for GPIO API * * Copyright (C) 2012, Intel Corporation * Authors: Mathias Nyman <mathias.nyman@linux.intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/errno.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/gpio/machine.h> diff --git a/drivers/gpio/gpiolib-devprop.c b/drivers/gpio/gpiolib-devprop.c index f748aa3e77f7..dd517098ab95 100644 --- a/drivers/gpio/gpiolib-devprop.c +++ b/drivers/gpio/gpiolib-devprop.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device property helpers for GPIO chips. * * Copyright (C) 2016, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/property.h> @@ -32,32 +29,29 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip, struct gpio_device *gdev = chip->gpiodev; const char **names; int ret, i; + int count; - ret = fwnode_property_read_string_array(fwnode, "gpio-line-names", - NULL, 0); - if (ret < 0) + count = fwnode_property_read_string_array(fwnode, "gpio-line-names", + NULL, 0); + if (count < 0) return; - if (ret != gdev->ngpio) { - dev_warn(&gdev->dev, - "names %d do not match number of GPIOs %d\n", ret, - gdev->ngpio); - return; - } + if (count > gdev->ngpio) + count = gdev->ngpio; - names = kcalloc(gdev->ngpio, sizeof(*names), GFP_KERNEL); + names = kcalloc(count, sizeof(*names), GFP_KERNEL); if (!names) return; ret = fwnode_property_read_string_array(fwnode, "gpio-line-names", - names, gdev->ngpio); + names, count); if (ret < 0) { dev_warn(&gdev->dev, "failed to read GPIO line names\n"); kfree(names); return; } - for (i = 0; i < gdev->ngpio; i++) + for (i = 0; i < count; i++) gdev->descs[i].name = names[i]; kfree(names); diff --git a/drivers/gpio/devres.c b/drivers/gpio/gpiolib-devres.c index e82cc763633c..01959369360b 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -1,14 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * drivers/gpio/devres.c - managed gpio resources - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * devres.c - managed gpio resources * This file is based on kernel/irq/devres.c * * Copyright (c) 2011 John Crispin <john@phrozen.org> diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c index 8b830996fe02..30e2476a6dc4 100644 --- a/drivers/gpio/gpiolib-legacy.c +++ b/drivers/gpio/gpiolib-legacy.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 #include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index d4e7a09598fa..7f1260c78270 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * OF helpers for the GPIO API * * Copyright (c) 2007-2008 MontaVista Software, Inc. * * Author: Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include <linux/device.h> @@ -58,7 +54,8 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, } static void of_gpio_flags_quirks(struct device_node *np, - enum of_gpio_flags *flags) + enum of_gpio_flags *flags, + int index) { /* * Some GPIO fixed regulator quirks. @@ -92,6 +89,51 @@ static void of_gpio_flags_quirks(struct device_node *np, pr_info("%s uses legacy open drain flag - update the DTS if you can\n", of_node_full_name(np)); } + + /* + * Legacy handling of SPI active high chip select. If we have a + * property named "cs-gpios" we need to inspect the child node + * to determine if the flags should have inverted semantics. + */ + if (IS_ENABLED(CONFIG_SPI_MASTER) && + of_property_read_bool(np, "cs-gpios")) { + struct device_node *child; + u32 cs; + int ret; + + for_each_child_of_node(np, child) { + ret = of_property_read_u32(child, "reg", &cs); + if (!ret) + continue; + if (cs == index) { + /* + * SPI children have active low chip selects + * by default. This can be specified negatively + * by just omitting "spi-cs-high" in the + * device node, or actively by tagging on + * GPIO_ACTIVE_LOW as flag in the device + * tree. If the line is simultaneously + * tagged as active low in the device tree + * and has the "spi-cs-high" set, we get a + * conflict and the "spi-cs-high" flag will + * take precedence. + */ + if (of_property_read_bool(np, "spi-cs-high")) { + if (*flags & OF_GPIO_ACTIVE_LOW) { + pr_warn("%s GPIO handle specifies active low - ignored\n", + of_node_full_name(np)); + *flags &= ~OF_GPIO_ACTIVE_LOW; + } + } else { + if (!(*flags & OF_GPIO_ACTIVE_LOW)) + pr_info("%s enforce active low on chipselect handle\n", + of_node_full_name(np)); + *flags |= OF_GPIO_ACTIVE_LOW; + } + break; + } + } + } } /** @@ -132,7 +174,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, goto out; if (flags) - of_gpio_flags_quirks(np, flags); + of_gpio_flags_quirks(np, flags, index); pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n", __func__, propname, np, index, @@ -349,8 +391,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, else if (of_property_read_bool(np, "output-high")) *dflags |= GPIOD_OUT_HIGH; else { - pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n", - desc_to_gpio(desc), np->name); + pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n", + desc_to_gpio(desc), np); return ERR_PTR(-EINVAL); } diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 3dbaf489a8a5..fbf6b1a0a4fa 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 #include <linux/idr.h> #include <linux/mutex.h> #include <linux/device.h> #include <linux/sysfs.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/interrupt.h> @@ -444,11 +444,6 @@ static struct attribute *gpiochip_attrs[] = { }; ATTRIBUTE_GROUPS(gpiochip); -static struct gpio_desc *gpio_to_valid_desc(int gpio) -{ - return gpio_is_valid(gpio) ? gpio_to_desc(gpio) : NULL; -} - /* * /sys/class/gpio/export ... write-only * integer N ... number of GPIO to export (full access) @@ -467,7 +462,7 @@ static ssize_t export_store(struct class *class, if (status < 0) goto done; - desc = gpio_to_valid_desc(gpio); + desc = gpio_to_desc(gpio); /* reject invalid GPIOs */ if (!desc) { pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); @@ -514,7 +509,7 @@ static ssize_t unexport_store(struct class *class, if (status < 0) goto done; - desc = gpio_to_valid_desc(gpio); + desc = gpio_to_desc(gpio); /* reject bogus commands (gpio_unexport ignores them) */ if (!desc) { pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 25187403e3ac..230e41562462 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 #include <linux/bitmap.h> #include <linux/kernel.h> #include <linux/module.h> @@ -210,15 +211,15 @@ static int gpiochip_find_base(int ngpio) */ int gpiod_get_direction(struct gpio_desc *desc) { - struct gpio_chip *chip; - unsigned offset; - int status = -EINVAL; + struct gpio_chip *chip; + unsigned offset; + int status; chip = gpiod_to_chip(desc); offset = gpio_chip_hwgpio(desc); if (!chip->get_direction) - return status; + return -ENOTSUPP; status = chip->get_direction(chip, offset); if (status > 0) { @@ -359,7 +360,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) return p; } -static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip) +static int gpiochip_alloc_valid_mask(struct gpio_chip *gpiochip) { #ifdef CONFIG_OF_GPIO int size; @@ -380,6 +381,14 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip) return 0; } +static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip) +{ + if (gpiochip->init_valid_mask) + return gpiochip->init_valid_mask(gpiochip); + + return 0; +} + static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) { kfree(gpiochip->valid_mask); @@ -427,7 +436,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, struct linehandle_state *lh = filep->private_data; void __user *ip = (void __user *)arg; struct gpiohandle_data ghd; - int vals[GPIOHANDLES_MAX]; + DECLARE_BITMAP(vals, GPIOHANDLES_MAX); int i; if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { @@ -436,13 +445,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, true, lh->numdescs, lh->descs, + NULL, vals); if (ret) return ret; memset(&ghd, 0, sizeof(ghd)); for (i = 0; i < lh->numdescs; i++) - ghd.values[i] = vals[i]; + ghd.values[i] = test_bit(i, vals); if (copy_to_user(ip, &ghd, sizeof(ghd))) return -EFAULT; @@ -461,13 +471,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, /* Clamp all values to [0,1] */ for (i = 0; i < lh->numdescs; i++) - vals[i] = !!ghd.values[i]; + __assign_bit(i, vals, ghd.values[i]); /* Reuse the array setting function */ return gpiod_set_array_value_complex(false, true, lh->numdescs, lh->descs, + NULL, vals); } return -EINVAL; @@ -812,26 +823,26 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) { struct lineevent_state *le = p; struct gpioevent_data ge; - int ret, level; + int ret; /* Do not leak kernel stack to userspace */ memset(&ge, 0, sizeof(ge)); ge.timestamp = le->timestamp; - level = gpiod_get_value_cansleep(le->desc); if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) { + int level = gpiod_get_value_cansleep(le->desc); if (level) /* Emit low-to-high event */ ge.id = GPIOEVENT_EVENT_RISING_EDGE; else /* Emit high-to-low event */ ge.id = GPIOEVENT_EVENT_FALLING_EDGE; - } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && level) { + } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) { /* Emit low-to-high event */ ge.id = GPIOEVENT_EVENT_RISING_EDGE; - } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE && !level) { + } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) { /* Emit high-to-low event */ ge.id = GPIOEVENT_EVENT_FALLING_EDGE; } else { @@ -942,7 +953,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE) irqflags |= IRQF_TRIGGER_FALLING; irqflags |= IRQF_ONESHOT; - irqflags |= IRQF_SHARED; INIT_KFIFO(le->events); init_waitqueue_head(&le->wait); @@ -1341,19 +1351,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, spin_unlock_irqrestore(&gpio_lock, flags); - for (i = 0; i < chip->ngpio; i++) { - struct gpio_desc *desc = &gdev->descs[i]; - - desc->gdev = gdev; - - /* REVISIT: most hardware initializes GPIOs as inputs (often - * with pullups enabled) so power usage is minimized. Linux - * code should set the gpio direction first thing; but until - * it does, and in case chip->get_direction is not set, we may - * expose the wrong direction in sysfs. - */ - desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; - } + for (i = 0; i < chip->ngpio; i++) + gdev->descs[i].gdev = gdev; #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); @@ -1367,7 +1366,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, if (status) goto err_remove_from_list; - status = gpiochip_init_valid_mask(chip); + status = gpiochip_alloc_valid_mask(chip); if (status) goto err_remove_irqchip_mask; @@ -1379,6 +1378,21 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, if (status) goto err_remove_chip; + status = gpiochip_init_valid_mask(chip); + if (status) + goto err_remove_chip; + + for (i = 0; i < chip->ngpio; i++) { + struct gpio_desc *desc = &gdev->descs[i]; + + if (chip->get_direction && gpiochip_line_is_valid(chip, i)) + desc->flags = !chip->get_direction(chip, i) ? + (1 << FLAG_IS_OUT) : 0; + else + desc->flags = !chip->direction_input ? + (1 << FLAG_IS_OUT) : 0; + } + acpi_gpiochip_add(chip); machine_gpiochip_add(chip); @@ -1512,7 +1526,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data) /** * devm_gpiochip_add_data() - Resource manager gpiochip_add_data() - * @dev: the device pointer on which irq_chip belongs to. + * @dev: pointer to the device that gpio_chip belongs to. * @chip: the chip to register, with chip->base initialized * @data: driver-private data associated with this chip * @@ -1649,7 +1663,6 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); /** * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip * @gpiochip: the gpiochip to set the irqchip chain to - * @irqchip: the irqchip to chain to the gpiochip * @parent_irq: the irq number corresponding to the parent IRQ for this * chained irqchip * @parent_handler: the parent interrupt handler for the accumulated IRQ @@ -1657,12 +1670,9 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); * cascaded, pass NULL in this handler argument */ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, - struct irq_chip *irqchip, unsigned int parent_irq, irq_flow_handler_t parent_handler) { - unsigned int offset; - if (!gpiochip->irq.domain) { chip_err(gpiochip, "called %s before setting up irqchip\n", __func__); @@ -1686,14 +1696,6 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, gpiochip->irq.parents = &gpiochip->irq.parent_irq; gpiochip->irq.num_parents = 1; } - - /* Set the parent IRQ for all affected IRQs */ - for (offset = 0; offset < gpiochip->ngpio; offset++) { - if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) - continue; - irq_set_parent(irq_find_mapping(gpiochip->irq.domain, offset), - parent_irq); - } } /** @@ -1703,8 +1705,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, * @parent_irq: the irq number corresponding to the parent IRQ for this * chained irqchip * @parent_handler: the parent interrupt handler for the accumulated IRQ - * coming out of the gpiochip. If the interrupt is nested rather than - * cascaded, pass NULL in this handler argument + * coming out of the gpiochip. */ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, struct irq_chip *irqchip, @@ -1716,8 +1717,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, return; } - gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq, - parent_handler); + gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, parent_handler); } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); @@ -1732,8 +1732,7 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip, struct irq_chip *irqchip, unsigned int parent_irq) { - gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq, - NULL); + gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, NULL); } EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip); @@ -1805,39 +1804,75 @@ static const struct irq_domain_ops gpiochip_domain_ops = { .xlate = irq_domain_xlate_twocell, }; +static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) +{ + if (!gpiochip_irqchip_irq_valid(chip, offset)) + return -ENXIO; + + return irq_create_mapping(chip->irq.domain, offset); +} + static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); - int ret; - - if (!try_module_get(chip->gpiodev->owner)) - return -ENODEV; - ret = gpiochip_lock_as_irq(chip, d->hwirq); - if (ret) { - chip_err(chip, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - module_put(chip->gpiodev->owner); - return ret; - } - return 0; + return gpiochip_reqres_irq(chip, d->hwirq); } static void gpiochip_irq_relres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); - gpiochip_unlock_as_irq(chip, d->hwirq); - module_put(chip->gpiodev->owner); + gpiochip_relres_irq(chip, d->hwirq); } -static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) +static void gpiochip_irq_enable(struct irq_data *d) { - if (!gpiochip_irqchip_irq_valid(chip, offset)) - return -ENXIO; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); - return irq_create_mapping(chip->irq.domain, offset); + gpiochip_enable_irq(chip, d->hwirq); + if (chip->irq.irq_enable) + chip->irq.irq_enable(d); + else + chip->irq.chip->irq_unmask(d); +} + +static void gpiochip_irq_disable(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + if (chip->irq.irq_disable) + chip->irq.irq_disable(d); + else + chip->irq.chip->irq_mask(d); + gpiochip_disable_irq(chip, d->hwirq); +} + +static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip) +{ + struct irq_chip *irqchip = gpiochip->irq.chip; + + if (!irqchip->irq_request_resources && + !irqchip->irq_release_resources) { + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + } + if (WARN_ON(gpiochip->irq.irq_enable)) + return; + /* Check if the irqchip already has this hook... */ + if (irqchip->irq_enable == gpiochip_irq_enable) { + /* + * ...and if so, give a gentle warning that this is bad + * practice. + */ + chip_info(gpiochip, + "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); + return; + } + gpiochip->irq.irq_enable = irqchip->irq_enable; + gpiochip->irq.irq_disable = irqchip->irq_disable; + irqchip->irq_enable = gpiochip_irq_enable; + irqchip->irq_disable = gpiochip_irq_disable; } /** @@ -1898,16 +1933,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, if (!gpiochip->irq.domain) return -EINVAL; - /* - * It is possible for a driver to override this, but only if the - * alternative functions are both implemented. - */ - if (!irqchip->irq_request_resources && - !irqchip->irq_release_resources) { - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; - } - if (gpiochip->irq.parent_handler) { void *data = gpiochip->irq.parent_handler_data ?: gpiochip; @@ -1923,6 +1948,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, } } + gpiochip_set_irq_hooks(gpiochip); + acpi_gpiochip_request_interrupts(gpiochip); return 0; @@ -1936,11 +1963,12 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, */ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) { + struct irq_chip *irqchip = gpiochip->irq.chip; unsigned int offset; acpi_gpiochip_free_interrupts(gpiochip); - if (gpiochip->irq.chip && gpiochip->irq.parent_handler) { + if (irqchip && gpiochip->irq.parent_handler) { struct gpio_irq_chip *irq = &gpiochip->irq; unsigned int i; @@ -1964,11 +1992,19 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) irq_domain_remove(gpiochip->irq.domain); } - if (gpiochip->irq.chip) { - gpiochip->irq.chip->irq_request_resources = NULL; - gpiochip->irq.chip->irq_release_resources = NULL; - gpiochip->irq.chip = NULL; + if (irqchip) { + if (irqchip->irq_request_resources == gpiochip_irq_reqres) { + irqchip->irq_request_resources = NULL; + irqchip->irq_release_resources = NULL; + } + if (irqchip->irq_enable == gpiochip_irq_enable) { + irqchip->irq_enable = gpiochip->irq.irq_enable; + irqchip->irq_disable = gpiochip->irq.irq_disable; + } } + gpiochip->irq.irq_enable = NULL; + gpiochip->irq.irq_disable = NULL; + gpiochip->irq.chip = NULL; gpiochip_irqchip_free_valid_mask(gpiochip); } @@ -2057,15 +2093,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, return -EINVAL; } - /* - * It is possible for a driver to override this, but only if the - * alternative functions are both implemented. - */ - if (!irqchip->irq_request_resources && - !irqchip->irq_release_resources) { - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; - } + gpiochip_set_irq_hooks(gpiochip); acpi_gpiochip_request_interrupts(gpiochip); @@ -2513,19 +2541,38 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); int gpiod_direction_input(struct gpio_desc *desc) { struct gpio_chip *chip; - int status = -EINVAL; + int status = 0; VALIDATE_DESC(desc); chip = desc->gdev->chip; - if (!chip->get || !chip->direction_input) { + /* + * It is legal to have no .get() and .direction_input() specified if + * the chip is output-only, but you can't specify .direction_input() + * and not support the .get() operation, that doesn't make sense. + */ + if (!chip->get && chip->direction_input) { gpiod_warn(desc, - "%s: missing get() or direction_input() operations\n", - __func__); + "%s: missing get() but have direction_input()\n", + __func__); return -EIO; } - status = chip->direction_input(chip, gpio_chip_hwgpio(desc)); + /* + * If we have a .direction_input() callback, things are simple, + * just call it. Else we are some input-only chip so try to check the + * direction (if .get_direction() is supported) else we silently + * assume we are in input mode after this. + */ + if (chip->direction_input) { + status = chip->direction_input(chip, gpio_chip_hwgpio(desc)); + } else if (chip->get_direction && + (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) { + gpiod_warn(desc, + "%s: missing direction_input() operation and line is output\n", + __func__); + return -EIO; + } if (status == 0) clear_bit(FLAG_IS_OUT, &desc->flags); @@ -2547,16 +2594,38 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) { struct gpio_chip *gc = desc->gdev->chip; int val = !!value; - int ret; + int ret = 0; - if (!gc->set || !gc->direction_output) { + /* + * It's OK not to specify .direction_output() if the gpiochip is + * output-only, but if there is then not even a .set() operation it + * is pretty tricky to drive the output line. + */ + if (!gc->set && !gc->direction_output) { gpiod_warn(desc, - "%s: missing set() or direction_output() operations\n", - __func__); + "%s: missing set() and direction_output() operations\n", + __func__); return -EIO; } - ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val); + if (gc->direction_output) { + ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val); + } else { + /* Check that we are in output mode if we can */ + if (gc->get_direction && + gc->get_direction(gc, gpio_chip_hwgpio(desc))) { + gpiod_warn(desc, + "%s: missing direction_output() operation\n", + __func__); + return -EIO; + } + /* + * If we can't actively set the direction, we are some + * output-only chip, so just drive the output as desired. + */ + gc->set(gc, gpio_chip_hwgpio(desc), val); + } + if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); trace_gpio_value(desc_to_gpio(desc), 0, val); @@ -2605,8 +2674,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) else value = !!value; - /* GPIOs used for IRQs shall not be set as output */ - if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { + /* GPIOs used for enabled IRQs shall not be set as output */ + if (test_bit(FLAG_USED_AS_IRQ, &desc->flags) && + test_bit(FLAG_IRQ_IS_ENABLED, &desc->flags)) { gpiod_err(desc, "%s: tried to set a GPIO tied to an IRQ as output\n", __func__); @@ -2785,9 +2855,39 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip, int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + struct gpio_array *array_info, + unsigned long *value_bitmap) { - int i = 0; + int err, i = 0; + + /* + * Validate array_info against desc_array and its size. + * It should immediately follow desc_array if both + * have been obtained from the same gpiod_get_array() call. + */ + if (array_info && array_info->desc == desc_array && + array_size <= array_info->size && + (void *)array_info == desc_array + array_info->size) { + if (!can_sleep) + WARN_ON(array_info->chip->can_sleep); + + err = gpio_chip_get_multiple(array_info->chip, + array_info->get_mask, + value_bitmap); + if (err) + return err; + + if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) + bitmap_xor(value_bitmap, value_bitmap, + array_info->invert_mask, array_size); + + if (bitmap_full(array_info->get_mask, array_size)) + return 0; + + i = find_first_zero_bit(array_info->get_mask, array_size); + } else { + array_info = NULL; + } while (i < array_size) { struct gpio_chip *chip = desc_array[i]->gdev->chip; @@ -2819,6 +2919,10 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, __set_bit(hwgpio, mask); i++; + + if (array_info) + i = find_next_zero_bit(array_info->get_mask, + array_size, i); } while ((i < array_size) && (desc_array[i]->gdev->chip == chip)); @@ -2829,15 +2933,20 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, return ret; } - for (j = first; j < i; j++) { + for (j = first; j < i; ) { const struct gpio_desc *desc = desc_array[j]; int hwgpio = gpio_chip_hwgpio(desc); int value = test_bit(hwgpio, bits); if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; - value_array[j] = value; + __assign_bit(j, value_bitmap, value); trace_gpio_value(desc_to_gpio(desc), 1, value); + j++; + + if (array_info) + j = find_next_zero_bit(array_info->get_mask, i, + j); } if (mask != fastpath) @@ -2896,9 +3005,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); /** * gpiod_get_raw_array_value() - read raw values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap to store the read values * * Read the raw values of the GPIOs, i.e. the values of the physical lines * without regard for their ACTIVE_LOW status. Return 0 in case of success, @@ -2908,20 +3018,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); * and it will complain if the GPIO chip functions potentially sleep. */ int gpiod_get_raw_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(true, false, array_size, - desc_array, value_array); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); /** * gpiod_get_array_value() - read values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap to store the read values * * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. Return 0 in case of success, else an error code. @@ -2930,12 +3044,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); * and it will complain if the GPIO chip functions potentially sleep. */ int gpiod_get_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(false, false, array_size, - desc_array, value_array); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_array_value); @@ -3026,12 +3143,39 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip, } int gpiod_set_array_value_complex(bool raw, bool can_sleep, - unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array) + unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) { int i = 0; + /* + * Validate array_info against desc_array and its size. + * It should immediately follow desc_array if both + * have been obtained from the same gpiod_get_array() call. + */ + if (array_info && array_info->desc == desc_array && + array_size <= array_info->size && + (void *)array_info == desc_array + array_info->size) { + if (!can_sleep) + WARN_ON(array_info->chip->can_sleep); + + if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) + bitmap_xor(value_bitmap, value_bitmap, + array_info->invert_mask, array_size); + + gpio_chip_set_multiple(array_info->chip, array_info->set_mask, + value_bitmap); + + if (bitmap_full(array_info->set_mask, array_size)) + return 0; + + i = find_first_zero_bit(array_info->set_mask, array_size); + } else { + array_info = NULL; + } + while (i < array_size) { struct gpio_chip *chip = desc_array[i]->gdev->chip; unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; @@ -3057,9 +3201,16 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, do { struct gpio_desc *desc = desc_array[i]; int hwgpio = gpio_chip_hwgpio(desc); - int value = value_array[i]; + int value = test_bit(i, value_bitmap); - if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + /* + * Pins applicable for fast input but not for + * fast output processing may have been already + * inverted inside the fast path, skip them. + */ + if (!raw && !(array_info && + test_bit(i, array_info->invert_mask)) && + test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; trace_gpio_value(desc_to_gpio(desc), 0, value); /* @@ -3079,6 +3230,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, count++; } i++; + + if (array_info) + i = find_next_zero_bit(array_info->set_mask, + array_size, i); } while ((i < array_size) && (desc_array[i]->gdev->chip == chip)); /* push collected bits to outputs */ @@ -3153,9 +3308,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); /** * gpiod_set_raw_array_value() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap of values to assign * * Set the raw values of the GPIOs, i.e. the values of the physical lines * without regard for their ACTIVE_LOW status. @@ -3164,20 +3320,23 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); * complain if the GPIO chip functions potentially sleep. */ int gpiod_set_raw_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(true, false, array_size, - desc_array, value_array); + desc_array, array_info, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); /** * gpiod_set_array_value() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap of values to assign * * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. @@ -3185,13 +3344,16 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); * This function should be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. */ -void gpiod_set_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) +int gpiod_set_array_value(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) { if (!desc_array) - return; - gpiod_set_array_value_complex(false, false, array_size, desc_array, - value_array); + return -EINVAL; + return gpiod_set_array_value_complex(false, false, array_size, + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_array_value); @@ -3293,6 +3455,7 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) } set_bit(FLAG_USED_AS_IRQ, &desc->flags); + set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags); /* * If the consumer has not set up a label (such as when the @@ -3323,6 +3486,7 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) return; clear_bit(FLAG_USED_AS_IRQ, &desc->flags); + clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags); /* If we only had this marking, erase it */ if (desc->label && !strcmp(desc->label, "interrupt")) @@ -3330,6 +3494,28 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) } EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); +void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct gpio_desc *desc = gpiochip_get_desc(chip, offset); + + if (!IS_ERR(desc) && + !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) + clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags); +} +EXPORT_SYMBOL_GPL(gpiochip_disable_irq); + +void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct gpio_desc *desc = gpiochip_get_desc(chip, offset); + + if (!IS_ERR(desc) && + !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) { + WARN_ON(test_bit(FLAG_IS_OUT, &desc->flags)); + set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags); + } +} +EXPORT_SYMBOL_GPL(gpiochip_enable_irq); + bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset) { if (offset >= chip->ngpio) @@ -3339,6 +3525,30 @@ bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset) } EXPORT_SYMBOL_GPL(gpiochip_line_is_irq); +int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset) +{ + int ret; + + if (!try_module_get(chip->gpiodev->owner)) + return -ENODEV; + + ret = gpiochip_lock_as_irq(chip, offset); + if (ret) { + chip_err(chip, "unable to lock HW IRQ %u for IRQ\n", offset); + module_put(chip->gpiodev->owner); + return ret; + } + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_reqres_irq); + +void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset) +{ + gpiochip_unlock_as_irq(chip, offset); + module_put(chip->gpiodev->owner); +} +EXPORT_SYMBOL_GPL(gpiochip_relres_irq); + bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset) { if (offset >= chip->ngpio) @@ -3411,9 +3621,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); /** * gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap to store the read values * * Read the raw values of the GPIOs, i.e. the values of the physical lines * without regard for their ACTIVE_LOW status. Return 0 in case of success, @@ -3423,21 +3634,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); */ int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + struct gpio_array *array_info, + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(true, true, array_size, - desc_array, value_array); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); /** * gpiod_get_array_value_cansleep() - read values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap to store the read values * * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. Return 0 in case of success, else an error code. @@ -3446,13 +3660,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); */ int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + struct gpio_array *array_info, + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(false, true, array_size, - desc_array, value_array); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); @@ -3494,9 +3710,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); /** * gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap of values to assign * * Set the raw values of the GPIOs, i.e. the values of the physical lines * without regard for their ACTIVE_LOW status. @@ -3504,14 +3721,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); * This function is to be called from contexts that can sleep. */ int gpiod_set_raw_array_value_cansleep(unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array) + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(true, true, array_size, desc_array, - value_array); + array_info, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep); @@ -3534,24 +3752,27 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) /** * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @array_info: information on applicability of fast bitmap processing path + * @value_bitmap: bitmap of values to assign * * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. * * This function is to be called from contexts that can sleep. */ -void gpiod_set_array_value_cansleep(unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array) +int gpiod_set_array_value_cansleep(unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) - return; - gpiod_set_array_value_complex(false, true, array_size, desc_array, - value_array); + return -EINVAL; + return gpiod_set_array_value_complex(false, true, array_size, + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); @@ -3909,8 +4130,23 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, * the device name as label */ status = gpiod_request(desc, con_id ? con_id : devname); - if (status < 0) - return ERR_PTR(status); + if (status < 0) { + if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { + /* + * This happens when there are several consumers for + * the same GPIO line: we just return here without + * further initialization. It is a bit if a hack. + * This is necessary to support fixed regulators. + * + * FIXME: Make this more sane and safe. + */ + dev_info(dev, "nonexclusive access to GPIO for %s\n", + con_id ? con_id : devname); + return desc; + } else { + return ERR_PTR(status); + } + } status = gpiod_configure_flags(desc, con_id, lookupflags, flags); if (status < 0) { @@ -4171,7 +4407,9 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, { struct gpio_desc *desc; struct gpio_descs *descs; - int count; + struct gpio_array *array_info = NULL; + struct gpio_chip *chip; + int count, bitmap_size; count = gpiod_count(dev, con_id); if (count < 0) @@ -4187,9 +4425,92 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, gpiod_put_array(descs); return ERR_CAST(desc); } + descs->desc[descs->ndescs] = desc; + + chip = gpiod_to_chip(desc); + /* + * If pin hardware number of array member 0 is also 0, select + * its chip as a candidate for fast bitmap processing path. + */ + if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) { + struct gpio_descs *array; + + bitmap_size = BITS_TO_LONGS(chip->ngpio > count ? + chip->ngpio : count); + + array = kzalloc(struct_size(descs, desc, count) + + struct_size(array_info, invert_mask, + 3 * bitmap_size), GFP_KERNEL); + if (!array) { + gpiod_put_array(descs); + return ERR_PTR(-ENOMEM); + } + + memcpy(array, descs, + struct_size(descs, desc, descs->ndescs + 1)); + kfree(descs); + + descs = array; + array_info = (void *)(descs->desc + count); + array_info->get_mask = array_info->invert_mask + + bitmap_size; + array_info->set_mask = array_info->get_mask + + bitmap_size; + + array_info->desc = descs->desc; + array_info->size = count; + array_info->chip = chip; + bitmap_set(array_info->get_mask, descs->ndescs, + count - descs->ndescs); + bitmap_set(array_info->set_mask, descs->ndescs, + count - descs->ndescs); + descs->info = array_info; + } + /* Unmark array members which don't belong to the 'fast' chip */ + if (array_info && array_info->chip != chip) { + __clear_bit(descs->ndescs, array_info->get_mask); + __clear_bit(descs->ndescs, array_info->set_mask); + } + /* + * Detect array members which belong to the 'fast' chip + * but their pins are not in hardware order. + */ + else if (array_info && + gpio_chip_hwgpio(desc) != descs->ndescs) { + /* + * Don't use fast path if all array members processed so + * far belong to the same chip as this one but its pin + * hardware number is different from its array index. + */ + if (bitmap_full(array_info->get_mask, descs->ndescs)) { + array_info = NULL; + } else { + __clear_bit(descs->ndescs, + array_info->get_mask); + __clear_bit(descs->ndescs, + array_info->set_mask); + } + } else if (array_info) { + /* Exclude open drain or open source from fast output */ + if (gpiochip_line_is_open_drain(chip, descs->ndescs) || + gpiochip_line_is_open_source(chip, descs->ndescs)) + __clear_bit(descs->ndescs, + array_info->set_mask); + /* Identify 'fast' pins which require invertion */ + if (gpiod_is_active_low(desc)) + __set_bit(descs->ndescs, + array_info->invert_mask); + } + descs->ndescs++; } + if (array_info) + dev_dbg(dev, + "GPIO array info: chip=%s, size=%d, get_mask=%lx, set_mask=%lx, invert_mask=%lx\n", + array_info->chip->label, array_info->size, + *array_info->get_mask, *array_info->set_mask, + *array_info->invert_mask); return descs; } EXPORT_SYMBOL_GPL(gpiod_get_array); @@ -4276,8 +4597,9 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) struct gpio_chip *chip = gdev->chip; unsigned gpio = gdev->base; struct gpio_desc *gdesc = &gdev->descs[0]; - int is_out; - int is_irq; + bool is_out; + bool is_irq; + bool active_low; for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) { @@ -4291,11 +4613,13 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); - seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s", + active_low = test_bit(FLAG_ACTIVE_LOW, &gdesc->flags); + seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s", gpio, gdesc->name ? gdesc->name : "", gdesc->label, is_out ? "out" : "in ", chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? ", - is_irq ? "IRQ" : " "); + is_irq ? "IRQ " : "", + active_low ? "ACTIVE LOW" : ""); seq_printf(s, "\n"); } } diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index a7e49fef73d4..087d865286a0 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Internal GPIO functions. * * Copyright (C) 2013, Intel Corporation * Author: Mika Westerberg <mika.westerberg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef GPIOLIB_H @@ -183,15 +180,26 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev, } #endif +struct gpio_array { + struct gpio_desc **desc; + unsigned int size; + struct gpio_chip *chip; + unsigned long *get_mask; + unsigned long *set_mask; + unsigned long invert_mask[]; +}; + struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, - int *value_array); + struct gpio_array *array_info, + unsigned long *value_bitmap); int gpiod_set_array_value_complex(bool raw, bool can_sleep, - unsigned int array_size, - struct gpio_desc **desc_array, - int *value_array); + unsigned int array_size, + struct gpio_desc **desc_array, + struct gpio_array *array_info, + unsigned long *value_bitmap); /* This is just passed between gpiolib and devres */ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, @@ -214,6 +222,7 @@ struct gpio_desc { #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ +#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 018fcdb353d2..281cf9cbb44c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -174,6 +174,11 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state) state->crtcs[i].state = NULL; state->crtcs[i].old_state = NULL; state->crtcs[i].new_state = NULL; + + if (state->crtcs[i].commit) { + drm_crtc_commit_put(state->crtcs[i].commit); + state->crtcs[i].commit = NULL; + } } for (i = 0; i < config->num_total_plane; i++) { diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 80be74df7ba6..1bb4c318bdd4 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1408,15 +1408,16 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev, struct drm_atomic_state *old_state) { - struct drm_crtc_state *new_crtc_state; struct drm_crtc *crtc; int i; - for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { - struct drm_crtc_commit *commit = new_crtc_state->commit; + for (i = 0; i < dev->mode_config.num_crtc; i++) { + struct drm_crtc_commit *commit = old_state->crtcs[i].commit; int ret; - if (!commit) + crtc = old_state->crtcs[i].ptr; + + if (!crtc || !commit) continue; ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ); @@ -1934,6 +1935,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, drm_crtc_commit_get(commit); commit->abort_completion = true; + + state->crtcs[i].commit = commit; + drm_crtc_commit_get(commit); } for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index e36004fbe453..2a15f2f9271e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -81,9 +81,19 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, int i; for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) { - unsigned long ideal = rate * i; + u64 ideal = (u64)rate * i; unsigned long rounded; + /* + * ideal has overflowed the max value that can be stored in an + * unsigned long, and every clk operation we might do on a + * truncated u64 value will give us incorrect results. + * Let's just stop there since bigger dividers will result in + * the same overflow issue. + */ + if (ideal > ULONG_MAX) + goto out; + rounded = clk_hw_round_rate(clk_hw_get_parent(hw), ideal); diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c index 5e449eac788a..92de8139d398 100644 --- a/drivers/hwmon/aspeed-pwm-tacho.c +++ b/drivers/hwmon/aspeed-pwm-tacho.c @@ -852,7 +852,7 @@ static int aspeed_create_pwm_cooling(struct device *dev, dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); return ret; } - snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%s%d", child->name, pwm_port); + snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port); cdev->tcdev = thermal_of_cooling_device_register(child, cdev->name, diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index a6636fe42189..a7cf00885c5d 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -1210,10 +1210,8 @@ static int atk_register_hwmon(struct atk_data *data) data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110", data, data->attr_groups); - if (IS_ERR(data->hwmon_dev)) - return PTR_ERR(data->hwmon_dev); - return 0; + return PTR_ERR_OR_ZERO(data->hwmon_dev); } static int atk_probe_if(struct atk_data *data) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 33d51281272b..975c95169884 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -24,6 +24,9 @@ #include <linux/string.h> #include <linux/thermal.h> +#define CREATE_TRACE_POINTS +#include <trace/events/hwmon.h> + #define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" @@ -171,6 +174,13 @@ static int hwmon_thermal_add_sensor(struct device *dev, } #endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */ +static int hwmon_attr_base(enum hwmon_sensor_types type) +{ + if (type == hwmon_in) + return 0; + return 1; +} + /* sysfs attribute management */ static ssize_t hwmon_attr_show(struct device *dev, @@ -185,6 +195,9 @@ static ssize_t hwmon_attr_show(struct device *dev, if (ret < 0) return ret; + trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type), + hattr->name, val); + return sprintf(buf, "%ld\n", val); } @@ -193,6 +206,7 @@ static ssize_t hwmon_attr_show_string(struct device *dev, char *buf) { struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); + enum hwmon_sensor_types type = hattr->type; const char *s; int ret; @@ -201,6 +215,9 @@ static ssize_t hwmon_attr_show_string(struct device *dev, if (ret < 0) return ret; + trace_hwmon_attr_show_string(hattr->index + hwmon_attr_base(type), + hattr->name, s); + return sprintf(buf, "%s\n", s); } @@ -221,14 +238,10 @@ static ssize_t hwmon_attr_store(struct device *dev, if (ret < 0) return ret; - return count; -} + trace_hwmon_attr_store(hattr->index + hwmon_attr_base(hattr->type), + hattr->name, val); -static int hwmon_attr_base(enum hwmon_sensor_types type) -{ - if (type == hwmon_in) - return 0; - return 1; + return count; } static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) @@ -356,6 +369,7 @@ static const char * const hwmon_in_attr_templates[] = { [hwmon_in_max_alarm] = "in%d_max_alarm", [hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm", [hwmon_in_crit_alarm] = "in%d_crit_alarm", + [hwmon_in_enable] = "in%d_enable", }; static const char * const hwmon_curr_attr_templates[] = { diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index 1f643782ce04..9e92673f6913 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -101,7 +101,7 @@ static struct platform_driver aem_driver = { struct aem_ipmi_data { struct completion read_complete; struct ipmi_addr address; - ipmi_user_t user; + struct ipmi_user *user; int interface; struct kernel_ipmi_msg tx_message; diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index ab72cabf5a95..bb17a29af64c 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -84,7 +84,7 @@ struct ibmpex_bmc_data { struct ipmi_addr address; struct completion read_complete; - ipmi_user_t user; + struct ipmi_user *user; int interface; struct kernel_ipmi_msg tx_message; diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c index 83472808c816..0ccca87f5271 100644 --- a/drivers/hwmon/ibmpowernv.c +++ b/drivers/hwmon/ibmpowernv.c @@ -458,9 +458,6 @@ static int populate_attr_groups(struct platform_device *pdev) for_each_child_of_node(opal, np) { const char *label; - if (np->name == NULL) - continue; - type = get_sensor_type(np); if (type == MAX_SENSOR_TYPE) continue; @@ -589,9 +586,6 @@ static int create_device_attrs(struct platform_device *pdev) const char *label; enum sensors type; - if (np->name == NULL) - continue; - type = get_sensor_type(np); if (type == MAX_SENSOR_TYPE) continue; @@ -603,8 +597,8 @@ static int create_device_attrs(struct platform_device *pdev) if (of_property_read_u32(np, "sensor-id", &sensor_id) && of_property_read_u32(np, "sensor-data", &sensor_id)) { dev_info(&pdev->dev, - "'sensor-id' missing in the node '%s'\n", - np->name); + "'sensor-id' missing in the node '%pOFn'\n", + np); continue; } diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 2f3f875c06ac..eed66e533ee2 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -65,13 +65,9 @@ static int iio_hwmon_probe(struct platform_device *pdev) int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1; enum iio_chan_type type; struct iio_channel *channels; - const char *name = "iio_hwmon"; struct device *hwmon_dev; char *sname; - if (dev->of_node && dev->of_node->name) - name = dev->of_node->name; - channels = devm_iio_channel_get_all(dev); if (IS_ERR(channels)) { if (PTR_ERR(channels) == -ENODEV) @@ -141,11 +137,15 @@ static int iio_hwmon_probe(struct platform_device *pdev) st->attr_group.attrs = st->attrs; st->groups[0] = &st->attr_group; - sname = devm_kstrdup(dev, name, GFP_KERNEL); - if (!sname) - return -ENOMEM; + if (dev->of_node) { + sname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node); + if (!sname) + return -ENOMEM; + strreplace(sname, '-', '_'); + } else { + sname = "iio_hwmon"; + } - strreplace(sname, '-', '_'); hwmon_dev = devm_hwmon_device_register_with_groups(dev, sname, st, st->groups); return PTR_ERR_OR_ZERO(hwmon_dev); diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index e6b49500c52a..d61688f04594 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -38,9 +38,12 @@ #define INA3221_WARN3 0x0c #define INA3221_MASK_ENABLE 0x0f -#define INA3221_CONFIG_MODE_SHUNT BIT(1) -#define INA3221_CONFIG_MODE_BUS BIT(2) -#define INA3221_CONFIG_MODE_CONTINUOUS BIT(3) +#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0) +#define INA3221_CONFIG_MODE_POWERDOWN 0 +#define INA3221_CONFIG_MODE_SHUNT BIT(0) +#define INA3221_CONFIG_MODE_BUS BIT(1) +#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) +#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) #define INA3221_RSHUNT_DEFAULT 10000 @@ -74,30 +77,37 @@ enum ina3221_channels { INA3221_NUM_CHANNELS }; -static const unsigned int register_channel[] = { - [INA3221_SHUNT1] = INA3221_CHANNEL1, - [INA3221_SHUNT2] = INA3221_CHANNEL2, - [INA3221_SHUNT3] = INA3221_CHANNEL3, - [INA3221_CRIT1] = INA3221_CHANNEL1, - [INA3221_CRIT2] = INA3221_CHANNEL2, - [INA3221_CRIT3] = INA3221_CHANNEL3, - [INA3221_WARN1] = INA3221_CHANNEL1, - [INA3221_WARN2] = INA3221_CHANNEL2, - [INA3221_WARN3] = INA3221_CHANNEL3, +/** + * struct ina3221_input - channel input source specific information + * @label: label of channel input source + * @shunt_resistor: shunt resistor value of channel input source + * @disconnected: connection status of channel input source + */ +struct ina3221_input { + const char *label; + int shunt_resistor; + bool disconnected; }; /** * struct ina3221_data - device specific information * @regmap: Register map of the device * @fields: Register fields of the device - * @shunt_resistors: Array of resistor values per channel + * @inputs: Array of channel input source specific structures + * @reg_config: Register value of INA3221_CONFIG */ struct ina3221_data { struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; - int shunt_resistors[INA3221_NUM_CHANNELS]; + struct ina3221_input inputs[INA3221_NUM_CHANNELS]; + u32 reg_config; }; +static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) +{ + return ina->reg_config & INA3221_CONFIG_CHx_EN(channel); +} + static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, int *val) { @@ -113,107 +123,284 @@ static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, return 0; } -static ssize_t ina3221_show_bus_voltage(struct device *dev, - struct device_attribute *attr, - char *buf) +static const u8 ina3221_in_reg[] = { + INA3221_BUS1, + INA3221_BUS2, + INA3221_BUS3, + INA3221_SHUNT1, + INA3221_SHUNT2, + INA3221_SHUNT3, +}; + +static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val) { - struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + const bool is_shunt = channel > INA3221_CHANNEL3; struct ina3221_data *ina = dev_get_drvdata(dev); - unsigned int reg = sd_attr->index; - int val, voltage_mv, ret; - - ret = ina3221_read_value(ina, reg, &val); - if (ret) - return ret; + u8 reg = ina3221_in_reg[channel]; + int regval, ret; + + /* Translate shunt channel index to sensor channel index */ + channel %= INA3221_NUM_CHANNELS; + + switch (attr) { + case hwmon_in_input: + if (!ina3221_is_enabled(ina, channel)) + return -ENODATA; + + ret = ina3221_read_value(ina, reg, ®val); + if (ret) + return ret; + + /* + * Scale of shunt voltage (uV): LSB is 40uV + * Scale of bus voltage (mV): LSB is 8mV + */ + *val = regval * (is_shunt ? 40 : 8); + return 0; + case hwmon_in_enable: + *val = ina3221_is_enabled(ina, channel); + return 0; + default: + return -EOPNOTSUPP; + } +} - voltage_mv = val * 8; +static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS] = { + [hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, INA3221_SHUNT3 }, + [hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3 }, + [hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, INA3221_CRIT3 }, + [hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3 }, + [hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3 }, +}; - return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv); +static int ina3221_read_curr(struct device *dev, u32 attr, + int channel, long *val) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + struct ina3221_input *input = &ina->inputs[channel]; + int resistance_uo = input->shunt_resistor; + u8 reg = ina3221_curr_reg[attr][channel]; + int regval, voltage_nv, ret; + + switch (attr) { + case hwmon_curr_input: + if (!ina3221_is_enabled(ina, channel)) + return -ENODATA; + /* fall through */ + case hwmon_curr_crit: + case hwmon_curr_max: + ret = ina3221_read_value(ina, reg, ®val); + if (ret) + return ret; + + /* Scale of shunt voltage: LSB is 40uV (40000nV) */ + voltage_nv = regval * 40000; + /* Return current in mA */ + *val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); + return 0; + case hwmon_curr_crit_alarm: + case hwmon_curr_max_alarm: + ret = regmap_field_read(ina->fields[reg], ®val); + if (ret) + return ret; + *val = regval; + return 0; + default: + return -EOPNOTSUPP; + } } -static ssize_t ina3221_show_shunt_voltage(struct device *dev, - struct device_attribute *attr, - char *buf) +static int ina3221_write_curr(struct device *dev, u32 attr, + int channel, long val) { - struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); - unsigned int reg = sd_attr->index; - int val, voltage_uv, ret; + struct ina3221_input *input = &ina->inputs[channel]; + int resistance_uo = input->shunt_resistor; + u8 reg = ina3221_curr_reg[attr][channel]; + int regval, current_ma, voltage_uv; - ret = ina3221_read_value(ina, reg, &val); - if (ret) - return ret; - voltage_uv = val * 40; + /* clamp current */ + current_ma = clamp_val(val, + INT_MIN / resistance_uo, + INT_MAX / resistance_uo); + + voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); - return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv); + /* clamp voltage */ + voltage_uv = clamp_val(voltage_uv, -163800, 163800); + + /* 1 / 40uV(scale) << 3(register shift) = 5 */ + regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; + + return regmap_write(ina->regmap, reg, regval); } -static ssize_t ina3221_show_current(struct device *dev, - struct device_attribute *attr, char *buf) +static int ina3221_write_enable(struct device *dev, int channel, bool enable) { - struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); - unsigned int reg = sd_attr->index; - unsigned int channel = register_channel[reg]; - int resistance_uo = ina->shunt_resistors[channel]; - int val, current_ma, voltage_nv, ret; + u16 config, mask = INA3221_CONFIG_CHx_EN(channel); + int ret; - ret = ina3221_read_value(ina, reg, &val); + config = enable ? mask : 0; + + /* Enable or disable the channel */ + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config); if (ret) return ret; - voltage_nv = val * 40000; - current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); + /* Cache the latest config register value */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); + if (ret) + return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", current_ma); + return 0; } -static ssize_t ina3221_set_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_in: + /* 0-align channel ID */ + return ina3221_read_in(dev, attr, channel - 1, val); + case hwmon_curr: + return ina3221_read_curr(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_in: + /* 0-align channel ID */ + return ina3221_write_enable(dev, channel - 1, val); + case hwmon_curr: + return ina3221_write_curr(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) { - struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); - unsigned int reg = sd_attr->index; - unsigned int channel = register_channel[reg]; - int resistance_uo = ina->shunt_resistors[channel]; - int val, current_ma, voltage_uv, ret; + int index = channel - 1; - ret = kstrtoint(buf, 0, ¤t_ma); - if (ret) - return ret; + *str = ina->inputs[index].label; - /* clamp current */ - current_ma = clamp_val(current_ma, - INT_MIN / resistance_uo, - INT_MAX / resistance_uo); + return 0; +} - voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); +static umode_t ina3221_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct ina3221_data *ina = drvdata; + const struct ina3221_input *input = NULL; + + switch (type) { + case hwmon_in: + /* Ignore in0_ */ + if (channel == 0) + return 0; + + switch (attr) { + case hwmon_in_label: + if (channel - 1 <= INA3221_CHANNEL3) + input = &ina->inputs[channel - 1]; + /* Hide label node if label is not provided */ + return (input && input->label) ? 0444 : 0; + case hwmon_in_input: + return 0444; + case hwmon_in_enable: + return 0644; + default: + return 0; + } + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + case hwmon_curr_crit_alarm: + case hwmon_curr_max_alarm: + return 0444; + case hwmon_curr_crit: + case hwmon_curr_max: + return 0644; + default: + return 0; + } + default: + return 0; + } +} - /* clamp voltage */ - voltage_uv = clamp_val(voltage_uv, -163800, 163800); +static const u32 ina3221_in_config[] = { + /* 0: dummy, skipped in is_visible */ + HWMON_I_INPUT, + /* 1-3: input voltage Channels */ + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL, + /* 4-6: shunt voltage Channels */ + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + 0 +}; - /* 1 / 40uV(scale) << 3(register shift) = 5 */ - val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; +static const struct hwmon_channel_info ina3221_in = { + .type = hwmon_in, + .config = ina3221_in_config, +}; - ret = regmap_write(ina->regmap, reg, val); - if (ret) - return ret; +#define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \ + HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \ + HWMON_C_MAX | HWMON_C_MAX_ALARM) - return count; -} +static const u32 ina3221_curr_config[] = { + INA3221_HWMON_CURR_CONFIG, + INA3221_HWMON_CURR_CONFIG, + INA3221_HWMON_CURR_CONFIG, + 0 +}; + +static const struct hwmon_channel_info ina3221_curr = { + .type = hwmon_curr, + .config = ina3221_curr_config, +}; + +static const struct hwmon_channel_info *ina3221_info[] = { + &ina3221_in, + &ina3221_curr, + NULL +}; + +static const struct hwmon_ops ina3221_hwmon_ops = { + .is_visible = ina3221_is_visible, + .read_string = ina3221_read_string, + .read = ina3221_read, + .write = ina3221_write, +}; +static const struct hwmon_chip_info ina3221_chip_info = { + .ops = &ina3221_hwmon_ops, + .info = ina3221_info, +}; + +/* Extra attribute groups */ static ssize_t ina3221_show_shunt(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int channel = sd_attr->index; - unsigned int resistance_uo; - - resistance_uo = ina->shunt_resistors[channel]; + struct ina3221_input *input = &ina->inputs[channel]; - return snprintf(buf, PAGE_SIZE, "%d\n", resistance_uo); + return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); } static ssize_t ina3221_set_shunt(struct device *dev, @@ -223,6 +410,7 @@ static ssize_t ina3221_set_shunt(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int channel = sd_attr->index; + struct ina3221_input *input = &ina->inputs[channel]; int val; int ret; @@ -232,43 +420,11 @@ static ssize_t ina3221_set_shunt(struct device *dev, val = clamp_val(val, 1, INT_MAX); - ina->shunt_resistors[channel] = val; + input->shunt_resistor = val; return count; } -static ssize_t ina3221_show_alert(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); - struct ina3221_data *ina = dev_get_drvdata(dev); - unsigned int field = sd_attr->index; - unsigned int regval; - int ret; - - ret = regmap_field_read(ina->fields[field], ®val); - if (ret) - return ret; - - return snprintf(buf, PAGE_SIZE, "%d\n", regval); -} - -/* bus voltage */ -static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, - ina3221_show_bus_voltage, NULL, INA3221_BUS1); -static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, - ina3221_show_bus_voltage, NULL, INA3221_BUS2); -static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, - ina3221_show_bus_voltage, NULL, INA3221_BUS3); - -/* calculated current */ -static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, - ina3221_show_current, NULL, INA3221_SHUNT1); -static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, - ina3221_show_current, NULL, INA3221_SHUNT2); -static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, - ina3221_show_current, NULL, INA3221_SHUNT3); - /* shunt resistance */ static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR, ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1); @@ -277,83 +433,16 @@ static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR, ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3); -/* critical current */ -static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR, - ina3221_show_current, ina3221_set_current, INA3221_CRIT1); -static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR, - ina3221_show_current, ina3221_set_current, INA3221_CRIT2); -static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR, - ina3221_show_current, ina3221_set_current, INA3221_CRIT3); - -/* critical current alert */ -static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO, - ina3221_show_alert, NULL, F_CF1); -static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO, - ina3221_show_alert, NULL, F_CF2); -static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO, - ina3221_show_alert, NULL, F_CF3); - -/* warning current */ -static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, - ina3221_show_current, ina3221_set_current, INA3221_WARN1); -static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR, - ina3221_show_current, ina3221_set_current, INA3221_WARN2); -static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR, - ina3221_show_current, ina3221_set_current, INA3221_WARN3); - -/* warning current alert */ -static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, - ina3221_show_alert, NULL, F_WF1); -static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO, - ina3221_show_alert, NULL, F_WF2); -static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO, - ina3221_show_alert, NULL, F_WF3); - -/* shunt voltage */ -static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, - ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1); -static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, - ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2); -static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, - ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3); - static struct attribute *ina3221_attrs[] = { - /* channel 1 */ - &sensor_dev_attr_in1_input.dev_attr.attr, - &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_shunt1_resistor.dev_attr.attr, - &sensor_dev_attr_curr1_crit.dev_attr.attr, - &sensor_dev_attr_curr1_crit_alarm.dev_attr.attr, - &sensor_dev_attr_curr1_max.dev_attr.attr, - &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, - &sensor_dev_attr_in4_input.dev_attr.attr, - - /* channel 2 */ - &sensor_dev_attr_in2_input.dev_attr.attr, - &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_shunt2_resistor.dev_attr.attr, - &sensor_dev_attr_curr2_crit.dev_attr.attr, - &sensor_dev_attr_curr2_crit_alarm.dev_attr.attr, - &sensor_dev_attr_curr2_max.dev_attr.attr, - &sensor_dev_attr_curr2_max_alarm.dev_attr.attr, - &sensor_dev_attr_in5_input.dev_attr.attr, - - /* channel 3 */ - &sensor_dev_attr_in3_input.dev_attr.attr, - &sensor_dev_attr_curr3_input.dev_attr.attr, &sensor_dev_attr_shunt3_resistor.dev_attr.attr, - &sensor_dev_attr_curr3_crit.dev_attr.attr, - &sensor_dev_attr_curr3_crit_alarm.dev_attr.attr, - &sensor_dev_attr_curr3_max.dev_attr.attr, - &sensor_dev_attr_curr3_max_alarm.dev_attr.attr, - &sensor_dev_attr_in6_input.dev_attr.attr, - NULL, }; ATTRIBUTE_GROUPS(ina3221); static const struct regmap_range ina3221_yes_ranges[] = { - regmap_reg_range(INA3221_SHUNT1, INA3221_BUS3), + regmap_reg_range(INA3221_CONFIG, INA3221_BUS3), regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), }; @@ -370,6 +459,66 @@ static const struct regmap_config ina3221_regmap_config = { .volatile_table = &ina3221_volatile_table, }; +static int ina3221_probe_child_from_dt(struct device *dev, + struct device_node *child, + struct ina3221_data *ina) +{ + struct ina3221_input *input; + u32 val; + int ret; + + ret = of_property_read_u32(child, "reg", &val); + if (ret) { + dev_err(dev, "missing reg property of %s\n", child->name); + return ret; + } else if (val > INA3221_CHANNEL3) { + dev_err(dev, "invalid reg %d of %s\n", val, child->name); + return ret; + } + + input = &ina->inputs[val]; + + /* Log the disconnected channel input */ + if (!of_device_is_available(child)) { + input->disconnected = true; + return 0; + } + + /* Save the connected input label if available */ + of_property_read_string(child, "label", &input->label); + + /* Overwrite default shunt resistor value optionally */ + if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) { + if (val < 1 || val > INT_MAX) { + dev_err(dev, "invalid shunt resistor value %u of %s\n", + val, child->name); + return -EINVAL; + } + input->shunt_resistor = val; + } + + return 0; +} + +static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) +{ + const struct device_node *np = dev->of_node; + struct device_node *child; + int ret; + + /* Compatible with non-DT platforms */ + if (!np) + return 0; + + for_each_child_of_node(np, child) { + ret = ina3221_probe_child_from_dt(dev, child, ina); + if (ret) + return ret; + } + + return 0; +} + static int ina3221_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -399,7 +548,13 @@ static int ina3221_probe(struct i2c_client *client, } for (i = 0; i < INA3221_NUM_CHANNELS; i++) - ina->shunt_resistors[i] = INA3221_RSHUNT_DEFAULT; + ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; + + ret = ina3221_probe_from_dt(dev, ina); + if (ret) { + dev_err(dev, "Unable to probe from device tree\n"); + return ret; + } ret = regmap_field_write(ina->fields[F_RST], true); if (ret) { @@ -407,9 +562,25 @@ static int ina3221_probe(struct i2c_client *client, return ret; } - hwmon_dev = devm_hwmon_device_register_with_groups(dev, - client->name, - ina, ina3221_groups); + /* Sync config register after reset */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); + if (ret) + return ret; + + /* Disable channels if their inputs are disconnected */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (ina->inputs[i].disconnected) + ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); + } + ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); + if (ret) + return ret; + + dev_set_drvdata(dev, ina); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, + &ina3221_chip_info, + ina3221_groups); if (IS_ERR(hwmon_dev)) { dev_err(dev, "Unable to register hwmon device\n"); return PTR_ERR(hwmon_dev); @@ -418,6 +589,60 @@ static int ina3221_probe(struct i2c_client *client, return 0; } +static int __maybe_unused ina3221_suspend(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + /* Save config register value and enable cache-only */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); + if (ret) + return ret; + + /* Set to power-down mode for power saving */ + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, + INA3221_CONFIG_MODE_MASK, + INA3221_CONFIG_MODE_POWERDOWN); + if (ret) + return ret; + + regcache_cache_only(ina->regmap, true); + regcache_mark_dirty(ina->regmap); + + return 0; +} + +static int __maybe_unused ina3221_resume(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + regcache_cache_only(ina->regmap, false); + + /* Software reset the chip */ + ret = regmap_field_write(ina->fields[F_RST], true); + if (ret) { + dev_err(dev, "Unable to reset device\n"); + return ret; + } + + /* Restore cached register values to hardware */ + ret = regcache_sync(ina->regmap); + if (ret) + return ret; + + /* Restore config register value to hardware */ + ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); + if (ret) + return ret; + + return 0; +} + +static const struct dev_pm_ops ina3221_pm = { + SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume) +}; + static const struct of_device_id ina3221_of_match_table[] = { { .compatible = "ti,ina3221", }, { /* sentinel */ } @@ -435,6 +660,7 @@ static struct i2c_driver ina3221_i2c_driver = { .driver = { .name = INA3221_DRIVER_NAME, .of_match_table = ina3221_of_match_table, + .pm = &ina3221_pm, }, .id_table = ina3221_ids, }; diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index bb15d7816a29..2cef0c37ff6f 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -325,8 +325,9 @@ static int k10temp_probe(struct pci_dev *pdev, data->pdev = pdev; - if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 || - boot_cpu_data.x86_model == 0x70)) { + if (boot_cpu_data.x86 == 0x15 && + ((boot_cpu_data.x86_model & 0xf0) == 0x60 || + (boot_cpu_data.x86_model & 0xf0) == 0x70)) { data->read_htcreg = read_htcreg_nb_f15; data->read_tempreg = read_tempreg_nb_f15; } else if (boot_cpu_data.x86 == 0x17) { diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 49f4b33a5685..c7f20543b2bf 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -47,6 +47,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ lm75b, max6625, max6626, + max31725, mcp980x, stds75, tcn75, @@ -64,7 +65,6 @@ enum lm75_type { /* keep sorted in alphabetical order */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; - /* The LM75 registers */ #define LM75_REG_TEMP 0x00 #define LM75_REG_CONF 0x01 @@ -76,7 +76,7 @@ struct lm75_data { struct i2c_client *client; struct regmap *regmap; u8 orig_conf; - u8 resolution; /* In bits, between 9 and 12 */ + u8 resolution; /* In bits, between 9 and 16 */ u8 resolution_limits; unsigned int sample_time; /* In ms */ }; @@ -254,7 +254,8 @@ static const struct regmap_config lm75_regmap_config = { .volatile_reg = lm75_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static void lm75_remove(void *data) @@ -339,6 +340,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) data->resolution_limits = 9; data->sample_time = MSEC_PER_SEC / 4; break; + case max31725: + data->resolution = 16; + data->sample_time = MSEC_PER_SEC / 8; + break; case tcn75: data->resolution = 9; data->sample_time = MSEC_PER_SEC / 8; @@ -415,6 +420,8 @@ static const struct i2c_device_id lm75_ids[] = { { "lm75b", lm75b, }, { "max6625", max6625, }, { "max6626", max6626, }, + { "max31725", max31725, }, + { "max31726", max31725, }, { "mcp980x", mcp980x, }, { "stds75", stds75, }, { "tcn75", tcn75, }, @@ -472,6 +479,14 @@ static const struct of_device_id lm75_of_match[] = { .data = (void *)max6626 }, { + .compatible = "maxim,max31725", + .data = (void *)max31725 + }, + { + .compatible = "maxim,max31726", + .data = (void *)max31725 + }, + { .compatible = "maxim,mcp980x", .data = (void *)mcp980x }, diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index d40fe5122e94..e7333f8e185c 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -127,8 +127,8 @@ static struct lm92_data *lm92_update_device(struct device *dev) mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) - || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ) || + !data->valid) { dev_dbg(&client->dev, "Updating lm92 data\n"); for (i = 0; i < t_num_regs; i++) { data->temp[i] = @@ -153,7 +153,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, } static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm92_data *data = dev_get_drvdata(dev); @@ -161,7 +161,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, int nr = attr->index; long val; int err; - + err = kstrtol(buf, 10, &val); if (err) return err; @@ -178,6 +178,7 @@ static ssize_t show_temp_hyst(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]) - TEMP_FROM_REG(data->temp[t_hyst])); } @@ -186,6 +187,7 @@ static ssize_t temp1_min_hyst_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) + TEMP_FROM_REG(data->temp[t_hyst])); } @@ -206,7 +208,7 @@ static ssize_t set_temp_hyst(struct device *dev, val = clamp_val(val, -120000, 220000); mutex_lock(&data->update_lock); - data->temp[t_hyst] = + data->temp[t_hyst] = TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val); i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, data->temp[t_hyst]); @@ -218,6 +220,7 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input])); } @@ -324,7 +327,6 @@ static int lm92_probe(struct i2c_client *new_client, return PTR_ERR_OR_ZERO(hwmon_dev); } - /* * Module and driver stuff */ diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 27cb06d65594..996b50246175 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -541,7 +541,8 @@ static const struct regmap_config lm95245_regmap_config = { .writeable_reg = lm95245_is_writeable_reg, .volatile_reg = lm95245_is_volatile_reg, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const u32 lm95245_chip_config[] = { diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 78fe8759d2a9..825b922a3f92 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs. * * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2009 Sascha Hauer, Pengutronix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/mfd/mc13xxx.h> diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 78603b78cf41..c3040079b1cb 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -42,6 +42,10 @@ * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3 * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3 + * nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3 + * (0xd451) + * nct6798d 14 7 7 2+6 0xd458 0xc1 0x5ca3 + * (0xd459) * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -69,7 +73,7 @@ #define USE_ALTERNATE enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, - nct6795, nct6796 }; + nct6795, nct6796, nct6797, nct6798 }; /* used to set data->name = nct6775_device_names[data->sio_kind] */ static const char * const nct6775_device_names[] = { @@ -82,6 +86,8 @@ static const char * const nct6775_device_names[] = { "nct6793", "nct6795", "nct6796", + "nct6797", + "nct6798", }; static const char * const nct6775_sio_names[] __initconst = { @@ -94,6 +100,8 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6793D", "NCT6795D", "NCT6796D", + "NCT6797D", + "NCT6798D", }; static unsigned short force_id; @@ -129,7 +137,9 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6793_ID 0xd120 #define SIO_NCT6795_ID 0xd350 #define SIO_NCT6796_ID 0xd420 -#define SIO_ID_MASK 0xFFF0 +#define SIO_NCT6797_ID 0xd450 +#define SIO_NCT6798_ID 0xd458 +#define SIO_ID_MASK 0xFFF8 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; @@ -504,7 +514,7 @@ static const s8 NCT6779_BEEP_BITS[] = { static const u16 NCT6779_REG_FAN[] = { 0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce }; static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = { - 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 }; + 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f }; static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = { 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 }; @@ -704,10 +714,10 @@ static const char *const nct6795_temp_label[] = { "PCH_CHIP_TEMP", "PCH_CPU_TEMP", "PCH_MCH_TEMP", - "PCH_DIM0_TEMP", - "PCH_DIM1_TEMP", - "PCH_DIM2_TEMP", - "PCH_DIM3_TEMP", + "Agent0 Dimm0", + "Agent0 Dimm1", + "Agent1 Dimm0", + "Agent1 Dimm1", "BYTE_TEMP0", "BYTE_TEMP1", "PECI Agent 0 Calibration", @@ -742,10 +752,10 @@ static const char *const nct6796_temp_label[] = { "PCH_CHIP_TEMP", "PCH_CPU_TEMP", "PCH_MCH_TEMP", - "PCH_DIM0_TEMP", - "PCH_DIM1_TEMP", - "PCH_DIM2_TEMP", - "PCH_DIM3_TEMP", + "Agent0 Dimm0", + "Agent0 Dimm1", + "Agent1 Dimm0", + "Agent1 Dimm1", "BYTE_TEMP0", "BYTE_TEMP1", "PECI Agent 0 Calibration", @@ -757,6 +767,44 @@ static const char *const nct6796_temp_label[] = { #define NCT6796_TEMP_MASK 0xbfff0ffe #define NCT6796_VIRT_TEMP_MASK 0x80000c00 +static const char *const nct6798_temp_label[] = { + "", + "SYSTIN", + "CPUTIN", + "AUXTIN0", + "AUXTIN1", + "AUXTIN2", + "AUXTIN3", + "AUXTIN4", + "SMBUSMASTER 0", + "SMBUSMASTER 1", + "Virtual_TEMP", + "Virtual_TEMP", + "", + "", + "", + "", + "PECI Agent 0", + "PECI Agent 1", + "PCH_CHIP_CPU_MAX_TEMP", + "PCH_CHIP_TEMP", + "PCH_CPU_TEMP", + "PCH_MCH_TEMP", + "Agent0 Dimm0", + "Agent0 Dimm1", + "Agent1 Dimm0", + "Agent1 Dimm1", + "BYTE_TEMP0", + "BYTE_TEMP1", + "", + "", + "", + "Virtual_TEMP" +}; + +#define NCT6798_TEMP_MASK 0x8fff0ffe +#define NCT6798_VIRT_TEMP_MASK 0x80000c00 + /* NCT6102D/NCT6106D specific data */ #define NCT6106_REG_VBAT 0x318 @@ -1288,6 +1336,8 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) case nct6793: case nct6795: case nct6796: + case nct6797: + case nct6798: return reg == 0x150 || reg == 0x153 || reg == 0x155 || (reg & 0xfff0) == 0x4c0 || reg == 0x402 || @@ -1643,6 +1693,8 @@ static void nct6775_update_pwm_limits(struct device *dev) case nct6793: case nct6795: case nct6796: + case nct6797: + case nct6798: reg = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i]); if (reg & data->CRITICAL_PWM_ENABLE_MASK) @@ -2847,6 +2899,8 @@ store_temp_tolerance(struct device *dev, struct device_attribute *attr, * Fan speed tolerance is a tricky beast, since the associated register is * a tick counter, but the value is reported and configured as rpm. * Compute resulting low and high rpm values and report the difference. + * A fan speed tolerance only makes sense if a fan target speed has been + * configured, so only display values other than 0 if that is the case. */ static ssize_t show_speed_tolerance(struct device *dev, struct device_attribute *attr, @@ -2855,19 +2909,23 @@ show_speed_tolerance(struct device *dev, struct device_attribute *attr, struct nct6775_data *data = nct6775_update_device(dev); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); int nr = sattr->index; - int low = data->target_speed[nr] - data->target_speed_tolerance[nr]; - int high = data->target_speed[nr] + data->target_speed_tolerance[nr]; - int tolerance; - - if (low <= 0) - low = 1; - if (high > 0xffff) - high = 0xffff; - if (high < low) - high = low; - - tolerance = (fan_from_reg16(low, data->fan_div[nr]) - - fan_from_reg16(high, data->fan_div[nr])) / 2; + int target = data->target_speed[nr]; + int tolerance = 0; + + if (target) { + int low = target - data->target_speed_tolerance[nr]; + int high = target + data->target_speed_tolerance[nr]; + + if (low <= 0) + low = 1; + if (high > 0xffff) + high = 0xffff; + if (high < low) + high = low; + + tolerance = (fan_from_reg16(low, data->fan_div[nr]) + - fan_from_reg16(high, data->fan_div[nr])) / 2; + } return sprintf(buf, "%d\n", tolerance); } @@ -3071,6 +3129,8 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6793: case nct6795: case nct6796: + case nct6797: + case nct6798: nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); reg = nct6775_read_value(data, @@ -3430,7 +3490,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data) bool pwm3pin = false, pwm4pin = false, pwm5pin = false; bool pwm6pin = false, pwm7pin = false; int sioreg = data->sioreg; - int regval; /* Store SIO_REG_ENABLE for use during resume */ superio_select(sioreg, NCT6775_LD_HWM); @@ -3438,10 +3497,10 @@ nct6775_check_fan_inputs(struct nct6775_data *data) /* fan4 and fan5 share some pins with the GPIO and serial flash */ if (data->kind == nct6775) { - regval = superio_inb(sioreg, 0x2c); + int cr2c = superio_inb(sioreg, 0x2c); - fan3pin = regval & BIT(6); - pwm3pin = regval & BIT(7); + fan3pin = cr2c & BIT(6); + pwm3pin = cr2c & BIT(7); /* On NCT6775, fan4 shares pins with the fdc interface */ fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80); @@ -3486,85 +3545,130 @@ nct6775_check_fan_inputs(struct nct6775_data *data) fan4min = fan4pin; pwm3pin = fan3pin; } else if (data->kind == nct6106) { - regval = superio_inb(sioreg, 0x24); - fan3pin = !(regval & 0x80); - pwm3pin = regval & 0x08; - } else { - /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */ - int regval_1b, regval_2a, regval_2f; - bool dsw_en; - - regval = superio_inb(sioreg, 0x1c); + int cr24 = superio_inb(sioreg, 0x24); - fan3pin = !(regval & BIT(5)); - fan4pin = !(regval & BIT(6)); - fan5pin = !(regval & BIT(7)); - - pwm3pin = !(regval & BIT(0)); - pwm4pin = !(regval & BIT(1)); - pwm5pin = !(regval & BIT(2)); + fan3pin = !(cr24 & 0x80); + pwm3pin = cr24 & 0x08; + } else { + /* + * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, + * NCT6797D, NCT6798D + */ + int cr1a = superio_inb(sioreg, 0x1a); + int cr1b = superio_inb(sioreg, 0x1b); + int cr1c = superio_inb(sioreg, 0x1c); + int cr1d = superio_inb(sioreg, 0x1d); + int cr2a = superio_inb(sioreg, 0x2a); + int cr2b = superio_inb(sioreg, 0x2b); + int cr2d = superio_inb(sioreg, 0x2d); + int cr2f = superio_inb(sioreg, 0x2f); + bool dsw_en = cr2f & BIT(3); + bool ddr4_en = cr2f & BIT(4); + int cre0; + int creb; + int cred; + + superio_select(sioreg, NCT6775_LD_12); + cre0 = superio_inb(sioreg, 0xe0); + creb = superio_inb(sioreg, 0xeb); + cred = superio_inb(sioreg, 0xed); + + fan3pin = !(cr1c & BIT(5)); + fan4pin = !(cr1c & BIT(6)); + fan5pin = !(cr1c & BIT(7)); + + pwm3pin = !(cr1c & BIT(0)); + pwm4pin = !(cr1c & BIT(1)); + pwm5pin = !(cr1c & BIT(2)); - regval = superio_inb(sioreg, 0x2d); switch (data->kind) { case nct6791: + fan6pin = cr2d & BIT(1); + pwm6pin = cr2d & BIT(0); + break; case nct6792: - fan6pin = regval & BIT(1); - pwm6pin = regval & BIT(0); + fan6pin = !dsw_en && (cr2d & BIT(1)); + pwm6pin = !dsw_en && (cr2d & BIT(0)); break; case nct6793: + fan5pin |= cr1b & BIT(5); + fan5pin |= creb & BIT(5); + + fan6pin = creb & BIT(3); + + pwm5pin |= cr2d & BIT(7); + pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + + pwm6pin = !dsw_en && (cr2d & BIT(0)); + pwm6pin |= creb & BIT(2); + break; case nct6795: + fan5pin |= cr1b & BIT(5); + fan5pin |= creb & BIT(5); + + fan6pin = (cr2a & BIT(4)) && + (!dsw_en || (cred & BIT(4))); + fan6pin |= creb & BIT(3); + + pwm5pin |= cr2d & BIT(7); + pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + + pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2)); + pwm6pin |= creb & BIT(2); + break; case nct6796: - regval_1b = superio_inb(sioreg, 0x1b); - regval_2a = superio_inb(sioreg, 0x2a); - regval_2f = superio_inb(sioreg, 0x2f); - dsw_en = regval_2f & BIT(3); + fan5pin |= cr1b & BIT(5); + fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0)); + fan5pin |= creb & BIT(5); - if (!pwm5pin) - pwm5pin = regval & BIT(7); + fan6pin = (cr2a & BIT(4)) && + (!dsw_en || (cred & BIT(4))); + fan6pin |= creb & BIT(3); - if (!fan5pin) - fan5pin = regval_1b & BIT(5); + fan7pin = !(cr2b & BIT(2)); - superio_select(sioreg, NCT6775_LD_12); - if (data->kind != nct6796) { - int regval_eb = superio_inb(sioreg, 0xeb); + pwm5pin |= cr2d & BIT(7); + pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0)); + pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); - if (!dsw_en) { - fan6pin = regval & BIT(1); - pwm6pin = regval & BIT(0); - } + pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2)); + pwm6pin |= creb & BIT(2); - if (!fan5pin) - fan5pin = regval_eb & BIT(5); - if (!pwm5pin) - pwm5pin = (regval_eb & BIT(4)) && - !(regval_2a & BIT(0)); - if (!fan6pin) - fan6pin = regval_eb & BIT(3); - if (!pwm6pin) - pwm6pin = regval_eb & BIT(2); - } + pwm7pin = !(cr1d & (BIT(2) | BIT(3))); + break; + case nct6797: + fan5pin |= !ddr4_en && (cr1b & BIT(5)); + fan5pin |= creb & BIT(5); - if (data->kind == nct6795 || data->kind == nct6796) { - int regval_ed = superio_inb(sioreg, 0xed); + fan6pin = cr2a & BIT(4); + fan6pin |= creb & BIT(3); - if (!fan6pin) - fan6pin = (regval_2a & BIT(4)) && - (!dsw_en || - (dsw_en && (regval_ed & BIT(4)))); - if (!pwm6pin) - pwm6pin = (regval_2a & BIT(3)) && - (regval_ed & BIT(2)); - } + fan7pin = cr1a & BIT(1); - if (data->kind == nct6796) { - int regval_1d = superio_inb(sioreg, 0x1d); - int regval_2b = superio_inb(sioreg, 0x2b); + pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + pwm5pin |= !ddr4_en && (cr2d & BIT(7)); - fan7pin = !(regval_2b & BIT(2)); - pwm7pin = !(regval_1d & (BIT(2) | BIT(3))); - } + pwm6pin = creb & BIT(2); + pwm6pin |= cred & BIT(2); + pwm7pin = cr1d & BIT(4); + break; + case nct6798: + fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3)); + fan6pin |= cr2a & BIT(4); + fan6pin |= creb & BIT(5); + + fan7pin = cr1b & BIT(5); + fan7pin |= !(cr2b & BIT(2)); + fan7pin |= creb & BIT(3); + + pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4)); + pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3)); + pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + + pwm7pin = !(cr1d & (BIT(2) | BIT(3))); + pwm7pin |= cr2d & BIT(7); + pwm7pin |= creb & BIT(2); break; default: /* NCT6779D */ break; @@ -3943,8 +4047,12 @@ static int nct6775_probe(struct platform_device *pdev) case nct6793: case nct6795: case nct6796: + case nct6797: + case nct6798: data->in_num = 15; - data->pwm_num = (data->kind == nct6796) ? 7 : 6; + data->pwm_num = (data->kind == nct6796 || + data->kind == nct6797 || + data->kind == nct6798) ? 7 : 6; data->auto_pwm_num = 4; data->has_fan_div = false; data->temp_fixed_num = 6; @@ -3978,6 +4086,7 @@ static int nct6775_probe(struct platform_device *pdev) data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK; break; case nct6795: + case nct6797: data->temp_label = nct6795_temp_label; data->temp_mask = NCT6795_TEMP_MASK; data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK; @@ -3987,6 +4096,11 @@ static int nct6775_probe(struct platform_device *pdev) data->temp_mask = NCT6796_TEMP_MASK; data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK; break; + case nct6798: + data->temp_label = nct6798_temp_label; + data->temp_mask = NCT6798_TEMP_MASK; + data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK; + break; } data->REG_CONFIG = NCT6775_REG_CONFIG; @@ -4256,6 +4370,8 @@ static int nct6775_probe(struct platform_device *pdev) case nct6793: case nct6795: case nct6796: + case nct6797: + case nct6798: break; } @@ -4291,6 +4407,8 @@ static int nct6775_probe(struct platform_device *pdev) case nct6793: case nct6795: case nct6796: + case nct6797: + case nct6798: tmp |= 0x7e; break; } @@ -4493,6 +4611,12 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) case SIO_NCT6796_ID: sio_data->kind = nct6796; break; + case SIO_NCT6797_ID: + sio_data->kind = nct6797; + break; + case SIO_NCT6798_ID: + sio_data->kind = nct6798; + break; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c index b998f9fbed41..b3b907bdfb63 100644 --- a/drivers/hwmon/npcm750-pwm-fan.c +++ b/drivers/hwmon/npcm750-pwm-fan.c @@ -52,7 +52,7 @@ /* Define the Counter Register, value = 100 for match 100% */ #define NPCM7XX_PWM_COUNTER_DEFAULT_NUM 255 -#define NPCM7XX_PWM_CMR_DEFAULT_NUM 127 +#define NPCM7XX_PWM_CMR_DEFAULT_NUM 255 #define NPCM7XX_PWM_CMR_MAX 255 /* default all PWM channels PRESCALE2 = 1 */ @@ -861,7 +861,7 @@ static int npcm7xx_create_pwm_cooling(struct device *dev, dev_err(dev, "Property 'cooling-levels' cannot be read.\n"); return ret; } - snprintf(cdev->name, THERMAL_NAME_LENGTH, "%s%d", child->name, + snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child, pwm_port); cdev->tcdev = thermal_of_cooling_device_register(child, diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index a82018aaf473..629cb45f8557 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -5,7 +5,6 @@ menuconfig PMBUS tristate "PMBus support" depends on I2C - default n help Say yes here if you want to enable PMBus support. @@ -28,7 +27,6 @@ config SENSORS_PMBUS config SENSORS_ADM1275 tristate "Analog Devices ADM1275 and compatibles" - default n help If you say yes here you get hardware monitoring support for Analog Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293, @@ -49,7 +47,6 @@ config SENSORS_IBM_CFFPS config SENSORS_IR35221 tristate "Infineon IR35221" - default n help If you say yes here you get hardware monitoring support for the Infineon IR35221 controller. @@ -59,7 +56,6 @@ config SENSORS_IR35221 config SENSORS_LM25066 tristate "National Semiconductor LM25066 and compatibles" - default n help If you say yes here you get hardware monitoring support for National Semiconductor LM25056, LM25066, LM5064, and LM5066. @@ -69,7 +65,6 @@ config SENSORS_LM25066 config SENSORS_LTC2978 tristate "Linear Technologies LTC2978 and compatibles" - default n help If you say yes here you get hardware monitoring support for Linear Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, @@ -83,11 +78,11 @@ config SENSORS_LTC2978_REGULATOR depends on SENSORS_LTC2978 && REGULATOR help If you say yes here you get regulator support for Linear - Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676. + Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTM4676 + and LTM4686. config SENSORS_LTC3815 tristate "Linear Technologies LTC3815" - default n help If you say yes here you get hardware monitoring support for Linear Technology LTC3815. @@ -97,7 +92,6 @@ config SENSORS_LTC3815 config SENSORS_MAX16064 tristate "Maxim MAX16064" - default n help If you say yes here you get hardware monitoring support for Maxim MAX16064. @@ -107,7 +101,6 @@ config SENSORS_MAX16064 config SENSORS_MAX20751 tristate "Maxim MAX20751" - default n help If you say yes here you get hardware monitoring support for Maxim MAX20751. @@ -117,7 +110,6 @@ config SENSORS_MAX20751 config SENSORS_MAX31785 tristate "Maxim MAX31785 and compatibles" - default n help If you say yes here you get hardware monitoring support for Maxim MAX31785. @@ -127,7 +119,6 @@ config SENSORS_MAX31785 config SENSORS_MAX34440 tristate "Maxim MAX34440 and compatibles" - default n help If you say yes here you get hardware monitoring support for Maxim MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461. @@ -137,7 +128,6 @@ config SENSORS_MAX34440 config SENSORS_MAX8688 tristate "Maxim MAX8688" - default n help If you say yes here you get hardware monitoring support for Maxim MAX8688. @@ -147,7 +137,6 @@ config SENSORS_MAX8688 config SENSORS_TPS40422 tristate "TI TPS40422" - default n help If you say yes here you get hardware monitoring support for TI TPS40422. @@ -166,7 +155,6 @@ config SENSORS_TPS53679 config SENSORS_UCD9000 tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910" - default n help If you say yes here you get hardware monitoring support for TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System @@ -177,7 +165,6 @@ config SENSORS_UCD9000 config SENSORS_UCD9200 tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248" - default n help If you say yes here you get hardware monitoring support for TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248 @@ -188,7 +175,6 @@ config SENSORS_UCD9200 config SENSORS_ZL6100 tristate "Intersil ZL6100 and compatibles" - default n help If you say yes here you get hardware monitoring support for Intersil ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105, diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 58b789c28b48..07afb92bb36b 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -4,6 +4,7 @@ * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2013, 2014, 2015 Guenter Roeck * Copyright (c) 2015 Linear Technology + * Copyright (c) 2018 Analog Devices Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +29,7 @@ #include "pmbus.h" enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, - ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676 }; + ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676, ltm4686 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -81,6 +82,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTM4676_ID_REV1 0x4400 #define LTM4676_ID_REV2 0x4480 #define LTM4676A_ID 0x47e0 +#define LTM4686_ID 0x4770 #define LTC2974_NUM_PAGES 4 #define LTC2978_NUM_PAGES 8 @@ -512,6 +514,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltm2987", ltm2987}, {"ltm4675", ltm4675}, {"ltm4676", ltm4676}, + {"ltm4686", ltm4686}, {} }; MODULE_DEVICE_TABLE(i2c, ltc2978_id); @@ -588,6 +591,8 @@ static int ltc2978_get_id(struct i2c_client *client) else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 || chip_id == LTM4676A_ID) return ltm4676; + else if (chip_id == LTM4686_ID) + return ltm4686; dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); return -ENODEV; @@ -684,6 +689,7 @@ static int ltc2978_probe(struct i2c_client *client, case ltc3887: case ltm4675: case ltm4676: + case ltm4686: data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; @@ -770,6 +776,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4675" }, { .compatible = "lltc,ltm4676" }, + { .compatible = "lltc,ltm4686" }, { } }; MODULE_DEVICE_TABLE(of, ltc2978_of_match); diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 7718e58dbda5..7688dab32f6e 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -118,6 +118,8 @@ static int pmbus_identify(struct i2c_client *client, } else { info->pages = 1; } + + pmbus_clear_faults(client); } if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 82c3754e21e3..2e2b5851139c 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2015,7 +2015,10 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) client->flags |= I2C_CLIENT_PEC; - pmbus_clear_faults(client); + if (data->info->pages) + pmbus_clear_faults(client); + else + pmbus_clear_fault_page(client, -1); if (info->identify) { ret = (*info->identify)(client, info); diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 7838af58f92d..7da6a160d45a 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -221,8 +221,12 @@ static int pwm_fan_probe(struct platform_device *pdev) ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL); if (IS_ERR(ctx->pwm)) { - dev_err(&pdev->dev, "Could not get PWM\n"); - return PTR_ERR(ctx->pwm); + ret = PTR_ERR(ctx->pwm); + + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get PWM: %d\n", ret); + + return ret; } platform_set_drvdata(pdev, ctx); @@ -290,9 +294,19 @@ static int pwm_fan_remove(struct platform_device *pdev) static int pwm_fan_suspend(struct device *dev) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + struct pwm_args args; + int ret; + + pwm_get_args(ctx->pwm, &args); + + if (ctx->pwm_value) { + ret = pwm_config(ctx->pwm, 0, args.period); + if (ret < 0) + return ret; - if (ctx->pwm_value) pwm_disable(ctx->pwm); + } + return 0; } diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c index 91976b6ca300..2e005edee0c9 100644 --- a/drivers/hwmon/scmi-hwmon.c +++ b/drivers/hwmon/scmi-hwmon.c @@ -56,7 +56,7 @@ scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, const struct scmi_sensors *scmi_sensors = drvdata; sensor = *(scmi_sensors->info[type] + channel); - if (sensor && sensor->name) + if (sensor) return S_IRUGO; return 0; diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c index 7e49da50bc69..111d521e2189 100644 --- a/drivers/hwmon/scpi-hwmon.c +++ b/drivers/hwmon/scpi-hwmon.c @@ -286,10 +286,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev) * any thermal zones or if the thermal subsystem is * not configured. */ - if (IS_ERR(z)) { + if (IS_ERR(z)) devm_kfree(dev, zone); - continue; - } } return 0; diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 2be77752cd56..c878242f3486 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * sht15.c - support for the SHT15 Temperature and Humidity Sensor * @@ -9,10 +10,6 @@ * * Copyright (c) 2007 Wouter Horre * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * For further information, see the Documentation/hwmon/sht15 file. */ diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index dfc40c740d07..6778283e36f9 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -212,7 +212,8 @@ static const struct regmap_config tmp102_regmap_config = { .volatile_reg = tmp102_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static int tmp102_probe(struct i2c_client *client, diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 91bb94639286..429bfeae4ca8 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -345,7 +345,8 @@ static const struct regmap_config tmp108_regmap_config = { .volatile_reg = tmp108_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static int tmp108_probe(struct i2c_client *client, diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index e36399213324..8844c9565d2a 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -226,8 +226,10 @@ static int tmp421_detect(struct i2c_client *client, { enum chips kind; struct i2c_adapter *adapter = client->adapter; - const char * const names[] = { "TMP421", "TMP422", "TMP423", - "TMP441", "TMP442" }; + static const char * const names[] = { + "TMP421", "TMP422", "TMP423", + "TMP441", "TMP442" + }; int addr = client->addr; u8 reg; diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 52cf42b32f0a..4aa7dde876f3 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -806,8 +806,12 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE, num * adap->timeout); - if (!time_left) { + + /* cleanup DMA if it couldn't complete properly due to an error */ + if (priv->dma_direction != DMA_NONE) rcar_i2c_cleanup_dma(priv); + + if (!time_left) { rcar_i2c_init(priv); ret = -ETIMEDOUT; } else if (priv->flags & ID_NACK) { diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 401308e3d036..13882a2a4f60 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -22,18 +22,16 @@ struct gpiomux { struct i2c_mux_gpio_platform_data data; unsigned gpio_base; struct gpio_desc **gpios; - int *values; }; static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) { - int i; + DECLARE_BITMAP(values, BITS_PER_TYPE(val)); - for (i = 0; i < mux->data.n_gpios; i++) - mux->values[i] = (val >> i) & 1; + values[0] = val; - gpiod_set_array_value_cansleep(mux->data.n_gpios, - mux->gpios, mux->values); + gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL, + values); } static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan) @@ -182,15 +180,13 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) return -EPROBE_DEFER; muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, - mux->data.n_gpios * sizeof(*mux->gpios) + - mux->data.n_gpios * sizeof(*mux->values), 0, + mux->data.n_gpios * sizeof(*mux->gpios), 0, i2c_mux_gpio_select, NULL); if (!muxc) { ret = -ENOMEM; goto alloc_failed; } mux->gpios = muxc->priv; - mux->values = (int *)(mux->gpios + mux->data.n_gpios); muxc->priv = mux; platform_set_drvdata(pdev, muxc); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 44a7a255ef74..f9b59d41813f 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1784,7 +1784,7 @@ static int ide_cd_probe(ide_drive_t *drive) ide_cd_read_toc(drive); g->fops = &idecd_ops; g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; - device_add_disk(&drive->gendev, g); + device_add_disk(&drive->gendev, g, NULL); return 0; out_free_disk: diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index e823394ed543..04e008e8f6f9 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -416,7 +416,7 @@ static int ide_gd_probe(ide_drive_t *drive) if (drive->dev_flags & IDE_DFLAG_REMOVABLE) g->flags = GENHD_FL_REMOVABLE; g->fops = &ide_gd_ops; - device_add_disk(&drive->gendev, g); + device_add_disk(&drive->gendev, g, NULL); return 0; out_free_disk: diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index b2ccce5fb071..8b5d85c91e9d 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -1066,46 +1066,43 @@ static const struct idle_cpu idle_cpu_dnv = { .disable_promotion_to_c1e = true, }; -#define ICPU(model, cpu) \ - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&cpu } - static const struct x86_cpu_id intel_idle_ids[] __initconst = { - ICPU(INTEL_FAM6_NEHALEM_EP, idle_cpu_nehalem), - ICPU(INTEL_FAM6_NEHALEM, idle_cpu_nehalem), - ICPU(INTEL_FAM6_NEHALEM_G, idle_cpu_nehalem), - ICPU(INTEL_FAM6_WESTMERE, idle_cpu_nehalem), - ICPU(INTEL_FAM6_WESTMERE_EP, idle_cpu_nehalem), - ICPU(INTEL_FAM6_NEHALEM_EX, idle_cpu_nehalem), - ICPU(INTEL_FAM6_ATOM_PINEVIEW, idle_cpu_atom), - ICPU(INTEL_FAM6_ATOM_LINCROFT, idle_cpu_lincroft), - ICPU(INTEL_FAM6_WESTMERE_EX, idle_cpu_nehalem), - ICPU(INTEL_FAM6_SANDYBRIDGE, idle_cpu_snb), - ICPU(INTEL_FAM6_SANDYBRIDGE_X, idle_cpu_snb), - ICPU(INTEL_FAM6_ATOM_CEDARVIEW, idle_cpu_atom), - ICPU(INTEL_FAM6_ATOM_SILVERMONT1, idle_cpu_byt), - ICPU(INTEL_FAM6_ATOM_MERRIFIELD, idle_cpu_tangier), - ICPU(INTEL_FAM6_ATOM_AIRMONT, idle_cpu_cht), - ICPU(INTEL_FAM6_IVYBRIDGE, idle_cpu_ivb), - ICPU(INTEL_FAM6_IVYBRIDGE_X, idle_cpu_ivt), - ICPU(INTEL_FAM6_HASWELL_CORE, idle_cpu_hsw), - ICPU(INTEL_FAM6_HASWELL_X, idle_cpu_hsw), - ICPU(INTEL_FAM6_HASWELL_ULT, idle_cpu_hsw), - ICPU(INTEL_FAM6_HASWELL_GT3E, idle_cpu_hsw), - ICPU(INTEL_FAM6_ATOM_SILVERMONT2, idle_cpu_avn), - ICPU(INTEL_FAM6_BROADWELL_CORE, idle_cpu_bdw), - ICPU(INTEL_FAM6_BROADWELL_GT3E, idle_cpu_bdw), - ICPU(INTEL_FAM6_BROADWELL_X, idle_cpu_bdw), - ICPU(INTEL_FAM6_BROADWELL_XEON_D, idle_cpu_bdw), - ICPU(INTEL_FAM6_SKYLAKE_MOBILE, idle_cpu_skl), - ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, idle_cpu_skl), - ICPU(INTEL_FAM6_KABYLAKE_MOBILE, idle_cpu_skl), - ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, idle_cpu_skl), - ICPU(INTEL_FAM6_SKYLAKE_X, idle_cpu_skx), - ICPU(INTEL_FAM6_XEON_PHI_KNL, idle_cpu_knl), - ICPU(INTEL_FAM6_XEON_PHI_KNM, idle_cpu_knl), - ICPU(INTEL_FAM6_ATOM_GOLDMONT, idle_cpu_bxt), - ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, idle_cpu_bxt), - ICPU(INTEL_FAM6_ATOM_DENVERTON, idle_cpu_dnv), + INTEL_CPU_FAM6(NEHALEM_EP, idle_cpu_nehalem), + INTEL_CPU_FAM6(NEHALEM, idle_cpu_nehalem), + INTEL_CPU_FAM6(NEHALEM_G, idle_cpu_nehalem), + INTEL_CPU_FAM6(WESTMERE, idle_cpu_nehalem), + INTEL_CPU_FAM6(WESTMERE_EP, idle_cpu_nehalem), + INTEL_CPU_FAM6(NEHALEM_EX, idle_cpu_nehalem), + INTEL_CPU_FAM6(ATOM_BONNELL, idle_cpu_atom), + INTEL_CPU_FAM6(ATOM_BONNELL_MID, idle_cpu_lincroft), + INTEL_CPU_FAM6(WESTMERE_EX, idle_cpu_nehalem), + INTEL_CPU_FAM6(SANDYBRIDGE, idle_cpu_snb), + INTEL_CPU_FAM6(SANDYBRIDGE_X, idle_cpu_snb), + INTEL_CPU_FAM6(ATOM_SALTWELL, idle_cpu_atom), + INTEL_CPU_FAM6(ATOM_SILVERMONT, idle_cpu_byt), + INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, idle_cpu_tangier), + INTEL_CPU_FAM6(ATOM_AIRMONT, idle_cpu_cht), + INTEL_CPU_FAM6(IVYBRIDGE, idle_cpu_ivb), + INTEL_CPU_FAM6(IVYBRIDGE_X, idle_cpu_ivt), + INTEL_CPU_FAM6(HASWELL_CORE, idle_cpu_hsw), + INTEL_CPU_FAM6(HASWELL_X, idle_cpu_hsw), + INTEL_CPU_FAM6(HASWELL_ULT, idle_cpu_hsw), + INTEL_CPU_FAM6(HASWELL_GT3E, idle_cpu_hsw), + INTEL_CPU_FAM6(ATOM_SILVERMONT_X, idle_cpu_avn), + INTEL_CPU_FAM6(BROADWELL_CORE, idle_cpu_bdw), + INTEL_CPU_FAM6(BROADWELL_GT3E, idle_cpu_bdw), + INTEL_CPU_FAM6(BROADWELL_X, idle_cpu_bdw), + INTEL_CPU_FAM6(BROADWELL_XEON_D, idle_cpu_bdw), + INTEL_CPU_FAM6(SKYLAKE_MOBILE, idle_cpu_skl), + INTEL_CPU_FAM6(SKYLAKE_DESKTOP, idle_cpu_skl), + INTEL_CPU_FAM6(KABYLAKE_MOBILE, idle_cpu_skl), + INTEL_CPU_FAM6(KABYLAKE_DESKTOP, idle_cpu_skl), + INTEL_CPU_FAM6(SKYLAKE_X, idle_cpu_skx), + INTEL_CPU_FAM6(XEON_PHI_KNL, idle_cpu_knl), + INTEL_CPU_FAM6(XEON_PHI_KNM, idle_cpu_knl), + INTEL_CPU_FAM6(ATOM_GOLDMONT, idle_cpu_bxt), + INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, idle_cpu_bxt), + INTEL_CPU_FAM6(ATOM_GOLDMONT_X, idle_cpu_dnv), {} }; @@ -1322,7 +1319,7 @@ static void intel_idle_state_table_update(void) ivt_idle_state_table_update(); break; case INTEL_FAM6_ATOM_GOLDMONT: - case INTEL_FAM6_ATOM_GEMINI_LAKE: + case INTEL_FAM6_ATOM_GOLDMONT_PLUS: bxt_idle_state_table_update(); break; case INTEL_FAM6_SKYLAKE_DESKTOP: diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 1f112ae15f3c..b09b8b60bd83 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -206,7 +206,8 @@ static const struct regmap_config apds9960_regmap_config = { .name = APDS9960_REGMAP_NAME, .reg_bits = 8, .val_bits = 8, - .use_single_rw = 1, + .use_single_read = true, + .use_single_write = true, .volatile_table = &apds9960_volatile_table, .precious_table = &apds9960_precious_table, diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index bcdb0eb9e537..4067dff2ff6a 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -473,17 +473,18 @@ static bool max44000_precious_reg(struct device *dev, unsigned int reg) } static const struct regmap_config max44000_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = MAX44000_REG_PRX_DATA, - .readable_reg = max44000_readable_reg, - .writeable_reg = max44000_writeable_reg, - .volatile_reg = max44000_volatile_reg, - .precious_reg = max44000_precious_reg, - - .use_single_rw = 1, - .cache_type = REGCACHE_RBTREE, + .reg_bits = 8, + .val_bits = 8, + + .max_register = MAX44000_REG_PRX_DATA, + .readable_reg = max44000_readable_reg, + .writeable_reg = max44000_writeable_reg, + .volatile_reg = max44000_volatile_reg, + .precious_reg = max44000_precious_reg, + + .use_single_read = true, + .use_single_write = true, + .cache_type = REGCACHE_RBTREE, }; static irqreturn_t max44000_trigger_handler(int irq, void *p) diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 9851311aa3fd..be03be719efe 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -140,7 +140,8 @@ static const struct regmap_config mlx90632_regmap = { .rd_table = &mlx90632_readable_regs_tbl, .wr_table = &mlx90632_writeable_regs_tbl, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index f5ae24865355..b0f9d19b3410 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1346,6 +1346,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0611", 0 }, { "ELAN0612", 0 }, { "ELAN0618", 0 }, + { "ELAN061C", 0 }, { "ELAN061D", 0 }, { "ELAN0622", 0 }, { "ELAN1000", 0 }, diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index e0fde590df8e..62973ac01381 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -68,7 +68,8 @@ const struct regmap_config tsc200x_regmap_config = { .read_flag_mask = TSC200X_REG_READ, .write_flag_mask = TSC200X_REG_PND0, .wr_table = &tsc200x_writable_table, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; EXPORT_SYMBOL_GPL(tsc200x_regmap_config); diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 84b3e4445d46..3931c7de7c69 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -902,12 +902,22 @@ static bool copy_device_table(void) } } - old_devtb_phys = entry & PAGE_MASK; + /* + * When SME is enabled in the first kernel, the entry includes the + * memory encryption mask(sme_me_mask), we must remove the memory + * encryption mask to obtain the true physical address in kdump kernel. + */ + old_devtb_phys = __sme_clr(entry) & PAGE_MASK; + if (old_devtb_phys >= 0x100000000ULL) { pr_err("The address of old device table is above 4G, not trustworthy!\n"); return false; } - old_devtb = memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB); + old_devtb = (sme_active() && is_kdump_kernel()) + ? (__force void *)ioremap_encrypted(old_devtb_phys, + dev_table_size) + : memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB); + if (!old_devtb) return false; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index bedc801b06a0..76f0a5d16ed3 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3895,7 +3895,7 @@ static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr) return !dma_addr; } -const struct dma_map_ops intel_dma_ops = { +static const struct dma_map_ops intel_dma_ops = { .alloc = intel_alloc_coherent, .free = intel_free_coherent, .map_sg = intel_map_sg, @@ -3903,9 +3903,7 @@ const struct dma_map_ops intel_dma_ops = { .map_page = intel_map_page, .unmap_page = intel_unmap_page, .mapping_error = intel_mapping_error, -#ifdef CONFIG_X86 .dma_supported = dma_direct_supported, -#endif }; static inline int iommu_domain_cache_init(void) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 44097a3e0fcc..a72f97fca57b 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -58,6 +58,16 @@ config LEDS_AAT1290 help This option enables support for the LEDs on the AAT1290. +config LEDS_AN30259A + tristate "LED support for Panasonic AN30259A" + depends on LEDS_CLASS && I2C && OF + help + This option enables support for the AN30259A 3-channel + LED driver. + + To compile this driver as a module, choose M here: the module + will be called leds-an30259a. + config LEDS_APU tristate "Front panel LED support for PC Engines APU/APU2/APU3 boards" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 420b5d2cfa62..4c1b0054f379 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o obj-$(CONFIG_LEDS_APU) += leds-apu.o obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o +obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c new file mode 100644 index 000000000000..1c1f0c8c56f4 --- /dev/null +++ b/drivers/leds/leds-an30259a.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Driver for Panasonic AN30259A 3-channel LED driver +// +// Copyright (c) 2018 Simon Shields <simon@lineageos.org> +// +// Datasheet: +// https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf + +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <uapi/linux/uleds.h> + +#define AN30259A_MAX_LEDS 3 + +#define AN30259A_REG_SRESET 0x00 +#define AN30259A_LED_SRESET BIT(0) + +/* LED power registers */ +#define AN30259A_REG_LED_ON 0x01 +#define AN30259A_LED_EN(x) BIT((x) - 1) +#define AN30259A_LED_SLOPE(x) BIT(((x) - 1) + 4) + +#define AN30259A_REG_LEDCC(x) (0x03 + ((x) - 1)) + +/* slope control registers */ +#define AN30259A_REG_SLOPE(x) (0x06 + ((x) - 1)) +#define AN30259A_LED_SLOPETIME1(x) (x) +#define AN30259A_LED_SLOPETIME2(x) ((x) << 4) + +#define AN30259A_REG_LEDCNT1(x) (0x09 + (4 * ((x) - 1))) +#define AN30259A_LED_DUTYMAX(x) ((x) << 4) +#define AN30259A_LED_DUTYMID(x) (x) + +#define AN30259A_REG_LEDCNT2(x) (0x0A + (4 * ((x) - 1))) +#define AN30259A_LED_DELAY(x) ((x) << 4) +#define AN30259A_LED_DUTYMIN(x) (x) + +/* detention time control (length of each slope step) */ +#define AN30259A_REG_LEDCNT3(x) (0x0B + (4 * ((x) - 1))) +#define AN30259A_LED_DT1(x) (x) +#define AN30259A_LED_DT2(x) ((x) << 4) + +#define AN30259A_REG_LEDCNT4(x) (0x0C + (4 * ((x) - 1))) +#define AN30259A_LED_DT3(x) (x) +#define AN30259A_LED_DT4(x) ((x) << 4) + +#define AN30259A_REG_MAX 0x14 + +#define AN30259A_BLINK_MAX_TIME 7500 /* ms */ +#define AN30259A_SLOPE_RESOLUTION 500 /* ms */ + +#define STATE_OFF 0 +#define STATE_KEEP 1 +#define STATE_ON 2 + +struct an30259a; + +struct an30259a_led { + struct an30259a *chip; + struct led_classdev cdev; + u32 num; + u32 default_state; + bool sloping; + char label[LED_MAX_NAME_SIZE]; +}; + +struct an30259a { + struct mutex mutex; /* held when writing to registers */ + struct i2c_client *client; + struct an30259a_led leds[AN30259A_MAX_LEDS]; + struct regmap *regmap; + int num_leds; +}; + +static int an30259a_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct an30259a_led *led; + int ret; + unsigned int led_on; + + led = container_of(cdev, struct an30259a_led, cdev); + mutex_lock(&led->chip->mutex); + + ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on); + if (ret) + goto error; + + switch (brightness) { + case LED_OFF: + led_on &= ~AN30259A_LED_EN(led->num); + led_on &= ~AN30259A_LED_SLOPE(led->num); + led->sloping = false; + break; + default: + led_on |= AN30259A_LED_EN(led->num); + if (led->sloping) + led_on |= AN30259A_LED_SLOPE(led->num); + ret = regmap_write(led->chip->regmap, + AN30259A_REG_LEDCNT1(led->num), + AN30259A_LED_DUTYMAX(0xf) | + AN30259A_LED_DUTYMID(0xf)); + if (ret) + goto error; + break; + } + + ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on); + if (ret) + goto error; + + ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCC(led->num), + brightness); + +error: + mutex_unlock(&led->chip->mutex); + + return ret; +} + +static int an30259a_blink_set(struct led_classdev *cdev, + unsigned long *delay_off, unsigned long *delay_on) +{ + struct an30259a_led *led; + int ret, num; + unsigned int led_on; + unsigned long off = *delay_off, on = *delay_on; + + led = container_of(cdev, struct an30259a_led, cdev); + + mutex_lock(&led->chip->mutex); + num = led->num; + + /* slope time can only be a multiple of 500ms. */ + if (off % AN30259A_SLOPE_RESOLUTION || on % AN30259A_SLOPE_RESOLUTION) { + ret = -EINVAL; + goto error; + } + + /* up to a maximum of 7500ms. */ + if (off > AN30259A_BLINK_MAX_TIME || on > AN30259A_BLINK_MAX_TIME) { + ret = -EINVAL; + goto error; + } + + /* if no blink specified, default to 1 Hz. */ + if (!off && !on) { + *delay_off = off = 500; + *delay_on = on = 500; + } + + /* convert into values the HW will understand. */ + off /= AN30259A_SLOPE_RESOLUTION; + on /= AN30259A_SLOPE_RESOLUTION; + + /* duty min should be zero (=off), delay should be zero. */ + ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT2(num), + AN30259A_LED_DELAY(0) | AN30259A_LED_DUTYMIN(0)); + if (ret) + goto error; + + /* reset detention time (no "breathing" effect). */ + ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT3(num), + AN30259A_LED_DT1(0) | AN30259A_LED_DT2(0)); + if (ret) + goto error; + ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT4(num), + AN30259A_LED_DT3(0) | AN30259A_LED_DT4(0)); + if (ret) + goto error; + + /* slope time controls on/off cycle length. */ + ret = regmap_write(led->chip->regmap, AN30259A_REG_SLOPE(num), + AN30259A_LED_SLOPETIME1(off) | + AN30259A_LED_SLOPETIME2(on)); + if (ret) + goto error; + + /* Finally, enable slope mode. */ + ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on); + if (ret) + goto error; + + led_on |= AN30259A_LED_SLOPE(num) | AN30259A_LED_EN(led->num); + + ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on); + + if (!ret) + led->sloping = true; +error: + mutex_unlock(&led->chip->mutex); + + return ret; +} + +static int an30259a_dt_init(struct i2c_client *client, + struct an30259a *chip) +{ + struct device_node *np = client->dev.of_node, *child; + int count, ret; + int i = 0; + const char *str; + struct an30259a_led *led; + + count = of_get_child_count(np); + if (!count || count > AN30259A_MAX_LEDS) + return -EINVAL; + + for_each_available_child_of_node(np, child) { + u32 source; + + ret = of_property_read_u32(child, "reg", &source); + if (ret != 0 || !source || source > AN30259A_MAX_LEDS) { + dev_err(&client->dev, "Couldn't read LED address: %d\n", + ret); + count--; + continue; + } + + led = &chip->leds[i]; + + led->num = source; + led->chip = chip; + + if (of_property_read_string(child, "label", &str)) + snprintf(led->label, sizeof(led->label), "an30259a::"); + else + snprintf(led->label, sizeof(led->label), "an30259a:%s", + str); + + led->cdev.name = led->label; + + if (!of_property_read_string(child, "default-state", &str)) { + if (!strcmp(str, "on")) + led->default_state = STATE_ON; + else if (!strcmp(str, "keep")) + led->default_state = STATE_KEEP; + else + led->default_state = STATE_OFF; + } + + of_property_read_string(child, "linux,default-trigger", + &led->cdev.default_trigger); + + i++; + } + + if (!count) + return -EINVAL; + + chip->num_leds = i; + + return 0; +} + +static const struct regmap_config an30259a_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AN30259A_REG_MAX, +}; + +static void an30259a_init_default_state(struct an30259a_led *led) +{ + struct an30259a *chip = led->chip; + int led_on, err; + + switch (led->default_state) { + case STATE_ON: + led->cdev.brightness = LED_FULL; + break; + case STATE_KEEP: + err = regmap_read(chip->regmap, AN30259A_REG_LED_ON, &led_on); + if (err) + break; + + if (!(led_on & AN30259A_LED_EN(led->num))) { + led->cdev.brightness = LED_OFF; + break; + } + regmap_read(chip->regmap, AN30259A_REG_LEDCC(led->num), + &led->cdev.brightness); + break; + default: + led->cdev.brightness = LED_OFF; + } + + an30259a_brightness_set(&led->cdev, led->cdev.brightness); +} + +static int an30259a_probe(struct i2c_client *client) +{ + struct an30259a *chip; + int i, err; + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + err = an30259a_dt_init(client, chip); + if (err < 0) + return err; + + mutex_init(&chip->mutex); + chip->client = client; + i2c_set_clientdata(client, chip); + + chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config); + + for (i = 0; i < chip->num_leds; i++) { + an30259a_init_default_state(&chip->leds[i]); + chip->leds[i].cdev.brightness_set_blocking = + an30259a_brightness_set; + chip->leds[i].cdev.blink_set = an30259a_blink_set; + + err = devm_led_classdev_register(&client->dev, + &chip->leds[i].cdev); + if (err < 0) + goto exit; + } + return 0; + +exit: + mutex_destroy(&chip->mutex); + return err; +} + +static int an30259a_remove(struct i2c_client *client) +{ + struct an30259a *chip = i2c_get_clientdata(client); + + mutex_destroy(&chip->mutex); + + return 0; +} + +static const struct of_device_id an30259a_match_table[] = { + { .compatible = "panasonic,an30259a", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, an30259a_match_table); + +static const struct i2c_device_id an30259a_id[] = { + { "an30259a", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i2c, an30259a_id); + +static struct i2c_driver an30259a_driver = { + .driver = { + .name = "leds-an32059a", + .of_match_table = of_match_ptr(an30259a_match_table), + }, + .probe_new = an30259a_probe, + .remove = an30259a_remove, + .id_table = an30259a_id, +}; + +module_i2c_driver(an30259a_driver); + +MODULE_AUTHOR("Simon Shields <simon@lineageos.org>"); +MODULE_DESCRIPTION("AN32059A LED driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c index f883616d9e60..98a69b1a43f9 100644 --- a/drivers/leds/leds-as3645a.c +++ b/drivers/leds/leds-as3645a.c @@ -529,7 +529,7 @@ static int as3645a_parse_node(struct as3645a *flash, strlcpy(names->flash, name, sizeof(names->flash)); else snprintf(names->flash, sizeof(names->flash), - "%s:flash", node->name); + "%pOFn:flash", node); rval = of_property_read_u32(flash->flash_node, "flash-timeout-us", &cfg->flash_timeout_us); @@ -573,7 +573,7 @@ static int as3645a_parse_node(struct as3645a *flash, strlcpy(names->indicator, name, sizeof(names->indicator)); else snprintf(names->indicator, sizeof(names->indicator), - "%s:indicator", node->name); + "%pOFn:indicator", node); rval = of_property_read_u32(flash->indicator_node, "led-max-microamp", &cfg->indicator_max_ua); diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 764c31301f90..32fa752565bc 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -81,35 +81,6 @@ static int create_gpio_led(const struct gpio_led *template, { int ret, state; - led_dat->gpiod = template->gpiod; - if (!led_dat->gpiod) { - /* - * This is the legacy code path for platform code that - * still uses GPIO numbers. Ultimately we would like to get - * rid of this block completely. - */ - unsigned long flags = GPIOF_OUT_INIT_LOW; - - /* skip leds that aren't available */ - if (!gpio_is_valid(template->gpio)) { - dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n", - template->gpio, template->name); - return 0; - } - - if (template->active_low) - flags |= GPIOF_ACTIVE_LOW; - - ret = devm_gpio_request_one(parent, template->gpio, flags, - template->name); - if (ret < 0) - return ret; - - led_dat->gpiod = gpio_to_desc(template->gpio); - if (!led_dat->gpiod) - return -EINVAL; - } - led_dat->cdev.name = template->name; led_dat->cdev.default_trigger = template->default_trigger; led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod); @@ -231,6 +202,52 @@ static const struct of_device_id of_gpio_leds_match[] = { MODULE_DEVICE_TABLE(of, of_gpio_leds_match); +static struct gpio_desc *gpio_led_get_gpiod(struct device *dev, int idx, + const struct gpio_led *template) +{ + struct gpio_desc *gpiod; + unsigned long flags = GPIOF_OUT_INIT_LOW; + int ret; + + /* + * This means the LED does not come from the device tree + * or ACPI, so let's try just getting it by index from the + * device, this will hit the board file, if any and get + * the GPIO from there. + */ + gpiod = devm_gpiod_get_index(dev, NULL, idx, flags); + if (!IS_ERR(gpiod)) { + gpiod_set_consumer_name(gpiod, template->name); + return gpiod; + } + if (PTR_ERR(gpiod) != -ENOENT) + return gpiod; + + /* + * This is the legacy code path for platform code that + * still uses GPIO numbers. Ultimately we would like to get + * rid of this block completely. + */ + + /* skip leds that aren't available */ + if (!gpio_is_valid(template->gpio)) + return ERR_PTR(-ENOENT); + + if (template->active_low) + flags |= GPIOF_ACTIVE_LOW; + + ret = devm_gpio_request_one(dev, template->gpio, flags, + template->name); + if (ret < 0) + return ERR_PTR(ret); + + gpiod = gpio_to_desc(template->gpio); + if (!gpiod) + return ERR_PTR(-EINVAL); + + return gpiod; +} + static int gpio_led_probe(struct platform_device *pdev) { struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -246,7 +263,22 @@ static int gpio_led_probe(struct platform_device *pdev) priv->num_leds = pdata->num_leds; for (i = 0; i < priv->num_leds; i++) { - ret = create_gpio_led(&pdata->leds[i], &priv->leds[i], + const struct gpio_led *template = &pdata->leds[i]; + struct gpio_led_data *led_dat = &priv->leds[i]; + + if (template->gpiod) + led_dat->gpiod = template->gpiod; + else + led_dat->gpiod = + gpio_led_get_gpiod(&pdev->dev, + i, template); + if (IS_ERR(led_dat->gpiod)) { + dev_info(&pdev->dev, "Skipping unavailable LED gpio %d (%s)\n", + template->gpio, template->name); + continue; + } + + ret = create_gpio_led(template, led_dat, &pdev->dev, NULL, pdata->gpio_blink_set); if (ret < 0) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index df80c89ebe7f..5d3faae51d59 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -100,8 +100,9 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, led_data->pwm = devm_pwm_get(dev, led->name); if (IS_ERR(led_data->pwm)) { ret = PTR_ERR(led_data->pwm); - dev_err(dev, "unable to request PWM for %s: %d\n", - led->name, ret); + if (ret != -EPROBE_DEFER) + dev_err(dev, "unable to request PWM for %s: %d\n", + led->name, ret); return ret; } diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c index 9d9b7aab843f..fecf27fb1cdc 100644 --- a/drivers/leds/leds-sc27xx-bltc.c +++ b/drivers/leds/leds-sc27xx-bltc.c @@ -32,8 +32,18 @@ #define SC27XX_DUTY_MASK GENMASK(15, 0) #define SC27XX_MOD_MASK GENMASK(7, 0) +#define SC27XX_CURVE_SHIFT 8 +#define SC27XX_CURVE_L_MASK GENMASK(7, 0) +#define SC27XX_CURVE_H_MASK GENMASK(15, 8) + #define SC27XX_LEDS_OFFSET 0x10 #define SC27XX_LEDS_MAX 3 +#define SC27XX_LEDS_PATTERN_CNT 4 +/* Stage duration step, in milliseconds */ +#define SC27XX_LEDS_STEP 125 +/* Minimum and maximum duration, in milliseconds */ +#define SC27XX_DELTA_T_MIN SC27XX_LEDS_STEP +#define SC27XX_DELTA_T_MAX (SC27XX_LEDS_STEP * 255) struct sc27xx_led { char name[LED_MAX_NAME_SIZE]; @@ -122,6 +132,113 @@ static int sc27xx_led_set(struct led_classdev *ldev, enum led_brightness value) return err; } +static void sc27xx_led_clamp_align_delta_t(u32 *delta_t) +{ + u32 v, offset, t = *delta_t; + + v = t + SC27XX_LEDS_STEP / 2; + v = clamp_t(u32, v, SC27XX_DELTA_T_MIN, SC27XX_DELTA_T_MAX); + offset = v - SC27XX_DELTA_T_MIN; + offset = SC27XX_LEDS_STEP * (offset / SC27XX_LEDS_STEP); + + *delta_t = SC27XX_DELTA_T_MIN + offset; +} + +static int sc27xx_led_pattern_clear(struct led_classdev *ldev) +{ + struct sc27xx_led *leds = to_sc27xx_led(ldev); + struct regmap *regmap = leds->priv->regmap; + u32 base = sc27xx_led_get_offset(leds); + u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL; + u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line; + int err; + + mutex_lock(&leds->priv->lock); + + /* Reset the rise, high, fall and low time to zero. */ + regmap_write(regmap, base + SC27XX_LEDS_CURVE0, 0); + regmap_write(regmap, base + SC27XX_LEDS_CURVE1, 0); + + err = regmap_update_bits(regmap, ctrl_base, + (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0); + + ldev->brightness = LED_OFF; + + mutex_unlock(&leds->priv->lock); + + return err; +} + +static int sc27xx_led_pattern_set(struct led_classdev *ldev, + struct led_pattern *pattern, + u32 len, int repeat) +{ + struct sc27xx_led *leds = to_sc27xx_led(ldev); + u32 base = sc27xx_led_get_offset(leds); + u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL; + u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line; + struct regmap *regmap = leds->priv->regmap; + int err; + + /* + * Must contain 4 tuples to configure the rise time, high time, fall + * time and low time to enable the breathing mode. + */ + if (len != SC27XX_LEDS_PATTERN_CNT) + return -EINVAL; + + mutex_lock(&leds->priv->lock); + + sc27xx_led_clamp_align_delta_t(&pattern[0].delta_t); + err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0, + SC27XX_CURVE_L_MASK, + pattern[0].delta_t / SC27XX_LEDS_STEP); + if (err) + goto out; + + sc27xx_led_clamp_align_delta_t(&pattern[1].delta_t); + err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1, + SC27XX_CURVE_L_MASK, + pattern[1].delta_t / SC27XX_LEDS_STEP); + if (err) + goto out; + + sc27xx_led_clamp_align_delta_t(&pattern[2].delta_t); + err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0, + SC27XX_CURVE_H_MASK, + (pattern[2].delta_t / SC27XX_LEDS_STEP) << + SC27XX_CURVE_SHIFT); + if (err) + goto out; + + sc27xx_led_clamp_align_delta_t(&pattern[3].delta_t); + err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1, + SC27XX_CURVE_H_MASK, + (pattern[3].delta_t / SC27XX_LEDS_STEP) << + SC27XX_CURVE_SHIFT); + if (err) + goto out; + + err = regmap_update_bits(regmap, base + SC27XX_LEDS_DUTY, + SC27XX_DUTY_MASK, + (pattern[1].brightness << SC27XX_DUTY_SHIFT) | + SC27XX_MOD_MASK); + if (err) + goto out; + + /* Enable the LED breathing mode */ + err = regmap_update_bits(regmap, ctrl_base, + SC27XX_LED_RUN << ctrl_shift, + SC27XX_LED_RUN << ctrl_shift); + if (!err) + ldev->brightness = pattern[1].brightness; + +out: + mutex_unlock(&leds->priv->lock); + + return err; +} + static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv) { int i, err; @@ -140,6 +257,9 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv) led->priv = priv; led->ldev.name = led->name; led->ldev.brightness_set_blocking = sc27xx_led_set; + led->ldev.pattern_set = sc27xx_led_pattern_set; + led->ldev.pattern_clear = sc27xx_led_pattern_clear; + led->ldev.default_trigger = "pattern"; err = devm_led_classdev_register(dev, &led->ldev); if (err) @@ -241,4 +361,5 @@ module_platform_driver(sc27xx_led_driver); MODULE_DESCRIPTION("Spreadtrum SC27xx breathing light controller driver"); MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>"); +MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 4018af769969..b76fc3cdc8f8 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -129,4 +129,11 @@ config LEDS_TRIGGER_NETDEV This allows LEDs to be controlled by network device activity. If unsure, say Y. +config LEDS_TRIGGER_PATTERN + tristate "LED Pattern Trigger" + help + This allows LEDs to be controlled by a software or hardware pattern + which is a series of tuples, of brightness and duration (ms). + If unsure, say N + endif # LEDS_TRIGGERS diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index f3cfe1950538..9bcb64ee8123 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o +obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c new file mode 100644 index 000000000000..ce7acd115dd8 --- /dev/null +++ b/drivers/leds/trigger/ledtrig-pattern.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * LED pattern trigger + * + * Idea discussed with Pavel Machek. Raphael Teysseyre implemented + * the first version, Baolin Wang simplified and improved the approach. + */ + +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/timer.h> + +#define MAX_PATTERNS 1024 +/* + * When doing gradual dimming, the led brightness will be updated + * every 50 milliseconds. + */ +#define UPDATE_INTERVAL 50 + +struct pattern_trig_data { + struct led_classdev *led_cdev; + struct led_pattern patterns[MAX_PATTERNS]; + struct led_pattern *curr; + struct led_pattern *next; + struct mutex lock; + u32 npatterns; + int repeat; + int last_repeat; + int delta_t; + bool is_indefinite; + bool is_hw_pattern; + struct timer_list timer; +}; + +static void pattern_trig_update_patterns(struct pattern_trig_data *data) +{ + data->curr = data->next; + if (!data->is_indefinite && data->curr == data->patterns) + data->repeat--; + + if (data->next == data->patterns + data->npatterns - 1) + data->next = data->patterns; + else + data->next++; + + data->delta_t = 0; +} + +static int pattern_trig_compute_brightness(struct pattern_trig_data *data) +{ + int step_brightness; + + /* + * If current tuple's duration is less than the dimming interval, + * we should treat it as a step change of brightness instead of + * doing gradual dimming. + */ + if (data->delta_t == 0 || data->curr->delta_t < UPDATE_INTERVAL) + return data->curr->brightness; + + step_brightness = abs(data->next->brightness - data->curr->brightness); + step_brightness = data->delta_t * step_brightness / data->curr->delta_t; + + if (data->next->brightness > data->curr->brightness) + return data->curr->brightness + step_brightness; + else + return data->curr->brightness - step_brightness; +} + +static void pattern_trig_timer_function(struct timer_list *t) +{ + struct pattern_trig_data *data = from_timer(data, t, timer); + + mutex_lock(&data->lock); + + for (;;) { + if (!data->is_indefinite && !data->repeat) + break; + + if (data->curr->brightness == data->next->brightness) { + /* Step change of brightness */ + led_set_brightness(data->led_cdev, + data->curr->brightness); + mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->curr->delta_t)); + + /* Skip the tuple with zero duration */ + pattern_trig_update_patterns(data); + /* Select next tuple */ + pattern_trig_update_patterns(data); + } else { + /* Gradual dimming */ + + /* + * If the accumulation time is larger than current + * tuple's duration, we should go next one and re-check + * if we repeated done. + */ + if (data->delta_t > data->curr->delta_t) { + pattern_trig_update_patterns(data); + continue; + } + + led_set_brightness(data->led_cdev, + pattern_trig_compute_brightness(data)); + mod_timer(&data->timer, + jiffies + msecs_to_jiffies(UPDATE_INTERVAL)); + + /* Accumulate the gradual dimming time */ + data->delta_t += UPDATE_INTERVAL; + } + + break; + } + + mutex_unlock(&data->lock); +} + +static int pattern_trig_start_pattern(struct led_classdev *led_cdev) +{ + struct pattern_trig_data *data = led_cdev->trigger_data; + + if (!data->npatterns) + return 0; + + if (data->is_hw_pattern) { + return led_cdev->pattern_set(led_cdev, data->patterns, + data->npatterns, data->repeat); + } + + /* At least 2 tuples for software pattern. */ + if (data->npatterns < 2) + return -EINVAL; + + data->delta_t = 0; + data->curr = data->patterns; + data->next = data->patterns + 1; + data->timer.expires = jiffies; + add_timer(&data->timer); + + return 0; +} + +static ssize_t repeat_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct pattern_trig_data *data = led_cdev->trigger_data; + int repeat; + + mutex_lock(&data->lock); + + repeat = data->last_repeat; + + mutex_unlock(&data->lock); + + return scnprintf(buf, PAGE_SIZE, "%d\n", repeat); +} + +static ssize_t repeat_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct pattern_trig_data *data = led_cdev->trigger_data; + int err, res; + + err = kstrtos32(buf, 10, &res); + if (err) + return err; + + /* Number 0 and negative numbers except -1 are invalid. */ + if (res < -1 || res == 0) + return -EINVAL; + + /* + * Clear previous patterns' performence firstly, and remove the timer + * without mutex lock to avoid dead lock. + */ + del_timer_sync(&data->timer); + + mutex_lock(&data->lock); + + if (data->is_hw_pattern) + led_cdev->pattern_clear(led_cdev); + + data->last_repeat = data->repeat = res; + /* -1 means repeat indefinitely */ + if (data->repeat == -1) + data->is_indefinite = true; + else + data->is_indefinite = false; + + err = pattern_trig_start_pattern(led_cdev); + + mutex_unlock(&data->lock); + return err < 0 ? err : count; +} + +static DEVICE_ATTR_RW(repeat); + +static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data, + char *buf, bool hw_pattern) +{ + ssize_t count = 0; + int i; + + mutex_lock(&data->lock); + + if (!data->npatterns || (data->is_hw_pattern ^ hw_pattern)) + goto out; + + for (i = 0; i < data->npatterns; i++) { + count += scnprintf(buf + count, PAGE_SIZE - count, + "%d %u ", + data->patterns[i].brightness, + data->patterns[i].delta_t); + } + + buf[count - 1] = '\n'; + +out: + mutex_unlock(&data->lock); + return count; +} + +static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, + const char *buf, size_t count, + bool hw_pattern) +{ + struct pattern_trig_data *data = led_cdev->trigger_data; + int ccount, cr, offset = 0, err = 0; + + /* + * Clear previous patterns' performence firstly, and remove the timer + * without mutex lock to avoid dead lock. + */ + del_timer_sync(&data->timer); + + mutex_lock(&data->lock); + + if (data->is_hw_pattern) + led_cdev->pattern_clear(led_cdev); + + data->is_hw_pattern = hw_pattern; + data->npatterns = 0; + + while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { + cr = 0; + ccount = sscanf(buf + offset, "%d %u %n", + &data->patterns[data->npatterns].brightness, + &data->patterns[data->npatterns].delta_t, &cr); + if (ccount != 2) { + data->npatterns = 0; + err = -EINVAL; + goto out; + } + + offset += cr; + data->npatterns++; + } + + err = pattern_trig_start_pattern(led_cdev); + if (err) + data->npatterns = 0; + +out: + mutex_unlock(&data->lock); + return err < 0 ? err : count; +} + +static ssize_t pattern_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct pattern_trig_data *data = led_cdev->trigger_data; + + return pattern_trig_show_patterns(data, buf, false); +} + +static ssize_t pattern_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return pattern_trig_store_patterns(led_cdev, buf, count, false); +} + +static DEVICE_ATTR_RW(pattern); + +static ssize_t hw_pattern_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct pattern_trig_data *data = led_cdev->trigger_data; + + return pattern_trig_show_patterns(data, buf, true); +} + +static ssize_t hw_pattern_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return pattern_trig_store_patterns(led_cdev, buf, count, true); +} + +static DEVICE_ATTR_RW(hw_pattern); + +static umode_t pattern_trig_attrs_mode(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + if (attr == &dev_attr_repeat.attr || attr == &dev_attr_pattern.attr) + return attr->mode; + else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set) + return attr->mode; + + return 0; +} + +static struct attribute *pattern_trig_attrs[] = { + &dev_attr_pattern.attr, + &dev_attr_hw_pattern.attr, + &dev_attr_repeat.attr, + NULL +}; + +static const struct attribute_group pattern_trig_group = { + .attrs = pattern_trig_attrs, + .is_visible = pattern_trig_attrs_mode, +}; + +static const struct attribute_group *pattern_trig_groups[] = { + &pattern_trig_group, + NULL, +}; + +static int pattern_trig_activate(struct led_classdev *led_cdev) +{ + struct pattern_trig_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (!!led_cdev->pattern_set ^ !!led_cdev->pattern_clear) { + dev_warn(led_cdev->dev, + "Hardware pattern ops validation failed\n"); + led_cdev->pattern_set = NULL; + led_cdev->pattern_clear = NULL; + } + + data->is_indefinite = true; + data->last_repeat = -1; + mutex_init(&data->lock); + data->led_cdev = led_cdev; + led_set_trigger_data(led_cdev, data); + timer_setup(&data->timer, pattern_trig_timer_function, 0); + led_cdev->activated = true; + + return 0; +} + +static void pattern_trig_deactivate(struct led_classdev *led_cdev) +{ + struct pattern_trig_data *data = led_cdev->trigger_data; + + if (!led_cdev->activated) + return; + + if (led_cdev->pattern_clear) + led_cdev->pattern_clear(led_cdev); + + del_timer_sync(&data->timer); + + led_set_brightness(led_cdev, LED_OFF); + kfree(data); + led_cdev->activated = false; +} + +static struct led_trigger pattern_led_trigger = { + .name = "pattern", + .activate = pattern_trig_activate, + .deactivate = pattern_trig_deactivate, + .groups = pattern_trig_groups, +}; + +static int __init pattern_trig_init(void) +{ + return led_trigger_register(&pattern_led_trigger); +} + +static void __exit pattern_trig_exit(void) +{ + led_trigger_unregister(&pattern_led_trigger); +} + +module_init(pattern_trig_init); +module_exit(pattern_trig_exit); + +MODULE_AUTHOR("Raphael Teysseyre <rteysseyre@gmail.com"); +MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org"); +MODULE_DESCRIPTION("LED Pattern trigger"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig index 439bf90d084d..a872cd720967 100644 --- a/drivers/lightnvm/Kconfig +++ b/drivers/lightnvm/Kconfig @@ -4,8 +4,7 @@ menuconfig NVM bool "Open-Channel SSD target support" - depends on BLOCK && PCI - select BLK_DEV_NVME + depends on BLOCK help Say Y here to get to enable Open-channel SSDs. diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 60aa7bc5a630..efb976a863d2 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -355,6 +355,11 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) return -EINVAL; } + if ((tt->flags & NVM_TGT_F_HOST_L2P) != (dev->geo.dom & NVM_RSP_L2P)) { + pr_err("nvm: device is incompatible with target L2P type.\n"); + return -EINVAL; + } + if (nvm_target_exists(create->tgtname)) { pr_err("nvm: target name already exists (%s)\n", create->tgtname); @@ -598,22 +603,16 @@ static void nvm_ppa_dev_to_tgt(struct nvm_tgt_dev *tgt_dev, static void nvm_rq_tgt_to_dev(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) { - if (rqd->nr_ppas == 1) { - nvm_ppa_tgt_to_dev(tgt_dev, &rqd->ppa_addr, 1); - return; - } + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); - nvm_ppa_tgt_to_dev(tgt_dev, rqd->ppa_list, rqd->nr_ppas); + nvm_ppa_tgt_to_dev(tgt_dev, ppa_list, rqd->nr_ppas); } static void nvm_rq_dev_to_tgt(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) { - if (rqd->nr_ppas == 1) { - nvm_ppa_dev_to_tgt(tgt_dev, &rqd->ppa_addr, 1); - return; - } + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); - nvm_ppa_dev_to_tgt(tgt_dev, rqd->ppa_list, rqd->nr_ppas); + nvm_ppa_dev_to_tgt(tgt_dev, ppa_list, rqd->nr_ppas); } int nvm_register_tgt_type(struct nvm_tgt_type *tt) @@ -712,45 +711,23 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev, nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list); } -int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta, - struct ppa_addr ppa, int nchks) +static int nvm_set_flags(struct nvm_geo *geo, struct nvm_rq *rqd) { - struct nvm_dev *dev = tgt_dev->parent; - - nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1); - - return dev->ops->get_chk_meta(tgt_dev->parent, meta, - (sector_t)ppa.ppa, nchks); -} -EXPORT_SYMBOL(nvm_get_chunk_meta); - -int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, - int nr_ppas, int type) -{ - struct nvm_dev *dev = tgt_dev->parent; - struct nvm_rq rqd; - int ret; + int flags = 0; - if (nr_ppas > NVM_MAX_VLBA) { - pr_err("nvm: unable to update all blocks atomically\n"); - return -EINVAL; - } + if (geo->version == NVM_OCSSD_SPEC_20) + return 0; - memset(&rqd, 0, sizeof(struct nvm_rq)); + if (rqd->is_seq) + flags |= geo->pln_mode >> 1; - nvm_set_rqd_ppalist(tgt_dev, &rqd, ppas, nr_ppas); - nvm_rq_tgt_to_dev(tgt_dev, &rqd); + if (rqd->opcode == NVM_OP_PREAD) + flags |= (NVM_IO_SCRAMBLE_ENABLE | NVM_IO_SUSPEND); + else if (rqd->opcode == NVM_OP_PWRITE) + flags |= NVM_IO_SCRAMBLE_ENABLE; - ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type); - nvm_free_rqd_ppalist(tgt_dev, &rqd); - if (ret) { - pr_err("nvm: failed bb mark\n"); - return -EINVAL; - } - - return 0; + return flags; } -EXPORT_SYMBOL(nvm_set_tgt_bb_tbl); int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) { @@ -763,6 +740,7 @@ int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) nvm_rq_tgt_to_dev(tgt_dev, rqd); rqd->dev = tgt_dev; + rqd->flags = nvm_set_flags(&tgt_dev->geo, rqd); /* In case of error, fail with right address format */ ret = dev->ops->submit_io(dev, rqd); @@ -783,6 +761,7 @@ int nvm_submit_io_sync(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) nvm_rq_tgt_to_dev(tgt_dev, rqd); rqd->dev = tgt_dev; + rqd->flags = nvm_set_flags(&tgt_dev->geo, rqd); /* In case of error, fail with right address format */ ret = dev->ops->submit_io_sync(dev, rqd); @@ -805,27 +784,159 @@ void nvm_end_io(struct nvm_rq *rqd) } EXPORT_SYMBOL(nvm_end_io); +static int nvm_submit_io_sync_raw(struct nvm_dev *dev, struct nvm_rq *rqd) +{ + if (!dev->ops->submit_io_sync) + return -ENODEV; + + rqd->flags = nvm_set_flags(&dev->geo, rqd); + + return dev->ops->submit_io_sync(dev, rqd); +} + +static int nvm_bb_chunk_sense(struct nvm_dev *dev, struct ppa_addr ppa) +{ + struct nvm_rq rqd = { NULL }; + struct bio bio; + struct bio_vec bio_vec; + struct page *page; + int ret; + + page = alloc_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + bio_init(&bio, &bio_vec, 1); + bio_add_page(&bio, page, PAGE_SIZE, 0); + bio_set_op_attrs(&bio, REQ_OP_READ, 0); + + rqd.bio = &bio; + rqd.opcode = NVM_OP_PREAD; + rqd.is_seq = 1; + rqd.nr_ppas = 1; + rqd.ppa_addr = generic_to_dev_addr(dev, ppa); + + ret = nvm_submit_io_sync_raw(dev, &rqd); + if (ret) + return ret; + + __free_page(page); + + return rqd.error; +} + /* - * folds a bad block list from its plane representation to its virtual - * block representation. The fold is done in place and reduced size is - * returned. - * - * If any of the planes status are bad or grown bad block, the virtual block - * is marked bad. If not bad, the first plane state acts as the block state. + * Scans a 1.2 chunk first and last page to determine if its state. + * If the chunk is found to be open, also scan it to update the write + * pointer. */ -int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks) +static int nvm_bb_chunk_scan(struct nvm_dev *dev, struct ppa_addr ppa, + struct nvm_chk_meta *meta) { struct nvm_geo *geo = &dev->geo; - int blk, offset, pl, blktype; + int ret, pg, pl; - if (nr_blks != geo->num_chk * geo->pln_mode) - return -EINVAL; + /* sense first page */ + ret = nvm_bb_chunk_sense(dev, ppa); + if (ret < 0) /* io error */ + return ret; + else if (ret == 0) /* valid data */ + meta->state = NVM_CHK_ST_OPEN; + else if (ret > 0) { + /* + * If empty page, the chunk is free, else it is an + * actual io error. In that case, mark it offline. + */ + switch (ret) { + case NVM_RSP_ERR_EMPTYPAGE: + meta->state = NVM_CHK_ST_FREE; + return 0; + case NVM_RSP_ERR_FAILCRC: + case NVM_RSP_ERR_FAILECC: + case NVM_RSP_WARN_HIGHECC: + meta->state = NVM_CHK_ST_OPEN; + goto scan; + default: + return -ret; /* other io error */ + } + } + + /* sense last page */ + ppa.g.pg = geo->num_pg - 1; + ppa.g.pl = geo->num_pln - 1; + + ret = nvm_bb_chunk_sense(dev, ppa); + if (ret < 0) /* io error */ + return ret; + else if (ret == 0) { /* Chunk fully written */ + meta->state = NVM_CHK_ST_CLOSED; + meta->wp = geo->clba; + return 0; + } else if (ret > 0) { + switch (ret) { + case NVM_RSP_ERR_EMPTYPAGE: + case NVM_RSP_ERR_FAILCRC: + case NVM_RSP_ERR_FAILECC: + case NVM_RSP_WARN_HIGHECC: + meta->state = NVM_CHK_ST_OPEN; + break; + default: + return -ret; /* other io error */ + } + } + +scan: + /* + * chunk is open, we scan sequentially to update the write pointer. + * We make the assumption that targets write data across all planes + * before moving to the next page. + */ + for (pg = 0; pg < geo->num_pg; pg++) { + for (pl = 0; pl < geo->num_pln; pl++) { + ppa.g.pg = pg; + ppa.g.pl = pl; + + ret = nvm_bb_chunk_sense(dev, ppa); + if (ret < 0) /* io error */ + return ret; + else if (ret == 0) { + meta->wp += geo->ws_min; + } else if (ret > 0) { + switch (ret) { + case NVM_RSP_ERR_EMPTYPAGE: + return 0; + case NVM_RSP_ERR_FAILCRC: + case NVM_RSP_ERR_FAILECC: + case NVM_RSP_WARN_HIGHECC: + meta->wp += geo->ws_min; + break; + default: + return -ret; /* other io error */ + } + } + } + } + + return 0; +} + +/* + * folds a bad block list from its plane representation to its + * chunk representation. + * + * If any of the planes status are bad or grown bad, the chunk is marked + * offline. If not bad, the first plane state acts as the chunk state. + */ +static int nvm_bb_to_chunk(struct nvm_dev *dev, struct ppa_addr ppa, + u8 *blks, int nr_blks, struct nvm_chk_meta *meta) +{ + struct nvm_geo *geo = &dev->geo; + int ret, blk, pl, offset, blktype; for (blk = 0; blk < geo->num_chk; blk++) { offset = blk * geo->pln_mode; blktype = blks[offset]; - /* Bad blocks on any planes take precedence over other types */ for (pl = 0; pl < geo->pln_mode; pl++) { if (blks[offset + pl] & (NVM_BLK_T_BAD|NVM_BLK_T_GRWN_BAD)) { @@ -834,23 +945,124 @@ int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks) } } - blks[blk] = blktype; + ppa.g.blk = blk; + + meta->wp = 0; + meta->type = NVM_CHK_TP_W_SEQ; + meta->wi = 0; + meta->slba = generic_to_dev_addr(dev, ppa).ppa; + meta->cnlb = dev->geo.clba; + + if (blktype == NVM_BLK_T_FREE) { + ret = nvm_bb_chunk_scan(dev, ppa, meta); + if (ret) + return ret; + } else { + meta->state = NVM_CHK_ST_OFFLINE; + } + + meta++; } - return geo->num_chk; + return 0; +} + +static int nvm_get_bb_meta(struct nvm_dev *dev, sector_t slba, + int nchks, struct nvm_chk_meta *meta) +{ + struct nvm_geo *geo = &dev->geo; + struct ppa_addr ppa; + u8 *blks; + int ch, lun, nr_blks; + int ret; + + ppa.ppa = slba; + ppa = dev_to_generic_addr(dev, ppa); + + if (ppa.g.blk != 0) + return -EINVAL; + + if ((nchks % geo->num_chk) != 0) + return -EINVAL; + + nr_blks = geo->num_chk * geo->pln_mode; + + blks = kmalloc(nr_blks, GFP_KERNEL); + if (!blks) + return -ENOMEM; + + for (ch = ppa.g.ch; ch < geo->num_ch; ch++) { + for (lun = ppa.g.lun; lun < geo->num_lun; lun++) { + struct ppa_addr ppa_gen, ppa_dev; + + if (!nchks) + goto done; + + ppa_gen.ppa = 0; + ppa_gen.g.ch = ch; + ppa_gen.g.lun = lun; + ppa_dev = generic_to_dev_addr(dev, ppa_gen); + + ret = dev->ops->get_bb_tbl(dev, ppa_dev, blks); + if (ret) + goto done; + + ret = nvm_bb_to_chunk(dev, ppa_gen, blks, nr_blks, + meta); + if (ret) + goto done; + + meta += geo->num_chk; + nchks -= geo->num_chk; + } + } +done: + kfree(blks); + return ret; } -EXPORT_SYMBOL(nvm_bb_tbl_fold); -int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa, - u8 *blks) +int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa, + int nchks, struct nvm_chk_meta *meta) { struct nvm_dev *dev = tgt_dev->parent; nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1); - return dev->ops->get_bb_tbl(dev, ppa, blks); + if (dev->geo.version == NVM_OCSSD_SPEC_12) + return nvm_get_bb_meta(dev, (sector_t)ppa.ppa, nchks, meta); + + return dev->ops->get_chk_meta(dev, (sector_t)ppa.ppa, nchks, meta); +} +EXPORT_SYMBOL_GPL(nvm_get_chunk_meta); + +int nvm_set_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, + int nr_ppas, int type) +{ + struct nvm_dev *dev = tgt_dev->parent; + struct nvm_rq rqd; + int ret; + + if (dev->geo.version == NVM_OCSSD_SPEC_20) + return 0; + + if (nr_ppas > NVM_MAX_VLBA) { + pr_err("nvm: unable to update all blocks atomically\n"); + return -EINVAL; + } + + memset(&rqd, 0, sizeof(struct nvm_rq)); + + nvm_set_rqd_ppalist(tgt_dev, &rqd, ppas, nr_ppas); + nvm_rq_tgt_to_dev(tgt_dev, &rqd); + + ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type); + nvm_free_rqd_ppalist(tgt_dev, &rqd); + if (ret) + return -EINVAL; + + return 0; } -EXPORT_SYMBOL(nvm_get_tgt_bb_tbl); +EXPORT_SYMBOL_GPL(nvm_set_chunk_meta); static int nvm_core_init(struct nvm_dev *dev) { diff --git a/drivers/lightnvm/pblk-cache.c b/drivers/lightnvm/pblk-cache.c index f565a56b898a..c9fa26f95659 100644 --- a/drivers/lightnvm/pblk-cache.c +++ b/drivers/lightnvm/pblk-cache.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 00984b486fea..6944aac43b01 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -16,7 +17,10 @@ * */ +#define CREATE_TRACE_POINTS + #include "pblk.h" +#include "pblk-trace.h" static void pblk_line_mark_bb(struct work_struct *work) { @@ -27,12 +31,12 @@ static void pblk_line_mark_bb(struct work_struct *work) struct ppa_addr *ppa = line_ws->priv; int ret; - ret = nvm_set_tgt_bb_tbl(dev, ppa, 1, NVM_BLK_T_GRWN_BAD); + ret = nvm_set_chunk_meta(dev, ppa, 1, NVM_BLK_T_GRWN_BAD); if (ret) { struct pblk_line *line; int pos; - line = &pblk->lines[pblk_ppa_to_line(*ppa)]; + line = pblk_ppa_to_line(pblk, *ppa); pos = pblk_ppa_to_pos(&dev->geo, *ppa); pblk_err(pblk, "failed to mark bb, line:%d, pos:%d\n", @@ -80,19 +84,28 @@ static void __pblk_end_io_erase(struct pblk *pblk, struct nvm_rq *rqd) struct pblk_line *line; int pos; - line = &pblk->lines[pblk_ppa_to_line(rqd->ppa_addr)]; + line = pblk_ppa_to_line(pblk, rqd->ppa_addr); pos = pblk_ppa_to_pos(geo, rqd->ppa_addr); chunk = &line->chks[pos]; atomic_dec(&line->left_seblks); if (rqd->error) { + trace_pblk_chunk_reset(pblk_disk_name(pblk), + &rqd->ppa_addr, PBLK_CHUNK_RESET_FAILED); + chunk->state = NVM_CHK_ST_OFFLINE; pblk_mark_bb(pblk, line, rqd->ppa_addr); } else { + trace_pblk_chunk_reset(pblk_disk_name(pblk), + &rqd->ppa_addr, PBLK_CHUNK_RESET_DONE); + chunk->state = NVM_CHK_ST_FREE; } + trace_pblk_chunk_state(pblk_disk_name(pblk), &rqd->ppa_addr, + chunk->state); + atomic_dec(&pblk->inflight_io); } @@ -108,9 +121,9 @@ static void pblk_end_io_erase(struct nvm_rq *rqd) /* * Get information for all chunks from the device. * - * The caller is responsible for freeing the returned structure + * The caller is responsible for freeing (vmalloc) the returned structure */ -struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk) +struct nvm_chk_meta *pblk_get_chunk_meta(struct pblk *pblk) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; @@ -122,11 +135,11 @@ struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk) ppa.ppa = 0; len = geo->all_chunks * sizeof(*meta); - meta = kzalloc(len, GFP_KERNEL); + meta = vzalloc(len); if (!meta) return ERR_PTR(-ENOMEM); - ret = nvm_get_chunk_meta(dev, meta, ppa, geo->all_chunks); + ret = nvm_get_chunk_meta(dev, ppa, geo->all_chunks, meta); if (ret) { kfree(meta); return ERR_PTR(-EIO); @@ -192,7 +205,6 @@ void pblk_map_invalidate(struct pblk *pblk, struct ppa_addr ppa) { struct pblk_line *line; u64 paddr; - int line_id; #ifdef CONFIG_NVM_PBLK_DEBUG /* Callers must ensure that the ppa points to a device address */ @@ -200,8 +212,7 @@ void pblk_map_invalidate(struct pblk *pblk, struct ppa_addr ppa) BUG_ON(pblk_ppa_empty(ppa)); #endif - line_id = pblk_ppa_to_line(ppa); - line = &pblk->lines[line_id]; + line = pblk_ppa_to_line(pblk, ppa); paddr = pblk_dev_ppa_to_line_addr(pblk, ppa); __pblk_map_invalidate(pblk, line, paddr); @@ -227,6 +238,33 @@ static void pblk_invalidate_range(struct pblk *pblk, sector_t slba, spin_unlock(&pblk->trans_lock); } +int pblk_alloc_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd) +{ + struct nvm_tgt_dev *dev = pblk->dev; + + rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, + &rqd->dma_meta_list); + if (!rqd->meta_list) + return -ENOMEM; + + if (rqd->nr_ppas == 1) + return 0; + + rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size; + rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size; + + return 0; +} + +void pblk_free_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd) +{ + struct nvm_tgt_dev *dev = pblk->dev; + + if (rqd->meta_list) + nvm_dev_dma_free(dev->parent, rqd->meta_list, + rqd->dma_meta_list); +} + /* Caller must guarantee that the request is a valid type */ struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int type) { @@ -258,7 +296,6 @@ struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int type) /* Typically used on completion path. Cannot guarantee request consistency */ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type) { - struct nvm_tgt_dev *dev = pblk->dev; mempool_t *pool; switch (type) { @@ -279,9 +316,7 @@ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type) return; } - if (rqd->meta_list) - nvm_dev_dma_free(dev->parent, rqd->meta_list, - rqd->dma_meta_list); + pblk_free_rqd_meta(pblk, rqd); mempool_free(rqd, pool); } @@ -409,6 +444,9 @@ struct list_head *pblk_line_gc_list(struct pblk *pblk, struct pblk_line *line) } } else { line->state = PBLK_LINESTATE_CORRUPT; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); + line->gc_group = PBLK_LINEGC_NONE; move_list = &l_mg->corrupt_list; pblk_err(pblk, "corrupted vsc for line %d, vsc:%d (%d/%d/%d)\n", @@ -479,9 +517,30 @@ int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd) return nvm_submit_io(dev, rqd); } +void pblk_check_chunk_state_update(struct pblk *pblk, struct nvm_rq *rqd) +{ + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); + + int i; + + for (i = 0; i < rqd->nr_ppas; i++) { + struct ppa_addr *ppa = &ppa_list[i]; + struct nvm_chk_meta *chunk = pblk_dev_ppa_to_chunk(pblk, *ppa); + u64 caddr = pblk_dev_ppa_to_chunk_addr(pblk, *ppa); + + if (caddr == 0) + trace_pblk_chunk_state(pblk_disk_name(pblk), + ppa, NVM_CHK_ST_OPEN); + else if (caddr == chunk->cnlb) + trace_pblk_chunk_state(pblk_disk_name(pblk), + ppa, NVM_CHK_ST_CLOSED); + } +} + int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd) { struct nvm_tgt_dev *dev = pblk->dev; + int ret; atomic_inc(&pblk->inflight_io); @@ -490,7 +549,27 @@ int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd) return NVM_IO_ERR; #endif - return nvm_submit_io_sync(dev, rqd); + ret = nvm_submit_io_sync(dev, rqd); + + if (trace_pblk_chunk_state_enabled() && !ret && + rqd->opcode == NVM_OP_PWRITE) + pblk_check_chunk_state_update(pblk, rqd); + + return ret; +} + +int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd) +{ + struct ppa_addr *ppa_list; + int ret; + + ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr; + + pblk_down_chunk(pblk, ppa_list[0]); + ret = pblk_submit_io_sync(pblk, rqd); + pblk_up_chunk(pblk, ppa_list[0]); + + return ret; } static void pblk_bio_map_addr_endio(struct bio *bio) @@ -621,262 +700,227 @@ u64 pblk_lookup_page(struct pblk *pblk, struct pblk_line *line) return paddr; } -/* - * Submit emeta to one LUN in the raid line at the time to avoid a deadlock when - * taking the per LUN semaphore. - */ -static int pblk_line_submit_emeta_io(struct pblk *pblk, struct pblk_line *line, - void *emeta_buf, u64 paddr, int dir) +u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; - void *ppa_list, *meta_list; - struct bio *bio; - struct nvm_rq rqd; - dma_addr_t dma_ppa_list, dma_meta_list; - int min = pblk->min_write_pgs; - int left_ppas = lm->emeta_sec[0]; - int id = line->id; - int rq_ppas, rq_len; - int cmd_op, bio_op; - int i, j; - int ret; + int bit; - if (dir == PBLK_WRITE) { - bio_op = REQ_OP_WRITE; - cmd_op = NVM_OP_PWRITE; - } else if (dir == PBLK_READ) { - bio_op = REQ_OP_READ; - cmd_op = NVM_OP_PREAD; - } else - return -EINVAL; + /* This usually only happens on bad lines */ + bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line); + if (bit >= lm->blk_per_line) + return -1; - meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, - &dma_meta_list); - if (!meta_list) - return -ENOMEM; + return bit * geo->ws_opt; +} - ppa_list = meta_list + pblk_dma_meta_size; - dma_ppa_list = dma_meta_list + pblk_dma_meta_size; +int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line) +{ + struct nvm_tgt_dev *dev = pblk->dev; + struct pblk_line_meta *lm = &pblk->lm; + struct bio *bio; + struct nvm_rq rqd; + u64 paddr = pblk_line_smeta_start(pblk, line); + int i, ret; -next_rq: memset(&rqd, 0, sizeof(struct nvm_rq)); - rq_ppas = pblk_calc_secs(pblk, left_ppas, 0); - rq_len = rq_ppas * geo->csecs; + ret = pblk_alloc_rqd_meta(pblk, &rqd); + if (ret) + return ret; - bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len, - l_mg->emeta_alloc_type, GFP_KERNEL); + bio = bio_map_kern(dev->q, line->smeta, lm->smeta_len, GFP_KERNEL); if (IS_ERR(bio)) { ret = PTR_ERR(bio); - goto free_rqd_dma; + goto clear_rqd; } bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, bio_op, 0); + bio_set_op_attrs(bio, REQ_OP_READ, 0); rqd.bio = bio; - rqd.meta_list = meta_list; - rqd.ppa_list = ppa_list; - rqd.dma_meta_list = dma_meta_list; - rqd.dma_ppa_list = dma_ppa_list; - rqd.opcode = cmd_op; - rqd.nr_ppas = rq_ppas; - - if (dir == PBLK_WRITE) { - struct pblk_sec_meta *meta_list = rqd.meta_list; - - rqd.flags = pblk_set_progr_mode(pblk, PBLK_WRITE); - for (i = 0; i < rqd.nr_ppas; ) { - spin_lock(&line->lock); - paddr = __pblk_alloc_page(pblk, line, min); - spin_unlock(&line->lock); - for (j = 0; j < min; j++, i++, paddr++) { - meta_list[i].lba = cpu_to_le64(ADDR_EMPTY); - rqd.ppa_list[i] = - addr_to_gen_ppa(pblk, paddr, id); - } - } - } else { - for (i = 0; i < rqd.nr_ppas; ) { - struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, id); - int pos = pblk_ppa_to_pos(geo, ppa); - int read_type = PBLK_READ_RANDOM; - - if (pblk_io_aligned(pblk, rq_ppas)) - read_type = PBLK_READ_SEQUENTIAL; - rqd.flags = pblk_set_read_mode(pblk, read_type); - - while (test_bit(pos, line->blk_bitmap)) { - paddr += min; - if (pblk_boundary_paddr_checks(pblk, paddr)) { - pblk_err(pblk, "corrupt emeta line:%d\n", - line->id); - bio_put(bio); - ret = -EINTR; - goto free_rqd_dma; - } - - ppa = addr_to_gen_ppa(pblk, paddr, id); - pos = pblk_ppa_to_pos(geo, ppa); - } - - if (pblk_boundary_paddr_checks(pblk, paddr + min)) { - pblk_err(pblk, "corrupt emeta line:%d\n", - line->id); - bio_put(bio); - ret = -EINTR; - goto free_rqd_dma; - } + rqd.opcode = NVM_OP_PREAD; + rqd.nr_ppas = lm->smeta_sec; + rqd.is_seq = 1; - for (j = 0; j < min; j++, i++, paddr++) - rqd.ppa_list[i] = - addr_to_gen_ppa(pblk, paddr, line->id); - } - } + for (i = 0; i < lm->smeta_sec; i++, paddr++) + rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id); ret = pblk_submit_io_sync(pblk, &rqd); if (ret) { - pblk_err(pblk, "emeta I/O submission failed: %d\n", ret); + pblk_err(pblk, "smeta I/O submission failed: %d\n", ret); bio_put(bio); - goto free_rqd_dma; + goto clear_rqd; } atomic_dec(&pblk->inflight_io); - if (rqd.error) { - if (dir == PBLK_WRITE) - pblk_log_write_err(pblk, &rqd); - else - pblk_log_read_err(pblk, &rqd); - } + if (rqd.error) + pblk_log_read_err(pblk, &rqd); - emeta_buf += rq_len; - left_ppas -= rq_ppas; - if (left_ppas) - goto next_rq; -free_rqd_dma: - nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list); +clear_rqd: + pblk_free_rqd_meta(pblk, &rqd); return ret; } -u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line) -{ - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - struct pblk_line_meta *lm = &pblk->lm; - int bit; - - /* This usually only happens on bad lines */ - bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line); - if (bit >= lm->blk_per_line) - return -1; - - return bit * geo->ws_opt; -} - -static int pblk_line_submit_smeta_io(struct pblk *pblk, struct pblk_line *line, - u64 paddr, int dir) +static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line, + u64 paddr) { struct nvm_tgt_dev *dev = pblk->dev; struct pblk_line_meta *lm = &pblk->lm; struct bio *bio; struct nvm_rq rqd; - __le64 *lba_list = NULL; + __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf); + __le64 addr_empty = cpu_to_le64(ADDR_EMPTY); int i, ret; - int cmd_op, bio_op; - int flags; - - if (dir == PBLK_WRITE) { - bio_op = REQ_OP_WRITE; - cmd_op = NVM_OP_PWRITE; - flags = pblk_set_progr_mode(pblk, PBLK_WRITE); - lba_list = emeta_to_lbas(pblk, line->emeta->buf); - } else if (dir == PBLK_READ_RECOV || dir == PBLK_READ) { - bio_op = REQ_OP_READ; - cmd_op = NVM_OP_PREAD; - flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL); - } else - return -EINVAL; memset(&rqd, 0, sizeof(struct nvm_rq)); - rqd.meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, - &rqd.dma_meta_list); - if (!rqd.meta_list) - return -ENOMEM; - - rqd.ppa_list = rqd.meta_list + pblk_dma_meta_size; - rqd.dma_ppa_list = rqd.dma_meta_list + pblk_dma_meta_size; + ret = pblk_alloc_rqd_meta(pblk, &rqd); + if (ret) + return ret; bio = bio_map_kern(dev->q, line->smeta, lm->smeta_len, GFP_KERNEL); if (IS_ERR(bio)) { ret = PTR_ERR(bio); - goto free_ppa_list; + goto clear_rqd; } bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, bio_op, 0); + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); rqd.bio = bio; - rqd.opcode = cmd_op; - rqd.flags = flags; + rqd.opcode = NVM_OP_PWRITE; rqd.nr_ppas = lm->smeta_sec; + rqd.is_seq = 1; for (i = 0; i < lm->smeta_sec; i++, paddr++) { struct pblk_sec_meta *meta_list = rqd.meta_list; rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id); - - if (dir == PBLK_WRITE) { - __le64 addr_empty = cpu_to_le64(ADDR_EMPTY); - - meta_list[i].lba = lba_list[paddr] = addr_empty; - } + meta_list[i].lba = lba_list[paddr] = addr_empty; } - /* - * This I/O is sent by the write thread when a line is replace. Since - * the write thread is the only one sending write and erase commands, - * there is no need to take the LUN semaphore. - */ - ret = pblk_submit_io_sync(pblk, &rqd); + ret = pblk_submit_io_sync_sem(pblk, &rqd); if (ret) { pblk_err(pblk, "smeta I/O submission failed: %d\n", ret); bio_put(bio); - goto free_ppa_list; + goto clear_rqd; } atomic_dec(&pblk->inflight_io); if (rqd.error) { - if (dir == PBLK_WRITE) { - pblk_log_write_err(pblk, &rqd); - ret = 1; - } else if (dir == PBLK_READ) - pblk_log_read_err(pblk, &rqd); + pblk_log_write_err(pblk, &rqd); + ret = -EIO; } -free_ppa_list: - nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list); - +clear_rqd: + pblk_free_rqd_meta(pblk, &rqd); return ret; } -int pblk_line_read_smeta(struct pblk *pblk, struct pblk_line *line) +int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line, + void *emeta_buf) { - u64 bpaddr = pblk_line_smeta_start(pblk, line); + struct nvm_tgt_dev *dev = pblk->dev; + struct nvm_geo *geo = &dev->geo; + struct pblk_line_mgmt *l_mg = &pblk->l_mg; + struct pblk_line_meta *lm = &pblk->lm; + void *ppa_list, *meta_list; + struct bio *bio; + struct nvm_rq rqd; + u64 paddr = line->emeta_ssec; + dma_addr_t dma_ppa_list, dma_meta_list; + int min = pblk->min_write_pgs; + int left_ppas = lm->emeta_sec[0]; + int line_id = line->id; + int rq_ppas, rq_len; + int i, j; + int ret; - return pblk_line_submit_smeta_io(pblk, line, bpaddr, PBLK_READ_RECOV); -} + meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, + &dma_meta_list); + if (!meta_list) + return -ENOMEM; -int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line, - void *emeta_buf) -{ - return pblk_line_submit_emeta_io(pblk, line, emeta_buf, - line->emeta_ssec, PBLK_READ); + ppa_list = meta_list + pblk_dma_meta_size; + dma_ppa_list = dma_meta_list + pblk_dma_meta_size; + +next_rq: + memset(&rqd, 0, sizeof(struct nvm_rq)); + + rq_ppas = pblk_calc_secs(pblk, left_ppas, 0); + rq_len = rq_ppas * geo->csecs; + + bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len, + l_mg->emeta_alloc_type, GFP_KERNEL); + if (IS_ERR(bio)) { + ret = PTR_ERR(bio); + goto free_rqd_dma; + } + + bio->bi_iter.bi_sector = 0; /* internal bio */ + bio_set_op_attrs(bio, REQ_OP_READ, 0); + + rqd.bio = bio; + rqd.meta_list = meta_list; + rqd.ppa_list = ppa_list; + rqd.dma_meta_list = dma_meta_list; + rqd.dma_ppa_list = dma_ppa_list; + rqd.opcode = NVM_OP_PREAD; + rqd.nr_ppas = rq_ppas; + + for (i = 0; i < rqd.nr_ppas; ) { + struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, line_id); + int pos = pblk_ppa_to_pos(geo, ppa); + + if (pblk_io_aligned(pblk, rq_ppas)) + rqd.is_seq = 1; + + while (test_bit(pos, line->blk_bitmap)) { + paddr += min; + if (pblk_boundary_paddr_checks(pblk, paddr)) { + bio_put(bio); + ret = -EINTR; + goto free_rqd_dma; + } + + ppa = addr_to_gen_ppa(pblk, paddr, line_id); + pos = pblk_ppa_to_pos(geo, ppa); + } + + if (pblk_boundary_paddr_checks(pblk, paddr + min)) { + bio_put(bio); + ret = -EINTR; + goto free_rqd_dma; + } + + for (j = 0; j < min; j++, i++, paddr++) + rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line_id); + } + + ret = pblk_submit_io_sync(pblk, &rqd); + if (ret) { + pblk_err(pblk, "emeta I/O submission failed: %d\n", ret); + bio_put(bio); + goto free_rqd_dma; + } + + atomic_dec(&pblk->inflight_io); + + if (rqd.error) + pblk_log_read_err(pblk, &rqd); + + emeta_buf += rq_len; + left_ppas -= rq_ppas; + if (left_ppas) + goto next_rq; + +free_rqd_dma: + nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list); + return ret; } static void pblk_setup_e_rq(struct pblk *pblk, struct nvm_rq *rqd, @@ -885,16 +929,17 @@ static void pblk_setup_e_rq(struct pblk *pblk, struct nvm_rq *rqd, rqd->opcode = NVM_OP_ERASE; rqd->ppa_addr = ppa; rqd->nr_ppas = 1; - rqd->flags = pblk_set_progr_mode(pblk, PBLK_ERASE); + rqd->is_seq = 1; rqd->bio = NULL; } static int pblk_blk_erase_sync(struct pblk *pblk, struct ppa_addr ppa) { - struct nvm_rq rqd; - int ret = 0; + struct nvm_rq rqd = {NULL}; + int ret; - memset(&rqd, 0, sizeof(struct nvm_rq)); + trace_pblk_chunk_reset(pblk_disk_name(pblk), &ppa, + PBLK_CHUNK_RESET_START); pblk_setup_e_rq(pblk, &rqd, ppa); @@ -902,19 +947,6 @@ static int pblk_blk_erase_sync(struct pblk *pblk, struct ppa_addr ppa) * with writes. Thus, there is no need to take the LUN semaphore. */ ret = pblk_submit_io_sync(pblk, &rqd); - if (ret) { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - - pblk_err(pblk, "could not sync erase line:%d,blk:%d\n", - pblk_ppa_to_line(ppa), - pblk_ppa_to_pos(geo, ppa)); - - rqd.error = ret; - goto out; - } - -out: rqd.private = pblk; __pblk_end_io_erase(pblk, &rqd); @@ -1008,6 +1040,8 @@ static int pblk_line_init_metadata(struct pblk *pblk, struct pblk_line *line, spin_lock(&l_mg->free_lock); spin_lock(&line->lock); line->state = PBLK_LINESTATE_BAD; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); spin_unlock(&line->lock); list_add_tail(&line->list, &l_mg->bad_list); @@ -1071,15 +1105,18 @@ static int pblk_line_init_metadata(struct pblk *pblk, struct pblk_line *line, static int pblk_line_alloc_bitmaps(struct pblk *pblk, struct pblk_line *line) { struct pblk_line_meta *lm = &pblk->lm; + struct pblk_line_mgmt *l_mg = &pblk->l_mg; - line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); + line->map_bitmap = mempool_alloc(l_mg->bitmap_pool, GFP_KERNEL); if (!line->map_bitmap) return -ENOMEM; + memset(line->map_bitmap, 0, lm->sec_bitmap_len); + /* will be initialized using bb info from map_bitmap */ - line->invalid_bitmap = kmalloc(lm->sec_bitmap_len, GFP_KERNEL); + line->invalid_bitmap = mempool_alloc(l_mg->bitmap_pool, GFP_KERNEL); if (!line->invalid_bitmap) { - kfree(line->map_bitmap); + mempool_free(line->map_bitmap, l_mg->bitmap_pool); line->map_bitmap = NULL; return -ENOMEM; } @@ -1122,7 +1159,7 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line, line->smeta_ssec = off; line->cur_sec = off + lm->smeta_sec; - if (init && pblk_line_submit_smeta_io(pblk, line, off, PBLK_WRITE)) { + if (init && pblk_line_smeta_write(pblk, line, off)) { pblk_debug(pblk, "line smeta I/O failed. Retry\n"); return 0; } @@ -1152,6 +1189,8 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line, bitmap_weight(line->invalid_bitmap, lm->sec_per_line)) { spin_lock(&line->lock); line->state = PBLK_LINESTATE_BAD; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); spin_unlock(&line->lock); list_add_tail(&line->list, &l_mg->bad_list); @@ -1204,6 +1243,8 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) if (line->state == PBLK_LINESTATE_NEW) { blk_to_erase = pblk_prepare_new_line(pblk, line); line->state = PBLK_LINESTATE_FREE; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); } else { blk_to_erase = blk_in_line; } @@ -1221,6 +1262,8 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) } line->state = PBLK_LINESTATE_OPEN; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); atomic_set(&line->left_eblks, blk_to_erase); atomic_set(&line->left_seblks, blk_to_erase); @@ -1265,7 +1308,9 @@ int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line) void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line) { - kfree(line->map_bitmap); + struct pblk_line_mgmt *l_mg = &pblk->l_mg; + + mempool_free(line->map_bitmap, l_mg->bitmap_pool); line->map_bitmap = NULL; line->smeta = NULL; line->emeta = NULL; @@ -1283,8 +1328,11 @@ static void pblk_line_reinit(struct pblk_line *line) void pblk_line_free(struct pblk_line *line) { - kfree(line->map_bitmap); - kfree(line->invalid_bitmap); + struct pblk *pblk = line->pblk; + struct pblk_line_mgmt *l_mg = &pblk->l_mg; + + mempool_free(line->map_bitmap, l_mg->bitmap_pool); + mempool_free(line->invalid_bitmap, l_mg->bitmap_pool); pblk_line_reinit(line); } @@ -1312,6 +1360,8 @@ retry: if (unlikely(bit >= lm->blk_per_line)) { spin_lock(&line->lock); line->state = PBLK_LINESTATE_BAD; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); spin_unlock(&line->lock); list_add_tail(&line->list, &l_mg->bad_list); @@ -1446,12 +1496,32 @@ retry_setup: return line; } +void pblk_ppa_to_line_put(struct pblk *pblk, struct ppa_addr ppa) +{ + struct pblk_line *line; + + line = pblk_ppa_to_line(pblk, ppa); + kref_put(&line->ref, pblk_line_put_wq); +} + +void pblk_rq_to_line_put(struct pblk *pblk, struct nvm_rq *rqd) +{ + struct ppa_addr *ppa_list; + int i; + + ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr; + + for (i = 0; i < rqd->nr_ppas; i++) + pblk_ppa_to_line_put(pblk, ppa_list[i]); +} + static void pblk_stop_writes(struct pblk *pblk, struct pblk_line *line) { lockdep_assert_held(&pblk->l_mg.free_lock); pblk_set_space_limit(pblk); pblk->state = PBLK_STATE_STOPPING; + trace_pblk_state(pblk_disk_name(pblk), pblk->state); } static void pblk_line_close_meta_sync(struct pblk *pblk) @@ -1501,6 +1571,7 @@ void __pblk_pipeline_flush(struct pblk *pblk) return; } pblk->state = PBLK_STATE_RECOVERING; + trace_pblk_state(pblk_disk_name(pblk), pblk->state); spin_unlock(&l_mg->free_lock); pblk_flush_writer(pblk); @@ -1522,6 +1593,7 @@ void __pblk_pipeline_stop(struct pblk *pblk) spin_lock(&l_mg->free_lock); pblk->state = PBLK_STATE_STOPPED; + trace_pblk_state(pblk_disk_name(pblk), pblk->state); l_mg->data_line = NULL; l_mg->data_next = NULL; spin_unlock(&l_mg->free_lock); @@ -1539,13 +1611,14 @@ struct pblk_line *pblk_line_replace_data(struct pblk *pblk) struct pblk_line *cur, *new = NULL; unsigned int left_seblks; - cur = l_mg->data_line; new = l_mg->data_next; if (!new) goto out; - l_mg->data_line = new; spin_lock(&l_mg->free_lock); + cur = l_mg->data_line; + l_mg->data_line = new; + pblk_line_setup_metadata(new, l_mg, &pblk->lm); spin_unlock(&l_mg->free_lock); @@ -1612,6 +1685,8 @@ static void __pblk_line_put(struct pblk *pblk, struct pblk_line *line) spin_lock(&line->lock); WARN_ON(line->state != PBLK_LINESTATE_GC); line->state = PBLK_LINESTATE_FREE; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); line->gc_group = PBLK_LINEGC_NONE; pblk_line_free(line); @@ -1680,6 +1755,9 @@ int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa) rqd->end_io = pblk_end_io_erase; rqd->private = pblk; + trace_pblk_chunk_reset(pblk_disk_name(pblk), + &ppa, PBLK_CHUNK_RESET_START); + /* The write thread schedules erases so that it minimizes disturbances * with writes. Thus, there is no need to take the LUN semaphore. */ @@ -1689,7 +1767,7 @@ int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa) struct nvm_geo *geo = &dev->geo; pblk_err(pblk, "could not async erase line:%d,blk:%d\n", - pblk_ppa_to_line(ppa), + pblk_ppa_to_line_id(ppa), pblk_ppa_to_pos(geo, ppa)); } @@ -1741,10 +1819,9 @@ void pblk_line_close(struct pblk *pblk, struct pblk_line *line) WARN_ON(line->state != PBLK_LINESTATE_OPEN); line->state = PBLK_LINESTATE_CLOSED; move_list = pblk_line_gc_list(pblk, line); - list_add_tail(&line->list, move_list); - kfree(line->map_bitmap); + mempool_free(line->map_bitmap, l_mg->bitmap_pool); line->map_bitmap = NULL; line->smeta = NULL; line->emeta = NULL; @@ -1760,6 +1837,9 @@ void pblk_line_close(struct pblk *pblk, struct pblk_line *line) spin_unlock(&line->lock); spin_unlock(&l_mg->gc_lock); + + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); } void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line) @@ -1778,6 +1858,17 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line) wa->pad = cpu_to_le64(atomic64_read(&pblk->pad_wa)); wa->gc = cpu_to_le64(atomic64_read(&pblk->gc_wa)); + if (le32_to_cpu(emeta_buf->header.identifier) != PBLK_MAGIC) { + emeta_buf->header.identifier = cpu_to_le32(PBLK_MAGIC); + memcpy(emeta_buf->header.uuid, pblk->instance_uuid, 16); + emeta_buf->header.id = cpu_to_le32(line->id); + emeta_buf->header.type = cpu_to_le16(line->type); + emeta_buf->header.version_major = EMETA_VERSION_MAJOR; + emeta_buf->header.version_minor = EMETA_VERSION_MINOR; + emeta_buf->header.crc = cpu_to_le32( + pblk_calc_meta_header_crc(pblk, &emeta_buf->header)); + } + emeta_buf->nr_valid_lbas = cpu_to_le64(line->nr_valid_lbas); emeta_buf->crc = cpu_to_le32(pblk_calc_emeta_crc(pblk, emeta_buf)); @@ -1795,8 +1886,6 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line) spin_unlock(&l_mg->close_lock); pblk_line_should_sync_meta(pblk); - - } static void pblk_save_lba_list(struct pblk *pblk, struct pblk_line *line) @@ -1847,8 +1936,7 @@ void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, queue_work(wq, &line_ws->ws); } -static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, - int nr_ppas, int pos) +static void __pblk_down_chunk(struct pblk *pblk, int pos) { struct pblk_lun *rlun = &pblk->luns[pos]; int ret; @@ -1857,13 +1945,6 @@ static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, * Only send one inflight I/O per LUN. Since we map at a page * granurality, all ppas in the I/O will map to the same LUN */ -#ifdef CONFIG_NVM_PBLK_DEBUG - int i; - - for (i = 1; i < nr_ppas; i++) - WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun || - ppa_list[0].a.ch != ppa_list[i].a.ch); -#endif ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(30000)); if (ret == -ETIME || ret == -EINTR) @@ -1871,21 +1952,21 @@ static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, -ret); } -void pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas) +void pblk_down_chunk(struct pblk *pblk, struct ppa_addr ppa) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - int pos = pblk_ppa_to_pos(geo, ppa_list[0]); + int pos = pblk_ppa_to_pos(geo, ppa); - __pblk_down_page(pblk, ppa_list, nr_ppas, pos); + __pblk_down_chunk(pblk, pos); } -void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, +void pblk_down_rq(struct pblk *pblk, struct ppa_addr ppa, unsigned long *lun_bitmap) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - int pos = pblk_ppa_to_pos(geo, ppa_list[0]); + int pos = pblk_ppa_to_pos(geo, ppa); /* If the LUN has been locked for this same request, do no attempt to * lock it again @@ -1893,30 +1974,21 @@ void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, if (test_and_set_bit(pos, lun_bitmap)) return; - __pblk_down_page(pblk, ppa_list, nr_ppas, pos); + __pblk_down_chunk(pblk, pos); } -void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas) +void pblk_up_chunk(struct pblk *pblk, struct ppa_addr ppa) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; struct pblk_lun *rlun; - int pos = pblk_ppa_to_pos(geo, ppa_list[0]); - -#ifdef CONFIG_NVM_PBLK_DEBUG - int i; - - for (i = 1; i < nr_ppas; i++) - WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun || - ppa_list[0].a.ch != ppa_list[i].a.ch); -#endif + int pos = pblk_ppa_to_pos(geo, ppa); rlun = &pblk->luns[pos]; up(&rlun->wr_sem); } -void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, - unsigned long *lun_bitmap) +void pblk_up_rq(struct pblk *pblk, unsigned long *lun_bitmap) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; @@ -2060,8 +2132,7 @@ void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas, /* If the L2P entry maps to a line, the reference is valid */ if (!pblk_ppa_empty(ppa) && !pblk_addr_in_cache(ppa)) { - int line_id = pblk_ppa_to_line(ppa); - struct pblk_line *line = &pblk->lines[line_id]; + struct pblk_line *line = pblk_ppa_to_line(pblk, ppa); kref_get(&line->ref); } diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c index 157c2567c9e8..2fa118c8eb71 100644 --- a/drivers/lightnvm/pblk-gc.c +++ b/drivers/lightnvm/pblk-gc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -16,8 +17,10 @@ */ #include "pblk.h" +#include "pblk-trace.h" #include <linux/delay.h> + static void pblk_gc_free_gc_rq(struct pblk_gc_rq *gc_rq) { if (gc_rq->data) @@ -64,6 +67,8 @@ static void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line) spin_lock(&line->lock); WARN_ON(line->state != PBLK_LINESTATE_GC); line->state = PBLK_LINESTATE_CLOSED; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); move_list = pblk_line_gc_list(pblk, line); spin_unlock(&line->lock); @@ -144,7 +149,7 @@ static __le64 *get_lba_list_from_emeta(struct pblk *pblk, if (!emeta_buf) return NULL; - ret = pblk_line_read_emeta(pblk, line, emeta_buf); + ret = pblk_line_emeta_read(pblk, line, emeta_buf); if (ret) { pblk_err(pblk, "line %d read emeta failed (%d)\n", line->id, ret); @@ -405,6 +410,8 @@ void pblk_gc_free_full_lines(struct pblk *pblk) spin_lock(&line->lock); WARN_ON(line->state != PBLK_LINESTATE_CLOSED); line->state = PBLK_LINESTATE_GC; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); spin_unlock(&line->lock); list_del(&line->list); @@ -451,6 +458,8 @@ next_gc_group: spin_lock(&line->lock); WARN_ON(line->state != PBLK_LINESTATE_CLOSED); line->state = PBLK_LINESTATE_GC; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); spin_unlock(&line->lock); list_del(&line->list); diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 537e98f2b24a..13822594647c 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015 IT University of Copenhagen (rrpc.c) * Copyright (C) 2016 CNEX Labs @@ -19,15 +20,31 @@ */ #include "pblk.h" +#include "pblk-trace.h" static unsigned int write_buffer_size; module_param(write_buffer_size, uint, 0644); MODULE_PARM_DESC(write_buffer_size, "number of entries in a write buffer"); -static struct kmem_cache *pblk_ws_cache, *pblk_rec_cache, *pblk_g_rq_cache, - *pblk_w_rq_cache; -static DECLARE_RWSEM(pblk_lock); +struct pblk_global_caches { + struct kmem_cache *ws; + struct kmem_cache *rec; + struct kmem_cache *g_rq; + struct kmem_cache *w_rq; + + struct kref kref; + + struct mutex mutex; /* Ensures consistency between + * caches and kref + */ +}; + +static struct pblk_global_caches pblk_caches = { + .mutex = __MUTEX_INITIALIZER(pblk_caches.mutex), + .kref = KREF_INIT(0), +}; + struct bio_set pblk_bio_set; static int pblk_rw_io(struct request_queue *q, struct pblk *pblk, @@ -168,36 +185,26 @@ static void pblk_rwb_free(struct pblk *pblk) if (pblk_rb_tear_down_check(&pblk->rwb)) pblk_err(pblk, "write buffer error on tear down\n"); - pblk_rb_data_free(&pblk->rwb); - vfree(pblk_rb_entries_ref(&pblk->rwb)); + pblk_rb_free(&pblk->rwb); } static int pblk_rwb_init(struct pblk *pblk) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - struct pblk_rb_entry *entries; - unsigned long nr_entries, buffer_size; - unsigned int power_size, power_seg_sz; - int pgs_in_buffer; + unsigned long buffer_size; + int pgs_in_buffer, threshold; - pgs_in_buffer = max(geo->mw_cunits, geo->ws_opt) * geo->all_luns; + threshold = geo->mw_cunits * geo->all_luns; + pgs_in_buffer = (max(geo->mw_cunits, geo->ws_opt) + geo->ws_opt) + * geo->all_luns; if (write_buffer_size && (write_buffer_size > pgs_in_buffer)) buffer_size = write_buffer_size; else buffer_size = pgs_in_buffer; - nr_entries = pblk_rb_calculate_size(buffer_size); - - entries = vzalloc(array_size(nr_entries, sizeof(struct pblk_rb_entry))); - if (!entries) - return -ENOMEM; - - power_size = get_count_order(nr_entries); - power_seg_sz = get_count_order(geo->csecs); - - return pblk_rb_init(&pblk->rwb, entries, power_size, power_seg_sz); + return pblk_rb_init(&pblk->rwb, buffer_size, threshold, geo->csecs); } /* Minimum pages needed within a lun */ @@ -306,53 +313,80 @@ static int pblk_set_addrf(struct pblk *pblk) return 0; } -static int pblk_init_global_caches(struct pblk *pblk) +static int pblk_create_global_caches(void) { - down_write(&pblk_lock); - pblk_ws_cache = kmem_cache_create("pblk_blk_ws", + + pblk_caches.ws = kmem_cache_create("pblk_blk_ws", sizeof(struct pblk_line_ws), 0, 0, NULL); - if (!pblk_ws_cache) { - up_write(&pblk_lock); + if (!pblk_caches.ws) return -ENOMEM; - } - pblk_rec_cache = kmem_cache_create("pblk_rec", + pblk_caches.rec = kmem_cache_create("pblk_rec", sizeof(struct pblk_rec_ctx), 0, 0, NULL); - if (!pblk_rec_cache) { - kmem_cache_destroy(pblk_ws_cache); - up_write(&pblk_lock); - return -ENOMEM; - } + if (!pblk_caches.rec) + goto fail_destroy_ws; - pblk_g_rq_cache = kmem_cache_create("pblk_g_rq", pblk_g_rq_size, + pblk_caches.g_rq = kmem_cache_create("pblk_g_rq", pblk_g_rq_size, 0, 0, NULL); - if (!pblk_g_rq_cache) { - kmem_cache_destroy(pblk_ws_cache); - kmem_cache_destroy(pblk_rec_cache); - up_write(&pblk_lock); - return -ENOMEM; - } + if (!pblk_caches.g_rq) + goto fail_destroy_rec; - pblk_w_rq_cache = kmem_cache_create("pblk_w_rq", pblk_w_rq_size, + pblk_caches.w_rq = kmem_cache_create("pblk_w_rq", pblk_w_rq_size, 0, 0, NULL); - if (!pblk_w_rq_cache) { - kmem_cache_destroy(pblk_ws_cache); - kmem_cache_destroy(pblk_rec_cache); - kmem_cache_destroy(pblk_g_rq_cache); - up_write(&pblk_lock); - return -ENOMEM; - } - up_write(&pblk_lock); + if (!pblk_caches.w_rq) + goto fail_destroy_g_rq; return 0; + +fail_destroy_g_rq: + kmem_cache_destroy(pblk_caches.g_rq); +fail_destroy_rec: + kmem_cache_destroy(pblk_caches.rec); +fail_destroy_ws: + kmem_cache_destroy(pblk_caches.ws); + + return -ENOMEM; } -static void pblk_free_global_caches(struct pblk *pblk) +static int pblk_get_global_caches(void) { - kmem_cache_destroy(pblk_ws_cache); - kmem_cache_destroy(pblk_rec_cache); - kmem_cache_destroy(pblk_g_rq_cache); - kmem_cache_destroy(pblk_w_rq_cache); + int ret; + + mutex_lock(&pblk_caches.mutex); + + if (kref_read(&pblk_caches.kref) > 0) { + kref_get(&pblk_caches.kref); + mutex_unlock(&pblk_caches.mutex); + return 0; + } + + ret = pblk_create_global_caches(); + + if (!ret) + kref_get(&pblk_caches.kref); + + mutex_unlock(&pblk_caches.mutex); + + return ret; +} + +static void pblk_destroy_global_caches(struct kref *ref) +{ + struct pblk_global_caches *c; + + c = container_of(ref, struct pblk_global_caches, kref); + + kmem_cache_destroy(c->ws); + kmem_cache_destroy(c->rec); + kmem_cache_destroy(c->g_rq); + kmem_cache_destroy(c->w_rq); +} + +static void pblk_put_global_caches(void) +{ + mutex_lock(&pblk_caches.mutex); + kref_put(&pblk_caches.kref, pblk_destroy_global_caches); + mutex_unlock(&pblk_caches.mutex); } static int pblk_core_init(struct pblk *pblk) @@ -371,23 +405,19 @@ static int pblk_core_init(struct pblk *pblk) atomic64_set(&pblk->nr_flush, 0); pblk->nr_flush_rst = 0; - pblk->min_write_pgs = geo->ws_opt * (geo->csecs / PAGE_SIZE); + pblk->min_write_pgs = geo->ws_opt; max_write_ppas = pblk->min_write_pgs * geo->all_luns; pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA); + pblk->max_write_pgs = min_t(int, pblk->max_write_pgs, + queue_max_hw_sectors(dev->q) / (geo->csecs >> SECTOR_SHIFT)); pblk_set_sec_per_write(pblk, pblk->min_write_pgs); - if (pblk->max_write_pgs > PBLK_MAX_REQ_ADDRS) { - pblk_err(pblk, "vector list too big(%u > %u)\n", - pblk->max_write_pgs, PBLK_MAX_REQ_ADDRS); - return -EINVAL; - } - pblk->pad_dist = kcalloc(pblk->min_write_pgs - 1, sizeof(atomic64_t), GFP_KERNEL); if (!pblk->pad_dist) return -ENOMEM; - if (pblk_init_global_caches(pblk)) + if (pblk_get_global_caches()) goto fail_free_pad_dist; /* Internal bios can be at most the sectors signaled by the device. */ @@ -396,27 +426,27 @@ static int pblk_core_init(struct pblk *pblk) goto free_global_caches; ret = mempool_init_slab_pool(&pblk->gen_ws_pool, PBLK_GEN_WS_POOL_SIZE, - pblk_ws_cache); + pblk_caches.ws); if (ret) goto free_page_bio_pool; ret = mempool_init_slab_pool(&pblk->rec_pool, geo->all_luns, - pblk_rec_cache); + pblk_caches.rec); if (ret) goto free_gen_ws_pool; ret = mempool_init_slab_pool(&pblk->r_rq_pool, geo->all_luns, - pblk_g_rq_cache); + pblk_caches.g_rq); if (ret) goto free_rec_pool; ret = mempool_init_slab_pool(&pblk->e_rq_pool, geo->all_luns, - pblk_g_rq_cache); + pblk_caches.g_rq); if (ret) goto free_r_rq_pool; ret = mempool_init_slab_pool(&pblk->w_rq_pool, geo->all_luns, - pblk_w_rq_cache); + pblk_caches.w_rq); if (ret) goto free_e_rq_pool; @@ -462,7 +492,7 @@ free_gen_ws_pool: free_page_bio_pool: mempool_exit(&pblk->page_bio_pool); free_global_caches: - pblk_free_global_caches(pblk); + pblk_put_global_caches(); fail_free_pad_dist: kfree(pblk->pad_dist); return -ENOMEM; @@ -486,7 +516,7 @@ static void pblk_core_free(struct pblk *pblk) mempool_exit(&pblk->e_rq_pool); mempool_exit(&pblk->w_rq_pool); - pblk_free_global_caches(pblk); + pblk_put_global_caches(); kfree(pblk->pad_dist); } @@ -504,6 +534,9 @@ static void pblk_line_mg_free(struct pblk *pblk) pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type); kfree(l_mg->eline_meta[i]); } + + mempool_destroy(l_mg->bitmap_pool); + kmem_cache_destroy(l_mg->bitmap_cache); } static void pblk_line_meta_free(struct pblk_line_mgmt *l_mg, @@ -540,67 +573,6 @@ static void pblk_lines_free(struct pblk *pblk) kfree(pblk->lines); } -static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun, - u8 *blks, int nr_blks) -{ - struct ppa_addr ppa; - int ret; - - ppa.ppa = 0; - ppa.g.ch = rlun->bppa.g.ch; - ppa.g.lun = rlun->bppa.g.lun; - - ret = nvm_get_tgt_bb_tbl(dev, ppa, blks); - if (ret) - return ret; - - nr_blks = nvm_bb_tbl_fold(dev->parent, blks, nr_blks); - if (nr_blks < 0) - return -EIO; - - return 0; -} - -static void *pblk_bb_get_meta(struct pblk *pblk) -{ - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - u8 *meta; - int i, nr_blks, blk_per_lun; - int ret; - - blk_per_lun = geo->num_chk * geo->pln_mode; - nr_blks = blk_per_lun * geo->all_luns; - - meta = kmalloc(nr_blks, GFP_KERNEL); - if (!meta) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < geo->all_luns; i++) { - struct pblk_lun *rlun = &pblk->luns[i]; - u8 *meta_pos = meta + i * blk_per_lun; - - ret = pblk_bb_get_tbl(dev, rlun, meta_pos, blk_per_lun); - if (ret) { - kfree(meta); - return ERR_PTR(-EIO); - } - } - - return meta; -} - -static void *pblk_chunk_get_meta(struct pblk *pblk) -{ - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - - if (geo->version == NVM_OCSSD_SPEC_12) - return pblk_bb_get_meta(pblk); - else - return pblk_chunk_get_info(pblk); -} - static int pblk_luns_init(struct pblk *pblk) { struct nvm_tgt_dev *dev = pblk->dev; @@ -699,51 +671,7 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); } -static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line, - void *chunk_meta) -{ - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - struct pblk_line_meta *lm = &pblk->lm; - int i, chk_per_lun, nr_bad_chks = 0; - - chk_per_lun = geo->num_chk * geo->pln_mode; - - for (i = 0; i < lm->blk_per_line; i++) { - struct pblk_lun *rlun = &pblk->luns[i]; - struct nvm_chk_meta *chunk; - int pos = pblk_ppa_to_pos(geo, rlun->bppa); - u8 *lun_bb_meta = chunk_meta + pos * chk_per_lun; - - chunk = &line->chks[pos]; - - /* - * In 1.2 spec. chunk state is not persisted by the device. Thus - * some of the values are reset each time pblk is instantiated, - * so we have to assume that the block is closed. - */ - if (lun_bb_meta[line->id] == NVM_BLK_T_FREE) - chunk->state = NVM_CHK_ST_CLOSED; - else - chunk->state = NVM_CHK_ST_OFFLINE; - - chunk->type = NVM_CHK_TP_W_SEQ; - chunk->wi = 0; - chunk->slba = -1; - chunk->cnlb = geo->clba; - chunk->wp = 0; - - if (!(chunk->state & NVM_CHK_ST_OFFLINE)) - continue; - - set_bit(pos, line->blk_bitmap); - nr_bad_chks++; - } - - return nr_bad_chks; -} - -static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line, +static int pblk_setup_line_meta_chk(struct pblk *pblk, struct pblk_line *line, struct nvm_chk_meta *meta) { struct nvm_tgt_dev *dev = pblk->dev; @@ -772,6 +700,9 @@ static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line, chunk->cnlb = chunk_meta->cnlb; chunk->wp = chunk_meta->wp; + trace_pblk_chunk_state(pblk_disk_name(pblk), &ppa, + chunk->state); + if (chunk->type & NVM_CHK_TP_SZ_SPEC) { WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n"); continue; @@ -790,8 +721,6 @@ static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line, static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, void *chunk_meta, int line_id) { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; long nr_bad_chks, chk_in_line; @@ -804,10 +733,7 @@ static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, line->vsc = &l_mg->vsc_list[line_id]; spin_lock_init(&line->lock); - if (geo->version == NVM_OCSSD_SPEC_12) - nr_bad_chks = pblk_setup_line_meta_12(pblk, line, chunk_meta); - else - nr_bad_chks = pblk_setup_line_meta_20(pblk, line, chunk_meta); + nr_bad_chks = pblk_setup_line_meta_chk(pblk, line, chunk_meta); chk_in_line = lm->blk_per_line - nr_bad_chks; if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line || @@ -913,6 +839,17 @@ static int pblk_line_mg_init(struct pblk *pblk) goto fail_free_smeta; } + l_mg->bitmap_cache = kmem_cache_create("pblk_lm_bitmap", + lm->sec_bitmap_len, 0, 0, NULL); + if (!l_mg->bitmap_cache) + goto fail_free_smeta; + + /* the bitmap pool is used for both valid and map bitmaps */ + l_mg->bitmap_pool = mempool_create_slab_pool(PBLK_DATA_LINES * 2, + l_mg->bitmap_cache); + if (!l_mg->bitmap_pool) + goto fail_destroy_bitmap_cache; + /* emeta allocates three different buffers for managing metadata with * in-memory and in-media layouts */ @@ -965,6 +902,10 @@ fail_free_emeta: kfree(l_mg->eline_meta[i]->buf); kfree(l_mg->eline_meta[i]); } + + mempool_destroy(l_mg->bitmap_pool); +fail_destroy_bitmap_cache: + kmem_cache_destroy(l_mg->bitmap_cache); fail_free_smeta: for (i = 0; i < PBLK_DATA_LINES; i++) kfree(l_mg->sline_meta[i]); @@ -1058,7 +999,7 @@ static int pblk_lines_init(struct pblk *pblk) if (ret) goto fail_free_meta; - chunk_meta = pblk_chunk_get_meta(pblk); + chunk_meta = pblk_get_chunk_meta(pblk); if (IS_ERR(chunk_meta)) { ret = PTR_ERR(chunk_meta); goto fail_free_luns; @@ -1079,16 +1020,20 @@ static int pblk_lines_init(struct pblk *pblk) goto fail_free_lines; nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i); + + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); } if (!nr_free_chks) { pblk_err(pblk, "too many bad blocks prevent for sane instance\n"); - return -EINTR; + ret = -EINTR; + goto fail_free_lines; } pblk_set_provision(pblk, nr_free_chks); - kfree(chunk_meta); + vfree(chunk_meta); return 0; fail_free_lines: @@ -1165,7 +1110,6 @@ static void pblk_exit(void *private, bool graceful) { struct pblk *pblk = private; - down_write(&pblk_lock); pblk_gc_exit(pblk, graceful); pblk_tear_down(pblk, graceful); @@ -1174,7 +1118,6 @@ static void pblk_exit(void *private, bool graceful) #endif pblk_free(pblk); - up_write(&pblk_lock); } static sector_t pblk_capacity(void *private) @@ -1200,6 +1143,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, pblk->dev = dev; pblk->disk = tdisk; pblk->state = PBLK_STATE_RUNNING; + trace_pblk_state(pblk_disk_name(pblk), pblk->state); pblk->gc.gc_enabled = 0; if (!(geo->version == NVM_OCSSD_SPEC_12 || @@ -1210,13 +1154,6 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, return ERR_PTR(-EINVAL); } - if (geo->version == NVM_OCSSD_SPEC_12 && geo->dom & NVM_RSP_L2P) { - pblk_err(pblk, "host-side L2P table not supported. (%x)\n", - geo->dom); - kfree(pblk); - return ERR_PTR(-EINVAL); - } - spin_lock_init(&pblk->resubmit_lock); spin_lock_init(&pblk->trans_lock); spin_lock_init(&pblk->lock); diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c index 953ca31dda68..6dcbd44e3acb 100644 --- a/drivers/lightnvm/pblk-map.c +++ b/drivers/lightnvm/pblk-map.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -79,7 +80,7 @@ static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry, } } - pblk_down_rq(pblk, ppa_list, nr_secs, lun_bitmap); + pblk_down_rq(pblk, ppa_list[0], lun_bitmap); return 0; } @@ -88,13 +89,14 @@ void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, unsigned int off) { struct pblk_sec_meta *meta_list = rqd->meta_list; + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); unsigned int map_secs; int min = pblk->min_write_pgs; int i; for (i = off; i < rqd->nr_ppas; i += min) { map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; - if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], + if (pblk_map_page_data(pblk, sentry + i, &ppa_list[i], lun_bitmap, &meta_list[i], map_secs)) { bio_put(rqd->bio); pblk_free_rqd(pblk, rqd, PBLK_WRITE); @@ -112,6 +114,7 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, struct nvm_geo *geo = &dev->geo; struct pblk_line_meta *lm = &pblk->lm; struct pblk_sec_meta *meta_list = rqd->meta_list; + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); struct pblk_line *e_line, *d_line; unsigned int map_secs; int min = pblk->min_write_pgs; @@ -119,14 +122,14 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, for (i = 0; i < rqd->nr_ppas; i += min) { map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; - if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], + if (pblk_map_page_data(pblk, sentry + i, &ppa_list[i], lun_bitmap, &meta_list[i], map_secs)) { bio_put(rqd->bio); pblk_free_rqd(pblk, rqd, PBLK_WRITE); pblk_pipeline_stop(pblk); } - erase_lun = pblk_ppa_to_pos(geo, rqd->ppa_list[i]); + erase_lun = pblk_ppa_to_pos(geo, ppa_list[i]); /* line can change after page map. We might also be writing the * last line. @@ -141,7 +144,7 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, set_bit(erase_lun, e_line->erase_bitmap); atomic_dec(&e_line->left_eblks); - *erase_ppa = rqd->ppa_list[i]; + *erase_ppa = ppa_list[i]; erase_ppa->a.blk = e_line->id; spin_unlock(&e_line->lock); diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c index f6eec0212dfc..b1f4b51783f4 100644 --- a/drivers/lightnvm/pblk-rb.c +++ b/drivers/lightnvm/pblk-rb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -22,7 +23,7 @@ static DECLARE_RWSEM(pblk_rb_lock); -void pblk_rb_data_free(struct pblk_rb *rb) +static void pblk_rb_data_free(struct pblk_rb *rb) { struct pblk_rb_pages *p, *t; @@ -35,25 +36,51 @@ void pblk_rb_data_free(struct pblk_rb *rb) up_write(&pblk_rb_lock); } +void pblk_rb_free(struct pblk_rb *rb) +{ + pblk_rb_data_free(rb); + vfree(rb->entries); +} + +/* + * pblk_rb_calculate_size -- calculate the size of the write buffer + */ +static unsigned int pblk_rb_calculate_size(unsigned int nr_entries) +{ + /* Alloc a write buffer that can at least fit 128 entries */ + return (1 << max(get_count_order(nr_entries), 7)); +} + /* * Initialize ring buffer. The data and metadata buffers must be previously * allocated and their size must be a power of two * (Documentation/core-api/circular-buffers.rst) */ -int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base, - unsigned int power_size, unsigned int power_seg_sz) +int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold, + unsigned int seg_size) { struct pblk *pblk = container_of(rb, struct pblk, rwb); + struct pblk_rb_entry *entries; unsigned int init_entry = 0; - unsigned int alloc_order = power_size; unsigned int max_order = MAX_ORDER - 1; - unsigned int order, iter; + unsigned int power_size, power_seg_sz; + unsigned int alloc_order, order, iter; + unsigned int nr_entries; + + nr_entries = pblk_rb_calculate_size(size); + entries = vzalloc(array_size(nr_entries, sizeof(struct pblk_rb_entry))); + if (!entries) + return -ENOMEM; + + power_size = get_count_order(size); + power_seg_sz = get_count_order(seg_size); down_write(&pblk_rb_lock); - rb->entries = rb_entry_base; + rb->entries = entries; rb->seg_size = (1 << power_seg_sz); rb->nr_entries = (1 << power_size); rb->mem = rb->subm = rb->sync = rb->l2p_update = 0; + rb->back_thres = threshold; rb->flush_point = EMPTY_ENTRY; spin_lock_init(&rb->w_lock); @@ -61,6 +88,7 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base, INIT_LIST_HEAD(&rb->pages); + alloc_order = power_size; if (alloc_order >= max_order) { order = max_order; iter = (1 << (alloc_order - max_order)); @@ -79,6 +107,7 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base, page_set = kmalloc(sizeof(struct pblk_rb_pages), GFP_KERNEL); if (!page_set) { up_write(&pblk_rb_lock); + vfree(entries); return -ENOMEM; } @@ -88,6 +117,7 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base, kfree(page_set); pblk_rb_data_free(rb); up_write(&pblk_rb_lock); + vfree(entries); return -ENOMEM; } kaddr = page_address(page_set->pages); @@ -124,20 +154,6 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base, return 0; } -/* - * pblk_rb_calculate_size -- calculate the size of the write buffer - */ -unsigned int pblk_rb_calculate_size(unsigned int nr_entries) -{ - /* Alloc a write buffer that can at least fit 128 entries */ - return (1 << max(get_count_order(nr_entries), 7)); -} - -void *pblk_rb_entries_ref(struct pblk_rb *rb) -{ - return rb->entries; -} - static void clean_wctx(struct pblk_w_ctx *w_ctx) { int flags; @@ -168,6 +184,12 @@ static unsigned int pblk_rb_space(struct pblk_rb *rb) return pblk_rb_ring_space(rb, mem, sync, rb->nr_entries); } +unsigned int pblk_rb_ptr_wrap(struct pblk_rb *rb, unsigned int p, + unsigned int nr_entries) +{ + return (p + nr_entries) & (rb->nr_entries - 1); +} + /* * Buffer count is calculated with respect to the submission entry signaling the * entries that are available to send to the media @@ -194,8 +216,7 @@ unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int nr_entries) subm = READ_ONCE(rb->subm); /* Commit read means updating submission pointer */ - smp_store_release(&rb->subm, - (subm + nr_entries) & (rb->nr_entries - 1)); + smp_store_release(&rb->subm, pblk_rb_ptr_wrap(rb, subm, nr_entries)); return subm; } @@ -225,10 +246,10 @@ static int __pblk_rb_update_l2p(struct pblk_rb *rb, unsigned int to_update) pblk_update_map_dev(pblk, w_ctx->lba, w_ctx->ppa, entry->cacheline); - line = &pblk->lines[pblk_ppa_to_line(w_ctx->ppa)]; + line = pblk_ppa_to_line(pblk, w_ctx->ppa); kref_put(&line->ref, pblk_line_put); clean_wctx(w_ctx); - rb->l2p_update = (rb->l2p_update + 1) & (rb->nr_entries - 1); + rb->l2p_update = pblk_rb_ptr_wrap(rb, rb->l2p_update, 1); } pblk_rl_out(&pblk->rl, user_io, gc_io); @@ -385,11 +406,14 @@ static int __pblk_rb_may_write(struct pblk_rb *rb, unsigned int nr_entries, { unsigned int mem; unsigned int sync; + unsigned int threshold; sync = READ_ONCE(rb->sync); mem = READ_ONCE(rb->mem); - if (pblk_rb_ring_space(rb, mem, sync, rb->nr_entries) < nr_entries) + threshold = nr_entries + rb->back_thres; + + if (pblk_rb_ring_space(rb, mem, sync, rb->nr_entries) < threshold) return 0; if (pblk_rb_update_l2p(rb, nr_entries, mem, sync)) @@ -407,7 +431,7 @@ static int pblk_rb_may_write(struct pblk_rb *rb, unsigned int nr_entries, return 0; /* Protect from read count */ - smp_store_release(&rb->mem, (*pos + nr_entries) & (rb->nr_entries - 1)); + smp_store_release(&rb->mem, pblk_rb_ptr_wrap(rb, *pos, nr_entries)); return 1; } @@ -431,7 +455,7 @@ static int pblk_rb_may_write_flush(struct pblk_rb *rb, unsigned int nr_entries, if (!__pblk_rb_may_write(rb, nr_entries, pos)) return 0; - mem = (*pos + nr_entries) & (rb->nr_entries - 1); + mem = pblk_rb_ptr_wrap(rb, *pos, nr_entries); *io_ret = NVM_IO_DONE; if (bio->bi_opf & REQ_PREFLUSH) { @@ -571,7 +595,7 @@ try: /* Release flags on context. Protect from writes */ smp_store_release(&entry->w_ctx.flags, flags); - pos = (pos + 1) & (rb->nr_entries - 1); + pos = pblk_rb_ptr_wrap(rb, pos, 1); } if (pad) { @@ -651,7 +675,7 @@ out: struct pblk_w_ctx *pblk_rb_w_ctx(struct pblk_rb *rb, unsigned int pos) { - unsigned int entry = pos & (rb->nr_entries - 1); + unsigned int entry = pblk_rb_ptr_wrap(rb, pos, 0); return &rb->entries[entry].w_ctx; } @@ -697,7 +721,7 @@ unsigned int pblk_rb_sync_advance(struct pblk_rb *rb, unsigned int nr_entries) } } - sync = (sync + nr_entries) & (rb->nr_entries - 1); + sync = pblk_rb_ptr_wrap(rb, sync, nr_entries); /* Protect from counts */ smp_store_release(&rb->sync, sync); @@ -728,32 +752,6 @@ unsigned int pblk_rb_flush_point_count(struct pblk_rb *rb) return (submitted < to_flush) ? (to_flush - submitted) : 0; } -/* - * Scan from the current position of the sync pointer to find the entry that - * corresponds to the given ppa. This is necessary since write requests can be - * completed out of order. The assumption is that the ppa is close to the sync - * pointer thus the search will not take long. - * - * The caller of this function must guarantee that the sync pointer will no - * reach the entry while it is using the metadata associated with it. With this - * assumption in mind, there is no need to take the sync lock. - */ -struct pblk_rb_entry *pblk_rb_sync_scan_entry(struct pblk_rb *rb, - struct ppa_addr *ppa) -{ - unsigned int sync, subm, count; - unsigned int i; - - sync = READ_ONCE(rb->sync); - subm = READ_ONCE(rb->subm); - count = pblk_rb_ring_count(subm, sync, rb->nr_entries); - - for (i = 0; i < count; i++) - sync = (sync + 1) & (rb->nr_entries - 1); - - return NULL; -} - int pblk_rb_tear_down_check(struct pblk_rb *rb) { struct pblk_rb_entry *entry; diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c index 5a46d7f9302f..9fba614adeeb 100644 --- a/drivers/lightnvm/pblk-read.c +++ b/drivers/lightnvm/pblk-read.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -43,7 +44,7 @@ static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned long *read_bitmap) { struct pblk_sec_meta *meta_list = rqd->meta_list; - struct ppa_addr ppas[PBLK_MAX_REQ_ADDRS]; + struct ppa_addr ppas[NVM_MAX_VLBA]; int nr_secs = rqd->nr_ppas; bool advanced_bio = false; int i, j = 0; @@ -93,9 +94,7 @@ next: } if (pblk_io_aligned(pblk, nr_secs)) - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL); - else - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM); + rqd->is_seq = 1; #ifdef CONFIG_NVM_PBLK_DEBUG atomic_long_add(nr_secs, &pblk->inflight_reads); @@ -118,10 +117,9 @@ static void pblk_read_check_seq(struct pblk *pblk, struct nvm_rq *rqd, if (lba != blba + i) { #ifdef CONFIG_NVM_PBLK_DEBUG - struct ppa_addr *p; + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); - p = (nr_lbas == 1) ? &rqd->ppa_list[i] : &rqd->ppa_addr; - print_ppa(pblk, p, "seq", i); + print_ppa(pblk, &ppa_list[i], "seq", i); #endif pblk_err(pblk, "corrupted read LBA (%llu/%llu)\n", lba, (u64)blba + i); @@ -150,14 +148,12 @@ static void pblk_read_check_rand(struct pblk *pblk, struct nvm_rq *rqd, if (lba != meta_lba) { #ifdef CONFIG_NVM_PBLK_DEBUG - struct ppa_addr *p; - int nr_ppas = rqd->nr_ppas; + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); - p = (nr_ppas == 1) ? &rqd->ppa_list[j] : &rqd->ppa_addr; - print_ppa(pblk, p, "seq", j); + print_ppa(pblk, &ppa_list[j], "rnd", j); #endif pblk_err(pblk, "corrupted read LBA (%llu/%llu)\n", - lba, meta_lba); + meta_lba, lba); WARN_ON(1); } @@ -167,22 +163,6 @@ static void pblk_read_check_rand(struct pblk *pblk, struct nvm_rq *rqd, WARN_ONCE(j != rqd->nr_ppas, "pblk: corrupted random request\n"); } -static void pblk_read_put_rqd_kref(struct pblk *pblk, struct nvm_rq *rqd) -{ - struct ppa_addr *ppa_list; - int i; - - ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr; - - for (i = 0; i < rqd->nr_ppas; i++) { - struct ppa_addr ppa = ppa_list[i]; - struct pblk_line *line; - - line = &pblk->lines[pblk_ppa_to_line(ppa)]; - kref_put(&line->ref, pblk_line_put_wq); - } -} - static void pblk_end_user_read(struct bio *bio) { #ifdef CONFIG_NVM_PBLK_DEBUG @@ -210,7 +190,7 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd, bio_put(int_bio); if (put_line) - pblk_read_put_rqd_kref(pblk, rqd); + pblk_rq_to_line_put(pblk, rqd); #ifdef CONFIG_NVM_PBLK_DEBUG atomic_long_add(rqd->nr_ppas, &pblk->sync_reads); @@ -270,9 +250,9 @@ static void pblk_end_partial_read(struct nvm_rq *rqd) i = 0; hole = find_first_zero_bit(read_bitmap, nr_secs); do { - int line_id = pblk_ppa_to_line(rqd->ppa_list[i]); - struct pblk_line *line = &pblk->lines[line_id]; + struct pblk_line *line; + line = pblk_ppa_to_line(pblk, rqd->ppa_list[i]); kref_put(&line->ref, pblk_line_put); meta_list[hole].lba = lba_list_media[i]; @@ -344,7 +324,6 @@ static int pblk_setup_partial_read(struct pblk *pblk, struct nvm_rq *rqd, rqd->bio = new_bio; rqd->nr_ppas = nr_holes; - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM); pr_ctx->ppa_ptr = NULL; pr_ctx->orig_bio = bio; @@ -438,8 +417,6 @@ retry: } else { rqd->ppa_addr = ppa; } - - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM); } int pblk_submit_read(struct pblk *pblk, struct bio *bio) @@ -454,13 +431,6 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio) DECLARE_BITMAP(read_bitmap, NVM_MAX_VLBA); int ret = NVM_IO_ERR; - /* logic error: lba out-of-bounds. Ignore read request */ - if (blba >= pblk->rl.nr_secs || nr_secs > PBLK_MAX_REQ_ADDRS) { - WARN(1, "pblk: read lba out of bounds (lba:%llu, nr:%d)\n", - (unsigned long long)blba, nr_secs); - return NVM_IO_ERR; - } - generic_start_io_acct(q, REQ_OP_READ, bio_sectors(bio), &pblk->disk->part0); @@ -484,21 +454,13 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio) */ bio_init_idx = pblk_get_bi_idx(bio); - rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, - &rqd->dma_meta_list); - if (!rqd->meta_list) { - pblk_err(pblk, "not able to allocate ppa list\n"); + if (pblk_alloc_rqd_meta(pblk, rqd)) goto fail_rqd_free; - } - - if (nr_secs > 1) { - rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size; - rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size; + if (nr_secs > 1) pblk_read_ppalist_rq(pblk, rqd, bio, blba, read_bitmap); - } else { + else pblk_read_rq(pblk, rqd, bio, blba, read_bitmap); - } if (bitmap_full(read_bitmap, nr_secs)) { atomic_inc(&pblk->inflight_io); @@ -552,7 +514,7 @@ static int read_ppalist_rq_gc(struct pblk *pblk, struct nvm_rq *rqd, struct pblk_line *line, u64 *lba_list, u64 *paddr_list_gc, unsigned int nr_secs) { - struct ppa_addr ppa_list_l2p[PBLK_MAX_REQ_ADDRS]; + struct ppa_addr ppa_list_l2p[NVM_MAX_VLBA]; struct ppa_addr ppa_gc; int valid_secs = 0; int i; @@ -625,15 +587,11 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) memset(&rqd, 0, sizeof(struct nvm_rq)); - rqd.meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, - &rqd.dma_meta_list); - if (!rqd.meta_list) - return -ENOMEM; + ret = pblk_alloc_rqd_meta(pblk, &rqd); + if (ret) + return ret; if (gc_rq->nr_secs > 1) { - rqd.ppa_list = rqd.meta_list + pblk_dma_meta_size; - rqd.dma_ppa_list = rqd.dma_meta_list + pblk_dma_meta_size; - gc_rq->secs_to_gc = read_ppalist_rq_gc(pblk, &rqd, gc_rq->line, gc_rq->lba_list, gc_rq->paddr_list, @@ -654,7 +612,8 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) PBLK_VMALLOC_META, GFP_KERNEL); if (IS_ERR(bio)) { pblk_err(pblk, "could not allocate GC bio (%lu)\n", - PTR_ERR(bio)); + PTR_ERR(bio)); + ret = PTR_ERR(bio); goto err_free_dma; } @@ -663,7 +622,6 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) rqd.opcode = NVM_OP_PREAD; rqd.nr_ppas = gc_rq->secs_to_gc; - rqd.flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM); rqd.bio = bio; if (pblk_submit_io_sync(pblk, &rqd)) { @@ -690,12 +648,12 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) #endif out: - nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list); + pblk_free_rqd_meta(pblk, &rqd); return ret; err_free_bio: bio_put(bio); err_free_dma: - nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list); + pblk_free_rqd_meta(pblk, &rqd); return ret; } diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c index e232e47e1353..5740b7509bd8 100644 --- a/drivers/lightnvm/pblk-recovery.c +++ b/drivers/lightnvm/pblk-recovery.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial: Javier Gonzalez <javier@cnexlabs.com> @@ -15,6 +16,7 @@ */ #include "pblk.h" +#include "pblk-trace.h" int pblk_recov_check_emeta(struct pblk *pblk, struct line_emeta *emeta_buf) { @@ -85,15 +87,39 @@ static int pblk_recov_l2p_from_emeta(struct pblk *pblk, struct pblk_line *line) return 0; } -static int pblk_calc_sec_in_line(struct pblk *pblk, struct pblk_line *line) +static void pblk_update_line_wp(struct pblk *pblk, struct pblk_line *line, + u64 written_secs) +{ + int i; + + for (i = 0; i < written_secs; i += pblk->min_write_pgs) + pblk_alloc_page(pblk, line, pblk->min_write_pgs); +} + +static u64 pblk_sec_in_open_line(struct pblk *pblk, struct pblk_line *line) { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; struct pblk_line_meta *lm = &pblk->lm; int nr_bb = bitmap_weight(line->blk_bitmap, lm->blk_per_line); + u64 written_secs = 0; + int valid_chunks = 0; + int i; + + for (i = 0; i < lm->blk_per_line; i++) { + struct nvm_chk_meta *chunk = &line->chks[i]; + + if (chunk->state & NVM_CHK_ST_OFFLINE) + continue; + + written_secs += chunk->wp; + valid_chunks++; + } + + if (lm->blk_per_line - nr_bb != valid_chunks) + pblk_err(pblk, "recovery line %d is bad\n", line->id); - return lm->sec_per_line - lm->smeta_sec - lm->emeta_sec[0] - - nr_bb * geo->clba; + pblk_update_line_wp(pblk, line, written_secs - lm->smeta_sec); + + return written_secs; } struct pblk_recov_alloc { @@ -105,115 +131,6 @@ struct pblk_recov_alloc { dma_addr_t dma_meta_list; }; -static int pblk_recov_read_oob(struct pblk *pblk, struct pblk_line *line, - struct pblk_recov_alloc p, u64 r_ptr) -{ - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - struct ppa_addr *ppa_list; - struct pblk_sec_meta *meta_list; - struct nvm_rq *rqd; - struct bio *bio; - void *data; - dma_addr_t dma_ppa_list, dma_meta_list; - u64 r_ptr_int; - int left_ppas; - int rq_ppas, rq_len; - int i, j; - int ret = 0; - - ppa_list = p.ppa_list; - meta_list = p.meta_list; - rqd = p.rqd; - data = p.data; - dma_ppa_list = p.dma_ppa_list; - dma_meta_list = p.dma_meta_list; - - left_ppas = line->cur_sec - r_ptr; - if (!left_ppas) - return 0; - - r_ptr_int = r_ptr; - -next_read_rq: - memset(rqd, 0, pblk_g_rq_size); - - rq_ppas = pblk_calc_secs(pblk, left_ppas, 0); - if (!rq_ppas) - rq_ppas = pblk->min_write_pgs; - rq_len = rq_ppas * geo->csecs; - - bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL); - if (IS_ERR(bio)) - return PTR_ERR(bio); - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_READ, 0); - - rqd->bio = bio; - rqd->opcode = NVM_OP_PREAD; - rqd->meta_list = meta_list; - rqd->nr_ppas = rq_ppas; - rqd->ppa_list = ppa_list; - rqd->dma_ppa_list = dma_ppa_list; - rqd->dma_meta_list = dma_meta_list; - - if (pblk_io_aligned(pblk, rq_ppas)) - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL); - else - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM); - - for (i = 0; i < rqd->nr_ppas; ) { - struct ppa_addr ppa; - int pos; - - ppa = addr_to_gen_ppa(pblk, r_ptr_int, line->id); - pos = pblk_ppa_to_pos(geo, ppa); - - while (test_bit(pos, line->blk_bitmap)) { - r_ptr_int += pblk->min_write_pgs; - ppa = addr_to_gen_ppa(pblk, r_ptr_int, line->id); - pos = pblk_ppa_to_pos(geo, ppa); - } - - for (j = 0; j < pblk->min_write_pgs; j++, i++, r_ptr_int++) - rqd->ppa_list[i] = - addr_to_gen_ppa(pblk, r_ptr_int, line->id); - } - - /* If read fails, more padding is needed */ - ret = pblk_submit_io_sync(pblk, rqd); - if (ret) { - pblk_err(pblk, "I/O submission failed: %d\n", ret); - return ret; - } - - atomic_dec(&pblk->inflight_io); - - /* At this point, the read should not fail. If it does, it is a problem - * we cannot recover from here. Need FTL log. - */ - if (rqd->error && rqd->error != NVM_RSP_WARN_HIGHECC) { - pblk_err(pblk, "L2P recovery failed (%d)\n", rqd->error); - return -EINTR; - } - - for (i = 0; i < rqd->nr_ppas; i++) { - u64 lba = le64_to_cpu(meta_list[i].lba); - - if (lba == ADDR_EMPTY || lba > pblk->rl.nr_secs) - continue; - - pblk_update_map(pblk, lba, rqd->ppa_list[i]); - } - - left_ppas -= rq_ppas; - if (left_ppas > 0) - goto next_read_rq; - - return 0; -} - static void pblk_recov_complete(struct kref *ref) { struct pblk_pad_rq *pad_rq = container_of(ref, struct pblk_pad_rq, ref); @@ -223,10 +140,11 @@ static void pblk_recov_complete(struct kref *ref) static void pblk_end_io_recov(struct nvm_rq *rqd) { + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); struct pblk_pad_rq *pad_rq = rqd->private; struct pblk *pblk = pad_rq->pblk; - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); + pblk_up_chunk(pblk, ppa_list[0]); pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT); @@ -234,18 +152,17 @@ static void pblk_end_io_recov(struct nvm_rq *rqd) kref_put(&pad_rq->ref, pblk_recov_complete); } -static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line, - int left_ppas) +/* pad line using line bitmap. */ +static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line, + int left_ppas) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - struct ppa_addr *ppa_list; struct pblk_sec_meta *meta_list; struct pblk_pad_rq *pad_rq; struct nvm_rq *rqd; struct bio *bio; void *data; - dma_addr_t dma_ppa_list, dma_meta_list; __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf); u64 w_ptr = line->cur_sec; int left_line_ppas, rq_ppas, rq_len; @@ -279,20 +196,11 @@ next_pad_rq: rq_len = rq_ppas * geo->csecs; - meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list); - if (!meta_list) { - ret = -ENOMEM; - goto fail_free_pad; - } - - ppa_list = (void *)(meta_list) + pblk_dma_meta_size; - dma_ppa_list = dma_meta_list + pblk_dma_meta_size; - bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len, PBLK_VMALLOC_META, GFP_KERNEL); if (IS_ERR(bio)) { ret = PTR_ERR(bio); - goto fail_free_meta; + goto fail_free_pad; } bio->bi_iter.bi_sector = 0; /* internal bio */ @@ -300,17 +208,19 @@ next_pad_rq: rqd = pblk_alloc_rqd(pblk, PBLK_WRITE_INT); + ret = pblk_alloc_rqd_meta(pblk, rqd); + if (ret) + goto fail_free_rqd; + rqd->bio = bio; rqd->opcode = NVM_OP_PWRITE; - rqd->flags = pblk_set_progr_mode(pblk, PBLK_WRITE); - rqd->meta_list = meta_list; + rqd->is_seq = 1; rqd->nr_ppas = rq_ppas; - rqd->ppa_list = ppa_list; - rqd->dma_ppa_list = dma_ppa_list; - rqd->dma_meta_list = dma_meta_list; rqd->end_io = pblk_end_io_recov; rqd->private = pad_rq; + meta_list = rqd->meta_list; + for (i = 0; i < rqd->nr_ppas; ) { struct ppa_addr ppa; int pos; @@ -338,13 +248,13 @@ next_pad_rq: } kref_get(&pad_rq->ref); - pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas); + pblk_down_chunk(pblk, rqd->ppa_list[0]); ret = pblk_submit_io(pblk, rqd); if (ret) { pblk_err(pblk, "I/O submission failed: %d\n", ret); - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); - goto fail_free_bio; + pblk_up_chunk(pblk, rqd->ppa_list[0]); + goto fail_free_rqd; } left_line_ppas -= rq_ppas; @@ -368,157 +278,60 @@ free_rq: kfree(pad_rq); return ret; -fail_free_bio: +fail_free_rqd: + pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT); bio_put(bio); -fail_free_meta: - nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list); fail_free_pad: kfree(pad_rq); vfree(data); return ret; } -/* When this function is called, it means that not all upper pages have been - * written in a page that contains valid data. In order to recover this data, we - * first find the write pointer on the device, then we pad all necessary - * sectors, and finally attempt to read the valid data - */ -static int pblk_recov_scan_all_oob(struct pblk *pblk, struct pblk_line *line, - struct pblk_recov_alloc p) +static int pblk_pad_distance(struct pblk *pblk, struct pblk_line *line) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - struct ppa_addr *ppa_list; - struct pblk_sec_meta *meta_list; - struct nvm_rq *rqd; - struct bio *bio; - void *data; - dma_addr_t dma_ppa_list, dma_meta_list; - u64 w_ptr = 0, r_ptr; - int rq_ppas, rq_len; - int i, j; - int ret = 0; - int rec_round; - int left_ppas = pblk_calc_sec_in_line(pblk, line) - line->cur_sec; - - ppa_list = p.ppa_list; - meta_list = p.meta_list; - rqd = p.rqd; - data = p.data; - dma_ppa_list = p.dma_ppa_list; - dma_meta_list = p.dma_meta_list; - - /* we could recover up until the line write pointer */ - r_ptr = line->cur_sec; - rec_round = 0; - -next_rq: - memset(rqd, 0, pblk_g_rq_size); + int distance = geo->mw_cunits * geo->all_luns * geo->ws_opt; - rq_ppas = pblk_calc_secs(pblk, left_ppas, 0); - if (!rq_ppas) - rq_ppas = pblk->min_write_pgs; - rq_len = rq_ppas * geo->csecs; - - bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL); - if (IS_ERR(bio)) - return PTR_ERR(bio); - - bio->bi_iter.bi_sector = 0; /* internal bio */ - bio_set_op_attrs(bio, REQ_OP_READ, 0); + return (distance > line->left_msecs) ? line->left_msecs : distance; +} - rqd->bio = bio; - rqd->opcode = NVM_OP_PREAD; - rqd->meta_list = meta_list; - rqd->nr_ppas = rq_ppas; - rqd->ppa_list = ppa_list; - rqd->dma_ppa_list = dma_ppa_list; - rqd->dma_meta_list = dma_meta_list; +static int pblk_line_wp_is_unbalanced(struct pblk *pblk, + struct pblk_line *line) +{ + struct nvm_tgt_dev *dev = pblk->dev; + struct nvm_geo *geo = &dev->geo; + struct pblk_line_meta *lm = &pblk->lm; + struct pblk_lun *rlun; + struct nvm_chk_meta *chunk; + struct ppa_addr ppa; + u64 line_wp; + int pos, i; - if (pblk_io_aligned(pblk, rq_ppas)) - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL); - else - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM); + rlun = &pblk->luns[0]; + ppa = rlun->bppa; + pos = pblk_ppa_to_pos(geo, ppa); + chunk = &line->chks[pos]; - for (i = 0; i < rqd->nr_ppas; ) { - struct ppa_addr ppa; - int pos; + line_wp = chunk->wp; - w_ptr = pblk_alloc_page(pblk, line, pblk->min_write_pgs); - ppa = addr_to_gen_ppa(pblk, w_ptr, line->id); + for (i = 1; i < lm->blk_per_line; i++) { + rlun = &pblk->luns[i]; + ppa = rlun->bppa; pos = pblk_ppa_to_pos(geo, ppa); + chunk = &line->chks[pos]; - while (test_bit(pos, line->blk_bitmap)) { - w_ptr += pblk->min_write_pgs; - ppa = addr_to_gen_ppa(pblk, w_ptr, line->id); - pos = pblk_ppa_to_pos(geo, ppa); - } - - for (j = 0; j < pblk->min_write_pgs; j++, i++, w_ptr++) - rqd->ppa_list[i] = - addr_to_gen_ppa(pblk, w_ptr, line->id); - } - - ret = pblk_submit_io_sync(pblk, rqd); - if (ret) { - pblk_err(pblk, "I/O submission failed: %d\n", ret); - return ret; - } - - atomic_dec(&pblk->inflight_io); - - /* This should not happen since the read failed during normal recovery, - * but the media works funny sometimes... - */ - if (!rec_round++ && !rqd->error) { - rec_round = 0; - for (i = 0; i < rqd->nr_ppas; i++, r_ptr++) { - u64 lba = le64_to_cpu(meta_list[i].lba); - - if (lba == ADDR_EMPTY || lba > pblk->rl.nr_secs) - continue; - - pblk_update_map(pblk, lba, rqd->ppa_list[i]); - } - } - - /* Reached the end of the written line */ - if (rqd->error == NVM_RSP_ERR_EMPTYPAGE) { - int pad_secs, nr_error_bits, bit; - int ret; - - bit = find_first_bit((void *)&rqd->ppa_status, rqd->nr_ppas); - nr_error_bits = rqd->nr_ppas - bit; - - /* Roll back failed sectors */ - line->cur_sec -= nr_error_bits; - line->left_msecs += nr_error_bits; - bitmap_clear(line->map_bitmap, line->cur_sec, nr_error_bits); - - pad_secs = pblk_pad_distance(pblk); - if (pad_secs > line->left_msecs) - pad_secs = line->left_msecs; - - ret = pblk_recov_pad_oob(pblk, line, pad_secs); - if (ret) - pblk_err(pblk, "OOB padding failed (err:%d)\n", ret); - - ret = pblk_recov_read_oob(pblk, line, p, r_ptr); - if (ret) - pblk_err(pblk, "OOB read failed (err:%d)\n", ret); - - left_ppas = 0; + if (chunk->wp > line_wp) + return 1; + else if (chunk->wp < line_wp) + line_wp = chunk->wp; } - left_ppas -= rq_ppas; - if (left_ppas > 0) - goto next_rq; - - return ret; + return 0; } static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line, - struct pblk_recov_alloc p, int *done) + struct pblk_recov_alloc p) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; @@ -528,11 +341,16 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line, struct bio *bio; void *data; dma_addr_t dma_ppa_list, dma_meta_list; - u64 paddr; + __le64 *lba_list; + u64 paddr = 0; + bool padded = false; int rq_ppas, rq_len; int i, j; - int ret = 0; - int left_ppas = pblk_calc_sec_in_line(pblk, line); + int ret; + u64 left_ppas = pblk_sec_in_open_line(pblk, line); + + if (pblk_line_wp_is_unbalanced(pblk, line)) + pblk_warn(pblk, "recovering unbalanced line (%d)\n", line->id); ppa_list = p.ppa_list; meta_list = p.meta_list; @@ -541,7 +359,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line, dma_ppa_list = p.dma_ppa_list; dma_meta_list = p.dma_meta_list; - *done = 1; + lba_list = emeta_to_lbas(pblk, line->emeta->buf); next_rq: memset(rqd, 0, pblk_g_rq_size); @@ -567,15 +385,13 @@ next_rq: rqd->dma_meta_list = dma_meta_list; if (pblk_io_aligned(pblk, rq_ppas)) - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL); - else - rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM); + rqd->is_seq = 1; +retry_rq: for (i = 0; i < rqd->nr_ppas; ) { struct ppa_addr ppa; int pos; - paddr = pblk_alloc_page(pblk, line, pblk->min_write_pgs); ppa = addr_to_gen_ppa(pblk, paddr, line->id); pos = pblk_ppa_to_pos(geo, ppa); @@ -585,9 +401,9 @@ next_rq: pos = pblk_ppa_to_pos(geo, ppa); } - for (j = 0; j < pblk->min_write_pgs; j++, i++, paddr++) + for (j = 0; j < pblk->min_write_pgs; j++, i++) rqd->ppa_list[i] = - addr_to_gen_ppa(pblk, paddr, line->id); + addr_to_gen_ppa(pblk, paddr + j, line->id); } ret = pblk_submit_io_sync(pblk, rqd); @@ -599,31 +415,33 @@ next_rq: atomic_dec(&pblk->inflight_io); - /* Reached the end of the written line */ + /* If a read fails, do a best effort by padding the line and retrying */ if (rqd->error) { - int nr_error_bits, bit; + int pad_distance, ret; - bit = find_first_bit((void *)&rqd->ppa_status, rqd->nr_ppas); - nr_error_bits = rqd->nr_ppas - bit; - - /* Roll back failed sectors */ - line->cur_sec -= nr_error_bits; - line->left_msecs += nr_error_bits; - bitmap_clear(line->map_bitmap, line->cur_sec, nr_error_bits); + if (padded) { + pblk_log_read_err(pblk, rqd); + return -EINTR; + } - left_ppas = 0; - rqd->nr_ppas = bit; + pad_distance = pblk_pad_distance(pblk, line); + ret = pblk_recov_pad_line(pblk, line, pad_distance); + if (ret) + return ret; - if (rqd->error != NVM_RSP_ERR_EMPTYPAGE) - *done = 0; + padded = true; + goto retry_rq; } for (i = 0; i < rqd->nr_ppas; i++) { u64 lba = le64_to_cpu(meta_list[i].lba); + lba_list[paddr++] = cpu_to_le64(lba); + if (lba == ADDR_EMPTY || lba > pblk->rl.nr_secs) continue; + line->nr_valid_lbas++; pblk_update_map(pblk, lba, rqd->ppa_list[i]); } @@ -631,7 +449,11 @@ next_rq: if (left_ppas > 0) goto next_rq; - return ret; +#ifdef CONFIG_NVM_PBLK_DEBUG + WARN_ON(padded && !pblk_line_is_full(line)); +#endif + + return 0; } /* Scan line for lbas on out of bound area */ @@ -645,7 +467,7 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line) struct pblk_recov_alloc p; void *data; dma_addr_t dma_ppa_list, dma_meta_list; - int done, ret = 0; + int ret = 0; meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list); if (!meta_list) @@ -660,7 +482,8 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line) goto free_meta_list; } - rqd = pblk_alloc_rqd(pblk, PBLK_READ); + rqd = mempool_alloc(&pblk->r_rq_pool, GFP_KERNEL); + memset(rqd, 0, pblk_g_rq_size); p.ppa_list = ppa_list; p.meta_list = meta_list; @@ -669,24 +492,17 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line) p.dma_ppa_list = dma_ppa_list; p.dma_meta_list = dma_meta_list; - ret = pblk_recov_scan_oob(pblk, line, p, &done); + ret = pblk_recov_scan_oob(pblk, line, p); if (ret) { - pblk_err(pblk, "could not recover L2P from OOB\n"); + pblk_err(pblk, "could not recover L2P form OOB\n"); goto out; } - if (!done) { - ret = pblk_recov_scan_all_oob(pblk, line, p); - if (ret) { - pblk_err(pblk, "could not recover L2P from OOB\n"); - goto out; - } - } - if (pblk_line_is_full(line)) pblk_line_recov_close(pblk, line); out: + mempool_free(rqd, &pblk->r_rq_pool); kfree(data); free_meta_list: nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list); @@ -775,7 +591,7 @@ static void pblk_recov_wa_counters(struct pblk *pblk, } static int pblk_line_was_written(struct pblk_line *line, - struct pblk *pblk) + struct pblk *pblk) { struct pblk_line_meta *lm = &pblk->lm; @@ -801,6 +617,18 @@ static int pblk_line_was_written(struct pblk_line *line, return 1; } +static bool pblk_line_is_open(struct pblk *pblk, struct pblk_line *line) +{ + struct pblk_line_meta *lm = &pblk->lm; + int i; + + for (i = 0; i < lm->blk_per_line; i++) + if (line->chks[i].state & NVM_CHK_ST_OPEN) + return true; + + return false; +} + struct pblk_line *pblk_recov_l2p(struct pblk *pblk) { struct pblk_line_meta *lm = &pblk->lm; @@ -841,7 +669,7 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk) continue; /* Lines that cannot be read are assumed as not written here */ - if (pblk_line_read_smeta(pblk, line)) + if (pblk_line_smeta_read(pblk, line)) continue; crc = pblk_calc_smeta_crc(pblk, smeta_buf); @@ -911,7 +739,12 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk) line->emeta = emeta; memset(line->emeta->buf, 0, lm->emeta_len[0]); - if (pblk_line_read_emeta(pblk, line, line->emeta->buf)) { + if (pblk_line_is_open(pblk, line)) { + pblk_recov_l2p_from_oob(pblk, line); + goto next; + } + + if (pblk_line_emeta_read(pblk, line, line->emeta->buf)) { pblk_recov_l2p_from_oob(pblk, line); goto next; } @@ -935,6 +768,8 @@ next: spin_lock(&line->lock); line->state = PBLK_LINESTATE_CLOSED; + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); move_list = pblk_line_gc_list(pblk, line); spin_unlock(&line->lock); @@ -942,26 +777,36 @@ next: list_move_tail(&line->list, move_list); spin_unlock(&l_mg->gc_lock); - kfree(line->map_bitmap); + mempool_free(line->map_bitmap, l_mg->bitmap_pool); line->map_bitmap = NULL; line->smeta = NULL; line->emeta = NULL; } else { - if (open_lines > 1) - pblk_err(pblk, "failed to recover L2P\n"); + spin_lock(&line->lock); + line->state = PBLK_LINESTATE_OPEN; + spin_unlock(&line->lock); + + line->emeta->mem = 0; + atomic_set(&line->emeta->sync, 0); + + trace_pblk_line_state(pblk_disk_name(pblk), line->id, + line->state); - open_lines++; - line->meta_line = meta_line; data_line = line; + line->meta_line = meta_line; + + open_lines++; } } - spin_lock(&l_mg->free_lock); if (!open_lines) { + spin_lock(&l_mg->free_lock); WARN_ON_ONCE(!test_and_clear_bit(meta_line, &l_mg->meta_bitmap)); + spin_unlock(&l_mg->free_lock); pblk_line_replace_data(pblk); } else { + spin_lock(&l_mg->free_lock); /* Allocate next line for preparation */ l_mg->data_next = pblk_line_get(pblk); if (l_mg->data_next) { @@ -969,8 +814,8 @@ next: l_mg->data_next->type = PBLK_LINETYPE_DATA; is_next = 1; } + spin_unlock(&l_mg->free_lock); } - spin_unlock(&l_mg->free_lock); if (is_next) pblk_line_erase(pblk, l_mg->data_next); @@ -998,7 +843,7 @@ int pblk_recov_pad(struct pblk *pblk) left_msecs = line->left_msecs; spin_unlock(&l_mg->free_lock); - ret = pblk_recov_pad_oob(pblk, line, left_msecs); + ret = pblk_recov_pad_line(pblk, line, left_msecs); if (ret) { pblk_err(pblk, "tear down padding failed (%d)\n", ret); return ret; diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c index 6a0616a6fcaf..db55a1c89997 100644 --- a/drivers/lightnvm/pblk-rl.c +++ b/drivers/lightnvm/pblk-rl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -127,7 +128,7 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl, } else if (free_blocks < rl->high) { int shift = rl->high_pw - rl->rb_windows_pw; int user_windows = free_blocks >> shift; - int user_max = user_windows << PBLK_MAX_REQ_ADDRS_PW; + int user_max = user_windows << ilog2(NVM_MAX_VLBA); rl->rb_user_max = user_max; rl->rb_gc_max = max - user_max; @@ -228,7 +229,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget) rl->rsv_blocks = min_blocks; /* This will always be a power-of-2 */ - rb_windows = budget / PBLK_MAX_REQ_ADDRS; + rb_windows = budget / NVM_MAX_VLBA; rl->rb_windows_pw = get_count_order(rb_windows); /* To start with, all buffer is available to user I/O writers */ diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c index 9fc3dfa168b4..2d2818155aa8 100644 --- a/drivers/lightnvm/pblk-sysfs.c +++ b/drivers/lightnvm/pblk-sysfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -262,8 +263,14 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page) sec_in_line = l_mg->data_line->sec_in_line; meta_weight = bitmap_weight(&l_mg->meta_bitmap, PBLK_DATA_LINES); - map_weight = bitmap_weight(l_mg->data_line->map_bitmap, + + spin_lock(&l_mg->data_line->lock); + if (l_mg->data_line->map_bitmap) + map_weight = bitmap_weight(l_mg->data_line->map_bitmap, lm->sec_per_line); + else + map_weight = 0; + spin_unlock(&l_mg->data_line->lock); } spin_unlock(&l_mg->free_lock); @@ -337,7 +344,6 @@ static ssize_t pblk_get_write_amp(u64 user, u64 gc, u64 pad, { int sz; - sz = snprintf(page, PAGE_SIZE, "user:%lld gc:%lld pad:%lld WA:", user, gc, pad); @@ -349,7 +355,7 @@ static ssize_t pblk_get_write_amp(u64 user, u64 gc, u64 pad, u32 wa_frac; wa_int = (user + gc + pad) * 100000; - wa_int = div_u64(wa_int, user); + wa_int = div64_u64(wa_int, user); wa_int = div_u64_rem(wa_int, 100000, &wa_frac); sz += snprintf(page + sz, PAGE_SIZE - sz, "%llu.%05u\n", diff --git a/drivers/lightnvm/pblk-trace.h b/drivers/lightnvm/pblk-trace.h new file mode 100644 index 000000000000..679e5c458ca6 --- /dev/null +++ b/drivers/lightnvm/pblk-trace.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM pblk + +#if !defined(_TRACE_PBLK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_PBLK_H + +#include <linux/tracepoint.h> + +struct ppa_addr; + +#define show_chunk_flags(state) __print_flags(state, "", \ + { NVM_CHK_ST_FREE, "FREE", }, \ + { NVM_CHK_ST_CLOSED, "CLOSED", }, \ + { NVM_CHK_ST_OPEN, "OPEN", }, \ + { NVM_CHK_ST_OFFLINE, "OFFLINE", }) + +#define show_line_state(state) __print_symbolic(state, \ + { PBLK_LINESTATE_NEW, "NEW", }, \ + { PBLK_LINESTATE_FREE, "FREE", }, \ + { PBLK_LINESTATE_OPEN, "OPEN", }, \ + { PBLK_LINESTATE_CLOSED, "CLOSED", }, \ + { PBLK_LINESTATE_GC, "GC", }, \ + { PBLK_LINESTATE_BAD, "BAD", }, \ + { PBLK_LINESTATE_CORRUPT, "CORRUPT" }) + + +#define show_pblk_state(state) __print_symbolic(state, \ + { PBLK_STATE_RUNNING, "RUNNING", }, \ + { PBLK_STATE_STOPPING, "STOPPING", }, \ + { PBLK_STATE_RECOVERING, "RECOVERING", }, \ + { PBLK_STATE_STOPPED, "STOPPED" }) + +#define show_chunk_erase_state(state) __print_symbolic(state, \ + { PBLK_CHUNK_RESET_START, "START", }, \ + { PBLK_CHUNK_RESET_DONE, "OK", }, \ + { PBLK_CHUNK_RESET_FAILED, "FAILED" }) + + +TRACE_EVENT(pblk_chunk_reset, + + TP_PROTO(const char *name, struct ppa_addr *ppa, int state), + + TP_ARGS(name, ppa, state), + + TP_STRUCT__entry( + __string(name, name) + __field(u64, ppa) + __field(int, state); + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->ppa = ppa->ppa; + __entry->state = state; + ), + + TP_printk("dev=%s grp=%llu pu=%llu chk=%llu state=%s", __get_str(name), + (u64)(((struct ppa_addr *)(&__entry->ppa))->m.grp), + (u64)(((struct ppa_addr *)(&__entry->ppa))->m.pu), + (u64)(((struct ppa_addr *)(&__entry->ppa))->m.chk), + show_chunk_erase_state((int)__entry->state)) + +); + +TRACE_EVENT(pblk_chunk_state, + + TP_PROTO(const char *name, struct ppa_addr *ppa, int state), + + TP_ARGS(name, ppa, state), + + TP_STRUCT__entry( + __string(name, name) + __field(u64, ppa) + __field(int, state); + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->ppa = ppa->ppa; + __entry->state = state; + ), + + TP_printk("dev=%s grp=%llu pu=%llu chk=%llu state=%s", __get_str(name), + (u64)(((struct ppa_addr *)(&__entry->ppa))->m.grp), + (u64)(((struct ppa_addr *)(&__entry->ppa))->m.pu), + (u64)(((struct ppa_addr *)(&__entry->ppa))->m.chk), + show_chunk_flags((int)__entry->state)) + +); + +TRACE_EVENT(pblk_line_state, + + TP_PROTO(const char *name, int line, int state), + + TP_ARGS(name, line, state), + + TP_STRUCT__entry( + __string(name, name) + __field(int, line) + __field(int, state); + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->line = line; + __entry->state = state; + ), + + TP_printk("dev=%s line=%d state=%s", __get_str(name), + (int)__entry->line, + show_line_state((int)__entry->state)) + +); + +TRACE_EVENT(pblk_state, + + TP_PROTO(const char *name, int state), + + TP_ARGS(name, state), + + TP_STRUCT__entry( + __string(name, name) + __field(int, state); + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->state = state; + ), + + TP_printk("dev=%s state=%s", __get_str(name), + show_pblk_state((int)__entry->state)) + +); + +#endif /* !defined(_TRACE_PBLK_H) || defined(TRACE_HEADER_MULTI_READ) */ + +/* This part must be outside protection */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../../drivers/lightnvm +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE pblk-trace +#include <trace/define_trace.h> diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c index ee774a86cf1e..fa8726493b39 100644 --- a/drivers/lightnvm/pblk-write.c +++ b/drivers/lightnvm/pblk-write.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2016 CNEX Labs * Initial release: Javier Gonzalez <javier@cnexlabs.com> @@ -16,6 +17,7 @@ */ #include "pblk.h" +#include "pblk-trace.h" static unsigned long pblk_end_w_bio(struct pblk *pblk, struct nvm_rq *rqd, struct pblk_c_ctx *c_ctx) @@ -81,8 +83,7 @@ static void pblk_complete_write(struct pblk *pblk, struct nvm_rq *rqd, #ifdef CONFIG_NVM_PBLK_DEBUG atomic_long_sub(c_ctx->nr_valid, &pblk->inflight_writes); #endif - - pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap); + pblk_up_rq(pblk, c_ctx->lun_bitmap); pos = pblk_rb_sync_init(&pblk->rwb, &flags); if (pos == c_ctx->sentry) { @@ -106,14 +107,12 @@ retry: /* Map remaining sectors in chunk, starting from ppa */ static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa) { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; struct pblk_line *line; struct ppa_addr map_ppa = *ppa; u64 paddr; int done = 0; - line = &pblk->lines[pblk_ppa_to_line(*ppa)]; + line = pblk_ppa_to_line(pblk, *ppa); spin_lock(&line->lock); while (!done) { @@ -125,15 +124,7 @@ static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa) if (!test_and_set_bit(paddr, line->invalid_bitmap)) le32_add_cpu(line->vsc, -1); - if (geo->version == NVM_OCSSD_SPEC_12) { - map_ppa.ppa++; - if (map_ppa.g.pg == geo->num_pg) - done = 1; - } else { - map_ppa.m.sec++; - if (map_ppa.m.sec == geo->clba) - done = 1; - } + done = nvm_next_ppa_in_chk(pblk->dev, &map_ppa); } line->w_err_gc->has_write_err = 1; @@ -149,12 +140,11 @@ static void pblk_prepare_resubmit(struct pblk *pblk, unsigned int sentry, struct pblk_w_ctx *w_ctx; struct ppa_addr ppa_l2p; int flags; - unsigned int pos, i; + unsigned int i; spin_lock(&pblk->trans_lock); - pos = sentry; for (i = 0; i < nr_entries; i++) { - entry = &rb->entries[pos]; + entry = &rb->entries[pblk_rb_ptr_wrap(rb, sentry, i)]; w_ctx = &entry->w_ctx; /* Check if the lba has been overwritten */ @@ -168,13 +158,11 @@ static void pblk_prepare_resubmit(struct pblk *pblk, unsigned int sentry, /* Release flags on write context. Protect from writes */ smp_store_release(&w_ctx->flags, flags); - /* Decrese the reference count to the line as we will + /* Decrease the reference count to the line as we will * re-map these entries */ - line = &pblk->lines[pblk_ppa_to_line(w_ctx->ppa)]; + line = pblk_ppa_to_line(pblk, w_ctx->ppa); kref_put(&line->ref, pblk_line_put); - - pos = (pos + 1) & (rb->nr_entries - 1); } spin_unlock(&pblk->trans_lock); } @@ -208,19 +196,14 @@ static void pblk_submit_rec(struct work_struct *work) struct pblk *pblk = recovery->pblk; struct nvm_rq *rqd = recovery->rqd; struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); - struct ppa_addr *ppa_list; + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); pblk_log_write_err(pblk, rqd); - if (rqd->nr_ppas == 1) - ppa_list = &rqd->ppa_addr; - else - ppa_list = rqd->ppa_list; - pblk_map_remaining(pblk, ppa_list); pblk_queue_resubmit(pblk, c_ctx); - pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap); + pblk_up_rq(pblk, c_ctx->lun_bitmap); if (c_ctx->nr_padded) pblk_bio_free_pages(pblk, rqd->bio, c_ctx->nr_valid, c_ctx->nr_padded); @@ -257,11 +240,13 @@ static void pblk_end_io_write(struct nvm_rq *rqd) if (rqd->error) { pblk_end_w_fail(pblk, rqd); return; - } + } else { + if (trace_pblk_chunk_state_enabled()) + pblk_check_chunk_state_update(pblk, rqd); #ifdef CONFIG_NVM_PBLK_DEBUG - else WARN_ONCE(rqd->bio->bi_status, "pblk: corrupted write error\n"); #endif + } pblk_complete_write(pblk, rqd, c_ctx); atomic_dec(&pblk->inflight_io); @@ -273,14 +258,18 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd) struct pblk_g_ctx *m_ctx = nvm_rq_to_pdu(rqd); struct pblk_line *line = m_ctx->private; struct pblk_emeta *emeta = line->emeta; + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); int sync; - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); + pblk_up_chunk(pblk, ppa_list[0]); if (rqd->error) { pblk_log_write_err(pblk, rqd); pblk_err(pblk, "metadata I/O failed. Line %d\n", line->id); line->w_err_gc->has_write_err = 1; + } else { + if (trace_pblk_chunk_state_enabled()) + pblk_check_chunk_state_update(pblk, rqd); } sync = atomic_add_return(rqd->nr_ppas, &emeta->sync); @@ -294,27 +283,16 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd) } static int pblk_alloc_w_rq(struct pblk *pblk, struct nvm_rq *rqd, - unsigned int nr_secs, - nvm_end_io_fn(*end_io)) + unsigned int nr_secs, nvm_end_io_fn(*end_io)) { - struct nvm_tgt_dev *dev = pblk->dev; - /* Setup write request */ rqd->opcode = NVM_OP_PWRITE; rqd->nr_ppas = nr_secs; - rqd->flags = pblk_set_progr_mode(pblk, PBLK_WRITE); + rqd->is_seq = 1; rqd->private = pblk; rqd->end_io = end_io; - rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, - &rqd->dma_meta_list); - if (!rqd->meta_list) - return -ENOMEM; - - rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size; - rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size; - - return 0; + return pblk_alloc_rqd_meta(pblk, rqd); } static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd, @@ -375,6 +353,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; struct pblk_emeta *emeta = meta_line->emeta; + struct ppa_addr *ppa_list; struct pblk_g_ctx *m_ctx; struct bio *bio; struct nvm_rq *rqd; @@ -409,22 +388,22 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) if (ret) goto fail_free_bio; + ppa_list = nvm_rq_to_ppa_list(rqd); for (i = 0; i < rqd->nr_ppas; ) { spin_lock(&meta_line->lock); paddr = __pblk_alloc_page(pblk, meta_line, rq_ppas); spin_unlock(&meta_line->lock); for (j = 0; j < rq_ppas; j++, i++, paddr++) - rqd->ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); + ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id); } + spin_lock(&l_mg->close_lock); emeta->mem += rq_len; - if (emeta->mem >= lm->emeta_len[0]) { - spin_lock(&l_mg->close_lock); + if (emeta->mem >= lm->emeta_len[0]) list_del(&meta_line->list); - spin_unlock(&l_mg->close_lock); - } + spin_unlock(&l_mg->close_lock); - pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas); + pblk_down_chunk(pblk, ppa_list[0]); ret = pblk_submit_io(pblk, rqd); if (ret) { @@ -435,7 +414,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) return NVM_IO_OK; fail_rollback: - pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas); + pblk_up_chunk(pblk, ppa_list[0]); spin_lock(&l_mg->close_lock); pblk_dealloc_page(pblk, meta_line, rq_ppas); list_add(&meta_line->list, &meta_line->list); @@ -491,14 +470,15 @@ static struct pblk_line *pblk_should_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line; spin_lock(&l_mg->close_lock); -retry: if (list_empty(&l_mg->emeta_list)) { spin_unlock(&l_mg->close_lock); return NULL; } meta_line = list_first_entry(&l_mg->emeta_list, struct pblk_line, list); - if (meta_line->emeta->mem >= lm->emeta_len[0]) - goto retry; + if (meta_line->emeta->mem >= lm->emeta_len[0]) { + spin_unlock(&l_mg->close_lock); + return NULL; + } spin_unlock(&l_mg->close_lock); if (!pblk_valid_meta_ppa(pblk, meta_line, data_rqd)) diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h index 4760af7b6499..02bb2e98f8a9 100644 --- a/drivers/lightnvm/pblk.h +++ b/drivers/lightnvm/pblk.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2015 IT University of Copenhagen (rrpc.h) * Copyright (C) 2016 CNEX Labs @@ -37,8 +38,6 @@ #define PBLK_SECTOR (512) #define PBLK_EXPOSED_PAGE_SIZE (4096) -#define PBLK_MAX_REQ_ADDRS (64) -#define PBLK_MAX_REQ_ADDRS_PW (6) #define PBLK_NR_CLOSE_JOBS (4) @@ -81,6 +80,12 @@ enum { PBLK_BLK_ST_CLOSED = 0x2, }; +enum { + PBLK_CHUNK_RESET_START, + PBLK_CHUNK_RESET_DONE, + PBLK_CHUNK_RESET_FAILED, +}; + struct pblk_sec_meta { u64 reserved; __le64 lba; @@ -99,8 +104,8 @@ enum { PBLK_RL_LOW = 4 }; -#define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS) -#define pblk_dma_ppa_size (sizeof(u64) * PBLK_MAX_REQ_ADDRS) +#define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * NVM_MAX_VLBA) +#define pblk_dma_ppa_size (sizeof(u64) * NVM_MAX_VLBA) /* write buffer completion context */ struct pblk_c_ctx { @@ -198,6 +203,11 @@ struct pblk_rb { * will be 4KB */ + unsigned int back_thres; /* Threshold that shall be maintained by + * the backpointer in order to respect + * geo->mw_cunits on a per chunk basis + */ + struct list_head pages; /* List of data pages */ spinlock_t w_lock; /* Write lock */ @@ -218,8 +228,8 @@ struct pblk_lun { struct pblk_gc_rq { struct pblk_line *line; void *data; - u64 paddr_list[PBLK_MAX_REQ_ADDRS]; - u64 lba_list[PBLK_MAX_REQ_ADDRS]; + u64 paddr_list[NVM_MAX_VLBA]; + u64 lba_list[NVM_MAX_VLBA]; int nr_secs; int secs_to_gc; struct list_head list; @@ -532,6 +542,10 @@ struct pblk_line_mgmt { struct pblk_emeta *eline_meta[PBLK_DATA_LINES]; unsigned long meta_bitmap; + /* Cache and mempool for map/invalid bitmaps */ + struct kmem_cache *bitmap_cache; + mempool_t *bitmap_pool; + /* Helpers for fast bitmap calculations */ unsigned long *bb_template; unsigned long *bb_aux; @@ -725,10 +739,8 @@ struct pblk_line_ws { /* * pblk ring buffer operations */ -int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base, - unsigned int power_size, unsigned int power_seg_sz); -unsigned int pblk_rb_calculate_size(unsigned int nr_entries); -void *pblk_rb_entries_ref(struct pblk_rb *rb); +int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold, + unsigned int seg_sz); int pblk_rb_may_write_user(struct pblk_rb *rb, struct bio *bio, unsigned int nr_entries, unsigned int *pos); int pblk_rb_may_write_gc(struct pblk_rb *rb, unsigned int nr_entries, @@ -751,8 +763,8 @@ unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries); unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags); unsigned int pblk_rb_sync_advance(struct pblk_rb *rb, unsigned int nr_entries); -struct pblk_rb_entry *pblk_rb_sync_scan_entry(struct pblk_rb *rb, - struct ppa_addr *ppa); +unsigned int pblk_rb_ptr_wrap(struct pblk_rb *rb, unsigned int p, + unsigned int nr_entries); void pblk_rb_sync_end(struct pblk_rb *rb, unsigned long *flags); unsigned int pblk_rb_flush_point_count(struct pblk_rb *rb); @@ -762,7 +774,7 @@ unsigned int pblk_rb_wrap_pos(struct pblk_rb *rb, unsigned int pos); int pblk_rb_tear_down_check(struct pblk_rb *rb); int pblk_rb_pos_oob(struct pblk_rb *rb, u64 pos); -void pblk_rb_data_free(struct pblk_rb *rb); +void pblk_rb_free(struct pblk_rb *rb); ssize_t pblk_rb_sysfs(struct pblk_rb *rb, char *buf); /* @@ -770,11 +782,13 @@ ssize_t pblk_rb_sysfs(struct pblk_rb *rb, char *buf); */ struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int type); void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type); +int pblk_alloc_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd); +void pblk_free_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd); void pblk_set_sec_per_write(struct pblk *pblk, int sec_per_write); int pblk_setup_w_rec_rq(struct pblk *pblk, struct nvm_rq *rqd, struct pblk_c_ctx *c_ctx); void pblk_discard(struct pblk *pblk, struct bio *bio); -struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk); +struct nvm_chk_meta *pblk_get_chunk_meta(struct pblk *pblk); struct nvm_chk_meta *pblk_chunk_get_off(struct pblk *pblk, struct nvm_chk_meta *lp, struct ppa_addr ppa); @@ -782,13 +796,17 @@ void pblk_log_write_err(struct pblk *pblk, struct nvm_rq *rqd); void pblk_log_read_err(struct pblk *pblk, struct nvm_rq *rqd); int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd); int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd); +int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd); int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line); +void pblk_check_chunk_state_update(struct pblk *pblk, struct nvm_rq *rqd); struct bio *pblk_bio_map_addr(struct pblk *pblk, void *data, unsigned int nr_secs, unsigned int len, int alloc_type, gfp_t gfp_mask); struct pblk_line *pblk_line_get(struct pblk *pblk); struct pblk_line *pblk_line_get_first_data(struct pblk *pblk); struct pblk_line *pblk_line_replace_data(struct pblk *pblk); +void pblk_ppa_to_line_put(struct pblk *pblk, struct ppa_addr ppa); +void pblk_rq_to_line_put(struct pblk *pblk, struct nvm_rq *rqd); int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line); void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line); struct pblk_line *pblk_line_get_data(struct pblk *pblk); @@ -806,8 +824,8 @@ void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, void (*work)(struct work_struct *), gfp_t gfp_mask, struct workqueue_struct *wq); u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line); -int pblk_line_read_smeta(struct pblk *pblk, struct pblk_line *line); -int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line, +int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line); +int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line, void *emeta_buf); int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr erase_ppa); void pblk_line_put(struct kref *ref); @@ -819,12 +837,11 @@ u64 pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs); u64 __pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs); int pblk_calc_secs(struct pblk *pblk, unsigned long secs_avail, unsigned long secs_to_flush); -void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas); -void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, +void pblk_down_rq(struct pblk *pblk, struct ppa_addr ppa, unsigned long *lun_bitmap); -void pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas); -void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, - unsigned long *lun_bitmap); +void pblk_down_chunk(struct pblk *pblk, struct ppa_addr ppa); +void pblk_up_chunk(struct pblk *pblk, struct ppa_addr ppa); +void pblk_up_rq(struct pblk *pblk, unsigned long *lun_bitmap); int pblk_bio_add_pages(struct pblk *pblk, struct bio *bio, gfp_t flags, int nr_pages); void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off, @@ -976,17 +993,15 @@ static inline int pblk_line_vsc(struct pblk_line *line) return le32_to_cpu(*line->vsc); } -static inline int pblk_pad_distance(struct pblk *pblk) +static inline int pblk_ppa_to_line_id(struct ppa_addr p) { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - - return geo->mw_cunits * geo->all_luns * geo->ws_opt; + return p.a.blk; } -static inline int pblk_ppa_to_line(struct ppa_addr p) +static inline struct pblk_line *pblk_ppa_to_line(struct pblk *pblk, + struct ppa_addr p) { - return p.a.blk; + return &pblk->lines[pblk_ppa_to_line_id(p)]; } static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p) @@ -1034,6 +1049,25 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr, return ppa; } +static inline struct nvm_chk_meta *pblk_dev_ppa_to_chunk(struct pblk *pblk, + struct ppa_addr p) +{ + struct nvm_tgt_dev *dev = pblk->dev; + struct nvm_geo *geo = &dev->geo; + struct pblk_line *line = pblk_ppa_to_line(pblk, p); + int pos = pblk_ppa_to_pos(geo, p); + + return &line->chks[pos]; +} + +static inline u64 pblk_dev_ppa_to_chunk_addr(struct pblk *pblk, + struct ppa_addr p) +{ + struct nvm_tgt_dev *dev = pblk->dev; + + return dev_to_chunk_addr(dev->parent, &pblk->addrf, p); +} + static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk, struct ppa_addr p) { @@ -1067,86 +1101,16 @@ static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk, static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32) { - struct ppa_addr ppa64; - - ppa64.ppa = 0; - - if (ppa32 == -1) { - ppa64.ppa = ADDR_EMPTY; - } else if (ppa32 & (1U << 31)) { - ppa64.c.line = ppa32 & ((~0U) >> 1); - ppa64.c.is_cached = 1; - } else { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - - if (geo->version == NVM_OCSSD_SPEC_12) { - struct nvm_addrf_12 *ppaf = - (struct nvm_addrf_12 *)&pblk->addrf; - - ppa64.g.ch = (ppa32 & ppaf->ch_mask) >> - ppaf->ch_offset; - ppa64.g.lun = (ppa32 & ppaf->lun_mask) >> - ppaf->lun_offset; - ppa64.g.blk = (ppa32 & ppaf->blk_mask) >> - ppaf->blk_offset; - ppa64.g.pg = (ppa32 & ppaf->pg_mask) >> - ppaf->pg_offset; - ppa64.g.pl = (ppa32 & ppaf->pln_mask) >> - ppaf->pln_offset; - ppa64.g.sec = (ppa32 & ppaf->sec_mask) >> - ppaf->sec_offset; - } else { - struct nvm_addrf *lbaf = &pblk->addrf; - - ppa64.m.grp = (ppa32 & lbaf->ch_mask) >> - lbaf->ch_offset; - ppa64.m.pu = (ppa32 & lbaf->lun_mask) >> - lbaf->lun_offset; - ppa64.m.chk = (ppa32 & lbaf->chk_mask) >> - lbaf->chk_offset; - ppa64.m.sec = (ppa32 & lbaf->sec_mask) >> - lbaf->sec_offset; - } - } + struct nvm_tgt_dev *dev = pblk->dev; - return ppa64; + return nvm_ppa32_to_ppa64(dev->parent, &pblk->addrf, ppa32); } static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64) { - u32 ppa32 = 0; - - if (ppa64.ppa == ADDR_EMPTY) { - ppa32 = ~0U; - } else if (ppa64.c.is_cached) { - ppa32 |= ppa64.c.line; - ppa32 |= 1U << 31; - } else { - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - - if (geo->version == NVM_OCSSD_SPEC_12) { - struct nvm_addrf_12 *ppaf = - (struct nvm_addrf_12 *)&pblk->addrf; - - ppa32 |= ppa64.g.ch << ppaf->ch_offset; - ppa32 |= ppa64.g.lun << ppaf->lun_offset; - ppa32 |= ppa64.g.blk << ppaf->blk_offset; - ppa32 |= ppa64.g.pg << ppaf->pg_offset; - ppa32 |= ppa64.g.pl << ppaf->pln_offset; - ppa32 |= ppa64.g.sec << ppaf->sec_offset; - } else { - struct nvm_addrf *lbaf = &pblk->addrf; - - ppa32 |= ppa64.m.grp << lbaf->ch_offset; - ppa32 |= ppa64.m.pu << lbaf->lun_offset; - ppa32 |= ppa64.m.chk << lbaf->chk_offset; - ppa32 |= ppa64.m.sec << lbaf->sec_offset; - } - } + struct nvm_tgt_dev *dev = pblk->dev; - return ppa32; + return nvm_ppa64_to_ppa32(dev->parent, &pblk->addrf, ppa64); } static inline struct ppa_addr pblk_trans_map_get(struct pblk *pblk, @@ -1255,44 +1219,6 @@ static inline u32 pblk_calc_emeta_crc(struct pblk *pblk, return crc; } -static inline int pblk_set_progr_mode(struct pblk *pblk, int type) -{ - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - int flags; - - if (geo->version == NVM_OCSSD_SPEC_20) - return 0; - - flags = geo->pln_mode >> 1; - - if (type == PBLK_WRITE) - flags |= NVM_IO_SCRAMBLE_ENABLE; - - return flags; -} - -enum { - PBLK_READ_RANDOM = 0, - PBLK_READ_SEQUENTIAL = 1, -}; - -static inline int pblk_set_read_mode(struct pblk *pblk, int type) -{ - struct nvm_tgt_dev *dev = pblk->dev; - struct nvm_geo *geo = &dev->geo; - int flags; - - if (geo->version == NVM_OCSSD_SPEC_20) - return 0; - - flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE; - if (type == PBLK_READ_SEQUENTIAL) - flags |= geo->pln_mode >> 1; - - return flags; -} - static inline int pblk_io_aligned(struct pblk *pblk, int nr_secs) { return !(nr_secs % pblk->min_write_pgs); @@ -1375,9 +1301,7 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev, static inline int pblk_check_io(struct pblk *pblk, struct nvm_rq *rqd) { struct nvm_tgt_dev *dev = pblk->dev; - struct ppa_addr *ppa_list; - - ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr; + struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); if (pblk_boundary_ppa_checks(dev, ppa_list, rqd->nr_ppas)) { WARN_ON(1); @@ -1386,12 +1310,10 @@ static inline int pblk_check_io(struct pblk *pblk, struct nvm_rq *rqd) if (rqd->opcode == NVM_OP_PWRITE) { struct pblk_line *line; - struct ppa_addr ppa; int i; for (i = 0; i < rqd->nr_ppas; i++) { - ppa = ppa_list[i]; - line = &pblk->lines[pblk_ppa_to_line(ppa)]; + line = pblk_ppa_to_line(pblk, ppa_list[i]); spin_lock(&line->lock); if (line->state != PBLK_LINESTATE_OPEN) { @@ -1441,4 +1363,11 @@ static inline void pblk_setup_uuid(struct pblk *pblk) uuid_le_gen(&uuid); memcpy(pblk->instance_uuid, uuid.b, 16); } + +static inline char *pblk_disk_name(struct pblk *pblk) +{ + struct gendisk *disk = pblk->disk; + + return disk->disk_name; +} #endif /* PBLK_H_ */ diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 311e91b1a14f..256f18b67e8a 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -461,8 +461,11 @@ static int __init acpi_pcc_probe(void) count = acpi_table_parse_entries_array(ACPI_SIG_PCCT, sizeof(struct acpi_table_pcct), proc, ACPI_PCCT_TYPE_RESERVED, MAX_PCC_SUBSPACES); - if (count == 0 || count > MAX_PCC_SUBSPACES) { - pr_warn("Invalid PCCT: %d PCC subspaces\n", count); + if (count <= 0 || count > MAX_PCC_SUBSPACES) { + if (count < 0) + pr_warn("Error parsing PCC subspaces from PCCT\n"); + else + pr_warn("Invalid PCCT: %d PCC subspaces\n", count); return -EINVAL; } diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 7a28232d868b..5002838ea476 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -484,7 +484,7 @@ int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve, int i; lockdep_assert_held(&c->bucket_lock); - BUG_ON(!n || n > c->caches_loaded || n > 8); + BUG_ON(!n || n > c->caches_loaded || n > MAX_CACHES_PER_SET); bkey_init(k); diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 954dad29e6e8..b61b83bbcfff 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -1004,7 +1004,7 @@ void bch_open_buckets_free(struct cache_set *c); int bch_cache_allocator_start(struct cache *ca); void bch_debug_exit(void); -void bch_debug_init(struct kobject *kobj); +void bch_debug_init(void); void bch_request_exit(void); int bch_request_init(void); diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index e7d4817681f2..3f4211b5cd33 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -2434,7 +2434,7 @@ static int refill_keybuf_fn(struct btree_op *op, struct btree *b, struct keybuf *buf = refill->buf; int ret = MAP_CONTINUE; - if (bkey_cmp(k, refill->end) >= 0) { + if (bkey_cmp(k, refill->end) > 0) { ret = MAP_DONE; goto out; } diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h index eca0d496b686..c88cdc4ae4ec 100644 --- a/drivers/md/bcache/closure.h +++ b/drivers/md/bcache/closure.h @@ -345,7 +345,8 @@ do { \ } while (0) /** - * closure_return - finish execution of a closure, with destructor + * closure_return_with_destructor - finish execution of a closure, + * with destructor * * Works like closure_return(), except @destructor will be called when all * outstanding refs on @cl have been dropped; @destructor may be used to safely diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 06da66b2488a..8f448b9c96a1 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -253,7 +253,7 @@ void bch_debug_exit(void) debugfs_remove_recursive(bcache_debug); } -void __init bch_debug_init(struct kobject *kobj) +void __init bch_debug_init(void) { /* * it is unnecessary to check return value of diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index c809724e6571..956004366699 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c @@ -553,7 +553,7 @@ static bool bch_extent_bad(struct btree_keys *bk, const struct bkey *k) for (i = 0; i < KEY_PTRS(k); i++) { stale = ptr_stale(b->c, k, i); - btree_bug_on(stale > 96, b, + btree_bug_on(stale > BUCKET_GC_GEN_MAX, b, "key too stale: %i, need_gc %u", stale, b->c->need_gc); diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 51be355a3309..3bf35914bb57 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -395,7 +395,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) * unless the read-ahead request is for metadata (eg, for gfs2). */ if (bio->bi_opf & (REQ_RAHEAD|REQ_BACKGROUND) && - !(bio->bi_opf & REQ_META)) + !(bio->bi_opf & REQ_PRIO)) goto skip; if (bio->bi_iter.bi_sector & (c->sb.block_size - 1) || @@ -850,7 +850,7 @@ static void cached_dev_read_done_bh(struct closure *cl) bch_mark_cache_accounting(s->iop.c, s->d, !s->cache_missed, s->iop.bypass); - trace_bcache_read(s->orig_bio, !s->cache_miss, s->iop.bypass); + trace_bcache_read(s->orig_bio, !s->cache_missed, s->iop.bypass); if (s->iop.status) continue_at_nobarrier(cl, cached_dev_read_error, bcache_wq); @@ -877,7 +877,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, } if (!(bio->bi_opf & REQ_RAHEAD) && - !(bio->bi_opf & REQ_META) && + !(bio->bi_opf & REQ_PRIO) && s->iop.c->gc_stats.in_use < CUTOFF_CACHE_READA) reada = min_t(sector_t, dc->readahead >> 9, get_capacity(bio->bi_disk) - bio_end_sector(bio)); @@ -1218,6 +1218,9 @@ static int cached_dev_ioctl(struct bcache_device *d, fmode_t mode, { struct cached_dev *dc = container_of(d, struct cached_dev, disk); + if (dc->io_disable) + return -EIO; + return __blkdev_driver_ioctl(dc->bdev, mode, cmd, arg); } diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h index aa055cfeb099..721bf336ed1a 100644 --- a/drivers/md/bcache/request.h +++ b/drivers/md/bcache/request.h @@ -39,6 +39,6 @@ void bch_data_insert(struct closure *cl); void bch_cached_dev_request_init(struct cached_dev *dc); void bch_flash_dev_request_init(struct bcache_device *d); -extern struct kmem_cache *bch_search_cache, *bch_passthrough_cache; +extern struct kmem_cache *bch_search_cache; #endif /* _BCACHE_REQUEST_H_ */ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 30ba9aeb5ee8..7bbd670a5a84 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -418,6 +418,7 @@ static int __uuid_write(struct cache_set *c) { BKEY_PADDED(key) k; struct closure cl; + struct cache *ca; closure_init_stack(&cl); lockdep_assert_held(&bch_register_lock); @@ -429,6 +430,10 @@ static int __uuid_write(struct cache_set *c) uuid_io(c, REQ_OP_WRITE, 0, &k.key, &cl); closure_sync(&cl); + /* Only one bucket used for uuid write */ + ca = PTR_CACHE(c, &k.key, 0); + atomic_long_add(ca->sb.bucket_size, &ca->meta_sectors_written); + bkey_copy(&c->uuid_bucket, &k.key); bkey_put(c, &k.key); return 0; @@ -643,10 +648,6 @@ static int ioctl_dev(struct block_device *b, fmode_t mode, unsigned int cmd, unsigned long arg) { struct bcache_device *d = b->bd_disk->private_data; - struct cached_dev *dc = container_of(d, struct cached_dev, disk); - - if (dc->io_disable) - return -EIO; return d->ioctl(d, mode, cmd, arg); } @@ -1008,6 +1009,7 @@ static void cached_dev_detach_finish(struct work_struct *w) bch_write_bdev_super(dc, &cl); closure_sync(&cl); + calc_cached_dev_sectors(dc->disk.c); bcache_device_detach(&dc->disk); list_move(&dc->list, &uncached_devices); @@ -1152,11 +1154,12 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, } if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) { - bch_sectors_dirty_init(&dc->disk); atomic_set(&dc->has_dirty, 1); bch_writeback_queue(dc); } + bch_sectors_dirty_init(&dc->disk); + bch_cached_dev_run(dc); bcache_device_link(&dc->disk, c, "bdev"); atomic_inc(&c->attached_dev_nr); @@ -2049,6 +2052,8 @@ static int cache_alloc(struct cache *ca) size_t free; size_t btree_buckets; struct bucket *b; + int ret = -ENOMEM; + const char *err = NULL; __module_get(THIS_MODULE); kobject_init(&ca->kobj, &bch_cache_ktype); @@ -2066,27 +2071,93 @@ static int cache_alloc(struct cache *ca) */ btree_buckets = ca->sb.njournal_buckets ?: 8; free = roundup_pow_of_two(ca->sb.nbuckets) >> 10; + if (!free) { + ret = -EPERM; + err = "ca->sb.nbuckets is too small"; + goto err_free; + } - if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets, GFP_KERNEL) || - !init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) || - !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) || - !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) || - !init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) || - !init_heap(&ca->heap, free << 3, GFP_KERNEL) || - !(ca->buckets = vzalloc(array_size(sizeof(struct bucket), - ca->sb.nbuckets))) || - !(ca->prio_buckets = kzalloc(array3_size(sizeof(uint64_t), - prio_buckets(ca), 2), - GFP_KERNEL)) || - !(ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca))) - return -ENOMEM; + if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets, + GFP_KERNEL)) { + err = "ca->free[RESERVE_BTREE] alloc failed"; + goto err_btree_alloc; + } + + if (!init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), + GFP_KERNEL)) { + err = "ca->free[RESERVE_PRIO] alloc failed"; + goto err_prio_alloc; + } + + if (!init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL)) { + err = "ca->free[RESERVE_MOVINGGC] alloc failed"; + goto err_movinggc_alloc; + } + + if (!init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL)) { + err = "ca->free[RESERVE_NONE] alloc failed"; + goto err_none_alloc; + } + + if (!init_fifo(&ca->free_inc, free << 2, GFP_KERNEL)) { + err = "ca->free_inc alloc failed"; + goto err_free_inc_alloc; + } + + if (!init_heap(&ca->heap, free << 3, GFP_KERNEL)) { + err = "ca->heap alloc failed"; + goto err_heap_alloc; + } + + ca->buckets = vzalloc(array_size(sizeof(struct bucket), + ca->sb.nbuckets)); + if (!ca->buckets) { + err = "ca->buckets alloc failed"; + goto err_buckets_alloc; + } + + ca->prio_buckets = kzalloc(array3_size(sizeof(uint64_t), + prio_buckets(ca), 2), + GFP_KERNEL); + if (!ca->prio_buckets) { + err = "ca->prio_buckets alloc failed"; + goto err_prio_buckets_alloc; + } + + ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca); + if (!ca->disk_buckets) { + err = "ca->disk_buckets alloc failed"; + goto err_disk_buckets_alloc; + } ca->prio_last_buckets = ca->prio_buckets + prio_buckets(ca); for_each_bucket(b, ca) atomic_set(&b->pin, 0); - return 0; + +err_disk_buckets_alloc: + kfree(ca->prio_buckets); +err_prio_buckets_alloc: + vfree(ca->buckets); +err_buckets_alloc: + free_heap(&ca->heap); +err_heap_alloc: + free_fifo(&ca->free_inc); +err_free_inc_alloc: + free_fifo(&ca->free[RESERVE_NONE]); +err_none_alloc: + free_fifo(&ca->free[RESERVE_MOVINGGC]); +err_movinggc_alloc: + free_fifo(&ca->free[RESERVE_PRIO]); +err_prio_alloc: + free_fifo(&ca->free[RESERVE_BTREE]); +err_btree_alloc: +err_free: + module_put(THIS_MODULE); + if (err) + pr_notice("error %s: %s", ca->cache_dev_name, err); + return ret; } static int register_cache(struct cache_sb *sb, struct page *sb_page, @@ -2112,6 +2183,8 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); if (ret == -ENOMEM) err = "cache_alloc(): -ENOMEM"; + else if (ret == -EPERM) + err = "cache_alloc(): cache device is too small"; else err = "cache_alloc(): unknown error"; goto err; @@ -2386,7 +2459,7 @@ static int __init bcache_init(void) sysfs_create_files(bcache_kobj, files)) goto err; - bch_debug_init(bcache_kobj); + bch_debug_init(); closure_debug_init(); return 0; diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index 150cf4f4cf74..26f035a0c5b9 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -285,6 +285,7 @@ STORE(__cached_dev) 1, WRITEBACK_RATE_UPDATE_SECS_MAX); d_strtoul(writeback_rate_i_term_inverse); d_strtoul_nonzero(writeback_rate_p_term_inverse); + d_strtoul_nonzero(writeback_rate_minimum); sysfs_strtoul_clamp(io_error_limit, dc->error_limit, 0, INT_MAX); @@ -412,6 +413,7 @@ static struct attribute *bch_cached_dev_files[] = { &sysfs_writeback_rate_update_seconds, &sysfs_writeback_rate_i_term_inverse, &sysfs_writeback_rate_p_term_inverse, + &sysfs_writeback_rate_minimum, &sysfs_writeback_rate_debug, &sysfs_errors, &sysfs_io_error_limit, diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index ac1cffd2a09b..f3fb5bb8c82a 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -542,7 +542,7 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) !discard_bio) continue; bio_chain(discard_bio, bio); - bio_clone_blkcg_association(discard_bio, bio); + bio_clone_blkg_association(discard_bio, bio); if (mddev->gendisk) trace_block_bio_remap(bdev_get_queue(rdev->bdev), discard_bio, disk_devt(mddev->gendisk), diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index 716fc8ed31d3..8a02f11076f9 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -2146,7 +2146,7 @@ static int msb_init_disk(struct memstick_dev *card) set_disk_ro(msb->disk, 1); msb_start(card); - device_add_disk(&card->dev, msb->disk); + device_add_disk(&card->dev, msb->disk, NULL); dbg("Disk added"); return 0; diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 5ee932631fae..0cd30dcb6801 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -1236,7 +1236,7 @@ static int mspro_block_init_disk(struct memstick_dev *card) set_capacity(msb->disk, capacity); dev_dbg(&card->dev, "capacity set %ld\n", capacity); - device_add_disk(&card->dev, msb->disk); + device_add_disk(&card->dev, msb->disk, NULL); msb->active = 1; return 0; diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c index 96e7d2cb7b89..400e0b51844b 100644 --- a/drivers/mfd/altera-a10sr.c +++ b/drivers/mfd/altera-a10sr.c @@ -108,7 +108,8 @@ static const struct regmap_config altr_a10sr_regmap_config = { .cache_type = REGCACHE_NONE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .read_flag_mask = 1, .write_flag_mask = 0, diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index abfb11818fdc..fdae1288bc6d 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -46,7 +46,8 @@ static int da9052_spi_probe(struct spi_device *spi) config.reg_bits = 7; config.pad_bits = 1; config.val_bits = 8; - config.use_single_rw = 1; + config.use_single_read = true; + config.use_single_write = true; da9052->regmap = devm_regmap_init_spi(spi, &config); if (IS_ERR(da9052->regmap)) { diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index cbc1e5ed599c..ee3411cc5ce4 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -57,7 +57,8 @@ static const struct regmap_config mc13xxx_regmap_spi_config = { .max_register = MC13XXX_NUMREGS, .cache_type = REGCACHE_NONE, - .use_single_rw = 1, + .use_single_read = true, + .use_single_write = true, }; static int mc13xxx_spi_read(void *context, const void *reg, size_t reg_size, diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c index 75c8ec659547..a29d529a96f4 100644 --- a/drivers/mfd/rohm-bd718x7.c +++ b/drivers/mfd/rohm-bd718x7.c @@ -2,26 +2,21 @@ // // Copyright (C) 2018 ROHM Semiconductors // -// ROHM BD71837MWV PMIC driver +// ROHM BD71837MWV and BD71847MWV PMIC driver // -// Datasheet available from +// Datasheet for BD71837MWV available from // https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e +#include <linux/gpio_keys.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/mfd/rohm-bd718x7.h> #include <linux/mfd/core.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/regmap.h> - -/* - * gpio_keys.h requires definiton of bool. It is brought in - * by above includes. Keep this as last until gpio_keys.h gets fixed. - */ -#include <linux/gpio_keys.h> - -static const u8 supported_revisions[] = { 0xA2 /* BD71837 */ }; +#include <linux/types.h> static struct gpio_keys_button button = { .code = KEY_POWER, @@ -35,42 +30,42 @@ static struct gpio_keys_platform_data bd718xx_powerkey_data = { .name = "bd718xx-pwrkey", }; -static struct mfd_cell bd71837_mfd_cells[] = { +static struct mfd_cell bd718xx_mfd_cells[] = { { .name = "gpio-keys", .platform_data = &bd718xx_powerkey_data, .pdata_size = sizeof(bd718xx_powerkey_data), }, - { .name = "bd71837-clk", }, - { .name = "bd71837-pmic", }, + { .name = "bd718xx-clk", }, + { .name = "bd718xx-pmic", }, }; -static const struct regmap_irq bd71837_irqs[] = { - REGMAP_IRQ_REG(BD71837_INT_SWRST, 0, BD71837_INT_SWRST_MASK), - REGMAP_IRQ_REG(BD71837_INT_PWRBTN_S, 0, BD71837_INT_PWRBTN_S_MASK), - REGMAP_IRQ_REG(BD71837_INT_PWRBTN_L, 0, BD71837_INT_PWRBTN_L_MASK), - REGMAP_IRQ_REG(BD71837_INT_PWRBTN, 0, BD71837_INT_PWRBTN_MASK), - REGMAP_IRQ_REG(BD71837_INT_WDOG, 0, BD71837_INT_WDOG_MASK), - REGMAP_IRQ_REG(BD71837_INT_ON_REQ, 0, BD71837_INT_ON_REQ_MASK), - REGMAP_IRQ_REG(BD71837_INT_STBY_REQ, 0, BD71837_INT_STBY_REQ_MASK), +static const struct regmap_irq bd718xx_irqs[] = { + REGMAP_IRQ_REG(BD718XX_INT_SWRST, 0, BD718XX_INT_SWRST_MASK), + REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_S, 0, BD718XX_INT_PWRBTN_S_MASK), + REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_L, 0, BD718XX_INT_PWRBTN_L_MASK), + REGMAP_IRQ_REG(BD718XX_INT_PWRBTN, 0, BD718XX_INT_PWRBTN_MASK), + REGMAP_IRQ_REG(BD718XX_INT_WDOG, 0, BD718XX_INT_WDOG_MASK), + REGMAP_IRQ_REG(BD718XX_INT_ON_REQ, 0, BD718XX_INT_ON_REQ_MASK), + REGMAP_IRQ_REG(BD718XX_INT_STBY_REQ, 0, BD718XX_INT_STBY_REQ_MASK), }; -static struct regmap_irq_chip bd71837_irq_chip = { - .name = "bd71837-irq", - .irqs = bd71837_irqs, - .num_irqs = ARRAY_SIZE(bd71837_irqs), +static struct regmap_irq_chip bd718xx_irq_chip = { + .name = "bd718xx-irq", + .irqs = bd718xx_irqs, + .num_irqs = ARRAY_SIZE(bd718xx_irqs), .num_regs = 1, .irq_reg_stride = 1, - .status_base = BD71837_REG_IRQ, - .mask_base = BD71837_REG_MIRQ, - .ack_base = BD71837_REG_IRQ, + .status_base = BD718XX_REG_IRQ, + .mask_base = BD718XX_REG_MIRQ, + .ack_base = BD718XX_REG_IRQ, .init_ack_masked = true, .mask_invert = false, }; static const struct regmap_range pmic_status_range = { - .range_min = BD71837_REG_IRQ, - .range_max = BD71837_REG_POW_STATE, + .range_min = BD718XX_REG_IRQ, + .range_max = BD718XX_REG_POW_STATE, }; static const struct regmap_access_table volatile_regs = { @@ -78,67 +73,53 @@ static const struct regmap_access_table volatile_regs = { .n_yes_ranges = 1, }; -static const struct regmap_config bd71837_regmap_config = { +static const struct regmap_config bd718xx_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_table = &volatile_regs, - .max_register = BD71837_MAX_REGISTER - 1, + .max_register = BD718XX_MAX_REGISTER - 1, .cache_type = REGCACHE_RBTREE, }; -static int bd71837_i2c_probe(struct i2c_client *i2c, +static int bd718xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct bd71837 *bd71837; - int ret, i; - unsigned int val; - - bd71837 = devm_kzalloc(&i2c->dev, sizeof(struct bd71837), GFP_KERNEL); + struct bd718xx *bd718xx; + int ret; - if (!bd71837) - return -ENOMEM; - - bd71837->chip_irq = i2c->irq; - - if (!bd71837->chip_irq) { + if (!i2c->irq) { dev_err(&i2c->dev, "No IRQ configured\n"); return -EINVAL; } - bd71837->dev = &i2c->dev; - dev_set_drvdata(&i2c->dev, bd71837); + bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL); - bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config); - if (IS_ERR(bd71837->regmap)) { - dev_err(&i2c->dev, "regmap initialization failed\n"); - return PTR_ERR(bd71837->regmap); - } + if (!bd718xx) + return -ENOMEM; - ret = regmap_read(bd71837->regmap, BD71837_REG_REV, &val); - if (ret) { - dev_err(&i2c->dev, "Read BD71837_REG_DEVICE failed\n"); - return ret; - } - for (i = 0; i < ARRAY_SIZE(supported_revisions); i++) - if (supported_revisions[i] == val) - break; + bd718xx->chip_irq = i2c->irq; + bd718xx->chip_type = (unsigned int)(uintptr_t) + of_device_get_match_data(&i2c->dev); + bd718xx->dev = &i2c->dev; + dev_set_drvdata(&i2c->dev, bd718xx); - if (i == ARRAY_SIZE(supported_revisions)) { - dev_err(&i2c->dev, "Unsupported chip revision\n"); - return -ENODEV; + bd718xx->regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config); + if (IS_ERR(bd718xx->regmap)) { + dev_err(&i2c->dev, "regmap initialization failed\n"); + return PTR_ERR(bd718xx->regmap); } - ret = devm_regmap_add_irq_chip(&i2c->dev, bd71837->regmap, - bd71837->chip_irq, IRQF_ONESHOT, 0, - &bd71837_irq_chip, &bd71837->irq_data); + ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->regmap, + bd718xx->chip_irq, IRQF_ONESHOT, 0, + &bd718xx_irq_chip, &bd718xx->irq_data); if (ret) { dev_err(&i2c->dev, "Failed to add irq_chip\n"); return ret; } /* Configure short press to 10 milliseconds */ - ret = regmap_update_bits(bd71837->regmap, - BD71837_REG_PWRONCONFIG0, + ret = regmap_update_bits(bd718xx->regmap, + BD718XX_REG_PWRONCONFIG0, BD718XX_PWRBTN_PRESS_DURATION_MASK, BD718XX_PWRBTN_SHORT_PRESS_10MS); if (ret) { @@ -148,8 +129,8 @@ static int bd71837_i2c_probe(struct i2c_client *i2c, } /* Configure long press to 10 seconds */ - ret = regmap_update_bits(bd71837->regmap, - BD71837_REG_PWRONCONFIG1, + ret = regmap_update_bits(bd718xx->regmap, + BD718XX_REG_PWRONCONFIG1, BD718XX_PWRBTN_PRESS_DURATION_MASK, BD718XX_PWRBTN_LONG_PRESS_10S); @@ -159,7 +140,7 @@ static int bd71837_i2c_probe(struct i2c_client *i2c, return ret; } - ret = regmap_irq_get_virq(bd71837->irq_data, BD71837_INT_PWRBTN_S); + ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S); if (ret < 0) { dev_err(&i2c->dev, "Failed to get the IRQ\n"); @@ -168,44 +149,51 @@ static int bd71837_i2c_probe(struct i2c_client *i2c, button.irq = ret; - ret = devm_mfd_add_devices(bd71837->dev, PLATFORM_DEVID_AUTO, - bd71837_mfd_cells, - ARRAY_SIZE(bd71837_mfd_cells), NULL, 0, - regmap_irq_get_domain(bd71837->irq_data)); + ret = devm_mfd_add_devices(bd718xx->dev, PLATFORM_DEVID_AUTO, + bd718xx_mfd_cells, + ARRAY_SIZE(bd718xx_mfd_cells), NULL, 0, + regmap_irq_get_domain(bd718xx->irq_data)); if (ret) dev_err(&i2c->dev, "Failed to create subdevices\n"); return ret; } -static const struct of_device_id bd71837_of_match[] = { - { .compatible = "rohm,bd71837", }, +static const struct of_device_id bd718xx_of_match[] = { + { + .compatible = "rohm,bd71837", + .data = (void *)BD718XX_TYPE_BD71837, + }, + { + .compatible = "rohm,bd71847", + .data = (void *)BD718XX_TYPE_BD71847, + }, { } }; -MODULE_DEVICE_TABLE(of, bd71837_of_match); +MODULE_DEVICE_TABLE(of, bd718xx_of_match); -static struct i2c_driver bd71837_i2c_driver = { +static struct i2c_driver bd718xx_i2c_driver = { .driver = { .name = "rohm-bd718x7", - .of_match_table = bd71837_of_match, + .of_match_table = bd718xx_of_match, }, - .probe = bd71837_i2c_probe, + .probe = bd718xx_i2c_probe, }; -static int __init bd71837_i2c_init(void) +static int __init bd718xx_i2c_init(void) { - return i2c_add_driver(&bd71837_i2c_driver); + return i2c_add_driver(&bd718xx_i2c_driver); } /* Initialise early so consumer devices can complete system boot */ -subsys_initcall(bd71837_i2c_init); +subsys_initcall(bd718xx_i2c_init); -static void __exit bd71837_i2c_exit(void) +static void __exit bd718xx_i2c_exit(void) { - i2c_del_driver(&bd71837_i2c_driver); + i2c_del_driver(&bd718xx_i2c_driver); } -module_exit(bd71837_i2c_exit); +module_exit(bd718xx_i2c_exit); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); -MODULE_DESCRIPTION("ROHM BD71837 Power Management IC driver"); +MODULE_DESCRIPTION("ROHM BD71837/BD71847 Power Management IC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index dd19f17a1b63..7c3c5fd5fcd0 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -613,7 +613,8 @@ static const struct regmap_config twl6040_regmap_config = { .writeable_reg = twl6040_writeable_reg, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const struct regmap_irq twl6040_irqs[] = { diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 2154d1bfd18b..5a755590d3dc 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -183,6 +183,7 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(USERCOPY_STACK_FRAME_FROM), CRASHTYPE(USERCOPY_STACK_BEYOND), CRASHTYPE(USERCOPY_KERNEL), + CRASHTYPE(USERCOPY_KERNEL_DS), }; diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 9e513dcfd809..07db641d71d0 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -82,5 +82,6 @@ void lkdtm_USERCOPY_STACK_FRAME_TO(void); void lkdtm_USERCOPY_STACK_FRAME_FROM(void); void lkdtm_USERCOPY_STACK_BEYOND(void); void lkdtm_USERCOPY_KERNEL(void); +void lkdtm_USERCOPY_KERNEL_DS(void); #endif diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c index 9725aed305bb..389475b25bb7 100644 --- a/drivers/misc/lkdtm/usercopy.c +++ b/drivers/misc/lkdtm/usercopy.c @@ -322,6 +322,19 @@ free_user: vm_munmap(user_addr, PAGE_SIZE); } +void lkdtm_USERCOPY_KERNEL_DS(void) +{ + char __user *user_ptr = (char __user *)ERR_PTR(-EINVAL); + mm_segment_t old_fs = get_fs(); + char buf[10] = {0}; + + pr_info("attempting copy_to_user on unmapped kernel address\n"); + set_fs(KERNEL_DS); + if (copy_to_user(user_ptr, buf, sizeof(buf))) + pr_info("copy_to_user un unmapped kernel address failed\n"); + set_fs(old_fs); +} + void __init lkdtm_usercopy_init(void) { /* Prepare cache that lacks SLAB_USERCOPY flag. */ diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 42e89060cd41..2f38a7ad07e0 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -14,7 +14,7 @@ config PWRSEQ_EMMC config PWRSEQ_SD8787 tristate "HW reset support for SD8787 BT + Wifi module" - depends on OF && (MWIFIEX || BT_MRVL_SDIO) + depends on OF && (MWIFIEX || BT_MRVL_SDIO || LIBERTAS_SDIO) help This selects hardware reset support for the SD8787 BT + Wifi module. By default this option is set to n. diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index e201ccb3fda4..c35b5b08bb33 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2708,7 +2708,7 @@ static int mmc_add_disk(struct mmc_blk_data *md) int ret; struct mmc_card *card = md->queue.card; - device_add_disk(md->parent, md->disk); + device_add_disk(md->parent, md->disk, NULL); md->force_ro.show = force_ro_show; md->force_ro.store = force_ro_store; sysfs_attr_init(&md->force_ro.attr); diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index a8b9fee4d62a..ece34c734693 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -40,17 +40,21 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, struct gpio_descs *reset_gpios = pwrseq->reset_gpios; if (!IS_ERR(reset_gpios)) { - int i, *values; + unsigned long *values; int nvalues = reset_gpios->ndescs; - values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL); + values = bitmap_alloc(nvalues, GFP_KERNEL); if (!values) return; - for (i = 0; i < nvalues; i++) - values[i] = value; + if (value) + bitmap_fill(values, nvalues); + else + bitmap_zero(values, nvalues); + + gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, + reset_gpios->info, values); - gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values); kfree(values); } } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 694d0828215d..1b58739d9744 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -34,6 +34,16 @@ config MMC_QCOM_DML if unsure, say N. +config MMC_STM32_SDMMC + bool "STMicroelectronics STM32 SDMMC Controller" + depends on MMC_ARMMMCI + default y + help + This selects the STMicroelectronics STM32 SDMMC host controller. + If you have a STM32 sdmmc host with internal DMA say Y here. + + If unsure, say N. + config MMC_PXA tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" depends on ARCH_PXA @@ -345,6 +355,7 @@ config MMC_SDHCI_IPROC tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller" depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST depends on MMC_SDHCI_PLTFM + depends on OF || ACPI default ARCH_BCM_IPROC select MMC_SDHCI_IO_ACCESSORS help @@ -592,6 +603,19 @@ config MMC_SDRICOH_CS To compile this driver as a module, choose M here: the module will be called sdricoh_cs. +config MMC_SDHCI_SPRD + tristate "Spreadtrum SDIO host Controller" + depends on ARCH_SPRD + depends on MMC_SDHCI_PLTFM + select MMC_SDHCI_IO_ACCESSORS + help + This selects the SDIO Host Controller in Spreadtrum + SoCs, this driver supports R11(IP version: R11P0). + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_TMIO_CORE tristate @@ -622,14 +646,24 @@ config MMC_SDHI_SYS_DMAC config MMC_SDHI_INTERNAL_DMAC tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering" - depends on ARM64 || COMPILE_TEST + depends on ARM64 || ARCH_R8A77470 || COMPILE_TEST depends on MMC_SDHI - default MMC_SDHI if ARM64 + default MMC_SDHI if (ARM64 || ARCH_R8A77470) help This provides DMA support for SDHI SD/SDIO controllers using on-chip bus mastering. This supports the controllers found in arm64 based SoCs. +config MMC_UNIPHIER + tristate "UniPhier SD/eMMC Host Controller support" + depends on ARCH_UNIPHIER || COMPILE_TEST + depends on OF + select MMC_TMIO_CORE + help + This provides support for the SD/eMMC controller found in + UniPhier SoCs. The eMMC variant of this controller is used + only for 32-bit SoCs. + config MMC_CB710 tristate "ENE CB710 MMC/SD Interface support" depends on PCI @@ -772,7 +806,7 @@ config MMC_SH_MMCIF config MMC_JZ4740 tristate "Ingenic JZ47xx SD/Multimedia Card Interface support" - depends on MACH_JZ4740 || MACH_JZ4780 + depends on MIPS help This selects support for the SD/MMC controller on Ingenic JZ4740, JZ4750, JZ4770 and JZ4780 SoCs. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index ce8398e6f2c0..720d37777098 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o armmmci-y := mmci.o armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o +armmmci-$(CONFIG_MMC_STM32_SDMMC) += mmci_stm32_sdmmc.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o @@ -42,6 +43,7 @@ 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 obj-$(CONFIG_MMC_SDHI_INTERNAL_DMAC) += renesas_sdhi_internal_dmac.o +obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o octeon-mmc-objs := cavium.o cavium-octeon.o @@ -91,6 +93,7 @@ obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o +obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o obj-$(CONFIG_MMC_CQHCI) += cqhci.o ifeq ($(CONFIG_CB710_DEBUG),y) diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index ab47b018716a..d46c3439b508 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -253,6 +253,8 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) if (timing == MMC_TIMING_MMC_HS400) { dqs |= DATA_STROBE_EN; strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay); + } else if (timing == MMC_TIMING_UHS_SDR104) { + dqs &= 0xffffff00; } else { dqs &= ~DATA_STROBE_EN; } @@ -312,6 +314,15 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) if (ios->bus_width == MMC_BUS_WIDTH_8) wanted <<= 1; break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + clksel = (priv->sdr_timing & 0xfff8ffff) | + (priv->ciu_div << 16); + break; + case MMC_TIMING_UHS_DDR50: + clksel = (priv->ddr_timing & 0xfff8ffff) | + (priv->ciu_div << 16); + break; default: clksel = priv->sdr_timing; } diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index f9b333ff259e..bc51cef47c47 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -23,6 +23,12 @@ struct hi3798cv200_priv { struct clk *drive_clk; }; +static unsigned long dw_mci_hi3798cv200_caps[] = { + MMC_CAP_CMD23, + MMC_CAP_CMD23, + MMC_CAP_CMD23 +}; + static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios) { struct hi3798cv200_priv *priv = host->priv; @@ -160,6 +166,8 @@ disable_sample_clk: } static const struct dw_mci_drv_data hi3798cv200_data = { + .caps = dw_mci_hi3798cv200_caps, + .num_caps = ARRAY_SIZE(dw_mci_hi3798cv200_caps), .init = dw_mci_hi3798cv200_init, .set_ios = dw_mci_hi3798cv200_set_ios, .execute_tuning = dw_mci_hi3798cv200_execute_tuning, diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 993386c9ea50..0c1efd5100b7 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -115,7 +115,7 @@ enum jz4740_mmc_version { JZ_MMC_JZ4740, - JZ_MMC_JZ4750, + JZ_MMC_JZ4725B, JZ_MMC_JZ4780, }; @@ -176,7 +176,7 @@ struct jz4740_mmc_host { static void jz4740_mmc_write_irq_mask(struct jz4740_mmc_host *host, uint32_t val) { - if (host->version >= JZ_MMC_JZ4750) + if (host->version >= JZ_MMC_JZ4725B) return writel(val, host->base + JZ_REG_MMC_IMASK); else return writew(val, host->base + JZ_REG_MMC_IMASK); @@ -1012,6 +1012,7 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev) static const struct of_device_id jz4740_mmc_of_match[] = { { .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 }, + { .compatible = "ingenic,jz4725b-mmc", .data = (void *)JZ_MMC_JZ4725B }, { .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 }, {}, }; diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index 2cfec33178c1..abe253c262a2 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -294,7 +294,7 @@ static void meson_mx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_OFF: vdd = 0; - /* fall-through: */ + /* fall through */ case MMC_POWER_UP: if (!IS_ERR(mmc->supply.vmmc)) { host->error = mmc_regulator_set_ocr(mmc, diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 1841d250e9e2..82bab35fff41 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -28,8 +28,7 @@ #include <linux/amba/bus.h> #include <linux/clk.h> #include <linux/scatterlist.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/of.h> #include <linux/regulator/consumer.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> @@ -37,6 +36,7 @@ #include <linux/pm_runtime.h> #include <linux/types.h> #include <linux/pinctrl/consumer.h> +#include <linux/reset.h> #include <asm/div64.h> #include <asm/io.h> @@ -46,41 +46,77 @@ #define DRIVER_NAME "mmci-pl18x" +#ifdef CONFIG_DMA_ENGINE +void mmci_variant_init(struct mmci_host *host); +#else +static inline void mmci_variant_init(struct mmci_host *host) {} +#endif + +#ifdef CONFIG_MMC_STM32_SDMMC +void sdmmc_variant_init(struct mmci_host *host); +#else +static inline void sdmmc_variant_init(struct mmci_host *host) {} +#endif + static unsigned int fmax = 515633; static struct variant_data variant_arm = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 100000000, .reversed_irq_handling = true, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = mmci_variant_init, }; static struct variant_data variant_arm_extended_fifo = { .fifosize = 128 * 4, .fifohalfsize = 64 * 4, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 100000000, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = mmci_variant_init, }; static struct variant_data variant_arm_extended_fifo_hwfc = { .fifosize = 128 * 4, .fifohalfsize = 64 * 4, .clkreg_enable = MCI_ARM_HWFCEN, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 100000000, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = mmci_variant_init, }; static struct variant_data variant_u300 = { @@ -88,7 +124,13 @@ static struct variant_data variant_u300 = { .fifohalfsize = 8 * 4, .clkreg_enable = MCI_ST_U300_HWFCEN, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .pwrreg_powerup = MCI_PWR_ON, @@ -97,8 +139,10 @@ static struct variant_data variant_u300 = { .pwrreg_clkgate = true, .pwrreg_nopower = true, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_nomadik = { @@ -106,7 +150,13 @@ static struct variant_data variant_nomadik = { .fifohalfsize = 8 * 4, .clkreg = MCI_CLK_ENABLE, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, @@ -116,8 +166,10 @@ static struct variant_data variant_nomadik = { .pwrreg_clkgate = true, .pwrreg_nopower = true, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_ux500 = { @@ -127,7 +179,13 @@ static struct variant_data variant_ux500 = { .clkreg_enable = MCI_ST_UX500_HWFCEN, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, @@ -141,8 +199,10 @@ static struct variant_data variant_ux500 = { .busy_detect_mask = MCI_ST_BUSYENDMASK, .pwrreg_nopower = true, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_ux500v2 = { @@ -152,8 +212,14 @@ static struct variant_data variant_ux500v2 = { .clkreg_enable = MCI_ST_UX500_HWFCEN, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE, .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, @@ -168,8 +234,10 @@ static struct variant_data variant_ux500v2 = { .busy_detect_mask = MCI_ST_BUSYENDMASK, .pwrreg_nopower = true, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_stm32 = { @@ -179,7 +247,14 @@ static struct variant_data variant_stm32 = { .clkreg_enable = MCI_ST_UX500_HWFCEN, .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, @@ -187,6 +262,26 @@ static struct variant_data variant_stm32 = { .f_max = 48000000, .pwrreg_clkgate = true, .pwrreg_nopower = true, + .init = mmci_variant_init, +}; + +static struct variant_data variant_stm32_sdmmc = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .f_max = 208000000, + .stm32_clkdiv = true, + .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, + .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, + .cmdreg_srsp = MCI_CPSM_STM32_SRSP, + .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, + .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, + .datactrl_first = true, + .datacnt_useless = true, + .datalength_bits = 25, + .datactrl_blocksz = 14, + .stm32_idmabsize_mask = GENMASK(12, 5), + .init = sdmmc_variant_init, }; static struct variant_data variant_qcom = { @@ -197,15 +292,22 @@ static struct variant_data variant_qcom = { MCI_QCOM_CLK_SELECT_IN_FBCLK, .clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8, .datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, .data_cmd_enable = MCI_CPSM_QCOM_DATCMD, .blksz_datactrl4 = true, .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 208000000, .explicit_mclk_control = true, .qcom_fifo = true, .qcom_dml = true, .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, .init = qcom_variant_init, @@ -226,24 +328,6 @@ static int mmci_card_busy(struct mmc_host *mmc) return busy; } -/* - * Validate mmc prerequisites - */ -static int mmci_validate_data(struct mmci_host *host, - struct mmc_data *data) -{ - if (!data) - return 0; - - if (!is_power_of_2(data->blksz)) { - dev_err(mmc_dev(host->mmc), - "unsupported block size (%d bytes)\n", data->blksz); - return -EINVAL; - } - - return 0; -} - static void mmci_reg_delay(struct mmci_host *host) { /* @@ -262,7 +346,7 @@ static void mmci_reg_delay(struct mmci_host *host) /* * This must be called with host->lock held */ -static void mmci_write_clkreg(struct mmci_host *host, u32 clk) +void mmci_write_clkreg(struct mmci_host *host, u32 clk) { if (host->clk_reg != clk) { host->clk_reg = clk; @@ -273,7 +357,7 @@ static void mmci_write_clkreg(struct mmci_host *host, u32 clk) /* * This must be called with host->lock held */ -static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) +void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) { if (host->pwr_reg != pwr) { host->pwr_reg = pwr; @@ -357,6 +441,135 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) mmci_write_clkreg(host, clk); } +void mmci_dma_release(struct mmci_host *host) +{ + if (host->ops && host->ops->dma_release) + host->ops->dma_release(host); + + host->use_dma = false; +} + +void mmci_dma_setup(struct mmci_host *host) +{ + if (!host->ops || !host->ops->dma_setup) + return; + + if (host->ops->dma_setup(host)) + return; + + /* initialize pre request cookie */ + host->next_cookie = 1; + + host->use_dma = true; +} + +/* + * Validate mmc prerequisites + */ +static int mmci_validate_data(struct mmci_host *host, + struct mmc_data *data) +{ + if (!data) + return 0; + + if (!is_power_of_2(data->blksz)) { + dev_err(mmc_dev(host->mmc), + "unsupported block size (%d bytes)\n", data->blksz); + return -EINVAL; + } + + if (host->ops && host->ops->validate_data) + return host->ops->validate_data(host, data); + + return 0; +} + +int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next) +{ + int err; + + if (!host->ops || !host->ops->prep_data) + return 0; + + err = host->ops->prep_data(host, data, next); + + if (next && !err) + data->host_cookie = ++host->next_cookie < 0 ? + 1 : host->next_cookie; + + return err; +} + +void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data, + int err) +{ + if (host->ops && host->ops->unprep_data) + host->ops->unprep_data(host, data, err); + + data->host_cookie = 0; +} + +void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) +{ + WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); + + if (host->ops && host->ops->get_next_data) + host->ops->get_next_data(host, data); +} + +int mmci_dma_start(struct mmci_host *host, unsigned int datactrl) +{ + struct mmc_data *data = host->data; + int ret; + + if (!host->use_dma) + return -EINVAL; + + ret = mmci_prep_data(host, data, false); + if (ret) + return ret; + + if (!host->ops || !host->ops->dma_start) + return -EINVAL; + + /* Okay, go for it. */ + dev_vdbg(mmc_dev(host->mmc), + "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", + data->sg_len, data->blksz, data->blocks, data->flags); + + host->ops->dma_start(host, &datactrl); + + /* Trigger the DMA transfer */ + mmci_write_datactrlreg(host, datactrl); + + /* + * Let the MMCI say when the data is ended and it's time + * to fire next DMA request. When that happens, MMCI will + * call mmci_data_end() + */ + writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, + host->base + MMCIMASK0); + return 0; +} + +void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +{ + if (!host->use_dma) + return; + + if (host->ops && host->ops->dma_finalize) + host->ops->dma_finalize(host, data); +} + +void mmci_dma_error(struct mmci_host *host) +{ + if (!host->use_dma) + return; + + if (host->ops && host->ops->dma_error) + host->ops->dma_error(host); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -378,7 +591,7 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) if (host->singleirq) { unsigned int mask0 = readl(base + MMCIMASK0); - mask0 &= ~MCI_IRQ1MASK; + mask0 &= ~variant->irq_pio_mask; mask0 |= mask; writel(mask0, base + MMCIMASK0); @@ -415,31 +628,50 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) * no custom DMA interfaces are supported. */ #ifdef CONFIG_DMA_ENGINE -static void mmci_dma_setup(struct mmci_host *host) +struct mmci_dmae_next { + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan; +}; + +struct mmci_dmae_priv { + struct dma_chan *cur; + struct dma_chan *rx_channel; + struct dma_chan *tx_channel; + struct dma_async_tx_descriptor *desc_current; + struct mmci_dmae_next next_data; +}; + +int mmci_dmae_setup(struct mmci_host *host) { const char *rxname, *txname; + struct mmci_dmae_priv *dmae; - host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); - host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); + dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL); + if (!dmae) + return -ENOMEM; - /* initialize pre request cookie */ - host->next_data.cookie = 1; + host->dma_priv = dmae; + + dmae->rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), + "rx"); + dmae->tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), + "tx"); /* * If only an RX channel is specified, the driver will * attempt to use it bidirectionally, however if it is * is specified but cannot be located, DMA will be disabled. */ - if (host->dma_rx_channel && !host->dma_tx_channel) - host->dma_tx_channel = host->dma_rx_channel; + if (dmae->rx_channel && !dmae->tx_channel) + dmae->tx_channel = dmae->rx_channel; - if (host->dma_rx_channel) - rxname = dma_chan_name(host->dma_rx_channel); + if (dmae->rx_channel) + rxname = dma_chan_name(dmae->rx_channel); else rxname = "none"; - if (host->dma_tx_channel) - txname = dma_chan_name(host->dma_tx_channel); + if (dmae->tx_channel) + txname = dma_chan_name(dmae->tx_channel); else txname = "none"; @@ -450,66 +682,84 @@ static void mmci_dma_setup(struct mmci_host *host) * Limit the maximum segment size in any SG entry according to * the parameters of the DMA engine device. */ - if (host->dma_tx_channel) { - struct device *dev = host->dma_tx_channel->device->dev; + if (dmae->tx_channel) { + struct device *dev = dmae->tx_channel->device->dev; unsigned int max_seg_size = dma_get_max_seg_size(dev); if (max_seg_size < host->mmc->max_seg_size) host->mmc->max_seg_size = max_seg_size; } - if (host->dma_rx_channel) { - struct device *dev = host->dma_rx_channel->device->dev; + if (dmae->rx_channel) { + struct device *dev = dmae->rx_channel->device->dev; unsigned int max_seg_size = dma_get_max_seg_size(dev); if (max_seg_size < host->mmc->max_seg_size) host->mmc->max_seg_size = max_seg_size; } - if (host->ops && host->ops->dma_setup) - host->ops->dma_setup(host); + if (!dmae->tx_channel || !dmae->rx_channel) { + mmci_dmae_release(host); + return -EINVAL; + } + + return 0; } /* * This is used in or so inline it * so it can be discarded. */ -static inline void mmci_dma_release(struct mmci_host *host) +void mmci_dmae_release(struct mmci_host *host) { - if (host->dma_rx_channel) - dma_release_channel(host->dma_rx_channel); - if (host->dma_tx_channel) - dma_release_channel(host->dma_tx_channel); - host->dma_rx_channel = host->dma_tx_channel = NULL; -} + struct mmci_dmae_priv *dmae = host->dma_priv; -static void mmci_dma_data_error(struct mmci_host *host) -{ - dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); - dmaengine_terminate_all(host->dma_current); - host->dma_in_progress = false; - host->dma_current = NULL; - host->dma_desc_current = NULL; - host->data->host_cookie = 0; + if (dmae->rx_channel) + dma_release_channel(dmae->rx_channel); + if (dmae->tx_channel) + dma_release_channel(dmae->tx_channel); + dmae->rx_channel = dmae->tx_channel = NULL; } static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) { + struct mmci_dmae_priv *dmae = host->dma_priv; struct dma_chan *chan; if (data->flags & MMC_DATA_READ) - chan = host->dma_rx_channel; + chan = dmae->rx_channel; else - chan = host->dma_tx_channel; + chan = dmae->tx_channel; dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, mmc_get_dma_dir(data)); } -static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +void mmci_dmae_error(struct mmci_host *host) { + struct mmci_dmae_priv *dmae = host->dma_priv; + + if (!dma_inprogress(host)) + return; + + dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); + dmaengine_terminate_all(dmae->cur); + host->dma_in_progress = false; + dmae->cur = NULL; + dmae->desc_current = NULL; + host->data->host_cookie = 0; + + mmci_dma_unmap(host, host->data); +} + +void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; u32 status; int i; + if (!dma_inprogress(host)) + return; + /* Wait up to 1ms for the DMA to complete */ for (i = 0; ; i++) { status = readl(host->base + MMCISTATUS); @@ -525,13 +775,12 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) * contiguous buffers. On TX, we'll get a FIFO underrun error. */ if (status & MCI_RXDATAAVLBLMASK) { - mmci_dma_data_error(host); + mmci_dma_error(host); if (!data->error) data->error = -EIO; - } - - if (!data->host_cookie) + } else if (!data->host_cookie) { mmci_dma_unmap(host, data); + } /* * Use of DMA with scatter-gather is impossible. @@ -543,15 +792,16 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) } host->dma_in_progress = false; - host->dma_current = NULL; - host->dma_desc_current = NULL; + dmae->cur = NULL; + dmae->desc_current = NULL; } /* prepares DMA channel and DMA descriptor, returns non-zero on failure */ -static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, +static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, struct dma_chan **dma_chan, struct dma_async_tx_descriptor **dma_desc) { + struct mmci_dmae_priv *dmae = host->dma_priv; struct variant_data *variant = host->variant; struct dma_slave_config conf = { .src_addr = host->phybase + MMCIFIFO, @@ -570,10 +820,10 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, if (data->flags & MMC_DATA_READ) { conf.direction = DMA_DEV_TO_MEM; - chan = host->dma_rx_channel; + chan = dmae->rx_channel; } else { conf.direction = DMA_MEM_TO_DEV; - chan = host->dma_tx_channel; + chan = dmae->tx_channel; } /* If there's no DMA channel, fall back to PIO */ @@ -610,160 +860,137 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, return -ENOMEM; } -static inline int mmci_dma_prep_data(struct mmci_host *host, - struct mmc_data *data) +int mmci_dmae_prep_data(struct mmci_host *host, + struct mmc_data *data, + bool next) { + struct mmci_dmae_priv *dmae = host->dma_priv; + struct mmci_dmae_next *nd = &dmae->next_data; + + if (!host->use_dma) + return -EINVAL; + + if (next) + return _mmci_dmae_prep_data(host, data, &nd->chan, &nd->desc); /* Check if next job is already prepared. */ - if (host->dma_current && host->dma_desc_current) + if (dmae->cur && dmae->desc_current) return 0; /* No job were prepared thus do it now. */ - return __mmci_dma_prep_data(host, data, &host->dma_current, - &host->dma_desc_current); -} - -static inline int mmci_dma_prep_next(struct mmci_host *host, - struct mmc_data *data) -{ - struct mmci_host_next *nd = &host->next_data; - return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc); + return _mmci_dmae_prep_data(host, data, &dmae->cur, + &dmae->desc_current); } -static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) { - int ret; + struct mmci_dmae_priv *dmae = host->dma_priv; struct mmc_data *data = host->data; - ret = mmci_dma_prep_data(host, host->data); - if (ret) - return ret; - - /* Okay, go for it. */ - dev_vdbg(mmc_dev(host->mmc), - "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", - data->sg_len, data->blksz, data->blocks, data->flags); host->dma_in_progress = true; - dmaengine_submit(host->dma_desc_current); - dma_async_issue_pending(host->dma_current); + dmaengine_submit(dmae->desc_current); + dma_async_issue_pending(dmae->cur); if (host->variant->qcom_dml) dml_start_xfer(host, data); - datactrl |= MCI_DPSM_DMAENABLE; + *datactrl |= MCI_DPSM_DMAENABLE; - /* Trigger the DMA transfer */ - mmci_write_datactrlreg(host, datactrl); - - /* - * Let the MMCI say when the data is ended and it's time - * to fire next DMA request. When that happens, MMCI will - * call mmci_data_end() - */ - writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, - host->base + MMCIMASK0); return 0; } -static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) +void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data) { - struct mmci_host_next *next = &host->next_data; - - WARN_ON(data->host_cookie && data->host_cookie != next->cookie); - WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan)); - - host->dma_desc_current = next->dma_desc; - host->dma_current = next->dma_chan; - next->dma_desc = NULL; - next->dma_chan = NULL; -} + struct mmci_dmae_priv *dmae = host->dma_priv; + struct mmci_dmae_next *next = &dmae->next_data; -static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct mmci_host *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - struct mmci_host_next *nd = &host->next_data; - - if (!data) + if (!host->use_dma) return; - BUG_ON(data->host_cookie); + WARN_ON(!data->host_cookie && (next->desc || next->chan)); - if (mmci_validate_data(host, data)) - return; - - if (!mmci_dma_prep_next(host, data)) - data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie; + dmae->desc_current = next->desc; + dmae->cur = next->chan; + next->desc = NULL; + next->chan = NULL; } -static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, - int err) +void mmci_dmae_unprep_data(struct mmci_host *host, + struct mmc_data *data, int err) + { - struct mmci_host *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; + struct mmci_dmae_priv *dmae = host->dma_priv; - if (!data || !data->host_cookie) + if (!host->use_dma) return; mmci_dma_unmap(host, data); if (err) { - struct mmci_host_next *next = &host->next_data; + struct mmci_dmae_next *next = &dmae->next_data; struct dma_chan *chan; if (data->flags & MMC_DATA_READ) - chan = host->dma_rx_channel; + chan = dmae->rx_channel; else - chan = host->dma_tx_channel; + chan = dmae->tx_channel; dmaengine_terminate_all(chan); - if (host->dma_desc_current == next->dma_desc) - host->dma_desc_current = NULL; + if (dmae->desc_current == next->desc) + dmae->desc_current = NULL; - if (host->dma_current == next->dma_chan) { + if (dmae->cur == next->chan) { host->dma_in_progress = false; - host->dma_current = NULL; + dmae->cur = NULL; } - next->dma_desc = NULL; - next->dma_chan = NULL; - data->host_cookie = 0; + next->desc = NULL; + next->chan = NULL; } } -#else -/* Blank functions if the DMA engine is not available */ -static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) -{ -} -static inline void mmci_dma_setup(struct mmci_host *host) -{ -} +static struct mmci_host_ops mmci_variant_ops = { + .prep_data = mmci_dmae_prep_data, + .unprep_data = mmci_dmae_unprep_data, + .get_next_data = mmci_dmae_get_next_data, + .dma_setup = mmci_dmae_setup, + .dma_release = mmci_dmae_release, + .dma_start = mmci_dmae_start, + .dma_finalize = mmci_dmae_finalize, + .dma_error = mmci_dmae_error, +}; -static inline void mmci_dma_release(struct mmci_host *host) +void mmci_variant_init(struct mmci_host *host) { + host->ops = &mmci_variant_ops; } +#endif -static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) +static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) { -} + struct mmci_host *host = mmc_priv(mmc); + struct mmc_data *data = mrq->data; -static inline void mmci_dma_finalize(struct mmci_host *host, - struct mmc_data *data) -{ -} + if (!data) + return; -static inline void mmci_dma_data_error(struct mmci_host *host) -{ + WARN_ON(data->host_cookie); + + if (mmci_validate_data(host, data)) + return; + + mmci_prep_data(host, data, true); } -static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, + int err) { - return -ENOSYS; -} + struct mmci_host *host = mmc_priv(mmc); + struct mmc_data *data = mrq->data; -#define mmci_pre_request NULL -#define mmci_post_request NULL + if (!data || !data->host_cookie) + return; -#endif + mmci_unprep_data(host, data, err); +} static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { @@ -793,11 +1020,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) BUG_ON(1 << blksz_bits != data->blksz); if (variant->blksz_datactrl16) - datactrl = MCI_DPSM_ENABLE | (data->blksz << 16); + datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16); else if (variant->blksz_datactrl4) - datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); + datactrl = variant->datactrl_dpsm_enable | (data->blksz << 4); else - datactrl = MCI_DPSM_ENABLE | blksz_bits << 4; + datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4; if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; @@ -831,7 +1058,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) * Attempt to use DMA operation mode, if this * should fail, fall back to PIO mode */ - if (!mmci_dma_start_data(host, datactrl)) + if (!mmci_dma_start(host, datactrl)) return; /* IRQ mode, map the SG list for CPU reading/writing */ @@ -868,16 +1095,19 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags); - if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { + if (readl(base + MMCICOMMAND) & host->variant->cmdreg_cpsm_enable) { writel(0, base + MMCICOMMAND); mmci_reg_delay(host); } - c |= cmd->opcode | MCI_CPSM_ENABLE; + c |= cmd->opcode | host->variant->cmdreg_cpsm_enable; if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) - c |= MCI_CPSM_LONGRSP; - c |= MCI_CPSM_RESPONSE; + c |= host->variant->cmdreg_lrsp_crc; + else if (cmd->flags & MMC_RSP_CRC) + c |= host->variant->cmdreg_srsp_crc; + else + c |= host->variant->cmdreg_srsp; } if (/*interrupt*/0) c |= MCI_CPSM_INTERRUPT; @@ -895,21 +1125,22 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { + unsigned int status_err; + /* Make sure we have data to handle */ if (!data) return; /* First check for errors */ - if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | - host->variant->start_err | - MCI_TXUNDERRUN | MCI_RXOVERRUN)) { + status_err = status & (host->variant->start_err | + MCI_DATACRCFAIL | MCI_DATATIMEOUT | + MCI_TXUNDERRUN | MCI_RXOVERRUN); + + if (status_err) { u32 remain, success; /* Terminate the DMA transfer */ - if (dma_inprogress(host)) { - mmci_dma_data_error(host); - mmci_dma_unmap(host, data); - } + mmci_dma_error(host); /* * Calculate how far we are into the transfer. Note that @@ -918,22 +1149,26 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, * can be as much as a FIFO-worth of data ahead. This * matters for FIFO overruns only. */ - remain = readl(host->base + MMCIDATACNT); - success = data->blksz * data->blocks - remain; + if (!host->variant->datacnt_useless) { + remain = readl(host->base + MMCIDATACNT); + success = data->blksz * data->blocks - remain; + } else { + success = 0; + } dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", - status, success); - if (status & MCI_DATACRCFAIL) { + status_err, success); + if (status_err & MCI_DATACRCFAIL) { /* Last block was not successful */ success -= 1; data->error = -EILSEQ; - } else if (status & MCI_DATATIMEOUT) { + } else if (status_err & MCI_DATATIMEOUT) { data->error = -ETIMEDOUT; - } else if (status & MCI_STARTBITERR) { + } else if (status_err & MCI_STARTBITERR) { data->error = -ECOMM; - } else if (status & MCI_TXUNDERRUN) { + } else if (status_err & MCI_TXUNDERRUN) { data->error = -EIO; - } else if (status & MCI_RXOVERRUN) { + } else if (status_err & MCI_RXOVERRUN) { if (success > host->variant->fifosize) success -= host->variant->fifosize; else @@ -947,8 +1182,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); if (status & MCI_DATAEND || data->error) { - if (dma_inprogress(host)) - mmci_dma_finalize(host, data); + mmci_dma_finalize(host, data); + mmci_stop_data(host); if (!data->error) @@ -1055,16 +1290,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, if ((!sbc && !cmd->data) || cmd->error) { if (host->data) { /* Terminate the DMA transfer */ - if (dma_inprogress(host)) { - mmci_dma_data_error(host); - mmci_dma_unmap(host, host->data); - } + mmci_dma_error(host); + mmci_stop_data(host); } mmci_request_end(host, host->mrq); } else if (sbc) { mmci_start_command(host, host->mrq->cmd, 0); - } else if (!(cmd->data->flags & MMC_DATA_READ)) { + } else if (!host->variant->datactrl_first && + !(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); } } @@ -1264,7 +1498,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) if (status & host->mask1_reg) mmci_pio_irq(irq, dev_id); - status &= ~MCI_IRQ1MASK; + status &= ~host->variant->irq_pio_mask; } /* @@ -1328,7 +1562,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) if (mrq->data) mmci_get_next_data(host, mrq->data); - if (mrq->data && mrq->data->flags & MMC_DATA_READ) + if (mrq->data && + (host->variant->datactrl_first || mrq->data->flags & MMC_DATA_READ)) mmci_start_data(host, mrq->data); if (mrq->sbc) @@ -1438,8 +1673,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); - mmci_set_clkreg(host, ios->clock); - mmci_write_pwrreg(host, pwr); + if (host->ops && host->ops->set_clkreg) + host->ops->set_clkreg(host, ios->clock); + else + mmci_set_clkreg(host, ios->clock); + + if (host->ops && host->ops->set_pwrreg) + host->ops->set_pwrreg(host, pwr); + else + mmci_write_pwrreg(host, pwr); + mmci_reg_delay(host); spin_unlock_irqrestore(&host->lock, flags); @@ -1518,6 +1761,12 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) host->pwr_reg_add |= MCI_ST_CMDDIREN; if (of_get_property(np, "st,sig-pin-fbclk", NULL)) host->pwr_reg_add |= MCI_ST_FBCLKEN; + if (of_get_property(np, "st,sig-dir", NULL)) + host->pwr_reg_add |= MCI_STM32_DIRPOL; + if (of_get_property(np, "st,neg-edge", NULL)) + host->clk_reg_add |= MCI_STM32_CLK_NEGEDGE; + if (of_get_property(np, "st,use-ckin", NULL)) + host->clk_reg_add |= MCI_STM32_CLK_SELCKIN; if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) mmc->caps |= MMC_CAP_MMC_HIGHSPEED; @@ -1644,6 +1893,8 @@ static int mmci_probe(struct amba_device *dev, */ if (variant->st_clkdiv) mmc->f_min = DIV_ROUND_UP(host->mclk, 257); + else if (variant->stm32_clkdiv) + mmc->f_min = DIV_ROUND_UP(host->mclk, 2046); else if (variant->explicit_mclk_control) mmc->f_min = clk_round_rate(host->clk, 100000); else @@ -1665,6 +1916,12 @@ static int mmci_probe(struct amba_device *dev, dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); + host->rst = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); + if (IS_ERR(host->rst)) { + ret = PTR_ERR(host->rst); + goto clk_disable; + } + /* Get regulators and the supported OCR mask */ ret = mmc_regulator_get_supply(mmc); if (ret) @@ -1675,13 +1932,6 @@ static int mmci_probe(struct amba_device *dev, else if (plat->ocr_mask) dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); - /* DT takes precedence over platform data. */ - if (!np) { - if (!plat->cd_invert) - mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; - mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; - } - /* We support these capabilities. */ mmc->caps |= MMC_CAP_CMD23; @@ -1727,13 +1977,13 @@ static int mmci_probe(struct amba_device *dev, /* * Block size can be up to 2048 bytes, but must be a power of two. */ - mmc->max_blk_size = 1 << 11; + mmc->max_blk_size = 1 << variant->datactrl_blocksz; /* * Limit the number of blocks transferred so that we don't overflow * the maximum request size. */ - mmc->max_blk_count = mmc->max_req_size >> 11; + mmc->max_blk_count = mmc->max_req_size >> variant->datactrl_blocksz; spin_lock_init(&host->lock); @@ -1749,30 +1999,16 @@ static int mmci_probe(struct amba_device *dev, * - not using DT but using a descriptor table, or * - using a table of descriptors ALONGSIDE DT, or * look up these descriptors named "cd" and "wp" right here, fail - * silently of these do not exist and proceed to try platform data + * silently of these do not exist */ if (!np) { ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL); - if (ret < 0) { - if (ret == -EPROBE_DEFER) - goto clk_disable; - else if (gpio_is_valid(plat->gpio_cd)) { - ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0); - if (ret) - goto clk_disable; - } - } + if (ret == -EPROBE_DEFER) + goto clk_disable; ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL); - if (ret < 0) { - if (ret == -EPROBE_DEFER) - goto clk_disable; - else if (gpio_is_valid(plat->gpio_wp)) { - ret = mmc_gpio_request_ro(mmc, plat->gpio_wp); - if (ret) - goto clk_disable; - } - } + if (ret == -EPROBE_DEFER) + goto clk_disable; } ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED, @@ -1789,7 +2025,7 @@ static int mmci_probe(struct amba_device *dev, goto clk_disable; } - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + writel(MCI_IRQENABLE | variant->start_err, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); @@ -1876,7 +2112,8 @@ static void mmci_restore(struct mmci_host *host) writel(host->datactrl_reg, host->base + MMCIDATACTRL); writel(host->pwr_reg, host->base + MMCIPOWER); } - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + writel(MCI_IRQENABLE | host->variant->start_err, + host->base + MMCIMASK0); mmci_reg_delay(host); spin_unlock_irqrestore(&host->lock, flags); @@ -1971,6 +2208,11 @@ static const struct amba_id mmci_ids[] = { .mask = 0x00ffffff, .data = &variant_stm32, }, + { + .id = 0x10153180, + .mask = 0xf0ffffff, + .data = &variant_stm32_sdmmc, + }, /* Qualcomm variants */ { .id = 0x00051180, diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 517591d219e9..550dd3914461 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -23,6 +23,14 @@ #define MCI_ST_DATA31DIREN (1 << 5) #define MCI_ST_FBCLKEN (1 << 7) #define MCI_ST_DATA74DIREN (1 << 8) +/* + * The STM32 sdmmc does not have PWR_UP/OD/ROD + * and uses the power register for + */ +#define MCI_STM32_PWR_CYC 0x02 +#define MCI_STM32_VSWITCH BIT(2) +#define MCI_STM32_VSWITCHEN BIT(3) +#define MCI_STM32_DIRPOL BIT(4) #define MMCICLOCK 0x004 #define MCI_CLK_ENABLE (1 << 8) @@ -50,6 +58,19 @@ #define MCI_QCOM_CLK_SELECT_IN_FBCLK BIT(15) #define MCI_QCOM_CLK_SELECT_IN_DDR_MODE (BIT(14) | BIT(15)) +/* Modified on STM32 sdmmc */ +#define MCI_STM32_CLK_CLKDIV_MSK GENMASK(9, 0) +#define MCI_STM32_CLK_WIDEBUS_4 BIT(14) +#define MCI_STM32_CLK_WIDEBUS_8 BIT(15) +#define MCI_STM32_CLK_NEGEDGE BIT(16) +#define MCI_STM32_CLK_HWFCEN BIT(17) +#define MCI_STM32_CLK_DDR BIT(18) +#define MCI_STM32_CLK_BUSSPEED BIT(19) +#define MCI_STM32_CLK_SEL_MSK GENMASK(21, 20) +#define MCI_STM32_CLK_SELCK (0 << 20) +#define MCI_STM32_CLK_SELCKIN (1 << 20) +#define MCI_STM32_CLK_SELFBCK (2 << 20) + #define MMCIARGUMENT 0x008 /* The command register controls the Command Path State Machine (CPSM) */ @@ -72,6 +93,15 @@ #define MCI_CPSM_QCOM_CCSDISABLE BIT(15) #define MCI_CPSM_QCOM_AUTO_CMD19 BIT(16) #define MCI_CPSM_QCOM_AUTO_CMD21 BIT(21) +/* Command register in STM32 sdmmc versions */ +#define MCI_CPSM_STM32_CMDTRANS BIT(6) +#define MCI_CPSM_STM32_CMDSTOP BIT(7) +#define MCI_CPSM_STM32_WAITRESP_MASK GENMASK(9, 8) +#define MCI_CPSM_STM32_NORSP (0 << 8) +#define MCI_CPSM_STM32_SRSP_CRC (1 << 8) +#define MCI_CPSM_STM32_SRSP (2 << 8) +#define MCI_CPSM_STM32_LRSP_CRC (3 << 8) +#define MCI_CPSM_STM32_ENABLE BIT(12) #define MMCIRESPCMD 0x010 #define MMCIRESPONSE0 0x014 @@ -130,6 +160,8 @@ #define MCI_ST_SDIOIT (1 << 22) #define MCI_ST_CEATAEND (1 << 23) #define MCI_ST_CARDBUSY (1 << 24) +/* Extended status bits for the STM32 variants */ +#define MCI_STM32_BUSYD0 BIT(20) #define MMCICLEAR 0x038 #define MCI_CMDCRCFAILCLR (1 << 0) @@ -175,21 +207,45 @@ #define MCI_ST_SDIOITMASK (1 << 22) #define MCI_ST_CEATAENDMASK (1 << 23) #define MCI_ST_BUSYENDMASK (1 << 24) +/* Extended status bits for the STM32 variants */ +#define MCI_STM32_BUSYD0ENDMASK BIT(21) #define MMCIMASK1 0x040 #define MMCIFIFOCNT 0x048 #define MMCIFIFO 0x080 /* to 0x0bc */ +/* STM32 sdmmc registers for IDMA (Internal DMA) */ +#define MMCI_STM32_IDMACTRLR 0x050 +#define MMCI_STM32_IDMAEN BIT(0) +#define MMCI_STM32_IDMALLIEN BIT(1) + +#define MMCI_STM32_IDMABSIZER 0x054 +#define MMCI_STM32_IDMABNDT_SHIFT 5 +#define MMCI_STM32_IDMABNDT_MASK GENMASK(12, 5) + +#define MMCI_STM32_IDMABASE0R 0x058 + +#define MMCI_STM32_IDMALAR 0x64 +#define MMCI_STM32_IDMALA_MASK GENMASK(13, 0) +#define MMCI_STM32_ABR BIT(29) +#define MMCI_STM32_ULS BIT(30) +#define MMCI_STM32_ULA BIT(31) + +#define MMCI_STM32_IDMABAR 0x68 + #define MCI_IRQENABLE \ - (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ - MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK) + (MCI_CMDCRCFAILMASK | MCI_DATACRCFAILMASK | MCI_CMDTIMEOUTMASK | \ + MCI_DATATIMEOUTMASK | MCI_TXUNDERRUNMASK | MCI_RXOVERRUNMASK | \ + MCI_CMDRESPENDMASK | MCI_CMDSENTMASK) /* These interrupts are directed to IRQ1 when two IRQ lines are available */ -#define MCI_IRQ1MASK \ +#define MCI_IRQ_PIO_MASK \ (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ MCI_TXFIFOHALFEMPTYMASK) +#define MCI_IRQ_PIO_STM32_MASK \ + (MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK) + #define NR_SG 128 #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain" @@ -204,6 +260,10 @@ struct mmci_host; * @clkreg_enable: enable value for MMCICLOCK register * @clkreg_8bit_bus_enable: enable value for 8 bit bus * @clkreg_neg_edge_enable: enable value for inverted data/cmd output + * @cmdreg_cpsm_enable: enable value for CPSM + * @cmdreg_lrsp_crc: enable value for long response with crc + * @cmdreg_srsp_crc: enable value for short response with crc + * @cmdreg_srsp: enable value for short response without crc * @datalength_bits: number of bits in the MMCIDATALENGTH register * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY * is asserted (likewise for RX) @@ -212,11 +272,17 @@ struct mmci_host; * @data_cmd_enable: enable value for data commands. * @st_sdio: enable ST specific SDIO logic * @st_clkdiv: true if using a ST-specific clock divider algorithm + * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm * @datactrl_mask_ddrmode: ddr mode mask in datactrl register. * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl * register * @datactrl_mask_sdio: SDIO enable mask in datactrl register + * @datactrl_blksz: block size in power of two + * @datactrl_dpsm_enable: enable value for DPSM + * @datactrl_first: true if data must be setup before send command + * @datacnt_useless: true if you could not use datacnt register to read + * remaining data * @pwrreg_powerup: power up value for MMCIPOWER register * @f_max: maximum clk frequency supported by the controller. * @signal_direction: input/out direction of bus signals can be indicated @@ -233,53 +299,75 @@ struct mmci_host; * @qcom_dml: enables qcom specific dma glue for dma transfers. * @reversed_irq_handling: handle data irq before cmd irq. * @mmcimask1: true if variant have a MMCIMASK1 register. + * @irq_pio_mask: bitmask used to manage interrupt pio transfert in mmcimask + * register * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS * register. * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register + * @dma_lli: true if variant has dma link list feature. + * @stm32_idmabsize_mask: stm32 sdmmc idma buffer size. */ struct variant_data { unsigned int clkreg; unsigned int clkreg_enable; unsigned int clkreg_8bit_bus_enable; unsigned int clkreg_neg_edge_enable; + unsigned int cmdreg_cpsm_enable; + unsigned int cmdreg_lrsp_crc; + unsigned int cmdreg_srsp_crc; + unsigned int cmdreg_srsp; unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; unsigned int data_cmd_enable; unsigned int datactrl_mask_ddrmode; unsigned int datactrl_mask_sdio; - bool st_sdio; - bool st_clkdiv; - bool blksz_datactrl16; - bool blksz_datactrl4; + unsigned int datactrl_blocksz; + unsigned int datactrl_dpsm_enable; + u8 datactrl_first:1; + u8 datacnt_useless:1; + u8 st_sdio:1; + u8 st_clkdiv:1; + u8 stm32_clkdiv:1; + u8 blksz_datactrl16:1; + u8 blksz_datactrl4:1; u32 pwrreg_powerup; u32 f_max; - bool signal_direction; - bool pwrreg_clkgate; - bool busy_detect; + u8 signal_direction:1; + u8 pwrreg_clkgate:1; + u8 busy_detect:1; u32 busy_dpsm_flag; u32 busy_detect_flag; u32 busy_detect_mask; - bool pwrreg_nopower; - bool explicit_mclk_control; - bool qcom_fifo; - bool qcom_dml; - bool reversed_irq_handling; - bool mmcimask1; + u8 pwrreg_nopower:1; + u8 explicit_mclk_control:1; + u8 qcom_fifo:1; + u8 qcom_dml:1; + u8 reversed_irq_handling:1; + u8 mmcimask1:1; + unsigned int irq_pio_mask; u32 start_err; u32 opendrain; + u8 dma_lli:1; + u32 stm32_idmabsize_mask; void (*init)(struct mmci_host *host); }; /* mmci variant callbacks */ struct mmci_host_ops { - void (*dma_setup)(struct mmci_host *host); -}; - -struct mmci_host_next { - struct dma_async_tx_descriptor *dma_desc; - struct dma_chan *dma_chan; - s32 cookie; + int (*validate_data)(struct mmci_host *host, struct mmc_data *data); + int (*prep_data)(struct mmci_host *host, struct mmc_data *data, + bool next); + void (*unprep_data)(struct mmci_host *host, struct mmc_data *data, + int err); + void (*get_next_data)(struct mmci_host *host, struct mmc_data *data); + int (*dma_setup)(struct mmci_host *host); + void (*dma_release)(struct mmci_host *host); + int (*dma_start)(struct mmci_host *host, unsigned int *datactrl); + void (*dma_finalize)(struct mmci_host *host, struct mmc_data *data); + void (*dma_error)(struct mmci_host *host); + void (*set_clkreg)(struct mmci_host *host, unsigned int desired); + void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); }; struct mmci_host { @@ -290,7 +378,9 @@ struct mmci_host { struct mmc_data *data; struct mmc_host *mmc; struct clk *clk; - bool singleirq; + u8 singleirq:1; + + struct reset_control *rst; spinlock_t lock; @@ -301,10 +391,11 @@ struct mmci_host { u32 pwr_reg; u32 pwr_reg_add; u32 clk_reg; + u32 clk_reg_add; u32 datactrl_reg; u32 busy_status; u32 mask1_reg; - bool vqmmc_enabled; + u8 vqmmc_enabled:1; struct mmci_platform_data *plat; struct mmci_host_ops *ops; struct variant_data *variant; @@ -323,18 +414,25 @@ struct mmci_host { unsigned int size; int (*get_rx_fifocnt)(struct mmci_host *h, u32 status, int remain); -#ifdef CONFIG_DMA_ENGINE - /* DMA stuff */ - struct dma_chan *dma_current; - struct dma_chan *dma_rx_channel; - struct dma_chan *dma_tx_channel; - struct dma_async_tx_descriptor *dma_desc_current; - struct mmci_host_next next_data; - bool dma_in_progress; + u8 use_dma:1; + u8 dma_in_progress:1; + void *dma_priv; -#define dma_inprogress(host) ((host)->dma_in_progress) -#else -#define dma_inprogress(host) (0) -#endif + s32 next_cookie; }; +#define dma_inprogress(host) ((host)->dma_in_progress) + +void mmci_write_clkreg(struct mmci_host *host, u32 clk); +void mmci_write_pwrreg(struct mmci_host *host, u32 pwr); + +int mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, + bool next); +void mmci_dmae_unprep_data(struct mmci_host *host, struct mmc_data *data, + int err); +void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data); +int mmci_dmae_setup(struct mmci_host *host); +void mmci_dmae_release(struct mmci_host *host); +int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl); +void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data); +void mmci_dmae_error(struct mmci_host *host); diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index be3fab5db83f..25d0a75533ea 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -119,19 +119,23 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name) } /* Initialize the dml hardware connected to SD Card controller */ -static void qcom_dma_setup(struct mmci_host *host) +static int qcom_dma_setup(struct mmci_host *host) { u32 config; void __iomem *base; int consumer_id, producer_id; struct device_node *np = host->mmc->parent->of_node; + if (mmci_dmae_setup(host)) + return -EINVAL; + consumer_id = of_get_dml_pipe_index(np, "tx"); producer_id = of_get_dml_pipe_index(np, "rx"); if (producer_id < 0 || consumer_id < 0) { host->variant->qcom_dml = false; - return; + mmci_dmae_release(host); + return -EINVAL; } base = host->base + DML_OFFSET; @@ -175,10 +179,19 @@ static void qcom_dma_setup(struct mmci_host *host) /* Make sure dml initialization is finished */ mb(); + + return 0; } static struct mmci_host_ops qcom_variant_ops = { + .prep_data = mmci_dmae_prep_data, + .unprep_data = mmci_dmae_unprep_data, + .get_next_data = mmci_dmae_get_next_data, .dma_setup = qcom_dma_setup, + .dma_release = mmci_dmae_release, + .dma_start = mmci_dmae_start, + .dma_finalize = mmci_dmae_finalize, + .dma_error = mmci_dmae_error, }; void qcom_variant_init(struct mmci_host *host) diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c new file mode 100644 index 000000000000..cfbfc6f1048f --- /dev/null +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Ludovic.barre@st.com for STMicroelectronics. + */ +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/reset.h> +#include <linux/scatterlist.h> +#include "mmci.h" + +#define SDMMC_LLI_BUF_LEN PAGE_SIZE +#define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT) + +struct sdmmc_lli_desc { + u32 idmalar; + u32 idmabase; + u32 idmasize; +}; + +struct sdmmc_priv { + dma_addr_t sg_dma; + void *sg_cpu; +}; + +int sdmmc_idma_validate_data(struct mmci_host *host, + struct mmc_data *data) +{ + struct scatterlist *sg; + int i; + + /* + * idma has constraints on idmabase & idmasize for each element + * excepted the last element which has no constraint on idmasize + */ + for_each_sg(data->sg, sg, data->sg_len - 1, i) { + if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) || + !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) { + dev_err(mmc_dev(host->mmc), + "unaligned scatterlist: ofst:%x length:%d\n", + data->sg->offset, data->sg->length); + return -EINVAL; + } + } + + if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) { + dev_err(mmc_dev(host->mmc), + "unaligned last scatterlist: ofst:%x length:%d\n", + data->sg->offset, data->sg->length); + return -EINVAL; + } + + return 0; +} + +static int _sdmmc_idma_prep_data(struct mmci_host *host, + struct mmc_data *data) +{ + int n_elem; + + n_elem = dma_map_sg(mmc_dev(host->mmc), + data->sg, + data->sg_len, + mmc_get_dma_dir(data)); + + if (!n_elem) { + dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n"); + return -EINVAL; + } + + return 0; +} + +static int sdmmc_idma_prep_data(struct mmci_host *host, + struct mmc_data *data, bool next) +{ + /* Check if job is already prepared. */ + if (!next && data->host_cookie == host->next_cookie) + return 0; + + return _sdmmc_idma_prep_data(host, data); +} + +static void sdmmc_idma_unprep_data(struct mmci_host *host, + struct mmc_data *data, int err) +{ + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + mmc_get_dma_dir(data)); +} + +static int sdmmc_idma_setup(struct mmci_host *host) +{ + struct sdmmc_priv *idma; + + idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); + if (!idma) + return -ENOMEM; + + host->dma_priv = idma; + + if (host->variant->dma_lli) { + idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc), + SDMMC_LLI_BUF_LEN, + &idma->sg_dma, GFP_KERNEL); + if (!idma->sg_cpu) { + dev_err(mmc_dev(host->mmc), + "Failed to alloc IDMA descriptor\n"); + return -ENOMEM; + } + host->mmc->max_segs = SDMMC_LLI_BUF_LEN / + sizeof(struct sdmmc_lli_desc); + host->mmc->max_seg_size = host->variant->stm32_idmabsize_mask; + } else { + host->mmc->max_segs = 1; + host->mmc->max_seg_size = host->mmc->max_req_size; + } + + return 0; +} + +static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) + +{ + struct sdmmc_priv *idma = host->dma_priv; + struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu; + struct mmc_data *data = host->data; + struct scatterlist *sg; + int i; + + if (!host->variant->dma_lli || data->sg_len == 1) { + writel_relaxed(sg_dma_address(data->sg), + host->base + MMCI_STM32_IDMABASE0R); + writel_relaxed(MMCI_STM32_IDMAEN, + host->base + MMCI_STM32_IDMACTRLR); + return 0; + } + + for_each_sg(data->sg, sg, data->sg_len, i) { + desc[i].idmalar = (i + 1) * sizeof(struct sdmmc_lli_desc); + desc[i].idmalar |= MMCI_STM32_ULA | MMCI_STM32_ULS + | MMCI_STM32_ABR; + desc[i].idmabase = sg_dma_address(sg); + desc[i].idmasize = sg_dma_len(sg); + } + + /* notice the end of link list */ + desc[data->sg_len - 1].idmalar &= ~MMCI_STM32_ULA; + + dma_wmb(); + writel_relaxed(idma->sg_dma, host->base + MMCI_STM32_IDMABAR); + writel_relaxed(desc[0].idmalar, host->base + MMCI_STM32_IDMALAR); + writel_relaxed(desc[0].idmabase, host->base + MMCI_STM32_IDMABASE0R); + writel_relaxed(desc[0].idmasize, host->base + MMCI_STM32_IDMABSIZER); + writel_relaxed(MMCI_STM32_IDMAEN | MMCI_STM32_IDMALLIEN, + host->base + MMCI_STM32_IDMACTRLR); + + return 0; +} + +static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data) +{ + writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); +} + +static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) +{ + unsigned int clk = 0, ddr = 0; + + if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52 || + host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) + ddr = MCI_STM32_CLK_DDR; + + /* + * cclk = mclk / (2 * clkdiv) + * clkdiv 0 => bypass + * in ddr mode bypass is not possible + */ + if (desired) { + if (desired >= host->mclk && !ddr) { + host->cclk = host->mclk; + } else { + clk = DIV_ROUND_UP(host->mclk, 2 * desired); + if (clk > MCI_STM32_CLK_CLKDIV_MSK) + clk = MCI_STM32_CLK_CLKDIV_MSK; + host->cclk = host->mclk / (2 * clk); + } + } else { + /* + * while power-on phase the clock can't be define to 0, + * Only power-off and power-cyc deactivate the clock. + * if desired clock is 0, set max divider + */ + clk = MCI_STM32_CLK_CLKDIV_MSK; + host->cclk = host->mclk / (2 * clk); + } + + /* Set actual clock for debug */ + if (host->mmc->ios.power_mode == MMC_POWER_ON) + host->mmc->actual_clock = host->cclk; + else + host->mmc->actual_clock = 0; + + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) + clk |= MCI_STM32_CLK_WIDEBUS_4; + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) + clk |= MCI_STM32_CLK_WIDEBUS_8; + + clk |= MCI_STM32_CLK_HWFCEN; + clk |= host->clk_reg_add; + clk |= ddr; + + /* + * SDMMC_FBCK is selected when an external Delay Block is needed + * with SDR104. + */ + if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) { + clk |= MCI_STM32_CLK_BUSSPEED; + if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) { + clk &= ~MCI_STM32_CLK_SEL_MSK; + clk |= MCI_STM32_CLK_SELFBCK; + } + } + + mmci_write_clkreg(host, clk); +} + +static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) +{ + struct mmc_ios ios = host->mmc->ios; + + pwr = host->pwr_reg_add; + + if (ios.power_mode == MMC_POWER_OFF) { + /* Only a reset could power-off sdmmc */ + reset_control_assert(host->rst); + udelay(2); + reset_control_deassert(host->rst); + + /* + * Set the SDMMC in Power-cycle state. + * This will make that the SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK + * are driven low, to prevent the Card from being supplied + * through the signal lines. + */ + mmci_write_pwrreg(host, MCI_STM32_PWR_CYC | pwr); + } else if (ios.power_mode == MMC_POWER_ON) { + /* + * After power-off (reset): the irq mask defined in probe + * functionis lost + * ault irq mask (probe) must be activated + */ + writel(MCI_IRQENABLE | host->variant->start_err, + host->base + MMCIMASK0); + + /* + * After a power-cycle state, we must set the SDMMC in + * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are + * driven high. Then we can set the SDMMC to Power-on state + */ + mmci_write_pwrreg(host, MCI_PWR_OFF | pwr); + mdelay(1); + mmci_write_pwrreg(host, MCI_PWR_ON | pwr); + } +} + +static struct mmci_host_ops sdmmc_variant_ops = { + .validate_data = sdmmc_idma_validate_data, + .prep_data = sdmmc_idma_prep_data, + .unprep_data = sdmmc_idma_unprep_data, + .dma_setup = sdmmc_idma_setup, + .dma_start = sdmmc_idma_start, + .dma_finalize = sdmmc_idma_finalize, + .set_clkreg = mmci_sdmmc_set_clkreg, + .set_pwrreg = mmci_sdmmc_set_pwrreg, +}; + +void sdmmc_variant_init(struct mmci_host *host) +{ + host->ops = &sdmmc_variant_ops; +} diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 04841386b65d..6334cc752d8b 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -87,6 +87,13 @@ #define SDC_FIFO_CFG 0x228 /*--------------------------------------------------------------------------*/ +/* Top Pad Register Offset */ +/*--------------------------------------------------------------------------*/ +#define EMMC_TOP_CONTROL 0x00 +#define EMMC_TOP_CMD 0x04 +#define EMMC50_PAD_DS_TUNE 0x0c + +/*--------------------------------------------------------------------------*/ /* Register Mask */ /*--------------------------------------------------------------------------*/ @@ -261,6 +268,23 @@ #define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */ #define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */ +/* EMMC_TOP_CONTROL mask */ +#define PAD_RXDLY_SEL (0x1 << 0) /* RW */ +#define DELAY_EN (0x1 << 1) /* RW */ +#define PAD_DAT_RD_RXDLY2 (0x1f << 2) /* RW */ +#define PAD_DAT_RD_RXDLY (0x1f << 7) /* RW */ +#define PAD_DAT_RD_RXDLY2_SEL (0x1 << 12) /* RW */ +#define PAD_DAT_RD_RXDLY_SEL (0x1 << 13) /* RW */ +#define DATA_K_VALUE_SEL (0x1 << 14) /* RW */ +#define SDC_RX_ENH_EN (0x1 << 15) /* TW */ + +/* EMMC_TOP_CMD mask */ +#define PAD_CMD_RXDLY2 (0x1f << 0) /* RW */ +#define PAD_CMD_RXDLY (0x1f << 5) /* RW */ +#define PAD_CMD_RD_RXDLY2_SEL (0x1 << 10) /* RW */ +#define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */ +#define PAD_CMD_TX_DLY (0x1f << 12) /* RW */ + #define REQ_CMD_EIO (0x1 << 0) #define REQ_CMD_TMO (0x1 << 1) #define REQ_DAT_ERR (0x1 << 2) @@ -333,6 +357,9 @@ struct msdc_save_para { u32 emmc50_cfg0; u32 emmc50_cfg3; u32 sdc_fifo_cfg; + u32 emmc_top_control; + u32 emmc_top_cmd; + u32 emmc50_pad_ds_tune; }; struct mtk_mmc_compatible { @@ -351,6 +378,8 @@ struct msdc_tune_para { u32 iocon; u32 pad_tune; u32 pad_cmd_tune; + u32 emmc_top_control; + u32 emmc_top_cmd; }; struct msdc_delay_phase { @@ -372,6 +401,7 @@ struct msdc_host { int error; void __iomem *base; /* host base address */ + void __iomem *top_base; /* host top register base address */ struct msdc_dma dma; /* dma channel */ u64 dma_mask; @@ -387,10 +417,10 @@ struct msdc_host { struct clk *src_clk; /* msdc source clock */ struct clk *h_clk; /* msdc h_clk */ + struct clk *bus_clk; /* bus clock which used to access register */ struct clk *src_clk_cg; /* msdc source clock control gate */ u32 mclk; /* mmc subsystem clock frequency */ u32 src_clk_freq; /* source clock frequency */ - u32 sclk; /* SD/MS bus clock frequency */ unsigned char timing; bool vqmmc_enabled; u32 latch_ck; @@ -429,6 +459,18 @@ static const struct mtk_mmc_compatible mt8173_compat = { .support_64g = false, }; +static const struct mtk_mmc_compatible mt8183_compat = { + .clk_div_bits = 12, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, + .enhance_rx = true, + .support_64g = true, +}; + static const struct mtk_mmc_compatible mt2701_compat = { .clk_div_bits = 12, .hs400_tune = false, @@ -468,6 +510,7 @@ static const struct mtk_mmc_compatible mt7622_compat = { static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, + { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, @@ -635,10 +678,10 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) host->timeout_ns = ns; host->timeout_clks = clks; - if (host->sclk == 0) { + if (host->mmc->actual_clock == 0) { timeout = 0; } else { - clk_ns = 1000000000UL / host->sclk; + clk_ns = 1000000000UL / host->mmc->actual_clock; timeout = (ns + clk_ns - 1) / clk_ns + clks; /* in 1048576 sclk cycle unit */ timeout = (timeout + (0x1 << 20) - 1) >> 20; @@ -660,12 +703,14 @@ static void msdc_gate_clock(struct msdc_host *host) { clk_disable_unprepare(host->src_clk_cg); clk_disable_unprepare(host->src_clk); + clk_disable_unprepare(host->bus_clk); clk_disable_unprepare(host->h_clk); } static void msdc_ungate_clock(struct msdc_host *host) { clk_prepare_enable(host->h_clk); + clk_prepare_enable(host->bus_clk); clk_prepare_enable(host->src_clk); clk_prepare_enable(host->src_clk_cg); while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) @@ -683,6 +728,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) if (!hz) { dev_dbg(host->dev, "set mclk to 0\n"); host->mclk = 0; + host->mmc->actual_clock = 0; sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); return; } @@ -761,7 +807,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) cpu_relax(); sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); - host->sclk = sclk; + host->mmc->actual_clock = sclk; host->mclk = hz; host->timing = timing; /* need because clk changed. */ @@ -772,14 +818,30 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) * mmc_select_hs400() will drop to 50Mhz and High speed mode, * tune result of hs200/200Mhz is not suitable for 50Mhz */ - if (host->sclk <= 52000000) { + if (host->mmc->actual_clock <= 52000000) { writel(host->def_tune_para.iocon, host->base + MSDC_IOCON); - writel(host->def_tune_para.pad_tune, host->base + tune_reg); + if (host->top_base) { + writel(host->def_tune_para.emmc_top_control, + host->top_base + EMMC_TOP_CONTROL); + writel(host->def_tune_para.emmc_top_cmd, + host->top_base + EMMC_TOP_CMD); + } else { + writel(host->def_tune_para.pad_tune, + host->base + tune_reg); + } } else { writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON); - writel(host->saved_tune_para.pad_tune, host->base + tune_reg); writel(host->saved_tune_para.pad_cmd_tune, host->base + PAD_CMD_TUNE); + if (host->top_base) { + writel(host->saved_tune_para.emmc_top_control, + host->top_base + EMMC_TOP_CONTROL); + writel(host->saved_tune_para.emmc_top_cmd, + host->top_base + EMMC_TOP_CMD); + } else { + writel(host->saved_tune_para.pad_tune, + host->base + tune_reg); + } } if (timing == MMC_TIMING_MMC_HS400 && @@ -787,7 +849,8 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) sdr_set_field(host->base + PAD_CMD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, host->hs400_cmd_int_delay); - dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing); + dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->mmc->actual_clock, + timing); } static inline u32 msdc_cmd_find_resp(struct msdc_host *host, @@ -1055,6 +1118,7 @@ static void msdc_start_command(struct msdc_host *host, WARN_ON(host->cmd); host->cmd = cmd; + mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); if (!msdc_cmd_is_ready(host, mrq, cmd)) return; @@ -1066,7 +1130,6 @@ static void msdc_start_command(struct msdc_host *host, cmd->error = 0; rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd); - mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask); writel(cmd->arg, host->base + SDC_ARG); @@ -1351,7 +1414,12 @@ static void msdc_init_hw(struct msdc_host *host) val = readl(host->base + MSDC_INT); writel(val, host->base + MSDC_INT); - writel(0, host->base + tune_reg); + if (host->top_base) { + writel(0, host->top_base + EMMC_TOP_CONTROL); + writel(0, host->top_base + EMMC_TOP_CMD); + } else { + writel(0, host->base + tune_reg); + } writel(0, host->base + MSDC_IOCON); sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0); writel(0x403c0046, host->base + MSDC_PATCH_BIT); @@ -1375,8 +1443,12 @@ static void msdc_init_hw(struct msdc_host *host) sdr_set_field(host->base + MSDC_PATCH_BIT2, MSDC_PB2_RESPWAIT, 3); if (host->dev_comp->enhance_rx) { - sdr_set_bits(host->base + SDC_ADV_CFG0, - SDC_RX_ENHANCE_EN); + if (host->top_base) + sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, + SDC_RX_ENH_EN); + else + sdr_set_bits(host->base + SDC_ADV_CFG0, + SDC_RX_ENHANCE_EN); } else { sdr_set_field(host->base + MSDC_PATCH_BIT2, MSDC_PB2_RESPSTSENSEL, 2); @@ -1394,11 +1466,26 @@ static void msdc_init_hw(struct msdc_host *host) sdr_set_bits(host->base + MSDC_PATCH_BIT2, MSDC_PB2_SUPPORT_64G); if (host->dev_comp->data_tune) { - sdr_set_bits(host->base + tune_reg, - MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL); + if (host->top_base) { + sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY_SEL); + sdr_clr_bits(host->top_base + EMMC_TOP_CONTROL, + DATA_K_VALUE_SEL); + sdr_set_bits(host->top_base + EMMC_TOP_CMD, + PAD_CMD_RD_RXDLY_SEL); + } else { + sdr_set_bits(host->base + tune_reg, + MSDC_PAD_TUNE_RD_SEL | + MSDC_PAD_TUNE_CMD_SEL); + } } else { /* choose clock tune */ - sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RXDLYSEL); + if (host->top_base) + sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, + PAD_RXDLY_SEL); + else + sdr_set_bits(host->base + tune_reg, + MSDC_PAD_TUNE_RXDLYSEL); } /* Configure to enable SDIO mode. @@ -1413,9 +1500,20 @@ static void msdc_init_hw(struct msdc_host *host) sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); host->def_tune_para.iocon = readl(host->base + MSDC_IOCON); - host->def_tune_para.pad_tune = readl(host->base + tune_reg); host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON); - host->saved_tune_para.pad_tune = readl(host->base + tune_reg); + if (host->top_base) { + host->def_tune_para.emmc_top_control = + readl(host->top_base + EMMC_TOP_CONTROL); + host->def_tune_para.emmc_top_cmd = + readl(host->top_base + EMMC_TOP_CMD); + host->saved_tune_para.emmc_top_control = + readl(host->top_base + EMMC_TOP_CONTROL); + host->saved_tune_para.emmc_top_cmd = + readl(host->top_base + EMMC_TOP_CMD); + } else { + host->def_tune_para.pad_tune = readl(host->base + tune_reg); + host->saved_tune_para.pad_tune = readl(host->base + tune_reg); + } dev_dbg(host->dev, "init hardware done!"); } @@ -1563,6 +1661,30 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) return delay_phase; } +static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value) +{ + u32 tune_reg = host->dev_comp->pad_tune_reg; + + if (host->top_base) + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, + value); + else + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, + value); +} + +static inline void msdc_set_data_delay(struct msdc_host *host, u32 value) +{ + u32 tune_reg = host->dev_comp->pad_tune_reg; + + if (host->top_base) + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY, value); + else + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, + value); +} + static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); @@ -1583,8 +1705,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); for (i = 0 ; i < PAD_DELAY_MAX; i++) { - sdr_set_field(host->base + tune_reg, - MSDC_PAD_TUNE_CMDRDLY, i); + msdc_set_cmd_delay(host, i); /* * Using the same parameters, it may sometimes pass the test, * but sometimes it may fail. To make sure the parameters are @@ -1608,8 +1729,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); for (i = 0; i < PAD_DELAY_MAX; i++) { - sdr_set_field(host->base + tune_reg, - MSDC_PAD_TUNE_CMDRDLY, i); + msdc_set_cmd_delay(host, i); /* * Using the same parameters, it may sometimes pass the test, * but sometimes it may fail. To make sure the parameters are @@ -1633,15 +1753,13 @@ skip_fall: final_maxlen = final_fall_delay.maxlen; if (final_maxlen == final_rise_delay.maxlen) { sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, - final_rise_delay.final_phase); final_delay = final_rise_delay.final_phase; } else { sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, - final_fall_delay.final_phase); final_delay = final_fall_delay.final_phase; } + msdc_set_cmd_delay(host, final_delay); + if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay) goto skip_internal; @@ -1716,7 +1834,6 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) u32 rise_delay = 0, fall_delay = 0; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; u8 final_delay, final_maxlen; - u32 tune_reg = host->dev_comp->pad_tune_reg; int i, ret; sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL, @@ -1724,8 +1841,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); for (i = 0 ; i < PAD_DELAY_MAX; i++) { - sdr_set_field(host->base + tune_reg, - MSDC_PAD_TUNE_DATRRDLY, i); + msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) rise_delay |= (1 << i); @@ -1739,8 +1855,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); for (i = 0; i < PAD_DELAY_MAX; i++) { - sdr_set_field(host->base + tune_reg, - MSDC_PAD_TUNE_DATRRDLY, i); + msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) fall_delay |= (1 << i); @@ -1752,29 +1867,97 @@ skip_fall: if (final_maxlen == final_rise_delay.maxlen) { sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); - sdr_set_field(host->base + tune_reg, - MSDC_PAD_TUNE_DATRRDLY, - final_rise_delay.final_phase); final_delay = final_rise_delay.final_phase; } else { sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); - sdr_set_field(host->base + tune_reg, - MSDC_PAD_TUNE_DATRRDLY, - final_fall_delay.final_phase); final_delay = final_fall_delay.final_phase; } + msdc_set_data_delay(host, final_delay); dev_dbg(host->dev, "Final data pad delay: %x\n", final_delay); return final_delay == 0xff ? -EIO : 0; } +/* + * MSDC IP which supports data tune + async fifo can do CMD/DAT tune + * together, which can save the tuning time. + */ +static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) +{ + struct msdc_host *host = mmc_priv(mmc); + u32 rise_delay = 0, fall_delay = 0; + struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; + u8 final_delay, final_maxlen; + int i, ret; + + sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL, + host->latch_ck); + + sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); + sdr_clr_bits(host->base + MSDC_IOCON, + MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + for (i = 0 ; i < PAD_DELAY_MAX; i++) { + msdc_set_cmd_delay(host, i); + msdc_set_data_delay(host, i); + ret = mmc_send_tuning(mmc, opcode, NULL); + if (!ret) + rise_delay |= (1 << i); + } + final_rise_delay = get_best_delay(host, rise_delay); + /* if rising edge has enough margin, then do not scan falling edge */ + if (final_rise_delay.maxlen >= 12 || + (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) + goto skip_fall; + + sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); + sdr_set_bits(host->base + MSDC_IOCON, + MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + for (i = 0; i < PAD_DELAY_MAX; i++) { + msdc_set_cmd_delay(host, i); + msdc_set_data_delay(host, i); + ret = mmc_send_tuning(mmc, opcode, NULL); + if (!ret) + fall_delay |= (1 << i); + } + final_fall_delay = get_best_delay(host, fall_delay); + +skip_fall: + final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); + if (final_maxlen == final_rise_delay.maxlen) { + sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); + sdr_clr_bits(host->base + MSDC_IOCON, + MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + final_delay = final_rise_delay.final_phase; + } else { + sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); + sdr_set_bits(host->base + MSDC_IOCON, + MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + final_delay = final_fall_delay.final_phase; + } + + msdc_set_cmd_delay(host, final_delay); + msdc_set_data_delay(host, final_delay); + + dev_dbg(host->dev, "Final pad delay: %x\n", final_delay); + return final_delay == 0xff ? -EIO : 0; +} + static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); int ret; u32 tune_reg = host->dev_comp->pad_tune_reg; + if (host->dev_comp->data_tune && host->dev_comp->async_fifo) { + ret = msdc_tune_together(mmc, opcode); + if (host->hs400_mode) { + sdr_clr_bits(host->base + MSDC_IOCON, + MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + msdc_set_data_delay(host, 0); + } + goto tune_done; + } if (host->hs400_mode && host->dev_comp->hs400_tune) ret = hs400_tune_response(mmc, opcode); @@ -1790,9 +1973,16 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode) dev_err(host->dev, "Tune data fail!\n"); } +tune_done: host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON); host->saved_tune_para.pad_tune = readl(host->base + tune_reg); host->saved_tune_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE); + if (host->top_base) { + host->saved_tune_para.emmc_top_control = readl(host->top_base + + EMMC_TOP_CONTROL); + host->saved_tune_para.emmc_top_cmd = readl(host->top_base + + EMMC_TOP_CMD); + } return ret; } @@ -1801,7 +1991,11 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) struct msdc_host *host = mmc_priv(mmc); host->hs400_mode = true; - writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE); + if (host->top_base) + writel(host->hs400_ds_delay, + host->top_base + EMMC50_PAD_DS_TUNE); + else + writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE); /* hs400 mode must set it to 0 */ sdr_clr_bits(host->base + MSDC_PATCH_BIT2, MSDC_PATCH_BIT2_CFGCRCSTS); /* to improve read performance, set outstanding to 2 */ @@ -1884,6 +2078,11 @@ static int msdc_drv_probe(struct platform_device *pdev) goto host_free; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + host->top_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(host->top_base)) + host->top_base = NULL; + ret = mmc_regulator_get_supply(mmc); if (ret) goto host_free; @@ -1900,6 +2099,9 @@ static int msdc_drv_probe(struct platform_device *pdev) goto host_free; } + host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); + if (IS_ERR(host->bus_clk)) + host->bus_clk = NULL; /*source clock control gate is optional clock*/ host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg"); if (IS_ERR(host->src_clk_cg)) @@ -2049,7 +2251,6 @@ static void msdc_save_reg(struct msdc_host *host) host->save_para.msdc_cfg = readl(host->base + MSDC_CFG); host->save_para.iocon = readl(host->base + MSDC_IOCON); host->save_para.sdc_cfg = readl(host->base + SDC_CFG); - host->save_para.pad_tune = readl(host->base + tune_reg); host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT); host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1); host->save_para.patch_bit2 = readl(host->base + MSDC_PATCH_BIT2); @@ -2058,6 +2259,16 @@ static void msdc_save_reg(struct msdc_host *host) host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0); host->save_para.emmc50_cfg3 = readl(host->base + EMMC50_CFG3); host->save_para.sdc_fifo_cfg = readl(host->base + SDC_FIFO_CFG); + if (host->top_base) { + host->save_para.emmc_top_control = + readl(host->top_base + EMMC_TOP_CONTROL); + host->save_para.emmc_top_cmd = + readl(host->top_base + EMMC_TOP_CMD); + host->save_para.emmc50_pad_ds_tune = + readl(host->top_base + EMMC50_PAD_DS_TUNE); + } else { + host->save_para.pad_tune = readl(host->base + tune_reg); + } } static void msdc_restore_reg(struct msdc_host *host) @@ -2067,7 +2278,6 @@ static void msdc_restore_reg(struct msdc_host *host) writel(host->save_para.msdc_cfg, host->base + MSDC_CFG); writel(host->save_para.iocon, host->base + MSDC_IOCON); writel(host->save_para.sdc_cfg, host->base + SDC_CFG); - writel(host->save_para.pad_tune, host->base + tune_reg); writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT); writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1); writel(host->save_para.patch_bit2, host->base + MSDC_PATCH_BIT2); @@ -2076,6 +2286,16 @@ static void msdc_restore_reg(struct msdc_host *host) writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0); writel(host->save_para.emmc50_cfg3, host->base + EMMC50_CFG3); writel(host->save_para.sdc_fifo_cfg, host->base + SDC_FIFO_CFG); + if (host->top_base) { + writel(host->save_para.emmc_top_control, + host->top_base + EMMC_TOP_CONTROL); + writel(host->save_para.emmc_top_cmd, + host->top_base + EMMC_TOP_CMD); + writel(host->save_para.emmc50_pad_ds_tune, + host->top_base + EMMC50_PAD_DS_TUNE); + } else { + writel(host->save_para.pad_tune, host->base + tune_reg); + } } static int msdc_runtime_suspend(struct device *dev) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index de4e6e5bf304..4d17032d15ee 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -728,7 +728,6 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) static irqreturn_t mxcmci_irq(int irq, void *devid) { struct mxcmci_host *host = devid; - unsigned long flags; bool sdio_irq; u32 stat; @@ -740,9 +739,9 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); - spin_lock_irqsave(&host->lock, flags); + spin_lock(&host->lock); sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; - spin_unlock_irqrestore(&host->lock, flags); + spin_unlock(&host->lock); if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE))) mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 68760d4a5d3d..467d889a1638 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -30,7 +30,6 @@ #include <linux/clk.h> #include <linux/of.h> #include <linux/of_irq.h> -#include <linux/of_gpio.h> #include <linux/of_device.h> #include <linux/mmc/host.h> #include <linux/mmc/core.h> @@ -38,7 +37,6 @@ #include <linux/mmc/slot-gpio.h> #include <linux/io.h> #include <linux/irq.h> -#include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> @@ -198,7 +196,6 @@ struct omap_hsmmc_host { struct dma_chan *rx_chan; int response_busy; int context_loss; - int protect_card; int reqs_blocked; int req_in_progress; unsigned long clk_rate; @@ -207,16 +204,6 @@ struct omap_hsmmc_host { #define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */ struct omap_hsmmc_next next_data; struct omap_hsmmc_platform_data *pdata; - - /* return MMC cover switch state, can be NULL if not supported. - * - * possible return values: - * 0 - closed - * 1 - open - */ - int (*get_cover_state)(struct device *dev); - - int (*card_detect)(struct device *dev); }; struct omap_mmc_of_data { @@ -226,20 +213,6 @@ struct omap_mmc_of_data { static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host); -static int omap_hsmmc_card_detect(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - return mmc_gpio_get_cd(host->mmc); -} - -static int omap_hsmmc_get_cover_state(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - return mmc_gpio_get_cd(host->mmc); -} - static int omap_hsmmc_enable_supply(struct mmc_host *mmc) { int ret; @@ -484,38 +457,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) return 0; } -static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id); - -static int omap_hsmmc_gpio_init(struct mmc_host *mmc, - struct omap_hsmmc_host *host, - struct omap_hsmmc_platform_data *pdata) -{ - int ret; - - if (gpio_is_valid(pdata->gpio_cod)) { - ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0); - if (ret) - return ret; - - host->get_cover_state = omap_hsmmc_get_cover_state; - mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq); - } else if (gpio_is_valid(pdata->gpio_cd)) { - ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0); - if (ret) - return ret; - - host->card_detect = omap_hsmmc_card_detect; - } - - if (gpio_is_valid(pdata->gpio_wp)) { - ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp); - if (ret) - return ret; - } - - return 0; -} - /* * Start clock to the card */ @@ -781,9 +722,6 @@ static void send_init_stream(struct omap_hsmmc_host *host) int reg = 0; unsigned long timeout; - if (host->protect_card) - return; - disable_irq(host->irq); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); @@ -804,29 +742,6 @@ static void send_init_stream(struct omap_hsmmc_host *host) enable_irq(host->irq); } -static inline -int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host) -{ - int r = 1; - - if (host->get_cover_state) - r = host->get_cover_state(host->dev); - return r; -} - -static ssize_t -omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); - struct omap_hsmmc_host *host = mmc_priv(mmc); - - return sprintf(buf, "%s\n", - omap_hsmmc_cover_is_closed(host) ? "closed" : "open"); -} - -static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL); - static ssize_t omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -1247,44 +1162,6 @@ err: return ret; } -/* Protect the card while the cover is open */ -static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) -{ - if (!host->get_cover_state) - return; - - host->reqs_blocked = 0; - if (host->get_cover_state(host->dev)) { - if (host->protect_card) { - dev_info(host->dev, "%s: cover is closed, " - "card is now accessible\n", - mmc_hostname(host->mmc)); - host->protect_card = 0; - } - } else { - if (!host->protect_card) { - dev_info(host->dev, "%s: cover is open, " - "card is now inaccessible\n", - mmc_hostname(host->mmc)); - host->protect_card = 1; - } - } -} - -/* - * irq handler when (cell-phone) cover is mounted/removed - */ -static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id) -{ - struct omap_hsmmc_host *host = dev_id; - - sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); - - omap_hsmmc_protect_card(host); - mmc_detect_change(host->mmc, (HZ * 200) / 1000); - return IRQ_HANDLED; -} - static void omap_hsmmc_dma_callback(void *param) { struct omap_hsmmc_host *host = param; @@ -1555,24 +1432,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) BUG_ON(host->req_in_progress); BUG_ON(host->dma_ch != -1); - if (host->protect_card) { - if (host->reqs_blocked < 3) { - /* - * Ensure the controller is left in a consistent - * state by resetting the command and data state - * machines. - */ - omap_hsmmc_reset_controller_fsm(host, SRD); - omap_hsmmc_reset_controller_fsm(host, SRC); - host->reqs_blocked += 1; - } - req->cmd->error = -EBADF; - if (req->data) - req->data->error = -EBADF; - req->cmd->retries = 0; - mmc_request_done(mmc, req); - return; - } else if (host->reqs_blocked) + if (host->reqs_blocked) host->reqs_blocked = 0; WARN_ON(host->mrq != NULL); host->mrq = req; @@ -1646,15 +1506,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) omap_hsmmc_set_bus_mode(host); } -static int omap_hsmmc_get_cd(struct mmc_host *mmc) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - if (!host->card_detect) - return -ENOSYS; - return host->card_detect(host->dev); -} - static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) { struct omap_hsmmc_host *host = mmc_priv(mmc); @@ -1793,7 +1644,7 @@ static struct mmc_host_ops omap_hsmmc_ops = { .pre_req = omap_hsmmc_pre_req, .request = omap_hsmmc_request, .set_ios = omap_hsmmc_set_ios, - .get_cd = omap_hsmmc_get_cd, + .get_cd = mmc_gpio_get_cd, .get_ro = mmc_gpio_get_ro, .init_card = omap_hsmmc_init_card, .enable_sdio_irq = omap_hsmmc_enable_sdio_irq, @@ -1920,10 +1771,6 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) if (of_find_property(np, "ti,dual-volt", NULL)) pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; - pdata->gpio_cd = -EINVAL; - pdata->gpio_cod = -EINVAL; - pdata->gpio_wp = -EINVAL; - if (of_find_property(np, "ti,non-removable", NULL)) { pdata->nonremovable = true; pdata->no_regulator_off_init = true; @@ -2008,10 +1855,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->pbias_enabled = 0; host->vqmmc_enabled = 0; - ret = omap_hsmmc_gpio_init(mmc, host, pdata); - if (ret) - goto err_gpio; - platform_set_drvdata(pdev, host); if (pdev->dev.of_node) @@ -2125,8 +1968,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (!ret) mmc->caps |= MMC_CAP_SDIO_IRQ; - omap_hsmmc_protect_card(host); - mmc_add_host(mmc); if (mmc_pdata(host)->name != NULL) { @@ -2134,12 +1975,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (ret < 0) goto err_slot_name; } - if (host->get_cover_state) { - ret = device_create_file(&mmc->class_dev, - &dev_attr_cover_switch); - if (ret < 0) - goto err_slot_name; - } omap_hsmmc_debugfs(mmc); pm_runtime_mark_last_busy(host->dev); @@ -2161,7 +1996,6 @@ err_irq: if (host->dbclk) clk_disable_unprepare(host->dbclk); err1: -err_gpio: mmc_free_host(mmc); err: return ret; @@ -2231,7 +2065,6 @@ static int omap_hsmmc_resume(struct device *dev) if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) omap_hsmmc_conf_bus_power(host); - omap_hsmmc_protect_card(host); pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); return 0; diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index f13f798d8506..da1e49c45bec 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Renesas Mobile SDHI * * Copyright (C) 2017 Horms Solutions Ltd., Simon Horman * Copyright (C) 2017 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef RENESAS_SDHI_H diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 777e32b0e410..d3ac43c3d0b6 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas SDHI * @@ -6,10 +7,6 @@ * Copyright (C) 2016-17 Horms Solutions, Simon Horman * Copyright (C) 2009 Magnus Damm * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on "Compaq ASIC3 support": * * Copyright 2001 Compaq Computer Corporation. @@ -155,6 +152,52 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, return ret == 0 ? best_freq : clk_get_rate(priv->clk); } +static void renesas_sdhi_set_clock(struct tmio_mmc_host *host, + unsigned int new_clock) +{ + u32 clk = 0, clock; + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + + if (new_clock == 0) + goto out; + + /* + * Both HS400 and HS200/SD104 set 200MHz, but some devices need to + * set 400MHz to distinguish the CPG settings in HS400. + */ + if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && + host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400 && + new_clock == 200000000) + new_clock = 400000000; + + clock = renesas_sdhi_clk_update(host, new_clock) / 512; + + for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1) + clock <<= 1; + + /* 1/1 clock is option */ + if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) { + if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400)) + clk |= 0xff; + else + clk &= ~0xff; + } + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) + 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)); + +out: + /* HW engineers overrode docs: no sleep needed on R-Car2+ */ + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) + usleep_range(10000, 11000); +} + static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host) { struct renesas_sdhi *priv = host_to_priv(host); @@ -443,6 +486,19 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) { struct renesas_sdhi *priv = host_to_priv(host); + bool use_4tap = host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400; + + /* + * Skip checking SCC errors when running on 4 taps in HS400 mode as + * any retuning would still result in the same 4 taps being used. + */ + if (!(host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) && + !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200) && + !(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap)) + return false; + + if (mmc_doing_retune(host->mmc)) + return false; /* Check SCC error */ if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & @@ -620,8 +676,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->write16_hook = renesas_sdhi_write16_hook; host->clk_enable = renesas_sdhi_clk_enable; - host->clk_update = renesas_sdhi_clk_update; host->clk_disable = renesas_sdhi_clk_disable; + host->set_clock = renesas_sdhi_set_clock; host->multi_io_quirk = renesas_sdhi_multi_io_quirk; host->dma_ops = dma_ops; diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index ca0b43973769..b6f54102bfdd 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * DMA support for Internal DMAC with SDHI SD/SDIO controller * * Copyright (C) 2016-17 Renesas Electronics Corporation * Copyright (C) 2016-17 Horms Solutions, Simon Horman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bitops.h> @@ -35,8 +32,8 @@ /* DM_CM_DTRAN_MODE */ #define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */ -#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "uptream" = for read commands */ -#define DTRAN_MODE_BUS_WID_TH (BIT(5) | BIT(4)) +#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "upstream" = for read commands */ +#define DTRAN_MODE_BUS_WIDTH (BIT(5) | BIT(4)) #define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */ /* DM_CM_DTRAN_CTRL */ @@ -116,6 +113,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { }; static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { + { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, }, { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, }, { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, @@ -174,7 +172,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, struct mmc_data *data) { struct scatterlist *sg = host->sg_ptr; - u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE; + u32 dtran_mode = DTRAN_MODE_BUS_WIDTH | DTRAN_MODE_ADDR_MODE; if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data))) @@ -201,13 +199,14 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR, sg_dma_address(sg)); + host->dma_on = true; + return; force_pio_with_unmap: dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data)); force_pio: - host->force_pio = true; renesas_sdhi_internal_dmac_enable_dma(host, false); } @@ -291,16 +290,19 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = { * Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC * implementation as others may use a different implementation. */ -static const struct soc_device_attribute gen3_soc_whitelist[] = { +static const struct soc_device_attribute soc_whitelist[] = { /* specific ones */ { .soc_id = "r8a7795", .revision = "ES1.*", .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) }, { .soc_id = "r8a7796", .revision = "ES1.0", .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) }, /* generic ones */ + { .soc_id = "r8a774a1" }, + { .soc_id = "r8a77470" }, { .soc_id = "r8a7795" }, { .soc_id = "r8a7796" }, { .soc_id = "r8a77965" }, + { .soc_id = "r8a77970" }, { .soc_id = "r8a77980" }, { .soc_id = "r8a77995" }, { /* sentinel */ } @@ -308,13 +310,21 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = { static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev) { - const struct soc_device_attribute *soc = soc_device_match(gen3_soc_whitelist); + const struct soc_device_attribute *soc = soc_device_match(soc_whitelist); + struct device *dev = &pdev->dev; if (!soc) return -ENODEV; global_flags |= (unsigned long)soc->data; + dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + + /* value is max of SD_SECCNT. Confirmed by HW engineers */ + dma_set_max_seg_size(dev, 0xffffffff); + return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops); } diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 5389c4821882..1a4016f635d3 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * DMA support use of SYS DMAC with SDHI SD/SDIO controller * @@ -5,10 +6,6 @@ * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang * Copyright (C) 2017 Horms Solutions, Simon Horman * Copyright (C) 2010-2011 Guennadi Liakhovetski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/device.h> @@ -213,10 +210,8 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) goto pio; } - if (sg->length < TMIO_MMC_MIN_DMA_LEN) { - host->force_pio = true; + if (sg->length < TMIO_MMC_MIN_DMA_LEN) return; - } /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { @@ -240,6 +235,7 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) desc = NULL; ret = cookie; } + host->dma_on = true; } pio: if (!desc) { @@ -286,10 +282,8 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) goto pio; } - if (sg->length < TMIO_MMC_MIN_DMA_LEN) { - host->force_pio = true; + if (sg->length < TMIO_MMC_MIN_DMA_LEN) return; - } /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { @@ -318,6 +312,7 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) desc = NULL; ret = cookie; } + host->dma_on = true; } pio: if (!desc) { diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 32321bd596d8..057e24f4a620 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -76,6 +76,7 @@ struct sdhci_acpi_slot { size_t priv_size; int (*probe_slot)(struct platform_device *, const char *, const char *); int (*remove_slot)(struct platform_device *); + int (*free_slot)(struct platform_device *pdev); int (*setup_host)(struct platform_device *pdev); }; @@ -246,7 +247,7 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { static bool sdhci_acpi_byt(void) { static const struct x86_cpu_id byt[] = { - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, {} }; @@ -470,10 +471,70 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { .priv_size = sizeof(struct intel_host), }; +#define VENDOR_SPECIFIC_PWRCTL_CLEAR_REG 0x1a8 +#define VENDOR_SPECIFIC_PWRCTL_CTL_REG 0x1ac +static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr) +{ + struct sdhci_host *host = ptr; + + sdhci_writel(host, 0x3, VENDOR_SPECIFIC_PWRCTL_CLEAR_REG); + sdhci_writel(host, 0x1, VENDOR_SPECIFIC_PWRCTL_CTL_REG); + + return IRQ_HANDLED; +} + +static int qcom_probe_slot(struct platform_device *pdev, const char *hid, + const char *uid) +{ + struct sdhci_acpi_host *c = platform_get_drvdata(pdev); + struct sdhci_host *host = c->host; + int *irq = sdhci_acpi_priv(c); + + *irq = -EINVAL; + + if (strcmp(hid, "QCOM8051")) + return 0; + + *irq = platform_get_irq(pdev, 1); + if (*irq < 0) + return 0; + + return request_threaded_irq(*irq, NULL, sdhci_acpi_qcom_handler, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + "sdhci_qcom", host); +} + +static int qcom_free_slot(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sdhci_acpi_host *c = platform_get_drvdata(pdev); + struct sdhci_host *host = c->host; + struct acpi_device *adev; + int *irq = sdhci_acpi_priv(c); + const char *hid; + + adev = ACPI_COMPANION(dev); + if (!adev) + return -ENODEV; + + hid = acpi_device_hid(adev); + if (strcmp(hid, "QCOM8051")) + return 0; + + if (*irq < 0) + return 0; + + free_irq(*irq, host); + return 0; +} + static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = { .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, .quirks2 = SDHCI_QUIRK2_NO_1_8_V, .caps = MMC_CAP_NONREMOVABLE, + .priv_size = sizeof(int), + .probe_slot = qcom_probe_slot, + .free_slot = qcom_free_slot, }; static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = { @@ -756,6 +817,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev) err_cleanup: sdhci_cleanup_host(c->host); err_free: + if (c->slot && c->slot->free_slot) + c->slot->free_slot(pdev); + sdhci_free_host(c->host); return err; } @@ -777,6 +841,10 @@ static int sdhci_acpi_remove(struct platform_device *pdev) dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0); sdhci_remove_host(c->host, dead); + + if (c->slot && c->slot->free_slot) + c->slot->free_slot(pdev); + sdhci_free_host(c->host); return 0; diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index dfa58f8b8dfa..3f16d9c90ba2 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -60,6 +60,7 @@ /* Tuning Block Control Register */ #define ESDHC_TBCTL 0x120 #define ESDHC_TB_EN 0x00000004 +#define ESDHC_TBPTR 0x128 /* Control Register for DMA transfer */ #define ESDHC_DMA_SYSCTL 0x40c diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index d0e83db42ae5..0db99057c44f 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -15,6 +15,7 @@ * iProc SDHCI platform driver */ +#include <linux/acpi.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/mmc/host.h> @@ -162,9 +163,19 @@ static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_iproc_writel(host, newval, reg & ~3); } +static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + if (pltfm_host->clk) + return sdhci_pltfm_clk_get_max_clock(host); + else + return pltfm_host->clock; +} + static const struct sdhci_ops sdhci_iproc_ops = { .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_max_clock = sdhci_iproc_get_max_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, @@ -178,7 +189,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = { .write_w = sdhci_iproc_writew, .write_b = sdhci_iproc_writeb, .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_max_clock = sdhci_iproc_get_max_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, @@ -256,19 +267,25 @@ static const struct of_device_id sdhci_iproc_of_match[] = { }; MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match); +static const struct acpi_device_id sdhci_iproc_acpi_ids[] = { + { .id = "BRCM5871", .driver_data = (kernel_ulong_t)&iproc_cygnus_data }, + { .id = "BRCM5872", .driver_data = (kernel_ulong_t)&iproc_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids); + static int sdhci_iproc_probe(struct platform_device *pdev) { - const struct of_device_id *match; - const struct sdhci_iproc_data *iproc_data; + struct device *dev = &pdev->dev; + const struct sdhci_iproc_data *iproc_data = NULL; struct sdhci_host *host; struct sdhci_iproc_host *iproc_host; struct sdhci_pltfm_host *pltfm_host; int ret; - match = of_match_device(sdhci_iproc_of_match, &pdev->dev); - if (!match) - return -EINVAL; - iproc_data = match->data; + iproc_data = device_get_match_data(dev); + if (!iproc_data) + return -ENODEV; host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host)); if (IS_ERR(host)) @@ -280,19 +297,21 @@ static int sdhci_iproc_probe(struct platform_device *pdev) iproc_host->data = iproc_data; mmc_of_parse(host->mmc); - sdhci_get_of_property(pdev); + sdhci_get_property(pdev); host->mmc->caps |= iproc_host->data->mmc_caps; - pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pltfm_host->clk)) { - ret = PTR_ERR(pltfm_host->clk); - goto err; - } - ret = clk_prepare_enable(pltfm_host->clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable host clk\n"); - goto err; + if (dev->of_node) { + pltfm_host->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pltfm_host->clk)) { + ret = PTR_ERR(pltfm_host->clk); + goto err; + } + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) { + dev_err(dev, "failed to enable host clk\n"); + goto err; + } } if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) { @@ -307,7 +326,8 @@ static int sdhci_iproc_probe(struct platform_device *pdev) return 0; err_clk: - clk_disable_unprepare(pltfm_host->clk); + if (dev->of_node) + clk_disable_unprepare(pltfm_host->clk); err: sdhci_pltfm_free(pdev); return ret; @@ -317,6 +337,7 @@ static struct platform_driver sdhci_iproc_driver = { .driver = { .name = "sdhci-iproc", .of_match_table = sdhci_iproc_of_match, + .acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids), .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_iproc_probe, diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index a40bcc27f187..142c4b802f31 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -107,6 +107,11 @@ struct sdhci_arasan_data { #define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1) }; +struct sdhci_arasan_of_data { + const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; + const struct sdhci_pltfm_data *pdata; +}; + static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { .baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 }, .clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0}, @@ -226,6 +231,25 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) } } +static void sdhci_arasan_am654_set_clock(struct sdhci_host *host, + unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + + if (sdhci_arasan->is_phy_on) { + phy_power_off(sdhci_arasan->phy); + sdhci_arasan->is_phy_on = false; + } + + sdhci_set_clock(host, clock); + + if (clock > PHY_CLK_TOO_SLOW_HZ) { + phy_power_on(sdhci_arasan->phy); + sdhci_arasan->is_phy_on = true; + } +} + static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -307,6 +331,33 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = { SDHCI_QUIRK2_STOP_WITH_TC, }; +static struct sdhci_arasan_of_data sdhci_arasan_data = { + .pdata = &sdhci_arasan_pdata, +}; + +static const struct sdhci_ops sdhci_arasan_am654_ops = { + .set_clock = sdhci_arasan_am654_set_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_arasan_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data sdhci_arasan_am654_pdata = { + .ops = &sdhci_arasan_am654_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_INVERTED_WRITE_PROTECT | + SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, +}; + +static const struct sdhci_arasan_of_data sdhci_arasan_am654_data = { + .pdata = &sdhci_arasan_am654_pdata, +}; + static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) { int cmd_error = 0; @@ -363,6 +414,11 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; +static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { + .soc_ctl_map = &rk3399_soc_ctl_map, + .pdata = &sdhci_arasan_cqe_pdata, +}; + #ifdef CONFIG_PM_SLEEP /** * sdhci_arasan_suspend - Suspend method for the driver @@ -462,14 +518,25 @@ static const struct of_device_id sdhci_arasan_of_match[] = { /* SoC-specific compatible strings w/ soc_ctl_map */ { .compatible = "rockchip,rk3399-sdhci-5.1", - .data = &rk3399_soc_ctl_map, + .data = &sdhci_arasan_rk3399_data, + }, + { + .compatible = "ti,am654-sdhci-5.1", + .data = &sdhci_arasan_am654_data, }, - /* Generic compatible below here */ - { .compatible = "arasan,sdhci-8.9a" }, - { .compatible = "arasan,sdhci-5.1" }, - { .compatible = "arasan,sdhci-4.9a" }, - + { + .compatible = "arasan,sdhci-8.9a", + .data = &sdhci_arasan_data, + }, + { + .compatible = "arasan,sdhci-5.1", + .data = &sdhci_arasan_data, + }, + { + .compatible = "arasan,sdhci-4.9a", + .data = &sdhci_arasan_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); @@ -707,14 +774,11 @@ static int sdhci_arasan_probe(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host; struct sdhci_arasan_data *sdhci_arasan; struct device_node *np = pdev->dev.of_node; - const struct sdhci_pltfm_data *pdata; - - if (of_device_is_compatible(pdev->dev.of_node, "arasan,sdhci-5.1")) - pdata = &sdhci_arasan_cqe_pdata; - else - pdata = &sdhci_arasan_pdata; + const struct sdhci_arasan_of_data *data; - host = sdhci_pltfm_init(pdev, pdata, sizeof(*sdhci_arasan)); + match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node); + data = match->data; + host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan)); if (IS_ERR(host)) return PTR_ERR(host); @@ -723,8 +787,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) sdhci_arasan = sdhci_pltfm_priv(pltfm_host); sdhci_arasan->host = host; - match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node); - sdhci_arasan->soc_ctl_map = match->data; + sdhci_arasan->soc_ctl_map = data->soc_ctl_map; node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0); if (node) { @@ -788,7 +851,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) { - dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret); goto unreg_clk; } diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 1b7cd144fb01..a5137845a1c7 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -8,21 +8,51 @@ */ #include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/sizes.h> #include "sdhci-pltfm.h" +#define BOUNDARY_OK(addr, len) \ + ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) + struct dwcmshc_priv { struct clk *bus_clk; }; +/* + * If DMA addr spans 128MB boundary, we split the DMA transfer into two + * so that each DMA transfer doesn't exceed the boundary. + */ +static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd) +{ + int tmplen, offset; + + if (likely(!len || BOUNDARY_OK(addr, len))) { + sdhci_adma_write_desc(host, desc, addr, len, cmd); + return; + } + + offset = addr & (SZ_128M - 1); + tmplen = SZ_128M - offset; + sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); + + addr += tmplen; + len -= tmplen; + sdhci_adma_write_desc(host, desc, addr, len, cmd); +} + static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, .set_uhs_signaling = sdhci_set_uhs_signaling, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .reset = sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, }; static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { @@ -36,12 +66,21 @@ static int dwcmshc_probe(struct platform_device *pdev) struct sdhci_host *host; struct dwcmshc_priv *priv; int err; + u32 extra; host = sdhci_pltfm_init(pdev, &sdhci_dwcmshc_pdata, sizeof(struct dwcmshc_priv)); if (IS_ERR(host)) return PTR_ERR(host); + /* + * extra adma table cnt for cross 128M boundary handling. + */ + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); + if (extra > SDHCI_MAX_SEGS) + extra = SDHCI_MAX_SEGS; + host->adma_table_cnt += extra; + pltfm_host = sdhci_priv(host); priv = sdhci_pltfm_priv(pltfm_host); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 9cb7554a463d..86fc9f022002 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -78,8 +78,10 @@ struct sdhci_esdhc { u8 vendor_ver; u8 spec_ver; bool quirk_incorrect_hostver; + bool quirk_fixup_tuning; unsigned int peripheral_clock; const struct esdhc_clk_fixup *clk_fixup; + u32 div_ratio; }; /** @@ -580,6 +582,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", clock, host->max_clk / pre_div / div); host->mmc->actual_clock = host->max_clk / pre_div / div; + esdhc->div_ratio = pre_div * div; pre_div >>= 1; div--; @@ -712,9 +715,24 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc, } } +static struct soc_device_attribute soc_fixup_tuning[] = { + { .family = "QorIQ T1040", .revision = "1.0", }, + { .family = "QorIQ T2080", .revision = "1.0", }, + { .family = "QorIQ T1023", .revision = "1.0", }, + { .family = "QorIQ LS1021A", .revision = "1.0", }, + { .family = "QorIQ LS1080A", .revision = "1.0", }, + { .family = "QorIQ LS2080A", .revision = "1.0", }, + { .family = "QorIQ LS1012A", .revision = "1.0", }, + { .family = "QorIQ LS1043A", .revision = "1.*", }, + { .family = "QorIQ LS1046A", .revision = "1.0", }, + { }, +}; + static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); u32 val; /* Use tuning block for tuning procedure */ @@ -728,7 +746,26 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_writel(host, val, ESDHC_TBCTL); esdhc_clock_enable(host, true); - return sdhci_execute_tuning(mmc, opcode); + sdhci_execute_tuning(mmc, opcode); + if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) { + + /* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and + * program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO + */ + val = sdhci_readl(host, ESDHC_TBPTR); + val = (val & ~((0x7f << 8) | 0x7f)) | + (3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8); + sdhci_writel(host, val, ESDHC_TBPTR); + + /* program the software tuning mode by setting + * TBCTL[TB_MODE]=2'h3 + */ + val = sdhci_readl(host, ESDHC_TBCTL); + val |= 0x3; + sdhci_writel(host, val, ESDHC_TBCTL); + sdhci_execute_tuning(mmc, opcode); + } + return 0; } #ifdef CONFIG_PM_SLEEP @@ -903,6 +940,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); esdhc = sdhci_pltfm_priv(pltfm_host); + if (soc_device_match(soc_fixup_tuning)) + esdhc->quirk_fixup_tuning = true; + else + esdhc->quirk_fixup_tuning = false; + if (esdhc->vendor_ver == VENDOR_V_22) host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index 77e9bc4aaee9..cc3ffeffd7a2 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -490,6 +490,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); break; case PCI_DEVICE_ID_O2_SEABIRD0: + if (chip->pdev->revision == 0x01) + chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; + /* fall through */ case PCI_DEVICE_ID_O2_SEABIRD1: /* UnLock WP */ ret = pci_read_config_byte(chip->pdev, diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 02bea6159d79..b231c9a3f888 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -30,6 +30,7 @@ #include <linux/err.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/of.h> #ifdef CONFIG_PPC #include <asm/machdep.h> @@ -51,11 +52,10 @@ static const struct sdhci_ops sdhci_pltfm_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; -#ifdef CONFIG_OF -static bool sdhci_of_wp_inverted(struct device_node *np) +static bool sdhci_wp_inverted(struct device *dev) { - if (of_get_property(np, "sdhci,wp-inverted", NULL) || - of_get_property(np, "wp-inverted", NULL)) + if (device_property_present(dev, "sdhci,wp-inverted") || + device_property_present(dev, "wp-inverted")) return true; /* Old device trees don't have the wp-inverted property. */ @@ -66,52 +66,64 @@ static bool sdhci_of_wp_inverted(struct device_node *np) #endif /* CONFIG_PPC */ } -void sdhci_get_of_property(struct platform_device *pdev) +#ifdef CONFIG_OF +static void sdhci_get_compatibility(struct platform_device *pdev) { + struct sdhci_host *host = platform_get_drvdata(pdev); struct device_node *np = pdev->dev.of_node; + + if (!np) + return; + + if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) + host->quirks |= SDHCI_QUIRK_BROKEN_DMA; + + if (of_device_is_compatible(np, "fsl,p2020-esdhc") || + of_device_is_compatible(np, "fsl,p1010-esdhc") || + of_device_is_compatible(np, "fsl,t4240-esdhc") || + of_device_is_compatible(np, "fsl,mpc8536-esdhc")) + host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; +} +#else +void sdhci_get_compatibility(struct platform_device *pdev) {} +#endif /* CONFIG_OF */ + +void sdhci_get_property(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); u32 bus_width; - if (of_get_property(np, "sdhci,auto-cmd12", NULL)) + if (device_property_present(dev, "sdhci,auto-cmd12")) host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; - if (of_get_property(np, "sdhci,1-bit-only", NULL) || - (of_property_read_u32(np, "bus-width", &bus_width) == 0 && + if (device_property_present(dev, "sdhci,1-bit-only") || + (device_property_read_u32(dev, "bus-width", &bus_width) == 0 && bus_width == 1)) host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; - if (sdhci_of_wp_inverted(np)) + if (sdhci_wp_inverted(dev)) host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; - if (of_get_property(np, "broken-cd", NULL)) + if (device_property_present(dev, "broken-cd")) host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - if (of_get_property(np, "no-1-8-v", NULL)) + if (device_property_present(dev, "no-1-8-v")) host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; - if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) - host->quirks |= SDHCI_QUIRK_BROKEN_DMA; - - if (of_device_is_compatible(np, "fsl,p2020-esdhc") || - of_device_is_compatible(np, "fsl,p1010-esdhc") || - of_device_is_compatible(np, "fsl,t4240-esdhc") || - of_device_is_compatible(np, "fsl,mpc8536-esdhc")) - host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + sdhci_get_compatibility(pdev); - of_property_read_u32(np, "clock-frequency", &pltfm_host->clock); + device_property_read_u32(dev, "clock-frequency", &pltfm_host->clock); - if (of_find_property(np, "keep-power-in-suspend", NULL)) + if (device_property_present(dev, "keep-power-in-suspend")) host->mmc->pm_caps |= MMC_PM_KEEP_POWER; - if (of_property_read_bool(np, "wakeup-source") || - of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */ + if (device_property_read_bool(dev, "wakeup-source") || + device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */ host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; } -#else -void sdhci_get_of_property(struct platform_device *pdev) {} -#endif /* CONFIG_OF */ -EXPORT_SYMBOL_GPL(sdhci_get_of_property); +EXPORT_SYMBOL_GPL(sdhci_get_property); struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata, @@ -184,7 +196,7 @@ int sdhci_pltfm_register(struct platform_device *pdev, if (IS_ERR(host)) return PTR_ERR(host); - sdhci_get_of_property(pdev); + sdhci_get_property(pdev); ret = sdhci_add_host(host); if (ret) diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 1e91fb1c020e..6109987fc3b5 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -90,7 +90,12 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg) } #endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */ -extern void sdhci_get_of_property(struct platform_device *pdev); +void sdhci_get_property(struct platform_device *pdev); + +static inline void sdhci_get_of_property(struct platform_device *pdev) +{ + return sdhci_get_property(pdev); +} extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata, diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index b8e96f392428..1783e29eae04 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -21,17 +21,14 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> -#include <linux/mmc/slot-gpio.h> #include <linux/platform_data/pxa_sdhci.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/mbus.h> @@ -452,16 +449,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) host->mmc->caps2 |= pdata->host_caps2; if (pdata->pm_caps) host->mmc->pm_caps |= pdata->pm_caps; - - if (gpio_is_valid(pdata->ext_cd_gpio)) { - ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio, - 0); - if (ret) { - dev_err(mmc_dev(host->mmc), - "failed to allocate card detect gpio\n"); - goto err_cd_req; - } - } } pm_runtime_get_noresume(&pdev->dev); @@ -486,7 +473,6 @@ err_add_host: pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); err_of_parse: -err_cd_req: err_mbus_win: clk_disable_unprepare(pxa->clk_io); clk_disable_unprepare(pxa->clk_core); diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index 391d52b467ca..5eada6f87e60 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -11,7 +11,6 @@ #include <linux/mmc/host.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/mmc/slot-gpio.h> #include "sdhci-pltfm.h" @@ -19,10 +18,6 @@ #define SDHCI_SIRF_8BITBUS BIT(3) #define SIRF_TUNING_COUNT 16384 -struct sdhci_sirf_priv { - int gpio_cd; -}; - static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width) { u8 ctrl; @@ -170,9 +165,7 @@ static int sdhci_sirf_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; - struct sdhci_sirf_priv *priv; struct clk *clk; - int gpio_cd; int ret; clk = devm_clk_get(&pdev->dev, NULL); @@ -181,19 +174,12 @@ static int sdhci_sirf_probe(struct platform_device *pdev) return PTR_ERR(clk); } - if (pdev->dev.of_node) - gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0); - else - gpio_cd = -EINVAL; - - host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv)); + host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, 0); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); pltfm_host->clk = clk; - priv = sdhci_pltfm_priv(pltfm_host); - priv->gpio_cd = gpio_cd; sdhci_get_of_property(pdev); @@ -209,15 +195,11 @@ static int sdhci_sirf_probe(struct platform_device *pdev) * We must request the IRQ after sdhci_add_host(), as the tasklet only * gets setup in sdhci_add_host() and we oops. */ - if (gpio_is_valid(priv->gpio_cd)) { - ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0); - if (ret) { - dev_err(&pdev->dev, "card detect irq request failed: %d\n", - ret); - goto err_request_cd; - } + ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL); + if (ret == -EPROBE_DEFER) + goto err_request_cd; + if (!ret) mmc_gpiod_request_cd_irq(host->mmc); - } return 0; diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 9247d51f2eed..916b5b09c3d1 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -15,13 +15,11 @@ #include <linux/clk.h> #include <linux/delay.h> -#include <linux/gpio.h> #include <linux/highmem.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/slab.h> @@ -32,7 +30,6 @@ struct spear_sdhci { struct clk *clk; - int card_int_gpio; }; /* sdhci ops */ @@ -43,18 +40,6 @@ static const struct sdhci_ops sdhci_pltfm_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; -static void sdhci_probe_config_dt(struct device_node *np, - struct spear_sdhci *host) -{ - int cd_gpio; - - cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - if (!gpio_is_valid(cd_gpio)) - cd_gpio = -1; - - host->card_int_gpio = cd_gpio; -} - static int sdhci_probe(struct platform_device *pdev) { struct sdhci_host *host; @@ -109,21 +94,13 @@ static int sdhci_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n", clk_get_rate(sdhci->clk)); - sdhci_probe_config_dt(pdev->dev.of_node, sdhci); /* - * It is optional to use GPIOs for sdhci card detection. If - * sdhci->card_int_gpio < 0, then use original sdhci lines otherwise - * GPIO lines. We use the built-in GPIO support for this. + * It is optional to use GPIOs for sdhci card detection. If we + * find a descriptor using slot GPIO, we use it. */ - if (sdhci->card_int_gpio >= 0) { - ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0); - if (ret < 0) { - dev_dbg(&pdev->dev, - "failed to request card-detect gpio%d\n", - sdhci->card_int_gpio); - goto disable_clk; - } - } + ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL); + if (ret == -EPROBE_DEFER) + goto disable_clk; ret = sdhci_add_host(host); if (ret) diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c new file mode 100644 index 000000000000..9a822e2e9f0b --- /dev/null +++ b/drivers/mmc/host/sdhci-sprd.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Secure Digital Host Controller +// +// Copyright (C) 2018 Spreadtrum, Inc. +// Author: Chunyan Zhang <chunyan.zhang@unisoc.com> + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/highmem.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +#include "sdhci-pltfm.h" + +/* SDHCI_ARGUMENT2 register high 16bit */ +#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16) + +#define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET 0x208 +#define SDHCIBSPRD_IT_WR_DLY_INV BIT(5) +#define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13) +#define SDHCI_SPRD_BIT_POSRD_DLY_INV BIT(21) +#define SDHCI_SPRD_BIT_NEGRD_DLY_INV BIT(29) + +#define SDHCI_SPRD_REG_32_BUSY_POSI 0x250 +#define SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN BIT(25) +#define SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN BIT(24) + +#define SDHCI_SPRD_REG_DEBOUNCE 0x28C +#define SDHCI_SPRD_BIT_DLL_BAK BIT(0) +#define SDHCI_SPRD_BIT_DLL_VAL BIT(1) + +#define SDHCI_SPRD_INT_SIGNAL_MASK 0x1B7F410B + +/* SDHCI_HOST_CONTROL2 */ +#define SDHCI_SPRD_CTRL_HS200 0x0005 +#define SDHCI_SPRD_CTRL_HS400 0x0006 + +/* + * According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is + * reserved, and only used on Spreadtrum's design, the hardware cannot work + * if this bit is cleared. + * 1 : normal work + * 0 : hardware reset + */ +#define SDHCI_HW_RESET_CARD BIT(3) + +#define SDHCI_SPRD_MAX_CUR 0xFFFFFF +#define SDHCI_SPRD_CLK_MAX_DIV 1023 + +#define SDHCI_SPRD_CLK_DEF_RATE 26000000 + +struct sdhci_sprd_host { + u32 version; + struct clk *clk_sdio; + struct clk *clk_enable; + u32 base_rate; + int flags; /* backup of host attribute */ +}; + +#define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host)) + +static void sdhci_sprd_init_config(struct sdhci_host *host) +{ + u16 val; + + /* set dll backup mode */ + val = sdhci_readl(host, SDHCI_SPRD_REG_DEBOUNCE); + val |= SDHCI_SPRD_BIT_DLL_BAK | SDHCI_SPRD_BIT_DLL_VAL; + sdhci_writel(host, val, SDHCI_SPRD_REG_DEBOUNCE); +} + +static inline u32 sdhci_sprd_readl(struct sdhci_host *host, int reg) +{ + if (unlikely(reg == SDHCI_MAX_CURRENT)) + return SDHCI_SPRD_MAX_CUR; + + return readl_relaxed(host->ioaddr + reg); +} + +static inline void sdhci_sprd_writel(struct sdhci_host *host, u32 val, int reg) +{ + /* SDHCI_MAX_CURRENT is reserved on Spreadtrum's platform */ + if (unlikely(reg == SDHCI_MAX_CURRENT)) + return; + + if (unlikely(reg == SDHCI_SIGNAL_ENABLE || reg == SDHCI_INT_ENABLE)) + val = val & SDHCI_SPRD_INT_SIGNAL_MASK; + + writel_relaxed(val, host->ioaddr + reg); +} + +static inline void sdhci_sprd_writew(struct sdhci_host *host, u16 val, int reg) +{ + /* SDHCI_BLOCK_COUNT is Read Only on Spreadtrum's platform */ + if (unlikely(reg == SDHCI_BLOCK_COUNT)) + return; + + writew_relaxed(val, host->ioaddr + reg); +} + +static inline void sdhci_sprd_writeb(struct sdhci_host *host, u8 val, int reg) +{ + /* + * Since BIT(3) of SDHCI_SOFTWARE_RESET is reserved according to the + * standard specification, sdhci_reset() write this register directly + * without checking other reserved bits, that will clear BIT(3) which + * is defined as hardware reset on Spreadtrum's platform and clearing + * it by mistake will lead the card not work. So here we need to work + * around it. + */ + if (unlikely(reg == SDHCI_SOFTWARE_RESET)) { + if (readb_relaxed(host->ioaddr + reg) & SDHCI_HW_RESET_CARD) + val |= SDHCI_HW_RESET_CARD; + } + + writeb_relaxed(val, host->ioaddr + reg); +} + +static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host) +{ + u16 ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + + ctrl &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL); +} + +static inline void +sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en) +{ + u32 dll_dly_offset; + + dll_dly_offset = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_DLY_OFFSET); + if (en) + dll_dly_offset |= mask; + else + dll_dly_offset &= ~mask; + sdhci_writel(host, dll_dly_offset, SDHCI_SPRD_REG_32_DLL_DLY_OFFSET); +} + +static inline u32 sdhci_sprd_calc_div(u32 base_clk, u32 clk) +{ + u32 div; + + /* select 2x clock source */ + if (base_clk <= clk * 2) + return 0; + + div = (u32) (base_clk / (clk * 2)); + + if ((base_clk / div) > (clk * 2)) + div++; + + if (div > SDHCI_SPRD_CLK_MAX_DIV) + div = SDHCI_SPRD_CLK_MAX_DIV; + + if (div % 2) + div = (div + 1) / 2; + else + div = div / 2; + + return div; +} + +static inline void _sdhci_sprd_set_clock(struct sdhci_host *host, + unsigned int clk) +{ + struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host); + u32 div, val, mask; + + div = sdhci_sprd_calc_div(sprd_host->base_rate, clk); + + clk |= ((div & 0x300) >> 2) | ((div & 0xFF) << 8); + sdhci_enable_clk(host, clk); + + /* enable auto gate sdhc_enable_auto_gate */ + val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI); + mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN | + SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN; + if (mask != (val & mask)) { + val |= mask; + sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI); + } +} + +static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock) +{ + bool en = false; + + if (clock == 0) { + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + } else if (clock != host->clock) { + sdhci_sprd_sd_clk_off(host); + _sdhci_sprd_set_clock(host, clock); + + if (clock <= 400000) + en = true; + sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV | + SDHCI_SPRD_BIT_POSRD_DLY_INV, en); + } else { + _sdhci_sprd_set_clock(host, clock); + } +} + +static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host); + + return clk_round_rate(sprd_host->clk_sdio, ULONG_MAX); +} + +static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host) +{ + return 400000; +} + +static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u16 ctrl_2; + + if (timing == host->timing) + return; + + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + switch (timing) { + case MMC_TIMING_UHS_SDR12: + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; + break; + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR25: + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + break; + case MMC_TIMING_UHS_SDR50: + ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + break; + case MMC_TIMING_UHS_SDR104: + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + break; + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + break; + case MMC_TIMING_MMC_HS200: + ctrl_2 |= SDHCI_SPRD_CTRL_HS200; + break; + case MMC_TIMING_MMC_HS400: + ctrl_2 |= SDHCI_SPRD_CTRL_HS400; + break; + default: + break; + } + + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} + +static void sdhci_sprd_hw_reset(struct sdhci_host *host) +{ + int val; + + /* + * Note: don't use sdhci_writeb() API here since it is redirected to + * sdhci_sprd_writeb() in which we have a workaround for + * SDHCI_SOFTWARE_RESET which would make bit SDHCI_HW_RESET_CARD can + * not be cleared. + */ + val = readb_relaxed(host->ioaddr + SDHCI_SOFTWARE_RESET); + val &= ~SDHCI_HW_RESET_CARD; + writeb_relaxed(val, host->ioaddr + SDHCI_SOFTWARE_RESET); + /* wait for 10 us */ + usleep_range(10, 20); + + val |= SDHCI_HW_RESET_CARD; + writeb_relaxed(val, host->ioaddr + SDHCI_SOFTWARE_RESET); + usleep_range(300, 500); +} + +static struct sdhci_ops sdhci_sprd_ops = { + .read_l = sdhci_sprd_readl, + .write_l = sdhci_sprd_writel, + .write_b = sdhci_sprd_writeb, + .set_clock = sdhci_sprd_set_clock, + .get_max_clock = sdhci_sprd_get_max_clock, + .get_min_clock = sdhci_sprd_get_min_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_sprd_set_uhs_signaling, + .hw_reset = sdhci_sprd_hw_reset, +}; + +static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host); + + host->flags |= sprd_host->flags & SDHCI_AUTO_CMD23; + + /* + * From version 4.10 onward, ARGUMENT2 register is also as 32-bit + * block count register which doesn't support stuff bits of + * CMD23 argument on Spreadtrum's sd host controller. + */ + if (host->version >= SDHCI_SPEC_410 && + mrq->sbc && (mrq->sbc->arg & SDHCI_SPRD_ARG2_STUFF) && + (host->flags & SDHCI_AUTO_CMD23)) + host->flags &= ~SDHCI_AUTO_CMD23; + + sdhci_request(mmc, mrq); +} + +static const struct sdhci_pltfm_data sdhci_sprd_pdata = { + .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, + .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 | + SDHCI_QUIRK2_USE_32BIT_BLK_CNT, + .ops = &sdhci_sprd_ops, +}; + +static int sdhci_sprd_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_sprd_host *sprd_host; + struct clk *clk; + int ret = 0; + + host = sdhci_pltfm_init(pdev, &sdhci_sprd_pdata, sizeof(*sprd_host)); + if (IS_ERR(host)) + return PTR_ERR(host); + + host->dma_mask = DMA_BIT_MASK(64); + pdev->dev.dma_mask = &host->dma_mask; + host->mmc_host_ops.request = sdhci_sprd_request; + + host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_ERASE | MMC_CAP_CMD23; + ret = mmc_of_parse(host->mmc); + if (ret) + goto pltfm_free; + + sprd_host = TO_SPRD_HOST(host); + + clk = devm_clk_get(&pdev->dev, "sdio"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto pltfm_free; + } + sprd_host->clk_sdio = clk; + sprd_host->base_rate = clk_get_rate(sprd_host->clk_sdio); + if (!sprd_host->base_rate) + sprd_host->base_rate = SDHCI_SPRD_CLK_DEF_RATE; + + clk = devm_clk_get(&pdev->dev, "enable"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto pltfm_free; + } + sprd_host->clk_enable = clk; + + ret = clk_prepare_enable(sprd_host->clk_sdio); + if (ret) + goto pltfm_free; + + clk_prepare_enable(sprd_host->clk_enable); + if (ret) + goto clk_disable; + + sdhci_sprd_init_config(host); + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >> + SDHCI_VENDOR_VER_SHIFT); + + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, 1); + + sdhci_enable_v4_mode(host); + + ret = sdhci_setup_host(host); + if (ret) + goto pm_runtime_disable; + + sprd_host->flags = host->flags; + + ret = __sdhci_add_host(host); + if (ret) + goto err_cleanup_host; + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + return 0; + +err_cleanup_host: + sdhci_cleanup_host(host); + +pm_runtime_disable: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + + clk_disable_unprepare(sprd_host->clk_enable); + +clk_disable: + clk_disable_unprepare(sprd_host->clk_sdio); + +pltfm_free: + sdhci_pltfm_free(pdev); + return ret; +} + +static int sdhci_sprd_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host); + struct mmc_host *mmc = host->mmc; + + mmc_remove_host(mmc); + clk_disable_unprepare(sprd_host->clk_sdio); + clk_disable_unprepare(sprd_host->clk_enable); + + mmc_free_host(mmc); + + return 0; +} + +static const struct of_device_id sdhci_sprd_of_match[] = { + { .compatible = "sprd,sdhci-r11", }, + { } +}; +MODULE_DEVICE_TABLE(of, sdhci_sprd_of_match); + +#ifdef CONFIG_PM +static int sdhci_sprd_runtime_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host); + + sdhci_runtime_suspend_host(host); + + clk_disable_unprepare(sprd_host->clk_sdio); + clk_disable_unprepare(sprd_host->clk_enable); + + return 0; +} + +static int sdhci_sprd_runtime_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host); + int ret; + + ret = clk_prepare_enable(sprd_host->clk_enable); + if (ret) + return ret; + + ret = clk_prepare_enable(sprd_host->clk_sdio); + if (ret) { + clk_disable_unprepare(sprd_host->clk_enable); + return ret; + } + + sdhci_runtime_resume_host(host); + + return 0; +} +#endif + +static const struct dev_pm_ops sdhci_sprd_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(sdhci_sprd_runtime_suspend, + sdhci_sprd_runtime_resume, NULL) +}; + +static struct platform_driver sdhci_sprd_driver = { + .probe = sdhci_sprd_probe, + .remove = sdhci_sprd_remove, + .driver = { + .name = "sdhci_sprd_r11", + .of_match_table = of_match_ptr(sdhci_sprd_of_match), + .pm = &sdhci_sprd_pm_ops, + }, +}; +module_platform_driver(sdhci_sprd_driver); + +MODULE_DESCRIPTION("Spreadtrum sdio host controller r11 driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sdhci-sprd-r11"); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 908b23e6a03c..7b95d088fdef 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -16,17 +16,21 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/iopoll.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> +#include <linux/regulator/consumer.h> #include <linux/reset.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/slot-gpio.h> #include <linux/gpio/consumer.h> +#include <linux/ktime.h> #include "sdhci-pltfm.h" @@ -34,40 +38,96 @@ #define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 #define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000 #define SDHCI_CLOCK_CTRL_TAP_SHIFT 16 +#define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000 +#define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24 #define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5) #define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3) #define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2) -#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 -#define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8 -#define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10 -#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 -#define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200 +#define SDHCI_TEGRA_VENDOR_SYS_SW_CTRL 0x104 +#define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE BIT(31) -#define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4 -#define SDHCI_AUTO_CAL_START BIT(31) -#define SDHCI_AUTO_CAL_ENABLE BIT(29) +#define SDHCI_TEGRA_VENDOR_CAP_OVERRIDES 0x10c +#define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK 0x00003f00 +#define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT 8 -#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) -#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) -#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) -#define NVQUIRK_ENABLE_SDR50 BIT(3) -#define NVQUIRK_ENABLE_SDR104 BIT(4) -#define NVQUIRK_ENABLE_DDR50 BIT(5) -#define NVQUIRK_HAS_PADCALIB BIT(6) +#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 +#define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8 +#define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10 +#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 +#define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200 + +#define SDHCI_TEGRA_VENDOR_DLLCAL_CFG 0x1b0 +#define SDHCI_TEGRA_DLLCAL_CALIBRATE BIT(31) + +#define SDHCI_TEGRA_VENDOR_DLLCAL_STA 0x1bc +#define SDHCI_TEGRA_DLLCAL_STA_ACTIVE BIT(31) + +#define SDHCI_VNDR_TUN_CTRL0_0 0x1c0 +#define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP 0x20000 + +#define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4 +#define SDHCI_AUTO_CAL_START BIT(31) +#define SDHCI_AUTO_CAL_ENABLE BIT(29) +#define SDHCI_AUTO_CAL_PDPU_OFFSET_MASK 0x0000ffff + +#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL 0x1e0 +#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK 0x0000000f +#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL 0x7 +#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD BIT(31) + +#define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec +#define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31) + +#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) +#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) +#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) +#define NVQUIRK_ENABLE_SDR50 BIT(3) +#define NVQUIRK_ENABLE_SDR104 BIT(4) +#define NVQUIRK_ENABLE_DDR50 BIT(5) +#define NVQUIRK_HAS_PADCALIB BIT(6) +#define NVQUIRK_NEEDS_PAD_CONTROL BIT(7) +#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) struct sdhci_tegra_soc_data { const struct sdhci_pltfm_data *pdata; u32 nvquirks; }; +/* Magic pull up and pull down pad calibration offsets */ +struct sdhci_tegra_autocal_offsets { + u32 pull_up_3v3; + u32 pull_down_3v3; + u32 pull_up_3v3_timeout; + u32 pull_down_3v3_timeout; + u32 pull_up_1v8; + u32 pull_down_1v8; + u32 pull_up_1v8_timeout; + u32 pull_down_1v8_timeout; + u32 pull_up_sdr104; + u32 pull_down_sdr104; + u32 pull_up_hs400; + u32 pull_down_hs400; +}; + struct sdhci_tegra { const struct sdhci_tegra_soc_data *soc_data; struct gpio_desc *power_gpio; bool ddr_signaling; bool pad_calib_required; + bool pad_control_available; struct reset_control *rst; + struct pinctrl *pinctrl_sdmmc; + struct pinctrl_state *pinctrl_state_3v3; + struct pinctrl_state *pinctrl_state_1v8; + + struct sdhci_tegra_autocal_offsets autocal_offsets; + ktime_t last_calib; + + u32 default_tap; + u32 default_trim; + u32 dqs_trim; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -133,23 +193,149 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) } } +static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable) +{ + bool status; + u32 reg; + + reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + status = !!(reg & SDHCI_CLOCK_CARD_EN); + + if (status == enable) + return status; + + if (enable) + reg |= SDHCI_CLOCK_CARD_EN; + else + reg &= ~SDHCI_CLOCK_CARD_EN; + + sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL); + + return status; +} + +static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg) +{ + bool is_tuning_cmd = 0; + bool clk_enabled; + u8 cmd; + + if (reg == SDHCI_COMMAND) { + cmd = SDHCI_GET_CMD(val); + is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK || + cmd == MMC_SEND_TUNING_BLOCK_HS200; + } + + if (is_tuning_cmd) + clk_enabled = tegra_sdhci_configure_card_clk(host, 0); + + writew(val, host->ioaddr + reg); + + if (is_tuning_cmd) { + udelay(1); + tegra_sdhci_configure_card_clk(host, clk_enabled); + } +} + static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) { return mmc_gpio_get_ro(host->mmc); } +static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + int has_1v8, has_3v3; + + /* + * The SoCs which have NVQUIRK_NEEDS_PAD_CONTROL require software pad + * voltage configuration in order to perform voltage switching. This + * means that valid pinctrl info is required on SDHCI instances capable + * of performing voltage switching. Whether or not an SDHCI instance is + * capable of voltage switching is determined based on the regulator. + */ + + if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)) + return true; + + if (IS_ERR(host->mmc->supply.vqmmc)) + return false; + + has_1v8 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, + 1700000, 1950000); + + has_3v3 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, + 2700000, 3600000); + + if (has_1v8 == 1 && has_3v3 == 1) + return tegra_host->pad_control_available; + + /* Fixed voltage, no pad control required. */ + return true; +} + +static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + bool card_clk_enabled = false; + u32 reg; + + /* + * Touching the tap values is a bit tricky on some SoC generations. + * The quirk enables a workaround for a glitch that sometimes occurs if + * the tap values are changed. + */ + + if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP) + card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); + + reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; + reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; + sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + + if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP && + card_clk_enabled) { + udelay(1); + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + tegra_sdhci_configure_card_clk(host, card_clk_enabled); + } +} + +static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 val; + + val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); + + if (ios->enhanced_strobe) + val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; + else + val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; + + sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); + +} + static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; - u32 misc_ctrl, clk_ctrl; + u32 misc_ctrl, clk_ctrl, pad_ctrl; sdhci_reset(host, mask); if (!(mask & SDHCI_RESET_ALL)) return; + tegra_sdhci_set_tap(host, tegra_host->default_tap); + misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); @@ -158,15 +344,10 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) SDHCI_MISC_CTRL_ENABLE_DDR50 | SDHCI_MISC_CTRL_ENABLE_SDR104); - clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE; + clk_ctrl &= ~(SDHCI_CLOCK_CTRL_TRIM_MASK | + SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE); - /* - * If the board does not define a regulator for the SDHCI - * IO voltage, then don't advertise support for UHS modes - * even if the device supports it because the IO voltage - * cannot be configured. - */ - if (!IS_ERR(host->mmc->supply.vqmmc)) { + if (tegra_sdhci_is_pad_and_regulator_valid(host)) { /* Erratum: Enable SDHCI spec v3.00 support */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; @@ -181,24 +362,237 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; } + clk_ctrl |= tegra_host->default_trim << SDHCI_CLOCK_CTRL_TRIM_SHIFT; + sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); - if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) + if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) { + pad_ctrl = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); + pad_ctrl &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK; + pad_ctrl |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL; + sdhci_writel(host, pad_ctrl, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); + tegra_host->pad_calib_required = true; + } tegra_host->ddr_signaling = false; } -static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) +static void tegra_sdhci_configure_cal_pad(struct sdhci_host *host, bool enable) { u32 val; - mdelay(1); + /* + * Enable or disable the additional I/O pad used by the drive strength + * calibration process. + */ + val = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); + + if (enable) + val |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; + else + val &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD; + + sdhci_writel(host, val, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); + + if (enable) + usleep_range(1, 2); +} + +static void tegra_sdhci_set_pad_autocal_offset(struct sdhci_host *host, + u16 pdpu) +{ + u32 reg; + + reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); + reg &= ~SDHCI_AUTO_CAL_PDPU_OFFSET_MASK; + reg |= pdpu; + sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); +} + +static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + struct sdhci_tegra_autocal_offsets offsets = + tegra_host->autocal_offsets; + struct mmc_ios *ios = &host->mmc->ios; + bool card_clk_enabled; + u16 pdpu; + u32 reg; + int ret; + + switch (ios->timing) { + case MMC_TIMING_UHS_SDR104: + pdpu = offsets.pull_down_sdr104 << 8 | offsets.pull_up_sdr104; + break; + case MMC_TIMING_MMC_HS400: + pdpu = offsets.pull_down_hs400 << 8 | offsets.pull_up_hs400; + break; + default: + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) + pdpu = offsets.pull_down_1v8 << 8 | offsets.pull_up_1v8; + else + pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3; + } + + tegra_sdhci_set_pad_autocal_offset(host, pdpu); + + card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); + + tegra_sdhci_configure_cal_pad(host, true); + + reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); + reg |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START; + sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); + + usleep_range(1, 2); + /* 10 ms timeout */ + ret = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_AUTO_CAL_STATUS, + reg, !(reg & SDHCI_TEGRA_AUTO_CAL_ACTIVE), + 1000, 10000); + + tegra_sdhci_configure_cal_pad(host, false); + + tegra_sdhci_configure_card_clk(host, card_clk_enabled); + + if (ret) { + dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n"); + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) + pdpu = offsets.pull_down_1v8_timeout << 8 | + offsets.pull_up_1v8_timeout; + else + pdpu = offsets.pull_down_3v3_timeout << 8 | + offsets.pull_up_3v3_timeout; + + /* Disable automatic calibration and use fixed offsets */ + reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); + reg &= ~SDHCI_AUTO_CAL_ENABLE; + sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); - val = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); - val |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START; - sdhci_writel(host,val, SDHCI_TEGRA_AUTO_CAL_CONFIG); + tegra_sdhci_set_pad_autocal_offset(host, pdpu); + } +} + +static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + struct sdhci_tegra_autocal_offsets *autocal = + &tegra_host->autocal_offsets; + int err; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-3v3", + &autocal->pull_up_3v3); + if (err) + autocal->pull_up_3v3 = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-3v3", + &autocal->pull_down_3v3); + if (err) + autocal->pull_down_3v3 = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-1v8", + &autocal->pull_up_1v8); + if (err) + autocal->pull_up_1v8 = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-1v8", + &autocal->pull_down_1v8); + if (err) + autocal->pull_down_1v8 = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-3v3-timeout", + &autocal->pull_up_3v3); + if (err) + autocal->pull_up_3v3_timeout = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-3v3-timeout", + &autocal->pull_down_3v3); + if (err) + autocal->pull_down_3v3_timeout = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-1v8-timeout", + &autocal->pull_up_1v8); + if (err) + autocal->pull_up_1v8_timeout = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-1v8-timeout", + &autocal->pull_down_1v8); + if (err) + autocal->pull_down_1v8_timeout = 0; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-sdr104", + &autocal->pull_up_sdr104); + if (err) + autocal->pull_up_sdr104 = autocal->pull_up_1v8; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-sdr104", + &autocal->pull_down_sdr104); + if (err) + autocal->pull_down_sdr104 = autocal->pull_down_1v8; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-hs400", + &autocal->pull_up_hs400); + if (err) + autocal->pull_up_hs400 = autocal->pull_up_1v8; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-hs400", + &autocal->pull_down_hs400); + if (err) + autocal->pull_down_hs400 = autocal->pull_down_1v8; +} + +static void tegra_sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + ktime_t since_calib = ktime_sub(ktime_get(), tegra_host->last_calib); + + /* 100 ms calibration interval is specified in the TRM */ + if (ktime_to_ms(since_calib) > 100) { + tegra_sdhci_pad_autocalib(host); + tegra_host->last_calib = ktime_get(); + } + + sdhci_request(mmc, mrq); +} + +static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + int err; + + err = device_property_read_u32(host->mmc->parent, "nvidia,default-tap", + &tegra_host->default_tap); + if (err) + tegra_host->default_tap = 0; + + err = device_property_read_u32(host->mmc->parent, "nvidia,default-trim", + &tegra_host->default_trim); + if (err) + tegra_host->default_trim = 0; + + err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim", + &tegra_host->dqs_trim); + if (err) + tegra_host->dqs_trim = 0x11; } static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) @@ -237,34 +631,82 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) } } -static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, - unsigned timing) +static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); - if (timing == MMC_TIMING_UHS_DDR50 || - timing == MMC_TIMING_MMC_DDR52) - tegra_host->ddr_signaling = true; - - sdhci_set_uhs_signaling(host, timing); + return clk_round_rate(pltfm_host->clk, UINT_MAX); } -static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) +static void tegra_sdhci_set_dqs_trim(struct sdhci_host *host, u8 trim) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + u32 val; - return clk_round_rate(pltfm_host->clk, UINT_MAX); + val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); + val &= ~SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK; + val |= trim << SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT; + sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES); } -static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) +static void tegra_sdhci_hs400_dll_cal(struct sdhci_host *host) { u32 reg; + int err; + + reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); + reg |= SDHCI_TEGRA_DLLCAL_CALIBRATE; + sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_DLLCAL_CFG); + + /* 1 ms sleep, 5 ms timeout */ + err = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_VENDOR_DLLCAL_STA, + reg, !(reg & SDHCI_TEGRA_DLLCAL_STA_ACTIVE), + 1000, 5000); + if (err) + dev_err(mmc_dev(host->mmc), + "HS400 delay line calibration timed out\n"); +} - reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); - reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; - reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; - sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); +static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, + unsigned timing) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + bool set_default_tap = false; + bool set_dqs_trim = false; + bool do_hs400_dll_cal = false; + + switch (timing) { + case MMC_TIMING_UHS_SDR50: + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* Don't set default tap on tunable modes. */ + break; + case MMC_TIMING_MMC_HS400: + set_dqs_trim = true; + do_hs400_dll_cal = true; + break; + case MMC_TIMING_MMC_DDR52: + case MMC_TIMING_UHS_DDR50: + tegra_host->ddr_signaling = true; + set_default_tap = true; + break; + default: + set_default_tap = true; + break; + } + + sdhci_set_uhs_signaling(host, timing); + + tegra_sdhci_pad_autocalib(host); + + if (set_default_tap) + tegra_sdhci_set_tap(host, tegra_host->default_tap); + + if (set_dqs_trim) + tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim); + + if (do_hs400_dll_cal) + tegra_sdhci_hs400_dll_cal(host); } static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) @@ -301,6 +743,89 @@ static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) return mmc_send_tuning(host->mmc, opcode, NULL); } +static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + int ret; + + if (!tegra_host->pad_control_available) + return 0; + + if (voltage == MMC_SIGNAL_VOLTAGE_180) { + ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, + tegra_host->pinctrl_state_1v8); + if (ret < 0) + dev_err(mmc_dev(host->mmc), + "setting 1.8V failed, ret: %d\n", ret); + } else { + ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, + tegra_host->pinctrl_state_3v3); + if (ret < 0) + dev_err(mmc_dev(host->mmc), + "setting 3.3V failed, ret: %d\n", ret); + } + + return ret; +} + +static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + int ret = 0; + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); + if (ret < 0) + return ret; + ret = sdhci_start_signal_voltage_switch(mmc, ios); + } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + ret = sdhci_start_signal_voltage_switch(mmc, ios); + if (ret < 0) + return ret; + ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); + } + + if (tegra_host->pad_calib_required) + tegra_sdhci_pad_autocalib(host); + + return ret; +} + +static int tegra_sdhci_init_pinctrl_info(struct device *dev, + struct sdhci_tegra *tegra_host) +{ + tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev); + if (IS_ERR(tegra_host->pinctrl_sdmmc)) { + dev_dbg(dev, "No pinctrl info, err: %ld\n", + PTR_ERR(tegra_host->pinctrl_sdmmc)); + return -1; + } + + tegra_host->pinctrl_state_3v3 = + pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-3v3"); + if (IS_ERR(tegra_host->pinctrl_state_3v3)) { + dev_warn(dev, "Missing 3.3V pad state, err: %ld\n", + PTR_ERR(tegra_host->pinctrl_state_3v3)); + return -1; + } + + tegra_host->pinctrl_state_1v8 = + pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-1v8"); + if (IS_ERR(tegra_host->pinctrl_state_1v8)) { + dev_warn(dev, "Missing 1.8V pad state, err: %ld\n", + PTR_ERR(tegra_host->pinctrl_state_1v8)); + return -1; + } + + tegra_host->pad_control_available = true; + + return 0; +} + static void tegra_sdhci_voltage_switch(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -421,6 +946,19 @@ static const struct sdhci_tegra_soc_data soc_data_tegra124 = { .pdata = &sdhci_tegra124_pdata, }; +static const struct sdhci_ops tegra210_sdhci_ops = { + .get_ro = tegra_sdhci_get_ro, + .read_w = tegra_sdhci_readw, + .write_w = tegra210_sdhci_writew, + .write_l = tegra_sdhci_writel, + .set_clock = tegra_sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = tegra_sdhci_reset, + .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, + .voltage_switch = tegra_sdhci_voltage_switch, + .get_max_clock = tegra_sdhci_get_max_clock, +}; + static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | @@ -429,11 +967,28 @@ static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, - .ops = &tegra114_sdhci_ops, + .ops = &tegra210_sdhci_ops, }; static const struct sdhci_tegra_soc_data soc_data_tegra210 = { .pdata = &sdhci_tegra210_pdata, + .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | + NVQUIRK_HAS_PADCALIB | + NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | + NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_SDR104, +}; + +static const struct sdhci_ops tegra186_sdhci_ops = { + .get_ro = tegra_sdhci_get_ro, + .read_w = tegra_sdhci_readw, + .write_l = tegra_sdhci_writel, + .set_clock = tegra_sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = tegra_sdhci_reset, + .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, + .voltage_switch = tegra_sdhci_voltage_switch, + .get_max_clock = tegra_sdhci_get_max_clock, }; static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { @@ -452,11 +1007,16 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { * But it is not supported as of now. */ SDHCI_QUIRK2_BROKEN_64_BIT_DMA, - .ops = &tegra114_sdhci_ops, + .ops = &tegra186_sdhci_ops, }; static const struct sdhci_tegra_soc_data soc_data_tegra186 = { .pdata = &sdhci_tegra186_pdata, + .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | + NVQUIRK_HAS_PADCALIB | + NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | + NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_SDR104, }; static const struct of_device_id sdhci_tegra_dt_match[] = { @@ -493,8 +1053,23 @@ static int sdhci_tegra_probe(struct platform_device *pdev) tegra_host = sdhci_pltfm_priv(pltfm_host); tegra_host->ddr_signaling = false; tegra_host->pad_calib_required = false; + tegra_host->pad_control_available = false; tegra_host->soc_data = soc_data; + if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) { + rc = tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host); + if (rc == 0) + host->mmc_host_ops.start_signal_voltage_switch = + sdhci_tegra_start_signal_voltage_switch; + } + + /* Hook to periodically rerun pad calibration */ + if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) + host->mmc_host_ops.request = tegra_sdhci_request; + + host->mmc_host_ops.hs400_enhanced_strobe = + tegra_sdhci_hs400_enhanced_strobe; + rc = mmc_of_parse(host->mmc); if (rc) goto err_parse_dt; @@ -502,6 +1077,10 @@ static int sdhci_tegra_probe(struct platform_device *pdev) if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) host->mmc->caps |= MMC_CAP_1_8V_DDR; + tegra_sdhci_parse_pad_autocal_dt(host); + + tegra_sdhci_parse_tap_and_trim(host); + tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_OUT_HIGH); if (IS_ERR(tegra_host->power_gpio)) { diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c index c335052d0c02..5956e90380e8 100644 --- a/drivers/mmc/host/sdhci-xenon-phy.c +++ b/drivers/mmc/host/sdhci-xenon-phy.c @@ -660,8 +660,8 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host, return 0; if (of_address_to_resource(np, 1, &iomem)) { - dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %s\n", - np->name); + dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %pOFn\n", + np); return -EINVAL; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1b3fbd9bd5c5..99bdae53fa2e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -123,6 +123,29 @@ EXPORT_SYMBOL_GPL(sdhci_dumpregs); * * \*****************************************************************************/ +static void sdhci_do_enable_v4_mode(struct sdhci_host *host) +{ + u16 ctrl2; + + ctrl2 = sdhci_readb(host, SDHCI_HOST_CONTROL2); + if (ctrl2 & SDHCI_CTRL_V4_MODE) + return; + + ctrl2 |= SDHCI_CTRL_V4_MODE; + sdhci_writeb(host, ctrl2, SDHCI_HOST_CONTROL); +} + +/* + * This can be called before sdhci_add_host() by Vendor's host controller + * driver to enable v4 mode if supported. + */ +void sdhci_enable_v4_mode(struct sdhci_host *host) +{ + host->v4_mode = true; + sdhci_do_enable_v4_mode(host); +} +EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode); + static inline bool sdhci_data_line_cmd(struct mmc_command *cmd) { return cmd->data || cmd->flags & MMC_RSP_BUSY; @@ -243,6 +266,52 @@ static void sdhci_set_default_irqs(struct sdhci_host *host) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } +static void sdhci_config_dma(struct sdhci_host *host) +{ + u8 ctrl; + u16 ctrl2; + + if (host->version < SDHCI_SPEC_200) + return; + + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + + /* + * Always adjust the DMA selection as some controllers + * (e.g. JMicron) can't do PIO properly when the selection + * is ADMA. + */ + ctrl &= ~SDHCI_CTRL_DMA_MASK; + if (!(host->flags & SDHCI_REQ_USE_DMA)) + goto out; + + /* Note if DMA Select is zero then SDMA is selected */ + if (host->flags & SDHCI_USE_ADMA) + ctrl |= SDHCI_CTRL_ADMA32; + + if (host->flags & SDHCI_USE_64_BIT_DMA) { + /* + * If v4 mode, all supported DMA can be 64-bit addressing if + * controller supports 64-bit system address, otherwise only + * ADMA can support 64-bit addressing. + */ + if (host->v4_mode) { + ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl2 |= SDHCI_CTRL_64BIT_ADDR; + sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); + } else if (host->flags & SDHCI_USE_ADMA) { + /* + * Don't need to undo SDHCI_CTRL_ADMA32 in order to + * set SDHCI_CTRL_ADMA64. + */ + ctrl |= SDHCI_CTRL_ADMA64; + } + } + +out: + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +} + static void sdhci_init(struct sdhci_host *host, int soft) { struct mmc_host *mmc = host->mmc; @@ -252,6 +321,9 @@ static void sdhci_init(struct sdhci_host *host, int soft) else sdhci_do_reset(host, SDHCI_RESET_ALL); + if (host->v4_mode) + sdhci_do_enable_v4_mode(host); + sdhci_set_default_irqs(host); host->cqe_on = false; @@ -554,10 +626,10 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) local_irq_restore(*flags); } -static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc, - dma_addr_t addr, int len, unsigned cmd) +void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd) { - struct sdhci_adma2_64_desc *dma_desc = desc; + struct sdhci_adma2_64_desc *dma_desc = *desc; /* 32-bit and 64-bit descriptors have these members in same position */ dma_desc->cmd = cpu_to_le16(cmd); @@ -566,6 +638,19 @@ static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc, if (host->flags & SDHCI_USE_64_BIT_DMA) dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32); + + *desc += host->desc_sz; +} +EXPORT_SYMBOL_GPL(sdhci_adma_write_desc); + +static inline void __sdhci_adma_write_desc(struct sdhci_host *host, + void **desc, dma_addr_t addr, + int len, unsigned int cmd) +{ + if (host->ops->adma_write_desc) + host->ops->adma_write_desc(host, desc, addr, len, cmd); + else + sdhci_adma_write_desc(host, desc, addr, len, cmd); } static void sdhci_adma_mark_end(void *desc) @@ -618,28 +703,24 @@ static void sdhci_adma_table_pre(struct sdhci_host *host, } /* tran, valid */ - sdhci_adma_write_desc(host, desc, align_addr, offset, - ADMA2_TRAN_VALID); + __sdhci_adma_write_desc(host, &desc, align_addr, + offset, ADMA2_TRAN_VALID); BUG_ON(offset > 65536); align += SDHCI_ADMA2_ALIGN; align_addr += SDHCI_ADMA2_ALIGN; - desc += host->desc_sz; - addr += offset; len -= offset; } BUG_ON(len > 65536); - if (len) { - /* tran, valid */ - sdhci_adma_write_desc(host, desc, addr, len, - ADMA2_TRAN_VALID); - desc += host->desc_sz; - } + /* tran, valid */ + if (len) + __sdhci_adma_write_desc(host, &desc, addr, len, + ADMA2_TRAN_VALID); /* * If this triggers then we have a calculation bug @@ -656,7 +737,7 @@ static void sdhci_adma_table_pre(struct sdhci_host *host, } } else { /* Add a terminating entry - nop, end, valid */ - sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); + __sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID); } } @@ -701,7 +782,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, } } -static u32 sdhci_sdma_address(struct sdhci_host *host) +static dma_addr_t sdhci_sdma_address(struct sdhci_host *host) { if (host->bounce_buffer) return host->bounce_addr; @@ -709,6 +790,17 @@ static u32 sdhci_sdma_address(struct sdhci_host *host) return sg_dma_address(host->data->sg); } +static void sdhci_set_sdma_addr(struct sdhci_host *host, dma_addr_t addr) +{ + if (host->v4_mode) { + sdhci_writel(host, addr, SDHCI_ADMA_ADDRESS); + if (host->flags & SDHCI_USE_64_BIT_DMA) + sdhci_writel(host, (u64)addr >> 32, SDHCI_ADMA_ADDRESS_HI); + } else { + sdhci_writel(host, addr, SDHCI_DMA_ADDRESS); + } +} + static unsigned int sdhci_target_timeout(struct sdhci_host *host, struct mmc_command *cmd, struct mmc_data *data) @@ -876,7 +968,6 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) { - u8 ctrl; struct mmc_data *data = cmd->data; host->data_timeout = 0; @@ -968,30 +1059,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) SDHCI_ADMA_ADDRESS_HI); } else { WARN_ON(sg_cnt != 1); - sdhci_writel(host, sdhci_sdma_address(host), - SDHCI_DMA_ADDRESS); + sdhci_set_sdma_addr(host, sdhci_sdma_address(host)); } } - /* - * Always adjust the DMA selection as some controllers - * (e.g. JMicron) can't do PIO properly when the selection - * is ADMA. - */ - if (host->version >= SDHCI_SPEC_200) { - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - ctrl &= ~SDHCI_CTRL_DMA_MASK; - if ((host->flags & SDHCI_REQ_USE_DMA) && - (host->flags & SDHCI_USE_ADMA)) { - if (host->flags & SDHCI_USE_64_BIT_DMA) - ctrl |= SDHCI_CTRL_ADMA64; - else - ctrl |= SDHCI_CTRL_ADMA32; - } else { - ctrl |= SDHCI_CTRL_SDMA; - } - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - } + sdhci_config_dma(host); if (!(host->flags & SDHCI_REQ_USE_DMA)) { int flags; @@ -1010,7 +1082,19 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) /* Set the DMA boundary value and block size */ sdhci_writew(host, SDHCI_MAKE_BLKSZ(host->sdma_boundary, data->blksz), SDHCI_BLOCK_SIZE); - sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); + + /* + * For Version 4.10 onwards, if v4 mode is enabled, 32-bit Block Count + * can be supported, in that case 16-bit block count register must be 0. + */ + if (host->version >= SDHCI_SPEC_410 && host->v4_mode && + (host->quirks2 & SDHCI_QUIRK2_USE_32BIT_BLK_CNT)) { + if (sdhci_readw(host, SDHCI_BLOCK_COUNT)) + sdhci_writew(host, 0, SDHCI_BLOCK_COUNT); + sdhci_writew(host, data->blocks, SDHCI_32BIT_BLK_CNT); + } else { + sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); + } } static inline bool sdhci_auto_cmd12(struct sdhci_host *host, @@ -1020,6 +1104,43 @@ static inline bool sdhci_auto_cmd12(struct sdhci_host *host, !mrq->cap_cmd_during_tfr; } +static inline void sdhci_auto_cmd_select(struct sdhci_host *host, + struct mmc_command *cmd, + u16 *mode) +{ + bool use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) && + (cmd->opcode != SD_IO_RW_EXTENDED); + bool use_cmd23 = cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23); + u16 ctrl2; + + /* + * In case of Version 4.10 or later, use of 'Auto CMD Auto + * Select' is recommended rather than use of 'Auto CMD12 + * Enable' or 'Auto CMD23 Enable'. + */ + if (host->version >= SDHCI_SPEC_410 && (use_cmd12 || use_cmd23)) { + *mode |= SDHCI_TRNS_AUTO_SEL; + + ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (use_cmd23) + ctrl2 |= SDHCI_CMD23_ENABLE; + else + ctrl2 &= ~SDHCI_CMD23_ENABLE; + sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); + + return; + } + + /* + * If we are sending CMD23, CMD12 never gets sent + * on successful completion (so no Auto-CMD12). + */ + if (use_cmd12) + *mode |= SDHCI_TRNS_AUTO_CMD12; + else if (use_cmd23) + *mode |= SDHCI_TRNS_AUTO_CMD23; +} + static void sdhci_set_transfer_mode(struct sdhci_host *host, struct mmc_command *cmd) { @@ -1048,17 +1169,9 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, if (mmc_op_multi(cmd->opcode) || data->blocks > 1) { mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI; - /* - * If we are sending CMD23, CMD12 never gets sent - * on successful completion (so no Auto-CMD12). - */ - if (sdhci_auto_cmd12(host, cmd->mrq) && - (cmd->opcode != SD_IO_RW_EXTENDED)) - mode |= SDHCI_TRNS_AUTO_CMD12; - else if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { - mode |= SDHCI_TRNS_AUTO_CMD23; + sdhci_auto_cmd_select(host, cmd, &mode); + if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2); - } } if (data->flags & MMC_DATA_READ) @@ -1630,7 +1743,7 @@ EXPORT_SYMBOL_GPL(sdhci_set_power); * * \*****************************************************************************/ -static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) +void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host; int present; @@ -1669,6 +1782,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } +EXPORT_SYMBOL_GPL(sdhci_request); void sdhci_set_bus_width(struct sdhci_host *host, int width) { @@ -2219,7 +2333,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) } EXPORT_SYMBOL_GPL(sdhci_send_tuning); -static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) { int i; @@ -2236,13 +2350,13 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", mmc_hostname(host->mmc)); sdhci_abort_tuning(host, opcode); - return; + return -ETIMEDOUT; } ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { if (ctrl & SDHCI_CTRL_TUNED_CLK) - return; /* Success! */ + return 0; /* Success! */ break; } @@ -2254,6 +2368,7 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", mmc_hostname(host->mmc)); sdhci_reset_tuning(host); + return -EAGAIN; } int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) @@ -2315,7 +2430,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_start_tuning(host); - __sdhci_execute_tuning(host, opcode); + host->tuning_err = __sdhci_execute_tuning(host, opcode); sdhci_end_tuning(host); out: @@ -2802,7 +2917,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) * some controllers are faulty, don't trust them. */ if (intmask & SDHCI_INT_DMA_END) { - u32 dmastart, dmanow; + dma_addr_t dmastart, dmanow; dmastart = sdhci_sdma_address(host); dmanow = dmastart + host->data->bytes_xfered; @@ -2810,12 +2925,12 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) * Force update to the next DMA block boundary. */ dmanow = (dmanow & - ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + + ~((dma_addr_t)SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + SDHCI_DEFAULT_BOUNDARY_SIZE; host->data->bytes_xfered = dmanow - dmastart; - DBG("DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x\n", - dmastart, host->data->bytes_xfered, dmanow); - sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); + DBG("DMA base %pad, transferred 0x%06x bytes, next %pad\n", + &dmastart, host->data->bytes_xfered, &dmanow); + sdhci_set_sdma_addr(host, dmanow); } if (intmask & SDHCI_INT_DATA_END) { @@ -3322,6 +3437,13 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG; + /* + * The DMA table descriptor count is calculated as the maximum + * number of segments times 2, to allow for an alignment + * descriptor for each segment, plus 1 for a nop end descriptor. + */ + host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1; + return host; } @@ -3376,6 +3498,9 @@ void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1) sdhci_do_reset(host, SDHCI_RESET_ALL); + if (host->v4_mode) + sdhci_do_enable_v4_mode(host); + of_property_read_u64(mmc_dev(host->mmc)->of_node, "sdhci-caps-mask", &dt_caps_mask); of_property_read_u64(mmc_dev(host->mmc)->of_node, @@ -3470,6 +3595,19 @@ static int sdhci_allocate_bounce_buffer(struct sdhci_host *host) return 0; } +static inline bool sdhci_can_64bit_dma(struct sdhci_host *host) +{ + /* + * According to SD Host Controller spec v4.10, bit[27] added from + * version 4.10 in Capabilities Register is used as 64-bit System + * Address support for V4 mode. + */ + if (host->version >= SDHCI_SPEC_410 && host->v4_mode) + return host->caps & SDHCI_CAN_64BIT_V4; + + return host->caps & SDHCI_CAN_64BIT; +} + int sdhci_setup_host(struct sdhci_host *host) { struct mmc_host *mmc; @@ -3506,7 +3644,7 @@ int sdhci_setup_host(struct sdhci_host *host) override_timeout_clk = host->timeout_clk; - if (host->version > SDHCI_SPEC_300) { + if (host->version > SDHCI_SPEC_420) { pr_err("%s: Unknown controller version (%d). You may experience problems.\n", mmc_hostname(mmc), host->version); } @@ -3541,7 +3679,7 @@ int sdhci_setup_host(struct sdhci_host *host) * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to * implement. */ - if (host->caps & SDHCI_CAN_64BIT) + if (sdhci_can_64bit_dma(host)) host->flags |= SDHCI_USE_64_BIT_DMA; if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { @@ -3559,32 +3697,30 @@ int sdhci_setup_host(struct sdhci_host *host) } } - /* SDMA does not support 64-bit DMA */ - if (host->flags & SDHCI_USE_64_BIT_DMA) + /* SDMA does not support 64-bit DMA if v4 mode not set */ + if ((host->flags & SDHCI_USE_64_BIT_DMA) && !host->v4_mode) host->flags &= ~SDHCI_USE_SDMA; if (host->flags & SDHCI_USE_ADMA) { dma_addr_t dma; void *buf; - /* - * The DMA descriptor table size is calculated as the maximum - * number of segments times 2, to allow for an alignment - * descriptor for each segment, plus 1 for a nop end descriptor, - * all multipled by the descriptor size. - */ if (host->flags & SDHCI_USE_64_BIT_DMA) { - host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * - SDHCI_ADMA2_64_DESC_SZ; - host->desc_sz = SDHCI_ADMA2_64_DESC_SZ; + host->adma_table_sz = host->adma_table_cnt * + SDHCI_ADMA2_64_DESC_SZ(host); + host->desc_sz = SDHCI_ADMA2_64_DESC_SZ(host); } else { - host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * + host->adma_table_sz = host->adma_table_cnt * SDHCI_ADMA2_32_DESC_SZ; host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; } host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN; - buf = dma_alloc_coherent(mmc_dev(mmc), host->align_buffer_sz + + /* + * Use zalloc to zero the reserved high 32-bits of 128-bit + * descriptors so that they never need to be written. + */ + buf = dma_zalloc_coherent(mmc_dev(mmc), host->align_buffer_sz + host->adma_table_sz, &dma, GFP_KERNEL); if (!buf) { pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", @@ -3708,10 +3844,13 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) host->flags |= SDHCI_AUTO_CMD12; - /* Auto-CMD23 stuff only works in ADMA or PIO. */ + /* + * For v3 mode, Auto-CMD23 stuff only works in ADMA or PIO. + * For v4 mode, SDMA may use Auto-CMD23 as well. + */ if ((host->version >= SDHCI_SPEC_300) && ((host->flags & SDHCI_USE_ADMA) || - !(host->flags & SDHCI_USE_SDMA)) && + !(host->flags & SDHCI_USE_SDMA) || host->v4_mode) && !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) { host->flags |= SDHCI_AUTO_CMD23; DBG("Auto-CMD23 available\n"); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index f0bd36ce3817..b001cf4d3d7e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -28,6 +28,7 @@ #define SDHCI_DMA_ADDRESS 0x00 #define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS +#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS #define SDHCI_BLOCK_SIZE 0x04 #define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) @@ -41,6 +42,7 @@ #define SDHCI_TRNS_BLK_CNT_EN 0x02 #define SDHCI_TRNS_AUTO_CMD12 0x04 #define SDHCI_TRNS_AUTO_CMD23 0x08 +#define SDHCI_TRNS_AUTO_SEL 0x0C #define SDHCI_TRNS_READ 0x10 #define SDHCI_TRNS_MULTI 0x20 @@ -184,6 +186,9 @@ #define SDHCI_CTRL_DRV_TYPE_D 0x0030 #define SDHCI_CTRL_EXEC_TUNING 0x0040 #define SDHCI_CTRL_TUNED_CLK 0x0080 +#define SDHCI_CMD23_ENABLE 0x0800 +#define SDHCI_CTRL_V4_MODE 0x1000 +#define SDHCI_CTRL_64BIT_ADDR 0x2000 #define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 #define SDHCI_CAPABILITIES 0x40 @@ -204,6 +209,7 @@ #define SDHCI_CAN_VDD_330 0x01000000 #define SDHCI_CAN_VDD_300 0x02000000 #define SDHCI_CAN_VDD_180 0x04000000 +#define SDHCI_CAN_64BIT_V4 0x08000000 #define SDHCI_CAN_64BIT 0x10000000 #define SDHCI_SUPPORT_SDR50 0x00000001 @@ -270,6 +276,9 @@ #define SDHCI_SPEC_100 0 #define SDHCI_SPEC_200 1 #define SDHCI_SPEC_300 2 +#define SDHCI_SPEC_400 3 +#define SDHCI_SPEC_410 4 +#define SDHCI_SPEC_420 5 /* * End of controller registers. @@ -305,8 +314,14 @@ struct sdhci_adma2_32_desc { */ #define SDHCI_ADMA2_DESC_ALIGN 8 -/* ADMA2 64-bit DMA descriptor size */ -#define SDHCI_ADMA2_64_DESC_SZ 12 +/* + * ADMA2 64-bit DMA descriptor size + * According to SD Host Controller spec v4.10, there are two kinds of + * descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit + * Descriptor, if Host Version 4 Enable is set in the Host Control 2 + * register, 128-bit Descriptor will be selected. + */ +#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12) /* * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte @@ -450,6 +465,13 @@ struct sdhci_host { * obtainable timeout. */ #define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17) +/* + * 32-bit block count may not support eMMC where upper bits of CMD23 are used + * for other purposes. Consequently we support 16-bit block count by default. + * Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit + * block count. + */ +#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ @@ -501,6 +523,7 @@ struct sdhci_host { bool preset_enabled; /* Preset is enabled */ bool pending_reset; /* Cmd/data reset is pending */ bool irq_wake_enabled; /* IRQ wakeup is enabled */ + bool v4_mode; /* Host Version 4 Enable */ struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */ struct mmc_command *cmd; /* Current command */ @@ -554,6 +577,7 @@ struct sdhci_host { unsigned int tuning_count; /* Timer count for re-tuning */ unsigned int tuning_mode; /* Re-tuning mode supported by host */ + unsigned int tuning_err; /* Error code for re-tuning */ #define SDHCI_TUNING_MODE_1 0 #define SDHCI_TUNING_MODE_2 1 #define SDHCI_TUNING_MODE_3 2 @@ -563,6 +587,9 @@ struct sdhci_host { /* Host SDMA buffer boundary. */ u32 sdma_boundary; + /* Host ADMA table count */ + u32 adma_table_cnt; + u64 data_timeout; unsigned long private[0] ____cacheline_aligned; @@ -603,6 +630,8 @@ struct sdhci_ops { void (*adma_workaround)(struct sdhci_host *host, u32 intmask); void (*card_event)(struct sdhci_host *host); void (*voltage_switch)(struct sdhci_host *host); + void (*adma_write_desc)(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS @@ -725,6 +754,7 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd); void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, unsigned short vdd); +void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); void sdhci_set_bus_width(struct sdhci_host *host, int width); void sdhci_reset(struct sdhci_host *host, u8 mask); void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); @@ -733,6 +763,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios); void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable); +void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd); #ifdef CONFIG_PM int sdhci_suspend_host(struct sdhci_host *host); @@ -747,6 +779,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, int *data_error); void sdhci_dumpregs(struct sdhci_host *host); +void sdhci_enable_v4_mode(struct sdhci_host *host); void sdhci_start_tuning(struct sdhci_host *host); void sdhci_end_tuning(struct sdhci_host *host); diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 4c2a1f8ddbf3..81bd9afb0980 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * MMCIF eMMC driver. * * Copyright (C) 2010 Renesas Solutions Corp. * Yusuke Goda <yusuke.goda.sx@renesas.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. */ /* @@ -1573,6 +1570,6 @@ static struct platform_driver sh_mmcif_driver = { module_platform_driver(sh_mmcif_driver); MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>"); diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 568349e1fbc2..279e326e397e 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -258,11 +258,16 @@ struct sunxi_mmc_cfg { /* Does DATA0 needs to be masked while the clock is updated */ bool mask_data0; - /* hardware only supports new timing mode */ + /* + * hardware only supports new timing mode, either due to lack of + * a mode switch in the clock controller, or the mmc controller + * is permanently configured in the new timing mode, without the + * NTSR mode switch. + */ bool needs_new_timings; - /* hardware can switch between old and new timing modes */ - bool has_timings_switch; + /* clock hardware can switch between old and new timing modes */ + bool ccu_has_timings_switch; }; struct sunxi_mmc_host { @@ -787,7 +792,7 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, clock <<= 1; } - if (host->use_new_timings && host->cfg->has_timings_switch) { + if (host->use_new_timings && host->cfg->ccu_has_timings_switch) { ret = sunxi_ccu_set_mmc_timing_mode(host->clk_mmc, true); if (ret) { dev_err(mmc_dev(mmc), @@ -822,6 +827,12 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, /* update card clock rate to account for internal divider */ rate /= div; + /* + * Configure the controller to use the new timing mode if needed. + * On controllers that only support the new timing mode, such as + * the eMMC controller on the A64, this register does not exist, + * and any writes to it are ignored. + */ if (host->use_new_timings) { /* Don't touch the delay bits */ rval = mmc_readl(host, REG_SD_NTSR); @@ -1145,7 +1156,7 @@ static const struct sunxi_mmc_cfg sun8i_a83t_emmc_cfg = { .idma_des_size_bits = 16, .clk_delays = sunxi_mmc_clk_delays, .can_calibrate = false, - .has_timings_switch = true, + .ccu_has_timings_switch = true, }; static const struct sunxi_mmc_cfg sun9i_a80_cfg = { @@ -1166,6 +1177,7 @@ static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = { .idma_des_size_bits = 13, .clk_delays = NULL, .can_calibrate = true, + .needs_new_timings = true, }; static const struct of_device_id sunxi_mmc_of_match[] = { @@ -1351,7 +1363,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) goto error_free_host; } - if (host->cfg->has_timings_switch) { + if (host->cfg->ccu_has_timings_switch) { /* * Supports both old and new timing modes. * Try setting the clk to new timing mode. diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index a3d8380ab480..b6644ce296b2 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -336,7 +336,8 @@ static unsigned int tifm_sd_op_flags(struct mmc_command *cmd) rc |= TIFM_MMCSD_RSP_R0; break; case MMC_RSP_R1B: - rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through + rc |= TIFM_MMCSD_RSP_BUSY; + /* fall-through */ case MMC_RSP_R1: rc |= TIFM_MMCSD_RSP_R1; break; diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 43a2ea5cff24..93e83ad25976 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the MMC / SD / SDIO cell found in: * @@ -7,12 +8,9 @@ * Copyright (C) 2017 Horms Solutions, Simon Horman * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ +#include <linux/delay.h> #include <linux/device.h> #include <linux/mfd/core.h> #include <linux/mfd/tmio.h> @@ -23,6 +21,76 @@ #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) +{ + /* FIXME - should we set stop clock reg here */ + sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); + usleep_range(10000, 11000); + sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); + usleep_range(10000, 11000); + + if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) { + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); + sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); + } +} + #ifdef CONFIG_PM_SLEEP static int tmio_mmc_suspend(struct device *dev) { @@ -90,8 +158,6 @@ static int tmio_mmc_probe(struct platform_device *pdev) goto cell_disable; } - pdata->flags |= TMIO_MMC_HAVE_HIGH_REG; - host = tmio_mmc_host_alloc(pdev, pdata); if (IS_ERR(host)) { ret = PTR_ERR(host); @@ -100,6 +166,8 @@ static int tmio_mmc_probe(struct platform_device *pdev) /* 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; diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 5d141f79e175..1e317027bf53 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver for the MMC / SD / SDIO cell found in: * @@ -8,11 +9,6 @@ * Copyright (C) 2016-17 Horms Solutions, Simon Horman * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #ifndef TMIO_MMC_H @@ -47,9 +43,6 @@ #define CTL_RESET_SD 0xe0 #define CTL_VERSION 0xe2 #define CTL_SDIF_MODE 0xe6 -#define CTL_SDIO_REGS 0x100 -#define CTL_CLK_AND_WAIT_CTL 0x138 -#define CTL_RESET_SDIO 0x1e0 /* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */ #define TMIO_STOP_STP BIT(0) @@ -133,7 +126,6 @@ struct tmio_mmc_host { /* Callbacks for clock / power control */ void (*set_pwr)(struct platform_device *host, int state); - void (*set_clk_div)(struct platform_device *host, int state); /* pio related stuff */ struct scatterlist *sg_ptr; @@ -146,7 +138,7 @@ struct tmio_mmc_host { struct tmio_mmc_data *pdata; /* DMA support */ - bool force_pio; + bool dma_on; struct dma_chan *chan_rx; struct dma_chan *chan_tx; struct tasklet_struct dma_issue; @@ -170,14 +162,14 @@ struct tmio_mmc_host { /* Mandatory callback */ int (*clk_enable)(struct tmio_mmc_host *host); + void (*set_clock)(struct tmio_mmc_host *host, unsigned int clock); /* Optional callbacks */ - unsigned int (*clk_update)(struct tmio_mmc_host *host, - unsigned int new_clock); void (*clk_disable)(struct tmio_mmc_host *host); int (*multi_io_quirk)(struct mmc_card *card, unsigned int direction, int blk_size); int (*write16_hook)(struct tmio_mmc_host *host, int addr); + void (*reset)(struct tmio_mmc_host *host); void (*hw_reset)(struct tmio_mmc_host *host); void (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap); bool (*check_scc_error)(struct tmio_mmc_host *host); diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 261b4d62d2b1..8d64f6196f33 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the MMC / SD / SDIO IP found in: * @@ -10,10 +11,6 @@ * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This driver draws mainly on scattered spec sheets, Reverse engineering * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit * support). (Further 4 bit support from a later datasheet). @@ -160,100 +157,18 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) } } -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)); - - /* HW engineers overrode docs: no sleep needed on R-Car2+ */ - if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) - usleep_range(10000, 11000); - - if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { - 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) -{ - if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { - 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)); - - /* HW engineers overrode docs: no sleep needed on R-Car2+ */ - if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) - usleep_range(10000, 11000); -} - -static void tmio_mmc_set_clock(struct tmio_mmc_host *host, - unsigned int new_clock) -{ - u32 clk = 0, clock; - - if (new_clock == 0) { - tmio_mmc_clk_stop(host); - return; - } - /* - * Both HS400 and HS200/SD104 set 200MHz, but some devices need to - * set 400MHz to distinguish the CPG settings in HS400. - */ - if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && - host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400 && - new_clock == 200000000) - new_clock = 400000000; - - if (host->clk_update) - clock = host->clk_update(host, new_clock) / 512; - else - clock = host->mmc->f_min; - - for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1) - clock <<= 1; - - /* 1/1 clock is option */ - if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && - ((clk >> 22) & 0x1)) { - if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400)) - clk |= 0xff; - else - clk &= ~0xff; - } - - if (host->set_clk_div) - host->set_clk_div(host->pdev, (clk >> 22) & 1); - - 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); - if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) - usleep_range(10000, 11000); - - tmio_mmc_clk_start(host); -} - static void tmio_mmc_reset(struct tmio_mmc_host *host) { /* FIXME - should we set stop clock reg here */ sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); - if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); usleep_range(10000, 11000); sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); - if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); usleep_range(10000, 11000); if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) { sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); } - } static void tmio_mmc_reset_work(struct work_struct *work) @@ -294,7 +209,7 @@ static void tmio_mmc_reset_work(struct work_struct *work) spin_unlock_irqrestore(&host->lock, flags); - tmio_mmc_reset(host); + host->reset(host); /* Ready for new calls */ host->mrq = NULL; @@ -446,7 +361,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) unsigned int count; unsigned long flags; - if ((host->chan_tx || host->chan_rx) && !host->force_pio) { + if (host->dma_on) { pr_err("PIO IRQ in DMA mode!\n"); return; } else if (!data) { @@ -518,7 +433,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) */ if (data->flags & MMC_DATA_READ) { - if (host->chan_rx && !host->force_pio) + if (host->dma_on) tmio_mmc_check_bounce_buffer(host); dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", host->mrq); @@ -555,7 +470,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat) if (stat & TMIO_STAT_CRCFAIL || stat & TMIO_STAT_STOPBIT_ERR || stat & TMIO_STAT_TXUNDERRUN) data->error = -EILSEQ; - if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) { + if (host->dma_on && (data->flags & MMC_DATA_WRITE)) { u32 status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS); bool done = false; @@ -579,7 +494,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat) tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); tmio_mmc_dataend_dma(host); } - } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) { + } else if (host->dma_on && (data->flags & MMC_DATA_READ)) { tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); tmio_mmc_dataend_dma(host); } else { @@ -632,7 +547,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat) */ if (host->data && (!cmd->error || cmd->error == -EILSEQ)) { if (host->data->flags & MMC_DATA_READ) { - if (host->force_pio || !host->chan_rx) { + if (!host->dma_on) { tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP); } else { tmio_mmc_disable_mmc_irqs(host, @@ -640,7 +555,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat) tasklet_schedule(&host->dma_issue); } } else { - if (host->force_pio || !host->chan_tx) { + if (!host->dma_on) { tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP); } else { tmio_mmc_disable_mmc_irqs(host, @@ -770,7 +685,7 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host, tmio_mmc_init_sg(host, data); host->data = data; - host->force_pio = false; + host->dma_on = false; /* Set transfer length / blocksize */ sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); @@ -919,8 +834,8 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) if (mrq->cmd->error || (mrq->data && mrq->data->error)) tmio_mmc_abort_dma(host); - if (host->check_scc_error) - host->check_scc_error(host); + if (host->check_scc_error && host->check_scc_error(host)) + mrq->cmd->error = -EILSEQ; /* If SET_BLOCK_COUNT, continue with main command */ if (host->mrq && !mrq->cmd->error) { @@ -1043,15 +958,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_OFF: tmio_mmc_power_off(host); - tmio_mmc_clk_stop(host); + host->set_clock(host, 0); break; case MMC_POWER_UP: tmio_mmc_power_on(host, ios->vdd); - tmio_mmc_set_clock(host, ios->clock); + host->set_clock(host, ios->clock); tmio_mmc_set_bus_width(host, ios->bus_width); break; case MMC_POWER_ON: - tmio_mmc_set_clock(host, ios->clock); + host->set_clock(host, ios->clock); tmio_mmc_set_bus_width(host, ios->bus_width); break; } @@ -1237,7 +1152,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) int ret; /* - * Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from + * Check the sanity of mmc->f_min to prevent host->set_clock() from * looping forever... */ if (mmc->f_min == 0) @@ -1247,7 +1162,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) _host->write16_hook = NULL; _host->set_pwr = pdata->set_pwr; - _host->set_clk_div = pdata->set_clk_div; ret = tmio_mmc_init_ocr(_host); if (ret < 0) @@ -1290,6 +1204,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) mmc->caps & MMC_CAP_NEEDS_POLL || !mmc_card_is_removable(mmc)); + if (!_host->reset) + _host->reset = tmio_mmc_reset; + /* * On Gen2+, eMMC with NONREMOVABLE currently fails because native * hotplug gets disabled. It seems RuntimePM related yet we need further @@ -1310,8 +1227,8 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) if (pdata->flags & TMIO_MMC_SDIO_IRQ) _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; - tmio_mmc_clk_stop(_host); - tmio_mmc_reset(_host); + _host->set_clock(_host, 0); + _host->reset(_host); _host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); @@ -1394,7 +1311,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev) tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); if (host->clk_cache) - tmio_mmc_clk_stop(host); + host->set_clock(host, 0); tmio_mmc_clk_disable(host); @@ -1411,11 +1328,11 @@ int tmio_mmc_host_runtime_resume(struct device *dev) { struct tmio_mmc_host *host = dev_get_drvdata(dev); - tmio_mmc_reset(host); + host->reset(host); tmio_mmc_clk_enable(host); if (host->clk_cache) - tmio_mmc_set_clock(host, host->clk_cache); + host->set_clock(host, host->clk_cache); if (host->native_hotplug) tmio_mmc_enable_mmc_irqs(host, diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c new file mode 100644 index 000000000000..91a2be41edf6 --- /dev/null +++ b/drivers/mmc/host/uniphier-sd.c @@ -0,0 +1,698 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2017-2018 Socionext Inc. +// Author: Masahiro Yamada <yamada.masahiro@socionext.com> + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/mfd/tmio.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include "tmio_mmc.h" + +#define UNIPHIER_SD_CLK_CTL_DIV1024 BIT(16) +#define UNIPHIER_SD_CLK_CTL_DIV1 BIT(10) +#define UNIPHIER_SD_CLKCTL_OFFEN BIT(9) // auto SDCLK stop +#define UNIPHIER_SD_CC_EXT_MODE 0x1b0 +#define UNIPHIER_SD_CC_EXT_MODE_DMA BIT(1) +#define UNIPHIER_SD_HOST_MODE 0x1c8 +#define UNIPHIER_SD_VOLT 0x1e4 +#define UNIPHIER_SD_VOLT_MASK GENMASK(1, 0) +#define UNIPHIER_SD_VOLT_OFF 0 +#define UNIPHIER_SD_VOLT_330 1 // 3.3V signal +#define UNIPHIER_SD_VOLT_180 2 // 1.8V signal +#define UNIPHIER_SD_DMA_MODE 0x410 +#define UNIPHIER_SD_DMA_MODE_DIR_MASK GENMASK(17, 16) +#define UNIPHIER_SD_DMA_MODE_DIR_TO_DEV 0 +#define UNIPHIER_SD_DMA_MODE_DIR_FROM_DEV 1 +#define UNIPHIER_SD_DMA_MODE_WIDTH_MASK GENMASK(5, 4) +#define UNIPHIER_SD_DMA_MODE_WIDTH_8 0 +#define UNIPHIER_SD_DMA_MODE_WIDTH_16 1 +#define UNIPHIER_SD_DMA_MODE_WIDTH_32 2 +#define UNIPHIER_SD_DMA_MODE_WIDTH_64 3 +#define UNIPHIER_SD_DMA_MODE_ADDR_INC BIT(0) // 1: inc, 0: fixed +#define UNIPHIER_SD_DMA_CTL 0x414 +#define UNIPHIER_SD_DMA_CTL_START BIT(0) // start DMA (auto cleared) +#define UNIPHIER_SD_DMA_RST 0x418 +#define UNIPHIER_SD_DMA_RST_CH1 BIT(9) +#define UNIPHIER_SD_DMA_RST_CH0 BIT(8) +#define UNIPHIER_SD_DMA_ADDR_L 0x440 +#define UNIPHIER_SD_DMA_ADDR_H 0x444 + +/* + * IP is extended to support various features: built-in DMA engine, + * 1/1024 divisor, etc. + */ +#define UNIPHIER_SD_CAP_EXTENDED_IP BIT(0) +/* RX channel of the built-in DMA controller is broken (Pro5) */ +#define UNIPHIER_SD_CAP_BROKEN_DMA_RX BIT(1) + +struct uniphier_sd_priv { + struct tmio_mmc_data tmio_data; + struct pinctrl *pinctrl; + struct pinctrl_state *pinstate_default; + struct pinctrl_state *pinstate_uhs; + struct clk *clk; + struct reset_control *rst; + struct reset_control *rst_br; + struct reset_control *rst_hw; + struct dma_chan *chan; + enum dma_data_direction dma_dir; + unsigned long clk_rate; + unsigned long caps; +}; + +static void *uniphier_sd_priv(struct tmio_mmc_host *host) +{ + return container_of(host->pdata, struct uniphier_sd_priv, tmio_data); +} + +static void uniphier_sd_dma_endisable(struct tmio_mmc_host *host, int enable) +{ + sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? DMA_ENABLE_DMASDRW : 0); +} + +/* external DMA engine */ +static void uniphier_sd_external_dma_issue(unsigned long arg) +{ + struct tmio_mmc_host *host = (void *)arg; + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + + uniphier_sd_dma_endisable(host, 1); + dma_async_issue_pending(priv->chan); +} + +static void uniphier_sd_external_dma_callback(void *param, + const struct dmaengine_result *result) +{ + struct tmio_mmc_host *host = param; + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + unsigned long flags; + + dma_unmap_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len, + priv->dma_dir); + + spin_lock_irqsave(&host->lock, flags); + + if (result->result == DMA_TRANS_NOERROR) { + /* + * When the external DMA engine is enabled, strangely enough, + * the DATAEND flag can be asserted even if the DMA engine has + * not been kicked yet. Enable the TMIO_STAT_DATAEND irq only + * after we make sure the DMA engine finishes the transfer, + * hence, in this callback. + */ + tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); + } else { + host->data->error = -ETIMEDOUT; + tmio_mmc_do_data_irq(host); + } + + spin_unlock_irqrestore(&host->lock, flags); +} + +static void uniphier_sd_external_dma_start(struct tmio_mmc_host *host, + struct mmc_data *data) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + enum dma_transfer_direction dma_tx_dir; + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + int sg_len; + + if (!priv->chan) + goto force_pio; + + if (data->flags & MMC_DATA_READ) { + priv->dma_dir = DMA_FROM_DEVICE; + dma_tx_dir = DMA_DEV_TO_MEM; + } else { + priv->dma_dir = DMA_TO_DEVICE; + dma_tx_dir = DMA_MEM_TO_DEV; + } + + sg_len = dma_map_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len, + priv->dma_dir); + if (sg_len == 0) + goto force_pio; + + desc = dmaengine_prep_slave_sg(priv->chan, host->sg_ptr, sg_len, + dma_tx_dir, DMA_CTRL_ACK); + if (!desc) + goto unmap_sg; + + desc->callback_result = uniphier_sd_external_dma_callback; + desc->callback_param = host; + + cookie = dmaengine_submit(desc); + if (cookie < 0) + goto unmap_sg; + + host->dma_on = true; + + return; + +unmap_sg: + dma_unmap_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len, + priv->dma_dir); +force_pio: + uniphier_sd_dma_endisable(host, 0); +} + +static void uniphier_sd_external_dma_enable(struct tmio_mmc_host *host, + bool enable) +{ +} + +static void uniphier_sd_external_dma_request(struct tmio_mmc_host *host, + struct tmio_mmc_data *pdata) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + struct dma_chan *chan; + + chan = dma_request_chan(mmc_dev(host->mmc), "rx-tx"); + if (IS_ERR(chan)) { + dev_warn(mmc_dev(host->mmc), + "failed to request DMA channel. falling back to PIO\n"); + return; /* just use PIO even for -EPROBE_DEFER */ + } + + /* this driver uses a single channel for both RX an TX */ + priv->chan = chan; + host->chan_rx = chan; + host->chan_tx = chan; + + tasklet_init(&host->dma_issue, uniphier_sd_external_dma_issue, + (unsigned long)host); +} + +static void uniphier_sd_external_dma_release(struct tmio_mmc_host *host) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + + if (priv->chan) + dma_release_channel(priv->chan); +} + +static void uniphier_sd_external_dma_abort(struct tmio_mmc_host *host) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + + uniphier_sd_dma_endisable(host, 0); + + if (priv->chan) + dmaengine_terminate_sync(priv->chan); +} + +static void uniphier_sd_external_dma_dataend(struct tmio_mmc_host *host) +{ + uniphier_sd_dma_endisable(host, 0); + + tmio_mmc_do_data_irq(host); +} + +static const struct tmio_mmc_dma_ops uniphier_sd_external_dma_ops = { + .start = uniphier_sd_external_dma_start, + .enable = uniphier_sd_external_dma_enable, + .request = uniphier_sd_external_dma_request, + .release = uniphier_sd_external_dma_release, + .abort = uniphier_sd_external_dma_abort, + .dataend = uniphier_sd_external_dma_dataend, +}; + +static void uniphier_sd_internal_dma_issue(unsigned long arg) +{ + struct tmio_mmc_host *host = (void *)arg; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); + spin_unlock_irqrestore(&host->lock, flags); + + uniphier_sd_dma_endisable(host, 1); + writel(UNIPHIER_SD_DMA_CTL_START, host->ctl + UNIPHIER_SD_DMA_CTL); +} + +static void uniphier_sd_internal_dma_start(struct tmio_mmc_host *host, + struct mmc_data *data) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + struct scatterlist *sg = host->sg_ptr; + dma_addr_t dma_addr; + unsigned int dma_mode_dir; + u32 dma_mode; + int sg_len; + + if ((data->flags & MMC_DATA_READ) && !host->chan_rx) + goto force_pio; + + if (WARN_ON(host->sg_len != 1)) + goto force_pio; + + if (!IS_ALIGNED(sg->offset, 8)) + goto force_pio; + + if (data->flags & MMC_DATA_READ) { + priv->dma_dir = DMA_FROM_DEVICE; + dma_mode_dir = UNIPHIER_SD_DMA_MODE_DIR_FROM_DEV; + } else { + priv->dma_dir = DMA_TO_DEVICE; + dma_mode_dir = UNIPHIER_SD_DMA_MODE_DIR_TO_DEV; + } + + sg_len = dma_map_sg(mmc_dev(host->mmc), sg, 1, priv->dma_dir); + if (sg_len == 0) + goto force_pio; + + dma_mode = FIELD_PREP(UNIPHIER_SD_DMA_MODE_DIR_MASK, dma_mode_dir); + dma_mode |= FIELD_PREP(UNIPHIER_SD_DMA_MODE_WIDTH_MASK, + UNIPHIER_SD_DMA_MODE_WIDTH_64); + dma_mode |= UNIPHIER_SD_DMA_MODE_ADDR_INC; + + writel(dma_mode, host->ctl + UNIPHIER_SD_DMA_MODE); + + dma_addr = sg_dma_address(data->sg); + writel(lower_32_bits(dma_addr), host->ctl + UNIPHIER_SD_DMA_ADDR_L); + writel(upper_32_bits(dma_addr), host->ctl + UNIPHIER_SD_DMA_ADDR_H); + + host->dma_on = true; + + return; +force_pio: + uniphier_sd_dma_endisable(host, 0); +} + +static void uniphier_sd_internal_dma_enable(struct tmio_mmc_host *host, + bool enable) +{ +} + +static void uniphier_sd_internal_dma_request(struct tmio_mmc_host *host, + struct tmio_mmc_data *pdata) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + + /* + * Due to a hardware bug, Pro5 cannot use DMA for RX. + * We can still use DMA for TX, but PIO for RX. + */ + if (!(priv->caps & UNIPHIER_SD_CAP_BROKEN_DMA_RX)) + host->chan_rx = (void *)0xdeadbeaf; + + host->chan_tx = (void *)0xdeadbeaf; + + tasklet_init(&host->dma_issue, uniphier_sd_internal_dma_issue, + (unsigned long)host); +} + +static void uniphier_sd_internal_dma_release(struct tmio_mmc_host *host) +{ + /* Each value is set to zero to assume "disabling" each DMA */ + host->chan_rx = NULL; + host->chan_tx = NULL; +} + +static void uniphier_sd_internal_dma_abort(struct tmio_mmc_host *host) +{ + u32 tmp; + + uniphier_sd_dma_endisable(host, 0); + + tmp = readl(host->ctl + UNIPHIER_SD_DMA_RST); + tmp &= ~(UNIPHIER_SD_DMA_RST_CH1 | UNIPHIER_SD_DMA_RST_CH0); + writel(tmp, host->ctl + UNIPHIER_SD_DMA_RST); + + tmp |= UNIPHIER_SD_DMA_RST_CH1 | UNIPHIER_SD_DMA_RST_CH0; + writel(tmp, host->ctl + UNIPHIER_SD_DMA_RST); +} + +static void uniphier_sd_internal_dma_dataend(struct tmio_mmc_host *host) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + + uniphier_sd_dma_endisable(host, 0); + dma_unmap_sg(mmc_dev(host->mmc), host->sg_ptr, 1, priv->dma_dir); + + tmio_mmc_do_data_irq(host); +} + +static const struct tmio_mmc_dma_ops uniphier_sd_internal_dma_ops = { + .start = uniphier_sd_internal_dma_start, + .enable = uniphier_sd_internal_dma_enable, + .request = uniphier_sd_internal_dma_request, + .release = uniphier_sd_internal_dma_release, + .abort = uniphier_sd_internal_dma_abort, + .dataend = uniphier_sd_internal_dma_dataend, +}; + +static int uniphier_sd_clk_enable(struct tmio_mmc_host *host) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + struct mmc_host *mmc = host->mmc; + int ret; + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + ret = clk_set_rate(priv->clk, ULONG_MAX); + if (ret) + goto disable_clk; + + priv->clk_rate = clk_get_rate(priv->clk); + + /* If max-frequency property is set, use it. */ + if (!mmc->f_max) + mmc->f_max = priv->clk_rate; + + /* + * 1/512 is the finest divisor in the original IP. Newer versions + * also supports 1/1024 divisor. (UniPhier-specific extension) + */ + if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP) + mmc->f_min = priv->clk_rate / 1024; + else + mmc->f_min = priv->clk_rate / 512; + + ret = reset_control_deassert(priv->rst); + if (ret) + goto disable_clk; + + ret = reset_control_deassert(priv->rst_br); + if (ret) + goto assert_rst; + + return 0; + +assert_rst: + reset_control_assert(priv->rst); +disable_clk: + clk_disable_unprepare(priv->clk); + + return ret; +} + +static void uniphier_sd_clk_disable(struct tmio_mmc_host *host) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + + reset_control_assert(priv->rst_br); + reset_control_assert(priv->rst); + clk_disable_unprepare(priv->clk); +} + +static void uniphier_sd_hw_reset(struct tmio_mmc_host *host) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + + reset_control_assert(priv->rst_hw); + /* For eMMC, minimum is 1us but give it 9us for good measure */ + udelay(9); + reset_control_deassert(priv->rst_hw); + /* For eMMC, minimum is 200us but give it 300us for good measure */ + usleep_range(300, 1000); +} + +static void uniphier_sd_set_clock(struct tmio_mmc_host *host, + unsigned int clock) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + unsigned long divisor; + u32 tmp; + + tmp = readl(host->ctl + (CTL_SD_CARD_CLK_CTL << 1)); + + /* stop the clock before changing its rate to avoid a glitch signal */ + tmp &= ~CLK_CTL_SCLKEN; + writel(tmp, host->ctl + (CTL_SD_CARD_CLK_CTL << 1)); + + if (clock == 0) + return; + + tmp &= ~UNIPHIER_SD_CLK_CTL_DIV1024; + tmp &= ~UNIPHIER_SD_CLK_CTL_DIV1; + tmp &= ~CLK_CTL_DIV_MASK; + + divisor = priv->clk_rate / clock; + + /* + * In the original IP, bit[7:0] represents the divisor. + * bit7 set: 1/512, ... bit0 set:1/4, all bits clear: 1/2 + * + * The IP does not define a way to achieve 1/1. For UniPhier variants, + * bit10 is used for 1/1. Newer versions of UniPhier variants use + * bit16 for 1/1024. + */ + if (divisor <= 1) + tmp |= UNIPHIER_SD_CLK_CTL_DIV1; + else if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP && divisor > 512) + tmp |= UNIPHIER_SD_CLK_CTL_DIV1024; + else + tmp |= roundup_pow_of_two(divisor) >> 2; + + writel(tmp, host->ctl + (CTL_SD_CARD_CLK_CTL << 1)); + + tmp |= CLK_CTL_SCLKEN; + writel(tmp, host->ctl + (CTL_SD_CARD_CLK_CTL << 1)); +} + +static void uniphier_sd_host_init(struct tmio_mmc_host *host) +{ + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + u32 val; + + /* + * Connected to 32bit AXI. + * This register holds settings for SoC-specific internal bus + * connection. What is worse, the register spec was changed, + * breaking the backward compatibility. Write an appropriate + * value depending on a flag associated with a compatible string. + */ + if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP) + val = 0x00000101; + else + val = 0x00000000; + + writel(val, host->ctl + UNIPHIER_SD_HOST_MODE); + + val = 0; + /* + * If supported, the controller can automatically + * enable/disable the clock line to the card. + */ + if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP) + val |= UNIPHIER_SD_CLKCTL_OFFEN; + + writel(val, host->ctl + (CTL_SD_CARD_CLK_CTL << 1)); +} + +static int uniphier_sd_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct uniphier_sd_priv *priv = uniphier_sd_priv(host); + struct pinctrl_state *pinstate; + u32 val, tmp; + + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + val = UNIPHIER_SD_VOLT_330; + pinstate = priv->pinstate_default; + break; + case MMC_SIGNAL_VOLTAGE_180: + val = UNIPHIER_SD_VOLT_180; + pinstate = priv->pinstate_uhs; + break; + default: + return -ENOTSUPP; + } + + tmp = readl(host->ctl + UNIPHIER_SD_VOLT); + tmp &= ~UNIPHIER_SD_VOLT_MASK; + tmp |= FIELD_PREP(UNIPHIER_SD_VOLT_MASK, val); + writel(tmp, host->ctl + UNIPHIER_SD_VOLT); + + pinctrl_select_state(priv->pinctrl, pinstate); + + return 0; +} + +static int uniphier_sd_uhs_init(struct tmio_mmc_host *host, + struct uniphier_sd_priv *priv) +{ + priv->pinctrl = devm_pinctrl_get(mmc_dev(host->mmc)); + if (IS_ERR(priv->pinctrl)) + return PTR_ERR(priv->pinctrl); + + priv->pinstate_default = pinctrl_lookup_state(priv->pinctrl, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(priv->pinstate_default)) + return PTR_ERR(priv->pinstate_default); + + priv->pinstate_uhs = pinctrl_lookup_state(priv->pinctrl, "uhs"); + if (IS_ERR(priv->pinstate_uhs)) + return PTR_ERR(priv->pinstate_uhs); + + host->ops.start_signal_voltage_switch = + uniphier_sd_start_signal_voltage_switch; + + return 0; +} + +static int uniphier_sd_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_sd_priv *priv; + struct tmio_mmc_data *tmio_data; + struct tmio_mmc_host *host; + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to get IRQ number"); + return irq; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->caps = (unsigned long)of_device_get_match_data(dev); + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); + } + + priv->rst = devm_reset_control_get_shared(dev, "host"); + if (IS_ERR(priv->rst)) { + dev_err(dev, "failed to get host reset\n"); + return PTR_ERR(priv->rst); + } + + /* old version has one more reset */ + if (!(priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP)) { + priv->rst_br = devm_reset_control_get_shared(dev, "bridge"); + if (IS_ERR(priv->rst_br)) { + dev_err(dev, "failed to get bridge reset\n"); + return PTR_ERR(priv->rst_br); + } + } + + tmio_data = &priv->tmio_data; + tmio_data->flags |= TMIO_MMC_32BIT_DATA_PORT; + + host = tmio_mmc_host_alloc(pdev, tmio_data); + if (IS_ERR(host)) + return PTR_ERR(host); + + if (host->mmc->caps & MMC_CAP_HW_RESET) { + priv->rst_hw = devm_reset_control_get_exclusive(dev, "hw"); + if (IS_ERR(priv->rst_hw)) { + dev_err(dev, "failed to get hw reset\n"); + ret = PTR_ERR(priv->rst_hw); + goto free_host; + } + host->hw_reset = uniphier_sd_hw_reset; + } + + if (host->mmc->caps & MMC_CAP_UHS) { + ret = uniphier_sd_uhs_init(host, priv); + if (ret) { + dev_warn(dev, + "failed to setup UHS (error %d). Disabling UHS.", + ret); + host->mmc->caps &= ~MMC_CAP_UHS; + } + } + + ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED, + dev_name(dev), host); + if (ret) + goto free_host; + + if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP) + host->dma_ops = &uniphier_sd_internal_dma_ops; + else + host->dma_ops = &uniphier_sd_external_dma_ops; + + host->bus_shift = 1; + host->clk_enable = uniphier_sd_clk_enable; + host->clk_disable = uniphier_sd_clk_disable; + host->set_clock = uniphier_sd_set_clock; + + ret = uniphier_sd_clk_enable(host); + if (ret) + goto free_host; + + uniphier_sd_host_init(host); + + tmio_data->ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34; + if (host->mmc->caps & MMC_CAP_UHS) + tmio_data->ocr_mask |= MMC_VDD_165_195; + + tmio_data->max_segs = 1; + tmio_data->max_blk_count = U16_MAX; + + ret = tmio_mmc_host_probe(host); + if (ret) + goto free_host; + + return 0; + +free_host: + tmio_mmc_host_free(host); + + return ret; +} + +static int uniphier_sd_remove(struct platform_device *pdev) +{ + struct tmio_mmc_host *host = platform_get_drvdata(pdev); + + tmio_mmc_host_remove(host); + uniphier_sd_clk_disable(host); + + return 0; +} + +static const struct of_device_id uniphier_sd_match[] = { + { + .compatible = "socionext,uniphier-sd-v2.91", + }, + { + .compatible = "socionext,uniphier-sd-v3.1", + .data = (void *)(UNIPHIER_SD_CAP_EXTENDED_IP | + UNIPHIER_SD_CAP_BROKEN_DMA_RX), + }, + { + .compatible = "socionext,uniphier-sd-v3.1.1", + .data = (void *)UNIPHIER_SD_CAP_EXTENDED_IP, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_sd_match); + +static struct platform_driver uniphier_sd_driver = { + .probe = uniphier_sd_probe, + .remove = uniphier_sd_remove, + .driver = { + .name = "uniphier-sd", + .of_match_table = uniphier_sd_match, + }, +}; +module_platform_driver(uniphier_sd_driver); + +MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); +MODULE_DESCRIPTION("UniPhier SD/eMMC host controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index cdfeb15b6f05..cd8b1b9d4d8a 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2013-2014 Renesas Electronics Europe Ltd. * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 270d3c9580c5..c4a1d04b8c80 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -90,7 +90,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, SPI_MEM_OP_ADDR(nor->addr_width, to, 1), SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(len, buf, 1)); - size_t remaining = len; int ret; /* get transfer protocols. */ @@ -101,22 +100,16 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) op.addr.nbytes = 0; - while (remaining) { - op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; - ret = spi_mem_adjust_op_size(flash->spimem, &op); - if (ret) - return ret; - - ret = spi_mem_exec_op(flash->spimem, &op); - if (ret) - return ret; + ret = spi_mem_adjust_op_size(flash->spimem, &op); + if (ret) + return ret; + op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes; - op.addr.val += op.data.nbytes; - remaining -= op.data.nbytes; - op.data.buf.out += op.data.nbytes; - } + ret = spi_mem_exec_op(flash->spimem, &op); + if (ret) + return ret; - return len; + return op.data.nbytes; } /* diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 9d9723693217..a20e85aa770e 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -14,6 +14,7 @@ */ #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> @@ -25,28 +26,24 @@ #include <linux/slab.h> #include <linux/types.h> -#define pr_devinit(fmt, args...) \ - ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) +#define win_mask(x) ((BIT(x)) - 1) #define DRIVER_NAME "gpio-addr-flash" -#define PFX DRIVER_NAME ": " /** * struct async_state - keep GPIO flash state * @mtd: MTD state for this mapping * @map: MTD map state for this flash - * @gpio_count: number of GPIOs used to address - * @gpio_addrs: array of GPIOs to twiddle + * @gpios: Struct containing the array of GPIO descriptors * @gpio_values: cached GPIO values - * @win_size: dedicated memory size (if no GPIOs) + * @win_order: dedicated memory size (if no GPIOs) */ struct async_state { struct mtd_info *mtd; struct map_info map; - size_t gpio_count; - unsigned *gpio_addrs; - int *gpio_values; - unsigned long win_size; + struct gpio_descs *gpios; + unsigned int gpio_values; + unsigned int win_order; }; #define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1) @@ -57,21 +54,25 @@ struct async_state { * * Rather than call the GPIO framework every time, cache the last-programmed * value. This speeds up sequential accesses (which are by far the most common - * type). We rely on the GPIO framework to treat non-zero value as high so - * that we don't have to normalize the bits. + * type). */ static void gf_set_gpios(struct async_state *state, unsigned long ofs) { - size_t i = 0; - int value; - ofs /= state->win_size; - do { - value = ofs & (1 << i); - if (state->gpio_values[i] != value) { - gpio_set_value(state->gpio_addrs[i], value); - state->gpio_values[i] = value; - } - } while (++i < state->gpio_count); + int i; + + ofs >>= state->win_order; + + if (ofs == state->gpio_values) + return; + + for (i = 0; i < state->gpios->ndescs; i++) { + if ((ofs & BIT(i)) == (state->gpio_values & BIT(i))) + continue; + + gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i))); + } + + state->gpio_values = ofs; } /** @@ -87,7 +88,7 @@ static map_word gf_read(struct map_info *map, unsigned long ofs) gf_set_gpios(state, ofs); - word = readw(map->virt + (ofs % state->win_size)); + word = readw(map->virt + (ofs & win_mask(state->win_order))); test.x[0] = word; return test; } @@ -109,14 +110,14 @@ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssi int this_len; while (len) { - if ((from % state->win_size) + len > state->win_size) - this_len = state->win_size - (from % state->win_size); - else - this_len = len; + this_len = from & win_mask(state->win_order); + this_len = BIT(state->win_order) - this_len; + this_len = min_t(int, len, this_len); gf_set_gpios(state, from); - memcpy_fromio(to, map->virt + (from % state->win_size), - this_len); + memcpy_fromio(to, + map->virt + (from & win_mask(state->win_order)), + this_len); len -= this_len; from += this_len; to += this_len; @@ -136,7 +137,7 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs) gf_set_gpios(state, ofs); d = d1.x[0]; - writew(d, map->virt + (ofs % state->win_size)); + writew(d, map->virt + (ofs & win_mask(state->win_order))); } /** @@ -156,13 +157,13 @@ static void gf_copy_to(struct map_info *map, unsigned long to, int this_len; while (len) { - if ((to % state->win_size) + len > state->win_size) - this_len = state->win_size - (to % state->win_size); - else - this_len = len; + this_len = to & win_mask(state->win_order); + this_len = BIT(state->win_order) - this_len; + this_len = min_t(int, len, this_len); gf_set_gpios(state, to); - memcpy_toio(map->virt + (to % state->win_size), from, len); + memcpy_toio(map->virt + (to & win_mask(state->win_order)), + from, len); len -= this_len; to += this_len; @@ -180,18 +181,22 @@ static const char * const part_probe_types[] = { * The platform resource layout expected looks something like: * struct mtd_partition partitions[] = { ... }; * struct physmap_flash_data flash_data = { ... }; - * unsigned flash_gpios[] = { GPIO_XX, GPIO_XX, ... }; + * static struct gpiod_lookup_table addr_flash_gpios = { + * .dev_id = "gpio-addr-flash.0", + * .table = { + * GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH), + * GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH), + * ); + * }; + * gpiod_add_lookup_table(&addr_flash_gpios); + * * struct resource flash_resource[] = { * { * .name = "cfi_probe", * .start = 0x20000000, * .end = 0x201fffff, * .flags = IORESOURCE_MEM, - * }, { - * .start = (unsigned long)flash_gpios, - * .end = ARRAY_SIZE(flash_gpios), - * .flags = IORESOURCE_IRQ, - * } + * }, * }; * struct platform_device flash_device = { * .name = "gpio-addr-flash", @@ -203,33 +208,25 @@ static const char * const part_probe_types[] = { */ static int gpio_flash_probe(struct platform_device *pdev) { - size_t i, arr_size; struct physmap_flash_data *pdata; struct resource *memory; - struct resource *gpios; struct async_state *state; pdata = dev_get_platdata(&pdev->dev); memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!memory || !gpios || !gpios->end) + if (!memory) return -EINVAL; - arr_size = sizeof(int) * gpios->end; - state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL); + state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; - /* - * We cast start/end to known types in the boards file, so cast - * away their pointer types here to the known types (gpios->xxx). - */ - state->gpio_count = gpios->end; - state->gpio_addrs = (void *)(unsigned long)gpios->start; - state->gpio_values = (void *)(state + 1); - state->win_size = resource_size(memory); - memset(state->gpio_values, 0xff, arr_size); + state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW); + if (IS_ERR(state->gpios)) + return PTR_ERR(state->gpios); + + state->win_order = get_bitmask_order(resource_size(memory)) - 1; state->map.name = DRIVER_NAME; state->map.read = gf_read; @@ -237,38 +234,21 @@ static int gpio_flash_probe(struct platform_device *pdev) state->map.write = gf_write; state->map.copy_to = gf_copy_to; state->map.bankwidth = pdata->width; - state->map.size = state->win_size * (1 << state->gpio_count); - state->map.virt = ioremap_nocache(memory->start, state->map.size); - if (!state->map.virt) - return -ENOMEM; + state->map.size = BIT(state->win_order + state->gpios->ndescs); + state->map.virt = devm_ioremap_resource(&pdev->dev, memory); + if (IS_ERR(state->map.virt)) + return PTR_ERR(state->map.virt); state->map.phys = NO_XIP; state->map.map_priv_1 = (unsigned long)state; platform_set_drvdata(pdev, state); - i = 0; - do { - if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) { - pr_devinit(KERN_ERR PFX "failed to request gpio %d\n", - state->gpio_addrs[i]); - while (i--) - gpio_free(state->gpio_addrs[i]); - kfree(state); - return -EBUSY; - } - gpio_direction_output(state->gpio_addrs[i], 0); - } while (++i < state->gpio_count); - - pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n", - state->map.bankwidth * 8); + dev_notice(&pdev->dev, "probing %d-bit flash bus\n", + state->map.bankwidth * 8); state->mtd = do_map_probe(memory->name, &state->map); - if (!state->mtd) { - for (i = 0; i < state->gpio_count; ++i) - gpio_free(state->gpio_addrs[i]); - kfree(state); + if (!state->mtd) return -ENXIO; - } state->mtd->dev.parent = &pdev->dev; mtd_device_parse_register(state->mtd, part_probe_types, NULL, @@ -280,13 +260,9 @@ static int gpio_flash_probe(struct platform_device *pdev) static int gpio_flash_remove(struct platform_device *pdev) { struct async_state *state = platform_get_drvdata(pdev); - size_t i = 0; - do { - gpio_free(state->gpio_addrs[i]); - } while (++i < state->gpio_count); + mtd_device_unregister(state->mtd); map_destroy(state->mtd); - kfree(state); return 0; } diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c index 4129535b8e46..ece605d78c21 100644 --- a/drivers/mtd/maps/physmap_of_core.c +++ b/drivers/mtd/maps/physmap_of_core.c @@ -31,7 +31,6 @@ struct of_flash_list { struct mtd_info *mtd; struct map_info map; - struct resource *res; }; struct of_flash { @@ -56,18 +55,10 @@ static int of_flash_remove(struct platform_device *dev) mtd_concat_destroy(info->cmtd); } - for (i = 0; i < info->list_size; i++) { + for (i = 0; i < info->list_size; i++) if (info->list[i].mtd) map_destroy(info->list[i].mtd); - if (info->list[i].map.virt) - iounmap(info->list[i].map.virt); - - if (info->list[i].res) { - release_resource(info->list[i].res); - kfree(info->list[i].res); - } - } return 0; } @@ -215,10 +206,11 @@ static int of_flash_probe(struct platform_device *dev) err = -EBUSY; res_size = resource_size(&res); - info->list[i].res = request_mem_region(res.start, res_size, - dev_name(&dev->dev)); - if (!info->list[i].res) + info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res); + if (IS_ERR(info->list[i].map.virt)) { + err = PTR_ERR(info->list[i].map.virt); goto err_out; + } err = -ENXIO; width = of_get_property(dp, "bank-width", NULL); @@ -246,15 +238,6 @@ static int of_flash_probe(struct platform_device *dev) if (err) goto err_out; - err = -ENOMEM; - info->list[i].map.virt = ioremap(info->list[i].map.phys, - info->list[i].map.size); - if (!info->list[i].map.virt) { - dev_err(&dev->dev, "Failed to ioremap() flash" - " region\n"); - goto err_out; - } - simple_map_init(&info->list[i].map); /* diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c index 830b1b7e702b..9df62ca721d5 100644 --- a/drivers/mtd/maps/physmap_of_gemini.c +++ b/drivers/mtd/maps/physmap_of_gemini.c @@ -44,11 +44,6 @@ #define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */ -static const struct of_device_id syscon_match[] = { - { .compatible = "cortina,gemini-syscon" }, - { }, -}; - int of_flash_probe_gemini(struct platform_device *pdev, struct device_node *np, struct map_info *map) diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 29c0bfd74e8a..b0d44f9214b0 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -27,6 +27,7 @@ #include <linux/mtd/blktrans.h> #include <linux/mtd/mtd.h> #include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/blkpg.h> #include <linux/spinlock.h> #include <linux/hdreg.h> @@ -45,6 +46,8 @@ static void blktrans_dev_release(struct kref *kref) dev->disk->private_data = NULL; blk_cleanup_queue(dev->rq); + blk_mq_free_tag_set(dev->tag_set); + kfree(dev->tag_set); put_disk(dev->disk); list_del(&dev->list); kfree(dev); @@ -134,28 +137,39 @@ int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev) } EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background); -static void mtd_blktrans_work(struct work_struct *work) +static struct request *mtd_next_request(struct mtd_blktrans_dev *dev) +{ + struct request *rq; + + rq = list_first_entry_or_null(&dev->rq_list, struct request, queuelist); + if (rq) { + list_del_init(&rq->queuelist); + blk_mq_start_request(rq); + return rq; + } + + return NULL; +} + +static void mtd_blktrans_work(struct mtd_blktrans_dev *dev) + __releases(&dev->queue_lock) + __acquires(&dev->queue_lock) { - struct mtd_blktrans_dev *dev = - container_of(work, struct mtd_blktrans_dev, work); struct mtd_blktrans_ops *tr = dev->tr; - struct request_queue *rq = dev->rq; struct request *req = NULL; int background_done = 0; - spin_lock_irq(rq->queue_lock); - while (1) { blk_status_t res; dev->bg_stop = false; - if (!req && !(req = blk_fetch_request(rq))) { + if (!req && !(req = mtd_next_request(dev))) { if (tr->background && !background_done) { - spin_unlock_irq(rq->queue_lock); + spin_unlock_irq(&dev->queue_lock); mutex_lock(&dev->lock); tr->background(dev); mutex_unlock(&dev->lock); - spin_lock_irq(rq->queue_lock); + spin_lock_irq(&dev->queue_lock); /* * Do background processing just once per idle * period. @@ -166,35 +180,39 @@ static void mtd_blktrans_work(struct work_struct *work) break; } - spin_unlock_irq(rq->queue_lock); + spin_unlock_irq(&dev->queue_lock); mutex_lock(&dev->lock); res = do_blktrans_request(dev->tr, dev, req); mutex_unlock(&dev->lock); - spin_lock_irq(rq->queue_lock); - - if (!__blk_end_request_cur(req, res)) + if (!blk_update_request(req, res, blk_rq_cur_bytes(req))) { + __blk_mq_end_request(req, res); req = NULL; + } background_done = 0; + spin_lock_irq(&dev->queue_lock); } - - spin_unlock_irq(rq->queue_lock); } -static void mtd_blktrans_request(struct request_queue *rq) +static blk_status_t mtd_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) { struct mtd_blktrans_dev *dev; - struct request *req = NULL; - dev = rq->queuedata; + dev = hctx->queue->queuedata; + if (!dev) { + blk_mq_start_request(bd->rq); + return BLK_STS_IOERR; + } + + spin_lock_irq(&dev->queue_lock); + list_add_tail(&bd->rq->queuelist, &dev->rq_list); + mtd_blktrans_work(dev); + spin_unlock_irq(&dev->queue_lock); - if (!dev) - while ((req = blk_fetch_request(rq)) != NULL) - __blk_end_request_all(req, BLK_STS_IOERR); - else - queue_work(dev->wq, &dev->work); + return BLK_STS_OK; } static int blktrans_open(struct block_device *bdev, fmode_t mode) @@ -329,6 +347,10 @@ static const struct block_device_operations mtd_block_ops = { .getgeo = blktrans_getgeo, }; +static const struct blk_mq_ops mtd_mq_ops = { + .queue_rq = mtd_queue_rq, +}; + int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) { struct mtd_blktrans_ops *tr = new->tr; @@ -416,11 +438,20 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) /* Create the request queue */ spin_lock_init(&new->queue_lock); - new->rq = blk_init_queue(mtd_blktrans_request, &new->queue_lock); + INIT_LIST_HEAD(&new->rq_list); - if (!new->rq) + new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL); + if (!new->tag_set) goto error3; + new->rq = blk_mq_init_sq_queue(new->tag_set, &mtd_mq_ops, 2, + BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING); + if (IS_ERR(new->rq)) { + ret = PTR_ERR(new->rq); + new->rq = NULL; + goto error4; + } + if (tr->flush) blk_queue_write_cache(new->rq, true, false); @@ -437,17 +468,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) gd->queue = new->rq; - /* Create processing workqueue */ - new->wq = alloc_workqueue("%s%d", 0, 0, - tr->name, new->mtd->index); - if (!new->wq) - goto error4; - INIT_WORK(&new->work, mtd_blktrans_work); - if (new->readonly) set_disk_ro(gd, 1); - device_add_disk(&new->mtd->dev, gd); + device_add_disk(&new->mtd->dev, gd, NULL); if (new->disk_attributes) { ret = sysfs_create_group(&disk_to_dev(gd)->kobj, @@ -456,7 +480,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) } return 0; error4: - blk_cleanup_queue(new->rq); + kfree(new->tag_set); error3: put_disk(new->disk); error2: @@ -481,15 +505,17 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) /* Stop new requests to arrive */ del_gendisk(old->disk); - /* Stop workqueue. This will perform any pending request. */ - destroy_workqueue(old->wq); - /* Kill current requests */ spin_lock_irqsave(&old->queue_lock, flags); old->rq->queuedata = NULL; - blk_start_queue(old->rq); spin_unlock_irqrestore(&old->queue_lock, flags); + /* freeze+quiesce queue to ensure all requests are flushed */ + blk_mq_freeze_queue(old->rq); + blk_mq_quiesce_queue(old->rq); + blk_mq_unquiesce_queue(old->rq); + blk_mq_unfreeze_queue(old->rq); + /* If the device is currently open, tell trans driver to close it, then put mtd device, and don't touch it again */ mutex_lock(&old->lock); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 5fc9a1bde4ac..c7efc31384d5 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -227,26 +227,6 @@ config MTD_NAND_DISKONCHIP_BBTWRITE load time (assuming you build diskonchip as a module) with the module parameter "inftl_bbt_write=1". -config MTD_NAND_DOCG4 - tristate "Support for DiskOnChip G4" - depends on HAS_IOMEM - select BCH - select BITREVERSE - help - Support for diskonchip G4 nand flash, found in various smartphones and - PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba - Portege G900, Asus P526, and O2 XDA Zinc. - - With this driver you will be able to use UBI and create a ubifs on the - device, so you may wish to consider enabling UBI and UBIFS as well. - - These devices ship with the Mys/Sandisk SAFTL formatting, for which - there is currently no mtd parser, so you may want to use command line - partitioning to segregate write-protected blocks. On the Treo680, the - first five erase blocks (256KiB each) are write-protected, followed - by the block containing the saftl partition table. This is probably - typical. - config MTD_NAND_SHARPSL tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" depends on ARCH_PXA || COMPILE_TEST diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index d5a5f9832b88..57159b349054 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o -obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o @@ -58,8 +57,11 @@ obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o -nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o +nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o +nand-objs += nand_onfi.o +nand-objs += nand_jedec.o nand-objs += nand_amd.o +nand-objs += nand_esmt.o nand-objs += nand_hynix.o nand-objs += nand_macronix.o nand-objs += nand_micron.o diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 37a3cc21c7bc..5ba180a291eb 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -20,23 +20,33 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/mtd/mtd.h> #include <linux/mtd/rawnand.h> #include <linux/mtd/partitions.h> -#include <linux/gpio.h> #include <linux/platform_data/gpio-omap.h> #include <asm/io.h> #include <asm/sizes.h> -#include <mach/board-ams-delta.h> - #include <mach/hardware.h> /* * MTD structure for E3 (Delta) */ -static struct mtd_info *ams_delta_mtd = NULL; + +struct ams_delta_nand { + struct nand_chip nand_chip; + struct gpio_desc *gpiod_rdy; + struct gpio_desc *gpiod_nce; + struct gpio_desc *gpiod_nre; + struct gpio_desc *gpiod_nwp; + struct gpio_desc *gpiod_nwe; + struct gpio_desc *gpiod_ale; + struct gpio_desc *gpiod_cle; + void __iomem *io_base; + bool data_in; +}; /* * Define partitions for flash devices @@ -63,48 +73,64 @@ static const struct mtd_partition partition_info[] = { .size = 3 * SZ_256K }, }; -static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) +static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte) { - struct nand_chip *this = mtd_to_nand(mtd); - void __iomem *io_base = (void __iomem *)nand_get_controller_data(this); - - writew(0, io_base + OMAP_MPUIO_IO_CNTL); - writew(byte, this->IO_ADDR_W); - gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0); + writew(byte, priv->nand_chip.legacy.IO_ADDR_W); + gpiod_set_value(priv->gpiod_nwe, 0); ndelay(40); - gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1); + gpiod_set_value(priv->gpiod_nwe, 1); } -static u_char ams_delta_read_byte(struct mtd_info *mtd) +static u_char ams_delta_io_read(struct ams_delta_nand *priv) { u_char res; - struct nand_chip *this = mtd_to_nand(mtd); - void __iomem *io_base = (void __iomem *)nand_get_controller_data(this); - gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0); + gpiod_set_value(priv->gpiod_nre, 0); ndelay(40); - writew(~0, io_base + OMAP_MPUIO_IO_CNTL); - res = readw(this->IO_ADDR_R); - gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1); + res = readw(priv->nand_chip.legacy.IO_ADDR_R); + gpiod_set_value(priv->gpiod_nre, 1); return res; } -static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf, +static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in) +{ + writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL); + priv->data_in = in; +} + +static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf, int len) { + struct ams_delta_nand *priv = nand_get_controller_data(this); int i; - for (i=0; i<len; i++) - ams_delta_write_byte(mtd, buf[i]); + if (priv->data_in) + ams_delta_dir_input(priv, false); + + for (i = 0; i < len; i++) + ams_delta_io_write(priv, buf[i]); } -static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len) { + struct ams_delta_nand *priv = nand_get_controller_data(this); int i; - for (i=0; i<len; i++) - buf[i] = ams_delta_read_byte(mtd); + if (!priv->data_in) + ams_delta_dir_input(priv, true); + + for (i = 0; i < len; i++) + buf[i] = ams_delta_io_read(priv); +} + +static u_char ams_delta_read_byte(struct nand_chip *this) +{ + u_char res; + + ams_delta_read_buf(this, &res, 1); + + return res; } /* @@ -115,67 +141,40 @@ static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len) * NAND_CLE: bit 1 -> bit 7 * NAND_ALE: bit 2 -> bit 6 */ -static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd, +static void ams_delta_hwcontrol(struct nand_chip *this, int cmd, unsigned int ctrl) { + struct ams_delta_nand *priv = nand_get_controller_data(this); if (ctrl & NAND_CTRL_CHANGE) { - gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE, - (ctrl & NAND_NCE) == 0); - gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE, - (ctrl & NAND_CLE) != 0); - gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE, - (ctrl & NAND_ALE) != 0); + gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE)); + gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE)); + gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE)); } - if (cmd != NAND_CMD_NONE) - ams_delta_write_byte(mtd, cmd); + if (cmd != NAND_CMD_NONE) { + u_char byte = cmd; + + ams_delta_write_buf(this, &byte, 1); + } } -static int ams_delta_nand_ready(struct mtd_info *mtd) +static int ams_delta_nand_ready(struct nand_chip *this) { - return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB); + struct ams_delta_nand *priv = nand_get_controller_data(this); + + return gpiod_get_value(priv->gpiod_rdy); } -static const struct gpio _mandatory_gpio[] = { - { - .gpio = AMS_DELTA_GPIO_PIN_NAND_NCE, - .flags = GPIOF_OUT_INIT_HIGH, - .label = "nand_nce", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_NAND_NRE, - .flags = GPIOF_OUT_INIT_HIGH, - .label = "nand_nre", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_NAND_NWP, - .flags = GPIOF_OUT_INIT_HIGH, - .label = "nand_nwp", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_NAND_NWE, - .flags = GPIOF_OUT_INIT_HIGH, - .label = "nand_nwe", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_NAND_ALE, - .flags = GPIOF_OUT_INIT_LOW, - .label = "nand_ale", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_NAND_CLE, - .flags = GPIOF_OUT_INIT_LOW, - .label = "nand_cle", - }, -}; /* * Main initialization routine */ static int ams_delta_init(struct platform_device *pdev) { + struct ams_delta_nand *priv; struct nand_chip *this; + struct mtd_info *mtd; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); void __iomem *io_base; int err = 0; @@ -184,15 +183,16 @@ static int ams_delta_init(struct platform_device *pdev) return -ENXIO; /* Allocate memory for MTD device structure and private data */ - this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); - if (!this) { + priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand), + GFP_KERNEL); + if (!priv) { pr_warn("Unable to allocate E3 NAND MTD device structure.\n"); - err = -ENOMEM; - goto out; + return -ENOMEM; } + this = &priv->nand_chip; - ams_delta_mtd = nand_to_mtd(this); - ams_delta_mtd->owner = THIS_MODULE; + mtd = nand_to_mtd(this); + mtd->dev.parent = &pdev->dev; /* * Don't try to request the memory region from here, @@ -207,51 +207,93 @@ static int ams_delta_init(struct platform_device *pdev) goto out_free; } - nand_set_controller_data(this, (void *)io_base); + priv->io_base = io_base; + nand_set_controller_data(this, priv); /* Set address of NAND IO lines */ - this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; - this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; - this->read_byte = ams_delta_read_byte; - this->write_buf = ams_delta_write_buf; - this->read_buf = ams_delta_read_buf; - this->cmd_ctrl = ams_delta_hwcontrol; - if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) { - this->dev_ready = ams_delta_nand_ready; - } else { - this->dev_ready = NULL; - pr_notice("Couldn't request gpio for Delta NAND ready.\n"); + this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; + this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; + this->legacy.read_byte = ams_delta_read_byte; + this->legacy.write_buf = ams_delta_write_buf; + this->legacy.read_buf = ams_delta_read_buf; + this->legacy.cmd_ctrl = ams_delta_hwcontrol; + + priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN); + if (IS_ERR(priv->gpiod_rdy)) { + err = PTR_ERR(priv->gpiod_rdy); + dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err); + goto out_mtd; } + + if (priv->gpiod_rdy) + this->legacy.dev_ready = ams_delta_nand_ready; + /* 25 us command delay time */ - this->chip_delay = 30; + this->legacy.chip_delay = 30; this->ecc.mode = NAND_ECC_SOFT; this->ecc.algo = NAND_ECC_HAMMING; - platform_set_drvdata(pdev, io_base); + platform_set_drvdata(pdev, priv); /* Set chip enabled, but */ - err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio)); - if (err) - goto out_gpio; + priv->gpiod_nwp = devm_gpiod_get(&pdev->dev, "nwp", GPIOD_OUT_HIGH); + if (IS_ERR(priv->gpiod_nwp)) { + err = PTR_ERR(priv->gpiod_nwp); + dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err); + goto out_mtd; + } + + priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH); + if (IS_ERR(priv->gpiod_nce)) { + err = PTR_ERR(priv->gpiod_nce); + dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err); + goto out_mtd; + } + + priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH); + if (IS_ERR(priv->gpiod_nre)) { + err = PTR_ERR(priv->gpiod_nre); + dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err); + goto out_mtd; + } + + priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH); + if (IS_ERR(priv->gpiod_nwe)) { + err = PTR_ERR(priv->gpiod_nwe); + dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err); + goto out_mtd; + } + + priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW); + if (IS_ERR(priv->gpiod_ale)) { + err = PTR_ERR(priv->gpiod_ale); + dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err); + goto out_mtd; + } + + priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW); + if (IS_ERR(priv->gpiod_cle)) { + err = PTR_ERR(priv->gpiod_cle); + dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err); + goto out_mtd; + } + + /* Initialize data port direction to a known state */ + ams_delta_dir_input(priv, true); /* Scan to find existence of the device */ - err = nand_scan(ams_delta_mtd, 1); + err = nand_scan(this, 1); if (err) goto out_mtd; /* Register the partitions */ - mtd_device_register(ams_delta_mtd, partition_info, - ARRAY_SIZE(partition_info)); + mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info)); goto out; out_mtd: - gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio)); -out_gpio: - gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB); iounmap(io_base); out_free: - kfree(this); out: return err; } @@ -261,18 +303,15 @@ out_free: */ static int ams_delta_cleanup(struct platform_device *pdev) { - void __iomem *io_base = platform_get_drvdata(pdev); + struct ams_delta_nand *priv = platform_get_drvdata(pdev); + struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip); + void __iomem *io_base = priv->io_base; /* Release resources, unregister device */ - nand_release(ams_delta_mtd); + nand_release(mtd_to_nand(mtd)); - gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio)); - gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB); iounmap(io_base); - /* Free the MTD device structure */ - kfree(mtd_to_nand(ams_delta_mtd)); - return 0; } diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index a068b214ebaa..fb33f6be7c4f 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -410,25 +410,15 @@ err: return -EIO; } -static u8 atmel_nand_read_byte(struct mtd_info *mtd) +static u8 atmel_nand_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); return ioread8(nand->activecs->io.virt); } -static u16 atmel_nand_read_word(struct mtd_info *mtd) +static void atmel_nand_write_byte(struct nand_chip *chip, u8 byte) { - struct nand_chip *chip = mtd_to_nand(mtd); - struct atmel_nand *nand = to_atmel_nand(chip); - - return ioread16(nand->activecs->io.virt); -} - -static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte) -{ - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); if (chip->options & NAND_BUSWIDTH_16) @@ -437,9 +427,8 @@ static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte) iowrite8(byte, nand->activecs->io.virt); } -static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void atmel_nand_read_buf(struct nand_chip *chip, u8 *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; @@ -462,9 +451,8 @@ static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) ioread8_rep(nand->activecs->io.virt, buf, len); } -static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void atmel_nand_write_buf(struct nand_chip *chip, const u8 *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; @@ -487,34 +475,31 @@ static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) iowrite8_rep(nand->activecs->io.virt, buf, len); } -static int atmel_nand_dev_ready(struct mtd_info *mtd) +static int atmel_nand_dev_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); return gpiod_get_value(nand->activecs->rb.gpio); } -static void atmel_nand_select_chip(struct mtd_info *mtd, int cs) +static void atmel_nand_select_chip(struct nand_chip *chip, int cs) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); if (cs < 0 || cs >= nand->numcs) { nand->activecs = NULL; - chip->dev_ready = NULL; + chip->legacy.dev_ready = NULL; return; } nand->activecs = &nand->cs[cs]; if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB) - chip->dev_ready = atmel_nand_dev_ready; + chip->legacy.dev_ready = atmel_nand_dev_ready; } -static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd) +static int atmel_hsmc_nand_dev_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_hsmc_nand_controller *nc; u32 status; @@ -526,15 +511,15 @@ static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd) return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id); } -static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs) +static void atmel_hsmc_nand_select_chip(struct nand_chip *chip, int cs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_hsmc_nand_controller *nc; nc = to_hsmc_nand_controller(chip->controller); - atmel_nand_select_chip(mtd, cs); + atmel_nand_select_chip(chip, cs); if (!nand->activecs) { regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL, @@ -543,7 +528,7 @@ static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs) } if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB) - chip->dev_ready = atmel_hsmc_nand_dev_ready; + chip->legacy.dev_ready = atmel_hsmc_nand_dev_ready; regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG, ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK | @@ -607,10 +592,9 @@ static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll) return ret; } -static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat, +static void atmel_hsmc_nand_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_hsmc_nand_controller *nc; @@ -634,10 +618,9 @@ static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat, } } -static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, +static void atmel_nand_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; @@ -851,7 +834,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf, if (ret) return ret; - atmel_nand_write_buf(mtd, buf, mtd->writesize); + atmel_nand_write_buf(chip, buf, mtd->writesize); ret = atmel_nand_pmecc_generate_eccbytes(chip, raw); if (ret) { @@ -861,20 +844,18 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf, atmel_nand_pmecc_disable(chip, raw); - atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); + atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } -static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, +static int atmel_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false); } -static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_nand_pmecc_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -893,8 +874,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, if (ret) return ret; - atmel_nand_read_buf(mtd, buf, mtd->writesize); - atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); + atmel_nand_read_buf(chip, buf, mtd->writesize); + atmel_nand_read_buf(chip, chip->oob_poi, mtd->oobsize); ret = atmel_nand_pmecc_correct_data(chip, buf, raw); @@ -903,15 +884,13 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, return ret; } -static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int atmel_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf, int oob_required, int page) { return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false); } -static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int atmel_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true); @@ -956,7 +935,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip, if (ret) return ret; - atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); + atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize); nc->op.cmds[0] = NAND_CMD_PAGEPROG; nc->op.ncmds = 1; @@ -966,15 +945,14 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip, dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n", ret); - status = chip->waitfunc(mtd, chip); + status = chip->legacy.waitfunc(chip); if (status & NAND_STATUS_FAIL) return -EIO; return ret; } -static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_hsmc_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -982,8 +960,7 @@ static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd, false); } -static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_hsmc_nand_pmecc_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -1045,16 +1022,14 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, return ret; } -static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int atmel_hsmc_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf, int oob_required, int page) { return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page, false); } -static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { @@ -1473,10 +1448,9 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand, return 0; } -static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline, +static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline, const struct nand_data_interface *conf) { - struct nand_chip *chip = mtd_to_nand(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; @@ -1498,19 +1472,18 @@ static void atmel_nand_init(struct atmel_nand_controller *nc, mtd->dev.parent = nc->dev; nand->base.controller = &nc->base; - chip->cmd_ctrl = atmel_nand_cmd_ctrl; - chip->read_byte = atmel_nand_read_byte; - chip->read_word = atmel_nand_read_word; - chip->write_byte = atmel_nand_write_byte; - chip->read_buf = atmel_nand_read_buf; - chip->write_buf = atmel_nand_write_buf; + chip->legacy.cmd_ctrl = atmel_nand_cmd_ctrl; + chip->legacy.read_byte = atmel_nand_read_byte; + chip->legacy.write_byte = atmel_nand_write_byte; + chip->legacy.read_buf = atmel_nand_read_buf; + chip->legacy.write_buf = atmel_nand_write_buf; chip->select_chip = atmel_nand_select_chip; if (nc->mck && nc->caps->ops->setup_data_interface) chip->setup_data_interface = atmel_nand_setup_data_interface; /* Some NANDs require a longer delay than the default one (20us). */ - chip->chip_delay = 40; + chip->legacy.chip_delay = 40; /* * Use a bounce buffer when the buffer passed by the MTD user is not @@ -1551,7 +1524,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc, atmel_nand_init(nc, nand); /* Overload some methods for the HSMC controller. */ - chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl; + chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl; chip->select_chip = atmel_hsmc_nand_select_chip; } @@ -1586,9 +1559,7 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc, return ERR_PTR(-EINVAL); } - nand = devm_kzalloc(nc->dev, - sizeof(*nand) + (numcs * sizeof(*nand->cs)), - GFP_KERNEL); + nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL); if (!nand) { dev_err(nc->dev, "Failed to allocate NAND object\n"); return ERR_PTR(-ENOMEM); @@ -1694,7 +1665,7 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc, nc->caps->ops->nand_init(nc, nand); - ret = nand_scan(mtd, nand->numcs); + ret = nand_scan(chip, nand->numcs); if (ret) { dev_err(nc->dev, "NAND scan failed: %d\n", ret); return ret; @@ -2063,6 +2034,10 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc) nand_np = dev->of_node; nfc_np = of_find_compatible_node(dev->of_node, NULL, "atmel,sama5d3-nfc"); + if (!nfc_np) { + dev_err(dev, "Could not find device node for sama5d3-nfc\n"); + return -ENODEV; + } nc->clk = of_clk_get(nfc_np, 0); if (IS_ERR(nc->clk)) { diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c index 35f5c84cd331..9731c1c487f6 100644 --- a/drivers/mtd/nand/raw/au1550nd.c +++ b/drivers/mtd/nand/raw/au1550nd.c @@ -24,134 +24,113 @@ struct au1550nd_ctx { int cs; void __iomem *base; - void (*write_byte)(struct mtd_info *, u_char); + void (*write_byte)(struct nand_chip *, u_char); }; /** * au_read_byte - read one byte from the chip - * @mtd: MTD device structure + * @this: NAND chip object * * read function for 8bit buswidth */ -static u_char au_read_byte(struct mtd_info *mtd) +static u_char au_read_byte(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); - u_char ret = readb(this->IO_ADDR_R); + u_char ret = readb(this->legacy.IO_ADDR_R); wmb(); /* drain writebuffer */ return ret; } /** * au_write_byte - write one byte to the chip - * @mtd: MTD device structure + * @this: NAND chip object * @byte: pointer to data byte to write * * write function for 8it buswidth */ -static void au_write_byte(struct mtd_info *mtd, u_char byte) +static void au_write_byte(struct nand_chip *this, u_char byte) { - struct nand_chip *this = mtd_to_nand(mtd); - writeb(byte, this->IO_ADDR_W); + writeb(byte, this->legacy.IO_ADDR_W); wmb(); /* drain writebuffer */ } /** * au_read_byte16 - read one byte endianness aware from the chip - * @mtd: MTD device structure + * @this: NAND chip object * * read function for 16bit buswidth with endianness conversion */ -static u_char au_read_byte16(struct mtd_info *mtd) +static u_char au_read_byte16(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); - u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R)); + u_char ret = (u_char) cpu_to_le16(readw(this->legacy.IO_ADDR_R)); wmb(); /* drain writebuffer */ return ret; } /** * au_write_byte16 - write one byte endianness aware to the chip - * @mtd: MTD device structure + * @this: NAND chip object * @byte: pointer to data byte to write * * write function for 16bit buswidth with endianness conversion */ -static void au_write_byte16(struct mtd_info *mtd, u_char byte) +static void au_write_byte16(struct nand_chip *this, u_char byte) { - struct nand_chip *this = mtd_to_nand(mtd); - writew(le16_to_cpu((u16) byte), this->IO_ADDR_W); + writew(le16_to_cpu((u16) byte), this->legacy.IO_ADDR_W); wmb(); /* drain writebuffer */ } /** - * au_read_word - read one word from the chip - * @mtd: MTD device structure - * - * read function for 16bit buswidth without endianness conversion - */ -static u16 au_read_word(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u16 ret = readw(this->IO_ADDR_R); - wmb(); /* drain writebuffer */ - return ret; -} - -/** * au_write_buf - write buffer to chip - * @mtd: MTD device structure + * @this: NAND chip object * @buf: data buffer * @len: number of bytes to write * * write function for 8bit buswidth */ -static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void au_write_buf(struct nand_chip *this, const u_char *buf, int len) { int i; - struct nand_chip *this = mtd_to_nand(mtd); for (i = 0; i < len; i++) { - writeb(buf[i], this->IO_ADDR_W); + writeb(buf[i], this->legacy.IO_ADDR_W); wmb(); /* drain writebuffer */ } } /** * au_read_buf - read chip data into buffer - * @mtd: MTD device structure + * @this: NAND chip object * @buf: buffer to store date * @len: number of bytes to read * * read function for 8bit buswidth */ -static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void au_read_buf(struct nand_chip *this, u_char *buf, int len) { int i; - struct nand_chip *this = mtd_to_nand(mtd); for (i = 0; i < len; i++) { - buf[i] = readb(this->IO_ADDR_R); + buf[i] = readb(this->legacy.IO_ADDR_R); wmb(); /* drain writebuffer */ } } /** * au_write_buf16 - write buffer to chip - * @mtd: MTD device structure + * @this: NAND chip object * @buf: data buffer * @len: number of bytes to write * * write function for 16bit buswidth */ -static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) +static void au_write_buf16(struct nand_chip *this, const u_char *buf, int len) { int i; - struct nand_chip *this = mtd_to_nand(mtd); u16 *p = (u16 *) buf; len >>= 1; for (i = 0; i < len; i++) { - writew(p[i], this->IO_ADDR_W); + writew(p[i], this->legacy.IO_ADDR_W); wmb(); /* drain writebuffer */ } @@ -173,7 +152,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) len >>= 1; for (i = 0; i < len; i++) { - p[i] = readw(this->IO_ADDR_R); + p[i] = readw(this->legacy.IO_ADDR_R); wmb(); /* drain writebuffer */ } } @@ -200,19 +179,19 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) switch (cmd) { case NAND_CTL_SETCLE: - this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD; + this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_CMD; break; case NAND_CTL_CLRCLE: - this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA; + this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA; break; case NAND_CTL_SETALE: - this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR; + this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_ADDR; break; case NAND_CTL_CLRALE: - this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA; + this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA; /* FIXME: Nobody knows why this is necessary, * but it works only that way */ udelay(1); @@ -229,12 +208,12 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) break; } - this->IO_ADDR_R = this->IO_ADDR_W; + this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W; wmb(); /* Drain the writebuffer */ } -int au1550_device_ready(struct mtd_info *mtd) +int au1550_device_ready(struct nand_chip *this) { return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0; } @@ -248,23 +227,24 @@ int au1550_device_ready(struct mtd_info *mtd) * chip needs it to be asserted during chip not ready time but the NAND * controller keeps it released. * - * @mtd: MTD device structure + * @this: NAND chip object * @chip: chipnumber to select, -1 for deselect */ -static void au1550_select_chip(struct mtd_info *mtd, int chip) +static void au1550_select_chip(struct nand_chip *this, int chip) { } /** * au1550_command - Send command to NAND device - * @mtd: MTD device structure + * @this: NAND chip object * @command: the command to be sent * @column: the column address for this command, -1 if none * @page_addr: the page address for this command, -1 if none */ -static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void au1550_command(struct nand_chip *this, unsigned command, + int column, int page_addr) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx, chip); int ce_override = 0, i; @@ -289,9 +269,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i column -= 256; readcmd = NAND_CMD_READ1; } - ctx->write_byte(mtd, readcmd); + ctx->write_byte(this, readcmd); } - ctx->write_byte(mtd, command); + ctx->write_byte(this, command); /* Set ALE and clear CLE to start address cycle */ au1550_hwcontrol(mtd, NAND_CTL_CLRCLE); @@ -305,10 +285,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i if (this->options & NAND_BUSWIDTH_16 && !nand_opcode_8bits(command)) column >>= 1; - ctx->write_byte(mtd, column); + ctx->write_byte(this, column); } if (page_addr != -1) { - ctx->write_byte(mtd, (u8)(page_addr & 0xff)); + ctx->write_byte(this, (u8)(page_addr & 0xff)); if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || @@ -326,10 +306,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i au1550_hwcontrol(mtd, NAND_CTL_SETNCE); } - ctx->write_byte(mtd, (u8)(page_addr >> 8)); + ctx->write_byte(this, (u8)(page_addr >> 8)); if (this->options & NAND_ROW_ADDR_3) - ctx->write_byte(mtd, + ctx->write_byte(this, ((page_addr >> 16) & 0x0f)); } /* Latch in address */ @@ -362,7 +342,8 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i /* Apply a short delay always to ensure that we do wait tWB. */ ndelay(100); /* Wait for a chip to become ready... */ - for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i) + for (i = this->legacy.chip_delay; + !this->legacy.dev_ready(this) && i > 0; --i) udelay(1); /* Release -CE and re-enable interrupts. */ @@ -373,7 +354,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i /* Apply this short delay always to ensure that we do wait tWB. */ ndelay(100); - while(!this->dev_ready(mtd)); + while(!this->legacy.dev_ready(this)); } static int find_nand_cs(unsigned long nand_base) @@ -448,25 +429,24 @@ static int au1550nd_probe(struct platform_device *pdev) } ctx->cs = cs; - this->dev_ready = au1550_device_ready; + this->legacy.dev_ready = au1550_device_ready; this->select_chip = au1550_select_chip; - this->cmdfunc = au1550_command; + this->legacy.cmdfunc = au1550_command; /* 30 us command delay time */ - this->chip_delay = 30; + this->legacy.chip_delay = 30; this->ecc.mode = NAND_ECC_SOFT; this->ecc.algo = NAND_ECC_HAMMING; if (pd->devwidth) this->options |= NAND_BUSWIDTH_16; - this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte; + this->legacy.read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte; ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte; - this->read_word = au_read_word; - this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf; - this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf; + this->legacy.write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf; + this->legacy.read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf; - ret = nand_scan(mtd, 1); + ret = nand_scan(this, 1); if (ret) { dev_err(&pdev->dev, "NAND scan failed with %d\n", ret); goto out3; @@ -492,7 +472,7 @@ static int au1550nd_remove(struct platform_device *pdev) struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nand_release(nand_to_mtd(&ctx->chip)); + nand_release(&ctx->chip); iounmap(ctx->base); release_mem_region(r->start, 0x1000); kfree(ctx); diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c index fb31429b70a9..d79694160845 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c @@ -65,7 +65,7 @@ static int bcm47xxnflash_remove(struct platform_device *pdev) { struct bcm47xxnflash *nflash = platform_get_drvdata(pdev); - nand_release(nand_to_mtd(&nflash->nand_chip)); + nand_release(&nflash->nand_chip); return 0; } diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c index 60874de430eb..9095a79ebc7d 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c @@ -170,10 +170,9 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, * NAND chip ops **************************************************/ -static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd, - unsigned int ctrl) +static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct nand_chip *nand_chip, + int cmd, unsigned int ctrl) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); u32 code = 0; @@ -191,15 +190,14 @@ static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd, } /* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */ -static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, - int chip) +static void bcm47xxnflash_ops_bcm4706_select_chip(struct nand_chip *chip, + int cs) { return; } -static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd) +static int bcm47xxnflash_ops_bcm4706_dev_ready(struct nand_chip *nand_chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY); @@ -212,11 +210,11 @@ static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd) * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert * standard commands would be much more complicated. */ -static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, +static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct nand_chip *nand_chip, unsigned command, int column, int page_addr) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(nand_chip); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); struct bcma_drv_cc *cc = b47n->cc; u32 ctlcode; @@ -229,10 +227,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, switch (command) { case NAND_CMD_RESET: - nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE); + nand_chip->legacy.cmd_ctrl(nand_chip, command, NAND_CTRL_CLE); ndelay(100); - nand_wait_ready(mtd); + nand_wait_ready(nand_chip); break; case NAND_CMD_READID: ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0; @@ -310,9 +308,9 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, b47n->curr_command = command; } -static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) +static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct nand_chip *nand_chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(nand_chip); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); struct bcma_drv_cc *cc = b47n->cc; u32 tmp = 0; @@ -338,31 +336,31 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) return 0; } -static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, +static void bcm47xxnflash_ops_bcm4706_read_buf(struct nand_chip *nand_chip, uint8_t *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); switch (b47n->curr_command) { case NAND_CMD_READ0: case NAND_CMD_READOOB: - bcm47xxnflash_ops_bcm4706_read(mtd, buf, len); + bcm47xxnflash_ops_bcm4706_read(nand_to_mtd(nand_chip), buf, + len); return; } pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); } -static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, +static void bcm47xxnflash_ops_bcm4706_write_buf(struct nand_chip *nand_chip, const uint8_t *buf, int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip); switch (b47n->curr_command) { case NAND_CMD_SEQIN: - bcm47xxnflash_ops_bcm4706_write(mtd, buf, len); + bcm47xxnflash_ops_bcm4706_write(nand_to_mtd(nand_chip), buf, + len); return; } @@ -386,16 +384,16 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) u32 val; b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; - nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl; - nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready; - b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; - b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; - b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; - b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; - b47n->nand_chip.set_features = nand_get_set_features_notsupp; - b47n->nand_chip.get_features = nand_get_set_features_notsupp; - - nand_chip->chip_delay = 50; + nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl; + nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready; + b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; + b47n->nand_chip.legacy.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; + b47n->nand_chip.legacy.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; + b47n->nand_chip.legacy.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; + b47n->nand_chip.legacy.set_features = nand_get_set_features_notsupp; + b47n->nand_chip.legacy.get_features = nand_get_set_features_notsupp; + + nand_chip->legacy.chip_delay = 50; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ @@ -423,7 +421,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0)); /* Scan NAND */ - err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1); + err = nand_scan(&b47n->nand_chip, 1); if (err) { pr_err("Could not scan NAND flash: %d\n", err); goto exit; diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 4b90d5b380c2..482c6f093f99 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1231,15 +1231,14 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) * NAND MTD API: read/program/erase ***********************************************************************/ -static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat, - unsigned int ctrl) +static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat, + unsigned int ctrl) { /* intentionally left blank */ } -static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) +static int brcmnand_waitfunc(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_controller *ctrl = host->ctrl; unsigned long timeo = msecs_to_jiffies(100); @@ -1274,7 +1273,6 @@ static int brcmnand_low_level_op(struct brcmnand_host *host, enum brcmnand_llop_type type, u32 data, bool last_op) { - struct mtd_info *mtd = nand_to_mtd(&host->chip); struct nand_chip *chip = &host->chip; struct brcmnand_controller *ctrl = host->ctrl; u32 tmp; @@ -1307,13 +1305,13 @@ static int brcmnand_low_level_op(struct brcmnand_host *host, (void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP); brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP); - return brcmnand_waitfunc(mtd, chip); + return brcmnand_waitfunc(chip); } -static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command, +static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command, int column, int page_addr) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_controller *ctrl = host->ctrl; u64 addr = (u64)page_addr << chip->page_shift; @@ -1383,7 +1381,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command, (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); brcmnand_send_cmd(host, native_cmd); - brcmnand_waitfunc(mtd, chip); + brcmnand_waitfunc(chip); if (native_cmd == CMD_PARAMETER_READ || native_cmd == CMD_PARAMETER_CHANGE_COL) { @@ -1417,9 +1415,8 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command, brcmnand_wp(mtd, 1); } -static uint8_t brcmnand_read_byte(struct mtd_info *mtd) +static uint8_t brcmnand_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_controller *ctrl = host->ctrl; uint8_t ret = 0; @@ -1474,19 +1471,18 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd) return ret; } -static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void brcmnand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { int i; for (i = 0; i < len; i++, buf++) - *buf = brcmnand_read_byte(mtd); + *buf = brcmnand_read_byte(chip); } -static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) +static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf, + int len) { int i; - struct nand_chip *chip = mtd_to_nand(mtd); struct brcmnand_host *host = nand_get_controller_data(chip); switch (host->last_cmd) { @@ -1617,7 +1613,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); /* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */ brcmnand_send_cmd(host, CMD_PAGE_READ); - brcmnand_waitfunc(mtd, chip); + brcmnand_waitfunc(chip); if (likely(buf)) { brcmnand_soc_data_bus_prepare(ctrl->soc, false); @@ -1689,7 +1685,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, sas = mtd->oobsize / chip->ecc.steps; /* read without ecc for verification */ - ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page); + ret = chip->ecc.read_page_raw(chip, buf, true, page); if (ret) return ret; @@ -1786,9 +1782,10 @@ try_dmaread: return 0; } -static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct brcmnand_host *host = nand_get_controller_data(chip); u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; @@ -1798,10 +1795,11 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip, mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); } -static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct brcmnand_host *host = nand_get_controller_data(chip); + struct mtd_info *mtd = nand_to_mtd(chip); u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; int ret; @@ -1814,17 +1812,18 @@ static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return ret; } -static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int brcmnand_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return brcmnand_read(mtd, chip, (u64)page << chip->page_shift, mtd->writesize >> FC_SHIFT, NULL, (u8 *)chip->oob_poi); } -static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int brcmnand_read_oob_raw(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct brcmnand_host *host = nand_get_controller_data(chip); brcmnand_set_ecc_enabled(host, 0); @@ -1892,7 +1891,7 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, /* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */ brcmnand_send_cmd(host, CMD_PROGRAM_PAGE); - status = brcmnand_waitfunc(mtd, chip); + status = brcmnand_waitfunc(chip); if (status & NAND_STATUS_FAIL) { dev_info(ctrl->dev, "program failed at %llx\n", @@ -1906,9 +1905,10 @@ out: return ret; } -static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct brcmnand_host *host = nand_get_controller_data(chip); void *oob = oob_required ? chip->oob_poi : NULL; @@ -1918,10 +1918,10 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip, return nand_prog_page_end_op(chip); } -static int brcmnand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, +static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct brcmnand_host *host = nand_get_controller_data(chip); void *oob = oob_required ? chip->oob_poi : NULL; @@ -1933,16 +1933,16 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd, return nand_prog_page_end_op(chip); } -static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int brcmnand_write_oob(struct nand_chip *chip, int page) { - return brcmnand_write(mtd, chip, (u64)page << chip->page_shift, - NULL, chip->oob_poi); + return brcmnand_write(nand_to_mtd(chip), chip, + (u64)page << chip->page_shift, NULL, + chip->oob_poi); } -static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int brcmnand_write_oob_raw(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct brcmnand_host *host = nand_get_controller_data(chip); int ret; @@ -2270,15 +2270,12 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn) mtd->owner = THIS_MODULE; mtd->dev.parent = &pdev->dev; - chip->IO_ADDR_R = (void __iomem *)0xdeadbeef; - chip->IO_ADDR_W = (void __iomem *)0xdeadbeef; - - chip->cmd_ctrl = brcmnand_cmd_ctrl; - chip->cmdfunc = brcmnand_cmdfunc; - chip->waitfunc = brcmnand_waitfunc; - chip->read_byte = brcmnand_read_byte; - chip->read_buf = brcmnand_read_buf; - chip->write_buf = brcmnand_write_buf; + chip->legacy.cmd_ctrl = brcmnand_cmd_ctrl; + chip->legacy.cmdfunc = brcmnand_cmdfunc; + chip->legacy.waitfunc = brcmnand_waitfunc; + chip->legacy.read_byte = brcmnand_read_byte; + chip->legacy.read_buf = brcmnand_read_buf; + chip->legacy.write_buf = brcmnand_write_buf; chip->ecc.mode = NAND_ECC_HW; chip->ecc.read_page = brcmnand_read_page; @@ -2301,7 +2298,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn) nand_writereg(ctrl, cfg_offs, nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH); - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret) return ret; @@ -2616,7 +2613,7 @@ int brcmnand_remove(struct platform_device *pdev) struct brcmnand_host *host; list_for_each_entry(host, &ctrl->host_list, node) - nand_release(nand_to_mtd(&host->chip)); + nand_release(&host->chip); clk_disable_unprepare(ctrl->clk); diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index 1dbe43adcfe7..c1a745940d12 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -100,9 +100,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; #define cafe_readl(cafe, addr) readl((cafe)->mmio + CAFE_##addr) #define cafe_writel(cafe, datum, addr) writel(datum, (cafe)->mmio + CAFE_##addr) -static int cafe_device_ready(struct mtd_info *mtd) +static int cafe_device_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct cafe_priv *cafe = nand_get_controller_data(chip); int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000); uint32_t irqs = cafe_readl(cafe, NAND_IRQ); @@ -117,9 +116,8 @@ static int cafe_device_ready(struct mtd_info *mtd) } -static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void cafe_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct cafe_priv *cafe = nand_get_controller_data(chip); if (cafe->usedma) @@ -133,9 +131,8 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) len, cafe->datalen); } -static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void cafe_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct cafe_priv *cafe = nand_get_controller_data(chip); if (cafe->usedma) @@ -148,22 +145,21 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) cafe->datalen += len; } -static uint8_t cafe_read_byte(struct mtd_info *mtd) +static uint8_t cafe_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct cafe_priv *cafe = nand_get_controller_data(chip); uint8_t d; - cafe_read_buf(mtd, &d, 1); + cafe_read_buf(chip, &d, 1); cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d); return d; } -static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command, +static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command, int column, int page_addr) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct cafe_priv *cafe = nand_get_controller_data(chip); int adrbytes = 0; uint32_t ctl1; @@ -313,13 +309,12 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command, cafe_writel(cafe, cafe->ctl2, NAND_CTRL2); return; } - nand_wait_ready(mtd); + nand_wait_ready(chip); cafe_writel(cafe, cafe->ctl2, NAND_CTRL2); } -static void cafe_select_chip(struct mtd_info *mtd, int chipnr) +static void cafe_select_chip(struct nand_chip *chip, int chipnr) { - struct nand_chip *chip = mtd_to_nand(mtd); struct cafe_priv *cafe = nand_get_controller_data(chip); cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr); @@ -346,17 +341,19 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id) return IRQ_HANDLED; } -static int cafe_nand_write_oob(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int cafe_nand_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi, mtd->oobsize); } /* Don't use -- use nand_read_oob_std for now */ -static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int cafe_nand_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); } /** @@ -369,9 +366,10 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, * The hw generator calculates the error syndrome automatically. Therefore * we need a special oob layout and handling. */ -static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int cafe_nand_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct cafe_priv *cafe = nand_get_controller_data(chip); unsigned int max_bitflips = 0; @@ -380,7 +378,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, cafe_readl(cafe, NAND_ECC_SYN01)); nand_read_page_op(chip, page, 0, buf, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) { unsigned short syn[8], pat[4]; @@ -531,15 +529,15 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = { }; -static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static int cafe_nand_write_page_lowlevel(struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct cafe_priv *cafe = nand_get_controller_data(chip); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); /* Set up ECC autogeneration */ cafe->ctl2 |= (1<<30); @@ -547,7 +545,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, return nand_prog_page_end_op(chip); } -static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs) +static int cafe_nand_block_bad(struct nand_chip *chip, loff_t ofs) { return 0; } @@ -705,23 +703,23 @@ static int cafe_nand_probe(struct pci_dev *pdev, goto out_ior; } - cafe->nand.cmdfunc = cafe_nand_cmdfunc; - cafe->nand.dev_ready = cafe_device_ready; - cafe->nand.read_byte = cafe_read_byte; - cafe->nand.read_buf = cafe_read_buf; - cafe->nand.write_buf = cafe_write_buf; + cafe->nand.legacy.cmdfunc = cafe_nand_cmdfunc; + cafe->nand.legacy.dev_ready = cafe_device_ready; + cafe->nand.legacy.read_byte = cafe_read_byte; + cafe->nand.legacy.read_buf = cafe_read_buf; + cafe->nand.legacy.write_buf = cafe_write_buf; cafe->nand.select_chip = cafe_select_chip; - cafe->nand.set_features = nand_get_set_features_notsupp; - cafe->nand.get_features = nand_get_set_features_notsupp; + cafe->nand.legacy.set_features = nand_get_set_features_notsupp; + cafe->nand.legacy.get_features = nand_get_set_features_notsupp; - cafe->nand.chip_delay = 0; + cafe->nand.legacy.chip_delay = 0; /* Enable the following for a flash based bad block table */ cafe->nand.bbt_options = NAND_BBT_USE_FLASH; if (skipbbt) { cafe->nand.options |= NAND_SKIP_BBTSCAN; - cafe->nand.block_bad = cafe_nand_block_bad; + cafe->nand.legacy.block_bad = cafe_nand_block_bad; } if (numtimings && numtimings != 3) { @@ -783,7 +781,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, /* Scan to find existence of the device */ cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops; - err = nand_scan(mtd, 2); + err = nand_scan(&cafe->nand, 2); if (err) goto out_irq; @@ -819,7 +817,7 @@ static void cafe_nand_remove(struct pci_dev *pdev) /* Disable NAND IRQ in global IRQ mask register */ cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); free_irq(pdev->irq, mtd); - nand_release(mtd); + nand_release(chip); free_rs(cafe->rs); pci_iounmap(pdev, cafe->mmio); dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr); diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c index b66e254b6802..143e4acacaae 100644 --- a/drivers/mtd/nand/raw/cmx270_nand.c +++ b/drivers/mtd/nand/raw/cmx270_nand.c @@ -49,29 +49,26 @@ static const struct mtd_partition partition_info[] = { }; #define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) -static u_char cmx270_read_byte(struct mtd_info *mtd) +static u_char cmx270_read_byte(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); - - return (readl(this->IO_ADDR_R) >> 16); + return (readl(this->legacy.IO_ADDR_R) >> 16); } -static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void cmx270_write_buf(struct nand_chip *this, const u_char *buf, + int len) { int i; - struct nand_chip *this = mtd_to_nand(mtd); for (i=0; i<len; i++) - writel((*buf++ << 16), this->IO_ADDR_W); + writel((*buf++ << 16), this->legacy.IO_ADDR_W); } -static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void cmx270_read_buf(struct nand_chip *this, u_char *buf, int len) { int i; - struct nand_chip *this = mtd_to_nand(mtd); for (i=0; i<len; i++) - *buf++ = readl(this->IO_ADDR_R) >> 16; + *buf++ = readl(this->legacy.IO_ADDR_R) >> 16; } static inline void nand_cs_on(void) @@ -89,11 +86,10 @@ static void nand_cs_off(void) /* * hardware specific access to control-lines */ -static void cmx270_hwcontrol(struct mtd_info *mtd, int dat, +static void cmx270_hwcontrol(struct nand_chip *this, int dat, unsigned int ctrl) { - struct nand_chip *this = mtd_to_nand(mtd); - unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; + unsigned int nandaddr = (unsigned int)this->legacy.IO_ADDR_W; dsb(); @@ -113,9 +109,9 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat, } dsb(); - this->IO_ADDR_W = (void __iomem*)nandaddr; + this->legacy.IO_ADDR_W = (void __iomem*)nandaddr; if (dat != NAND_CMD_NONE) - writel((dat << 16), this->IO_ADDR_W); + writel((dat << 16), this->legacy.IO_ADDR_W); dsb(); } @@ -123,7 +119,7 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat, /* * read device ready pin */ -static int cmx270_device_ready(struct mtd_info *mtd) +static int cmx270_device_ready(struct nand_chip *this) { dsb(); @@ -177,23 +173,23 @@ static int __init cmx270_init(void) cmx270_nand_mtd->owner = THIS_MODULE; /* insert callbacks */ - this->IO_ADDR_R = cmx270_nand_io; - this->IO_ADDR_W = cmx270_nand_io; - this->cmd_ctrl = cmx270_hwcontrol; - this->dev_ready = cmx270_device_ready; + this->legacy.IO_ADDR_R = cmx270_nand_io; + this->legacy.IO_ADDR_W = cmx270_nand_io; + this->legacy.cmd_ctrl = cmx270_hwcontrol; + this->legacy.dev_ready = cmx270_device_ready; /* 15 us command delay time */ - this->chip_delay = 20; + this->legacy.chip_delay = 20; this->ecc.mode = NAND_ECC_SOFT; this->ecc.algo = NAND_ECC_HAMMING; /* read/write functions */ - this->read_byte = cmx270_read_byte; - this->read_buf = cmx270_read_buf; - this->write_buf = cmx270_write_buf; + this->legacy.read_byte = cmx270_read_byte; + this->legacy.read_buf = cmx270_read_buf; + this->legacy.write_buf = cmx270_write_buf; /* Scan to find existence of the device */ - ret = nand_scan(cmx270_nand_mtd, 1); + ret = nand_scan(this, 1); if (ret) { pr_notice("No NAND device\n"); goto err_scan; @@ -228,7 +224,7 @@ module_init(cmx270_init); static void __exit cmx270_cleanup(void) { /* Release resources, unregister device */ - nand_release(cmx270_nand_mtd); + nand_release(mtd_to_nand(cmx270_nand_mtd)); gpio_free(GPIO_NAND_RB); gpio_free(GPIO_NAND_CS); diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c index beafad62e7d5..c6f578aff5d9 100644 --- a/drivers/mtd/nand/raw/cs553x_nand.c +++ b/drivers/mtd/nand/raw/cs553x_nand.c @@ -93,83 +93,74 @@ #define CS_NAND_ECC_CLRECC (1<<1) #define CS_NAND_ECC_ENECC (1<<0) -static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void cs553x_read_buf(struct nand_chip *this, u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); - while (unlikely(len > 0x800)) { - memcpy_fromio(buf, this->IO_ADDR_R, 0x800); + memcpy_fromio(buf, this->legacy.IO_ADDR_R, 0x800); buf += 0x800; len -= 0x800; } - memcpy_fromio(buf, this->IO_ADDR_R, len); + memcpy_fromio(buf, this->legacy.IO_ADDR_R, len); } -static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void cs553x_write_buf(struct nand_chip *this, const u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); - while (unlikely(len > 0x800)) { - memcpy_toio(this->IO_ADDR_R, buf, 0x800); + memcpy_toio(this->legacy.IO_ADDR_R, buf, 0x800); buf += 0x800; len -= 0x800; } - memcpy_toio(this->IO_ADDR_R, buf, len); + memcpy_toio(this->legacy.IO_ADDR_R, buf, len); } -static unsigned char cs553x_read_byte(struct mtd_info *mtd) +static unsigned char cs553x_read_byte(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); - return readb(this->IO_ADDR_R); + return readb(this->legacy.IO_ADDR_R); } -static void cs553x_write_byte(struct mtd_info *mtd, u_char byte) +static void cs553x_write_byte(struct nand_chip *this, u_char byte) { - struct nand_chip *this = mtd_to_nand(mtd); int i = 100000; - while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) { + while (i && readb(this->legacy.IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) { udelay(1); i--; } - writeb(byte, this->IO_ADDR_W + 0x801); + writeb(byte, this->legacy.IO_ADDR_W + 0x801); } -static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd, +static void cs553x_hwcontrol(struct nand_chip *this, int cmd, unsigned int ctrl) { - struct nand_chip *this = mtd_to_nand(mtd); - void __iomem *mmio_base = this->IO_ADDR_R; + void __iomem *mmio_base = this->legacy.IO_ADDR_R; if (ctrl & NAND_CTRL_CHANGE) { unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01; writeb(ctl, mmio_base + MM_NAND_CTL); } if (cmd != NAND_CMD_NONE) - cs553x_write_byte(mtd, cmd); + cs553x_write_byte(this, cmd); } -static int cs553x_device_ready(struct mtd_info *mtd) +static int cs553x_device_ready(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); - void __iomem *mmio_base = this->IO_ADDR_R; + void __iomem *mmio_base = this->legacy.IO_ADDR_R; unsigned char foo = readb(mmio_base + MM_NAND_STS); return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY); } -static void cs_enable_hwecc(struct mtd_info *mtd, int mode) +static void cs_enable_hwecc(struct nand_chip *this, int mode) { - struct nand_chip *this = mtd_to_nand(mtd); - void __iomem *mmio_base = this->IO_ADDR_R; + void __iomem *mmio_base = this->legacy.IO_ADDR_R; writeb(0x07, mmio_base + MM_NAND_ECC_CTL); } -static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat, + u_char *ecc_code) { uint32_t ecc; - struct nand_chip *this = mtd_to_nand(mtd); - void __iomem *mmio_base = this->IO_ADDR_R; + void __iomem *mmio_base = this->legacy.IO_ADDR_R; ecc = readl(mmio_base + MM_NAND_STS); @@ -208,20 +199,20 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) new_mtd->owner = THIS_MODULE; /* map physical address */ - this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096); - if (!this->IO_ADDR_R) { + this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = ioremap(adr, 4096); + if (!this->legacy.IO_ADDR_R) { pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr); err = -EIO; goto out_mtd; } - this->cmd_ctrl = cs553x_hwcontrol; - this->dev_ready = cs553x_device_ready; - this->read_byte = cs553x_read_byte; - this->read_buf = cs553x_read_buf; - this->write_buf = cs553x_write_buf; + this->legacy.cmd_ctrl = cs553x_hwcontrol; + this->legacy.dev_ready = cs553x_device_ready; + this->legacy.read_byte = cs553x_read_byte; + this->legacy.read_buf = cs553x_read_buf; + this->legacy.write_buf = cs553x_write_buf; - this->chip_delay = 0; + this->legacy.chip_delay = 0; this->ecc.mode = NAND_ECC_HW; this->ecc.size = 256; @@ -241,7 +232,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) } /* Scan to find existence of the device */ - err = nand_scan(new_mtd, 1); + err = nand_scan(this, 1); if (err) goto out_free; @@ -251,7 +242,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) out_free: kfree(new_mtd->name); out_ior: - iounmap(this->IO_ADDR_R); + iounmap(this->legacy.IO_ADDR_R); out_mtd: kfree(this); out: @@ -333,10 +324,10 @@ static void __exit cs553x_cleanup(void) continue; this = mtd_to_nand(mtd); - mmio_base = this->IO_ADDR_R; + mmio_base = this->legacy.IO_ADDR_R; /* Release resources, unregister device */ - nand_release(mtd); + nand_release(this); kfree(mtd->name); cs553x_mtd[i] = NULL; diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 40145e206a6b..80f228d23cd2 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -97,12 +97,11 @@ static inline void davinci_nand_writel(struct davinci_nand_info *info, * Access to hardware control lines: ALE, CLE, secondary chipselect. */ -static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, +static void nand_davinci_hwcontrol(struct nand_chip *nand, int cmd, unsigned int ctrl) { - struct davinci_nand_info *info = to_davinci_nand(mtd); + struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand)); void __iomem *addr = info->current_cs; - struct nand_chip *nand = mtd_to_nand(mtd); /* Did the control lines change? */ if (ctrl & NAND_CTRL_CHANGE) { @@ -111,16 +110,16 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE) addr += info->mask_ale; - nand->IO_ADDR_W = addr; + nand->legacy.IO_ADDR_W = addr; } if (cmd != NAND_CMD_NONE) - iowrite8(cmd, nand->IO_ADDR_W); + iowrite8(cmd, nand->legacy.IO_ADDR_W); } -static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) +static void nand_davinci_select_chip(struct nand_chip *nand, int chip) { - struct davinci_nand_info *info = to_davinci_nand(mtd); + struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand)); info->current_cs = info->vaddr; @@ -128,8 +127,8 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) if (chip > 0) info->current_cs += info->mask_chipsel; - info->chip.IO_ADDR_W = info->current_cs; - info->chip.IO_ADDR_R = info->chip.IO_ADDR_W; + info->chip.legacy.IO_ADDR_W = info->current_cs; + info->chip.legacy.IO_ADDR_R = info->chip.legacy.IO_ADDR_W; } /*----------------------------------------------------------------------*/ @@ -146,16 +145,16 @@ static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd) + 4 * info->core_chipsel); } -static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode) +static void nand_davinci_hwctl_1bit(struct nand_chip *chip, int mode) { struct davinci_nand_info *info; uint32_t nandcfr; unsigned long flags; - info = to_davinci_nand(mtd); + info = to_davinci_nand(nand_to_mtd(chip)); /* Reset ECC hardware */ - nand_davinci_readecc_1bit(mtd); + nand_davinci_readecc_1bit(nand_to_mtd(chip)); spin_lock_irqsave(&davinci_nand_lock, flags); @@ -170,10 +169,10 @@ static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode) /* * Read hardware ECC value and pack into three bytes */ -static int nand_davinci_calculate_1bit(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) +static int nand_davinci_calculate_1bit(struct nand_chip *chip, + const u_char *dat, u_char *ecc_code) { - unsigned int ecc_val = nand_davinci_readecc_1bit(mtd); + unsigned int ecc_val = nand_davinci_readecc_1bit(nand_to_mtd(chip)); unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4); /* invert so that erased block ecc is correct */ @@ -185,10 +184,9 @@ static int nand_davinci_calculate_1bit(struct mtd_info *mtd, return 0; } -static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, +static int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { - struct nand_chip *chip = mtd_to_nand(mtd); uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) | @@ -231,9 +229,9 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, * OOB without recomputing ECC. */ -static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode) +static void nand_davinci_hwctl_4bit(struct nand_chip *chip, int mode) { - struct davinci_nand_info *info = to_davinci_nand(mtd); + struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip)); unsigned long flags; u32 val; @@ -266,10 +264,10 @@ nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4]) } /* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */ -static int nand_davinci_calculate_4bit(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) +static int nand_davinci_calculate_4bit(struct nand_chip *chip, + const u_char *dat, u_char *ecc_code) { - struct davinci_nand_info *info = to_davinci_nand(mtd); + struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip)); u32 raw_ecc[4], *p; unsigned i; @@ -303,11 +301,11 @@ static int nand_davinci_calculate_4bit(struct mtd_info *mtd, /* Correct up to 4 bits in data we just read, using state left in the * hardware plus the ecc_code computed when it was first written. */ -static int nand_davinci_correct_4bit(struct mtd_info *mtd, - u_char *data, u_char *ecc_code, u_char *null) +static int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data, + u_char *ecc_code, u_char *null) { int i; - struct davinci_nand_info *info = to_davinci_nand(mtd); + struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip)); unsigned short ecc10[8]; unsigned short *ecc16; u32 syndrome[4]; @@ -436,38 +434,35 @@ correct: * the two LSBs for NAND access ... so we can issue 32-bit reads/writes * and have that transparently morphed into multiple NAND operations. */ -static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void nand_davinci_read_buf(struct nand_chip *chip, uint8_t *buf, + int len) { - struct nand_chip *chip = mtd_to_nand(mtd); - if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0) - ioread32_rep(chip->IO_ADDR_R, buf, len >> 2); + ioread32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2); else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0) - ioread16_rep(chip->IO_ADDR_R, buf, len >> 1); + ioread16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1); else - ioread8_rep(chip->IO_ADDR_R, buf, len); + ioread8_rep(chip->legacy.IO_ADDR_R, buf, len); } -static void nand_davinci_write_buf(struct mtd_info *mtd, - const uint8_t *buf, int len) +static void nand_davinci_write_buf(struct nand_chip *chip, const uint8_t *buf, + int len) { - struct nand_chip *chip = mtd_to_nand(mtd); - if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0) - iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2); + iowrite32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2); else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0) - iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1); + iowrite16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1); else - iowrite8_rep(chip->IO_ADDR_R, buf, len); + iowrite8_rep(chip->legacy.IO_ADDR_R, buf, len); } /* * Check hardware register for wait status. Returns 1 if device is ready, * 0 if it is still busy. */ -static int nand_davinci_dev_ready(struct mtd_info *mtd) +static int nand_davinci_dev_ready(struct nand_chip *chip) { - struct davinci_nand_info *info = to_davinci_nand(mtd); + struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip)); return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0); } @@ -764,9 +759,9 @@ static int nand_davinci_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; nand_set_flash_node(&info->chip, pdev->dev.of_node); - info->chip.IO_ADDR_R = vaddr; - info->chip.IO_ADDR_W = vaddr; - info->chip.chip_delay = 0; + info->chip.legacy.IO_ADDR_R = vaddr; + info->chip.legacy.IO_ADDR_W = vaddr; + info->chip.legacy.chip_delay = 0; info->chip.select_chip = nand_davinci_select_chip; /* options such as NAND_BBT_USE_FLASH */ @@ -786,12 +781,12 @@ static int nand_davinci_probe(struct platform_device *pdev) info->mask_cle = pdata->mask_cle ? : MASK_CLE; /* Set address of hardware control function */ - info->chip.cmd_ctrl = nand_davinci_hwcontrol; - info->chip.dev_ready = nand_davinci_dev_ready; + info->chip.legacy.cmd_ctrl = nand_davinci_hwcontrol; + info->chip.legacy.dev_ready = nand_davinci_dev_ready; /* Speed up buffer I/O */ - info->chip.read_buf = nand_davinci_read_buf; - info->chip.write_buf = nand_davinci_write_buf; + info->chip.legacy.read_buf = nand_davinci_read_buf; + info->chip.legacy.write_buf = nand_davinci_write_buf; /* Use board-specific ECC config */ info->chip.ecc.mode = pdata->ecc_mode; @@ -807,7 +802,7 @@ static int nand_davinci_probe(struct platform_device *pdev) /* Scan to find existence of the device(s) */ info->chip.dummy_controller.ops = &davinci_nand_controller_ops; - ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1); + ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1); if (ret < 0) { dev_dbg(&pdev->dev, "no NAND chip(s) found\n"); return ret; @@ -841,7 +836,7 @@ static int nand_davinci_remove(struct platform_device *pdev) ecc4_busy = false; spin_unlock_irq(&davinci_nand_lock); - nand_release(nand_to_mtd(&info->chip)); + nand_release(&info->chip); return 0; } diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index b864b93dd289..830ea247277b 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * NAND Flash Controller Device Driver * Copyright © 2009-2010, Intel Corporation and its suppliers. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * Copyright (c) 2017 Socionext Inc. + * Reworked by Masahiro Yamada <yamada.masahiro@socionext.com> */ #include <linux/bitfield.h> @@ -25,9 +20,8 @@ #include "denali.h" -MODULE_LICENSE("GPL"); - #define DENALI_NAND_NAME "denali-nand" +#define DENALI_DEFAULT_OOB_SKIP_BYTES 8 /* for Indexed Addressing */ #define DENALI_INDEXED_CTRL 0x00 @@ -222,8 +216,9 @@ static uint32_t denali_check_irq(struct denali_nand_info *denali) return irq_status; } -static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { + struct mtd_info *mtd = nand_to_mtd(chip); struct denali_nand_info *denali = mtd_to_denali(mtd); u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); int i; @@ -232,9 +227,10 @@ static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) buf[i] = denali->host_read(denali, addr); } -static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf, + int len) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); int i; @@ -242,9 +238,9 @@ static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) denali->host_write(denali, addr, buf[i]); } -static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); uint16_t *buf16 = (uint16_t *)buf; int i; @@ -253,10 +249,10 @@ static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) buf16[i] = denali->host_read(denali, addr); } -static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, +static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf, int len) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); const uint16_t *buf16 = (const uint16_t *)buf; int i; @@ -265,32 +261,23 @@ static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, denali->host_write(denali, addr, buf16[i]); } -static uint8_t denali_read_byte(struct mtd_info *mtd) +static uint8_t denali_read_byte(struct nand_chip *chip) { uint8_t byte; - denali_read_buf(mtd, &byte, 1); + denali_read_buf(chip, &byte, 1); return byte; } -static void denali_write_byte(struct mtd_info *mtd, uint8_t byte) -{ - denali_write_buf(mtd, &byte, 1); -} - -static uint16_t denali_read_word(struct mtd_info *mtd) +static void denali_write_byte(struct nand_chip *chip, uint8_t byte) { - uint16_t word; - - denali_read_buf16(mtd, (uint8_t *)&word, 2); - - return word; + denali_write_buf(chip, &byte, 1); } -static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); uint32_t type; if (ctrl & NAND_CLE) @@ -301,7 +288,8 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) return; /* - * Some commands are followed by chip->dev_ready or chip->waitfunc. + * Some commands are followed by chip->legacy.dev_ready or + * chip->legacy.waitfunc. * irq_status must be cleared here to catch the R/B# interrupt later. */ if (ctrl & NAND_CTRL_CHANGE) @@ -310,9 +298,9 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) denali->host_write(denali, DENALI_BANK(denali) | type, dat); } -static int denali_dev_ready(struct mtd_info *mtd) +static int denali_dev_ready(struct nand_chip *chip) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); return !!(denali_check_irq(denali) & INTR__INT_ACT); } @@ -698,9 +686,10 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, false); } -static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct denali_nand_info *denali = mtd_to_denali(mtd); int writesize = mtd->writesize; int oobsize = mtd->oobsize; @@ -773,17 +762,18 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int denali_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + denali_oob_xfer(mtd, chip, page, 0); return 0; } -static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int denali_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct denali_nand_info *denali = mtd_to_denali(mtd); denali_reset_irq(denali); @@ -793,9 +783,10 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, return nand_prog_page_end_op(chip); } -static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int denali_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct denali_nand_info *denali = mtd_to_denali(mtd); unsigned long uncor_ecc_flags = 0; int stat = 0; @@ -814,7 +805,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, return stat; if (uncor_ecc_flags) { - ret = denali_read_oob(mtd, chip, page); + ret = denali_read_oob(chip, page); if (ret) return ret; @@ -825,9 +816,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, return stat; } -static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct denali_nand_info *denali = mtd_to_denali(mtd); int writesize = mtd->writesize; int oobsize = mtd->oobsize; @@ -903,25 +895,26 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return denali_data_xfer(denali, tmp_buf, size, page, 1, 1); } -static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int denali_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct denali_nand_info *denali = mtd_to_denali(mtd); return denali_data_xfer(denali, (void *)buf, mtd->writesize, page, 0, 1); } -static void denali_select_chip(struct mtd_info *mtd, int chip) +static void denali_select_chip(struct nand_chip *chip, int cs) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); - denali->active_bank = chip; + denali->active_bank = cs; } -static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +static int denali_waitfunc(struct nand_chip *chip) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); uint32_t irq_status; /* R/B# pin transitioned from low to high? */ @@ -930,9 +923,9 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; } -static int denali_erase(struct mtd_info *mtd, int page) +static int denali_erase(struct nand_chip *chip, int page) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); uint32_t irq_status; denali_reset_irq(denali); @@ -947,10 +940,10 @@ static int denali_erase(struct mtd_info *mtd, int page) return irq_status & INTR__ERASE_COMP ? 0 : -EIO; } -static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, +static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, const struct nand_data_interface *conf) { - struct denali_nand_info *denali = mtd_to_denali(mtd); + struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip)); const struct nand_sdr_timings *timings; unsigned long t_x, mult_x; int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; @@ -1105,12 +1098,17 @@ static void denali_hw_init(struct denali_nand_info *denali) denali->revision = swab16(ioread32(denali->reg + REVISION)); /* - * tell driver how many bit controller will skip before - * writing ECC code in OOB, this register may be already - * set by firmware. So we read this value out. - * if this value is 0, just let it be. + * Set how many bytes should be skipped before writing data in OOB. + * If a non-zero value has already been set (by firmware or something), + * just use it. Otherwise, set the driver default. */ denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES); + if (!denali->oob_skip_bytes) { + denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES; + iowrite32(denali->oob_skip_bytes, + denali->reg + SPARE_AREA_SKIP_BYTES); + } + denali_detect_max_banks(denali); iowrite32(0x0F, denali->reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); @@ -1277,11 +1275,11 @@ static int denali_attach_chip(struct nand_chip *chip) mtd_set_ooblayout(mtd, &denali_ooblayout_ops); if (chip->options & NAND_BUSWIDTH_16) { - chip->read_buf = denali_read_buf16; - chip->write_buf = denali_write_buf16; + chip->legacy.read_buf = denali_read_buf16; + chip->legacy.write_buf = denali_write_buf16; } else { - chip->read_buf = denali_read_buf; - chip->write_buf = denali_write_buf; + chip->legacy.read_buf = denali_read_buf; + chip->legacy.write_buf = denali_write_buf; } chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; @@ -1289,7 +1287,7 @@ static int denali_attach_chip(struct nand_chip *chip) chip->ecc.write_page_raw = denali_write_page_raw; chip->ecc.read_oob = denali_read_oob; chip->ecc.write_oob = denali_write_oob; - chip->erase = denali_erase; + chip->legacy.erase = denali_erase; ret = denali_multidev_fixup(denali); if (ret) @@ -1358,12 +1356,11 @@ int denali_init(struct denali_nand_info *denali) mtd->name = "denali-nand"; chip->select_chip = denali_select_chip; - chip->read_byte = denali_read_byte; - chip->write_byte = denali_write_byte; - chip->read_word = denali_read_word; - chip->cmd_ctrl = denali_cmd_ctrl; - chip->dev_ready = denali_dev_ready; - chip->waitfunc = denali_waitfunc; + chip->legacy.read_byte = denali_read_byte; + chip->legacy.write_byte = denali_write_byte; + chip->legacy.cmd_ctrl = denali_cmd_ctrl; + chip->legacy.dev_ready = denali_dev_ready; + chip->legacy.waitfunc = denali_waitfunc; if (features & FEATURES__INDEX_ADDR) { denali->host_read = denali_indexed_read; @@ -1378,7 +1375,7 @@ int denali_init(struct denali_nand_info *denali) chip->setup_data_interface = denali_setup_data_interface; chip->dummy_controller.ops = &denali_controller_ops; - ret = nand_scan(mtd, denali->max_banks); + ret = nand_scan(chip, denali->max_banks); if (ret) goto disable_irq; @@ -1401,9 +1398,11 @@ EXPORT_SYMBOL(denali_init); void denali_remove(struct denali_nand_info *denali) { - struct mtd_info *mtd = nand_to_mtd(&denali->nand); - - nand_release(mtd); + nand_release(&denali->nand); denali_disable_irq(denali); } EXPORT_SYMBOL(denali_remove); + +MODULE_DESCRIPTION("Driver core for Denali NAND controller"); +MODULE_AUTHOR("Intel Corporation and its suppliers"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index 1f8feaf924eb..57a5498f58bb 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * NAND Flash Controller Device Driver * Copyright (c) 2009 - 2010, Intel Corporation and its suppliers. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DENALI_H__ diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 0faaad032e5f..7c6a8a426606 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * NAND Flash Controller Device Driver for DT * * Copyright © 2011, Picochip. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include <linux/clk.h> @@ -202,6 +194,6 @@ static struct platform_driver denali_dt_driver = { }; module_platform_driver(denali_dt_driver); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jamie Iles"); MODULE_DESCRIPTION("DT driver for Denali NAND controller"); diff --git a/drivers/mtd/nand/raw/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c index 7c8efc4c7bdf..48e9ac54ad53 100644 --- a/drivers/mtd/nand/raw/denali_pci.c +++ b/drivers/mtd/nand/raw/denali_pci.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * NAND Flash Controller Device Driver * Copyright © 2009-2010, Intel Corporation and its suppliers. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include <linux/errno.h> diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 3c46188dd6d2..3a4c373affab 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -83,9 +83,9 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, +static void doc200x_hwcontrol(struct nand_chip *this, int cmd, unsigned int bitmask); -static void doc200x_select_chip(struct mtd_info *mtd, int chip); +static void doc200x_select_chip(struct nand_chip *this, int chip); static int debug = 0; module_param(debug, int, 0); @@ -290,9 +290,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc) return ret; } -static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) +static void doc2000_write_byte(struct nand_chip *this, u_char datum) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -302,9 +301,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) WriteDOC(datum, docptr, 2k_CDSN_IO); } -static u_char doc2000_read_byte(struct mtd_info *mtd) +static u_char doc2000_read_byte(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; u_char ret; @@ -317,9 +315,9 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) return ret; } -static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len) +static void doc2000_writebuf(struct nand_chip *this, const u_char *buf, + int len) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -334,9 +332,8 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len) printk("\n"); } -static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len) +static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -344,14 +341,12 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len) if (debug) printk("readbuf of %d bytes: ", len); - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i); - } } -static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len) +static void doc2000_readbuf_dword(struct nand_chip *this, u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -376,19 +371,19 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) struct doc_priv *doc = nand_get_controller_data(this); uint16_t ret; - doc200x_select_chip(mtd, nr); - doc200x_hwcontrol(mtd, NAND_CMD_READID, + doc200x_select_chip(this, nr); + doc200x_hwcontrol(this, NAND_CMD_READID, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); - doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* We can't use dev_ready here, but at least we wait for the * command to complete */ udelay(50); - ret = this->read_byte(mtd) << 8; - ret |= this->read_byte(mtd); + ret = this->legacy.read_byte(this) << 8; + ret |= this->legacy.read_byte(this); if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) { /* First chip probe. See if we get same results by 32-bit access */ @@ -398,10 +393,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) } ident; void __iomem *docptr = doc->virtadr; - doc200x_hwcontrol(mtd, NAND_CMD_READID, + doc200x_hwcontrol(this, NAND_CMD_READID, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); - doc200x_hwcontrol(mtd, NAND_CMD_NONE, + doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); udelay(50); @@ -409,7 +404,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) ident.dword = readl(docptr + DoC_2k_CDSN_IO); if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { pr_info("DiskOnChip 2000 responds to DWORD access\n"); - this->read_buf = &doc2000_readbuf_dword; + this->legacy.read_buf = &doc2000_readbuf_dword; } } @@ -438,7 +433,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd) pr_debug("Detected %d chips per floor.\n", i); } -static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this) +static int doc200x_wait(struct nand_chip *this) { struct doc_priv *doc = nand_get_controller_data(this); @@ -447,14 +442,13 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this) DoC_WaitReady(doc); nand_status_op(this, NULL); DoC_WaitReady(doc); - status = (int)this->read_byte(mtd); + status = (int)this->legacy.read_byte(this); return status; } -static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) +static void doc2001_write_byte(struct nand_chip *this, u_char datum) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -463,9 +457,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) WriteDOC(datum, docptr, WritePipeTerm); } -static u_char doc2001_read_byte(struct mtd_info *mtd) +static u_char doc2001_read_byte(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -477,9 +470,8 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) return ReadDOC(docptr, LastDataRead); } -static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len) +static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -490,9 +482,8 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len) WriteDOC(0x00, docptr, WritePipeTerm); } -static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len) +static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -507,9 +498,8 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len) buf[i] = ReadDOC(docptr, LastDataRead); } -static u_char doc2001plus_read_byte(struct mtd_info *mtd) +static u_char doc2001plus_read_byte(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; u_char ret; @@ -522,9 +512,8 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) return ret; } -static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len) +static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -540,9 +529,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le printk("\n"); } -static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len) +static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -571,9 +559,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len) printk("\n"); } -static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) +static void doc2001plus_select_chip(struct nand_chip *this, int chip) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int floor = 0; @@ -598,9 +585,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) doc->curfloor = floor; } -static void doc200x_select_chip(struct mtd_info *mtd, int chip) +static void doc200x_select_chip(struct nand_chip *this, int chip) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int floor = 0; @@ -615,12 +601,12 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) chip -= (floor * doc->chips_per_floor); /* 11.4.4 -- deassert CE before changing chip */ - doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + doc200x_hwcontrol(this, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); WriteDOC(floor, docptr, FloorSelect); WriteDOC(chip, docptr, CDSNDeviceSelect); - doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); doc->curchip = chip; doc->curfloor = floor; @@ -628,10 +614,9 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) #define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE) -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, +static void doc200x_hwcontrol(struct nand_chip *this, int cmd, unsigned int ctrl) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -646,15 +631,16 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, } if (cmd != NAND_CMD_NONE) { if (DoC_is_2000(doc)) - doc2000_write_byte(mtd, cmd); + doc2000_write_byte(this, cmd); else - doc2001_write_byte(mtd, cmd); + doc2001_write_byte(this, cmd); } } -static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void doc2001plus_command(struct nand_chip *this, unsigned command, + int column, int page_addr) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -729,13 +715,13 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->legacy.dev_ready) break; - udelay(this->chip_delay); + udelay(this->legacy.chip_delay); WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd); WriteDOC(0, docptr, Mplus_WritePipeTerm); WriteDOC(0, docptr, Mplus_WritePipeTerm); - while (!(this->read_byte(mtd) & 0x40)) ; + while (!(this->legacy.read_byte(this) & 0x40)) ; return; /* This applies to read commands */ @@ -744,8 +730,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu * If we don't have access to the busy pin, we apply the given * command delay */ - if (!this->dev_ready) { - udelay(this->chip_delay); + if (!this->legacy.dev_ready) { + udelay(this->legacy.chip_delay); return; } } @@ -754,12 +740,11 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu * any case on any machine. */ ndelay(100); /* wait until command is processed */ - while (!this->dev_ready(mtd)) ; + while (!this->legacy.dev_ready(this)) ; } -static int doc200x_dev_ready(struct mtd_info *mtd) +static int doc200x_dev_ready(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -790,16 +775,15 @@ static int doc200x_dev_ready(struct mtd_info *mtd) } } -static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs) +static int doc200x_block_bad(struct nand_chip *this, loff_t ofs) { /* This is our last resort if we couldn't find or create a BBT. Just pretend all blocks are good. */ return 0; } -static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) +static void doc200x_enable_hwecc(struct nand_chip *this, int mode) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -816,9 +800,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) } } -static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) +static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; @@ -836,9 +819,9 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) } /* This code is only called on write */ -static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code) +static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat, + unsigned char *ecc_code) { - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; int i; @@ -895,11 +878,10 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsign return 0; } -static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, +static int doc200x_correct_data(struct nand_chip *this, u_char *dat, u_char *read_ecc, u_char *isnull) { int i, ret = 0; - struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); void __iomem *docptr = doc->virtadr; uint8_t calc_ecc[6]; @@ -1357,9 +1339,9 @@ static inline int __init doc2000_init(struct mtd_info *mtd) struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); - this->read_byte = doc2000_read_byte; - this->write_buf = doc2000_writebuf; - this->read_buf = doc2000_readbuf; + this->legacy.read_byte = doc2000_read_byte; + this->legacy.write_buf = doc2000_writebuf; + this->legacy.read_buf = doc2000_readbuf; doc->late_init = nftl_scan_bbt; doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO; @@ -1373,9 +1355,9 @@ static inline int __init doc2001_init(struct mtd_info *mtd) struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); - this->read_byte = doc2001_read_byte; - this->write_buf = doc2001_writebuf; - this->read_buf = doc2001_readbuf; + this->legacy.read_byte = doc2001_read_byte; + this->legacy.write_buf = doc2001_writebuf; + this->legacy.read_buf = doc2001_readbuf; ReadDOC(doc->virtadr, ChipID); ReadDOC(doc->virtadr, ChipID); @@ -1403,13 +1385,13 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd) struct nand_chip *this = mtd_to_nand(mtd); struct doc_priv *doc = nand_get_controller_data(this); - this->read_byte = doc2001plus_read_byte; - this->write_buf = doc2001plus_writebuf; - this->read_buf = doc2001plus_readbuf; + this->legacy.read_byte = doc2001plus_read_byte; + this->legacy.write_buf = doc2001plus_writebuf; + this->legacy.read_buf = doc2001plus_readbuf; doc->late_init = inftl_scan_bbt; - this->cmd_ctrl = NULL; + this->legacy.cmd_ctrl = NULL; this->select_chip = doc2001plus_select_chip; - this->cmdfunc = doc2001plus_command; + this->legacy.cmdfunc = doc2001plus_command; this->ecc.hwctl = doc2001plus_enable_hwecc; doc->chips_per_floor = 1; @@ -1587,10 +1569,10 @@ static int __init doc_probe(unsigned long physadr) nand_set_controller_data(nand, doc); nand->select_chip = doc200x_select_chip; - nand->cmd_ctrl = doc200x_hwcontrol; - nand->dev_ready = doc200x_dev_ready; - nand->waitfunc = doc200x_wait; - nand->block_bad = doc200x_block_bad; + nand->legacy.cmd_ctrl = doc200x_hwcontrol; + nand->legacy.dev_ready = doc200x_dev_ready; + nand->legacy.waitfunc = doc200x_wait; + nand->legacy.block_bad = doc200x_block_bad; nand->ecc.hwctl = doc200x_enable_hwecc; nand->ecc.calculate = doc200x_calculate_ecc; nand->ecc.correct = doc200x_correct_data; @@ -1620,14 +1602,14 @@ static int __init doc_probe(unsigned long physadr) else numchips = doc2001_init(mtd); - if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) { + if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) { /* DBB note: i believe nand_release is necessary here, as buffers may have been allocated in nand_base. Check with Thomas. FIX ME! */ /* nand_release will call mtd_device_unregister, but we haven't yet added it. This is handled without incident by mtd_device_unregister, as far as I can tell. */ - nand_release(mtd); + nand_release(nand); goto fail; } @@ -1662,7 +1644,7 @@ static void release_nanddoc(void) doc = nand_get_controller_data(nand); nextmtd = doc->nextdoc; - nand_release(mtd); + nand_release(nand); iounmap(doc->virtadr); release_mem_region(doc->physadr, DOC_IOREMAP_LEN); free_rs(doc->rs_decoder); diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c deleted file mode 100644 index 427fcbc1b71c..000000000000 --- a/drivers/mtd/nand/raw/docg4.c +++ /dev/null @@ -1,1442 +0,0 @@ -/* - * Copyright © 2012 Mike Dunn <mikedunn@newsguy.com> - * - * mtd nand driver for M-Systems DiskOnChip G4 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Tested on the Palm Treo 680. The G4 is also present on Toshiba Portege, Asus - * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others. - * Should work on these as well. Let me know! - * - * TODO: - * - * Mechanism for management of password-protected areas - * - * Hamming ecc when reading oob only - * - * According to the M-Sys documentation, this device is also available in a - * "dual-die" configuration having a 256MB capacity, but no mechanism for - * detecting this variant is documented. Currently this driver assumes 128MB - * capacity. - * - * Support for multiple cascaded devices ("floors"). Not sure which gadgets - * contain multiple G4s in a cascaded configuration, if any. - * - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/export.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/bitops.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/rawnand.h> -#include <linux/bch.h> -#include <linux/bitrev.h> -#include <linux/jiffies.h> - -/* - * In "reliable mode" consecutive 2k pages are used in parallel (in some - * fashion) to store the same data. The data can be read back from the - * even-numbered pages in the normal manner; odd-numbered pages will appear to - * contain junk. Systems that boot from the docg4 typically write the secondary - * program loader (SPL) code in this mode. The SPL is loaded by the initial - * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped - * to the reset vector address). This module parameter enables you to use this - * driver to write the SPL. When in this mode, no more than 2k of data can be - * written at a time, because the addresses do not increment in the normal - * manner, and the starting offset must be within an even-numbered 2k region; - * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800, - * 0x1a00, ... Reliable mode is a special case and should not be used unless - * you know what you're doing. - */ -static bool reliable_mode; -module_param(reliable_mode, bool, 0); -MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode"); - -/* - * You'll want to ignore badblocks if you're reading a partition that contains - * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since - * it does not use mtd nand's method for marking bad blocks (using oob area). - * This will also skip the check of the "page written" flag. - */ -static bool ignore_badblocks; -module_param(ignore_badblocks, bool, 0); -MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed"); - -struct docg4_priv { - struct mtd_info *mtd; - struct device *dev; - void __iomem *virtadr; - int status; - struct { - unsigned int command; - int column; - int page; - } last_command; - uint8_t oob_buf[16]; - uint8_t ecc_buf[7]; - int oob_page; - struct bch_control *bch; -}; - -/* - * Defines prefixed with DOCG4 are unique to the diskonchip G4. All others are - * shared with other diskonchip devices (P3, G3 at least). - * - * Functions with names prefixed with docg4_ are mtd / nand interface functions - * (though they may also be called internally). All others are internal. - */ - -#define DOC_IOSPACE_DATA 0x0800 - -/* register offsets */ -#define DOC_CHIPID 0x1000 -#define DOC_DEVICESELECT 0x100a -#define DOC_ASICMODE 0x100c -#define DOC_DATAEND 0x101e -#define DOC_NOP 0x103e - -#define DOC_FLASHSEQUENCE 0x1032 -#define DOC_FLASHCOMMAND 0x1034 -#define DOC_FLASHADDRESS 0x1036 -#define DOC_FLASHCONTROL 0x1038 -#define DOC_ECCCONF0 0x1040 -#define DOC_ECCCONF1 0x1042 -#define DOC_HAMMINGPARITY 0x1046 -#define DOC_BCH_SYNDROM(idx) (0x1048 + idx) - -#define DOC_ASICMODECONFIRM 0x1072 -#define DOC_CHIPID_INV 0x1074 -#define DOC_POWERMODE 0x107c - -#define DOCG4_MYSTERY_REG 0x1050 - -/* apparently used only to write oob bytes 6 and 7 */ -#define DOCG4_OOB_6_7 0x1052 - -/* DOC_FLASHSEQUENCE register commands */ -#define DOC_SEQ_RESET 0x00 -#define DOCG4_SEQ_PAGE_READ 0x03 -#define DOCG4_SEQ_FLUSH 0x29 -#define DOCG4_SEQ_PAGEWRITE 0x16 -#define DOCG4_SEQ_PAGEPROG 0x1e -#define DOCG4_SEQ_BLOCKERASE 0x24 -#define DOCG4_SEQ_SETMODE 0x45 - -/* DOC_FLASHCOMMAND register commands */ -#define DOCG4_CMD_PAGE_READ 0x00 -#define DOC_CMD_ERASECYCLE2 0xd0 -#define DOCG4_CMD_FLUSH 0x70 -#define DOCG4_CMD_READ2 0x30 -#define DOC_CMD_PROG_BLOCK_ADDR 0x60 -#define DOCG4_CMD_PAGEWRITE 0x80 -#define DOC_CMD_PROG_CYCLE2 0x10 -#define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */ -#define DOC_CMD_RELIABLE_MODE 0x22 -#define DOC_CMD_RESET 0xff - -/* DOC_POWERMODE register bits */ -#define DOC_POWERDOWN_READY 0x80 - -/* DOC_FLASHCONTROL register bits */ -#define DOC_CTRL_CE 0x10 -#define DOC_CTRL_UNKNOWN 0x40 -#define DOC_CTRL_FLASHREADY 0x01 - -/* DOC_ECCCONF0 register bits */ -#define DOC_ECCCONF0_READ_MODE 0x8000 -#define DOC_ECCCONF0_UNKNOWN 0x2000 -#define DOC_ECCCONF0_ECC_ENABLE 0x1000 -#define DOC_ECCCONF0_DATA_BYTES_MASK 0x07ff - -/* DOC_ECCCONF1 register bits */ -#define DOC_ECCCONF1_BCH_SYNDROM_ERR 0x80 -#define DOC_ECCCONF1_ECC_ENABLE 0x07 -#define DOC_ECCCONF1_PAGE_IS_WRITTEN 0x20 - -/* DOC_ASICMODE register bits */ -#define DOC_ASICMODE_RESET 0x00 -#define DOC_ASICMODE_NORMAL 0x01 -#define DOC_ASICMODE_POWERDOWN 0x02 -#define DOC_ASICMODE_MDWREN 0x04 -#define DOC_ASICMODE_BDETCT_RESET 0x08 -#define DOC_ASICMODE_RSTIN_RESET 0x10 -#define DOC_ASICMODE_RAM_WE 0x20 - -/* good status values read after read/write/erase operations */ -#define DOCG4_PROGSTATUS_GOOD 0x51 -#define DOCG4_PROGSTATUS_GOOD_2 0xe0 - -/* - * On read operations (page and oob-only), the first byte read from I/O reg is a - * status. On error, it reads 0x73; otherwise, it reads either 0x71 (first read - * after reset only) or 0x51, so bit 1 is presumed to be an error indicator. - */ -#define DOCG4_READ_ERROR 0x02 /* bit 1 indicates read error */ - -/* anatomy of the device */ -#define DOCG4_CHIP_SIZE 0x8000000 -#define DOCG4_PAGE_SIZE 0x200 -#define DOCG4_PAGES_PER_BLOCK 0x200 -#define DOCG4_BLOCK_SIZE (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE) -#define DOCG4_NUMBLOCKS (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE) -#define DOCG4_OOB_SIZE 0x10 -#define DOCG4_CHIP_SHIFT 27 /* log_2(DOCG4_CHIP_SIZE) */ -#define DOCG4_PAGE_SHIFT 9 /* log_2(DOCG4_PAGE_SIZE) */ -#define DOCG4_ERASE_SHIFT 18 /* log_2(DOCG4_BLOCK_SIZE) */ - -/* all but the last byte is included in ecc calculation */ -#define DOCG4_BCH_SIZE (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1) - -#define DOCG4_USERDATA_LEN 520 /* 512 byte page plus 8 oob avail to user */ - -/* expected values from the ID registers */ -#define DOCG4_IDREG1_VALUE 0x0400 -#define DOCG4_IDREG2_VALUE 0xfbff - -/* primitive polynomial used to build the Galois field used by hw ecc gen */ -#define DOCG4_PRIMITIVE_POLY 0x4443 - -#define DOCG4_M 14 /* Galois field is of order 2^14 */ -#define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */ - -#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */ -#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */ - -/* - * Bytes 0, 1 are used as badblock marker. - * Bytes 2 - 6 are available to the user. - * Byte 7 is hamming ecc for first 7 oob bytes only. - * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14. - * Byte 15 (the last) is used by the driver as a "page written" flag. - */ -static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section) - return -ERANGE; - - oobregion->offset = 7; - oobregion->length = 9; - - return 0; -} - -static int docg4_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section) - return -ERANGE; - - oobregion->offset = 2; - oobregion->length = 5; - - return 0; -} - -static const struct mtd_ooblayout_ops docg4_ooblayout_ops = { - .ecc = docg4_ooblayout_ecc, - .free = docg4_ooblayout_free, -}; - -/* - * The device has a nop register which M-Sys claims is for the purpose of - * inserting precise delays. But beware; at least some operations fail if the - * nop writes are replaced with a generic delay! - */ -static inline void write_nop(void __iomem *docptr) -{ - writew(0, docptr + DOC_NOP); -} - -static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - struct nand_chip *nand = mtd_to_nand(mtd); - uint16_t *p = (uint16_t *) buf; - len >>= 1; - - for (i = 0; i < len; i++) - p[i] = readw(nand->IO_ADDR_R); -} - -static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *nand = mtd_to_nand(mtd); - uint16_t *p = (uint16_t *) buf; - len >>= 1; - - for (i = 0; i < len; i++) - writew(p[i], nand->IO_ADDR_W); -} - -static int poll_status(struct docg4_priv *doc) -{ - /* - * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL - * register. Operations known to take a long time (e.g., block erase) - * should sleep for a while before calling this. - */ - - uint16_t flash_status; - unsigned long timeo; - void __iomem *docptr = doc->virtadr; - - dev_dbg(doc->dev, "%s...\n", __func__); - - /* hardware quirk requires reading twice initially */ - flash_status = readw(docptr + DOC_FLASHCONTROL); - - timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */ - do { - cpu_relax(); - flash_status = readb(docptr + DOC_FLASHCONTROL); - } while (!(flash_status & DOC_CTRL_FLASHREADY) && - time_before(jiffies, timeo)); - - if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) { - dev_err(doc->dev, "%s: timed out!\n", __func__); - return NAND_STATUS_FAIL; - } - - return 0; -} - - -static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand) -{ - - struct docg4_priv *doc = nand_get_controller_data(nand); - int status = NAND_STATUS_WP; /* inverse logic?? */ - dev_dbg(doc->dev, "%s...\n", __func__); - - /* report any previously unreported error */ - if (doc->status) { - status |= doc->status; - doc->status = 0; - return status; - } - - status |= poll_status(doc); - return status; -} - -static void docg4_select_chip(struct mtd_info *mtd, int chip) -{ - /* - * Select among multiple cascaded chips ("floors"). Multiple floors are - * not yet supported, so the only valid non-negative value is 0. - */ - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - - dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip); - - if (chip < 0) - return; /* deselected */ - - if (chip > 0) - dev_warn(doc->dev, "multiple floors currently unsupported\n"); - - writew(0, docptr + DOC_DEVICESELECT); -} - -static void reset(struct mtd_info *mtd) -{ - /* full device reset */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - - writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN, - docptr + DOC_ASICMODE); - writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN), - docptr + DOC_ASICMODECONFIRM); - write_nop(docptr); - - writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN, - docptr + DOC_ASICMODE); - writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN), - docptr + DOC_ASICMODECONFIRM); - - writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1); - - poll_status(doc); -} - -static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf) -{ - /* read the 7 hw-generated ecc bytes */ - - int i; - for (i = 0; i < 7; i++) { /* hw quirk; read twice */ - ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i)); - ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i)); - } -} - -static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page) -{ - /* - * Called after a page read when hardware reports bitflips. - * Up to four bitflips can be corrected. - */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - int i, numerrs, errpos[4]; - const uint8_t blank_read_hwecc[8] = { - 0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 }; - - read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */ - - /* check if read error is due to a blank page */ - if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7)) - return 0; /* yes */ - - /* skip additional check of "written flag" if ignore_badblocks */ - if (ignore_badblocks == false) { - - /* - * If the hw ecc bytes are not those of a blank page, there's - * still a chance that the page is blank, but was read with - * errors. Check the "written flag" in last oob byte, which - * is set to zero when a page is written. If more than half - * the bits are set, assume a blank page. Unfortunately, the - * bit flips(s) are not reported in stats. - */ - - if (nand->oob_poi[15]) { - int bit, numsetbits = 0; - unsigned long written_flag = nand->oob_poi[15]; - for_each_set_bit(bit, &written_flag, 8) - numsetbits++; - if (numsetbits > 4) { /* assume blank */ - dev_warn(doc->dev, - "error(s) in blank page " - "at offset %08x\n", - page * DOCG4_PAGE_SIZE); - return 0; - } - } - } - - /* - * The hardware ecc unit produces oob_ecc ^ calc_ecc. The kernel's bch - * algorithm is used to decode this. However the hw operates on page - * data in a bit order that is the reverse of that of the bch alg, - * requiring that the bits be reversed on the result. Thanks to Ivan - * Djelic for his analysis! - */ - for (i = 0; i < 7; i++) - doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]); - - numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL, - doc->ecc_buf, NULL, errpos); - - if (numerrs == -EBADMSG) { - dev_warn(doc->dev, "uncorrectable errors at offset %08x\n", - page * DOCG4_PAGE_SIZE); - return -EBADMSG; - } - - BUG_ON(numerrs < 0); /* -EINVAL, or anything other than -EBADMSG */ - - /* undo last step in BCH alg (modulo mirroring not needed) */ - for (i = 0; i < numerrs; i++) - errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7)); - - /* fix the errors */ - for (i = 0; i < numerrs; i++) { - - /* ignore if error within oob ecc bytes */ - if (errpos[i] > DOCG4_USERDATA_LEN * 8) - continue; - - /* if error within oob area preceeding ecc bytes... */ - if (errpos[i] > DOCG4_PAGE_SIZE * 8) - change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8, - (unsigned long *)nand->oob_poi); - - else /* error in page data */ - change_bit(errpos[i], (unsigned long *)buf); - } - - dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n", - numerrs, page * DOCG4_PAGE_SIZE); - - return numerrs; -} - -static uint8_t docg4_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - - dev_dbg(doc->dev, "%s\n", __func__); - - if (doc->last_command.command == NAND_CMD_STATUS) { - int status; - - /* - * Previous nand command was status request, so nand - * infrastructure code expects to read the status here. If an - * error occurred in a previous operation, report it. - */ - doc->last_command.command = 0; - - if (doc->status) { - status = doc->status; - doc->status = 0; - } - - /* why is NAND_STATUS_WP inverse logic?? */ - else - status = NAND_STATUS_WP | NAND_STATUS_READY; - - return status; - } - - dev_warn(doc->dev, "unexpected call to read_byte()\n"); - - return 0; -} - -static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr) -{ - /* write the four address bytes packed in docg4_addr to the device */ - - void __iomem *docptr = doc->virtadr; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); -} - -static int read_progstatus(struct docg4_priv *doc) -{ - /* - * This apparently checks the status of programming. Done after an - * erasure, and after page data is written. On error, the status is - * saved, to be later retrieved by the nand infrastructure code. - */ - void __iomem *docptr = doc->virtadr; - - /* status is read from the I/O reg */ - uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA); - uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA); - uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG); - - dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n", - __func__, status1, status2, status3); - - if (status1 != DOCG4_PROGSTATUS_GOOD - || status2 != DOCG4_PROGSTATUS_GOOD_2 - || status3 != DOCG4_PROGSTATUS_GOOD_2) { - doc->status = NAND_STATUS_FAIL; - dev_warn(doc->dev, "read_progstatus failed: " - "%02x, %02x, %02x\n", status1, status2, status3); - return -EIO; - } - return 0; -} - -static int pageprog(struct mtd_info *mtd) -{ - /* - * Final step in writing a page. Writes the contents of its - * internal buffer out to the flash array, or some such. - */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - int retval = 0; - - dev_dbg(doc->dev, "docg4: %s\n", __func__); - - writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE); - writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - - /* Just busy-wait; usleep_range() slows things down noticeably. */ - poll_status(doc); - - writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND); - writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - retval = read_progstatus(doc); - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - poll_status(doc); - write_nop(docptr); - - return retval; -} - -static void sequence_reset(struct mtd_info *mtd) -{ - /* common starting sequence for all operations */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - - writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL); - writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE); - writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - poll_status(doc); - write_nop(docptr); -} - -static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr) -{ - /* first step in reading a page */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - - dev_dbg(doc->dev, - "docg4: %s: g4 page %08x\n", __func__, docg4_addr); - - sequence_reset(mtd); - - writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - - write_addr(doc, docg4_addr); - - write_nop(docptr); - writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - - poll_status(doc); -} - -static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr) -{ - /* first step in writing a page */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - - dev_dbg(doc->dev, - "docg4: %s: g4 addr: %x\n", __func__, docg4_addr); - sequence_reset(mtd); - - if (unlikely(reliable_mode)) { - writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND); - writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - } - - writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_addr(doc, docg4_addr); - write_nop(docptr); - write_nop(docptr); - poll_status(doc); -} - -static uint32_t mtd_to_docg4_address(int page, int column) -{ - /* - * Convert mtd address to format used by the device, 32 bit packed. - * - * Some notes on G4 addressing... The M-Sys documentation on this device - * claims that pages are 2K in length, and indeed, the format of the - * address used by the device reflects that. But within each page are - * four 512 byte "sub-pages", each with its own oob data that is - * read/written immediately after the 512 bytes of page data. This oob - * data contains the ecc bytes for the preceeding 512 bytes. - * - * Rather than tell the mtd nand infrastructure that page size is 2k, - * with four sub-pages each, we engage in a little subterfuge and tell - * the infrastructure code that pages are 512 bytes in size. This is - * done because during the course of reverse-engineering the device, I - * never observed an instance where an entire 2K "page" was read or - * written as a unit. Each "sub-page" is always addressed individually, - * its data read/written, and ecc handled before the next "sub-page" is - * addressed. - * - * This requires us to convert addresses passed by the mtd nand - * infrastructure code to those used by the device. - * - * The address that is written to the device consists of four bytes: the - * first two are the 2k page number, and the second is the index into - * the page. The index is in terms of 16-bit half-words and includes - * the preceeding oob data, so e.g., the index into the second - * "sub-page" is 0x108, and the full device address of the start of mtd - * page 0x201 is 0x00800108. - */ - int g4_page = page / 4; /* device's 2K page */ - int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */ - return (g4_page << 16) | g4_index; /* pack */ -} - -static void docg4_command(struct mtd_info *mtd, unsigned command, int column, - int page_addr) -{ - /* handle standard nand commands */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - uint32_t g4_addr = mtd_to_docg4_address(page_addr, column); - - dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n", - __func__, command, page_addr, column); - - /* - * Save the command and its arguments. This enables emulation of - * standard flash devices, and also some optimizations. - */ - doc->last_command.command = command; - doc->last_command.column = column; - doc->last_command.page = page_addr; - - switch (command) { - - case NAND_CMD_RESET: - reset(mtd); - break; - - case NAND_CMD_READ0: - read_page_prologue(mtd, g4_addr); - break; - - case NAND_CMD_STATUS: - /* next call to read_byte() will expect a status */ - break; - - case NAND_CMD_SEQIN: - if (unlikely(reliable_mode)) { - uint16_t g4_page = g4_addr >> 16; - - /* writes to odd-numbered 2k pages are invalid */ - if (g4_page & 0x01) - dev_warn(doc->dev, - "invalid reliable mode address\n"); - } - - write_page_prologue(mtd, g4_addr); - - /* hack for deferred write of oob bytes */ - if (doc->oob_page == page_addr) - memcpy(nand->oob_poi, doc->oob_buf, 16); - break; - - case NAND_CMD_PAGEPROG: - pageprog(mtd); - break; - - /* we don't expect these, based on review of nand_base.c */ - case NAND_CMD_READOOB: - case NAND_CMD_READID: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - dev_warn(doc->dev, "docg4_command: " - "unexpected nand command 0x%x\n", command); - break; - - } -} - -static int read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int page, bool use_ecc) -{ - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - uint16_t status, edc_err, *buf16; - int bits_corrected = 0; - - dev_dbg(doc->dev, "%s: page %08x\n", __func__, page); - - nand_read_page_op(nand, page, 0, NULL, 0); - - writew(DOC_ECCCONF0_READ_MODE | - DOC_ECCCONF0_ECC_ENABLE | - DOC_ECCCONF0_UNKNOWN | - DOCG4_BCH_SIZE, - docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - /* the 1st byte from the I/O reg is a status; the rest is page data */ - status = readw(docptr + DOC_IOSPACE_DATA); - if (status & DOCG4_READ_ERROR) { - dev_err(doc->dev, - "docg4_read_page: bad status: 0x%02x\n", status); - writew(0, docptr + DOC_DATAEND); - return -EIO; - } - - dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status); - - docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */ - - /* this device always reads oob after page data */ - /* first 14 oob bytes read from I/O reg */ - docg4_read_buf(mtd, nand->oob_poi, 14); - - /* last 2 read from another reg */ - buf16 = (uint16_t *)(nand->oob_poi + 14); - *buf16 = readw(docptr + DOCG4_MYSTERY_REG); - - write_nop(docptr); - - if (likely(use_ecc == true)) { - - /* read the register that tells us if bitflip(s) detected */ - edc_err = readw(docptr + DOC_ECCCONF1); - edc_err = readw(docptr + DOC_ECCCONF1); - dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err); - - /* If bitflips are reported, attempt to correct with ecc */ - if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) { - bits_corrected = correct_data(mtd, buf, page); - if (bits_corrected == -EBADMSG) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += bits_corrected; - } - } - - writew(0, docptr + DOC_DATAEND); - if (bits_corrected == -EBADMSG) /* uncorrectable errors */ - return 0; - return bits_corrected; -} - - -static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, int page) -{ - return read_page(mtd, nand, buf, page, false); -} - -static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, int page) -{ - return read_page(mtd, nand, buf, page, true); -} - -static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - uint16_t status; - - dev_dbg(doc->dev, "%s: page %x\n", __func__, page); - - nand_read_page_op(nand, page, nand->ecc.size, NULL, 0); - - writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - /* the 1st byte from the I/O reg is a status; the rest is oob data */ - status = readw(docptr + DOC_IOSPACE_DATA); - if (status & DOCG4_READ_ERROR) { - dev_warn(doc->dev, - "docg4_read_oob failed: status = 0x%02x\n", status); - return -EIO; - } - - dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status); - - docg4_read_buf(mtd, nand->oob_poi, 16); - - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - - return 0; -} - -static int docg4_erase_block(struct mtd_info *mtd, int page) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - uint16_t g4_page; - int status; - - dev_dbg(doc->dev, "%s: page %04x\n", __func__, page); - - sequence_reset(mtd); - - writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE); - writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - - /* only 2 bytes of address are written to specify erase block */ - g4_page = (uint16_t)(page / 4); /* to g4's 2k page addressing */ - writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS); - g4_page >>= 8; - writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS); - write_nop(docptr); - - /* start the erasure */ - writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - - usleep_range(500, 1000); /* erasure is long; take a snooze */ - poll_status(doc); - writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND); - writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - read_progstatus(doc); - - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - poll_status(doc); - write_nop(docptr); - - status = nand->waitfunc(mtd, nand); - if (status < 0) - return status; - - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -static int write_page(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int page, bool use_ecc) -{ - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - uint8_t ecc_buf[8]; - - dev_dbg(doc->dev, "%s...\n", __func__); - - nand_prog_page_begin_op(nand, page, 0, NULL, 0); - - writew(DOC_ECCCONF0_ECC_ENABLE | - DOC_ECCCONF0_UNKNOWN | - DOCG4_BCH_SIZE, - docptr + DOC_ECCCONF0); - write_nop(docptr); - - /* write the page data */ - docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE); - - /* oob bytes 0 through 5 are written to I/O reg */ - docg4_write_buf16(mtd, nand->oob_poi, 6); - - /* oob byte 6 written to a separate reg */ - writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7); - - write_nop(docptr); - write_nop(docptr); - - /* write hw-generated ecc bytes to oob */ - if (likely(use_ecc == true)) { - /* oob byte 7 is hamming code */ - uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY); - hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */ - writew(hamming, docptr + DOCG4_OOB_6_7); - write_nop(docptr); - - /* read the 7 bch bytes from ecc regs */ - read_hw_ecc(docptr, ecc_buf); - ecc_buf[7] = 0; /* clear the "page written" flag */ - } - - /* write user-supplied bytes to oob */ - else { - writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7); - write_nop(docptr); - memcpy(ecc_buf, &nand->oob_poi[8], 8); - } - - docg4_write_buf16(mtd, ecc_buf, 8); - write_nop(docptr); - write_nop(docptr); - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - - return nand_prog_page_end_op(nand); -} - -static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required, int page) -{ - return write_page(mtd, nand, buf, page, false); -} - -static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required, int page) -{ - return write_page(mtd, nand, buf, page, true); -} - -static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - /* - * Writing oob-only is not really supported, because MLC nand must write - * oob bytes at the same time as page data. Nonetheless, we save the - * oob buffer contents here, and then write it along with the page data - * if the same page is subsequently written. This allows user space - * utilities that write the oob data prior to the page data to work - * (e.g., nandwrite). The disdvantage is that, if the intention was to - * write oob only, the operation is quietly ignored. Also, oob can get - * corrupted if two concurrent processes are running nandwrite. - */ - - /* note that bytes 7..14 are hw generated hamming/ecc and overwritten */ - struct docg4_priv *doc = nand_get_controller_data(nand); - doc->oob_page = page; - memcpy(doc->oob_buf, nand->oob_poi, 16); - return 0; -} - -static int __init read_factory_bbt(struct mtd_info *mtd) -{ - /* - * The device contains a read-only factory bad block table. Read it and - * update the memory-based bbt accordingly. - */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0); - uint8_t *buf; - int i, block; - __u32 eccfailed_stats = mtd->ecc_stats.failed; - - buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - read_page_prologue(mtd, g4_addr); - docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); - - /* - * If no memory-based bbt was created, exit. This will happen if module - * parameter ignore_badblocks is set. Then why even call this function? - * For an unknown reason, block erase always fails if it's the first - * operation after device power-up. The above read ensures it never is. - * Ugly, I know. - */ - if (nand->bbt == NULL) /* no memory-based bbt */ - goto exit; - - if (mtd->ecc_stats.failed > eccfailed_stats) { - /* - * Whoops, an ecc failure ocurred reading the factory bbt. - * It is stored redundantly, so we get another chance. - */ - eccfailed_stats = mtd->ecc_stats.failed; - docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE); - if (mtd->ecc_stats.failed > eccfailed_stats) { - dev_warn(doc->dev, - "The factory bbt could not be read!\n"); - goto exit; - } - } - - /* - * Parse factory bbt and update memory-based bbt. Factory bbt format is - * simple: one bit per block, block numbers increase left to right (msb - * to lsb). Bit clear means bad block. - */ - for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) { - int bitnum; - unsigned long bits = ~buf[i]; - for_each_set_bit(bitnum, &bits, 8) { - int badblock = block + 7 - bitnum; - nand->bbt[badblock / 4] |= - 0x03 << ((badblock % 4) * 2); - mtd->ecc_stats.badblocks++; - dev_notice(doc->dev, "factory-marked bad block: %d\n", - badblock); - } - } - exit: - kfree(buf); - return 0; -} - -static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - /* - * Mark a block as bad. Bad blocks are marked in the oob area of the - * first page of the block. The default scan_bbt() in the nand - * infrastructure code works fine for building the memory-based bbt - * during initialization, as does the nand infrastructure function that - * checks if a block is bad by reading the bbt. This function replaces - * the nand default because writes to oob-only are not supported. - */ - - int ret, i; - uint8_t *buf; - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - struct nand_bbt_descr *bbtd = nand->badblock_pattern; - int page = (int)(ofs >> nand->page_shift); - uint32_t g4_addr = mtd_to_docg4_address(page, 0); - - dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs); - - if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1))) - dev_warn(doc->dev, "%s: ofs %llx not start of block!\n", - __func__, ofs); - - /* allocate blank buffer for page data */ - buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - /* write bit-wise negation of pattern to oob buffer */ - memset(nand->oob_poi, 0xff, mtd->oobsize); - for (i = 0; i < bbtd->len; i++) - nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i]; - - /* write first page of block */ - write_page_prologue(mtd, g4_addr); - docg4_write_page(mtd, nand, buf, 1, page); - ret = pageprog(mtd); - - kfree(buf); - - return ret; -} - -static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs) -{ - /* only called when module_param ignore_badblocks is set */ - return 0; -} - -static int docg4_suspend(struct platform_device *pdev, pm_message_t state) -{ - /* - * Put the device into "deep power-down" mode. Note that CE# must be - * deasserted for this to take effect. The xscale, e.g., can be - * configured to float this signal when the processor enters power-down, - * and a suitable pull-up ensures its deassertion. - */ - - int i; - uint8_t pwr_down; - struct docg4_priv *doc = platform_get_drvdata(pdev); - void __iomem *docptr = doc->virtadr; - - dev_dbg(doc->dev, "%s...\n", __func__); - - /* poll the register that tells us we're ready to go to sleep */ - for (i = 0; i < 10; i++) { - pwr_down = readb(docptr + DOC_POWERMODE); - if (pwr_down & DOC_POWERDOWN_READY) - break; - usleep_range(1000, 4000); - } - - if (pwr_down & DOC_POWERDOWN_READY) { - dev_err(doc->dev, "suspend failed; " - "timeout polling DOC_POWERDOWN_READY\n"); - return -EIO; - } - - writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN, - docptr + DOC_ASICMODE); - writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN), - docptr + DOC_ASICMODECONFIRM); - - write_nop(docptr); - - return 0; -} - -static int docg4_resume(struct platform_device *pdev) -{ - - /* - * Exit power-down. Twelve consecutive reads of the address below - * accomplishes this, assuming CE# has been asserted. - */ - - struct docg4_priv *doc = platform_get_drvdata(pdev); - void __iomem *docptr = doc->virtadr; - int i; - - dev_dbg(doc->dev, "%s...\n", __func__); - - for (i = 0; i < 12; i++) - readb(docptr + 0x1fff); - - return 0; -} - -static void init_mtd_structs(struct mtd_info *mtd) -{ - /* initialize mtd and nand data structures */ - - /* - * Note that some of the following initializations are not usually - * required within a nand driver because they are performed by the nand - * infrastructure code as part of nand_scan(). In this case they need - * to be initialized here because we skip call to nand_scan_ident() (the - * first half of nand_scan()). The call to nand_scan_ident() could be - * skipped because for this device the chip id is not read in the manner - * of a standard nand device. - */ - - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - - mtd->size = DOCG4_CHIP_SIZE; - mtd->name = "Msys_Diskonchip_G4"; - mtd->writesize = DOCG4_PAGE_SIZE; - mtd->erasesize = DOCG4_BLOCK_SIZE; - mtd->oobsize = DOCG4_OOB_SIZE; - mtd_set_ooblayout(mtd, &docg4_ooblayout_ops); - nand->chipsize = DOCG4_CHIP_SIZE; - nand->chip_shift = DOCG4_CHIP_SHIFT; - nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT; - nand->chip_delay = 20; - nand->page_shift = DOCG4_PAGE_SHIFT; - nand->pagemask = 0x3ffff; - nand->badblockpos = NAND_LARGE_BADBLOCK_POS; - nand->badblockbits = 8; - nand->ecc.mode = NAND_ECC_HW_SYNDROME; - nand->ecc.size = DOCG4_PAGE_SIZE; - nand->ecc.prepad = 8; - nand->ecc.bytes = 8; - nand->ecc.strength = DOCG4_T; - nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE; - nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA; - nand->controller = &nand->dummy_controller; - nand_controller_init(nand->controller); - - /* methods */ - nand->cmdfunc = docg4_command; - nand->waitfunc = docg4_wait; - nand->select_chip = docg4_select_chip; - nand->read_byte = docg4_read_byte; - nand->block_markbad = docg4_block_markbad; - nand->read_buf = docg4_read_buf; - nand->write_buf = docg4_write_buf16; - nand->erase = docg4_erase_block; - nand->set_features = nand_get_set_features_notsupp; - nand->get_features = nand_get_set_features_notsupp; - nand->ecc.read_page = docg4_read_page; - nand->ecc.write_page = docg4_write_page; - nand->ecc.read_page_raw = docg4_read_page_raw; - nand->ecc.write_page_raw = docg4_write_page_raw; - nand->ecc.read_oob = docg4_read_oob; - nand->ecc.write_oob = docg4_write_oob; - - /* - * The way the nand infrastructure code is written, a memory-based bbt - * is not created if NAND_SKIP_BBTSCAN is set. With no memory bbt, - * nand->block_bad() is used. So when ignoring bad blocks, we skip the - * scan and define a dummy block_bad() which always returns 0. - */ - if (ignore_badblocks) { - nand->options |= NAND_SKIP_BBTSCAN; - nand->block_bad = docg4_block_neverbad; - } - -} - -static int read_id_reg(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct docg4_priv *doc = nand_get_controller_data(nand); - void __iomem *docptr = doc->virtadr; - uint16_t id1, id2; - - /* check for presence of g4 chip by reading id registers */ - id1 = readw(docptr + DOC_CHIPID); - id1 = readw(docptr + DOCG4_MYSTERY_REG); - id2 = readw(docptr + DOC_CHIPID_INV); - id2 = readw(docptr + DOCG4_MYSTERY_REG); - - if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) { - dev_info(doc->dev, - "NAND device: 128MiB Diskonchip G4 detected\n"); - return 0; - } - - return -ENODEV; -} - -static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL }; - -static int docg4_attach_chip(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct docg4_priv *doc = (struct docg4_priv *)(chip + 1); - int ret; - - init_mtd_structs(mtd); - - /* Initialize kernel BCH algorithm */ - doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY); - if (!doc->bch) - return -EINVAL; - - reset(mtd); - - ret = read_id_reg(mtd); - if (ret) - free_bch(doc->bch); - - return ret; -} - -static void docg4_detach_chip(struct nand_chip *chip) -{ - struct docg4_priv *doc = (struct docg4_priv *)(chip + 1); - - free_bch(doc->bch); -} - -static const struct nand_controller_ops docg4_controller_ops = { - .attach_chip = docg4_attach_chip, - .detach_chip = docg4_detach_chip, -}; - -static int __init probe_docg4(struct platform_device *pdev) -{ - struct mtd_info *mtd; - struct nand_chip *nand; - void __iomem *virtadr; - struct docg4_priv *doc; - int len, retval; - struct resource *r; - struct device *dev = &pdev->dev; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(dev, "no io memory resource defined!\n"); - return -ENODEV; - } - - virtadr = ioremap(r->start, resource_size(r)); - if (!virtadr) { - dev_err(dev, "Diskonchip ioremap failed: %pR\n", r); - return -EIO; - } - - len = sizeof(struct nand_chip) + sizeof(struct docg4_priv); - nand = kzalloc(len, GFP_KERNEL); - if (nand == NULL) { - retval = -ENOMEM; - goto unmap; - } - - mtd = nand_to_mtd(nand); - doc = (struct docg4_priv *) (nand + 1); - nand_set_controller_data(nand, doc); - mtd->dev.parent = &pdev->dev; - doc->virtadr = virtadr; - doc->dev = dev; - platform_set_drvdata(pdev, doc); - - /* - * Running nand_scan() with maxchips == 0 will skip nand_scan_ident(), - * which is a specific operation with this driver and done in the - * ->attach_chip callback. - */ - nand->dummy_controller.ops = &docg4_controller_ops; - retval = nand_scan(mtd, 0); - if (retval) - goto free_nand; - - retval = read_factory_bbt(mtd); - if (retval) - goto cleanup_nand; - - retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0); - if (retval) - goto cleanup_nand; - - doc->mtd = mtd; - - return 0; - -cleanup_nand: - nand_cleanup(nand); -free_nand: - kfree(nand); -unmap: - iounmap(virtadr); - - return retval; -} - -static int __exit cleanup_docg4(struct platform_device *pdev) -{ - struct docg4_priv *doc = platform_get_drvdata(pdev); - nand_release(doc->mtd); - kfree(mtd_to_nand(doc->mtd)); - iounmap(doc->virtadr); - return 0; -} - -static struct platform_driver docg4_driver = { - .driver = { - .name = "docg4", - }, - .suspend = docg4_suspend, - .resume = docg4_resume, - .remove = __exit_p(cleanup_docg4), -}; - -module_platform_driver_probe(docg4_driver, probe_docg4); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mike Dunn"); -MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver"); diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 55f449b711fd..d6ed697fcfe6 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -317,10 +317,10 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob) } /* cmdfunc send commands to the FCM */ -static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, +static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command, int column, int page_addr) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; @@ -533,7 +533,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, } } -static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip) +static void fsl_elbc_select_chip(struct nand_chip *chip, int cs) { /* The hardware does not seem to support multiple * chips per bank. @@ -543,9 +543,9 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip) /* * Write buf to the FCM Controller Data Buffer */ -static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void fsl_elbc_write_buf(struct nand_chip *chip, const u8 *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; unsigned int bufsize = mtd->writesize + mtd->oobsize; @@ -581,9 +581,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) * read a byte from either the FCM hardware buffer if it has any data left * otherwise issue a command to read a single byte. */ -static u8 fsl_elbc_read_byte(struct mtd_info *mtd) +static u8 fsl_elbc_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; @@ -598,9 +597,8 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd) /* * Read from the FCM Controller Data Buffer */ -static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void fsl_elbc_read_buf(struct nand_chip *chip, u8 *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; int avail; @@ -623,7 +621,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) /* This function is called after Program and Erase Operations to * check for success or failure. */ -static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) +static int fsl_elbc_wait(struct nand_chip *chip) { struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; @@ -660,8 +658,8 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip) chip->chipsize); dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n", chip->pagemask); - dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n", - chip->chip_delay); + dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n", + chip->legacy.chip_delay); dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n", chip->badblockpos); dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n", @@ -710,18 +708,19 @@ static const struct nand_controller_ops fsl_elbc_controller_ops = { .attach_chip = fsl_elbc_attach_chip, }; -static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; nand_read_page_op(chip, page, 0, buf, mtd->writesize); if (oob_required) - fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_elbc_read_buf(chip, chip->oob_poi, mtd->oobsize); - if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) + if (fsl_elbc_wait(chip) & NAND_STATUS_FAIL) mtd->ecc_stats.failed++; return elbc_fcm_ctrl->max_bitflips; @@ -730,11 +729,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int fsl_elbc_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); - fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } @@ -742,13 +743,15 @@ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, uint32_t data_len, - const uint8_t *buf, int oob_required, int page) +static int fsl_elbc_write_subpage(struct nand_chip *chip, uint32_t offset, + uint32_t data_len, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + nand_prog_page_begin_op(chip, page, 0, NULL, 0); - fsl_elbc_write_buf(mtd, buf, mtd->writesize); - fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_elbc_write_buf(chip, buf, mtd->writesize); + fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } @@ -773,14 +776,14 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) /* fill in nand_chip structure */ /* set up function call table */ - chip->read_byte = fsl_elbc_read_byte; - chip->write_buf = fsl_elbc_write_buf; - chip->read_buf = fsl_elbc_read_buf; + chip->legacy.read_byte = fsl_elbc_read_byte; + chip->legacy.write_buf = fsl_elbc_write_buf; + chip->legacy.read_buf = fsl_elbc_read_buf; chip->select_chip = fsl_elbc_select_chip; - chip->cmdfunc = fsl_elbc_cmdfunc; - chip->waitfunc = fsl_elbc_wait; - chip->set_features = nand_get_set_features_notsupp; - chip->get_features = nand_get_set_features_notsupp; + chip->legacy.cmdfunc = fsl_elbc_cmdfunc; + chip->legacy.waitfunc = fsl_elbc_wait; + chip->legacy.set_features = nand_get_set_features_notsupp; + chip->legacy.get_features = nand_get_set_features_notsupp; chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; @@ -915,7 +918,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev) goto err; priv->chip.controller->ops = &fsl_elbc_controller_ops; - ret = nand_scan(mtd, 1); + ret = nand_scan(&priv->chip, 1); if (ret) goto err; @@ -942,9 +945,8 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev) { struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev); - struct mtd_info *mtd = nand_to_mtd(&priv->chip); - nand_release(mtd); + nand_release(&priv->chip); fsl_elbc_chip_remove(priv); mutex_lock(&fsl_elbc_nand_mutex); diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index 24f59d0066af..6f4afc44381a 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -30,6 +30,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/nand_ecc.h> #include <linux/fsl_ifc.h> +#include <linux/iopoll.h> #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ @@ -300,9 +301,9 @@ static void fsl_ifc_do_read(struct nand_chip *chip, } /* cmdfunc send commands to the IFC NAND Machine */ -static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) { - struct nand_chip *chip = mtd_to_nand(mtd); +static void fsl_ifc_cmdfunc(struct nand_chip *chip, unsigned int command, + int column, int page_addr) { + struct mtd_info *mtd = nand_to_mtd(chip); struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs; @@ -508,7 +509,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, } } -static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) +static void fsl_ifc_select_chip(struct nand_chip *chip, int cs) { /* The hardware does not seem to support multiple * chips per bank. @@ -518,9 +519,9 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) /* * Write buf to the IFC NAND Controller Data Buffer */ -static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void fsl_ifc_write_buf(struct nand_chip *chip, const u8 *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); unsigned int bufsize = mtd->writesize + mtd->oobsize; @@ -544,9 +545,8 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) * Read a byte from either the IFC hardware buffer * read function for 8-bit buswidth */ -static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd) +static uint8_t fsl_ifc_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); unsigned int offset; @@ -567,9 +567,8 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd) * Read two bytes from the IFC hardware buffer * read function for 16-bit buswith */ -static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd) +static uint8_t fsl_ifc_read_byte16(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); uint16_t data; @@ -590,9 +589,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd) /* * Read from the IFC Controller Data Buffer */ -static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void fsl_ifc_read_buf(struct nand_chip *chip, u8 *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); int avail; @@ -616,8 +614,9 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) * This function is called after Program and Erase Operations to * check for success or failure. */ -static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) +static int fsl_ifc_wait(struct nand_chip *chip) { + struct mtd_info *mtd = nand_to_mtd(chip); struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs; @@ -678,20 +677,21 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf) return bitflips; } -static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int fsl_ifc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; nand_read_page_op(chip, page, 0, buf, mtd->writesize); if (oob_required) - fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize); if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) { if (!oob_required) - fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize); return check_erased_page(chip, buf); } @@ -705,11 +705,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int fsl_ifc_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); - fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_ifc_write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } @@ -725,8 +727,8 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip) chip->chipsize); dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__, chip->pagemask); - dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__, - chip->chip_delay); + dev_dbg(priv->dev, "%s: nand->legacy.chip_delay = %d\n", __func__, + chip->legacy.chip_delay); dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__, chip->badblockpos); dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__, @@ -761,7 +763,7 @@ static const struct nand_controller_ops fsl_ifc_controller_ops = { .attach_chip = fsl_ifc_attach_chip, }; -static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) +static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) { struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs; @@ -769,6 +771,27 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) uint32_t csor = 0, csor_8k = 0, csor_ext = 0; uint32_t cs = priv->bank; + if (ctrl->version < FSL_IFC_VERSION_1_1_0) + return 0; + + if (ctrl->version > FSL_IFC_VERSION_1_1_0) { + u32 ncfgr, status; + int ret; + + /* Trigger auto initialization */ + ncfgr = ifc_in32(&ifc_runtime->ifc_nand.ncfgr); + ifc_out32(ncfgr | IFC_NAND_NCFGR_SRAM_INIT_EN, &ifc_runtime->ifc_nand.ncfgr); + + /* Wait until done */ + ret = readx_poll_timeout(ifc_in32, &ifc_runtime->ifc_nand.ncfgr, + status, !(status & IFC_NAND_NCFGR_SRAM_INIT_EN), + 10, IFC_TIMEOUT_MSECS * 1000); + if (ret) + dev_err(priv->dev, "Failed to initialize SRAM!\n"); + + return ret; + } + /* Save CSOR and CSOR_ext */ csor = ifc_in32(&ifc_global->csor_cs[cs].csor); csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext); @@ -805,12 +828,16 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, msecs_to_jiffies(IFC_TIMEOUT_MSECS)); - if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) + if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) { pr_err("fsl-ifc: Failed to Initialise SRAM\n"); + return -ETIMEDOUT; + } /* Restore CSOR and CSOR_ext */ ifc_out32(csor, &ifc_global->csor_cs[cs].csor); ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext); + + return 0; } static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) @@ -821,6 +848,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) struct nand_chip *chip = &priv->chip; struct mtd_info *mtd = nand_to_mtd(&priv->chip); u32 csor; + int ret; /* Fill in fsl_ifc_mtd structure */ mtd->dev.parent = priv->dev; @@ -830,17 +858,17 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) /* set up function call table */ if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16) - chip->read_byte = fsl_ifc_read_byte16; + chip->legacy.read_byte = fsl_ifc_read_byte16; else - chip->read_byte = fsl_ifc_read_byte; + chip->legacy.read_byte = fsl_ifc_read_byte; - chip->write_buf = fsl_ifc_write_buf; - chip->read_buf = fsl_ifc_read_buf; + chip->legacy.write_buf = fsl_ifc_write_buf; + chip->legacy.read_buf = fsl_ifc_read_buf; chip->select_chip = fsl_ifc_select_chip; - chip->cmdfunc = fsl_ifc_cmdfunc; - chip->waitfunc = fsl_ifc_wait; - chip->set_features = nand_get_set_features_notsupp; - chip->get_features = nand_get_set_features_notsupp; + chip->legacy.cmdfunc = fsl_ifc_cmdfunc; + chip->legacy.waitfunc = fsl_ifc_wait; + chip->legacy.set_features = nand_get_set_features_notsupp; + chip->legacy.get_features = nand_get_set_features_notsupp; chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; @@ -853,10 +881,10 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) { - chip->read_byte = fsl_ifc_read_byte16; + chip->legacy.read_byte = fsl_ifc_read_byte16; chip->options |= NAND_BUSWIDTH_16; } else { - chip->read_byte = fsl_ifc_read_byte; + chip->legacy.read_byte = fsl_ifc_read_byte; } chip->controller = &ifc_nand_ctrl->controller; @@ -914,8 +942,9 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) chip->ecc.algo = NAND_ECC_HAMMING; } - if (ctrl->version >= FSL_IFC_VERSION_1_1_0) - fsl_ifc_sram_init(priv); + ret = fsl_ifc_sram_init(priv); + if (ret) + return ret; /* * As IFC version 2.0.0 has 16KB of internal SRAM as compared to older @@ -1051,7 +1080,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) goto err; priv->chip.controller->ops = &fsl_ifc_controller_ops; - ret = nand_scan(mtd, 1); + ret = nand_scan(&priv->chip, 1); if (ret) goto err; @@ -1077,9 +1106,8 @@ err: static int fsl_ifc_nand_remove(struct platform_device *dev) { struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev); - struct mtd_info *mtd = nand_to_mtd(&priv->chip); - nand_release(mtd); + nand_release(&priv->chip); fsl_ifc_chip_remove(priv); mutex_lock(&fsl_ifc_nand_mutex); diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index a88e2cf66e0f..673c5a0c9345 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -52,9 +52,9 @@ static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo) chip); } -static int fun_chip_ready(struct mtd_info *mtd) +static int fun_chip_ready(struct nand_chip *chip) { - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); if (gpio_get_value(fun->rnb_gpio[fun->mchip_number])) return 1; @@ -69,7 +69,7 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun) struct mtd_info *mtd = nand_to_mtd(&fun->chip); int cnt = 1000000; - while (--cnt && !fun_chip_ready(mtd)) + while (--cnt && !fun_chip_ready(&fun->chip)) cpu_relax(); if (!cnt) dev_err(fun->dev, "tired waiting for RNB\n"); @@ -78,10 +78,9 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun) } } -static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void fun_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); u32 mar; if (!(ctrl & fun->last_ctrl)) { @@ -102,51 +101,50 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) mar = (cmd << (32 - fun->upm.width)) | fun->mchip_offsets[fun->mchip_number]; - fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar); + fsl_upm_run_pattern(&fun->upm, chip->legacy.IO_ADDR_R, mar); if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) fun_wait_rnb(fun); } -static void fun_select_chip(struct mtd_info *mtd, int mchip_nr) +static void fun_select_chip(struct nand_chip *chip, int mchip_nr) { - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); if (mchip_nr == -1) { - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); } else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) { fun->mchip_number = mchip_nr; - chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr]; - chip->IO_ADDR_W = chip->IO_ADDR_R; + chip->legacy.IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr]; + chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R; } else { BUG(); } } -static uint8_t fun_read_byte(struct mtd_info *mtd) +static uint8_t fun_read_byte(struct nand_chip *chip) { - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); - return in_8(fun->chip.IO_ADDR_R); + return in_8(fun->chip.legacy.IO_ADDR_R); } -static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void fun_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); int i; for (i = 0; i < len; i++) - buf[i] = in_8(fun->chip.IO_ADDR_R); + buf[i] = in_8(fun->chip.legacy.IO_ADDR_R); } -static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void fun_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); int i; for (i = 0; i < len; i++) { - out_8(fun->chip.IO_ADDR_W, buf[i]); + out_8(fun->chip.legacy.IO_ADDR_W, buf[i]); if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE) fun_wait_rnb(fun); } @@ -162,20 +160,20 @@ static int fun_chip_init(struct fsl_upm_nand *fun, int ret; struct device_node *flash_np; - fun->chip.IO_ADDR_R = fun->io_base; - fun->chip.IO_ADDR_W = fun->io_base; - fun->chip.cmd_ctrl = fun_cmd_ctrl; - fun->chip.chip_delay = fun->chip_delay; - fun->chip.read_byte = fun_read_byte; - fun->chip.read_buf = fun_read_buf; - fun->chip.write_buf = fun_write_buf; + fun->chip.legacy.IO_ADDR_R = fun->io_base; + fun->chip.legacy.IO_ADDR_W = fun->io_base; + fun->chip.legacy.cmd_ctrl = fun_cmd_ctrl; + fun->chip.legacy.chip_delay = fun->chip_delay; + fun->chip.legacy.read_byte = fun_read_byte; + fun->chip.legacy.read_buf = fun_read_buf; + fun->chip.legacy.write_buf = fun_write_buf; fun->chip.ecc.mode = NAND_ECC_SOFT; fun->chip.ecc.algo = NAND_ECC_HAMMING; if (fun->mchip_count > 1) fun->chip.select_chip = fun_select_chip; if (fun->rnb_gpio[0] >= 0) - fun->chip.dev_ready = fun_chip_ready; + fun->chip.legacy.dev_ready = fun_chip_ready; mtd->dev.parent = fun->dev; @@ -184,14 +182,14 @@ static int fun_chip_init(struct fsl_upm_nand *fun, return -ENODEV; nand_set_flash_node(&fun->chip, flash_np); - mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start, - flash_np->name); + mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%pOFn", (u64)io_res->start, + flash_np); if (!mtd->name) { ret = -ENOMEM; goto err; } - ret = nand_scan(mtd, fun->mchip_count); + ret = nand_scan(&fun->chip, fun->mchip_count); if (ret) goto err; @@ -326,7 +324,7 @@ static int fun_remove(struct platform_device *ofdev) struct mtd_info *mtd = nand_to_mtd(&fun->chip); int i; - nand_release(mtd); + nand_release(&fun->chip); kfree(mtd->name); for (i = 0; i < fun->mchip_count; i++) { diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index f418236fa020..70ac8d875218 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -340,10 +340,9 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host, return 0; } -static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline, +static int fsmc_setup_data_interface(struct nand_chip *nand, int csline, const struct nand_data_interface *conf) { - struct nand_chip *nand = mtd_to_nand(mtd); struct fsmc_nand_data *host = nand_get_controller_data(nand); struct fsmc_nand_timings tims; const struct nand_sdr_timings *sdrt; @@ -368,9 +367,9 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline, /* * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers */ -static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) +static void fsmc_enable_hwecc(struct nand_chip *chip, int mode) { - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); + struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip)); writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256, host->regs_va + FSMC_PC); @@ -385,10 +384,10 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to * max of 8-bits) */ -static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, +static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data, uint8_t *ecc) { - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); + struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip)); uint32_t ecc_tmp; unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; @@ -433,10 +432,10 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to * max of 1-bit) */ -static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, +static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const uint8_t *data, uint8_t *ecc) { - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); + struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip)); uint32_t ecc_tmp; ecc_tmp = readl_relaxed(host->regs_va + ECC1); @@ -610,9 +609,9 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, } /* fsmc_select_chip - assert or deassert nCE */ -static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) +static void fsmc_select_chip(struct nand_chip *chip, int chipnr) { - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); + struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip)); u32 pc; /* Support only one CS */ @@ -707,7 +706,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, /* * fsmc_read_page_hwecc - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller expects OOB data read to chip->oob_poi @@ -719,9 +717,10 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, * After this read, fsmc hardware generates and reports error data bits(up to a * max of 8 bits) */ -static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, j, s, stat, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -740,7 +739,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { nand_read_page_op(chip, page, s * eccsize, NULL, 0); - chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->ecc.hwctl(chip, NAND_ECC_READ); nand_read_data_op(chip, p, eccsize, false); for (j = 0; j < eccbytes;) { @@ -767,9 +766,9 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } memcpy(&ecc_code[i], oob, chip->ecc.bytes); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]); if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -791,11 +790,10 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * calc_ecc is a 104 bit information containing maximum of 8 error * offset informations of 13 bits each in 512 bytes of read data. */ -static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) +static int fsmc_bch8_correct_data(struct nand_chip *chip, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) { - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsmc_nand_data *host = mtd_to_fsmc(mtd); + struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip)); uint32_t err_idx[8]; uint32_t num_err, i; uint32_t ecc1, ecc2, ecc3, ecc4; @@ -951,6 +949,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) nand->ecc.correct = nand_correct_data; nand->ecc.bytes = 3; nand->ecc.strength = 1; + nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER; break; case NAND_ECC_SOFT: @@ -1082,7 +1081,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; nand->exec_op = fsmc_exec_op; nand->select_chip = fsmc_select_chip; - nand->chip_delay = 30; /* * Setup default ECC mode. nand_dt_init() called from nand_scan_ident() @@ -1125,7 +1123,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * Scan to find existence of the device */ nand->dummy_controller.ops = &fsmc_nand_controller_ops; - ret = nand_scan(mtd, 1); + ret = nand_scan(nand, 1); if (ret) goto release_dma_write_chan; @@ -1161,7 +1159,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) struct fsmc_nand_data *host = platform_get_drvdata(pdev); if (host) { - nand_release(nand_to_mtd(&host->nand)); + nand_release(&host->nand); if (host->mode == USE_DMA_ACCESS) { dma_release_channel(host->write_dma_chan); diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index 2780af26d9ab..a6c9a824a7d4 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -73,9 +73,10 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd) static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {} #endif -static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd, + unsigned int ctrl) { - struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); + struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); gpio_nand_dosync(gpiomtd); @@ -89,13 +90,13 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) if (cmd == NAND_CMD_NONE) return; - writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W); + writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W); gpio_nand_dosync(gpiomtd); } -static int gpio_nand_devready(struct mtd_info *mtd) +static int gpio_nand_devready(struct nand_chip *chip) { - struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); + struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip)); return gpiod_get_value(gpiomtd->rdy); } @@ -194,7 +195,7 @@ static int gpio_nand_remove(struct platform_device *pdev) { struct gpiomtd *gpiomtd = platform_get_drvdata(pdev); - nand_release(nand_to_mtd(&gpiomtd->nand_chip)); + nand_release(&gpiomtd->nand_chip); /* Enable write protection and disable the chip */ if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp)) @@ -224,9 +225,9 @@ static int gpio_nand_probe(struct platform_device *pdev) chip = &gpiomtd->nand_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->IO_ADDR_R = devm_ioremap_resource(dev, res); - if (IS_ERR(chip->IO_ADDR_R)) - return PTR_ERR(chip->IO_ADDR_R); + chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->legacy.IO_ADDR_R)) + return PTR_ERR(chip->legacy.IO_ADDR_R); res = gpio_nand_get_io_sync(pdev); if (res) { @@ -270,15 +271,15 @@ static int gpio_nand_probe(struct platform_device *pdev) } /* Using RDY pin */ if (gpiomtd->rdy) - chip->dev_ready = gpio_nand_devready; + chip->legacy.dev_ready = gpio_nand_devready; nand_set_flash_node(chip, pdev->dev.of_node); - chip->IO_ADDR_W = chip->IO_ADDR_R; + chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; chip->options = gpiomtd->plat.options; - chip->chip_delay = gpiomtd->plat.chip_delay; - chip->cmd_ctrl = gpio_nand_cmd_ctrl; + chip->legacy.chip_delay = gpiomtd->plat.chip_delay; + chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl; mtd = nand_to_mtd(chip); mtd->dev.parent = dev; @@ -289,7 +290,7 @@ static int gpio_nand_probe(struct platform_device *pdev) if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp)) gpiod_direction_output(gpiomtd->nwp, 1); - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret) goto err_wp; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c index 88ea2203e263..bd4cfac6b5aa 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c @@ -471,10 +471,9 @@ void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) udelay(dll_wait_time_us); } -int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr, +int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr, const struct nand_data_interface *conf) { - struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); const struct nand_sdr_timings *sdr; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 1c1ebbc82824..94c2b7525c85 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -783,9 +783,8 @@ error_alloc: return -ENOMEM; } -static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) +static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); int ret; @@ -817,17 +816,15 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) this->command_length = 0; } -static int gpmi_dev_ready(struct mtd_info *mtd) +static int gpmi_dev_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); return gpmi_is_ready(this, this->current_chip); } -static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) +static void gpmi_select_chip(struct nand_chip *chip, int chipnr) { - struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); int ret; @@ -859,9 +856,8 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) this->current_chip = chipnr; } -static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); dev_dbg(this->dev, "len is %d\n", len); @@ -869,9 +865,8 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) gpmi_read_data(this, buf, len); } -static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); dev_dbg(this->dev, "len is %d\n", len); @@ -879,13 +874,12 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) gpmi_send_data(this, buf, len); } -static uint8_t gpmi_read_byte(struct mtd_info *mtd) +static uint8_t gpmi_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct gpmi_nand_data *this = nand_get_controller_data(chip); uint8_t *buf = this->data_buffer_dma; - gpmi_read_buf(mtd, buf, 1); + gpmi_read_buf(chip, buf, 1); return buf[0]; } @@ -1085,8 +1079,8 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip, return max_bitflips; } -static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { nand_read_page_op(chip, page, 0, NULL, 0); @@ -1094,8 +1088,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, } /* Fake a virtual small page for the subpage read */ -static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offs, uint32_t len, uint8_t *buf, int page) +static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs, + uint32_t len, uint8_t *buf, int page) { struct gpmi_nand_data *this = nand_get_controller_data(chip); void __iomem *bch_regs = this->resources.bch_regs; @@ -1130,7 +1124,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n", page, first, last, marker_pos); - return gpmi_ecc_read_page(mtd, chip, buf, 0, page); + return gpmi_ecc_read_page(chip, buf, 0, page); } } @@ -1182,9 +1176,10 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, return max_bitflips; } -static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip); struct bch_geometry *nfc_geo = &this->bch_geometry; const void *payload_virt; @@ -1324,9 +1319,9 @@ exit_auxiliary: * ECC-based or raw view of the page is implicit in which function it calls * (there is a similar pair of ECC-based/raw functions for writing). */ -static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int gpmi_ecc_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip); dev_dbg(this->dev, "page number is %d\n", page); @@ -1335,7 +1330,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, /* Read out the conventional OOB. */ nand_read_page_op(chip, page, mtd->writesize, NULL, 0); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); /* * Now, we want to make sure the block mark is correct. In the @@ -1345,15 +1340,15 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, if (GPMI_IS_MX23(this)) { /* Read the block mark into the first byte of the OOB buffer. */ nand_read_page_op(chip, page, 0, NULL, 0); - chip->oob_poi[0] = chip->read_byte(mtd); + chip->oob_poi[0] = chip->legacy.read_byte(chip); } return 0; } -static int -gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) +static int gpmi_ecc_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_oob_region of = { }; /* Do we have available oob area? */ @@ -1380,10 +1375,10 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) * See set_geometry_by_ecc_info inline comments to have a full description * of the layout used by the GPMI controller. */ -static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip); struct bch_geometry *nfc_geo = &this->bch_geometry; int eccsize = nfc_geo->ecc_chunk_size; @@ -1464,11 +1459,10 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, * See set_geometry_by_ecc_info inline comments to have a full description * of the layout used by the GPMI controller. */ -static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, +static int gpmi_ecc_write_page_raw(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip); struct bch_geometry *nfc_geo = &this->bch_geometry; int eccsize = nfc_geo->ecc_chunk_size; @@ -1536,28 +1530,26 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, mtd->writesize + mtd->oobsize); } -static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int gpmi_ecc_read_oob_raw(struct nand_chip *chip, int page) { - return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page); + return gpmi_ecc_read_page_raw(chip, NULL, 1, page); } -static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int gpmi_ecc_write_oob_raw(struct nand_chip *chip, int page) { - return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page); + return gpmi_ecc_write_page_raw(chip, NULL, 1, page); } -static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) +static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip); int ret = 0; uint8_t *block_mark; int column, page, chipnr; chipnr = (int)(ofs >> chip->chip_shift); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); column = !GPMI_IS_MX23(this) ? mtd->writesize : 0; @@ -1570,7 +1562,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) ret = nand_prog_page_op(chip, page, column, block_mark, 1); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); return ret; } @@ -1607,7 +1599,6 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) struct boot_rom_geometry *rom_geo = &this->rom_geometry; struct device *dev = this->dev; struct nand_chip *chip = &this->nand; - struct mtd_info *mtd = nand_to_mtd(chip); unsigned int search_area_size_in_strides; unsigned int stride; unsigned int page; @@ -1619,7 +1610,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; saved_chip_number = this->current_chip; - chip->select_chip(mtd, 0); + chip->select_chip(chip, 0); /* * Loop through the first search area, looking for the NCB fingerprint. @@ -1637,7 +1628,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) * and starts in the 12th byte of the page. */ nand_read_page_op(chip, page, 12, NULL, 0); - chip->read_buf(mtd, buffer, strlen(fingerprint)); + chip->legacy.read_buf(chip, buffer, strlen(fingerprint)); /* Look for the fingerprint. */ if (!memcmp(buffer, fingerprint, strlen(fingerprint))) { @@ -1647,7 +1638,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) } - chip->select_chip(mtd, saved_chip_number); + chip->select_chip(chip, saved_chip_number); if (found_an_ncb_fingerprint) dev_dbg(dev, "\tFound a fingerprint\n"); @@ -1690,7 +1681,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Select chip 0. */ saved_chip_number = this->current_chip; - chip->select_chip(mtd, 0); + chip->select_chip(chip, 0); /* Loop over blocks in the first search area, erasing them. */ dev_dbg(dev, "Erasing the search area...\n"); @@ -1716,13 +1707,13 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Write the first page of the current stride. */ dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); - status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page); + status = chip->ecc.write_page_raw(chip, buffer, 0, page); if (status) dev_err(dev, "[%s] Write failed.\n", __func__); } /* Deselect chip 0. */ - chip->select_chip(mtd, saved_chip_number); + chip->select_chip(chip, saved_chip_number); return 0; } @@ -1771,10 +1762,10 @@ static int mx23_boot_init(struct gpmi_nand_data *this) byte = block << chip->phys_erase_shift; /* Send the command to read the conventional block mark. */ - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); nand_read_page_op(chip, page, mtd->writesize, NULL, 0); - block_mark = chip->read_byte(mtd); - chip->select_chip(mtd, -1); + block_mark = chip->legacy.read_byte(chip); + chip->select_chip(chip, -1); /* * Check if the block is marked bad. If so, we need to mark it @@ -1783,7 +1774,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this) */ if (block_mark != 0xff) { dev_dbg(dev, "Transcribing mark in block %u\n", block); - ret = chip->block_markbad(mtd, byte); + ret = chip->legacy.block_markbad(chip, byte); if (ret) dev_err(dev, "Failed to mark block bad with ret %d\n", @@ -1911,13 +1902,13 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) nand_set_flash_node(chip, this->pdev->dev.of_node); chip->select_chip = gpmi_select_chip; chip->setup_data_interface = gpmi_setup_data_interface; - chip->cmd_ctrl = gpmi_cmd_ctrl; - chip->dev_ready = gpmi_dev_ready; - chip->read_byte = gpmi_read_byte; - chip->read_buf = gpmi_read_buf; - chip->write_buf = gpmi_write_buf; + chip->legacy.cmd_ctrl = gpmi_cmd_ctrl; + chip->legacy.dev_ready = gpmi_dev_ready; + chip->legacy.read_byte = gpmi_read_byte; + chip->legacy.read_buf = gpmi_read_buf; + chip->legacy.write_buf = gpmi_write_buf; chip->badblock_pattern = &gpmi_bbt_descr; - chip->block_markbad = gpmi_block_markbad; + chip->legacy.block_markbad = gpmi_block_markbad; chip->options |= NAND_NO_SUBPAGE_WRITE; /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ @@ -1934,7 +1925,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) goto err_out; chip->dummy_controller.ops = &gpmi_nand_controller_ops; - ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1); + ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1); if (ret) goto err_out; @@ -2026,7 +2017,7 @@ static int gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); - nand_release(nand_to_mtd(&this->nand)); + nand_release(&this->nand); gpmi_free_dma_buffer(this); release_resources(this); return 0; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h index 69cd0cbde4f2..d0b79bac2728 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h @@ -178,7 +178,7 @@ int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); int gpmi_send_command(struct gpmi_nand_data *); int gpmi_enable_clk(struct gpmi_nand_data *this); int gpmi_disable_clk(struct gpmi_nand_data *this); -int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr, +int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr, const struct nand_data_interface *conf); void gpmi_nfc_apply_timings(struct gpmi_nand_data *this); int gpmi_read_data(struct gpmi_nand_data *, void *buf, int len); diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c index 950dc7789296..f043938ee36b 100644 --- a/drivers/mtd/nand/raw/hisi504_nand.c +++ b/drivers/mtd/nand/raw/hisi504_nand.c @@ -353,9 +353,8 @@ static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect) return 0; } -static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect) +static void hisi_nfc_select_chip(struct nand_chip *chip, int chipselect) { - struct nand_chip *chip = mtd_to_nand(mtd); struct hinfc_host *host = nand_get_controller_data(chip); if (chipselect < 0) @@ -364,9 +363,8 @@ static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect) host->chipselect = chipselect; } -static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd) +static uint8_t hisi_nfc_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct hinfc_host *host = nand_get_controller_data(chip); if (host->command == NAND_CMD_STATUS) @@ -380,28 +378,17 @@ static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd) return *(uint8_t *)(host->buffer + host->offset - 1); } -static u16 hisi_nfc_read_word(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct hinfc_host *host = nand_get_controller_data(chip); - - host->offset += 2; - return *(u16 *)(host->buffer + host->offset - 2); -} - static void -hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +hisi_nfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct hinfc_host *host = nand_get_controller_data(chip); memcpy(host->buffer + host->offset, buf, len); host->offset += len; } -static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void hisi_nfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct hinfc_host *host = nand_get_controller_data(chip); memcpy(buf, host->buffer + host->offset, len); @@ -442,10 +429,10 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr) } } -static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column, - int page_addr) +static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command, + int column, int page_addr) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct hinfc_host *host = nand_get_controller_data(chip); int is_cache_invalid = 1; unsigned int flag = 0; @@ -537,15 +524,16 @@ static irqreturn_t hinfc_irq_handle(int irq, void *devid) return IRQ_HANDLED; } -static int hisi_nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int hisi_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct hinfc_host *host = nand_get_controller_data(chip); int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc; int stat_1, stat_2; nand_read_page_op(chip, page, 0, buf, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); /* errors which can not be corrected by ECC */ if (host->irq_status & HINFC504_INTS_UE) { @@ -569,9 +557,9 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd, return max_bitflips; } -static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int hisi_nand_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct hinfc_host *host = nand_get_controller_data(chip); nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); @@ -585,13 +573,15 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static int hisi_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required, - int page) +static int hisi_nand_write_page_hwecc(struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); if (oob_required) - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } @@ -792,15 +782,14 @@ static int hisi_nfc_probe(struct platform_device *pdev) nand_set_controller_data(chip, host); nand_set_flash_node(chip, np); - chip->cmdfunc = hisi_nfc_cmdfunc; + chip->legacy.cmdfunc = hisi_nfc_cmdfunc; chip->select_chip = hisi_nfc_select_chip; - chip->read_byte = hisi_nfc_read_byte; - chip->read_word = hisi_nfc_read_word; - chip->write_buf = hisi_nfc_write_buf; - chip->read_buf = hisi_nfc_read_buf; - chip->chip_delay = HINFC504_CHIP_DELAY; - chip->set_features = nand_get_set_features_notsupp; - chip->get_features = nand_get_set_features_notsupp; + chip->legacy.read_byte = hisi_nfc_read_byte; + chip->legacy.write_buf = hisi_nfc_write_buf; + chip->legacy.read_buf = hisi_nfc_read_buf; + chip->legacy.chip_delay = HINFC504_CHIP_DELAY; + chip->legacy.set_features = nand_get_set_features_notsupp; + chip->legacy.get_features = nand_get_set_features_notsupp; hisi_nfc_host_init(host); @@ -811,7 +800,7 @@ static int hisi_nfc_probe(struct platform_device *pdev) } chip->dummy_controller.ops = &hisi_nfc_controller_ops; - ret = nand_scan(mtd, max_chips); + ret = nand_scan(chip, max_chips); if (ret) return ret; @@ -828,9 +817,8 @@ static int hisi_nfc_probe(struct platform_device *pdev) static int hisi_nfc_remove(struct platform_device *pdev) { struct hinfc_host *host = platform_get_drvdata(pdev); - struct mtd_info *mtd = nand_to_mtd(&host->chip); - nand_release(mtd); + nand_release(&host->chip); return 0; } diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h new file mode 100644 index 000000000000..04c2cf74eff3 --- /dev/null +++ b/drivers/mtd/nand/raw/internals.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 - Bootlin + * + * Author: Boris Brezillon <boris.brezillon@bootlin.com> + * + * Header containing internal definitions to be used only by core files. + * NAND controller drivers should not include this file. + */ + +#ifndef __LINUX_RAWNAND_INTERNALS +#define __LINUX_RAWNAND_INTERNALS + +#include <linux/mtd/rawnand.h> + +/* + * NAND Flash Manufacturer ID Codes + */ +#define NAND_MFR_AMD 0x01 +#define NAND_MFR_ATO 0x9b +#define NAND_MFR_EON 0x92 +#define NAND_MFR_ESMT 0xc8 +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_INTEL 0x89 +#define NAND_MFR_MACRONIX 0xc2 +#define NAND_MFR_MICRON 0x2c +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_SANDISK 0x45 +#define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_WINBOND 0xef + +/** + * struct nand_manufacturer_ops - NAND Manufacturer operations + * @detect: detect the NAND memory organization and capabilities + * @init: initialize all vendor specific fields (like the ->read_retry() + * implementation) if any. + * @cleanup: the ->init() function may have allocated resources, ->cleanup() + * is here to let vendor specific code release those resources. + * @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter + * page. This is called after the checksum is verified. + */ +struct nand_manufacturer_ops { + void (*detect)(struct nand_chip *chip); + int (*init)(struct nand_chip *chip); + void (*cleanup)(struct nand_chip *chip); + void (*fixup_onfi_param_page)(struct nand_chip *chip, + struct nand_onfi_params *p); +}; + +/** + * struct nand_manufacturer - NAND Flash Manufacturer structure + * @name: Manufacturer name + * @id: manufacturer ID code of device. + * @ops: manufacturer operations + */ +struct nand_manufacturer { + int id; + char *name; + const struct nand_manufacturer_ops *ops; +}; + + +extern struct nand_flash_dev nand_flash_ids[]; + +extern const struct nand_manufacturer_ops amd_nand_manuf_ops; +extern const struct nand_manufacturer_ops esmt_nand_manuf_ops; +extern const struct nand_manufacturer_ops hynix_nand_manuf_ops; +extern const struct nand_manufacturer_ops macronix_nand_manuf_ops; +extern const struct nand_manufacturer_ops micron_nand_manuf_ops; +extern const struct nand_manufacturer_ops samsung_nand_manuf_ops; +extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; + +/* Core functions */ +const struct nand_manufacturer *nand_get_manufacturer(u8 id); +int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs); +int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, + int allowbbt); +int onfi_fill_data_interface(struct nand_chip *chip, + enum nand_data_interface_type type, + int timing_mode); +int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param); +int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param); +int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, + int oob_required, int page); +int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf, + int oob_required, int page); +int nand_exit_status_op(struct nand_chip *chip); +int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, + unsigned int len); +void nand_decode_ext_id(struct nand_chip *chip); +void panic_nand_wait(struct nand_chip *chip, unsigned long timeo); +void sanitize_string(uint8_t *s, size_t len); + +/* BBT functions */ +int nand_markbad_bbt(struct nand_chip *chip, loff_t offs); +int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs); +int nand_isbad_bbt(struct nand_chip *chip, loff_t offs, int allowbbt); + +/* Legacy */ +void nand_legacy_set_defaults(struct nand_chip *chip); +void nand_legacy_adjust_cmdfunc(struct nand_chip *chip); +int nand_legacy_check_hooks(struct nand_chip *chip); + +/* ONFI functions */ +u16 onfi_crc16(u16 crc, u8 const *p, size_t len); +int nand_onfi_detect(struct nand_chip *chip); + +/* JEDEC functions */ +int nand_jedec_detect(struct nand_chip *chip); + +#endif /* __LINUX_RAWNAND_INTERNALS */ diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c index a7515452bc59..fb59cfca11a7 100644 --- a/drivers/mtd/nand/raw/jz4740_nand.c +++ b/drivers/mtd/nand/raw/jz4740_nand.c @@ -78,10 +78,9 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) return container_of(mtd_to_nand(mtd), struct jz_nand, chip); } -static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr) +static void jz_nand_select_chip(struct nand_chip *chip, int chipnr) { - struct jz_nand *nand = mtd_to_jz_nand(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); uint32_t ctrl; int banknr; @@ -92,18 +91,18 @@ static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr) banknr = -1; } else { banknr = nand->banks[chipnr] - 1; - chip->IO_ADDR_R = nand->bank_base[banknr]; - chip->IO_ADDR_W = nand->bank_base[banknr]; + chip->legacy.IO_ADDR_R = nand->bank_base[banknr]; + chip->legacy.IO_ADDR_W = nand->bank_base[banknr]; } writel(ctrl, nand->base + JZ_REG_NAND_CTRL); nand->selected_bank = banknr; } -static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat, + unsigned int ctrl) { - struct jz_nand *nand = mtd_to_jz_nand(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); uint32_t reg; void __iomem *bank_base = nand->bank_base[nand->selected_bank]; @@ -115,7 +114,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) bank_base += JZ_NAND_MEM_ADDR_OFFSET; else if (ctrl & NAND_CLE) bank_base += JZ_NAND_MEM_CMD_OFFSET; - chip->IO_ADDR_W = bank_base; + chip->legacy.IO_ADDR_W = bank_base; reg = readl(nand->base + JZ_REG_NAND_CTRL); if (ctrl & NAND_NCE) @@ -125,18 +124,18 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) writel(reg, nand->base + JZ_REG_NAND_CTRL); } if (dat != NAND_CMD_NONE) - writeb(dat, chip->IO_ADDR_W); + writeb(dat, chip->legacy.IO_ADDR_W); } -static int jz_nand_dev_ready(struct mtd_info *mtd) +static int jz_nand_dev_ready(struct nand_chip *chip) { - struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); return gpiod_get_value_cansleep(nand->busy_gpio); } -static void jz_nand_hwctl(struct mtd_info *mtd, int mode) +static void jz_nand_hwctl(struct nand_chip *chip, int mode) { - struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); uint32_t reg; writel(0, nand->base + JZ_REG_NAND_IRQ_STAT); @@ -162,10 +161,10 @@ static void jz_nand_hwctl(struct mtd_info *mtd, int mode) writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); } -static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) +static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat, + uint8_t *ecc_code) { - struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); uint32_t reg, status; int i; unsigned int timeout = 1000; @@ -215,10 +214,10 @@ static void jz_nand_correct_data(uint8_t *dat, int index, int mask) dat[index+1] = (data >> 8) & 0xff; } -static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) +static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) { - struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip)); int i, error_count, index; uint32_t reg, status, error; unsigned int timeout = 1000; @@ -331,19 +330,19 @@ static int jz_nand_detect_bank(struct platform_device *pdev, if (chipnr == 0) { /* Detect first chip. */ - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret) goto notfound_id; /* Retrieve the IDs from the first chip. */ - chip->select_chip(mtd, 0); + chip->select_chip(chip, 0); nand_reset_op(chip); nand_readid_op(chip, 0, id, sizeof(id)); *nand_maf_id = id[0]; *nand_dev_id = id[1]; } else { /* Detect additional chip. */ - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); nand_reset_op(chip); nand_readid_op(chip, 0, id, sizeof(id)); if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) { @@ -426,13 +425,13 @@ static int jz_nand_probe(struct platform_device *pdev) chip->ecc.strength = 4; chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; - chip->chip_delay = 50; - chip->cmd_ctrl = jz_nand_cmd_ctrl; + chip->legacy.chip_delay = 50; + chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl; chip->select_chip = jz_nand_select_chip; chip->dummy_controller.ops = &jz_nand_controller_ops; if (nand->busy_gpio) - chip->dev_ready = jz_nand_dev_ready; + chip->legacy.dev_ready = jz_nand_dev_ready; platform_set_drvdata(pdev, nand); @@ -507,7 +506,7 @@ static int jz_nand_remove(struct platform_device *pdev) struct jz_nand *nand = platform_get_drvdata(pdev); size_t i; - nand_release(nand_to_mtd(&nand->chip)); + nand_release(&nand->chip); /* Deassert and disable all chips */ writel(0, nand->base + JZ_REG_NAND_CTRL); diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c index db4fa60bd52a..cdf22100ab77 100644 --- a/drivers/mtd/nand/raw/jz4780_nand.c +++ b/drivers/mtd/nand/raw/jz4780_nand.c @@ -71,9 +71,9 @@ static inline struct jz4780_nand_controller return container_of(ctrl, struct jz4780_nand_controller, controller); } -static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr) +static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr) { - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd); + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); struct jz4780_nand_cs *cs; @@ -86,10 +86,10 @@ static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr) nfc->selected = chipnr; } -static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, +static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd); + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); struct jz4780_nand_cs *cs; @@ -109,24 +109,24 @@ static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, writeb(cmd, cs->base + OFFSET_CMD); } -static int jz4780_nand_dev_ready(struct mtd_info *mtd) +static int jz4780_nand_dev_ready(struct nand_chip *chip) { - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd); + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); return !gpiod_get_value_cansleep(nand->busy_gpio); } -static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode) +static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode) { - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd); + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); nand->reading = (mode == NAND_ECC_READ); } -static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat, +static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat, u8 *ecc_code) { - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd); + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); struct jz4780_bch_params params; @@ -144,10 +144,10 @@ static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat, return jz4780_bch_calculate(nfc->bch, ¶ms, dat, ecc_code); } -static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat, +static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat, u8 *read_ecc, u8 *calc_ecc) { - struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd); + struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip)); struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller); struct jz4780_bch_params params; @@ -256,7 +256,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev, dev_err(dev, "failed to request busy GPIO: %d\n", ret); return ret; } else if (nand->busy_gpio) { - nand->chip.dev_ready = jz4780_nand_dev_ready; + nand->chip.legacy.dev_ready = jz4780_nand_dev_ready; } nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW); @@ -275,24 +275,24 @@ static int jz4780_nand_init_chip(struct platform_device *pdev, return -ENOMEM; mtd->dev.parent = dev; - chip->IO_ADDR_R = cs->base + OFFSET_DATA; - chip->IO_ADDR_W = cs->base + OFFSET_DATA; - chip->chip_delay = RB_DELAY_US; + chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA; + chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA; + chip->legacy.chip_delay = RB_DELAY_US; chip->options = NAND_NO_SUBPAGE_WRITE; chip->select_chip = jz4780_nand_select_chip; - chip->cmd_ctrl = jz4780_nand_cmd_ctrl; + chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl; chip->ecc.mode = NAND_ECC_HW; chip->controller = &nfc->controller; nand_set_flash_node(chip, np); chip->controller->ops = &jz4780_nand_controller_ops; - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret) return ret; ret = mtd_device_register(mtd, NULL, 0); if (ret) { - nand_release(mtd); + nand_release(chip); return ret; } @@ -307,7 +307,7 @@ static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc) while (!list_empty(&nfc->chips)) { chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list); - nand_release(nand_to_mtd(&chip->chip)); + nand_release(&chip->chip); list_del(&chip->chip_list); } } @@ -352,7 +352,7 @@ static int jz4780_nand_probe(struct platform_device *pdev) return -ENODEV; } - nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL); + nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL); if (!nfc) return -ENOMEM; diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index e82abada130a..abbb655fe154 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -286,10 +286,9 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) /* * Hardware specific access to control lines */ -static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, +static void lpc32xx_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd, unsigned int ctrl) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip); if (cmd != NAND_CMD_NONE) { @@ -303,9 +302,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, /* * Read Device Ready (NAND device _and_ controller ready) */ -static int lpc32xx_nand_device_ready(struct mtd_info *mtd) +static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip); if ((readb(MLC_ISR(host->io_base)) & @@ -330,8 +328,9 @@ static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host) return IRQ_HANDLED; } -static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip) +static int lpc32xx_waitfunc_nand(struct nand_chip *chip) { + struct mtd_info *mtd = nand_to_mtd(chip); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY) @@ -349,9 +348,9 @@ exit: return NAND_STATUS_READY; } -static int lpc32xx_waitfunc_controller(struct mtd_info *mtd, - struct nand_chip *chip) +static int lpc32xx_waitfunc_controller(struct nand_chip *chip) { + struct mtd_info *mtd = nand_to_mtd(chip); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY) @@ -369,10 +368,10 @@ exit: return NAND_STATUS_READY; } -static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +static int lpc32xx_waitfunc(struct nand_chip *chip) { - lpc32xx_waitfunc_nand(mtd, chip); - lpc32xx_waitfunc_controller(mtd, chip); + lpc32xx_waitfunc_nand(chip); + lpc32xx_waitfunc_controller(chip); return NAND_STATUS_READY; } @@ -442,9 +441,10 @@ out1: return -ENXIO; } -static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); int i, j; uint8_t *oobbuf = chip->oob_poi; @@ -470,7 +470,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base)); /* Wait for Controller Ready */ - lpc32xx_waitfunc_controller(mtd, chip); + lpc32xx_waitfunc_controller(chip); /* Check ECC Error status */ mlc_isr = readl(MLC_ISR(host->io_base)); @@ -507,11 +507,11 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, - struct nand_chip *chip, +static int lpc32xx_write_page_lowlevel(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); const uint8_t *oobbuf = chip->oob_poi; uint8_t *dma_buf = (uint8_t *)buf; @@ -551,32 +551,30 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base)); /* Wait for Controller Ready */ - lpc32xx_waitfunc_controller(mtd, chip); + lpc32xx_waitfunc_controller(chip); } return nand_prog_page_end_op(chip); } -static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int lpc32xx_read_oob(struct nand_chip *chip, int page) { struct lpc32xx_nand_host *host = nand_get_controller_data(chip); /* Read whole page - necessary with MLC controller! */ - lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page); + lpc32xx_read_page(chip, host->dummy_buf, 1, page); return 0; } -static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int lpc32xx_write_oob(struct nand_chip *chip, int page) { /* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */ return 0; } /* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */ -static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode) +static void lpc32xx_ecc_enable(struct nand_chip *chip, int mode) { /* Always enabled! */ } @@ -741,11 +739,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) if (res) goto put_clk; - nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; - nand_chip->dev_ready = lpc32xx_nand_device_ready; - nand_chip->chip_delay = 25; /* us */ - nand_chip->IO_ADDR_R = MLC_DATA(host->io_base); - nand_chip->IO_ADDR_W = MLC_DATA(host->io_base); + nand_chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl; + nand_chip->legacy.dev_ready = lpc32xx_nand_device_ready; + nand_chip->legacy.chip_delay = 25; /* us */ + nand_chip->legacy.IO_ADDR_R = MLC_DATA(host->io_base); + nand_chip->legacy.IO_ADDR_W = MLC_DATA(host->io_base); /* Init NAND controller */ lpc32xx_nand_setup(host); @@ -762,7 +760,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) nand_chip->ecc.read_oob = lpc32xx_read_oob; nand_chip->ecc.strength = 4; nand_chip->ecc.bytes = 10; - nand_chip->waitfunc = lpc32xx_waitfunc; + nand_chip->legacy.waitfunc = lpc32xx_waitfunc; nand_chip->options = NAND_NO_SUBPAGE_WRITE; nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; @@ -802,7 +800,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) * SMALL block or LARGE block. */ nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops; - res = nand_scan(mtd, 1); + res = nand_scan(nand_chip, 1); if (res) goto free_irq; @@ -839,9 +837,8 @@ free_gpio: static int lpc32xx_nand_remove(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); - struct mtd_info *mtd = nand_to_mtd(&host->nand_chip); - nand_release(mtd); + nand_release(&host->nand_chip); free_irq(host->irq, host); if (use_dma) dma_release_channel(host->dma_chan); diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index a4e8b7e75135..f2f2cdbb9d04 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -278,11 +278,10 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) /* * Hardware specific access to control lines */ -static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, - unsigned int ctrl) +static void lpc32xx_nand_cmd_ctrl(struct nand_chip *chip, int cmd, + unsigned int ctrl) { uint32_t tmp; - struct nand_chip *chip = mtd_to_nand(mtd); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); /* Does CE state need to be changed? */ @@ -304,9 +303,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, /* * Read the Device Ready pin */ -static int lpc32xx_nand_device_ready(struct mtd_info *mtd) +static int lpc32xx_nand_device_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); int rdy = 0; @@ -337,7 +335,7 @@ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) /* * Prepares SLC for transfers with H/W ECC enabled */ -static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode) +static void lpc32xx_nand_ecc_enable(struct nand_chip *chip, int mode) { /* Hardware ECC is enabled automatically in hardware as needed */ } @@ -345,7 +343,7 @@ static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode) /* * Calculates the ECC for the data */ -static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd, +static int lpc32xx_nand_ecc_calculate(struct nand_chip *chip, const unsigned char *buf, unsigned char *code) { @@ -359,9 +357,8 @@ static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd, /* * Read a single byte from NAND device */ -static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd) +static uint8_t lpc32xx_nand_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); return (uint8_t)readl(SLC_DATA(host->io_base)); @@ -370,9 +367,8 @@ static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd) /* * Simple device read without ECC */ -static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void lpc32xx_nand_read_buf(struct nand_chip *chip, u_char *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); /* Direct device read with no ECC */ @@ -383,9 +379,9 @@ static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) /* * Simple device write without ECC */ -static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void lpc32xx_nand_write_buf(struct nand_chip *chip, const uint8_t *buf, + int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); /* Direct device write with no ECC */ @@ -396,18 +392,20 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int /* * Read the OOB data from the device without ECC using FIFO method */ -static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int lpc32xx_nand_read_oob_syndrome(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); } /* * Write the OOB data to the device without ECC using FIFO method */ -static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int lpc32xx_nand_write_oob_syndrome(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi, mtd->oobsize); } @@ -610,10 +608,10 @@ static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages, * Read the data and OOB data from the device, use ECC correction with the * data, disable ECC for the OOB data */ -static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int lpc32xx_nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); struct mtd_oob_region oobregion = { }; int stat, i, status, error; @@ -626,7 +624,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1); /* Get OOB data */ - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); /* Convert to stored ECC format */ lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps); @@ -639,7 +637,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, oobecc = chip->oob_poi + oobregion.offset; for (i = 0; i < chip->ecc.steps; i++) { - stat = chip->ecc.correct(mtd, buf, oobecc, + stat = chip->ecc.correct(chip, buf, oobecc, &tmpecc[i * chip->ecc.bytes]); if (stat < 0) mtd->ecc_stats.failed++; @@ -657,17 +655,18 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, * Read the data and OOB data from the device, no ECC correction with the * data or OOB data */ -static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, +static int lpc32xx_nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + /* Issue read command */ nand_read_page_op(chip, page, 0, NULL, 0); /* Raw reads can just use the FIFO interface */ - chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.read_buf(chip, buf, chip->ecc.size * chip->ecc.steps); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); return 0; } @@ -676,11 +675,11 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd, * Write the data and OOB data to the device, use ECC with the data, * disable ECC for the OOB data */ -static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, +static int lpc32xx_nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct lpc32xx_nand_host *host = nand_get_controller_data(chip); struct mtd_oob_region oobregion = { }; uint8_t *pb; @@ -705,7 +704,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps); /* Write ECC data to device */ - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } @@ -714,15 +713,16 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, * Write the data and OOB data to the device, no ECC correction with the * data or OOB data */ -static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, +static int lpc32xx_nand_write_page_raw_syndrome(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + /* Raw writes can just use the FIFO interface */ nand_prog_page_begin_op(chip, page, 0, buf, chip->ecc.size * chip->ecc.steps); - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } @@ -878,11 +878,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) goto enable_wp; /* Set NAND IO addresses and command/ready functions */ - chip->IO_ADDR_R = SLC_DATA(host->io_base); - chip->IO_ADDR_W = SLC_DATA(host->io_base); - chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; - chip->dev_ready = lpc32xx_nand_device_ready; - chip->chip_delay = 20; /* 20us command delay time */ + chip->legacy.IO_ADDR_R = SLC_DATA(host->io_base); + chip->legacy.IO_ADDR_W = SLC_DATA(host->io_base); + chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl; + chip->legacy.dev_ready = lpc32xx_nand_device_ready; + chip->legacy.chip_delay = 20; /* 20us command delay time */ /* Init NAND controller */ lpc32xx_nand_setup(host); @@ -891,9 +891,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* NAND callbacks for LPC32xx SLC hardware */ chip->ecc.mode = NAND_ECC_HW_SYNDROME; - chip->read_byte = lpc32xx_nand_read_byte; - chip->read_buf = lpc32xx_nand_read_buf; - chip->write_buf = lpc32xx_nand_write_buf; + chip->legacy.read_byte = lpc32xx_nand_read_byte; + chip->legacy.read_buf = lpc32xx_nand_read_buf; + chip->legacy.write_buf = lpc32xx_nand_write_buf; chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome; chip->ecc.read_page = lpc32xx_nand_read_page_syndrome; chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome; @@ -925,7 +925,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* Find NAND device */ chip->dummy_controller.ops = &lpc32xx_nand_controller_ops; - res = nand_scan(mtd, 1); + res = nand_scan(chip, 1); if (res) goto release_dma; @@ -956,9 +956,8 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) { uint32_t tmp; struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); - struct mtd_info *mtd = nand_to_mtd(&host->nand_chip); - nand_release(mtd); + nand_release(&host->nand_chip); dma_release_channel(host->dma_chan); /* Force CE high */ diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index bc2ef5209783..650f2b490a05 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -5,6 +5,73 @@ * Copyright (C) 2017 Marvell * Author: Miquel RAYNAL <miquel.raynal@free-electrons.com> * + * + * This NAND controller driver handles two versions of the hardware, + * one is called NFCv1 and is available on PXA SoCs and the other is + * called NFCv2 and is available on Armada SoCs. + * + * The main visible difference is that NFCv1 only has Hamming ECC + * capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA + * is not used with NFCv2. + * + * The ECC layouts are depicted in details in Marvell AN-379, but here + * is a brief description. + * + * When using Hamming, the data is split in 512B chunks (either 1, 2 + * or 4) and each chunk will have its own ECC "digest" of 6B at the + * beginning of the OOB area and eventually the remaining free OOB + * bytes (also called "spare" bytes in the driver). This engine + * corrects up to 1 bit per chunk and detects reliably an error if + * there are at most 2 bitflips. Here is the page layout used by the + * controller when Hamming is chosen: + * + * +-------------------------------------------------------------+ + * | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes | + * +-------------------------------------------------------------+ + * + * When using the BCH engine, there are N identical (data + free OOB + + * ECC) sections and potentially an extra one to deal with + * configurations where the chosen (data + free OOB + ECC) sizes do + * not align with the page (data + OOB) size. ECC bytes are always + * 30B per ECC chunk. Here is the page layout used by the controller + * when BCH is chosen: + * + * +----------------------------------------- + * | Data 1 | Free OOB bytes 1 | ECC 1 | ... + * +----------------------------------------- + * + * ------------------------------------------- + * ... | Data N | Free OOB bytes N | ECC N | + * ------------------------------------------- + * + * --------------------------------------------+ + * Last Data | Last Free OOB bytes | Last ECC | + * --------------------------------------------+ + * + * In both cases, the layout seen by the user is always: all data + * first, then all free OOB bytes and finally all ECC bytes. With BCH, + * ECC bytes are 30B long and are padded with 0xFF to align on 32 + * bytes. + * + * The controller has certain limitations that are handled by the + * driver: + * - It can only read 2k at a time. To overcome this limitation, the + * driver issues data cycles on the bus, without issuing new + * CMD + ADDR cycles. The Marvell term is "naked" operations. + * - The ECC strength in BCH mode cannot be tuned. It is fixed 16 + * bits. What can be tuned is the ECC block size as long as it + * stays between 512B and 2kiB. It's usually chosen based on the + * chip ECC requirements. For instance, using 2kiB ECC chunks + * provides 4b/512B correctability. + * - The controller will always treat data bytes, free OOB bytes + * and ECC bytes in that order, no matter what the real layout is + * (which is usually all data then all OOB bytes). The + * marvell_nfc_layouts array below contains the currently + * supported layouts. + * - Because of these weird layouts, the Bad Block Markers can be + * located in data section. In this case, the NAND_BBT_NO_OOB_BBM + * option must be set to prevent scanning/writing bad block + * markers. */ #include <linux/module.h> @@ -217,8 +284,11 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = { MARVELL_LAYOUT( 512, 512, 1, 1, 1, 512, 8, 8, 0, 0, 0), MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0), MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0), + MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30), MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0), MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30), + MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0), + MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30), }; /** @@ -634,9 +704,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms) return 0; } -static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr) +static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr) { - struct nand_chip *chip = mtd_to_nand(mtd); struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); u32 ndcr_generic; @@ -686,7 +755,7 @@ static irqreturn_t marvell_nfc_isr(int irq, void *dev_id) marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT); - if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ))) + if (st & (NDSR_RDY(0) | NDSR_RDY(1))) complete(&nfc->complete); return IRQ_HANDLED; @@ -959,18 +1028,15 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip, return ret; } -static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, true, page); } -static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - u8 *buf, int oob_required, - int page) +static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf, + int oob_required, int page) { const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes; @@ -1008,8 +1074,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd, * it appears before the ECC bytes when reading), the ->read_oob_raw() function * also stands for ->read_oob(). */ -static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page) { /* Invalidate page cache */ chip->pagebuf = -1; @@ -1073,8 +1138,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip, return ret; } -static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -1082,8 +1146,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd, true, page); } -static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd, - struct nand_chip *chip, +static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -1102,10 +1165,11 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd, * it appears before the ECC bytes when reading), the ->write_oob_raw() function * also stands for ->write_oob(). */ -static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + /* Invalidate page cache */ chip->pagebuf = -1; @@ -1116,10 +1180,10 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd, } /* BCH read helpers */ -static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; u8 *oob = chip->oob_poi; int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes; @@ -1228,17 +1292,17 @@ static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk, } } -static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd, - struct nand_chip *chip, +static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; - int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len; - u8 *data = buf, *spare = chip->oob_poi, *ecc; + int data_len = lt->data_bytes, spare_len = lt->spare_bytes; + u8 *data = buf, *spare = chip->oob_poi; int max_bitflips = 0; u32 failure_mask = 0; - int chunk, ecc_offset_in_page, ret; + int chunk, ret; /* * With BCH, OOB is not fully used (and thus not read entirely), not @@ -1279,73 +1343,98 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd, * the controller in normal mode and must be re-read in raw mode. To * avoid dropping the performances, we prefer not to include them. The * user should re-read the page in raw mode if ECC bytes are required. + */ + + /* + * In case there is any subpage read error reported by ->correct(), we + * usually re-read only ECC bytes in raw mode and check if the whole + * page is empty. In this case, it is normal that the ECC check failed + * and we just ignore the error. * - * However, for any subpage read error reported by ->correct(), the ECC - * bytes must be read in raw mode and the full subpage must be checked - * to see if it is entirely empty of if there was an actual error. + * However, it has been empirically observed that for some layouts (e.g + * 2k page, 8b strength per 512B chunk), the controller tries to correct + * bits and may create itself bitflips in the erased area. To overcome + * this strange behavior, the whole page is re-read in raw mode, not + * only the ECC bytes. */ for (chunk = 0; chunk < lt->nchunks; chunk++) { + int data_off_in_page, spare_off_in_page, ecc_off_in_page; + int data_off, spare_off, ecc_off; + int data_len, spare_len, ecc_len; + /* No failure reported for this chunk, move to the next one */ if (!(failure_mask & BIT(chunk))) continue; - /* Derive ECC bytes positions (in page/buffer) and length */ - ecc = chip->oob_poi + - (lt->full_chunk_cnt * lt->spare_bytes) + - lt->last_spare_bytes + - (chunk * ALIGN(lt->ecc_bytes, 32)); - ecc_offset_in_page = - (chunk * (lt->data_bytes + lt->spare_bytes + - lt->ecc_bytes)) + - (chunk < lt->full_chunk_cnt ? - lt->data_bytes + lt->spare_bytes : - lt->last_data_bytes + lt->last_spare_bytes); - ecc_len = chunk < lt->full_chunk_cnt ? - lt->ecc_bytes : lt->last_ecc_bytes; - - /* Do the actual raw read of the ECC bytes */ - nand_change_read_column_op(chip, ecc_offset_in_page, - ecc, ecc_len, false); - - /* Derive data/spare bytes positions (in buffer) and length */ - data = buf + (chunk * lt->data_bytes); - data_len = chunk < lt->full_chunk_cnt ? - lt->data_bytes : lt->last_data_bytes; - spare = chip->oob_poi + (chunk * (lt->spare_bytes + - lt->ecc_bytes)); - spare_len = chunk < lt->full_chunk_cnt ? - lt->spare_bytes : lt->last_spare_bytes; + data_off_in_page = chunk * (lt->data_bytes + lt->spare_bytes + + lt->ecc_bytes); + spare_off_in_page = data_off_in_page + + (chunk < lt->full_chunk_cnt ? lt->data_bytes : + lt->last_data_bytes); + ecc_off_in_page = spare_off_in_page + + (chunk < lt->full_chunk_cnt ? lt->spare_bytes : + lt->last_spare_bytes); + + data_off = chunk * lt->data_bytes; + spare_off = chunk * lt->spare_bytes; + ecc_off = (lt->full_chunk_cnt * lt->spare_bytes) + + lt->last_spare_bytes + + (chunk * (lt->ecc_bytes + 2)); + + data_len = chunk < lt->full_chunk_cnt ? lt->data_bytes : + lt->last_data_bytes; + spare_len = chunk < lt->full_chunk_cnt ? lt->spare_bytes : + lt->last_spare_bytes; + ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes : + lt->last_ecc_bytes; + + /* + * Only re-read the ECC bytes, unless we are using the 2k/8b + * layout which is buggy in the sense that the ECC engine will + * try to correct data bytes anyway, creating bitflips. In this + * case, re-read the entire page. + */ + if (lt->writesize == 2048 && lt->strength == 8) { + nand_change_read_column_op(chip, data_off_in_page, + buf + data_off, data_len, + false); + nand_change_read_column_op(chip, spare_off_in_page, + chip->oob_poi + spare_off, spare_len, + false); + } + + nand_change_read_column_op(chip, ecc_off_in_page, + chip->oob_poi + ecc_off, ecc_len, + false); /* Check the entire chunk (data + spare + ecc) for emptyness */ - marvell_nfc_check_empty_chunk(chip, data, data_len, spare, - spare_len, ecc, ecc_len, + marvell_nfc_check_empty_chunk(chip, buf + data_off, data_len, + chip->oob_poi + spare_off, spare_len, + chip->oob_poi + ecc_off, ecc_len, &max_bitflips); } return max_bitflips; } -static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page) { /* Invalidate page cache */ chip->pagebuf = -1; - return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page); + return chip->ecc.read_page_raw(chip, chip->data_buf, true, page); } -static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page) { /* Invalidate page cache */ chip->pagebuf = -1; - return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page); + return chip->ecc.read_page(chip, chip->data_buf, true, page); } /* BCH write helpers */ -static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -1458,11 +1547,11 @@ marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk, return 0; } -static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd, - struct nand_chip *chip, +static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout; const u8 *data = buf; const u8 *spare = chip->oob_poi; @@ -1507,27 +1596,29 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd, return 0; } -static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd, - struct nand_chip *chip, +static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + /* Invalidate page cache */ chip->pagebuf = -1; memset(chip->data_buf, 0xFF, mtd->writesize); - return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page); + return chip->ecc.write_page_raw(chip, chip->data_buf, true, page); } -static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd, - struct nand_chip *chip, int page) +static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + /* Invalidate page cache */ chip->pagebuf = -1; memset(chip->data_buf, 0xFF, mtd->writesize); - return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page); + return chip->ecc.write_page(chip, chip->data_buf, true, page); } /* NAND framework ->exec_op() hooks and related helpers */ @@ -2097,6 +2188,16 @@ static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, return -ENOTSUPP; } + /* Special care for the layout 2k/8-bit/512B */ + if (l->writesize == 2048 && l->strength == 8) { + if (mtd->oobsize < 128) { + dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n"); + return -ENOTSUPP; + } else { + chip->bbt_options |= NAND_BBT_NO_OOB_BBM; + } + } + mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops); ecc->steps = l->nchunks; ecc->size = l->data_bytes; @@ -2192,11 +2293,10 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = bbt_mirror_pattern }; -static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr, +static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr, const struct nand_data_interface *conf) { - struct nand_chip *chip = mtd_to_nand(mtd); struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2; @@ -2540,7 +2640,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, chip->options |= NAND_BUSWIDTH_AUTO; - ret = nand_scan(mtd, marvell_nand->nsels); + ret = nand_scan(chip, marvell_nand->nsels); if (ret) { dev_err(dev, "could not scan the nand chip\n"); return ret; @@ -2553,7 +2653,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(dev, "failed to register mtd device: %d\n", ret); - nand_release(mtd); + nand_release(chip); return ret; } @@ -2608,7 +2708,7 @@ static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc) struct marvell_nand_chip *entry, *temp; list_for_each_entry_safe(entry, temp, &nfc->chips, node) { - nand_release(nand_to_mtd(&entry->chip)); + nand_release(&entry->chip); list_del(&entry->node); } } @@ -2699,24 +2799,23 @@ static int marvell_nfc_init(struct marvell_nfc *nfc) struct regmap *sysctrl_base = syscon_regmap_lookup_by_phandle(np, "marvell,system-controller"); - u32 reg; if (IS_ERR(sysctrl_base)) return PTR_ERR(sysctrl_base); - reg = GENCONF_SOC_DEVICE_MUX_NFC_EN | - GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST | - GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST | - GENCONF_SOC_DEVICE_MUX_NFC_INT_EN; - regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg); + regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, + GENCONF_SOC_DEVICE_MUX_NFC_EN | + GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST | + GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST | + GENCONF_SOC_DEVICE_MUX_NFC_INT_EN); - regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, ®); - reg |= GENCONF_CLK_GATING_CTRL_ND_GATE; - regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg); + regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL, + GENCONF_CLK_GATING_CTRL_ND_GATE, + GENCONF_CLK_GATING_CTRL_ND_GATE); - regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, ®); - reg |= GENCONF_ND_CLK_CTRL_EN; - regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg); + regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL, + GENCONF_ND_CLK_CTRL_EN, + GENCONF_ND_CLK_CTRL_EN); } /* Configure the DMA if appropriate */ diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index 6d1740d54e0d..86a0aabe08df 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -263,8 +263,10 @@ static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) } /* Control chip select signals */ -static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip) +static void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip) { + struct mtd_info *mtd = nand_to_mtd(nand); + if (chip < 0) { nfc_clear(mtd, NFC_CONFIG1, NFC_CE); return; @@ -299,9 +301,9 @@ static int ads5121_chipselect_init(struct mtd_info *mtd) } /* Control chips select signal on ADS5121 board */ -static void ads5121_select_chip(struct mtd_info *mtd, int chip) +static void ads5121_select_chip(struct nand_chip *nand, int chip) { - struct nand_chip *nand = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(nand); struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); u8 v; @@ -309,16 +311,16 @@ static void ads5121_select_chip(struct mtd_info *mtd, int chip) v |= 0x0F; if (chip >= 0) { - mpc5121_nfc_select_chip(mtd, 0); + mpc5121_nfc_select_chip(nand, 0); v &= ~(1 << chip); } else - mpc5121_nfc_select_chip(mtd, -1); + mpc5121_nfc_select_chip(nand, -1); out_8(prv->csreg, v); } /* Read NAND Ready/Busy signal */ -static int mpc5121_nfc_dev_ready(struct mtd_info *mtd) +static int mpc5121_nfc_dev_ready(struct nand_chip *nand) { /* * NFC handles ready/busy signal internally. Therefore, this function @@ -328,10 +330,10 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd) } /* Write command to NAND flash */ -static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command, - int column, int page) +static void mpc5121_nfc_command(struct nand_chip *chip, unsigned command, + int column, int page) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); prv->column = (column >= 0) ? column : 0; @@ -362,7 +364,7 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command, break; case NAND_CMD_SEQIN: - mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page); + mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page); column = 0; break; @@ -493,34 +495,24 @@ static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len, } /* Read data from NFC buffers */ -static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len) { - mpc5121_nfc_buf_copy(mtd, buf, len, 0); + mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0); } /* Write data to NFC buffers */ -static void mpc5121_nfc_write_buf(struct mtd_info *mtd, - const u_char *buf, int len) +static void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf, + int len) { - mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1); + mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1); } /* Read byte from NFC buffers */ -static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd) +static u8 mpc5121_nfc_read_byte(struct nand_chip *chip) { u8 tmp; - mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp)); - - return tmp; -} - -/* Read word from NFC buffers */ -static u16 mpc5121_nfc_read_word(struct mtd_info *mtd) -{ - u16 tmp; - - mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); + mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp)); return tmp; } @@ -700,15 +692,14 @@ static int mpc5121_nfc_probe(struct platform_device *op) } mtd->name = "MPC5121 NAND"; - chip->dev_ready = mpc5121_nfc_dev_ready; - chip->cmdfunc = mpc5121_nfc_command; - chip->read_byte = mpc5121_nfc_read_byte; - chip->read_word = mpc5121_nfc_read_word; - chip->read_buf = mpc5121_nfc_read_buf; - chip->write_buf = mpc5121_nfc_write_buf; + chip->legacy.dev_ready = mpc5121_nfc_dev_ready; + chip->legacy.cmdfunc = mpc5121_nfc_command; + chip->legacy.read_byte = mpc5121_nfc_read_byte; + chip->legacy.read_buf = mpc5121_nfc_read_buf; + chip->legacy.write_buf = mpc5121_nfc_write_buf; chip->select_chip = mpc5121_nfc_select_chip; - chip->set_features = nand_get_set_features_notsupp; - chip->get_features = nand_get_set_features_notsupp; + chip->legacy.set_features = nand_get_set_features_notsupp; + chip->legacy.get_features = nand_get_set_features_notsupp; chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; @@ -778,7 +769,7 @@ static int mpc5121_nfc_probe(struct platform_device *op) } /* Detect NAND chips */ - retval = nand_scan(mtd, be32_to_cpup(chips_no)); + retval = nand_scan(chip, be32_to_cpup(chips_no)); if (retval) { dev_err(dev, "NAND Flash not found !\n"); goto error; @@ -828,7 +819,7 @@ static int mpc5121_nfc_remove(struct platform_device *op) struct device *dev = &op->dev; struct mtd_info *mtd = dev_get_drvdata(dev); - nand_release(mtd); + nand_release(mtd_to_nand(mtd)); mpc5121_nfc_free(dev, mtd); return 0; diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index 57b5ed1699e3..2bb0df1b7244 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -389,23 +389,22 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd) return 0; } -static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip) +static void mtk_nfc_select_chip(struct nand_chip *nand, int chip) { - struct nand_chip *nand = mtd_to_nand(mtd); struct mtk_nfc *nfc = nand_get_controller_data(nand); struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand); if (chip < 0) return; - mtk_nfc_hw_runtime_config(mtd); + mtk_nfc_hw_runtime_config(nand_to_mtd(nand)); nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL); } -static int mtk_nfc_dev_ready(struct mtd_info *mtd) +static int mtk_nfc_dev_ready(struct nand_chip *nand) { - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + struct mtk_nfc *nfc = nand_get_controller_data(nand); if (nfi_readl(nfc, NFI_STA) & STA_BUSY) return 0; @@ -413,9 +412,10 @@ static int mtk_nfc_dev_ready(struct mtd_info *mtd) return 1; } -static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat, + unsigned int ctrl) { - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + struct mtk_nfc *nfc = nand_get_controller_data(chip); if (ctrl & NAND_ALE) { mtk_nfc_send_address(nfc, dat); @@ -438,9 +438,8 @@ static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc) dev_err(nfc->dev, "data not ready\n"); } -static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd) +static inline u8 mtk_nfc_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct mtk_nfc *nfc = nand_get_controller_data(chip); u32 reg; @@ -467,17 +466,17 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd) return nfi_readb(nfc, NFI_DATAR); } -static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void mtk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len) { int i; for (i = 0; i < len; i++) - buf[i] = mtk_nfc_read_byte(mtd); + buf[i] = mtk_nfc_read_byte(chip); } -static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte) +static void mtk_nfc_write_byte(struct nand_chip *chip, u8 byte) { - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + struct mtk_nfc *nfc = nand_get_controller_data(chip); u32 reg; reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK; @@ -496,18 +495,18 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte) nfi_writeb(nfc, byte, NFI_DATAW); } -static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len) { int i; for (i = 0; i < len; i++) - mtk_nfc_write_byte(mtd, buf[i]); + mtk_nfc_write_byte(chip, buf[i]); } -static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline, +static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline, const struct nand_data_interface *conf) { - struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + struct mtk_nfc *nfc = nand_get_controller_data(chip); const struct nand_sdr_timings *timings; u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt; @@ -807,27 +806,27 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, return nand_prog_page_end_op(chip); } -static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, +static int mtk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, int oob_on, int page) { - return mtk_nfc_write_page(mtd, chip, buf, page, 0); + return mtk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0); } -static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const u8 *buf, int oob_on, int pg) +static int mtk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf, + int oob_on, int pg) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mtk_nfc *nfc = nand_get_controller_data(chip); mtk_nfc_format_page(mtd, buf); return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1); } -static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, u32 offset, +static int mtk_nfc_write_subpage_hwecc(struct nand_chip *chip, u32 offset, u32 data_len, const u8 *buf, int oob_on, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mtk_nfc *nfc = nand_get_controller_data(chip); int ret; @@ -839,10 +838,9 @@ static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd, return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1); } -static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page) { - return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page); + return mtk_nfc_write_page_raw(chip, NULL, 1, page); } static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors) @@ -969,23 +967,25 @@ done: return bitflips; } -static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, u32 off, +static int mtk_nfc_read_subpage_hwecc(struct nand_chip *chip, u32 off, u32 len, u8 *p, int pg) { - return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0); + return mtk_nfc_read_subpage(nand_to_mtd(chip), chip, off, len, p, pg, + 0); } -static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, u8 *p, - int oob_on, int pg) +static int mtk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on, + int pg) { + struct mtd_info *mtd = nand_to_mtd(chip); + return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0); } -static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - u8 *buf, int oob_on, int page) +static int mtk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on, + int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip); struct mtk_nfc *nfc = nand_get_controller_data(chip); struct mtk_nfc_fdm *fdm = &mtk_nand->fdm; @@ -1011,10 +1011,9 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return ret; } -static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int mtk_nfc_read_oob_std(struct nand_chip *chip, int page) { - return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page); + return mtk_nfc_read_page_raw(chip, NULL, 1, page); } static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc) @@ -1333,13 +1332,13 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, nand_set_controller_data(nand, nfc); nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ; - nand->dev_ready = mtk_nfc_dev_ready; + nand->legacy.dev_ready = mtk_nfc_dev_ready; nand->select_chip = mtk_nfc_select_chip; - nand->write_byte = mtk_nfc_write_byte; - nand->write_buf = mtk_nfc_write_buf; - nand->read_byte = mtk_nfc_read_byte; - nand->read_buf = mtk_nfc_read_buf; - nand->cmd_ctrl = mtk_nfc_cmd_ctrl; + nand->legacy.write_byte = mtk_nfc_write_byte; + nand->legacy.write_buf = mtk_nfc_write_buf; + nand->legacy.read_byte = mtk_nfc_read_byte; + nand->legacy.read_buf = mtk_nfc_read_buf; + nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl; nand->setup_data_interface = mtk_nfc_setup_data_interface; /* set default mode in case dt entry is missing */ @@ -1365,14 +1364,14 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, mtk_nfc_hw_init(nfc); - ret = nand_scan(mtd, nsels); + ret = nand_scan(nand, nsels); if (ret) return ret; ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(dev, "mtd parse partition error\n"); - nand_release(mtd); + nand_release(nand); return ret; } @@ -1538,7 +1537,7 @@ static int mtk_nfc_remove(struct platform_device *pdev) while (!list_empty(&nfc->chips)) { chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip, node); - nand_release(nand_to_mtd(&chip->nand)); + nand_release(&chip->nand); list_del(&chip->node); } diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 4c9214dea424..88bd3f6a499c 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -136,8 +136,8 @@ struct mxc_nand_devtype_data { void (*irq_control)(struct mxc_nand_host *, int); u32 (*get_ecc_status)(struct mxc_nand_host *); const struct mtd_ooblayout_ops *ooblayout; - void (*select_chip)(struct mtd_info *mtd, int chip); - int (*setup_data_interface)(struct mtd_info *mtd, int csline, + void (*select_chip)(struct nand_chip *chip, int cs); + int (*setup_data_interface)(struct nand_chip *chip, int csline, const struct nand_data_interface *conf); void (*enable_hwecc)(struct nand_chip *chip, bool enable); @@ -701,7 +701,7 @@ static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable) } /* This functions is used by upper layer to checks if device is ready */ -static int mxc_nand_dev_ready(struct mtd_info *mtd) +static int mxc_nand_dev_ready(struct nand_chip *chip) { /* * NFC handles R/B internally. Therefore, this function @@ -816,8 +816,8 @@ static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf, return max_bitflips; } -static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct mxc_nand_host *host = nand_get_controller_data(chip); void *oob_buf; @@ -830,8 +830,8 @@ static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, return host->devtype_data->read_page(chip, buf, oob_buf, 1, page); } -static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct mxc_nand_host *host = nand_get_controller_data(chip); void *oob_buf; @@ -844,8 +844,7 @@ static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return host->devtype_data->read_page(chip, buf, oob_buf, 0, page); } -static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int mxc_nand_read_oob(struct nand_chip *chip, int page) { struct mxc_nand_host *host = nand_get_controller_data(chip); @@ -874,22 +873,21 @@ static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf, return 0; } -static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { return mxc_nand_write_page(chip, buf, true, page); } -static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { return mxc_nand_write_page(chip, buf, false, page); } -static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int mxc_nand_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mxc_nand_host *host = nand_get_controller_data(chip); memset(host->data_buf, 0xff, mtd->writesize); @@ -897,9 +895,8 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, return mxc_nand_write_page(chip, host->data_buf, false, page); } -static u_char mxc_nand_read_byte(struct mtd_info *mtd) +static u_char mxc_nand_read_byte(struct nand_chip *nand_chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); uint8_t ret; @@ -921,25 +918,13 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) return ret; } -static uint16_t mxc_nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - uint16_t ret; - - ret = *(uint16_t *)(host->data_buf + host->buf_start); - host->buf_start += 2; - - return ret; -} - /* Write data of length len to buffer buf. The data to be * written on NAND Flash is first copied to RAMbuffer. After the Data Input * Operation by the NFC, the data is written to NAND Flash */ -static void mxc_nand_write_buf(struct mtd_info *mtd, - const u_char *buf, int len) +static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf, + int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(nand_chip); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); u16 col = host->buf_start; int n = mtd->oobsize + mtd->writesize - col; @@ -955,9 +940,10 @@ static void mxc_nand_write_buf(struct mtd_info *mtd, * Flash first the data output cycle is initiated by the NFC, which copies * the data to RAMbuffer. This data of length len is then copied to buffer buf. */ -static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf, + int len) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(nand_chip); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); u16 col = host->buf_start; int n = mtd->oobsize + mtd->writesize - col; @@ -971,9 +957,8 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) /* This function is used by upper layer for select and * deselect of the NAND chip */ -static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip) +static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); if (chip == -1) { @@ -992,9 +977,8 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip) } } -static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) +static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); if (chip == -1) { @@ -1155,11 +1139,10 @@ static void preset_v1(struct mtd_info *mtd) writew(0x4, NFC_V1_V2_WRPROT); } -static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline, +static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline, const struct nand_data_interface *conf) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); int tRC_min_ns, tRC_ps, ret; unsigned long rate, rate_round; const struct nand_sdr_timings *timings; @@ -1349,10 +1332,10 @@ static void preset_v3(struct mtd_info *mtd) /* Used by the upper layer to write command to NAND Flash for * different operations to be carried out on NAND Flash */ -static void mxc_nand_command(struct mtd_info *mtd, unsigned command, - int column, int page_addr) +static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command, + int column, int page_addr) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(nand_chip); struct mxc_nand_host *host = nand_get_controller_data(nand_chip); dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", @@ -1409,17 +1392,17 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, } } -static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, u8 *subfeature_param) +static int mxc_nand_set_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); int i; host->buf_start = 0; for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - chip->write_byte(mtd, subfeature_param[i]); + chip->legacy.write_byte(chip, subfeature_param[i]); memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize); host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false); @@ -1429,11 +1412,11 @@ static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, u8 *subfeature_param) +static int mxc_nand_get_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct mxc_nand_host *host = nand_get_controller_data(chip); int i; host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false); @@ -1443,7 +1426,7 @@ static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip, host->buf_start = 0; for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - *subfeature_param++ = chip->read_byte(mtd); + *subfeature_param++ = chip->legacy.read_byte(chip); return 0; } @@ -1786,18 +1769,17 @@ static int mxcnd_probe(struct platform_device *pdev) mtd->name = DRIVER_NAME; /* 50 us command delay time */ - this->chip_delay = 5; + this->legacy.chip_delay = 5; nand_set_controller_data(this, host); nand_set_flash_node(this, pdev->dev.of_node), - this->dev_ready = mxc_nand_dev_ready; - this->cmdfunc = mxc_nand_command; - this->read_byte = mxc_nand_read_byte; - this->read_word = mxc_nand_read_word; - this->write_buf = mxc_nand_write_buf; - this->read_buf = mxc_nand_read_buf; - this->set_features = mxc_nand_set_features; - this->get_features = mxc_nand_get_features; + this->legacy.dev_ready = mxc_nand_dev_ready; + this->legacy.cmdfunc = mxc_nand_command; + this->legacy.read_byte = mxc_nand_read_byte; + this->legacy.write_buf = mxc_nand_write_buf; + this->legacy.read_buf = mxc_nand_read_buf; + this->legacy.set_features = mxc_nand_set_features; + this->legacy.get_features = mxc_nand_get_features; host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) @@ -1900,7 +1882,7 @@ static int mxcnd_probe(struct platform_device *pdev) /* Scan the NAND device */ this->dummy_controller.ops = &mxcnd_controller_ops; - err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1); + err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1); if (err) goto escan; @@ -1928,7 +1910,7 @@ static int mxcnd_remove(struct platform_device *pdev) { struct mxc_nand_host *host = platform_get_drvdata(pdev); - nand_release(nand_to_mtd(&host->nand)); + nand_release(&host->nand); if (host->clk_act) clk_disable_unprepare(host->clk); diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c index 22f060f38123..890c5b43e03c 100644 --- a/drivers/mtd/nand/raw/nand_amd.c +++ b/drivers/mtd/nand/raw/nand_amd.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include <linux/mtd/rawnand.h> +#include "internals.h" static void amd_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index d527e448ce19..05bd0779fe9b 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -36,10 +36,8 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/mm.h> -#include <linux/nmi.h> #include <linux/types.h> #include <linux/mtd/mtd.h> -#include <linux/mtd/rawnand.h> #include <linux/mtd/nand_ecc.h> #include <linux/mtd/nand_bch.h> #include <linux/interrupt.h> @@ -48,6 +46,8 @@ #include <linux/mtd/partitions.h> #include <linux/of.h> +#include "internals.h" + static int nand_get_device(struct mtd_info *mtd, int new_state); static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, @@ -253,183 +253,16 @@ static void nand_release_device(struct mtd_info *mtd) } /** - * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure - * - * Default read function for 8bit buswidth - */ -static uint8_t nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - return readb(chip->IO_ADDR_R); -} - -/** - * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip - * @mtd: MTD device structure - * - * Default read function for 16bit buswidth with endianness conversion. - * - */ -static uint8_t nand_read_byte16(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); -} - -/** - * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure - * - * Default read function for 16bit buswidth without endianness conversion. - */ -static u16 nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - return readw(chip->IO_ADDR_R); -} - -/** - * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect - * - * Default select function for 1 chip devices. - */ -static void nand_select_chip(struct mtd_info *mtd, int chipnr) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - switch (chipnr) { - case -1: - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - break; - case 0: - break; - - default: - BUG(); - } -} - -/** - * nand_write_byte - [DEFAULT] write single byte to chip - * @mtd: MTD device structure - * @byte: value to write - * - * Default function to write a byte to I/O[7:0] - */ -static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - chip->write_buf(mtd, &byte, 1); -} - -/** - * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 - * @mtd: MTD device structure - * @byte: value to write - * - * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. - */ -static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - uint16_t word = byte; - - /* - * It's not entirely clear what should happen to I/O[15:8] when writing - * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: - * - * When the host supports a 16-bit bus width, only data is - * transferred at the 16-bit width. All address and command line - * transfers shall use only the lower 8-bits of the data bus. During - * command transfers, the host may place any value on the upper - * 8-bits of the data bus. During address transfers, the host shall - * set the upper 8-bits of the data bus to 00h. - * - * One user of the write_byte callback is nand_set_features. The - * four parameters are specified to be written to I/O[7:0], but this is - * neither an address nor a command transfer. Let's assume a 0 on the - * upper I/O lines is OK. - */ - chip->write_buf(mtd, (uint8_t *)&word, 2); -} - -/** - * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write - * - * Default write function for 8bit buswidth. - */ -static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - iowrite8_rep(chip->IO_ADDR_W, buf, len); -} - -/** - * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read - * - * Default read function for 8bit buswidth. - */ -static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - ioread8_rep(chip->IO_ADDR_R, buf, len); -} - -/** - * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write - * - * Default write function for 16bit buswidth. - */ -static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u16 *p = (u16 *) buf; - - iowrite16_rep(chip->IO_ADDR_W, p, len >> 1); -} - -/** - * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read - * - * Default read function for 16bit buswidth. - */ -static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u16 *p = (u16 *) buf; - - ioread16_rep(chip->IO_ADDR_R, p, len >> 1); -} - -/** * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure + * @chip: NAND chip object * @ofs: offset from device start * * Check, if the block is bad. */ -static int nand_block_bad(struct mtd_info *mtd, loff_t ofs) +static int nand_block_bad(struct nand_chip *chip, loff_t ofs) { + struct mtd_info *mtd = nand_to_mtd(chip); int page, page_end, res; - struct nand_chip *chip = mtd_to_nand(mtd); u8 bad; if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) @@ -439,7 +272,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs) page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1); for (; page < page_end; page++) { - res = chip->ecc.read_oob(mtd, chip, page); + res = chip->ecc.read_oob(chip, page); if (res < 0) return res; @@ -458,16 +291,16 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs) /** * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker - * @mtd: MTD device structure + * @chip: NAND chip object * @ofs: offset from device start * * This is the default implementation, which can be overridden by a hardware * specific driver. It provides the details for writing a bad block marker to a * block. */ -static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) +static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_oob_ops ops; uint8_t buf[2] = { 0, 0 }; int ret = 0, res, i = 0; @@ -499,13 +332,34 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) } /** + * nand_markbad_bbm - mark a block by updating the BBM + * @chip: NAND chip object + * @ofs: offset of the block to mark bad + */ +int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs) +{ + if (chip->legacy.block_markbad) + return chip->legacy.block_markbad(chip, ofs); + + return nand_default_block_markbad(chip, ofs); +} + +static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) +{ + if (chip->legacy.block_bad) + return chip->legacy.block_bad(chip, ofs); + + return nand_block_bad(chip, ofs); +} + +/** * nand_block_markbad_lowlevel - mark a block bad * @mtd: MTD device structure * @ofs: offset from device start * * This function performs the generic NAND bad block marking steps (i.e., bad * block table(s) and/or marker(s)). We only allow the hardware driver to - * specify how to write bad block markers to OOB (chip->block_markbad). + * specify how to write bad block markers to OOB (chip->legacy.block_markbad). * * We try operations in the following order: * @@ -529,17 +383,17 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) memset(&einfo, 0, sizeof(einfo)); einfo.addr = ofs; einfo.len = 1ULL << chip->phys_erase_shift; - nand_erase_nand(mtd, &einfo, 0); + nand_erase_nand(chip, &einfo, 0); /* Write bad block marker to OOB */ nand_get_device(mtd, FL_WRITING); - ret = chip->block_markbad(mtd, ofs); + ret = nand_markbad_bbm(chip, ofs); nand_release_device(mtd); } /* Mark block bad in BBT */ if (chip->bbt) { - res = nand_markbad_bbt(mtd, ofs); + res = nand_markbad_bbt(chip, ofs); if (!ret) ret = res; } @@ -589,7 +443,7 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs) if (!chip->bbt) return 0; /* Return info from the table */ - return nand_isreserved_bbt(mtd, ofs); + return nand_isreserved_bbt(chip, ofs); } /** @@ -605,89 +459,14 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt) { struct nand_chip *chip = mtd_to_nand(mtd); - if (!chip->bbt) - return chip->block_bad(mtd, ofs); - /* Return info from the table */ - return nand_isbad_bbt(mtd, ofs, allowbbt); -} + if (chip->bbt) + return nand_isbad_bbt(chip, ofs, allowbbt); -/** - * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. - * @mtd: MTD device structure - * @timeo: Timeout - * - * Helper function for nand_wait_ready used when needing to wait in interrupt - * context. - */ -static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int i; - - /* Wait for the device to get ready */ - for (i = 0; i < timeo; i++) { - if (chip->dev_ready(mtd)) - break; - touch_softlockup_watchdog(); - mdelay(1); - } + return nand_isbad_bbm(chip, ofs); } /** - * nand_wait_ready - [GENERIC] Wait for the ready pin after commands. - * @mtd: MTD device structure - * - * Wait for the ready pin after a command, and warn if a timeout occurs. - */ -void nand_wait_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - unsigned long timeo = 400; - - if (in_interrupt() || oops_in_progress) - return panic_nand_wait_ready(mtd, timeo); - - /* Wait until command is processed or timeout occurs */ - timeo = jiffies + msecs_to_jiffies(timeo); - do { - if (chip->dev_ready(mtd)) - return; - cond_resched(); - } while (time_before(jiffies, timeo)); - - if (!chip->dev_ready(mtd)) - pr_warn_ratelimited("timeout while waiting for chip to become ready\n"); -} -EXPORT_SYMBOL_GPL(nand_wait_ready); - -/** - * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. - * @mtd: MTD device structure - * @timeo: Timeout in ms - * - * Wait for status ready (i.e. command done) or timeout. - */ -static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - int ret; - - timeo = jiffies + msecs_to_jiffies(timeo); - do { - u8 status; - - ret = nand_read_data_op(chip, &status, sizeof(status), true); - if (ret) - return; - - if (status & NAND_STATUS_READY) - break; - touch_softlockup_watchdog(); - } while (time_before(jiffies, timeo)); -}; - -/** * nand_soft_waitrdy - Poll STATUS reg until RDY bit is set to 1 * @chip: NAND chip structure * @timeout_ms: Timeout in ms @@ -753,273 +532,6 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) EXPORT_SYMBOL_GPL(nand_soft_waitrdy); /** - * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none - * - * Send command to NAND device. This function is used for small page devices - * (512 Bytes per page). - */ -static void nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - - /* Write out the command to the device */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->writesize) { - /* OOB area */ - column -= mtd->writesize; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - chip->cmd_ctrl(mtd, readcmd, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - if (command != NAND_CMD_NONE) - chip->cmd_ctrl(mtd, command, ctrl); - - /* Address cycle, when necessary */ - ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16 && - !nand_opcode_8bits(command)) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); - if (chip->options & NAND_ROW_ADDR_3) - chip->cmd_ctrl(mtd, page_addr >> 16, ctrl); - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Program and erase have their own busy handlers status and sequential - * in needs no delay - */ - switch (command) { - - case NAND_CMD_NONE: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - case NAND_CMD_READID: - case NAND_CMD_SET_FEATURES: - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, - NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ - nand_wait_status_ready(mtd, 250); - return; - - /* This applies to read commands */ - case NAND_CMD_READ0: - /* - * READ0 is sometimes used to exit GET STATUS mode. When this - * is the case no address cycles are requested, and we can use - * this information to detect that we should not wait for the - * device to be ready. - */ - if (column == -1 && page_addr == -1) - return; - - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } - } - /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. - */ - ndelay(100); - - nand_wait_ready(mtd); -} - -static void nand_ccs_delay(struct nand_chip *chip) -{ - /* - * The controller already takes care of waiting for tCCS when the RNDIN - * or RNDOUT command is sent, return directly. - */ - if (!(chip->options & NAND_WAIT_TCCS)) - return; - - /* - * Wait tCCS_min if it is correctly defined, otherwise wait 500ns - * (which should be safe for all NANDs). - */ - if (chip->setup_data_interface) - ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000); - else - ndelay(500); -} - -/** - * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none - * - * Send command to NAND device. This is the version for the new large page - * devices. We don't have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. - */ -static void nand_command_lp(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Command latch cycle */ - if (command != NAND_CMD_NONE) - chip->cmd_ctrl(mtd, command, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - - if (column != -1 || page_addr != -1) { - int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; - - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16 && - !nand_opcode_8bits(command)) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - - /* Only output a single addr cycle for 8bits opcodes. */ - if (!nand_opcode_8bits(command)) - chip->cmd_ctrl(mtd, column >> 8, ctrl); - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - chip->cmd_ctrl(mtd, page_addr >> 8, - NAND_NCE | NAND_ALE); - if (chip->options & NAND_ROW_ADDR_3) - chip->cmd_ctrl(mtd, page_addr >> 16, - NAND_NCE | NAND_ALE); - } - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Program and erase have their own busy handlers status, sequential - * in and status need no delay. - */ - switch (command) { - - case NAND_CMD_NONE: - case NAND_CMD_CACHEDPROG: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - case NAND_CMD_READID: - case NAND_CMD_SET_FEATURES: - return; - - case NAND_CMD_RNDIN: - nand_ccs_delay(chip); - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ - nand_wait_status_ready(mtd, 250); - return; - - case NAND_CMD_RNDOUT: - /* No ready / busy check necessary */ - chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - - nand_ccs_delay(chip); - return; - - case NAND_CMD_READ0: - /* - * READ0 is sometimes used to exit GET STATUS mode. When this - * is the case no address cycles are requested, and we can use - * this information to detect that READSTART should not be - * issued. - */ - if (column == -1 && page_addr == -1) - return; - - chip->cmd_ctrl(mtd, NAND_CMD_READSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay. - */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } - } - - /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. - */ - ndelay(100); - - nand_wait_ready(mtd); -} - -/** * panic_nand_get_device - [GENERIC] Get chip for selected access * @chip: the nand chip descriptor * @mtd: MTD device structure @@ -1086,13 +598,12 @@ retry: * we are in interrupt context. May happen when in panic and trying to write * an oops through mtdoops. */ -static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, - unsigned long timeo) +void panic_nand_wait(struct nand_chip *chip, unsigned long timeo) { int i; for (i = 0; i < timeo; i++) { - if (chip->dev_ready) { - if (chip->dev_ready(mtd)) + if (chip->legacy.dev_ready) { + if (chip->legacy.dev_ready(chip)) break; } else { int ret; @@ -1110,60 +621,6 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, } } -/** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure - * - * Wait for command done. This applies to erase and program only. - */ -static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) -{ - - unsigned long timeo = 400; - u8 status; - int ret; - - /* - * Apply this short delay always to ensure that we do wait tWB in any - * case on any machine. - */ - ndelay(100); - - ret = nand_status_op(chip, NULL); - if (ret) - return ret; - - if (in_interrupt() || oops_in_progress) - panic_nand_wait(mtd, chip, timeo); - else { - timeo = jiffies + msecs_to_jiffies(timeo); - do { - if (chip->dev_ready) { - if (chip->dev_ready(mtd)) - break; - } else { - ret = nand_read_data_op(chip, &status, - sizeof(status), true); - if (ret) - return ret; - - if (status & NAND_STATUS_READY) - break; - } - cond_resched(); - } while (time_before(jiffies, timeo)); - } - - ret = nand_read_data_op(chip, &status, sizeof(status), true); - if (ret) - return ret; - - /* This can happen if in case of timeout or buggy dev_ready */ - WARN_ON(!(status & NAND_STATUS_READY)); - return status; -} - static bool nand_supports_get_features(struct nand_chip *chip, int addr) { return (chip->parameters.supports_set_get_features && @@ -1177,48 +634,6 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr) } /** - * nand_get_features - wrapper to perform a GET_FEATURE - * @chip: NAND chip info structure - * @addr: feature address - * @subfeature_param: the subfeature parameters, a four bytes array - * - * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the - * operation cannot be handled. - */ -int nand_get_features(struct nand_chip *chip, int addr, - u8 *subfeature_param) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - - if (!nand_supports_get_features(chip, addr)) - return -ENOTSUPP; - - return chip->get_features(mtd, chip, addr, subfeature_param); -} -EXPORT_SYMBOL_GPL(nand_get_features); - -/** - * nand_set_features - wrapper to perform a SET_FEATURE - * @chip: NAND chip info structure - * @addr: feature address - * @subfeature_param: the subfeature parameters, a four bytes array - * - * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the - * operation cannot be handled. - */ -int nand_set_features(struct nand_chip *chip, int addr, - u8 *subfeature_param) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - - if (!nand_supports_set_features(chip, addr)) - return -ENOTSUPP; - - return chip->set_features(mtd, chip, addr, subfeature_param); -} -EXPORT_SYMBOL_GPL(nand_set_features); - -/** * nand_reset_data_interface - Reset data interface and timings * @chip: The NAND chip * @chipnr: Internal die id @@ -1229,7 +644,6 @@ EXPORT_SYMBOL_GPL(nand_set_features); */ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) { - struct mtd_info *mtd = nand_to_mtd(chip); int ret; if (!chip->setup_data_interface) @@ -1250,7 +664,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) */ onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); - ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface); + ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface); if (ret) pr_err("Failed to configure data interface to SDR timing mode 0\n"); @@ -1272,7 +686,6 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) */ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) { - struct mtd_info *mtd = nand_to_mtd(chip); u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { chip->onfi_timing_mode_default, }; @@ -1283,16 +696,16 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) /* Change the mode on the chip side (if supported by the NAND chip) */ if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) { - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, tmode_param); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); if (ret) return ret; } /* Change the mode on the controller side */ - ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface); + ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface); if (ret) return ret; @@ -1301,10 +714,10 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) return 0; memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, tmode_param); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); if (ret) goto err_reset_chip; @@ -1322,9 +735,9 @@ err_reset_chip: * timing mode. */ nand_reset_data_interface(chip, chipnr); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); nand_reset_op(chip); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); return ret; } @@ -1345,7 +758,6 @@ err_reset_chip: */ static int nand_init_data_interface(struct nand_chip *chip) { - struct mtd_info *mtd = nand_to_mtd(chip); int modes, mode, ret; if (!chip->setup_data_interface) @@ -1356,15 +768,15 @@ static int nand_init_data_interface(struct nand_chip *chip) * if the NAND does not support ONFI, fallback to the default ONFI * timing mode. */ - modes = onfi_get_async_timing_mode(chip); - if (modes == ONFI_TIMING_MODE_UNKNOWN) { + if (chip->parameters.onfi) { + modes = chip->parameters.onfi->async_timing_mode; + } else { if (!chip->onfi_timing_mode_default) return 0; modes = GENMASK(chip->onfi_timing_mode_default, 0); } - for (mode = fls(modes) - 1; mode >= 0; mode--) { ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode); if (ret) @@ -1374,7 +786,7 @@ static int nand_init_data_interface(struct nand_chip *chip) * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the * controller supports the requested timings. */ - ret = chip->setup_data_interface(mtd, + ret = chip->setup_data_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, &chip->data_interface); if (!ret) { @@ -1554,9 +966,9 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page, buf, len); } - chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page); + chip->legacy.cmdfunc(chip, NAND_CMD_READ0, offset_in_page, page); if (len) - chip->read_buf(mtd, buf, len); + chip->legacy.read_buf(chip, buf, len); return 0; } @@ -1574,10 +986,9 @@ EXPORT_SYMBOL_GPL(nand_read_page_op); * * Returns 0 on success, a negative error code otherwise. */ -static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, - unsigned int len) +int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, + unsigned int len) { - struct mtd_info *mtd = nand_to_mtd(chip); unsigned int i; u8 *p = buf; @@ -1603,9 +1014,9 @@ static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_PARAM, page, -1); for (i = 0; i < len; i++) - p[i] = chip->read_byte(mtd); + p[i] = chip->legacy.read_byte(chip); return 0; } @@ -1666,9 +1077,9 @@ int nand_change_read_column_op(struct nand_chip *chip, return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_RNDOUT, offset_in_page, -1); if (len) - chip->read_buf(mtd, buf, len); + chip->legacy.read_buf(chip, buf, len); return 0; } @@ -1703,9 +1114,9 @@ int nand_read_oob_op(struct nand_chip *chip, unsigned int page, mtd->writesize + offset_in_oob, buf, len); - chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page); + chip->legacy.cmdfunc(chip, NAND_CMD_READOOB, offset_in_oob, page); if (len) - chip->read_buf(mtd, buf, len); + chip->legacy.read_buf(chip, buf, len); return 0; } @@ -1815,10 +1226,10 @@ int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page, return nand_exec_prog_page_op(chip, page, offset_in_page, buf, len, false); - chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page); + chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, page); if (buf) - chip->write_buf(mtd, buf, len); + chip->legacy.write_buf(chip, buf, len); return 0; } @@ -1835,7 +1246,6 @@ EXPORT_SYMBOL_GPL(nand_prog_page_begin_op); */ int nand_prog_page_end_op(struct nand_chip *chip) { - struct mtd_info *mtd = nand_to_mtd(chip); int ret; u8 status; @@ -1857,8 +1267,8 @@ int nand_prog_page_end_op(struct nand_chip *chip) if (ret) return ret; } else { - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - ret = chip->waitfunc(mtd, chip); + chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); + ret = chip->legacy.waitfunc(chip); if (ret < 0) return ret; @@ -1902,10 +1312,11 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page, status = nand_exec_prog_page_op(chip, page, offset_in_page, buf, len, true); } else { - chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page); - chip->write_buf(mtd, buf, len); - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); + chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, + page); + chip->legacy.write_buf(chip, buf, len); + chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); + status = chip->legacy.waitfunc(chip); } if (status & NAND_STATUS_FAIL) @@ -1970,9 +1381,9 @@ int nand_change_write_column_op(struct nand_chip *chip, return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_RNDIN, offset_in_page, -1); if (len) - chip->write_buf(mtd, buf, len); + chip->legacy.write_buf(chip, buf, len); return 0; } @@ -1994,7 +1405,6 @@ EXPORT_SYMBOL_GPL(nand_change_write_column_op); int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, unsigned int len) { - struct mtd_info *mtd = nand_to_mtd(chip); unsigned int i; u8 *id = buf; @@ -2018,10 +1428,10 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1); for (i = 0; i < len; i++) - id[i] = chip->read_byte(mtd); + id[i] = chip->legacy.read_byte(chip); return 0; } @@ -2040,8 +1450,6 @@ EXPORT_SYMBOL_GPL(nand_readid_op); */ int nand_status_op(struct nand_chip *chip, u8 *status) { - struct mtd_info *mtd = nand_to_mtd(chip); - if (chip->exec_op) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); @@ -2058,9 +1466,9 @@ int nand_status_op(struct nand_chip *chip, u8 *status) return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1); if (status) - *status = chip->read_byte(mtd); + *status = chip->legacy.read_byte(chip); return 0; } @@ -2079,8 +1487,6 @@ EXPORT_SYMBOL_GPL(nand_status_op); */ int nand_exit_status_op(struct nand_chip *chip) { - struct mtd_info *mtd = nand_to_mtd(chip); - if (chip->exec_op) { struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_READ0, 0), @@ -2090,11 +1496,10 @@ int nand_exit_status_op(struct nand_chip *chip) return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_READ0, -1, -1); return 0; } -EXPORT_SYMBOL_GPL(nand_exit_status_op); /** * nand_erase_op - Do an erase operation @@ -2109,7 +1514,6 @@ EXPORT_SYMBOL_GPL(nand_exit_status_op); */ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock) { - struct mtd_info *mtd = nand_to_mtd(chip); unsigned int page = eraseblock << (chip->phys_erase_shift - chip->page_shift); int ret; @@ -2139,10 +1543,10 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock) if (ret) return ret; } else { - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); - chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_ERASE1, -1, page); + chip->legacy.cmdfunc(chip, NAND_CMD_ERASE2, -1, -1); - ret = chip->waitfunc(mtd, chip); + ret = chip->legacy.waitfunc(chip); if (ret < 0) return ret; @@ -2171,7 +1575,6 @@ EXPORT_SYMBOL_GPL(nand_erase_op); static int nand_set_features_op(struct nand_chip *chip, u8 feature, const void *data) { - struct mtd_info *mtd = nand_to_mtd(chip); const u8 *params = data; int i, ret; @@ -2190,11 +1593,11 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature, return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_SET_FEATURES, feature, -1); for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - chip->write_byte(mtd, params[i]); + chip->legacy.write_byte(chip, params[i]); - ret = chip->waitfunc(mtd, chip); + ret = chip->legacy.waitfunc(chip); if (ret < 0) return ret; @@ -2219,7 +1622,6 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature, static int nand_get_features_op(struct nand_chip *chip, u8 feature, void *data) { - struct mtd_info *mtd = nand_to_mtd(chip); u8 *params = data; int i; @@ -2239,9 +1641,31 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature, return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1); for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - params[i] = chip->read_byte(mtd); + params[i] = chip->legacy.read_byte(chip); + + return 0; +} + +static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms, + unsigned int delay_ns) +{ + if (chip->exec_op) { + struct nand_op_instr instrs[] = { + NAND_OP_WAIT_RDY(PSEC_TO_MSEC(timeout_ms), + PSEC_TO_NSEC(delay_ns)), + }; + struct nand_operation op = NAND_OPERATION(instrs); + + return nand_exec_op(chip, &op); + } + + /* Apply delay or wait for ready/busy pin */ + if (!chip->legacy.dev_ready) + udelay(chip->legacy.chip_delay); + else + nand_wait_ready(chip); return 0; } @@ -2258,8 +1682,6 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature, */ int nand_reset_op(struct nand_chip *chip) { - struct mtd_info *mtd = nand_to_mtd(chip); - if (chip->exec_op) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); @@ -2272,7 +1694,7 @@ int nand_reset_op(struct nand_chip *chip) return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->legacy.cmdfunc(chip, NAND_CMD_RESET, -1, -1); return 0; } @@ -2294,8 +1716,6 @@ EXPORT_SYMBOL_GPL(nand_reset_op); int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len, bool force_8bit) { - struct mtd_info *mtd = nand_to_mtd(chip); - if (!len || !buf) return -EINVAL; @@ -2315,9 +1735,9 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len, unsigned int i; for (i = 0; i < len; i++) - p[i] = chip->read_byte(mtd); + p[i] = chip->legacy.read_byte(chip); } else { - chip->read_buf(mtd, buf, len); + chip->legacy.read_buf(chip, buf, len); } return 0; @@ -2340,8 +1760,6 @@ EXPORT_SYMBOL_GPL(nand_read_data_op); int nand_write_data_op(struct nand_chip *chip, const void *buf, unsigned int len, bool force_8bit) { - struct mtd_info *mtd = nand_to_mtd(chip); - if (!len || !buf) return -EINVAL; @@ -2361,9 +1779,9 @@ int nand_write_data_op(struct nand_chip *chip, const void *buf, unsigned int i; for (i = 0; i < len; i++) - chip->write_byte(mtd, p[i]); + chip->legacy.write_byte(chip, p[i]); } else { - chip->write_buf(mtd, buf, len); + chip->legacy.write_buf(chip, buf, len); } return 0; @@ -2798,7 +2216,6 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len); */ int nand_reset(struct nand_chip *chip, int chipnr) { - struct mtd_info *mtd = nand_to_mtd(chip); struct nand_data_interface saved_data_intf = chip->data_interface; int ret; @@ -2810,9 +2227,9 @@ int nand_reset(struct nand_chip *chip, int chipnr) * The CS line has to be released before we can apply the new NAND * interface settings, hence this weird ->select_chip() dance. */ - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); ret = nand_reset_op(chip); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); if (ret) return ret; @@ -2836,6 +2253,48 @@ int nand_reset(struct nand_chip *chip, int chipnr) EXPORT_SYMBOL_GPL(nand_reset); /** + * nand_get_features - wrapper to perform a GET_FEATURE + * @chip: NAND chip info structure + * @addr: feature address + * @subfeature_param: the subfeature parameters, a four bytes array + * + * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the + * operation cannot be handled. + */ +int nand_get_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + if (!nand_supports_get_features(chip, addr)) + return -ENOTSUPP; + + if (chip->legacy.get_features) + return chip->legacy.get_features(chip, addr, subfeature_param); + + return nand_get_features_op(chip, addr, subfeature_param); +} + +/** + * nand_set_features - wrapper to perform a SET_FEATURE + * @chip: NAND chip info structure + * @addr: feature address + * @subfeature_param: the subfeature parameters, a four bytes array + * + * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the + * operation cannot be handled. + */ +int nand_set_features(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + if (!nand_supports_set_features(chip, addr)) + return -ENOTSUPP; + + if (chip->legacy.set_features) + return chip->legacy.set_features(chip, addr, subfeature_param); + + return nand_set_features_op(chip, addr, subfeature_param); +} + +/** * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data * @buf: buffer to test * @len: buffer length @@ -2968,7 +2427,6 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk); /** * nand_read_page_raw_notsupp - dummy read raw page function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -2976,16 +2434,14 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk); * * Returns -ENOTSUPP unconditionally. */ -int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip, - u8 *buf, int oob_required, int page) +int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf, + int oob_required, int page) { return -ENOTSUPP; } -EXPORT_SYMBOL(nand_read_page_raw_notsupp); /** * nand_read_page_raw - [INTERN] read raw page data without ecc - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -2993,9 +2449,10 @@ EXPORT_SYMBOL(nand_read_page_raw_notsupp); * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ -int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required, + int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int ret; ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize); @@ -3015,7 +2472,6 @@ EXPORT_SYMBOL(nand_read_page_raw); /** * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -3023,10 +2479,10 @@ EXPORT_SYMBOL(nand_read_page_raw); * * We need a special oob layout and handling even when OOB isn't used. */ -static int nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; uint8_t *oob = chip->oob_poi; @@ -3080,15 +2536,15 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, /** * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read */ -static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int nand_read_page_swecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -3097,10 +2553,10 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_code = chip->ecc.code_buf; unsigned int max_bitflips = 0; - chip->ecc.read_page_raw(mtd, chip, buf, 1, page); + chip->ecc.read_page_raw(chip, buf, 1, page); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, chip->ecc.total); @@ -3113,7 +2569,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]); if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -3126,17 +2582,16 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function - * @mtd: mtd info structure * @chip: nand chip info structure * @data_offs: offset of requested data within the page * @readlen: data length * @bufpoi: buffer to store read data * @page: page number to read */ -static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, - int page) +static int nand_read_subpage(struct nand_chip *chip, uint32_t data_offs, + uint32_t readlen, uint8_t *bufpoi, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int start_step, end_step, num_steps, ret; uint8_t *p; int data_col_addr, i, gaps = 0; @@ -3165,7 +2620,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, /* Calculate ECC */ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) - chip->ecc.calculate(mtd, p, &chip->ecc.calc_buf[i]); + chip->ecc.calculate(chip, p, &chip->ecc.calc_buf[i]); /* * The performance is faster if we position offsets according to @@ -3214,7 +2669,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { int stat; - stat = chip->ecc.correct(mtd, p, &chip->ecc.code_buf[i], + stat = chip->ecc.correct(chip, p, &chip->ecc.code_buf[i], &chip->ecc.calc_buf[i]); if (stat == -EBADMSG && (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { @@ -3238,7 +2693,6 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -3246,9 +2700,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, * * Not for syndrome calculating ECC controllers which need a special oob layout. */ -static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -3262,13 +2717,13 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, return ret; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->ecc.hwctl(chip, NAND_ECC_READ); ret = nand_read_data_op(chip, p, eccsize, false); if (ret) return ret; - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); } ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false); @@ -3286,7 +2741,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]); if (stat == -EBADMSG && (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { /* check for empty pages with bitflips */ @@ -3308,7 +2763,6 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -3320,9 +2774,10 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from * the data area, by overwriting the NAND manufacturer bad block markings. */ -static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +static int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -3348,15 +2803,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; - chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->ecc.hwctl(chip, NAND_ECC_READ); ret = nand_read_data_op(chip, p, eccsize, false); if (ret) return ret; - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); - stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); + stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL); if (stat == -EBADMSG && (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { /* check for empty pages with bitflips */ @@ -3378,7 +2833,6 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, /** * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -3387,9 +2841,10 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ -static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int ret, i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -3405,7 +2860,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; - chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->ecc.hwctl(chip, NAND_ECC_READ); ret = nand_read_data_op(chip, p, eccsize, false); if (ret) @@ -3420,13 +2875,13 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, oob += chip->ecc.prepad; } - chip->ecc.hwctl(mtd, NAND_ECC_READSYN); + chip->ecc.hwctl(chip, NAND_ECC_READSYN); ret = nand_read_data_op(chip, oob, eccbytes, false); if (ret) return ret; - stat = chip->ecc.correct(mtd, p, oob, NULL); + stat = chip->ecc.correct(chip, p, oob, NULL); oob += eccbytes; @@ -3502,17 +2957,15 @@ static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob, /** * nand_setup_read_retry - [INTERN] Set the READ RETRY mode - * @mtd: MTD device structure + * @chip: NAND chip object * @retry_mode: the retry mode to use * * Some vendors supply a special command to shift the Vt threshold, to be used * when there are too many bitflips in a page (i.e., ECC error). After setting * a new threshold, the host should retry reading the page. */ -static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) +static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode) { - struct nand_chip *chip = mtd_to_nand(mtd); - pr_debug("setting READ RETRY mode %d\n", retry_mode); if (retry_mode >= chip->read_retries) @@ -3521,7 +2974,18 @@ static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) if (!chip->setup_read_retry) return -EOPNOTSUPP; - return chip->setup_read_retry(mtd, retry_mode); + return chip->setup_read_retry(chip, retry_mode); +} + +static void nand_wait_readrdy(struct nand_chip *chip) +{ + const struct nand_sdr_timings *sdr; + + if (!(chip->options & NAND_NEED_READRDY)) + return; + + sdr = nand_get_sdr_timings(&chip->data_interface); + WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0)); } /** @@ -3549,7 +3013,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, bool ecc_fail = false; chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; @@ -3589,16 +3053,15 @@ read_retry: * the read methods return max bitflips per ecc step. */ if (unlikely(ops->mode == MTD_OPS_RAW)) - ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, + ret = chip->ecc.read_page_raw(chip, bufpoi, oob_required, page); else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && !oob) - ret = chip->ecc.read_subpage(mtd, chip, - col, bytes, bufpoi, - page); + ret = chip->ecc.read_subpage(chip, col, bytes, + bufpoi, page); else - ret = chip->ecc.read_page(mtd, chip, bufpoi, + ret = chip->ecc.read_page(chip, bufpoi, oob_required, page); if (ret < 0) { if (use_bufpoi) @@ -3631,18 +3094,12 @@ read_retry: } } - if (chip->options & NAND_NEED_READRDY) { - /* Apply delay or wait for ready/busy pin */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } + nand_wait_readrdy(chip); if (mtd->ecc_stats.failed - ecc_failures) { if (retry_mode + 1 < chip->read_retries) { retry_mode++; - ret = nand_setup_read_retry(mtd, + ret = nand_setup_read_retry(chip, retry_mode); if (ret < 0) break; @@ -3669,7 +3126,7 @@ read_retry: /* Reset to retry mode 0 */ if (retry_mode) { - ret = nand_setup_read_retry(mtd, 0); + ret = nand_setup_read_retry(chip, 0); if (ret < 0) break; retry_mode = 0; @@ -3687,11 +3144,11 @@ read_retry: /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, -1); + chip->select_chip(chip, chipnr); } } - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); ops->retlen = ops->len - (size_t) readlen; if (oob) @@ -3708,12 +3165,13 @@ read_retry: /** * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to read */ -int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) +int nand_read_oob_std(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); } EXPORT_SYMBOL(nand_read_oob_std); @@ -3721,13 +3179,12 @@ EXPORT_SYMBOL(nand_read_oob_std); /** * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC * with syndromes - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to read */ -int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int nand_read_oob_syndrome(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int length = mtd->oobsize; int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int eccsize = chip->ecc.size; @@ -3772,16 +3229,16 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -EXPORT_SYMBOL(nand_read_oob_syndrome); /** * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to write */ -int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) +int nand_write_oob_std(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi, mtd->oobsize); } @@ -3790,13 +3247,12 @@ EXPORT_SYMBOL(nand_write_oob_std); /** * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC * with syndrome - only for large page flash - * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to write */ -int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int nand_write_oob_syndrome(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; int eccsize = chip->ecc.size, length = mtd->oobsize; int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps; @@ -3860,7 +3316,6 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, return nand_prog_page_end_op(chip); } -EXPORT_SYMBOL(nand_write_oob_syndrome); /** * nand_do_read_oob - [INTERN] NAND read out-of-band @@ -3890,7 +3345,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, len = mtd_oobavail(mtd, ops); chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); /* Shift to get page */ realpage = (int)(from >> chip->page_shift); @@ -3898,9 +3353,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, while (1) { if (ops->mode == MTD_OPS_RAW) - ret = chip->ecc.read_oob_raw(mtd, chip, page); + ret = chip->ecc.read_oob_raw(chip, page); else - ret = chip->ecc.read_oob(mtd, chip, page); + ret = chip->ecc.read_oob(chip, page); if (ret < 0) break; @@ -3908,13 +3363,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, len = min(len, readlen); buf = nand_transfer_oob(mtd, buf, ops, len); - if (chip->options & NAND_NEED_READRDY) { - /* Apply delay or wait for ready/busy pin */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } + nand_wait_readrdy(chip); max_bitflips = max_t(unsigned int, max_bitflips, ret); @@ -3929,11 +3378,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, -1); + chip->select_chip(chip, chipnr); } } - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); ops->oobretlen = ops->ooblen - readlen; @@ -3979,7 +3428,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, /** * nand_write_page_raw_notsupp - dummy raw page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB @@ -3987,16 +3435,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, * * Returns -ENOTSUPP unconditionally. */ -int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip, - const u8 *buf, int oob_required, int page) +int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) { return -ENOTSUPP; } -EXPORT_SYMBOL(nand_write_page_raw_notsupp); /** * nand_write_page_raw - [INTERN] raw page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB @@ -4004,9 +3450,10 @@ EXPORT_SYMBOL(nand_write_page_raw_notsupp); * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ -int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int ret; ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); @@ -4026,7 +3473,6 @@ EXPORT_SYMBOL(nand_write_page_raw); /** * nand_write_page_raw_syndrome - [INTERN] raw page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB @@ -4034,11 +3480,11 @@ EXPORT_SYMBOL(nand_write_page_raw); * * We need a special oob layout and handling even when ECC isn't checked. */ -static int nand_write_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, +static int nand_write_page_raw_syndrome(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; uint8_t *oob = chip->oob_poi; @@ -4091,16 +3537,15 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd, } /** * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB * @page: page number to write */ -static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static int nand_write_page_swecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -4109,28 +3554,27 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, /* Software ECC calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, chip->ecc.total); if (ret) return ret; - return chip->ecc.write_page_raw(mtd, chip, buf, 1, page); + return chip->ecc.write_page_raw(chip, buf, 1, page); } /** * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB * @page: page number to write */ -static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static int nand_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, eccsize = chip->ecc.size, ret; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -4142,13 +3586,13 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, return ret; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->ecc.hwctl(chip, NAND_ECC_WRITE); ret = nand_write_data_op(chip, p, eccsize, false); if (ret) return ret; - chip->ecc.calculate(mtd, p, &ecc_calc[i]); + chip->ecc.calculate(chip, p, &ecc_calc[i]); } ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, @@ -4166,7 +3610,6 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write - * @mtd: mtd info structure * @chip: nand chip info structure * @offset: column address of subpage within the page * @data_len: data length @@ -4174,11 +3617,11 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * @oob_required: must write chip->oob_poi to OOB * @page: page number to write */ -static int nand_write_subpage_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint32_t offset, - uint32_t data_len, const uint8_t *buf, - int oob_required, int page) +static int nand_write_subpage_hwecc(struct nand_chip *chip, uint32_t offset, + uint32_t data_len, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); uint8_t *oob_buf = chip->oob_poi; uint8_t *ecc_calc = chip->ecc.calc_buf; int ecc_size = chip->ecc.size; @@ -4195,7 +3638,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, for (step = 0; step < ecc_steps; step++) { /* configure controller for WRITE access */ - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->ecc.hwctl(chip, NAND_ECC_WRITE); /* write data (untouched subpages already masked by 0xFF) */ ret = nand_write_data_op(chip, buf, ecc_size, false); @@ -4206,7 +3649,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, if ((step < start_step) || (step > end_step)) memset(ecc_calc, 0xff, ecc_bytes); else - chip->ecc.calculate(mtd, buf, ecc_calc); + chip->ecc.calculate(chip, buf, ecc_calc); /* mask OOB of un-touched subpages by padding 0xFF */ /* if oob_required, preserve OOB metadata of written subpage */ @@ -4237,7 +3680,6 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, /** * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB @@ -4246,11 +3688,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ -static int nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; @@ -4263,7 +3704,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, return ret; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->ecc.hwctl(chip, NAND_ECC_WRITE); ret = nand_write_data_op(chip, p, eccsize, false); if (ret) @@ -4278,7 +3719,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, oob += chip->ecc.prepad; } - chip->ecc.calculate(mtd, p, oob); + chip->ecc.calculate(chip, p, oob); ret = nand_write_data_op(chip, oob, eccbytes, false); if (ret) @@ -4331,14 +3772,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, subpage = 0; if (unlikely(raw)) - status = chip->ecc.write_page_raw(mtd, chip, buf, - oob_required, page); + status = chip->ecc.write_page_raw(chip, buf, oob_required, + page); else if (subpage) - status = chip->ecc.write_subpage(mtd, chip, offset, data_len, - buf, oob_required, page); + status = chip->ecc.write_subpage(chip, offset, data_len, buf, + oob_required, page); else - status = chip->ecc.write_page(mtd, chip, buf, oob_required, - page); + status = chip->ecc.write_page(chip, buf, oob_required, page); if (status < 0) return status; @@ -4423,7 +3863,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, column = to & (mtd->writesize - 1); chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { @@ -4499,8 +3939,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, -1); + chip->select_chip(chip, chipnr); } } @@ -4509,7 +3949,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, ops->oobretlen = ops->ooblen; err_out: - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); return ret; } @@ -4535,10 +3975,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); /* Wait for the device to get ready */ - panic_nand_wait(mtd, chip, 400); + panic_nand_wait(chip, 400); memset(&ops, 0, sizeof(ops)); ops.len = len; @@ -4587,14 +4027,14 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, */ nand_reset(chip, chipnr); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); /* Shift to get page */ page = (int)(to >> chip->page_shift); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); return -EROFS; } @@ -4605,11 +4045,11 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); if (ops->mode == MTD_OPS_RAW) - status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); + status = chip->ecc.write_oob_raw(chip, page & chip->pagemask); else - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); + status = chip->ecc.write_oob(chip, page & chip->pagemask); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); if (status) return status; @@ -4656,14 +4096,13 @@ out: /** * single_erase - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure + * @chip: NAND chip object * @page: the page address of the block which will be erased * * Standard erase command for NAND chips. Returns NAND status. */ -static int single_erase(struct mtd_info *mtd, int page) +static int single_erase(struct nand_chip *chip, int page) { - struct nand_chip *chip = mtd_to_nand(mtd); unsigned int eraseblock; /* Send commands to erase a block */ @@ -4681,22 +4120,22 @@ static int single_erase(struct mtd_info *mtd, int page) */ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) { - return nand_erase_nand(mtd, instr, 0); + return nand_erase_nand(mtd_to_nand(mtd), instr, 0); } /** * nand_erase_nand - [INTERN] erase block(s) - * @mtd: MTD device structure + * @chip: NAND chip object * @instr: erase instruction * @allowbbt: allow erasing the bbt area * * Erase one ore more blocks. */ -int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, +int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int allowbbt) { + struct mtd_info *mtd = nand_to_mtd(chip); int page, status, pages_per_block, ret, chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); loff_t len; pr_debug("%s: start = 0x%012llx, len = %llu\n", @@ -4717,7 +4156,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); /* Select the NAND device */ - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { @@ -4748,7 +4187,11 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, (page + pages_per_block)) chip->pagebuf = -1; - status = chip->erase(mtd, page & chip->pagemask); + if (chip->legacy.erase) + status = chip->legacy.erase(chip, + page & chip->pagemask); + else + status = single_erase(chip, page & chip->pagemask); /* See if block erase succeeded */ if (status) { @@ -4767,8 +4210,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* Check, if we cross a chip boundary */ if (len && !(page & chip->pagemask)) { chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, -1); + chip->select_chip(chip, chipnr); } } @@ -4776,7 +4219,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, erase_exit: /* Deselect and wake up anyone waiting on the device */ - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); nand_release_device(mtd); /* Return more or less happy */ @@ -4812,11 +4255,11 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) /* Select the NAND device */ nand_get_device(mtd, FL_READING); - chip->select_chip(mtd, chipnr); + chip->select_chip(chip, chipnr); ret = nand_block_checkbad(mtd, offs, 0); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); nand_release_device(mtd); return ret; @@ -4879,51 +4322,6 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) } /** - * nand_default_set_features- [REPLACEABLE] set NAND chip features - * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. - */ -static int nand_default_set_features(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - uint8_t *subfeature_param) -{ - return nand_set_features_op(chip, addr, subfeature_param); -} - -/** - * nand_default_get_features- [REPLACEABLE] get NAND chip features - * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. - */ -static int nand_default_get_features(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - uint8_t *subfeature_param) -{ - return nand_get_features_op(chip, addr, subfeature_param); -} - -/** - * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP - * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. - * - * Should be used by NAND controller drivers that do not support the SET/GET - * FEATURES operations. - */ -int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip, - int addr, u8 *subfeature_param) -{ - return -ENOTSUPP; -} -EXPORT_SYMBOL(nand_get_set_features_notsupp); - -/** * nand_suspend - [MTD Interface] Suspend the NAND flash * @mtd: MTD device structure */ @@ -4960,44 +4358,7 @@ static void nand_shutdown(struct mtd_info *mtd) /* Set default functions */ static void nand_set_defaults(struct nand_chip *chip) { - unsigned int busw = chip->options & NAND_BUSWIDTH_16; - - /* check for proper chip_delay setup, set 20us if not */ - if (!chip->chip_delay) - chip->chip_delay = 20; - - /* check, if a user supplied command function given */ - if (!chip->cmdfunc && !chip->exec_op) - chip->cmdfunc = nand_command; - - /* check, if a user supplied wait function given */ - if (chip->waitfunc == NULL) - chip->waitfunc = nand_wait; - - if (!chip->select_chip) - chip->select_chip = nand_select_chip; - - /* set for ONFI nand */ - if (!chip->set_features) - chip->set_features = nand_default_set_features; - if (!chip->get_features) - chip->get_features = nand_default_get_features; - - /* If called twice, pointers that depend on busw may need to be reset */ - if (!chip->read_byte || chip->read_byte == nand_read_byte) - chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; - if (!chip->read_word) - chip->read_word = nand_read_word; - if (!chip->block_bad) - chip->block_bad = nand_block_bad; - if (!chip->block_markbad) - chip->block_markbad = nand_default_block_markbad; - if (!chip->write_buf || chip->write_buf == nand_write_buf) - chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; - if (!chip->write_byte || chip->write_byte == nand_write_byte) - chip->write_byte = busw ? nand_write_byte16 : nand_write_byte; - if (!chip->read_buf || chip->read_buf == nand_read_buf) - chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; + nand_legacy_set_defaults(chip); if (!chip->controller) { chip->controller = &chip->dummy_controller; @@ -5009,7 +4370,7 @@ static void nand_set_defaults(struct nand_chip *chip) } /* Sanitize ONFI strings so we can safely print them */ -static void sanitize_string(uint8_t *s, size_t len) +void sanitize_string(uint8_t *s, size_t len) { ssize_t i; @@ -5026,390 +4387,6 @@ static void sanitize_string(uint8_t *s, size_t len) strim(s); } -static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) -{ - int i; - while (len--) { - crc ^= *p++ << 8; - for (i = 0; i < 8; i++) - crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); - } - - return crc; -} - -/* Parse the Extended Parameter Page. */ -static int nand_flash_detect_ext_param_page(struct nand_chip *chip, - struct nand_onfi_params *p) -{ - struct onfi_ext_param_page *ep; - struct onfi_ext_section *s; - struct onfi_ext_ecc_info *ecc; - uint8_t *cursor; - int ret; - int len; - int i; - - len = le16_to_cpu(p->ext_param_page_length) * 16; - ep = kmalloc(len, GFP_KERNEL); - if (!ep) - return -ENOMEM; - - /* Send our own NAND_CMD_PARAM. */ - ret = nand_read_param_page_op(chip, 0, NULL, 0); - if (ret) - goto ext_out; - - /* Use the Change Read Column command to skip the ONFI param pages. */ - ret = nand_change_read_column_op(chip, - sizeof(*p) * p->num_of_param_pages, - ep, len, true); - if (ret) - goto ext_out; - - ret = -EINVAL; - if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) - != le16_to_cpu(ep->crc))) { - pr_debug("fail in the CRC.\n"); - goto ext_out; - } - - /* - * Check the signature. - * Do not strictly follow the ONFI spec, maybe changed in future. - */ - if (strncmp(ep->sig, "EPPS", 4)) { - pr_debug("The signature is invalid.\n"); - goto ext_out; - } - - /* find the ECC section. */ - cursor = (uint8_t *)(ep + 1); - for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) { - s = ep->sections + i; - if (s->type == ONFI_SECTION_TYPE_2) - break; - cursor += s->length * 16; - } - if (i == ONFI_EXT_SECTION_MAX) { - pr_debug("We can not find the ECC section.\n"); - goto ext_out; - } - - /* get the info we want. */ - ecc = (struct onfi_ext_ecc_info *)cursor; - - if (!ecc->codeword_size) { - pr_debug("Invalid codeword size\n"); - goto ext_out; - } - - chip->ecc_strength_ds = ecc->ecc_bits; - chip->ecc_step_ds = 1 << ecc->codeword_size; - ret = 0; - -ext_out: - kfree(ep); - return ret; -} - -/* - * Recover data with bit-wise majority - */ -static void nand_bit_wise_majority(const void **srcbufs, - unsigned int nsrcbufs, - void *dstbuf, - unsigned int bufsize) -{ - int i, j, k; - - for (i = 0; i < bufsize; i++) { - u8 val = 0; - - for (j = 0; j < 8; j++) { - unsigned int cnt = 0; - - for (k = 0; k < nsrcbufs; k++) { - const u8 *srcbuf = srcbufs[k]; - - if (srcbuf[i] & BIT(j)) - cnt++; - } - - if (cnt > nsrcbufs / 2) - val |= BIT(j); - } - - ((u8 *)dstbuf)[i] = val; - } -} - -/* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. - */ -static int nand_flash_detect_onfi(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct nand_onfi_params *p; - struct onfi_params *onfi; - int onfi_version = 0; - char id[4]; - int i, ret, val; - - /* Try ONFI for unknown chip or LP */ - ret = nand_readid_op(chip, 0x20, id, sizeof(id)); - if (ret || strncmp(id, "ONFI", 4)) - return 0; - - /* ONFI chip: allocate a buffer to hold its parameter page */ - p = kzalloc((sizeof(*p) * 3), GFP_KERNEL); - if (!p) - return -ENOMEM; - - ret = nand_read_param_page_op(chip, 0, NULL, 0); - if (ret) { - ret = 0; - goto free_onfi_param_page; - } - - for (i = 0; i < 3; i++) { - ret = nand_read_data_op(chip, &p[i], sizeof(*p), true); - if (ret) { - ret = 0; - goto free_onfi_param_page; - } - - if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) == - le16_to_cpu(p->crc)) { - if (i) - memcpy(p, &p[i], sizeof(*p)); - break; - } - } - - if (i == 3) { - const void *srcbufs[3] = {p, p + 1, p + 2}; - - pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n"); - nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p, - sizeof(*p)); - - if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) != - le16_to_cpu(p->crc)) { - pr_err("ONFI parameter recovery failed, aborting\n"); - goto free_onfi_param_page; - } - } - - if (chip->manufacturer.desc && chip->manufacturer.desc->ops && - chip->manufacturer.desc->ops->fixup_onfi_param_page) - chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p); - - /* Check version */ - val = le16_to_cpu(p->revision); - if (val & ONFI_VERSION_2_3) - onfi_version = 23; - else if (val & ONFI_VERSION_2_2) - onfi_version = 22; - else if (val & ONFI_VERSION_2_1) - onfi_version = 21; - else if (val & ONFI_VERSION_2_0) - onfi_version = 20; - else if (val & ONFI_VERSION_1_0) - onfi_version = 10; - - if (!onfi_version) { - pr_info("unsupported ONFI version: %d\n", val); - goto free_onfi_param_page; - } - - sanitize_string(p->manufacturer, sizeof(p->manufacturer)); - sanitize_string(p->model, sizeof(p->model)); - chip->parameters.model = kstrdup(p->model, GFP_KERNEL); - if (!chip->parameters.model) { - ret = -ENOMEM; - goto free_onfi_param_page; - } - - mtd->writesize = le32_to_cpu(p->byte_per_page); - - /* - * pages_per_block and blocks_per_lun may not be a power-of-2 size - * (don't ask me who thought of this...). MTD assumes that these - * dimensions will be power-of-2, so just truncate the remaining area. - */ - mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); - mtd->erasesize *= mtd->writesize; - - mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - - /* See erasesize comment */ - chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); - chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; - chip->bits_per_cell = p->bits_per_cell; - - chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun); - chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun); - - if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) - chip->options |= NAND_BUSWIDTH_16; - - if (p->ecc_bits != 0xff) { - chip->ecc_strength_ds = p->ecc_bits; - chip->ecc_step_ds = 512; - } else if (onfi_version >= 21 && - (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) { - - /* - * The nand_flash_detect_ext_param_page() uses the - * Change Read Column command which maybe not supported - * by the chip->cmdfunc. So try to update the chip->cmdfunc - * now. We do not replace user supplied command function. - */ - if (mtd->writesize > 512 && chip->cmdfunc == nand_command) - chip->cmdfunc = nand_command_lp; - - /* The Extended Parameter Page is supported since ONFI 2.1. */ - if (nand_flash_detect_ext_param_page(chip, p)) - pr_warn("Failed to detect ONFI extended param page\n"); - } else { - pr_warn("Could not retrieve ONFI ECC requirements\n"); - } - - /* Save some parameters from the parameter page for future use */ - if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) { - chip->parameters.supports_set_get_features = true; - bitmap_set(chip->parameters.get_feature_list, - ONFI_FEATURE_ADDR_TIMING_MODE, 1); - bitmap_set(chip->parameters.set_feature_list, - ONFI_FEATURE_ADDR_TIMING_MODE, 1); - } - - onfi = kzalloc(sizeof(*onfi), GFP_KERNEL); - if (!onfi) { - ret = -ENOMEM; - goto free_model; - } - - onfi->version = onfi_version; - onfi->tPROG = le16_to_cpu(p->t_prog); - onfi->tBERS = le16_to_cpu(p->t_bers); - onfi->tR = le16_to_cpu(p->t_r); - onfi->tCCS = le16_to_cpu(p->t_ccs); - onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode); - onfi->vendor_revision = le16_to_cpu(p->vendor_revision); - memcpy(onfi->vendor, p->vendor, sizeof(p->vendor)); - chip->parameters.onfi = onfi; - - /* Identification done, free the full ONFI parameter page and exit */ - kfree(p); - - return 1; - -free_model: - kfree(chip->parameters.model); -free_onfi_param_page: - kfree(p); - - return ret; -} - -/* - * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise. - */ -static int nand_flash_detect_jedec(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct nand_jedec_params *p; - struct jedec_ecc_info *ecc; - int jedec_version = 0; - char id[5]; - int i, val, ret; - - /* Try JEDEC for unknown chip or LP */ - ret = nand_readid_op(chip, 0x40, id, sizeof(id)); - if (ret || strncmp(id, "JEDEC", sizeof(id))) - return 0; - - /* JEDEC chip: allocate a buffer to hold its parameter page */ - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - ret = nand_read_param_page_op(chip, 0x40, NULL, 0); - if (ret) { - ret = 0; - goto free_jedec_param_page; - } - - for (i = 0; i < 3; i++) { - ret = nand_read_data_op(chip, p, sizeof(*p), true); - if (ret) { - ret = 0; - goto free_jedec_param_page; - } - - if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) == - le16_to_cpu(p->crc)) - break; - } - - if (i == 3) { - pr_err("Could not find valid JEDEC parameter page; aborting\n"); - goto free_jedec_param_page; - } - - /* Check version */ - val = le16_to_cpu(p->revision); - if (val & (1 << 2)) - jedec_version = 10; - else if (val & (1 << 1)) - jedec_version = 1; /* vendor specific version */ - - if (!jedec_version) { - pr_info("unsupported JEDEC version: %d\n", val); - goto free_jedec_param_page; - } - - sanitize_string(p->manufacturer, sizeof(p->manufacturer)); - sanitize_string(p->model, sizeof(p->model)); - chip->parameters.model = kstrdup(p->model, GFP_KERNEL); - if (!chip->parameters.model) { - ret = -ENOMEM; - goto free_jedec_param_page; - } - - mtd->writesize = le32_to_cpu(p->byte_per_page); - - /* Please reference to the comment for nand_flash_detect_onfi. */ - mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); - mtd->erasesize *= mtd->writesize; - - mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - - /* Please reference to the comment for nand_flash_detect_onfi. */ - chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); - chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; - chip->bits_per_cell = p->bits_per_cell; - - if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) - chip->options |= NAND_BUSWIDTH_16; - - /* ECC info */ - ecc = &p->ecc_info[0]; - - if (ecc->codeword_size >= 9) { - chip->ecc_strength_ds = ecc->ecc_bits; - chip->ecc_step_ds = 1 << ecc->codeword_size; - } else { - pr_warn("Invalid codeword size\n"); - } - -free_jedec_param_page: - kfree(p); - return ret; -} - /* * nand_id_has_period - Check if an ID string has a given wraparound period * @id_data: the ID string @@ -5625,6 +4602,12 @@ static void nand_manufacturer_cleanup(struct nand_chip *chip) chip->manufacturer.desc->ops->cleanup(chip); } +static const char * +nand_manufacturer_name(const struct nand_manufacturer *manufacturer) +{ + return manufacturer ? manufacturer->name : "Unknown"; +} + /* * Get the flash and manufacturer id and lookup if the type is supported. */ @@ -5645,7 +4628,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) return ret; /* Select the device */ - chip->select_chip(mtd, 0); + chip->select_chip(chip, 0); /* Send the command for reading device ID */ ret = nand_readid_op(chip, 0, id_data, 2); @@ -5709,14 +4692,14 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) if (!type->name || !type->pagesize) { /* Check if the chip is ONFI compliant */ - ret = nand_flash_detect_onfi(chip); + ret = nand_onfi_detect(chip); if (ret < 0) return ret; else if (ret) goto ident_done; /* Check if the chip is JEDEC compliant */ - ret = nand_flash_detect_jedec(chip); + ret = nand_jedec_detect(chip); if (ret < 0) return ret; else if (ret) @@ -5783,11 +4766,8 @@ ident_done: chip->options |= NAND_ROW_ADDR_3; chip->badblockbits = 8; - chip->erase = single_erase; - /* Do not replace user supplied command function! */ - if (mtd->writesize > 512 && chip->cmdfunc == nand_command) - chip->cmdfunc = nand_command_lp; + nand_legacy_adjust_cmdfunc(chip); pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", maf_id, dev_id); @@ -5953,7 +4933,7 @@ static int nand_dt_init(struct nand_chip *chip) /** * nand_scan_ident - Scan for the NAND device - * @mtd: MTD device structure + * @chip: NAND chip object * @maxchips: number of chips to scan for * @table: alternative NAND ID table * @@ -5965,11 +4945,12 @@ static int nand_dt_init(struct nand_chip *chip) * prevented dynamic allocations during this phase which was unconvenient and * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks. */ -static int nand_scan_ident(struct mtd_info *mtd, int maxchips, +static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, struct nand_flash_dev *table) { - int i, nand_maf_id, nand_dev_id; - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); + int nand_maf_id, nand_dev_id; + unsigned int i; int ret; /* Enforce the right timings for reset/detection */ @@ -5982,21 +4963,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips, if (!mtd->name && mtd->dev.parent) mtd->name = dev_name(mtd->dev.parent); - /* - * ->cmdfunc() is legacy and will only be used if ->exec_op() is not - * populated. - */ - if (!chip->exec_op) { - /* - * Default functions assigned for ->cmdfunc() and - * ->select_chip() both expect ->cmd_ctrl() to be populated. - */ - if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) { - pr_err("->cmd_ctrl() should be provided\n"); - return -EINVAL; - } + if (chip->exec_op && !chip->select_chip) { + pr_err("->select_chip() is mandatory when implementing ->exec_op()\n"); + return -EINVAL; } + ret = nand_legacy_check_hooks(chip); + if (ret) + return ret; + /* Set the default functions */ nand_set_defaults(chip); @@ -6005,14 +4980,14 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips, if (ret) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) pr_warn("No NAND device found\n"); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); return ret; } nand_maf_id = chip->id.data[0]; nand_dev_id = chip->id.data[1]; - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); /* Check for a chip array */ for (i = 1; i < maxchips; i++) { @@ -6021,15 +4996,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips, /* See comment in nand_get_flash_type for reset */ nand_reset(chip, i); - chip->select_chip(mtd, i); + chip->select_chip(chip, i); /* Send the command for reading device ID */ nand_readid_op(chip, 0, id, sizeof(id)); /* Read manufacturer and device IDs */ if (nand_maf_id != id[0] || nand_dev_id != id[1]) { - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); break; } - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); } if (i > 1) pr_info("%d chips detected\n", i); @@ -6070,6 +5045,10 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd) ecc->size = 256; ecc->bytes = 3; ecc->strength = 1; + + if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) + ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER; + return 0; case NAND_ECC_BCH: if (!mtd_nand_has_bch()) { @@ -6423,15 +5402,15 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd) /** * nand_scan_tail - Scan for the NAND device - * @mtd: MTD device structure + * @chip: NAND chip object * * This is the second phase of the normal nand_scan() function. It fills out * all the uninitialized function pointers with the defaults and scans for a * bad block table if appropriate. */ -static int nand_scan_tail(struct mtd_info *mtd) +static int nand_scan_tail(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i; @@ -6451,9 +5430,9 @@ static int nand_scan_tail(struct mtd_info *mtd) * to explictly select the relevant die when interacting with the NAND * chip. */ - chip->select_chip(mtd, 0); + chip->select_chip(chip, 0); ret = nand_manufacturer_init(chip); - chip->select_chip(mtd, -1); + chip->select_chip(chip, -1); if (ret) goto err_free_buf; @@ -6770,33 +5749,31 @@ static void nand_detach(struct nand_chip *chip) /** * nand_scan_with_ids - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: number of chips to scan for. @nand_scan_ident() will not be run if - * this parameter is zero (useful for specific drivers that must - * handle this part of the process themselves, e.g docg4). + * @chip: NAND chip object + * @maxchips: number of chips to scan for. * @ids: optional flash IDs table * * This fills out all the uninitialized function pointers with the defaults. * The flash ID is read and the mtd/chip structures are filled with the * appropriate values. */ -int nand_scan_with_ids(struct mtd_info *mtd, int maxchips, +int nand_scan_with_ids(struct nand_chip *chip, unsigned int maxchips, struct nand_flash_dev *ids) { - struct nand_chip *chip = mtd_to_nand(mtd); int ret; - if (maxchips) { - ret = nand_scan_ident(mtd, maxchips, ids); - if (ret) - return ret; - } + if (!maxchips) + return -EINVAL; + + ret = nand_scan_ident(chip, maxchips, ids); + if (ret) + return ret; ret = nand_attach(chip); if (ret) goto cleanup_ident; - ret = nand_scan_tail(mtd); + ret = nand_scan_tail(chip); if (ret) goto detach_chip; @@ -6847,12 +5824,12 @@ EXPORT_SYMBOL_GPL(nand_cleanup); /** * nand_release - [NAND Interface] Unregister the MTD device and free resources * held by the NAND device - * @mtd: MTD device structure + * @chip: NAND chip object */ -void nand_release(struct mtd_info *mtd) +void nand_release(struct nand_chip *chip) { - mtd_device_unregister(mtd); - nand_cleanup(mtd_to_nand(mtd)); + mtd_device_unregister(nand_to_mtd(chip)); + nand_cleanup(chip); } EXPORT_SYMBOL_GPL(nand_release); diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 39db352f8757..98a826838b60 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -61,13 +61,14 @@ #include <linux/types.h> #include <linux/mtd/mtd.h> #include <linux/mtd/bbm.h> -#include <linux/mtd/rawnand.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/vmalloc.h> #include <linux/export.h> #include <linux/string.h> +#include "internals.h" + #define BBT_BLOCK_GOOD 0x00 #define BBT_BLOCK_WORN 0x01 #define BBT_BLOCK_RESERVED 0x02 @@ -683,14 +684,13 @@ static void mark_bbt_block_bad(struct nand_chip *this, struct nand_bbt_descr *td, int chip, int block) { - struct mtd_info *mtd = nand_to_mtd(this); loff_t to; int res; bbt_mark_entry(this, block, BBT_BLOCK_WORN); to = (loff_t)block << this->bbt_erase_shift; - res = this->block_markbad(mtd, to); + res = nand_markbad_bbm(this, to); if (res) pr_warn("nand_bbt: error %d while marking block %d bad\n", res, block); @@ -854,7 +854,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memset(&einfo, 0, sizeof(einfo)); einfo.addr = to; einfo.len = 1 << this->bbt_erase_shift; - res = nand_erase_nand(mtd, &einfo, 1); + res = nand_erase_nand(this, &einfo, 1); if (res < 0) { pr_warn("nand_bbt: error while erasing BBT block %d\n", res); @@ -1388,12 +1388,11 @@ EXPORT_SYMBOL(nand_create_bbt); /** * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved - * @mtd: MTD device structure + * @this: NAND chip object * @offs: offset in the device */ -int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs) +int nand_isreserved_bbt(struct nand_chip *this, loff_t offs) { - struct nand_chip *this = mtd_to_nand(mtd); int block; block = (int)(offs >> this->bbt_erase_shift); @@ -1402,13 +1401,12 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs) /** * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure + * @this: NAND chip object * @offs: offset in the device * @allowbbt: allow access to bad block table region */ -int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) +int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt) { - struct nand_chip *this = mtd_to_nand(mtd); int block, res; block = (int)(offs >> this->bbt_erase_shift); @@ -1430,12 +1428,12 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) /** * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT - * @mtd: MTD device structure + * @this: NAND chip object * @offs: offset of the bad block */ -int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) +int nand_markbad_bbt(struct nand_chip *this, loff_t offs) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); int block, ret = 0; block = (int)(offs >> this->bbt_erase_shift); diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c index b7387ace567a..574c0ca16160 100644 --- a/drivers/mtd/nand/raw/nand_bch.c +++ b/drivers/mtd/nand/raw/nand_bch.c @@ -43,14 +43,13 @@ struct nand_bch_control { /** * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block - * @mtd: MTD block structure + * @chip: NAND chip object * @buf: input buffer with raw data * @code: output buffer with ECC */ -int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, +int nand_bch_calculate_ecc(struct nand_chip *chip, const unsigned char *buf, unsigned char *code) { - const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int i; @@ -67,17 +66,16 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc); /** * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure + * @chip: NAND chip object * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data * * Detect and correct bit errors for a data byte block */ -int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, +int nand_bch_correct_data(struct nand_chip *chip, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { - const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int *errloc = nbc->errloc; int i, count; diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c index 8e132edbc5ce..4f4347533058 100644 --- a/drivers/mtd/nand/raw/nand_ecc.c +++ b/drivers/mtd/nand/raw/nand_ecc.c @@ -132,9 +132,10 @@ static const char addressbits[256] = { * @buf: input buffer with raw data * @eccsize: data bytes per ECC step (256 or 512) * @code: output buffer with ECC + * @sm_order: Smart Media byte ordering */ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, - unsigned char *code) + unsigned char *code, bool sm_order) { int i; const uint32_t *bp = (uint32_t *)buf; @@ -330,45 +331,26 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, * possible, but benchmarks showed that on the system this is developed * the code below is the fastest */ -#ifdef CONFIG_MTD_NAND_ECC_SMC - code[0] = - (invparity[rp7] << 7) | - (invparity[rp6] << 6) | - (invparity[rp5] << 5) | - (invparity[rp4] << 4) | - (invparity[rp3] << 3) | - (invparity[rp2] << 2) | - (invparity[rp1] << 1) | - (invparity[rp0]); - code[1] = - (invparity[rp15] << 7) | - (invparity[rp14] << 6) | - (invparity[rp13] << 5) | - (invparity[rp12] << 4) | - (invparity[rp11] << 3) | - (invparity[rp10] << 2) | - (invparity[rp9] << 1) | - (invparity[rp8]); -#else - code[1] = - (invparity[rp7] << 7) | - (invparity[rp6] << 6) | - (invparity[rp5] << 5) | - (invparity[rp4] << 4) | - (invparity[rp3] << 3) | - (invparity[rp2] << 2) | - (invparity[rp1] << 1) | - (invparity[rp0]); - code[0] = - (invparity[rp15] << 7) | - (invparity[rp14] << 6) | - (invparity[rp13] << 5) | - (invparity[rp12] << 4) | - (invparity[rp11] << 3) | - (invparity[rp10] << 2) | - (invparity[rp9] << 1) | - (invparity[rp8]); -#endif + if (sm_order) { + code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) | + (invparity[rp5] << 5) | (invparity[rp4] << 4) | + (invparity[rp3] << 3) | (invparity[rp2] << 2) | + (invparity[rp1] << 1) | (invparity[rp0]); + code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) | + (invparity[rp13] << 5) | (invparity[rp12] << 4) | + (invparity[rp11] << 3) | (invparity[rp10] << 2) | + (invparity[rp9] << 1) | (invparity[rp8]); + } else { + code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) | + (invparity[rp5] << 5) | (invparity[rp4] << 4) | + (invparity[rp3] << 3) | (invparity[rp2] << 2) | + (invparity[rp1] << 1) | (invparity[rp0]); + code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) | + (invparity[rp13] << 5) | (invparity[rp12] << 4) | + (invparity[rp11] << 3) | (invparity[rp10] << 2) | + (invparity[rp9] << 1) | (invparity[rp8]); + } + if (eccsize_mult == 1) code[2] = (invparity[par & 0xf0] << 7) | @@ -394,15 +376,16 @@ EXPORT_SYMBOL(__nand_calculate_ecc); /** * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte * block - * @mtd: MTD block structure + * @chip: NAND chip object * @buf: input buffer with raw data * @code: output buffer with ECC */ -int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, +int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf, unsigned char *code) { - __nand_calculate_ecc(buf, - mtd_to_nand(mtd)->ecc.size, code); + bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER; + + __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order); return 0; } @@ -414,12 +397,13 @@ EXPORT_SYMBOL(nand_calculate_ecc); * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data * @eccsize: data bytes per ECC step (256 or 512) + * @sm_order: Smart Media byte order * * Detect and correct a 1 bit error for eccsize byte block */ int __nand_correct_data(unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc, - unsigned int eccsize) + unsigned int eccsize, bool sm_order) { unsigned char b0, b1, b2, bit_addr; unsigned int byte_addr; @@ -431,13 +415,14 @@ int __nand_correct_data(unsigned char *buf, * we might need the xor result more than once, * so keep them in a local var */ -#ifdef CONFIG_MTD_NAND_ECC_SMC - b0 = read_ecc[0] ^ calc_ecc[0]; - b1 = read_ecc[1] ^ calc_ecc[1]; -#else - b0 = read_ecc[1] ^ calc_ecc[1]; - b1 = read_ecc[0] ^ calc_ecc[0]; -#endif + if (sm_order) { + b0 = read_ecc[0] ^ calc_ecc[0]; + b1 = read_ecc[1] ^ calc_ecc[1]; + } else { + b0 = read_ecc[1] ^ calc_ecc[1]; + b1 = read_ecc[0] ^ calc_ecc[0]; + } + b2 = read_ecc[2] ^ calc_ecc[2]; /* check if there are any bitfaults */ @@ -491,18 +476,20 @@ EXPORT_SYMBOL(__nand_correct_data); /** * nand_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure + * @chip: NAND chip object * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data * * Detect and correct a 1 bit error for 256/512 byte block */ -int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, +int nand_correct_data(struct nand_chip *chip, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { - return __nand_correct_data(buf, read_ecc, calc_ecc, - mtd_to_nand(mtd)->ecc.size); + bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER; + + return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size, + sm_order); } EXPORT_SYMBOL(nand_correct_data); diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c new file mode 100644 index 000000000000..96f039a83bc8 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_esmt.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Toradex AG + * + * Author: Marcel Ziswiler <marcel.ziswiler@toradex.com> + */ + +#include <linux/mtd/rawnand.h> +#include "internals.h" + +static void esmt_nand_decode_id(struct nand_chip *chip) +{ + nand_decode_ext_id(chip); + + /* Extract ECC requirements from 5th id byte. */ + if (chip->id.len >= 5 && nand_is_slc(chip)) { + chip->ecc_step_ds = 512; + switch (chip->id.data[4] & 0x3) { + case 0x0: + chip->ecc_strength_ds = 4; + break; + case 0x1: + chip->ecc_strength_ds = 2; + break; + case 0x2: + chip->ecc_strength_ds = 1; + break; + default: + WARN(1, "Could not get ECC info"); + chip->ecc_step_ds = 0; + break; + } + } +} + +static int esmt_nand_init(struct nand_chip *chip) +{ + if (nand_is_slc(chip)) + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + + return 0; +} + +const struct nand_manufacturer_ops esmt_nand_manuf_ops = { + .detect = esmt_nand_decode_id, + .init = esmt_nand_init, +}; diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 4ffbb26e76d6..ac1b5c103968 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -15,10 +15,11 @@ * GNU General Public License for more details. */ -#include <linux/mtd/rawnand.h> #include <linux/sizes.h> #include <linux/slab.h> +#include "internals.h" + #define NAND_HYNIX_CMD_SET_PARAMS 0x36 #define NAND_HYNIX_CMD_APPLY_PARAMS 0x16 @@ -79,8 +80,6 @@ static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip) static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd) { - struct mtd_info *mtd = nand_to_mtd(chip); - if (chip->exec_op) { struct nand_op_instr instrs[] = { NAND_OP_CMD(cmd, 0), @@ -90,14 +89,13 @@ static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd) return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, cmd, -1, -1); + chip->legacy.cmdfunc(chip, cmd, -1, -1); return 0; } static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val) { - struct mtd_info *mtd = nand_to_mtd(chip); u16 column = ((u16)addr << 8) | addr; if (chip->exec_op) { @@ -110,15 +108,14 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val) return nand_exec_op(chip, &op); } - chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1); - chip->write_byte(mtd, val); + chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1); + chip->legacy.write_byte(chip, val); return 0; } -static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) +static int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode) { - struct nand_chip *chip = mtd_to_nand(mtd); struct hynix_nand *hynix = nand_get_manufacturer_data(chip); const u8 *values; int i, ret; diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c index 5423c3bb388e..ea5a342cd91e 100644 --- a/drivers/mtd/nand/raw/nand_ids.c +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -6,9 +6,11 @@ * published by the Free Software Foundation. * */ -#include <linux/mtd/rawnand.h> + #include <linux/sizes.h> +#include "internals.h" + #define LP_OPTIONS 0 #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) @@ -169,21 +171,21 @@ struct nand_flash_dev nand_flash_ids[] = { /* Manufacturer IDs */ static const struct nand_manufacturer nand_manufacturers[] = { - {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops}, - {NAND_MFR_ESMT, "ESMT"}, - {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops}, + {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops}, + {NAND_MFR_ATO, "ATO"}, + {NAND_MFR_EON, "Eon"}, + {NAND_MFR_ESMT, "ESMT", &esmt_nand_manuf_ops}, {NAND_MFR_FUJITSU, "Fujitsu"}, - {NAND_MFR_NATIONAL, "National"}, - {NAND_MFR_RENESAS, "Renesas"}, - {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops}, - {NAND_MFR_MICRON, "Micron", µn_nand_manuf_ops}, - {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops}, + {NAND_MFR_INTEL, "Intel"}, {NAND_MFR_MACRONIX, "Macronix", ¯onix_nand_manuf_ops}, - {NAND_MFR_EON, "Eon"}, + {NAND_MFR_MICRON, "Micron", µn_nand_manuf_ops}, + {NAND_MFR_NATIONAL, "National"}, + {NAND_MFR_RENESAS, "Renesas"}, + {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops}, {NAND_MFR_SANDISK, "SanDisk"}, - {NAND_MFR_INTEL, "Intel"}, - {NAND_MFR_ATO, "ATO"}, + {NAND_MFR_STMICRO, "ST Micro"}, + {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops}, {NAND_MFR_WINBOND, "Winbond"}, }; diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c new file mode 100644 index 000000000000..5c26492c841d --- /dev/null +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * This file contains all ONFI helpers. + */ + +#include <linux/slab.h> + +#include "internals.h" + +/* + * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise. + */ +int nand_jedec_detect(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_jedec_params *p; + struct jedec_ecc_info *ecc; + int jedec_version = 0; + char id[5]; + int i, val, ret; + + /* Try JEDEC for unknown chip or LP */ + ret = nand_readid_op(chip, 0x40, id, sizeof(id)); + if (ret || strncmp(id, "JEDEC", sizeof(id))) + return 0; + + /* JEDEC chip: allocate a buffer to hold its parameter page */ + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + ret = nand_read_param_page_op(chip, 0x40, NULL, 0); + if (ret) { + ret = 0; + goto free_jedec_param_page; + } + + for (i = 0; i < 3; i++) { + ret = nand_read_data_op(chip, p, sizeof(*p), true); + if (ret) { + ret = 0; + goto free_jedec_param_page; + } + + if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) == + le16_to_cpu(p->crc)) + break; + } + + if (i == 3) { + pr_err("Could not find valid JEDEC parameter page; aborting\n"); + goto free_jedec_param_page; + } + + /* Check version */ + val = le16_to_cpu(p->revision); + if (val & (1 << 2)) + jedec_version = 10; + else if (val & (1 << 1)) + jedec_version = 1; /* vendor specific version */ + + if (!jedec_version) { + pr_info("unsupported JEDEC version: %d\n", val); + goto free_jedec_param_page; + } + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + chip->parameters.model = kstrdup(p->model, GFP_KERNEL); + if (!chip->parameters.model) { + ret = -ENOMEM; + goto free_jedec_param_page; + } + + mtd->writesize = le32_to_cpu(p->byte_per_page); + + /* Please reference to the comment for nand_flash_detect_onfi. */ + mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); + mtd->erasesize *= mtd->writesize; + + mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + + /* Please reference to the comment for nand_flash_detect_onfi. */ + chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; + chip->bits_per_cell = p->bits_per_cell; + + if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) + chip->options |= NAND_BUSWIDTH_16; + + /* ECC info */ + ecc = &p->ecc_info[0]; + + if (ecc->codeword_size >= 9) { + chip->ecc_strength_ds = ecc->ecc_bits; + chip->ecc_step_ds = 1 << ecc->codeword_size; + } else { + pr_warn("Invalid codeword size\n"); + } + +free_jedec_param_page: + kfree(p); + return ret; +} diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c new file mode 100644 index 000000000000..c5ddc86cd98c --- /dev/null +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -0,0 +1,642 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * This file contains all legacy helpers/code that should be removed + * at some point. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/nmi.h> + +#include "internals.h" + +/** + * nand_read_byte - [DEFAULT] read one byte from the chip + * @chip: NAND chip object + * + * Default read function for 8bit buswidth + */ +static uint8_t nand_read_byte(struct nand_chip *chip) +{ + return readb(chip->legacy.IO_ADDR_R); +} + +/** + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @chip: NAND chip object + * + * Default read function for 16bit buswidth with endianness conversion. + * + */ +static uint8_t nand_read_byte16(struct nand_chip *chip) +{ + return (uint8_t) cpu_to_le16(readw(chip->legacy.IO_ADDR_R)); +} + +/** + * nand_select_chip - [DEFAULT] control CE line + * @chip: NAND chip object + * @chipnr: chipnumber to select, -1 for deselect + * + * Default select function for 1 chip devices. + */ +static void nand_select_chip(struct nand_chip *chip, int chipnr) +{ + switch (chipnr) { + case -1: + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + 0 | NAND_CTRL_CHANGE); + break; + case 0: + break; + + default: + BUG(); + } +} + +/** + * nand_write_byte - [DEFAULT] write single byte to chip + * @chip: NAND chip object + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] + */ +static void nand_write_byte(struct nand_chip *chip, uint8_t byte) +{ + chip->legacy.write_buf(chip, &byte, 1); +} + +/** + * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 + * @chip: NAND chip object + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. + */ +static void nand_write_byte16(struct nand_chip *chip, uint8_t byte) +{ + uint16_t word = byte; + + /* + * It's not entirely clear what should happen to I/O[15:8] when writing + * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: + * + * When the host supports a 16-bit bus width, only data is + * transferred at the 16-bit width. All address and command line + * transfers shall use only the lower 8-bits of the data bus. During + * command transfers, the host may place any value on the upper + * 8-bits of the data bus. During address transfers, the host shall + * set the upper 8-bits of the data bus to 00h. + * + * One user of the write_byte callback is nand_set_features. The + * four parameters are specified to be written to I/O[7:0], but this is + * neither an address nor a command transfer. Let's assume a 0 on the + * upper I/O lines is OK. + */ + chip->legacy.write_buf(chip, (uint8_t *)&word, 2); +} + +/** + * nand_write_buf - [DEFAULT] write buffer to chip + * @chip: NAND chip object + * @buf: data buffer + * @len: number of bytes to write + * + * Default write function for 8bit buswidth. + */ +static void nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) +{ + iowrite8_rep(chip->legacy.IO_ADDR_W, buf, len); +} + +/** + * nand_read_buf - [DEFAULT] read chip data into buffer + * @chip: NAND chip object + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 8bit buswidth. + */ +static void nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) +{ + ioread8_rep(chip->legacy.IO_ADDR_R, buf, len); +} + +/** + * nand_write_buf16 - [DEFAULT] write buffer to chip + * @chip: NAND chip object + * @buf: data buffer + * @len: number of bytes to write + * + * Default write function for 16bit buswidth. + */ +static void nand_write_buf16(struct nand_chip *chip, const uint8_t *buf, + int len) +{ + u16 *p = (u16 *) buf; + + iowrite16_rep(chip->legacy.IO_ADDR_W, p, len >> 1); +} + +/** + * nand_read_buf16 - [DEFAULT] read chip data into buffer + * @chip: NAND chip object + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 16bit buswidth. + */ +static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len) +{ + u16 *p = (u16 *) buf; + + ioread16_rep(chip->legacy.IO_ADDR_R, p, len >> 1); +} + +/** + * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. + * @mtd: MTD device structure + * @timeo: Timeout + * + * Helper function for nand_wait_ready used when needing to wait in interrupt + * context. + */ +static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int i; + + /* Wait for the device to get ready */ + for (i = 0; i < timeo; i++) { + if (chip->legacy.dev_ready(chip)) + break; + touch_softlockup_watchdog(); + mdelay(1); + } +} + +/** + * nand_wait_ready - [GENERIC] Wait for the ready pin after commands. + * @chip: NAND chip object + * + * Wait for the ready pin after a command, and warn if a timeout occurs. + */ +void nand_wait_ready(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned long timeo = 400; + + if (in_interrupt() || oops_in_progress) + return panic_nand_wait_ready(mtd, timeo); + + /* Wait until command is processed or timeout occurs */ + timeo = jiffies + msecs_to_jiffies(timeo); + do { + if (chip->legacy.dev_ready(chip)) + return; + cond_resched(); + } while (time_before(jiffies, timeo)); + + if (!chip->legacy.dev_ready(chip)) + pr_warn_ratelimited("timeout while waiting for chip to become ready\n"); +} +EXPORT_SYMBOL_GPL(nand_wait_ready); + +/** + * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. + * @mtd: MTD device structure + * @timeo: Timeout in ms + * + * Wait for status ready (i.e. command done) or timeout. + */ +static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) +{ + register struct nand_chip *chip = mtd_to_nand(mtd); + int ret; + + timeo = jiffies + msecs_to_jiffies(timeo); + do { + u8 status; + + ret = nand_read_data_op(chip, &status, sizeof(status), true); + if (ret) + return; + + if (status & NAND_STATUS_READY) + break; + touch_softlockup_watchdog(); + } while (time_before(jiffies, timeo)); +}; + +/** + * nand_command - [DEFAULT] Send command to NAND device + * @chip: NAND chip object + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This function is used for small page devices + * (512 Bytes per page). + */ +static void nand_command(struct nand_chip *chip, unsigned int command, + int column, int page_addr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; + + /* Write out the command to the device */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->writesize) { + /* OOB area */ + column -= mtd->writesize; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + chip->legacy.cmd_ctrl(chip, readcmd, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (command != NAND_CMD_NONE) + chip->legacy.cmd_ctrl(chip, command, ctrl); + + /* Address cycle, when necessary */ + ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) + column >>= 1; + chip->legacy.cmd_ctrl(chip, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (page_addr != -1) { + chip->legacy.cmd_ctrl(chip, page_addr, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + chip->legacy.cmd_ctrl(chip, page_addr >> 8, ctrl); + if (chip->options & NAND_ROW_ADDR_3) + chip->legacy.cmd_ctrl(chip, page_addr >> 16, ctrl); + } + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status and sequential + * in needs no delay + */ + switch (command) { + + case NAND_CMD_NONE: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_RESET: + if (chip->legacy.dev_ready) + break; + udelay(chip->legacy.chip_delay); + chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(mtd, 250); + return; + + /* This applies to read commands */ + case NAND_CMD_READ0: + /* + * READ0 is sometimes used to exit GET STATUS mode. When this + * is the case no address cycles are requested, and we can use + * this information to detect that we should not wait for the + * device to be ready. + */ + if (column == -1 && page_addr == -1) + return; + + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!chip->legacy.dev_ready) { + udelay(chip->legacy.chip_delay); + return; + } + } + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + nand_wait_ready(chip); +} + +static void nand_ccs_delay(struct nand_chip *chip) +{ + /* + * The controller already takes care of waiting for tCCS when the RNDIN + * or RNDOUT command is sent, return directly. + */ + if (!(chip->options & NAND_WAIT_TCCS)) + return; + + /* + * Wait tCCS_min if it is correctly defined, otherwise wait 500ns + * (which should be safe for all NANDs). + */ + if (chip->setup_data_interface) + ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000); + else + ndelay(500); +} + +/** + * nand_command_lp - [DEFAULT] Send command to NAND large page device + * @chip: NAND chip object + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This is the version for the new large page + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + */ +static void nand_command_lp(struct nand_chip *chip, unsigned int command, + int column, int page_addr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Command latch cycle */ + if (command != NAND_CMD_NONE) + chip->legacy.cmd_ctrl(chip, command, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + + if (column != -1 || page_addr != -1) { + int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; + + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16 && + !nand_opcode_8bits(command)) + column >>= 1; + chip->legacy.cmd_ctrl(chip, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + + /* Only output a single addr cycle for 8bits opcodes. */ + if (!nand_opcode_8bits(command)) + chip->legacy.cmd_ctrl(chip, column >> 8, ctrl); + } + if (page_addr != -1) { + chip->legacy.cmd_ctrl(chip, page_addr, ctrl); + chip->legacy.cmd_ctrl(chip, page_addr >> 8, + NAND_NCE | NAND_ALE); + if (chip->options & NAND_ROW_ADDR_3) + chip->legacy.cmd_ctrl(chip, page_addr >> 16, + NAND_NCE | NAND_ALE); + } + } + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status, sequential + * in and status need no delay. + */ + switch (command) { + + case NAND_CMD_NONE: + case NAND_CMD_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_RNDIN: + nand_ccs_delay(chip); + return; + + case NAND_CMD_RESET: + if (chip->legacy.dev_ready) + break; + udelay(chip->legacy.chip_delay); + chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(mtd, 250); + return; + + case NAND_CMD_RNDOUT: + /* No ready / busy check necessary */ + chip->legacy.cmd_ctrl(chip, NAND_CMD_RNDOUTSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + nand_ccs_delay(chip); + return; + + case NAND_CMD_READ0: + /* + * READ0 is sometimes used to exit GET STATUS mode. When this + * is the case no address cycles are requested, and we can use + * this information to detect that READSTART should not be + * issued. + */ + if (column == -1 && page_addr == -1) + return; + + chip->legacy.cmd_ctrl(chip, NAND_CMD_READSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay. + */ + if (!chip->legacy.dev_ready) { + udelay(chip->legacy.chip_delay); + return; + } + } + + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + nand_wait_ready(chip); +} + +/** + * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. + * + * Should be used by NAND controller drivers that do not support the SET/GET + * FEATURES operations. + */ +int nand_get_set_features_notsupp(struct nand_chip *chip, int addr, + u8 *subfeature_param) +{ + return -ENOTSUPP; +} +EXPORT_SYMBOL(nand_get_set_features_notsupp); + +/** + * nand_wait - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure + * + * Wait for command done. This applies to erase and program only. + */ +static int nand_wait(struct nand_chip *chip) +{ + + unsigned long timeo = 400; + u8 status; + int ret; + + /* + * Apply this short delay always to ensure that we do wait tWB in any + * case on any machine. + */ + ndelay(100); + + ret = nand_status_op(chip, NULL); + if (ret) + return ret; + + if (in_interrupt() || oops_in_progress) + panic_nand_wait(chip, timeo); + else { + timeo = jiffies + msecs_to_jiffies(timeo); + do { + if (chip->legacy.dev_ready) { + if (chip->legacy.dev_ready(chip)) + break; + } else { + ret = nand_read_data_op(chip, &status, + sizeof(status), true); + if (ret) + return ret; + + if (status & NAND_STATUS_READY) + break; + } + cond_resched(); + } while (time_before(jiffies, timeo)); + } + + ret = nand_read_data_op(chip, &status, sizeof(status), true); + if (ret) + return ret; + + /* This can happen if in case of timeout or buggy dev_ready */ + WARN_ON(!(status & NAND_STATUS_READY)); + return status; +} + +void nand_legacy_set_defaults(struct nand_chip *chip) +{ + unsigned int busw = chip->options & NAND_BUSWIDTH_16; + + if (chip->exec_op) + return; + + /* check for proper chip_delay setup, set 20us if not */ + if (!chip->legacy.chip_delay) + chip->legacy.chip_delay = 20; + + /* check, if a user supplied command function given */ + if (!chip->legacy.cmdfunc && !chip->exec_op) + chip->legacy.cmdfunc = nand_command; + + /* check, if a user supplied wait function given */ + if (chip->legacy.waitfunc == NULL) + chip->legacy.waitfunc = nand_wait; + + if (!chip->select_chip) + chip->select_chip = nand_select_chip; + + /* If called twice, pointers that depend on busw may need to be reset */ + if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte) + chip->legacy.read_byte = busw ? nand_read_byte16 : nand_read_byte; + if (!chip->legacy.write_buf || chip->legacy.write_buf == nand_write_buf) + chip->legacy.write_buf = busw ? nand_write_buf16 : nand_write_buf; + if (!chip->legacy.write_byte || chip->legacy.write_byte == nand_write_byte) + chip->legacy.write_byte = busw ? nand_write_byte16 : nand_write_byte; + if (!chip->legacy.read_buf || chip->legacy.read_buf == nand_read_buf) + chip->legacy.read_buf = busw ? nand_read_buf16 : nand_read_buf; +} + +void nand_legacy_adjust_cmdfunc(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Do not replace user supplied command function! */ + if (mtd->writesize > 512 && chip->legacy.cmdfunc == nand_command) + chip->legacy.cmdfunc = nand_command_lp; +} + +int nand_legacy_check_hooks(struct nand_chip *chip) +{ + /* + * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is + * not populated. + */ + if (chip->exec_op) + return 0; + + /* + * Default functions assigned for ->legacy.cmdfunc() and + * ->select_chip() both expect ->legacy.cmd_ctrl() to be populated. + */ + if ((!chip->legacy.cmdfunc || !chip->select_chip) && + !chip->legacy.cmd_ctrl) { + pr_err("->legacy.cmd_ctrl() should be provided\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 49c546c97c6f..358dcc957bb2 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include <linux/mtd/rawnand.h> +#include "internals.h" /* * Macronix AC series does not support using SET/GET_FEATURES to change diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index f5dc0a7a2456..b85e1c13b79e 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -15,9 +15,10 @@ * GNU General Public License for more details. */ -#include <linux/mtd/rawnand.h> #include <linux/slab.h> +#include "internals.h" + /* * Special Micron status bit 3 indicates that the block has been * corrected by on-die ECC and should be rewritten. @@ -74,9 +75,8 @@ struct micron_nand { struct micron_on_die_ecc ecc; }; -static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) +static int micron_nand_setup_read_retry(struct nand_chip *chip, int retry_mode) { - struct nand_chip *chip = mtd_to_nand(mtd); u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); @@ -290,10 +290,10 @@ static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status) } static int -micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, - int page) +micron_nand_read_page_on_die_ecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); u8 status; int ret, max_bitflips = 0; @@ -332,9 +332,8 @@ out: } static int -micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { int ret; @@ -342,7 +341,7 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, if (ret) return ret; - ret = nand_write_page_raw(mtd, chip, buf, oob_required, page); + ret = nand_write_page_raw(chip, buf, oob_required, page); micron_nand_on_die_ecc_setup(chip, false); return ret; diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c new file mode 100644 index 000000000000..d8184cf591ad --- /dev/null +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * This file contains all ONFI helpers. + */ + +#include <linux/slab.h> + +#include "internals.h" + +u16 onfi_crc16(u16 crc, u8 const *p, size_t len) +{ + int i; + while (len--) { + crc ^= *p++ << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); + } + + return crc; +} + +/* Parse the Extended Parameter Page. */ +static int nand_flash_detect_ext_param_page(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + struct onfi_ext_param_page *ep; + struct onfi_ext_section *s; + struct onfi_ext_ecc_info *ecc; + uint8_t *cursor; + int ret; + int len; + int i; + + len = le16_to_cpu(p->ext_param_page_length) * 16; + ep = kmalloc(len, GFP_KERNEL); + if (!ep) + return -ENOMEM; + + /* Send our own NAND_CMD_PARAM. */ + ret = nand_read_param_page_op(chip, 0, NULL, 0); + if (ret) + goto ext_out; + + /* Use the Change Read Column command to skip the ONFI param pages. */ + ret = nand_change_read_column_op(chip, + sizeof(*p) * p->num_of_param_pages, + ep, len, true); + if (ret) + goto ext_out; + + ret = -EINVAL; + if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) + != le16_to_cpu(ep->crc))) { + pr_debug("fail in the CRC.\n"); + goto ext_out; + } + + /* + * Check the signature. + * Do not strictly follow the ONFI spec, maybe changed in future. + */ + if (strncmp(ep->sig, "EPPS", 4)) { + pr_debug("The signature is invalid.\n"); + goto ext_out; + } + + /* find the ECC section. */ + cursor = (uint8_t *)(ep + 1); + for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) { + s = ep->sections + i; + if (s->type == ONFI_SECTION_TYPE_2) + break; + cursor += s->length * 16; + } + if (i == ONFI_EXT_SECTION_MAX) { + pr_debug("We can not find the ECC section.\n"); + goto ext_out; + } + + /* get the info we want. */ + ecc = (struct onfi_ext_ecc_info *)cursor; + + if (!ecc->codeword_size) { + pr_debug("Invalid codeword size\n"); + goto ext_out; + } + + chip->ecc_strength_ds = ecc->ecc_bits; + chip->ecc_step_ds = 1 << ecc->codeword_size; + ret = 0; + +ext_out: + kfree(ep); + return ret; +} + +/* + * Recover data with bit-wise majority + */ +static void nand_bit_wise_majority(const void **srcbufs, + unsigned int nsrcbufs, + void *dstbuf, + unsigned int bufsize) +{ + int i, j, k; + + for (i = 0; i < bufsize; i++) { + u8 val = 0; + + for (j = 0; j < 8; j++) { + unsigned int cnt = 0; + + for (k = 0; k < nsrcbufs; k++) { + const u8 *srcbuf = srcbufs[k]; + + if (srcbuf[i] & BIT(j)) + cnt++; + } + + if (cnt > nsrcbufs / 2) + val |= BIT(j); + } + + ((u8 *)dstbuf)[i] = val; + } +} + +/* + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. + */ +int nand_onfi_detect(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_onfi_params *p; + struct onfi_params *onfi; + int onfi_version = 0; + char id[4]; + int i, ret, val; + + /* Try ONFI for unknown chip or LP */ + ret = nand_readid_op(chip, 0x20, id, sizeof(id)); + if (ret || strncmp(id, "ONFI", 4)) + return 0; + + /* ONFI chip: allocate a buffer to hold its parameter page */ + p = kzalloc((sizeof(*p) * 3), GFP_KERNEL); + if (!p) + return -ENOMEM; + + ret = nand_read_param_page_op(chip, 0, NULL, 0); + if (ret) { + ret = 0; + goto free_onfi_param_page; + } + + for (i = 0; i < 3; i++) { + ret = nand_read_data_op(chip, &p[i], sizeof(*p), true); + if (ret) { + ret = 0; + goto free_onfi_param_page; + } + + if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) == + le16_to_cpu(p->crc)) { + if (i) + memcpy(p, &p[i], sizeof(*p)); + break; + } + } + + if (i == 3) { + const void *srcbufs[3] = {p, p + 1, p + 2}; + + pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n"); + nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p, + sizeof(*p)); + + if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) != + le16_to_cpu(p->crc)) { + pr_err("ONFI parameter recovery failed, aborting\n"); + goto free_onfi_param_page; + } + } + + if (chip->manufacturer.desc && chip->manufacturer.desc->ops && + chip->manufacturer.desc->ops->fixup_onfi_param_page) + chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p); + + /* Check version */ + val = le16_to_cpu(p->revision); + if (val & ONFI_VERSION_2_3) + onfi_version = 23; + else if (val & ONFI_VERSION_2_2) + onfi_version = 22; + else if (val & ONFI_VERSION_2_1) + onfi_version = 21; + else if (val & ONFI_VERSION_2_0) + onfi_version = 20; + else if (val & ONFI_VERSION_1_0) + onfi_version = 10; + + if (!onfi_version) { + pr_info("unsupported ONFI version: %d\n", val); + goto free_onfi_param_page; + } + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + chip->parameters.model = kstrdup(p->model, GFP_KERNEL); + if (!chip->parameters.model) { + ret = -ENOMEM; + goto free_onfi_param_page; + } + + mtd->writesize = le32_to_cpu(p->byte_per_page); + + /* + * pages_per_block and blocks_per_lun may not be a power-of-2 size + * (don't ask me who thought of this...). MTD assumes that these + * dimensions will be power-of-2, so just truncate the remaining area. + */ + mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); + mtd->erasesize *= mtd->writesize; + + mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + + /* See erasesize comment */ + chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); + chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; + chip->bits_per_cell = p->bits_per_cell; + + chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun); + chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun); + + if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) + chip->options |= NAND_BUSWIDTH_16; + + if (p->ecc_bits != 0xff) { + chip->ecc_strength_ds = p->ecc_bits; + chip->ecc_step_ds = 512; + } else if (onfi_version >= 21 && + (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) { + + /* + * The nand_flash_detect_ext_param_page() uses the + * Change Read Column command which maybe not supported + * by the chip->legacy.cmdfunc. So try to update the + * chip->legacy.cmdfunc now. We do not replace user supplied + * command function. + */ + nand_legacy_adjust_cmdfunc(chip); + + /* The Extended Parameter Page is supported since ONFI 2.1. */ + if (nand_flash_detect_ext_param_page(chip, p)) + pr_warn("Failed to detect ONFI extended param page\n"); + } else { + pr_warn("Could not retrieve ONFI ECC requirements\n"); + } + + /* Save some parameters from the parameter page for future use */ + if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) { + chip->parameters.supports_set_get_features = true; + bitmap_set(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + bitmap_set(chip->parameters.set_feature_list, + ONFI_FEATURE_ADDR_TIMING_MODE, 1); + } + + onfi = kzalloc(sizeof(*onfi), GFP_KERNEL); + if (!onfi) { + ret = -ENOMEM; + goto free_model; + } + + onfi->version = onfi_version; + onfi->tPROG = le16_to_cpu(p->t_prog); + onfi->tBERS = le16_to_cpu(p->t_bers); + onfi->tR = le16_to_cpu(p->t_r); + onfi->tCCS = le16_to_cpu(p->t_ccs); + onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode); + onfi->vendor_revision = le16_to_cpu(p->vendor_revision); + memcpy(onfi->vendor, p->vendor, sizeof(p->vendor)); + chip->parameters.onfi = onfi; + + /* Identification done, free the full ONFI parameter page and exit */ + kfree(p); + + return 1; + +free_model: + kfree(chip->parameters.model); +free_onfi_param_page: + kfree(p); + + return ret; +} diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c index ef022f62f74c..e46d4c492ad8 100644 --- a/drivers/mtd/nand/raw/nand_samsung.c +++ b/drivers/mtd/nand/raw/nand_samsung.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include <linux/mtd/rawnand.h> +#include "internals.h" static void samsung_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c index ebc7b5f76f77..bea3062d71d6 100644 --- a/drivers/mtd/nand/raw/nand_timings.c +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -11,7 +11,8 @@ #include <linux/kernel.h> #include <linux/err.h> #include <linux/export.h> -#include <linux/mtd/rawnand.h> + +#include "internals.h" #define ONFI_DYN_TIMING_MAX U16_MAX @@ -271,20 +272,6 @@ static const struct nand_data_interface onfi_sdr_timings[] = { }; /** - * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND - * timings according to the given ONFI timing mode - * @mode: ONFI timing mode - */ -const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode) -{ - if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings)) - return ERR_PTR(-EINVAL); - - return &onfi_sdr_timings[mode].timings.sdr; -} -EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings); - -/** * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from * given ONFI mode * @mode: The ONFI timing mode @@ -339,4 +326,3 @@ int onfi_fill_data_interface(struct nand_chip *chip, return 0; } -EXPORT_SYMBOL(onfi_fill_data_interface); diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index ab43f027cd23..d068163b64b3 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -15,7 +15,88 @@ * GNU General Public License for more details. */ -#include <linux/mtd/rawnand.h> +#include "internals.h" + +/* Bit for detecting BENAND */ +#define TOSHIBA_NAND_ID4_IS_BENAND BIT(7) + +/* Recommended to rewrite for BENAND */ +#define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3) + +static int toshiba_nand_benand_eccstatus(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + unsigned int max_bitflips = 0; + u8 status; + + /* Check Status */ + ret = nand_status_op(chip, &status); + if (ret) + return ret; + + if (status & NAND_STATUS_FAIL) { + /* uncorrected */ + mtd->ecc_stats.failed++; + } else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) { + /* corrected */ + max_bitflips = mtd->bitflip_threshold; + mtd->ecc_stats.corrected += max_bitflips; + } + + return max_bitflips; +} + +static int +toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + int ret; + + ret = nand_read_page_raw(chip, buf, oob_required, page); + if (ret) + return ret; + + return toshiba_nand_benand_eccstatus(chip); +} + +static int +toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs, + uint32_t readlen, uint8_t *bufpoi, int page) +{ + int ret; + + ret = nand_read_page_op(chip, page, data_offs, + bufpoi + data_offs, readlen); + if (ret) + return ret; + + return toshiba_nand_benand_eccstatus(chip); +} + +static void toshiba_nand_benand_init(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* + * On BENAND, the entire OOB region can be used by the MTD user. + * The calculated ECC bytes are stored into other isolated + * area which is not accessible to users. + * This is why chip->ecc.bytes = 0. + */ + chip->ecc.bytes = 0; + chip->ecc.size = 512; + chip->ecc.strength = 8; + chip->ecc.read_page = toshiba_nand_read_page_benand; + chip->ecc.read_subpage = toshiba_nand_read_subpage_benand; + chip->ecc.write_page = nand_write_page_raw; + chip->ecc.read_page_raw = nand_read_page_raw_notsupp; + chip->ecc.write_page_raw = nand_write_page_raw_notsupp; + + chip->options |= NAND_SUBPAGE_READ; + + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); +} static void toshiba_nand_decode_id(struct nand_chip *chip) { @@ -68,6 +149,11 @@ static int toshiba_nand_init(struct nand_chip *chip) if (nand_is_slc(chip)) chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; + /* Check that chip is BENAND and ECC mode is on-die */ + if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE && + chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND) + toshiba_nand_benand_init(chip); + return 0; } diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 71ac034aee9c..c452819f6123 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -656,7 +656,7 @@ static int __init init_nandsim(struct mtd_info *mtd) } /* Force mtd to not do delays */ - chip->chip_delay = 0; + chip->legacy.chip_delay = 0; /* Initialize the NAND flash parameters */ ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8; @@ -1872,9 +1872,8 @@ static void switch_state(struct nandsim *ns) } } -static u_char ns_nand_read_byte(struct mtd_info *mtd) +static u_char ns_nand_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct nandsim *ns = nand_get_controller_data(chip); u_char outb = 0x00; @@ -1934,9 +1933,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd) return outb; } -static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) +static void ns_nand_write_byte(struct nand_chip *chip, u_char byte) { - struct nand_chip *chip = mtd_to_nand(mtd); struct nandsim *ns = nand_get_controller_data(chip); /* Sanity and correctness checks */ @@ -2089,9 +2087,8 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) return; } -static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask) +static void ns_hwcontrol(struct nand_chip *chip, int cmd, unsigned int bitmask) { - struct nand_chip *chip = mtd_to_nand(mtd); struct nandsim *ns = nand_get_controller_data(chip); ns->lines.cle = bitmask & NAND_CLE ? 1 : 0; @@ -2099,27 +2096,18 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask) ns->lines.ce = bitmask & NAND_NCE ? 1 : 0; if (cmd != NAND_CMD_NONE) - ns_nand_write_byte(mtd, cmd); + ns_nand_write_byte(chip, cmd); } -static int ns_device_ready(struct mtd_info *mtd) +static int ns_device_ready(struct nand_chip *chip) { NS_DBG("device_ready\n"); return 1; } -static uint16_t ns_nand_read_word(struct mtd_info *mtd) +static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf, + int len) { - struct nand_chip *chip = mtd_to_nand(mtd); - - NS_DBG("read_word\n"); - - return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); -} - -static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); struct nandsim *ns = nand_get_controller_data(chip); /* Check that chip is expecting data input */ @@ -2145,9 +2133,8 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) } } -static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct nandsim *ns = nand_get_controller_data(chip); /* Sanity and correctness checks */ @@ -2169,7 +2156,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) int i; for (i = 0; i < len; i++) - buf[i] = mtd_to_nand(mtd)->read_byte(mtd); + buf[i] = chip->legacy.read_byte(chip); return; } @@ -2262,12 +2249,11 @@ static int __init ns_init_module(void) /* * Register simulator's callbacks. */ - chip->cmd_ctrl = ns_hwcontrol; - chip->read_byte = ns_nand_read_byte; - chip->dev_ready = ns_device_ready; - chip->write_buf = ns_nand_write_buf; - chip->read_buf = ns_nand_read_buf; - chip->read_word = ns_nand_read_word; + chip->legacy.cmd_ctrl = ns_hwcontrol; + chip->legacy.read_byte = ns_nand_read_byte; + chip->legacy.dev_ready = ns_device_ready; + chip->legacy.write_buf = ns_nand_write_buf; + chip->legacy.read_buf = ns_nand_read_buf; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ @@ -2319,7 +2305,7 @@ static int __init ns_init_module(void) goto error; chip->dummy_controller.ops = &ns_controller_ops; - retval = nand_scan(nsmtd, 1); + retval = nand_scan(chip, 1); if (retval) { NS_ERR("Could not scan NAND Simulator device\n"); goto error; @@ -2364,7 +2350,7 @@ static int __init ns_init_module(void) err_exit: free_nandsim(nand); - nand_release(nsmtd); + nand_release(chip); for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) kfree(nand->partitions[i].name); error: @@ -2386,7 +2372,7 @@ static void __exit ns_cleanup_module(void) int i; free_nandsim(ns); /* Free nandsim private resources */ - nand_release(nsmtd); /* Unregister driver */ + nand_release(chip); /* Unregister driver */ for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) kfree(ns->partitions[i].name); kfree(mtd_to_nand(nsmtd)); /* Free other structures */ diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c index 540fa1a0ea24..d49a7a17146c 100644 --- a/drivers/mtd/nand/raw/ndfc.c +++ b/drivers/mtd/nand/raw/ndfc.c @@ -44,10 +44,9 @@ struct ndfc_controller { static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; -static void ndfc_select_chip(struct mtd_info *mtd, int chip) +static void ndfc_select_chip(struct nand_chip *nchip, int chip) { uint32_t ccr; - struct nand_chip *nchip = mtd_to_nand(mtd); struct ndfc_controller *ndfc = nand_get_controller_data(nchip); ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); @@ -59,9 +58,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); } -static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct ndfc_controller *ndfc = nand_get_controller_data(chip); if (cmd == NAND_CMD_NONE) @@ -73,18 +71,16 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE); } -static int ndfc_ready(struct mtd_info *mtd) +static int ndfc_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct ndfc_controller *ndfc = nand_get_controller_data(chip); return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; } -static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) +static void ndfc_enable_hwecc(struct nand_chip *chip, int mode) { uint32_t ccr; - struct nand_chip *chip = mtd_to_nand(mtd); struct ndfc_controller *ndfc = nand_get_controller_data(chip); ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); @@ -93,10 +89,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) wmb(); } -static int ndfc_calculate_ecc(struct mtd_info *mtd, +static int ndfc_calculate_ecc(struct nand_chip *chip, const u_char *dat, u_char *ecc_code) { - struct nand_chip *chip = mtd_to_nand(mtd); struct ndfc_controller *ndfc = nand_get_controller_data(chip); uint32_t ecc; uint8_t *p = (uint8_t *)&ecc; @@ -118,9 +113,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd, * functions. No further checking, as nand_base will always read/write * page aligned. */ -static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct ndfc_controller *ndfc = nand_get_controller_data(chip); uint32_t *p = (uint32_t *) buf; @@ -128,9 +122,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); } -static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct ndfc_controller *ndfc = nand_get_controller_data(chip); uint32_t *p = (uint32_t *) buf; @@ -149,15 +142,15 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, struct mtd_info *mtd = nand_to_mtd(chip); int ret; - chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; - chip->cmd_ctrl = ndfc_hwcontrol; - chip->dev_ready = ndfc_ready; + chip->legacy.IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; + chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; + chip->legacy.cmd_ctrl = ndfc_hwcontrol; + chip->legacy.dev_ready = ndfc_ready; chip->select_chip = ndfc_select_chip; - chip->chip_delay = 50; + chip->legacy.chip_delay = 50; chip->controller = &ndfc->ndfc_control; - chip->read_buf = ndfc_read_buf; - chip->write_buf = ndfc_write_buf; + chip->legacy.read_buf = ndfc_read_buf; + chip->legacy.write_buf = ndfc_write_buf; chip->ecc.correct = nand_correct_data; chip->ecc.hwctl = ndfc_enable_hwecc; chip->ecc.calculate = ndfc_calculate_ecc; @@ -174,14 +167,14 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, return -ENODEV; nand_set_flash_node(chip, flash_np); - mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev), - flash_np->name); + mtd->name = kasprintf(GFP_KERNEL, "%s.%pOFn", dev_name(&ndfc->ofdev->dev), + flash_np); if (!mtd->name) { ret = -ENOMEM; goto err; } - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret) goto err; @@ -258,7 +251,7 @@ static int ndfc_remove(struct platform_device *ofdev) struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); struct mtd_info *mtd = nand_to_mtd(&ndfc->chip); - nand_release(mtd); + nand_release(&ndfc->chip); kfree(mtd->name); return 0; diff --git a/drivers/mtd/nand/raw/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c index af5b32c9a791..38b1994e7ed3 100644 --- a/drivers/mtd/nand/raw/nuc900_nand.c +++ b/drivers/mtd/nand/raw/nuc900_nand.c @@ -79,31 +79,31 @@ static const struct mtd_partition partitions[] = { } }; -static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd) +static unsigned char nuc900_nand_read_byte(struct nand_chip *chip) { unsigned char ret; - struct nuc900_nand *nand = mtd_to_nuc900(mtd); + struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip)); ret = (unsigned char)read_data_reg(nand); return ret; } -static void nuc900_nand_read_buf(struct mtd_info *mtd, +static void nuc900_nand_read_buf(struct nand_chip *chip, unsigned char *buf, int len) { int i; - struct nuc900_nand *nand = mtd_to_nuc900(mtd); + struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip)); for (i = 0; i < len; i++) buf[i] = (unsigned char)read_data_reg(nand); } -static void nuc900_nand_write_buf(struct mtd_info *mtd, +static void nuc900_nand_write_buf(struct nand_chip *chip, const unsigned char *buf, int len) { int i; - struct nuc900_nand *nand = mtd_to_nuc900(mtd); + struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip)); for (i = 0; i < len; i++) write_data_reg(nand, buf[i]); @@ -120,19 +120,20 @@ static int nuc900_check_rb(struct nuc900_nand *nand) return val; } -static int nuc900_nand_devready(struct mtd_info *mtd) +static int nuc900_nand_devready(struct nand_chip *chip) { - struct nuc900_nand *nand = mtd_to_nuc900(mtd); + struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip)); int ready; ready = (nuc900_check_rb(nand)) ? 1 : 0; return ready; } -static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, +static void nuc900_nand_command_lp(struct nand_chip *chip, + unsigned int command, int column, int page_addr) { - register struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct nuc900_nand *nand = mtd_to_nuc900(mtd); if (command == NAND_CMD_READOOB) { @@ -174,9 +175,9 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, return; case NAND_CMD_RESET: - if (chip->dev_ready) + if (chip->legacy.dev_ready) break; - udelay(chip->chip_delay); + udelay(chip->legacy.chip_delay); write_cmd_reg(nand, NAND_CMD_STATUS); write_cmd_reg(nand, command); @@ -195,8 +196,8 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, write_cmd_reg(nand, NAND_CMD_READSTART); default: - if (!chip->dev_ready) { - udelay(chip->chip_delay); + if (!chip->legacy.dev_ready) { + udelay(chip->legacy.chip_delay); return; } } @@ -205,7 +206,7 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, * any case on any machine. */ ndelay(100); - while (!chip->dev_ready(mtd)) + while (!chip->legacy.dev_ready(chip)) ; } @@ -253,12 +254,12 @@ static int nuc900_nand_probe(struct platform_device *pdev) return -ENOENT; clk_enable(nuc900_nand->clk); - chip->cmdfunc = nuc900_nand_command_lp; - chip->dev_ready = nuc900_nand_devready; - chip->read_byte = nuc900_nand_read_byte; - chip->write_buf = nuc900_nand_write_buf; - chip->read_buf = nuc900_nand_read_buf; - chip->chip_delay = 50; + chip->legacy.cmdfunc = nuc900_nand_command_lp; + chip->legacy.dev_ready = nuc900_nand_devready; + chip->legacy.read_byte = nuc900_nand_read_byte; + chip->legacy.write_buf = nuc900_nand_write_buf; + chip->legacy.read_buf = nuc900_nand_read_buf; + chip->legacy.chip_delay = 50; chip->options = 0; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; @@ -270,7 +271,7 @@ static int nuc900_nand_probe(struct platform_device *pdev) nuc900_nand_enable(nuc900_nand); - if (nand_scan(mtd, 1)) + if (nand_scan(chip, 1)) return -ENXIO; mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions)); @@ -284,7 +285,7 @@ static int nuc900_nand_remove(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); - nand_release(nand_to_mtd(&nuc900_nand->chip)); + nand_release(&nuc900_nand->chip); clk_disable(nuc900_nand->clk); return 0; diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index 4546ac0bed4a..886d05c391ef 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -240,7 +240,7 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info) /** * omap_hwcontrol - hardware specific access to control-lines - * @mtd: MTD device structure + * @chip: NAND chip object * @cmd: command to device * @ctrl: * NAND_NCE: bit 0 -> don't care @@ -249,9 +249,9 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info) * * NOTE: boards may use different bits for these!! */ -static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void omap_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct omap_nand_info *info = mtd_to_omap(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); if (cmd != NAND_CMD_NONE) { if (ctrl & NAND_CLE) @@ -275,7 +275,7 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *nand = mtd_to_nand(mtd); - ioread8_rep(nand->IO_ADDR_R, buf, len); + ioread8_rep(nand->legacy.IO_ADDR_R, buf, len); } /** @@ -291,7 +291,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) bool status; while (len--) { - iowrite8(*p++, info->nand.IO_ADDR_W); + iowrite8(*p++, info->nand.legacy.IO_ADDR_W); /* wait until buffer is available for write */ do { status = info->ops->nand_writebuffer_empty(); @@ -309,7 +309,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *nand = mtd_to_nand(mtd); - ioread16_rep(nand->IO_ADDR_R, buf, len / 2); + ioread16_rep(nand->legacy.IO_ADDR_R, buf, len / 2); } /** @@ -327,7 +327,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) len >>= 1; while (len--) { - iowrite16(*p++, info->nand.IO_ADDR_W); + iowrite16(*p++, info->nand.legacy.IO_ADDR_W); /* wait until buffer is available for write */ do { status = info->ops->nand_writebuffer_empty(); @@ -337,12 +337,13 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) /** * omap_read_buf_pref - read data from NAND controller into buffer - * @mtd: MTD device structure + * @chip: NAND chip object * @buf: buffer to store date * @len: number of bytes to read */ -static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) +static void omap_read_buf_pref(struct nand_chip *chip, u_char *buf, int len) { + struct mtd_info *mtd = nand_to_mtd(chip); struct omap_nand_info *info = mtd_to_omap(mtd); uint32_t r_count = 0; int ret = 0; @@ -372,7 +373,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) r_count = readl(info->reg.gpmc_prefetch_status); r_count = PREFETCH_STATUS_FIFO_CNT(r_count); r_count = r_count >> 2; - ioread32_rep(info->nand.IO_ADDR_R, p, r_count); + ioread32_rep(info->nand.legacy.IO_ADDR_R, p, r_count); p += r_count; len -= r_count << 2; } while (len); @@ -383,13 +384,14 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) /** * omap_write_buf_pref - write buffer to NAND controller - * @mtd: MTD device structure + * @chip: NAND chip object * @buf: data buffer * @len: number of bytes to write */ -static void omap_write_buf_pref(struct mtd_info *mtd, - const u_char *buf, int len) +static void omap_write_buf_pref(struct nand_chip *chip, const u_char *buf, + int len) { + struct mtd_info *mtd = nand_to_mtd(chip); struct omap_nand_info *info = mtd_to_omap(mtd); uint32_t w_count = 0; int i = 0, ret = 0; @@ -399,7 +401,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, /* take care of subpage writes */ if (len % 2 != 0) { - writeb(*buf, info->nand.IO_ADDR_W); + writeb(*buf, info->nand.legacy.IO_ADDR_W); p = (u16 *)(buf + 1); len--; } @@ -419,7 +421,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, w_count = PREFETCH_STATUS_FIFO_CNT(w_count); w_count = w_count >> 1; for (i = 0; (i < w_count) && len; i++, len -= 2) - iowrite16(*p++, info->nand.IO_ADDR_W); + iowrite16(*p++, info->nand.legacy.IO_ADDR_W); } /* wait for data to flushed-out before reset the prefetch */ tim = 0; @@ -528,14 +530,17 @@ out_copy: /** * omap_read_buf_dma_pref - read data from NAND controller into buffer - * @mtd: MTD device structure + * @chip: NAND chip object * @buf: buffer to store date * @len: number of bytes to read */ -static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len) +static void omap_read_buf_dma_pref(struct nand_chip *chip, u_char *buf, + int len) { + struct mtd_info *mtd = nand_to_mtd(chip); + if (len <= mtd->oobsize) - omap_read_buf_pref(mtd, buf, len); + omap_read_buf_pref(chip, buf, len); else /* start transfer in DMA mode */ omap_nand_dma_transfer(mtd, buf, len, 0x0); @@ -543,18 +548,20 @@ static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len) /** * omap_write_buf_dma_pref - write buffer to NAND controller - * @mtd: MTD device structure + * @chip: NAND chip object * @buf: data buffer * @len: number of bytes to write */ -static void omap_write_buf_dma_pref(struct mtd_info *mtd, - const u_char *buf, int len) +static void omap_write_buf_dma_pref(struct nand_chip *chip, const u_char *buf, + int len) { + struct mtd_info *mtd = nand_to_mtd(chip); + if (len <= mtd->oobsize) - omap_write_buf_pref(mtd, buf, len); + omap_write_buf_pref(chip, buf, len); else /* start transfer in DMA mode */ - omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1); + omap_nand_dma_transfer(mtd, (u_char *)buf, len, 0x1); } /* @@ -578,14 +585,14 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) bytes = info->buf_len; else if (!info->buf_len) bytes = 0; - iowrite32_rep(info->nand.IO_ADDR_W, - (u32 *)info->buf, bytes >> 2); + iowrite32_rep(info->nand.legacy.IO_ADDR_W, (u32 *)info->buf, + bytes >> 2); info->buf = info->buf + bytes; info->buf_len -= bytes; } else { - ioread32_rep(info->nand.IO_ADDR_R, - (u32 *)info->buf, bytes >> 2); + ioread32_rep(info->nand.legacy.IO_ADDR_R, (u32 *)info->buf, + bytes >> 2); info->buf = info->buf + bytes; if (this_irq == info->gpmc_irq_count) @@ -605,17 +612,19 @@ done: /* * omap_read_buf_irq_pref - read data from NAND controller into buffer - * @mtd: MTD device structure + * @chip: NAND chip object * @buf: buffer to store date * @len: number of bytes to read */ -static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) +static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf, + int len) { + struct mtd_info *mtd = nand_to_mtd(chip); struct omap_nand_info *info = mtd_to_omap(mtd); int ret = 0; if (len <= mtd->oobsize) { - omap_read_buf_pref(mtd, buf, len); + omap_read_buf_pref(chip, buf, len); return; } @@ -651,20 +660,21 @@ out_copy: /* * omap_write_buf_irq_pref - write buffer to NAND controller - * @mtd: MTD device structure + * @chip: NAND chip object * @buf: data buffer * @len: number of bytes to write */ -static void omap_write_buf_irq_pref(struct mtd_info *mtd, - const u_char *buf, int len) +static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf, + int len) { + struct mtd_info *mtd = nand_to_mtd(chip); struct omap_nand_info *info = mtd_to_omap(mtd); int ret = 0; unsigned long tim, limit; u32 val; if (len <= mtd->oobsize) { - omap_write_buf_pref(mtd, buf, len); + omap_write_buf_pref(chip, buf, len); return; } @@ -857,7 +867,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ /** * omap_correct_data - Compares the ECC read with HW generated ECC - * @mtd: MTD device structure + * @chip: NAND chip object * @dat: page data * @read_ecc: ecc read from nand flash * @calc_ecc: ecc read from HW ECC registers @@ -869,10 +879,10 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ * corrected errors is returned. If uncorrectable errors exist, %-1 is * returned. */ -static int omap_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) +static int omap_correct_data(struct nand_chip *chip, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) { - struct omap_nand_info *info = mtd_to_omap(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); int blockCnt = 0, i = 0, ret = 0; int stat = 0; @@ -900,7 +910,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat, /** * omap_calcuate_ecc - Generate non-inverted ECC bytes. - * @mtd: MTD device structure + * @chip: NAND chip object * @dat: The pointer to data on which ecc is computed * @ecc_code: The ecc_code buffer * @@ -910,10 +920,10 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat, * an erased page will produce an ECC mismatch between generated and read * ECC bytes that has to be dealt with separately. */ -static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +static int omap_calculate_ecc(struct nand_chip *chip, const u_char *dat, + u_char *ecc_code) { - struct omap_nand_info *info = mtd_to_omap(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); u32 val; val = readl(info->reg.gpmc_ecc_config); @@ -935,10 +945,9 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, * @mtd: MTD device structure * @mode: Read/Write mode */ -static void omap_enable_hwecc(struct mtd_info *mtd, int mode) +static void omap_enable_hwecc(struct nand_chip *chip, int mode) { - struct omap_nand_info *info = mtd_to_omap(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; u32 val; @@ -972,8 +981,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) /** * omap_wait - wait until the command is done - * @mtd: MTD device structure - * @chip: NAND Chip structure + * @this: NAND Chip structure * * Wait function is called during Program and erase operations and * the way it is called from MTD layer, we should wait till the NAND @@ -982,10 +990,9 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs */ -static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) +static int omap_wait(struct nand_chip *this) { - struct nand_chip *this = mtd_to_nand(mtd); - struct omap_nand_info *info = mtd_to_omap(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this)); unsigned long timeo = jiffies; int status, state = this->state; @@ -1012,9 +1019,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) * * Returns true if ready and false if busy. */ -static int omap_dev_ready(struct mtd_info *mtd) +static int omap_dev_ready(struct nand_chip *chip) { - struct omap_nand_info *info = mtd_to_omap(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); return gpiod_get_value(info->ready_gpiod); } @@ -1030,13 +1037,13 @@ static int omap_dev_ready(struct mtd_info *mtd) * eccsize0 = 0 (no additional protected byte in spare area) * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) */ -static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode) +static void __maybe_unused omap_enable_hwecc_bch(struct nand_chip *chip, + int mode) { unsigned int bch_type; unsigned int dev_width, nsectors; - struct omap_nand_info *info = mtd_to_omap(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); enum omap_ecc ecc_opt = info->ecc_opt; - struct nand_chip *chip = mtd_to_nand(mtd); u32 val, wr_mode; unsigned int ecc_size1, ecc_size0; @@ -1256,7 +1263,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, /** * omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction - * @mtd: MTD device structure + * @chip: NAND chip object * @dat: The pointer to data on which ecc is computed * @ecc_code: The ecc_code buffer * @@ -1264,10 +1271,10 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, * when SW based correction is required as ECC is required for one sector * at a time. */ -static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd, +static int omap_calculate_ecc_bch_sw(struct nand_chip *chip, const u_char *dat, u_char *ecc_calc) { - return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0); + return _omap_calculate_ecc_bch(nand_to_mtd(chip), dat, ecc_calc, 0); } /** @@ -1339,7 +1346,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, /** * omap_elm_correct_data - corrects page data area in case error reported - * @mtd: MTD device structure + * @chip: NAND chip object * @data: page data * @read_ecc: ecc read from nand flash * @calc_ecc: ecc read from HW ECC registers @@ -1348,10 +1355,10 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, * In case of non-zero ecc vector, first filter out erased-pages, and * then process data via ELM to detect bit-flips. */ -static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, - u_char *read_ecc, u_char *calc_ecc) +static int omap_elm_correct_data(struct nand_chip *chip, u_char *data, + u_char *read_ecc, u_char *calc_ecc) { - struct omap_nand_info *info = mtd_to_omap(mtd); + struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); struct nand_ecc_ctrl *ecc = &info->nand.ecc; int eccsteps = info->nand.ecc.steps; int i , j, stat = 0; @@ -1512,7 +1519,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, /** * omap_write_page_bch - BCH ecc based write page function for entire page - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB @@ -1520,19 +1526,20 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, * * Custom write page method evolved to support multi sector writing in one shot */ -static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int ret; uint8_t *ecc_calc = chip->ecc.calc_buf; nand_prog_page_begin_op(chip, page, 0, NULL, 0); /* Enable GPMC ecc engine */ - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->ecc.hwctl(chip, NAND_ECC_WRITE); /* Write data */ - chip->write_buf(mtd, buf, mtd->writesize); + chip->legacy.write_buf(chip, buf, mtd->writesize); /* Update ecc vector from GPMC result registers */ omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]); @@ -1543,14 +1550,13 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, return ret; /* Write ecc vector to OOB area */ - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } /** * omap_write_subpage_bch - BCH hardware ECC based subpage write - * @mtd: mtd info structure * @chip: nand chip info structure * @offset: column address of subpage within the page * @data_len: data length @@ -1560,11 +1566,11 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, * * OMAP optimized subpage write method. */ -static int omap_write_subpage_bch(struct mtd_info *mtd, - struct nand_chip *chip, u32 offset, +static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset, u32 data_len, const u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); u8 *ecc_calc = chip->ecc.calc_buf; int ecc_size = chip->ecc.size; int ecc_bytes = chip->ecc.bytes; @@ -1582,10 +1588,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, nand_prog_page_begin_op(chip, page, 0, NULL, 0); /* Enable GPMC ECC engine */ - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->ecc.hwctl(chip, NAND_ECC_WRITE); /* Write data */ - chip->write_buf(mtd, buf, mtd->writesize); + chip->legacy.write_buf(chip, buf, mtd->writesize); for (step = 0; step < ecc_steps; step++) { /* mask ECC of un-touched subpages by padding 0xFF */ @@ -1610,14 +1616,13 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, return ret; /* write OOB buffer to NAND device */ - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } /** * omap_read_page_bch - BCH ecc based page read function for entire page - * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi @@ -1630,9 +1635,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, * ecc engine enabled. ecc vector updated after read of OOB data. * For non error pages ecc vector reported as zero. */ -static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); uint8_t *ecc_calc = chip->ecc.calc_buf; uint8_t *ecc_code = chip->ecc.code_buf; int stat, ret; @@ -1641,10 +1647,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, nand_read_page_op(chip, page, 0, NULL, 0); /* Enable GPMC ecc engine */ - chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->ecc.hwctl(chip, NAND_ECC_READ); /* Read data */ - chip->read_buf(mtd, buf, mtd->writesize); + chip->legacy.read_buf(chip, buf, mtd->writesize); /* Read oob bytes */ nand_change_read_column_op(chip, @@ -1660,7 +1666,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, if (ret) return ret; - stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc); + stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc); if (stat < 0) { mtd->ecc_stats.failed++; @@ -1927,8 +1933,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip) /* Re-populate low-level callbacks based on xfer modes */ switch (info->xfer_type) { case NAND_OMAP_PREFETCH_POLLED: - chip->read_buf = omap_read_buf_pref; - chip->write_buf = omap_write_buf_pref; + chip->legacy.read_buf = omap_read_buf_pref; + chip->legacy.write_buf = omap_write_buf_pref; break; case NAND_OMAP_POLLED: @@ -1960,8 +1966,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip) err); return err; } - chip->read_buf = omap_read_buf_dma_pref; - chip->write_buf = omap_write_buf_dma_pref; + chip->legacy.read_buf = omap_read_buf_dma_pref; + chip->legacy.write_buf = omap_write_buf_dma_pref; } break; @@ -1996,8 +2002,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip) return err; } - chip->read_buf = omap_read_buf_irq_pref; - chip->write_buf = omap_write_buf_irq_pref; + chip->legacy.read_buf = omap_read_buf_irq_pref; + chip->legacy.write_buf = omap_write_buf_irq_pref; break; @@ -2215,16 +2221,16 @@ static int omap_nand_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(nand_chip->IO_ADDR_R)) - return PTR_ERR(nand_chip->IO_ADDR_R); + nand_chip->legacy.IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(nand_chip->legacy.IO_ADDR_R)) + return PTR_ERR(nand_chip->legacy.IO_ADDR_R); info->phys_base = res->start; nand_chip->controller = &omap_gpmc_controller; - nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R; - nand_chip->cmd_ctrl = omap_hwcontrol; + nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R; + nand_chip->legacy.cmd_ctrl = omap_hwcontrol; info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb", GPIOD_IN); @@ -2241,11 +2247,11 @@ static int omap_nand_probe(struct platform_device *pdev) * device and read status register until you get a failure or success */ if (info->ready_gpiod) { - nand_chip->dev_ready = omap_dev_ready; - nand_chip->chip_delay = 0; + nand_chip->legacy.dev_ready = omap_dev_ready; + nand_chip->legacy.chip_delay = 0; } else { - nand_chip->waitfunc = omap_wait; - nand_chip->chip_delay = 50; + nand_chip->legacy.waitfunc = omap_wait; + nand_chip->legacy.chip_delay = 50; } if (info->flash_bbt) @@ -2254,7 +2260,7 @@ static int omap_nand_probe(struct platform_device *pdev) /* scan NAND device connected to chip controller */ nand_chip->options |= info->devsize & NAND_BUSWIDTH_16; - err = nand_scan(mtd, 1); + err = nand_scan(nand_chip, 1); if (err) goto return_error; @@ -2290,7 +2296,7 @@ static int omap_nand_remove(struct platform_device *pdev) } if (info->dma) dma_release_channel(info->dma); - nand_release(mtd); + nand_release(nand_chip); return 0; } diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c index 52d435285a3f..d27b39a7223c 100644 --- a/drivers/mtd/nand/raw/orion_nand.c +++ b/drivers/mtd/nand/raw/orion_nand.c @@ -26,9 +26,9 @@ struct orion_nand_info { struct clk *clk; }; -static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void orion_nand_cmd_ctrl(struct nand_chip *nc, int cmd, + unsigned int ctrl) { - struct nand_chip *nc = mtd_to_nand(mtd); struct orion_nand_data *board = nand_get_controller_data(nc); u32 offs; @@ -45,13 +45,12 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl if (nc->options & NAND_BUSWIDTH_16) offs <<= 1; - writeb(cmd, nc->IO_ADDR_W + offs); + writeb(cmd, nc->legacy.IO_ADDR_W + offs); } -static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); - void __iomem *io_base = chip->IO_ADDR_R; + void __iomem *io_base = chip->legacy.IO_ADDR_R; #if defined(__LINUX_ARM_ARCH__) && __LINUX_ARM_ARCH__ >= 5 uint64_t *buf64; #endif @@ -137,14 +136,14 @@ static int __init orion_nand_probe(struct platform_device *pdev) nand_set_controller_data(nc, board); nand_set_flash_node(nc, pdev->dev.of_node); - nc->IO_ADDR_R = nc->IO_ADDR_W = io_base; - nc->cmd_ctrl = orion_nand_cmd_ctrl; - nc->read_buf = orion_nand_read_buf; + nc->legacy.IO_ADDR_R = nc->legacy.IO_ADDR_W = io_base; + nc->legacy.cmd_ctrl = orion_nand_cmd_ctrl; + nc->legacy.read_buf = orion_nand_read_buf; nc->ecc.mode = NAND_ECC_SOFT; nc->ecc.algo = NAND_ECC_HAMMING; if (board->chip_delay) - nc->chip_delay = board->chip_delay; + nc->legacy.chip_delay = board->chip_delay; WARN(board->width > 16, "%d bit bus width out of range", @@ -174,14 +173,14 @@ static int __init orion_nand_probe(struct platform_device *pdev) return ret; } - ret = nand_scan(mtd, 1); + ret = nand_scan(nc, 1); if (ret) goto no_dev; mtd->name = "orion_nand"; ret = mtd_device_register(mtd, board->parts, board->nr_parts); if (ret) { - nand_release(mtd); + nand_release(nc); goto no_dev; } @@ -196,9 +195,8 @@ static int orion_nand_remove(struct platform_device *pdev) { struct orion_nand_info *info = platform_get_drvdata(pdev); struct nand_chip *chip = &info->chip; - struct mtd_info *mtd = nand_to_mtd(chip); - nand_release(mtd); + nand_release(chip); clk_disable_unprepare(info->clk); diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c index 01b00bb69c1e..0e52dc29141c 100644 --- a/drivers/mtd/nand/raw/oxnas_nand.c +++ b/drivers/mtd/nand/raw/oxnas_nand.c @@ -38,35 +38,32 @@ struct oxnas_nand_ctrl { struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS]; }; -static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd) +static uint8_t oxnas_nand_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); return readb(oxnas->io_base); } -static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); ioread8_rep(oxnas->io_base, buf, len); } -static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf, + int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); iowrite8_rep(oxnas->io_base, buf, len); } /* Single CS command control */ -static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, +static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); if (ctrl & NAND_CLE) @@ -135,20 +132,20 @@ static int oxnas_nand_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; mtd->priv = chip; - chip->cmd_ctrl = oxnas_nand_cmd_ctrl; - chip->read_buf = oxnas_nand_read_buf; - chip->read_byte = oxnas_nand_read_byte; - chip->write_buf = oxnas_nand_write_buf; - chip->chip_delay = 30; + chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl; + chip->legacy.read_buf = oxnas_nand_read_buf; + chip->legacy.read_byte = oxnas_nand_read_byte; + chip->legacy.write_buf = oxnas_nand_write_buf; + chip->legacy.chip_delay = 30; /* Scan to find existence of the device */ - err = nand_scan(mtd, 1); + err = nand_scan(chip, 1); if (err) goto err_clk_unprepare; err = mtd_device_register(mtd, NULL, 0); if (err) { - nand_release(mtd); + nand_release(chip); goto err_clk_unprepare; } @@ -176,7 +173,7 @@ static int oxnas_nand_remove(struct platform_device *pdev) struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev); if (oxnas->chips[0]) - nand_release(nand_to_mtd(oxnas->chips[0])); + nand_release(oxnas->chips[0]); clk_disable_unprepare(oxnas->clk); diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c index a47a7e4bd25a..643cd22af009 100644 --- a/drivers/mtd/nand/raw/pasemi_nand.c +++ b/drivers/mtd/nand/raw/pasemi_nand.c @@ -43,49 +43,44 @@ static unsigned int lpcctl; static struct mtd_info *pasemi_nand_mtd; static const char driver_name[] = "pasemi-nand"; -static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); - while (len > 0x800) { - memcpy_fromio(buf, chip->IO_ADDR_R, 0x800); + memcpy_fromio(buf, chip->legacy.IO_ADDR_R, 0x800); buf += 0x800; len -= 0x800; } - memcpy_fromio(buf, chip->IO_ADDR_R, len); + memcpy_fromio(buf, chip->legacy.IO_ADDR_R, len); } -static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf, + int len) { - struct nand_chip *chip = mtd_to_nand(mtd); - while (len > 0x800) { - memcpy_toio(chip->IO_ADDR_R, buf, 0x800); + memcpy_toio(chip->legacy.IO_ADDR_R, buf, 0x800); buf += 0x800; len -= 0x800; } - memcpy_toio(chip->IO_ADDR_R, buf, len); + memcpy_toio(chip->legacy.IO_ADDR_R, buf, len); } -static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd, +static void pasemi_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); - if (cmd == NAND_CMD_NONE) return; if (ctrl & NAND_CLE) - out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd); + out_8(chip->legacy.IO_ADDR_W + (1 << CLE_PIN_CTL), cmd); else - out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd); + out_8(chip->legacy.IO_ADDR_W + (1 << ALE_PIN_CTL), cmd); /* Push out posted writes */ eieio(); inl(lpcctl); } -int pasemi_device_ready(struct mtd_info *mtd) +int pasemi_device_ready(struct nand_chip *chip) { return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); } @@ -122,10 +117,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev) /* Link the private data with the MTD structure */ pasemi_nand_mtd->dev.parent = dev; - chip->IO_ADDR_R = of_iomap(np, 0); - chip->IO_ADDR_W = chip->IO_ADDR_R; + chip->legacy.IO_ADDR_R = of_iomap(np, 0); + chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R; - if (!chip->IO_ADDR_R) { + if (!chip->legacy.IO_ADDR_R) { err = -EIO; goto out_mtd; } @@ -144,11 +139,11 @@ static int pasemi_nand_probe(struct platform_device *ofdev) goto out_ior; } - chip->cmd_ctrl = pasemi_hwcontrol; - chip->dev_ready = pasemi_device_ready; - chip->read_buf = pasemi_read_buf; - chip->write_buf = pasemi_write_buf; - chip->chip_delay = 0; + chip->legacy.cmd_ctrl = pasemi_hwcontrol; + chip->legacy.dev_ready = pasemi_device_ready; + chip->legacy.read_buf = pasemi_read_buf; + chip->legacy.write_buf = pasemi_write_buf; + chip->legacy.chip_delay = 0; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; @@ -156,7 +151,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev) chip->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ - err = nand_scan(pasemi_nand_mtd, 1); + err = nand_scan(chip, 1); if (err) goto out_lpc; @@ -174,7 +169,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev) out_lpc: release_region(lpcctl, 4); out_ior: - iounmap(chip->IO_ADDR_R); + iounmap(chip->legacy.IO_ADDR_R); out_mtd: kfree(chip); out: @@ -191,11 +186,11 @@ static int pasemi_nand_remove(struct platform_device *ofdev) chip = mtd_to_nand(pasemi_nand_mtd); /* Release resources, unregister device */ - nand_release(pasemi_nand_mtd); + nand_release(chip); release_region(lpcctl, 4); - iounmap(chip->IO_ADDR_R); + iounmap(chip->legacy.IO_ADDR_R); /* Free the MTD device structure */ kfree(chip); diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index 222626df4b96..86c536ddaf24 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -15,8 +15,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/mtd/rawnand.h> -#include <linux/mtd/partitions.h> +#include <linux/mtd/platnand.h> struct plat_nand_data { struct nand_chip chip; @@ -60,14 +59,14 @@ static int plat_nand_probe(struct platform_device *pdev) mtd = nand_to_mtd(&data->chip); mtd->dev.parent = &pdev->dev; - data->chip.IO_ADDR_R = data->io_base; - data->chip.IO_ADDR_W = data->io_base; - data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl; - data->chip.dev_ready = pdata->ctrl.dev_ready; + data->chip.legacy.IO_ADDR_R = data->io_base; + data->chip.legacy.IO_ADDR_W = data->io_base; + data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl; + data->chip.legacy.dev_ready = pdata->ctrl.dev_ready; data->chip.select_chip = pdata->ctrl.select_chip; - data->chip.write_buf = pdata->ctrl.write_buf; - data->chip.read_buf = pdata->ctrl.read_buf; - data->chip.chip_delay = pdata->chip.chip_delay; + data->chip.legacy.write_buf = pdata->ctrl.write_buf; + data->chip.legacy.read_buf = pdata->ctrl.read_buf; + data->chip.legacy.chip_delay = pdata->chip.chip_delay; data->chip.options |= pdata->chip.options; data->chip.bbt_options |= pdata->chip.bbt_options; @@ -84,7 +83,7 @@ static int plat_nand_probe(struct platform_device *pdev) } /* Scan to find existence of the device */ - err = nand_scan(mtd, pdata->chip.nr_chips); + err = nand_scan(&data->chip, pdata->chip.nr_chips); if (err) goto out; @@ -97,7 +96,7 @@ static int plat_nand_probe(struct platform_device *pdev) if (!err) return err; - nand_release(mtd); + nand_release(&data->chip); out: if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); @@ -112,7 +111,7 @@ static int plat_nand_remove(struct platform_device *pdev) struct plat_nand_data *data = platform_get_drvdata(pdev); struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); - nand_release(nand_to_mtd(&data->chip)); + nand_release(&data->chip); if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index d1d470bb32e4..ef75dfa62a4f 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -23,7 +23,6 @@ #include <linux/of_device.h> #include <linux/delay.h> #include <linux/dma/qcom_bam_dma.h> -#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */ /* NANDc reg offsets */ #define NAND_FLASH_CMD 0x00 @@ -350,7 +349,8 @@ struct nandc_regs { * @data_buffer: our local DMA buffer for page read/writes, * used when we can't use the buffer provided * by upper layers directly - * @buf_size/count/start: markers for chip->read_buf/write_buf functions + * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf + * functions * @reg_read_buf: local buffer for reading back registers via DMA * @reg_read_dma: contains dma address for register read buffer * @reg_read_pos: marker for data read in reg_read_buf @@ -1155,8 +1155,8 @@ static void config_nand_cw_write(struct qcom_nand_controller *nandc) } /* - * the following functions are used within chip->cmdfunc() to perform different - * NAND_CMD_* commands + * the following functions are used within chip->legacy.cmdfunc() to + * perform different NAND_CMD_* commands */ /* sets up descriptors for NAND_CMD_PARAM */ @@ -1436,15 +1436,14 @@ static void post_command(struct qcom_nand_host *host, int command) } /* - * Implements chip->cmdfunc. It's only used for a limited set of commands. - * The rest of the commands wouldn't be called by upper layers. For example, - * NAND_CMD_READOOB would never be called because we have our own versions - * of read_oob ops for nand_ecc_ctrl. + * Implements chip->legacy.cmdfunc. It's only used for a limited set of + * commands. The rest of the commands wouldn't be called by upper layers. + * For example, NAND_CMD_READOOB would never be called because we have our own + * versions of read_oob ops for nand_ecc_ctrl. */ -static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command, +static void qcom_nandc_command(struct nand_chip *chip, unsigned int command, int column, int page_addr) { - struct nand_chip *chip = mtd_to_nand(mtd); struct qcom_nand_host *host = to_qcom_nand_host(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); @@ -1949,8 +1948,8 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) } /* implements ecc->read_page() */ -static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); @@ -1966,10 +1965,10 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip, } /* implements ecc->read_page_raw() */ -static int qcom_nandc_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int cw, ret; @@ -1989,8 +1988,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, } /* implements ecc->read_oob() */ -static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int qcom_nandc_read_oob(struct nand_chip *chip, int page) { struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); @@ -2007,8 +2005,8 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, } /* implements ecc->write_page() */ -static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); @@ -2077,10 +2075,11 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, } /* implements ecc->write_page_raw() */ -static int qcom_nandc_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, - int oob_required, int page) +static int qcom_nandc_write_page_raw(struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; @@ -2155,9 +2154,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, * since ECC is calculated for the combined codeword. So update the OOB from * chip->oob_poi, and pad the data area with OxFF before writing. */ -static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int qcom_nandc_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; @@ -2197,9 +2196,9 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, return nand_prog_page_end_op(chip); } -static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs) +static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; @@ -2235,9 +2234,8 @@ err: return bad; } -static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) +static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; @@ -2278,14 +2276,13 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) } /* - * the three functions below implement chip->read_byte(), chip->read_buf() - * and chip->write_buf() respectively. these aren't used for - * reading/writing page data, they are used for smaller data like reading - * id, status etc + * the three functions below implement chip->legacy.read_byte(), + * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these + * aren't used for reading/writing page data, they are used for smaller data + * like reading id, status etc */ -static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd) +static uint8_t qcom_nandc_read_byte(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); u8 *buf = nandc->data_buffer; @@ -2305,9 +2302,8 @@ static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd) return ret; } -static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start); @@ -2315,10 +2311,9 @@ static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) nandc->buf_start += real_len; } -static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf, +static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct nand_chip *chip = mtd_to_nand(mtd); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start); @@ -2328,9 +2323,8 @@ static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf, } /* we support only one external chip for now */ -static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr) +static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr) { - struct nand_chip *chip = mtd_to_nand(mtd); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); if (chipnr <= 0) @@ -2809,13 +2803,13 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, mtd->owner = THIS_MODULE; mtd->dev.parent = dev; - chip->cmdfunc = qcom_nandc_command; + chip->legacy.cmdfunc = qcom_nandc_command; chip->select_chip = qcom_nandc_select_chip; - chip->read_byte = qcom_nandc_read_byte; - chip->read_buf = qcom_nandc_read_buf; - chip->write_buf = qcom_nandc_write_buf; - chip->set_features = nand_get_set_features_notsupp; - chip->get_features = nand_get_set_features_notsupp; + chip->legacy.read_byte = qcom_nandc_read_byte; + chip->legacy.read_buf = qcom_nandc_read_buf; + chip->legacy.write_buf = qcom_nandc_write_buf; + chip->legacy.set_features = nand_get_set_features_notsupp; + chip->legacy.get_features = nand_get_set_features_notsupp; /* * the bad block marker is readable only when we read the last codeword @@ -2825,8 +2819,8 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, * and block_markbad helpers until we permanently switch to using * MTD_OPS_RAW for all drivers (with the help of badblockbits) */ - chip->block_bad = qcom_nandc_block_bad; - chip->block_markbad = qcom_nandc_block_markbad; + chip->legacy.block_bad = qcom_nandc_block_bad; + chip->legacy.block_markbad = qcom_nandc_block_markbad; chip->controller = &nandc->controller; chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER | @@ -2835,7 +2829,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, /* set up initial status value */ host->status = NAND_STATUS_READY | NAND_STATUS_WP; - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret) return ret; @@ -3000,7 +2994,7 @@ static int qcom_nandc_remove(struct platform_device *pdev) struct qcom_nand_host *host; list_for_each_entry(host, &nandc->host_list, node) - nand_release(nand_to_mtd(&host->chip)); + nand_release(&host->chip); qcom_nandc_unalloc(nandc); diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c index dcdeb0660e5e..39be65b35ac2 100644 --- a/drivers/mtd/nand/raw/r852.c +++ b/drivers/mtd/nand/raw/r852.c @@ -232,9 +232,9 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) /* * Program data lines of the nand chip to send data to it */ -static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void r852_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); uint32_t reg; /* Don't allow any access to hardware if we suspect card removal */ @@ -266,9 +266,9 @@ static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /* * Read data lines of the nand chip to retrieve data */ -static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void r852_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); uint32_t reg; if (dev->card_unstable) { @@ -303,9 +303,9 @@ static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) /* * Read one byte from nand chip */ -static uint8_t r852_read_byte(struct mtd_info *mtd) +static uint8_t r852_read_byte(struct nand_chip *chip) { - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); /* Same problem as in r852_read_buf.... */ if (dev->card_unstable) @@ -317,9 +317,9 @@ static uint8_t r852_read_byte(struct mtd_info *mtd) /* * Control several chip lines & send commands */ -static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl) +static void r852_cmdctl(struct nand_chip *chip, int dat, unsigned int ctrl) { - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); if (dev->card_unstable) return; @@ -362,7 +362,7 @@ static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl) * Wait till card is ready. * based on nand_wait, but returns errors on DMA error */ -static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) +static int r852_wait(struct nand_chip *chip) { struct r852_device *dev = nand_get_controller_data(chip); @@ -373,7 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) msecs_to_jiffies(400) : msecs_to_jiffies(20)); while (time_before(jiffies, timeout)) - if (chip->dev_ready(mtd)) + if (chip->legacy.dev_ready(chip)) break; nand_status_op(chip, &status); @@ -390,9 +390,9 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) * Check if card is ready */ -static int r852_ready(struct mtd_info *mtd) +static int r852_ready(struct nand_chip *chip) { - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY); } @@ -401,9 +401,9 @@ static int r852_ready(struct mtd_info *mtd) * Set ECC engine mode */ -static void r852_ecc_hwctl(struct mtd_info *mtd, int mode) +static void r852_ecc_hwctl(struct nand_chip *chip, int mode) { - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); if (dev->card_unstable) return; @@ -433,10 +433,10 @@ static void r852_ecc_hwctl(struct mtd_info *mtd, int mode) * Calculate ECC, only used for writes */ -static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) +static int r852_ecc_calculate(struct nand_chip *chip, const uint8_t *dat, + uint8_t *ecc_code) { - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); struct sm_oob *oob = (struct sm_oob *)ecc_code; uint32_t ecc1, ecc2; @@ -465,14 +465,14 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, * Correct the data using ECC, hw did almost everything for us */ -static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) +static int r852_ecc_correct(struct nand_chip *chip, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) { uint32_t ecc_reg; uint8_t ecc_status, err_byte; int i, error = 0; - struct r852_device *dev = r852_get_dev(mtd); + struct r852_device *dev = r852_get_dev(nand_to_mtd(chip)); if (dev->card_unstable) return 0; @@ -521,9 +521,10 @@ exit: * This is copy of nand_read_oob_std * nand_read_oob_syndrome assumes we can send column address - we can't */ -static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int r852_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); } @@ -636,7 +637,7 @@ static int r852_register_nand_device(struct r852_device *dev) { struct mtd_info *mtd = nand_to_mtd(dev->chip); - WARN_ON(dev->card_registred); + WARN_ON(dev->card_registered); mtd->dev.parent = &dev->pci_dev->dev; @@ -653,10 +654,10 @@ static int r852_register_nand_device(struct r852_device *dev) goto error3; } - dev->card_registred = 1; + dev->card_registered = 1; return 0; error3: - nand_release(mtd); + nand_release(dev->chip); error1: /* Force card redetect */ dev->card_detected = 0; @@ -671,13 +672,13 @@ static void r852_unregister_nand_device(struct r852_device *dev) { struct mtd_info *mtd = nand_to_mtd(dev->chip); - if (!dev->card_registred) + if (!dev->card_registered) return; device_remove_file(&mtd->dev, &dev_attr_media_type); - nand_release(mtd); + nand_release(dev->chip); r852_engine_disable(dev); - dev->card_registred = 0; + dev->card_registered = 0; } /* Card state updater */ @@ -691,7 +692,7 @@ static void r852_card_detect_work(struct work_struct *work) dev->card_unstable = 0; /* False alarm */ - if (dev->card_detected == dev->card_registred) + if (dev->card_detected == dev->card_registered) goto exit; /* Read media properties */ @@ -852,14 +853,14 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) goto error4; /* commands */ - chip->cmd_ctrl = r852_cmdctl; - chip->waitfunc = r852_wait; - chip->dev_ready = r852_ready; + chip->legacy.cmd_ctrl = r852_cmdctl; + chip->legacy.waitfunc = r852_wait; + chip->legacy.dev_ready = r852_ready; /* I/O */ - chip->read_byte = r852_read_byte; - chip->read_buf = r852_read_buf; - chip->write_buf = r852_write_buf; + chip->legacy.read_byte = r852_read_byte; + chip->legacy.read_buf = r852_read_buf; + chip->legacy.write_buf = r852_write_buf; /* ecc */ chip->ecc.mode = NAND_ECC_HW_SYNDROME; @@ -1025,7 +1026,6 @@ static int r852_suspend(struct device *device) static int r852_resume(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); - struct mtd_info *mtd = nand_to_mtd(dev->chip); r852_disable_irqs(dev); r852_card_update_present(dev); @@ -1033,7 +1033,7 @@ static int r852_resume(struct device *device) /* If card status changed, just do the work */ - if (dev->card_detected != dev->card_registred) { + if (dev->card_detected != dev->card_registered) { dbg("card was %s during low power state", dev->card_detected ? "added" : "removed"); @@ -1043,11 +1043,11 @@ static int r852_resume(struct device *device) } /* Otherwise, initialize the card */ - if (dev->card_registred) { + if (dev->card_registered) { r852_engine_enable(dev); - dev->chip->select_chip(mtd, 0); + dev->chip->select_chip(dev->chip, 0); nand_reset_op(dev->chip); - dev->chip->select_chip(mtd, -1); + dev->chip->select_chip(dev->chip, -1); } /* Program card detection IRQ */ diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h index 1eed2fc2fa42..bc67f5bf67e8 100644 --- a/drivers/mtd/nand/raw/r852.h +++ b/drivers/mtd/nand/raw/r852.h @@ -129,7 +129,7 @@ struct r852_device { /* card status area */ struct delayed_work card_detect_work; struct workqueue_struct *card_workqueue; - int card_registred; /* card registered with mtd */ + int card_registered; /* card registered with mtd */ int card_detected; /* card detected in slot */ int card_unstable; /* whenever the card is inserted, is not known yet */ diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index c21e8892394a..d2e42e9d0e8c 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -404,7 +404,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) /** * s3c2410_nand_select_chip - select the given nand chip - * @mtd: The MTD instance for this chip. + * @this: NAND chip object. * @chip: The chip number. * * This is called by the MTD layer to either select a given chip for the @@ -415,11 +415,10 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) * platform specific selection code is called to route nFCE to the specific * chip. */ -static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) +static void s3c2410_nand_select_chip(struct nand_chip *this, int chip) { struct s3c2410_nand_info *info; struct s3c2410_nand_mtd *nmtd; - struct nand_chip *this = mtd_to_nand(mtd); unsigned long cur; nmtd = nand_get_controller_data(this); @@ -457,9 +456,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) * Issue command and address cycles to the chip */ -static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd, +static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); if (cmd == NAND_CMD_NONE) @@ -473,9 +473,10 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd, /* command and control functions */ -static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd, +static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); if (cmd == NAND_CMD_NONE) @@ -492,29 +493,33 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd, * returns 0 if the nand is busy, 1 if it is ready */ -static int s3c2410_nand_devready(struct mtd_info *mtd) +static int s3c2410_nand_devready(struct nand_chip *chip) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; } -static int s3c2440_nand_devready(struct mtd_info *mtd) +static int s3c2440_nand_devready(struct nand_chip *chip) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; } -static int s3c2412_nand_devready(struct mtd_info *mtd) +static int s3c2412_nand_devready(struct nand_chip *chip) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY; } /* ECC handling functions */ -static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, +static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); unsigned int diff0, diff1, diff2; unsigned int bit, byte; @@ -591,38 +596,42 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, * generator block to ECC the data as it passes through] */ -static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) +static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode) { - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + struct s3c2410_nand_info *info; unsigned long ctrl; + info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip)); ctrl = readl(info->regs + S3C2410_NFCONF); ctrl |= S3C2410_NFCONF_INITECC; writel(ctrl, info->regs + S3C2410_NFCONF); } -static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode) +static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode) { - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + struct s3c2410_nand_info *info; unsigned long ctrl; + info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip)); ctrl = readl(info->regs + S3C2440_NFCONT); writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT); } -static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode) +static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode) { - struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + struct s3c2410_nand_info *info; unsigned long ctrl; + info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip)); ctrl = readl(info->regs + S3C2440_NFCONT); writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT); } -static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +static int s3c2410_nand_calculate_ecc(struct nand_chip *chip, + const u_char *dat, u_char *ecc_code) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0); @@ -634,9 +643,10 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, return 0; } -static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +static int s3c2412_nand_calculate_ecc(struct nand_chip *chip, + const u_char *dat, u_char *ecc_code) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); unsigned long ecc = readl(info->regs + S3C2412_NFMECC0); @@ -649,9 +659,10 @@ static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, return 0; } -static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +static int s3c2440_nand_calculate_ecc(struct nand_chip *chip, + const u_char *dat, u_char *ecc_code) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); unsigned long ecc = readl(info->regs + S3C2440_NFMECC0); @@ -668,14 +679,14 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, * use read/write block to move the data buffers to/from the controller */ -static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); - readsb(this->IO_ADDR_R, buf, len); + readsb(this->legacy.IO_ADDR_R, buf, len); } -static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len) { + struct mtd_info *mtd = nand_to_mtd(this); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); readsl(info->regs + S3C2440_NFDATA, buf, len >> 2); @@ -689,16 +700,16 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) } } -static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, +static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf, int len) { - struct nand_chip *this = mtd_to_nand(mtd); - writesb(this->IO_ADDR_W, buf, len); + writesb(this->legacy.IO_ADDR_W, buf, len); } -static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, +static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf, int len) { + struct mtd_info *mtd = nand_to_mtd(this); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); writesl(info->regs + S3C2440_NFDATA, buf, len >> 2); @@ -781,7 +792,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) { pr_debug("releasing mtd %d (%p)\n", mtdno, ptr); - nand_release(nand_to_mtd(&ptr->chip)); + nand_release(&ptr->chip); } } @@ -809,9 +820,10 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, return -ENODEV; } -static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline, +static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline, const struct nand_data_interface *conf) { + struct mtd_info *mtd = nand_to_mtd(chip); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct s3c2410_platform_nand *pdata = info->platform; const struct nand_sdr_timings *timings; @@ -852,10 +864,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, nand_set_flash_node(chip, set->of_node); - chip->write_buf = s3c2410_nand_write_buf; - chip->read_buf = s3c2410_nand_read_buf; + chip->legacy.write_buf = s3c2410_nand_write_buf; + chip->legacy.read_buf = s3c2410_nand_read_buf; chip->select_chip = s3c2410_nand_select_chip; - chip->chip_delay = 50; + chip->legacy.chip_delay = 50; nand_set_controller_data(chip, nmtd); chip->options = set->options; chip->controller = &info->controller; @@ -869,29 +881,29 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, switch (info->cpu_type) { case TYPE_S3C2410: - chip->IO_ADDR_W = regs + S3C2410_NFDATA; + chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA; info->sel_reg = regs + S3C2410_NFCONF; info->sel_bit = S3C2410_NFCONF_nFCE; - chip->cmd_ctrl = s3c2410_nand_hwcontrol; - chip->dev_ready = s3c2410_nand_devready; + chip->legacy.cmd_ctrl = s3c2410_nand_hwcontrol; + chip->legacy.dev_ready = s3c2410_nand_devready; break; case TYPE_S3C2440: - chip->IO_ADDR_W = regs + S3C2440_NFDATA; + chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA; info->sel_reg = regs + S3C2440_NFCONT; info->sel_bit = S3C2440_NFCONT_nFCE; - chip->cmd_ctrl = s3c2440_nand_hwcontrol; - chip->dev_ready = s3c2440_nand_devready; - chip->read_buf = s3c2440_nand_read_buf; - chip->write_buf = s3c2440_nand_write_buf; + chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol; + chip->legacy.dev_ready = s3c2440_nand_devready; + chip->legacy.read_buf = s3c2440_nand_read_buf; + chip->legacy.write_buf = s3c2440_nand_write_buf; break; case TYPE_S3C2412: - chip->IO_ADDR_W = regs + S3C2440_NFDATA; + chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA; info->sel_reg = regs + S3C2440_NFCONT; info->sel_bit = S3C2412_NFCONT_nFCE0; - chip->cmd_ctrl = s3c2440_nand_hwcontrol; - chip->dev_ready = s3c2412_nand_devready; + chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol; + chip->legacy.dev_ready = s3c2412_nand_devready; if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT) dev_info(info->device, "System booted from NAND\n"); @@ -899,7 +911,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, break; } - chip->IO_ADDR_R = chip->IO_ADDR_W; + chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W; nmtd->info = info; nmtd->set = set; @@ -1170,7 +1182,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; s3c2410_nand_init_chip(info, nmtd, sets); - err = nand_scan(mtd, sets ? sets->nr_chips : 1); + err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1); if (err) goto exit_error; diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index bb8866e05ff7..4d20d033de7b 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -480,7 +480,7 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) /* initiate DMA transfer */ if (flctl->chan_fifo0_rx && rlen >= 32 && - flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0) + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0) goto convert; /* DMA success */ /* do polling transfer */ @@ -539,7 +539,7 @@ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, /* initiate DMA transfer */ if (flctl->chan_fifo0_tx && rlen >= 32 && - flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0) + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0) return; /* DMA success */ /* do polling transfer */ @@ -611,21 +611,24 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va writel(flcmcdr_val, FLCMCDR(flctl)); } -static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int flctl_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + nand_read_page_op(chip, page, 0, buf, mtd->writesize); if (oob_required) - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); return 0; } -static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static int flctl_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize); - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); return nand_prog_page_end_op(chip); } @@ -747,9 +750,10 @@ static void execmd_write_oob(struct mtd_info *mtd) } } -static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, +static void flctl_cmdfunc(struct nand_chip *chip, unsigned int command, int column, int page_addr) { + struct mtd_info *mtd = nand_to_mtd(chip); struct sh_flctl *flctl = mtd_to_flctl(mtd); uint32_t read_cmd = 0; @@ -923,9 +927,9 @@ runtime_exit: return; } -static void flctl_select_chip(struct mtd_info *mtd, int chipnr) +static void flctl_select_chip(struct nand_chip *chip, int chipnr) { - struct sh_flctl *flctl = mtd_to_flctl(mtd); + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); int ret; switch (chipnr) { @@ -967,17 +971,17 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr) } } -static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void flctl_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct sh_flctl *flctl = mtd_to_flctl(mtd); + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); memcpy(&flctl->done_buff[flctl->index], buf, len); flctl->index += len; } -static uint8_t flctl_read_byte(struct mtd_info *mtd) +static uint8_t flctl_read_byte(struct nand_chip *chip) { - struct sh_flctl *flctl = mtd_to_flctl(mtd); + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); uint8_t data; data = flctl->done_buff[flctl->index]; @@ -985,18 +989,9 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd) return data; } -static uint16_t flctl_read_word(struct mtd_info *mtd) +static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct sh_flctl *flctl = mtd_to_flctl(mtd); - uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index]; - - flctl->index += 2; - return *buf; -} - -static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct sh_flctl *flctl = mtd_to_flctl(mtd); + struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip)); memcpy(buf, &flctl->done_buff[flctl->index], len); flctl->index += len; @@ -1183,16 +1178,15 @@ static int flctl_probe(struct platform_device *pdev) /* Set address of hardware control function */ /* 20 us command delay time */ - nand->chip_delay = 20; + nand->legacy.chip_delay = 20; - nand->read_byte = flctl_read_byte; - nand->read_word = flctl_read_word; - nand->write_buf = flctl_write_buf; - nand->read_buf = flctl_read_buf; + nand->legacy.read_byte = flctl_read_byte; + nand->legacy.write_buf = flctl_write_buf; + nand->legacy.read_buf = flctl_read_buf; nand->select_chip = flctl_select_chip; - nand->cmdfunc = flctl_cmdfunc; - nand->set_features = nand_get_set_features_notsupp; - nand->get_features = nand_get_set_features_notsupp; + nand->legacy.cmdfunc = flctl_cmdfunc; + nand->legacy.set_features = nand_get_set_features_notsupp; + nand->legacy.get_features = nand_get_set_features_notsupp; if (pdata->flcmncr_val & SEL_16BIT) nand->options |= NAND_BUSWIDTH_16; @@ -1203,7 +1197,7 @@ static int flctl_probe(struct platform_device *pdev) flctl_setup_dma(flctl); nand->dummy_controller.ops = &flctl_nand_controller_ops; - ret = nand_scan(flctl_mtd, 1); + ret = nand_scan(nand, 1); if (ret) goto err_chip; @@ -1226,7 +1220,7 @@ static int flctl_remove(struct platform_device *pdev) struct sh_flctl *flctl = platform_get_drvdata(pdev); flctl_release_dma(flctl); - nand_release(nand_to_mtd(&flctl->chip)); + nand_release(&flctl->chip); pm_runtime_disable(&pdev->dev); return 0; diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c index fc171b17a39b..c82f26c8b58c 100644 --- a/drivers/mtd/nand/raw/sharpsl.c +++ b/drivers/mtd/nand/raw/sharpsl.c @@ -59,11 +59,10 @@ static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd) * NAND_ALE: bit 2 -> bit 2 * */ -static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, +static void sharpsl_nand_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip)); if (ctrl & NAND_CTRL_CHANGE) { unsigned char bits = ctrl & 0x07; @@ -76,24 +75,25 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, } if (cmd != NAND_CMD_NONE) - writeb(cmd, chip->IO_ADDR_W); + writeb(cmd, chip->legacy.IO_ADDR_W); } -static int sharpsl_nand_dev_ready(struct mtd_info *mtd) +static int sharpsl_nand_dev_ready(struct nand_chip *chip) { - struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip)); return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0); } -static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) +static void sharpsl_nand_enable_hwecc(struct nand_chip *chip, int mode) { - struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip)); writeb(0, sharpsl->io + ECCCLRR); } -static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) +static int sharpsl_nand_calculate_ecc(struct nand_chip *chip, + const u_char * dat, u_char * ecc_code) { - struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip)); ecc_code[0] = ~readb(sharpsl->io + ECCLPUB); ecc_code[1] = ~readb(sharpsl->io + ECCLPLB); ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03; @@ -153,13 +153,13 @@ static int sharpsl_nand_probe(struct platform_device *pdev) writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL); /* Set address of NAND IO lines */ - this->IO_ADDR_R = sharpsl->io + FLASHIO; - this->IO_ADDR_W = sharpsl->io + FLASHIO; + this->legacy.IO_ADDR_R = sharpsl->io + FLASHIO; + this->legacy.IO_ADDR_W = sharpsl->io + FLASHIO; /* Set address of hardware control function */ - this->cmd_ctrl = sharpsl_nand_hwcontrol; - this->dev_ready = sharpsl_nand_dev_ready; + this->legacy.cmd_ctrl = sharpsl_nand_hwcontrol; + this->legacy.dev_ready = sharpsl_nand_dev_ready; /* 15 us command delay time */ - this->chip_delay = 15; + this->legacy.chip_delay = 15; /* set eccmode using hardware ECC */ this->ecc.mode = NAND_ECC_HW; this->ecc.size = 256; @@ -171,7 +171,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) this->ecc.correct = nand_correct_data; /* Scan to find existence of the device */ - err = nand_scan(mtd, 1); + err = nand_scan(this, 1); if (err) goto err_scan; @@ -187,7 +187,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) return 0; err_add: - nand_release(mtd); + nand_release(this); err_scan: iounmap(sharpsl->io); @@ -205,7 +205,7 @@ static int sharpsl_nand_remove(struct platform_device *pdev) struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); /* Release resources, unregister device */ - nand_release(nand_to_mtd(&sharpsl->chip)); + nand_release(&sharpsl->chip); iounmap(sharpsl->io); diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c index 73aafe8c3ef3..6f063ef57640 100644 --- a/drivers/mtd/nand/raw/sm_common.c +++ b/drivers/mtd/nand/raw/sm_common.c @@ -99,8 +99,9 @@ static const struct mtd_ooblayout_ops oob_sm_small_ops = { .free = oob_sm_small_ooblayout_free, }; -static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) +static int sm_block_markbad(struct nand_chip *chip, loff_t ofs) { + struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_oob_ops ops; struct sm_oob oob; int ret; @@ -167,7 +168,7 @@ static int sm_attach_chip(struct nand_chip *chip) /* Bad block marker position */ chip->badblockpos = 0x05; chip->badblockbits = 7; - chip->block_markbad = sm_block_markbad; + chip->legacy.block_markbad = sm_block_markbad; /* ECC layout */ if (mtd->writesize == SM_SECTOR_SIZE) @@ -195,7 +196,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia) /* Scan for card properties */ chip->dummy_controller.ops = &sm_controller_ops; flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids; - ret = nand_scan_with_ids(mtd, 1, flash_ids); + ret = nand_scan_with_ids(chip, 1, flash_ids); if (ret) return ret; diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c index 9824a9923583..8be9a50c7880 100644 --- a/drivers/mtd/nand/raw/socrates_nand.c +++ b/drivers/mtd/nand/raw/socrates_nand.c @@ -34,15 +34,14 @@ struct socrates_nand_host { /** * socrates_nand_write_buf - write buffer to chip - * @mtd: MTD device structure + * @this: NAND chip object * @buf: data buffer * @len: number of bytes to write */ -static void socrates_nand_write_buf(struct mtd_info *mtd, - const uint8_t *buf, int len) +static void socrates_nand_write_buf(struct nand_chip *this, const uint8_t *buf, + int len) { int i; - struct nand_chip *this = mtd_to_nand(mtd); struct socrates_nand_host *host = nand_get_controller_data(this); for (i = 0; i < len; i++) { @@ -54,14 +53,14 @@ static void socrates_nand_write_buf(struct mtd_info *mtd, /** * socrates_nand_read_buf - read chip data into buffer - * @mtd: MTD device structure + * @this: NAND chip object * @buf: buffer to store date * @len: number of bytes to read */ -static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void socrates_nand_read_buf(struct nand_chip *this, uint8_t *buf, + int len) { int i; - struct nand_chip *this = mtd_to_nand(mtd); struct socrates_nand_host *host = nand_get_controller_data(this); uint32_t val; @@ -78,31 +77,19 @@ static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) * socrates_nand_read_byte - read one byte from the chip * @mtd: MTD device structure */ -static uint8_t socrates_nand_read_byte(struct mtd_info *mtd) +static uint8_t socrates_nand_read_byte(struct nand_chip *this) { uint8_t byte; - socrates_nand_read_buf(mtd, &byte, sizeof(byte)); + socrates_nand_read_buf(this, &byte, sizeof(byte)); return byte; } -/** - * socrates_nand_read_word - read one word from the chip - * @mtd: MTD device structure - */ -static uint16_t socrates_nand_read_word(struct mtd_info *mtd) -{ - uint16_t word; - socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word)); - return word; -} - /* * Hardware specific access to control-lines */ -static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, - unsigned int ctrl) +static void socrates_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd, + unsigned int ctrl) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct socrates_nand_host *host = nand_get_controller_data(nand_chip); uint32_t val; @@ -125,9 +112,8 @@ static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, /* * Read the Device Ready pin. */ -static int socrates_nand_device_ready(struct mtd_info *mtd) +static int socrates_nand_device_ready(struct nand_chip *nand_chip) { - struct nand_chip *nand_chip = mtd_to_nand(mtd); struct socrates_nand_host *host = nand_get_controller_data(nand_chip); if (in_be32(host->io_base) & FPGA_NAND_BUSY) @@ -166,26 +152,21 @@ static int socrates_nand_probe(struct platform_device *ofdev) mtd->name = "socrates_nand"; mtd->dev.parent = &ofdev->dev; - /*should never be accessed directly */ - nand_chip->IO_ADDR_R = (void *)0xdeadbeef; - nand_chip->IO_ADDR_W = (void *)0xdeadbeef; - - nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl; - nand_chip->read_byte = socrates_nand_read_byte; - nand_chip->read_word = socrates_nand_read_word; - nand_chip->write_buf = socrates_nand_write_buf; - nand_chip->read_buf = socrates_nand_read_buf; - nand_chip->dev_ready = socrates_nand_device_ready; + nand_chip->legacy.cmd_ctrl = socrates_nand_cmd_ctrl; + nand_chip->legacy.read_byte = socrates_nand_read_byte; + nand_chip->legacy.write_buf = socrates_nand_write_buf; + nand_chip->legacy.read_buf = socrates_nand_read_buf; + nand_chip->legacy.dev_ready = socrates_nand_device_ready; nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ nand_chip->ecc.algo = NAND_ECC_HAMMING; /* TODO: I have no idea what real delay is. */ - nand_chip->chip_delay = 20; /* 20us command delay time */ + nand_chip->legacy.chip_delay = 20; /* 20us command delay time */ dev_set_drvdata(&ofdev->dev, host); - res = nand_scan(mtd, 1); + res = nand_scan(nand_chip, 1); if (res) goto out; @@ -193,7 +174,7 @@ static int socrates_nand_probe(struct platform_device *ofdev) if (!res) return res; - nand_release(mtd); + nand_release(nand_chip); out: iounmap(host->io_base); @@ -206,9 +187,8 @@ out: static int socrates_nand_remove(struct platform_device *ofdev) { struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); - struct mtd_info *mtd = nand_to_mtd(&host->nand_chip); - nand_release(mtd); + nand_release(&host->nand_chip); iounmap(host->io_base); diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 1f0b7ee38df5..51b1a548064b 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -400,9 +400,8 @@ static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd, nfc->regs + NFC_REG_CTL); } -static int sunxi_nfc_dev_ready(struct mtd_info *mtd) +static int sunxi_nfc_dev_ready(struct nand_chip *nand) { - struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); u32 mask; @@ -420,9 +419,9 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd) return !!(readl(nfc->regs + NFC_REG_ST) & mask); } -static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) +static void sunxi_nfc_select_chip(struct nand_chip *nand, int chip) { - struct nand_chip *nand = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(nand); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct sunxi_nand_chip_sel *sel; @@ -443,9 +442,9 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | NFC_PAGE_SHIFT(nand->page_shift); if (sel->rb < 0) { - nand->dev_ready = NULL; + nand->legacy.dev_ready = NULL; } else { - nand->dev_ready = sunxi_nfc_dev_ready; + nand->legacy.dev_ready = sunxi_nfc_dev_ready; ctl |= NFC_RB_SEL(sel->rb); } @@ -464,9 +463,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) sunxi_nand->selected = chip; } -static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len) { - struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); int ret; @@ -502,10 +500,9 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) } } -static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, +static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf, int len) { - struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); int ret; @@ -540,19 +537,18 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, } } -static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) +static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand) { uint8_t ret = 0; - sunxi_nfc_read_buf(mtd, &ret, 1); + sunxi_nfc_read_buf(nand, &ret, 1); return ret; } -static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, +static void sunxi_nfc_cmd_ctrl(struct nand_chip *nand, int dat, unsigned int ctrl) { - struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); int ret; @@ -761,7 +757,7 @@ static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd, { sunxi_nfc_randomizer_config(mtd, page, ecc); sunxi_nfc_randomizer_enable(mtd); - sunxi_nfc_write_buf(mtd, buf, len); + sunxi_nfc_write_buf(mtd_to_nand(mtd), buf, len); sunxi_nfc_randomizer_disable(mtd); } @@ -770,7 +766,7 @@ static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf, { sunxi_nfc_randomizer_config(mtd, page, ecc); sunxi_nfc_randomizer_enable(mtd); - sunxi_nfc_read_buf(mtd, buf, len); + sunxi_nfc_read_buf(mtd_to_nand(mtd), buf, len); sunxi_nfc_randomizer_disable(mtd); } @@ -995,7 +991,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, false); if (!randomize) - sunxi_nfc_read_buf(mtd, oob + offset, len); + sunxi_nfc_read_buf(nand, oob + offset, len); else sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len, false, page); @@ -1189,10 +1185,10 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, *cur_off = mtd->oobsize + mtd->writesize; } -static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, +static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; unsigned int max_bitflips = 0; int ret, i, cur_off = 0; @@ -1227,10 +1223,10 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, return max_bitflips; } -static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int ret; nand_read_page_op(chip, page, 0, NULL, 0); @@ -1241,14 +1237,14 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd, return ret; /* Fallback to PIO mode */ - return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page); + return sunxi_nfc_hw_ecc_read_page(chip, buf, oob_required, page); } -static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, - struct nand_chip *chip, +static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *chip, u32 data_offs, u32 readlen, u8 *bufpoi, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i, cur_off = 0; unsigned int max_bitflips = 0; @@ -1278,11 +1274,11 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, return max_bitflips; } -static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd, - struct nand_chip *chip, +static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *chip, u32 data_offs, u32 readlen, u8 *buf, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size); int ret; @@ -1293,15 +1289,15 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd, return ret; /* Fallback to PIO mode */ - return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen, + return sunxi_nfc_hw_ecc_read_subpage(chip, data_offs, readlen, buf, page); } -static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, +static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i, cur_off = 0; @@ -1331,12 +1327,12 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, return nand_prog_page_end_op(chip); } -static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, - struct nand_chip *chip, +static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *chip, u32 data_offs, u32 data_len, const u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i, cur_off = 0; @@ -1363,12 +1359,12 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, return nand_prog_page_end_op(chip); } -static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, - struct nand_chip *chip, +static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); struct nand_ecc_ctrl *ecc = &nand->ecc; @@ -1425,28 +1421,25 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, return nand_prog_page_end_op(chip); pio_fallback: - return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page); + return sunxi_nfc_hw_ecc_write_page(chip, buf, oob_required, page); } -static int sunxi_nfc_hw_ecc_read_oob(struct mtd_info *mtd, - struct nand_chip *chip, - int page) +static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *chip, int page) { chip->pagebuf = -1; - return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page); + return chip->ecc.read_page(chip, chip->data_buf, 1, page); } -static int sunxi_nfc_hw_ecc_write_oob(struct mtd_info *mtd, - struct nand_chip *chip, - int page) +static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); int ret; chip->pagebuf = -1; memset(chip->data_buf, 0xff, mtd->writesize); - ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page); + ret = chip->ecc.write_page(chip, chip->data_buf, 1, page); if (ret) return ret; @@ -1475,10 +1468,9 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, #define sunxi_nand_lookup_timing(l, p, c) \ _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) -static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline, +static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline, const struct nand_data_interface *conf) { - struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nand_chip *chip = to_sunxi_nand(nand); struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller); const struct nand_sdr_timings *timings; @@ -1920,7 +1912,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, nand = &chip->nand; /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ - nand->chip_delay = 200; + nand->legacy.chip_delay = 200; nand->controller = &nfc->controller; nand->controller->ops = &sunxi_nand_controller_ops; @@ -1931,23 +1923,23 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, nand->ecc.mode = NAND_ECC_HW; nand_set_flash_node(nand, np); nand->select_chip = sunxi_nfc_select_chip; - nand->cmd_ctrl = sunxi_nfc_cmd_ctrl; - nand->read_buf = sunxi_nfc_read_buf; - nand->write_buf = sunxi_nfc_write_buf; - nand->read_byte = sunxi_nfc_read_byte; + nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl; + nand->legacy.read_buf = sunxi_nfc_read_buf; + nand->legacy.write_buf = sunxi_nfc_write_buf; + nand->legacy.read_byte = sunxi_nfc_read_byte; nand->setup_data_interface = sunxi_nfc_setup_data_interface; mtd = nand_to_mtd(nand); mtd->dev.parent = dev; - ret = nand_scan(mtd, nsels); + ret = nand_scan(nand, nsels); if (ret) return ret; ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(dev, "failed to register mtd device: %d\n", ret); - nand_release(mtd); + nand_release(nand); return ret; } @@ -1986,7 +1978,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) while (!list_empty(&nfc->chips)) { chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, node); - nand_release(nand_to_mtd(&chip->nand)); + nand_release(&chip->nand); sunxi_nand_ecc_cleanup(&chip->nand.ecc); list_del(&chip->node); } diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c index 72698691727d..8818f893f300 100644 --- a/drivers/mtd/nand/raw/tango_nand.c +++ b/drivers/mtd/nand/raw/tango_nand.c @@ -116,9 +116,9 @@ struct tango_chip { #define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3)) -static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl) { - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + struct tango_chip *tchip = to_tango_chip(chip); if (ctrl & NAND_CLE) writeb_relaxed(dat, tchip->base + PBUS_CMD); @@ -127,38 +127,36 @@ static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) writeb_relaxed(dat, tchip->base + PBUS_ADDR); } -static int tango_dev_ready(struct mtd_info *mtd) +static int tango_dev_ready(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); struct tango_nfc *nfc = to_tango_nfc(chip->controller); return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY; } -static u8 tango_read_byte(struct mtd_info *mtd) +static u8 tango_read_byte(struct nand_chip *chip) { - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + struct tango_chip *tchip = to_tango_chip(chip); return readb_relaxed(tchip->base + PBUS_DATA); } -static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len) { - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + struct tango_chip *tchip = to_tango_chip(chip); ioread8_rep(tchip->base + PBUS_DATA, buf, len); } -static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len) { - struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + struct tango_chip *tchip = to_tango_chip(chip); iowrite8_rep(tchip->base + PBUS_DATA, buf, len); } -static void tango_select_chip(struct mtd_info *mtd, int idx) +static void tango_select_chip(struct nand_chip *chip, int idx) { - struct nand_chip *chip = mtd_to_nand(mtd); struct tango_nfc *nfc = to_tango_nfc(chip->controller); struct tango_chip *tchip = to_tango_chip(chip); @@ -277,14 +275,15 @@ dma_unmap: return err; } -static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip, - u8 *buf, int oob_required, int page) +static int tango_read_page(struct nand_chip *chip, u8 *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct tango_nfc *nfc = to_tango_nfc(chip->controller); int err, res, len = mtd->writesize; if (oob_required) - chip->ecc.read_oob(mtd, chip, page); + chip->ecc.read_oob(chip, page); err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page); if (err) @@ -292,16 +291,17 @@ static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip, res = decode_error_report(chip); if (res < 0) { - chip->ecc.read_oob_raw(mtd, chip, page); + chip->ecc.read_oob_raw(chip, page); res = check_erased_page(chip, buf); } return res; } -static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const u8 *buf, int oob_required, int page) +static int tango_write_page(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct tango_nfc *nfc = to_tango_nfc(chip->controller); int err, status, len = mtd->writesize; @@ -314,7 +314,7 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (err) return err; - status = chip->waitfunc(mtd, chip); + status = chip->legacy.waitfunc(chip); if (status & NAND_STATUS_FAIL) return -EIO; @@ -323,30 +323,26 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip, static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) { - struct mtd_info *mtd = nand_to_mtd(chip); - *pos += len; if (!*buf) { /* skip over "len" bytes */ nand_change_read_column_op(chip, *pos, NULL, 0, false); } else { - tango_read_buf(mtd, *buf, len); + tango_read_buf(chip, *buf, len); *buf += len; } } static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) { - struct mtd_info *mtd = nand_to_mtd(chip); - *pos += len; if (!*buf) { /* skip over "len" bytes */ nand_change_write_column_op(chip, *pos, NULL, 0, false); } else { - tango_write_buf(mtd, *buf, len); + tango_write_buf(chip, *buf, len); *buf += len; } } @@ -424,32 +420,30 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) aux_write(chip, &oob, ecc_size, &pos); } -static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - u8 *buf, int oob_required, int page) +static int tango_read_page_raw(struct nand_chip *chip, u8 *buf, + int oob_required, int page) { nand_read_page_op(chip, page, 0, NULL, 0); raw_read(chip, buf, chip->oob_poi); return 0; } -static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const u8 *buf, int oob_required, int page) +static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) { nand_prog_page_begin_op(chip, page, 0, NULL, 0); raw_write(chip, buf, chip->oob_poi); return nand_prog_page_end_op(chip); } -static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int tango_read_oob(struct nand_chip *chip, int page) { nand_read_page_op(chip, page, 0, NULL, 0); raw_read(chip, NULL, chip->oob_poi); return 0; } -static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int tango_write_oob(struct nand_chip *chip, int page) { nand_prog_page_begin_op(chip, page, 0, NULL, 0); raw_write(chip, NULL, chip->oob_poi); @@ -485,11 +479,10 @@ static u32 to_ticks(int kHz, int ps) return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC); } -static int tango_set_timings(struct mtd_info *mtd, int csline, +static int tango_set_timings(struct nand_chip *chip, int csline, const struct nand_data_interface *conf) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf); - struct nand_chip *chip = mtd_to_nand(mtd); struct tango_nfc *nfc = to_tango_nfc(chip->controller); struct tango_chip *tchip = to_tango_chip(chip); u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr; @@ -571,12 +564,12 @@ static int chip_init(struct device *dev, struct device_node *np) ecc = &chip->ecc; mtd = nand_to_mtd(chip); - chip->read_byte = tango_read_byte; - chip->write_buf = tango_write_buf; - chip->read_buf = tango_read_buf; + chip->legacy.read_byte = tango_read_byte; + chip->legacy.write_buf = tango_write_buf; + chip->legacy.read_buf = tango_read_buf; chip->select_chip = tango_select_chip; - chip->cmd_ctrl = tango_cmd_ctrl; - chip->dev_ready = tango_dev_ready; + chip->legacy.cmd_ctrl = tango_cmd_ctrl; + chip->legacy.dev_ready = tango_dev_ready; chip->setup_data_interface = tango_set_timings; chip->options = NAND_USE_BOUNCE_BUFFER | NAND_NO_SUBPAGE_WRITE | @@ -588,7 +581,7 @@ static int chip_init(struct device *dev, struct device_node *np) mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops); mtd->dev.parent = dev; - err = nand_scan(mtd, 1); + err = nand_scan(chip, 1); if (err) return err; @@ -617,7 +610,7 @@ static int tango_nand_remove(struct platform_device *pdev) for (cs = 0; cs < MAX_CS; ++cs) { if (nfc->chips[cs]) - nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip)); + nand_release(&nfc->chips[cs]->nand_chip); } return 0; diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index 79da1efc88d1..9767e29d74e2 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -462,9 +462,8 @@ static int tegra_nand_exec_op(struct nand_chip *chip, check_only); } -static void tegra_nand_select_chip(struct mtd_info *mtd, int die_nr) +static void tegra_nand_select_chip(struct nand_chip *chip, int die_nr) { - struct nand_chip *chip = mtd_to_nand(mtd); struct tegra_nand_chip *nand = to_tegra_chip(chip); struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); @@ -615,44 +614,46 @@ err_unmap_dma_page: return ret; } -static int tegra_nand_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int tegra_nand_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); void *oob_buf = oob_required ? chip->oob_poi : NULL; return tegra_nand_page_xfer(mtd, chip, buf, oob_buf, mtd->oobsize, page, true); } -static int tegra_nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, +static int tegra_nand_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); void *oob_buf = oob_required ? chip->oob_poi : NULL; return tegra_nand_page_xfer(mtd, chip, (void *)buf, oob_buf, mtd->oobsize, page, false); } -static int tegra_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int tegra_nand_read_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi, mtd->oobsize, page, true); } -static int tegra_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int tegra_nand_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); + return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi, mtd->oobsize, page, false); } -static int tegra_nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int tegra_nand_read_page_hwecc(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); struct tegra_nand_chip *nand = to_tegra_chip(chip); void *oob_buf = oob_required ? chip->oob_poi : NULL; @@ -716,7 +717,7 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd, * erased or if error correction just failed for all sub- * pages. */ - ret = tegra_nand_read_oob(mtd, chip, page); + ret = tegra_nand_read_oob(chip, page); if (ret < 0) return ret; @@ -759,10 +760,10 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd, } } -static int tegra_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, +static int tegra_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); void *oob_buf = oob_required ? chip->oob_poi : NULL; int ret; @@ -813,10 +814,9 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl, writel_relaxed(reg, ctrl->regs + TIMING_2); } -static int tegra_nand_setup_data_interface(struct mtd_info *mtd, int csline, +static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline, const struct nand_data_interface *conf) { - struct nand_chip *chip = mtd_to_nand(mtd); struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); const struct nand_sdr_timings *timings; @@ -1119,7 +1119,7 @@ static int tegra_nand_chips_init(struct device *dev, chip->select_chip = tegra_nand_select_chip; chip->setup_data_interface = tegra_nand_setup_data_interface; - ret = nand_scan(mtd, 1); + ret = nand_scan(chip, 1); if (ret) return ret; diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c index dcaa924502de..f3b59e649b7d 100644 --- a/drivers/mtd/nand/raw/tmio_nand.c +++ b/drivers/mtd/nand/raw/tmio_nand.c @@ -126,11 +126,10 @@ static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd) /*--------------------------------------------------------------------------*/ -static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) +static void tmio_nand_hwcontrol(struct nand_chip *chip, int cmd, + unsigned int ctrl) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip)); if (ctrl & NAND_CTRL_CHANGE) { u8 mode; @@ -156,12 +155,12 @@ static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd, } if (cmd != NAND_CMD_NONE) - tmio_iowrite8(cmd, chip->IO_ADDR_W); + tmio_iowrite8(cmd, chip->legacy.IO_ADDR_W); } -static int tmio_nand_dev_ready(struct mtd_info *mtd) +static int tmio_nand_dev_ready(struct nand_chip *chip) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip)); return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY); } @@ -187,10 +186,9 @@ static irqreturn_t tmio_irq(int irq, void *__tmio) *erase and write, we enable it to wake us up. The irq handler *disables the interrupt. */ -static int -tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) +static int tmio_nand_wait(struct nand_chip *nand_chip) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(nand_chip)); long timeout; u8 status; @@ -199,10 +197,10 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) tmio_iowrite8(0x81, tmio->fcr + FCR_IMR); timeout = wait_event_timeout(nand_chip->controller->wq, - tmio_nand_dev_ready(mtd), + tmio_nand_dev_ready(nand_chip), msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20)); - if (unlikely(!tmio_nand_dev_ready(mtd))) { + if (unlikely(!tmio_nand_dev_ready(nand_chip))) { tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n", nand_chip->state == FL_ERASING ? "erase" : "program", @@ -225,9 +223,9 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) *To prevent stale data from being read, tmio_nand_hwcontrol() clears *tmio->read_good. */ -static u_char tmio_nand_read_byte(struct mtd_info *mtd) +static u_char tmio_nand_read_byte(struct nand_chip *chip) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip)); unsigned int data; if (tmio->read_good--) @@ -245,33 +243,33 @@ static u_char tmio_nand_read_byte(struct mtd_info *mtd) *buffer functions. */ static void -tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +tmio_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip)); tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); } -static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void tmio_nand_read_buf(struct nand_chip *chip, u_char *buf, int len) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip)); tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1); } -static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode) +static void tmio_nand_enable_hwecc(struct nand_chip *chip, int mode) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip)); tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE); tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */ tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE); } -static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +static int tmio_nand_calculate_ecc(struct nand_chip *chip, const u_char *dat, + u_char *ecc_code) { - struct tmio_nand *tmio = mtd_to_tmio(mtd); + struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip)); unsigned int ecc; tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE); @@ -290,16 +288,18 @@ static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, return 0; } -static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, - unsigned char *read_ecc, unsigned char *calc_ecc) +static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) { int r0, r1; /* assume ecc.size = 512 and ecc.bytes = 6 */ - r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256); + r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256, false); if (r0 < 0) return r0; - r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256); + r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256, + false); if (r1 < 0) return r1; return r0 + r1; @@ -400,15 +400,15 @@ static int tmio_probe(struct platform_device *dev) return retval; /* Set address of NAND IO lines */ - nand_chip->IO_ADDR_R = tmio->fcr; - nand_chip->IO_ADDR_W = tmio->fcr; + nand_chip->legacy.IO_ADDR_R = tmio->fcr; + nand_chip->legacy.IO_ADDR_W = tmio->fcr; /* Set address of hardware control function */ - nand_chip->cmd_ctrl = tmio_nand_hwcontrol; - nand_chip->dev_ready = tmio_nand_dev_ready; - nand_chip->read_byte = tmio_nand_read_byte; - nand_chip->write_buf = tmio_nand_write_buf; - nand_chip->read_buf = tmio_nand_read_buf; + nand_chip->legacy.cmd_ctrl = tmio_nand_hwcontrol; + nand_chip->legacy.dev_ready = tmio_nand_dev_ready; + nand_chip->legacy.read_byte = tmio_nand_read_byte; + nand_chip->legacy.write_buf = tmio_nand_write_buf; + nand_chip->legacy.read_buf = tmio_nand_read_buf; /* set eccmode using hardware ECC */ nand_chip->ecc.mode = NAND_ECC_HW; @@ -423,7 +423,7 @@ static int tmio_probe(struct platform_device *dev) nand_chip->badblock_pattern = data->badblock_pattern; /* 15 us command delay time */ - nand_chip->chip_delay = 15; + nand_chip->legacy.chip_delay = 15; retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0, dev_name(&dev->dev), tmio); @@ -433,10 +433,10 @@ static int tmio_probe(struct platform_device *dev) } tmio->irq = irq; - nand_chip->waitfunc = tmio_nand_wait; + nand_chip->legacy.waitfunc = tmio_nand_wait; /* Scan to find existence of the device */ - retval = nand_scan(mtd, 1); + retval = nand_scan(nand_chip, 1); if (retval) goto err_irq; @@ -449,7 +449,7 @@ static int tmio_probe(struct platform_device *dev) if (!retval) return retval; - nand_release(mtd); + nand_release(nand_chip); err_irq: tmio_hw_stop(dev, tmio); @@ -460,7 +460,7 @@ static int tmio_remove(struct platform_device *dev) { struct tmio_nand *tmio = platform_get_drvdata(dev); - nand_release(nand_to_mtd(&tmio->chip)); + nand_release(&tmio->chip); tmio_hw_stop(dev, tmio); return 0; } diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c index 4d61a14fcb65..ddf0420c0997 100644 --- a/drivers/mtd/nand/raw/txx9ndfmc.c +++ b/drivers/mtd/nand/raw/txx9ndfmc.c @@ -102,17 +102,17 @@ static void txx9ndfmc_write(struct platform_device *dev, __raw_writel(val, ndregaddr(dev, reg)); } -static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd) +static uint8_t txx9ndfmc_read_byte(struct nand_chip *chip) { - struct platform_device *dev = mtd_to_platdev(mtd); + struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip)); return txx9ndfmc_read(dev, TXX9_NDFDTR); } -static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, +static void txx9ndfmc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) { - struct platform_device *dev = mtd_to_platdev(mtd); + struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip)); void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR); u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR); @@ -122,19 +122,18 @@ static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, txx9ndfmc_write(dev, mcr, TXX9_NDFMCR); } -static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void txx9ndfmc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) { - struct platform_device *dev = mtd_to_platdev(mtd); + struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip)); void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR); while (len--) *buf++ = __raw_readl(ndfdtr); } -static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd, +static void txx9ndfmc_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { - struct nand_chip *chip = mtd_to_nand(mtd); struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip); struct platform_device *dev = txx9_priv->dev; struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev); @@ -163,18 +162,17 @@ static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd, mmiowb(); } -static int txx9ndfmc_dev_ready(struct mtd_info *mtd) +static int txx9ndfmc_dev_ready(struct nand_chip *chip) { - struct platform_device *dev = mtd_to_platdev(mtd); + struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip)); return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY); } -static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, +static int txx9ndfmc_calculate_ecc(struct nand_chip *chip, const uint8_t *dat, uint8_t *ecc_code) { - struct platform_device *dev = mtd_to_platdev(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); + struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip)); int eccbytes; u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR); @@ -191,16 +189,17 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, return 0; } -static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf, - unsigned char *read_ecc, unsigned char *calc_ecc) +static int txx9ndfmc_correct_data(struct nand_chip *chip, unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) { - struct nand_chip *chip = mtd_to_nand(mtd); int eccsize; int corrected = 0; int stat; for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) { - stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256); + stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256, + false); if (stat < 0) return stat; corrected += stat; @@ -211,9 +210,9 @@ static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf, return corrected; } -static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) +static void txx9ndfmc_enable_hwecc(struct nand_chip *chip, int mode) { - struct platform_device *dev = mtd_to_platdev(mtd); + struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip)); u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR); mcr &= ~TXX9_NDFMCR_ECC_ALL; @@ -326,17 +325,17 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) mtd = nand_to_mtd(chip); mtd->dev.parent = &dev->dev; - chip->read_byte = txx9ndfmc_read_byte; - chip->read_buf = txx9ndfmc_read_buf; - chip->write_buf = txx9ndfmc_write_buf; - chip->cmd_ctrl = txx9ndfmc_cmd_ctrl; - chip->dev_ready = txx9ndfmc_dev_ready; + chip->legacy.read_byte = txx9ndfmc_read_byte; + chip->legacy.read_buf = txx9ndfmc_read_buf; + chip->legacy.write_buf = txx9ndfmc_write_buf; + chip->legacy.cmd_ctrl = txx9ndfmc_cmd_ctrl; + chip->legacy.dev_ready = txx9ndfmc_dev_ready; chip->ecc.calculate = txx9ndfmc_calculate_ecc; chip->ecc.correct = txx9ndfmc_correct_data; chip->ecc.hwctl = txx9ndfmc_enable_hwecc; chip->ecc.mode = NAND_ECC_HW; chip->ecc.strength = 1; - chip->chip_delay = 100; + chip->legacy.chip_delay = 100; chip->controller = &drvdata->controller; nand_set_controller_data(chip, txx9_priv); @@ -359,7 +358,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) if (plat->wide_mask & (1 << i)) chip->options |= NAND_BUSWIDTH_16; - if (nand_scan(mtd, 1)) { + if (nand_scan(chip, 1)) { kfree(txx9_priv->mtdname); kfree(txx9_priv); continue; @@ -390,7 +389,7 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev) chip = mtd_to_nand(mtd); txx9_priv = nand_get_controller_data(chip); - nand_release(mtd); + nand_release(chip); kfree(txx9_priv->mtdname); kfree(txx9_priv); } diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 6f6dcbf9095b..9814fd4a84cf 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -498,9 +498,9 @@ static int vf610_nfc_exec_op(struct nand_chip *chip, /* * This function supports Vybrid only (MPC5125 would have full RB and four CS) */ -static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip) +static void vf610_nfc_select_chip(struct nand_chip *chip, int cs) { - struct vf610_nfc *nfc = mtd_to_nfc(mtd); + struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip)); u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR); /* Vybrid only (MPC5125 would have full RB and four CS) */ @@ -509,9 +509,9 @@ static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip) tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK); - if (chip >= 0) { + if (cs >= 0) { tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; - tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT; + tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT; } vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp); @@ -557,9 +557,10 @@ static void vf610_nfc_fill_row(struct nand_chip *chip, int page, u32 *code, } } -static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct vf610_nfc *nfc = mtd_to_nfc(mtd); int trfr_sz = mtd->writesize + mtd->oobsize; u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; @@ -602,9 +603,10 @@ static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, } } -static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct vf610_nfc *nfc = mtd_to_nfc(mtd); int trfr_sz = mtd->writesize + mtd->oobsize; u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; @@ -643,24 +645,24 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static int vf610_nfc_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, +static int vf610_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct vf610_nfc *nfc = mtd_to_nfc(mtd); int ret; nfc->data_access = true; - ret = nand_read_page_raw(mtd, chip, buf, oob_required, page); + ret = nand_read_page_raw(chip, buf, oob_required, page); nfc->data_access = false; return ret; } -static int vf610_nfc_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, +static int vf610_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct vf610_nfc *nfc = mtd_to_nfc(mtd); int ret; @@ -677,22 +679,21 @@ static int vf610_nfc_write_page_raw(struct mtd_info *mtd, return nand_prog_page_end_op(chip); } -static int vf610_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int vf610_nfc_read_oob(struct nand_chip *chip, int page) { - struct vf610_nfc *nfc = mtd_to_nfc(mtd); + struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip)); int ret; nfc->data_access = true; - ret = nand_read_oob_std(mtd, chip, page); + ret = nand_read_oob_std(chip, page); nfc->data_access = false; return ret; } -static int vf610_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int vf610_nfc_write_oob(struct nand_chip *chip, int page) { + struct mtd_info *mtd = nand_to_mtd(chip); struct vf610_nfc *nfc = mtd_to_nfc(mtd); int ret; @@ -892,7 +893,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) /* Scan the NAND chip */ chip->dummy_controller.ops = &vf610_nfc_controller_ops; - err = nand_scan(mtd, 1); + err = nand_scan(chip, 1); if (err) goto err_disable_clk; @@ -916,7 +917,7 @@ static int vf610_nfc_remove(struct platform_device *pdev) struct mtd_info *mtd = platform_get_drvdata(pdev); struct vf610_nfc *nfc = mtd_to_nfc(mtd); - nand_release(mtd); + nand_release(mtd_to_nand(mtd)); clk_disable_unprepare(nfc->clk); return 0; } diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index 9926b4e3d69d..a234a5cb4868 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -85,9 +85,8 @@ static void xway_writeb(struct mtd_info *mtd, int op, u8 value) writeb(value, data->nandaddr + op); } -static void xway_select_chip(struct mtd_info *mtd, int select) +static void xway_select_chip(struct nand_chip *chip, int select) { - struct nand_chip *chip = mtd_to_nand(mtd); struct xway_nand_data *data = nand_get_controller_data(chip); switch (select) { @@ -106,8 +105,10 @@ static void xway_select_chip(struct mtd_info *mtd, int select) } } -static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +static void xway_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl) { + struct mtd_info *mtd = nand_to_mtd(chip); + if (cmd == NAND_CMD_NONE) return; @@ -120,30 +121,30 @@ static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) ; } -static int xway_dev_ready(struct mtd_info *mtd) +static int xway_dev_ready(struct nand_chip *chip) { return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD; } -static unsigned char xway_read_byte(struct mtd_info *mtd) +static unsigned char xway_read_byte(struct nand_chip *chip) { - return xway_readb(mtd, NAND_READ_DATA); + return xway_readb(nand_to_mtd(chip), NAND_READ_DATA); } -static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len) +static void xway_read_buf(struct nand_chip *chip, u_char *buf, int len) { int i; for (i = 0; i < len; i++) - buf[i] = xway_readb(mtd, NAND_WRITE_DATA); + buf[i] = xway_readb(nand_to_mtd(chip), NAND_WRITE_DATA); } -static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +static void xway_write_buf(struct nand_chip *chip, const u_char *buf, int len) { int i; for (i = 0; i < len; i++) - xway_writeb(mtd, NAND_WRITE_DATA, buf[i]); + xway_writeb(nand_to_mtd(chip), NAND_WRITE_DATA, buf[i]); } /* @@ -173,13 +174,13 @@ static int xway_nand_probe(struct platform_device *pdev) mtd = nand_to_mtd(&data->chip); mtd->dev.parent = &pdev->dev; - data->chip.cmd_ctrl = xway_cmd_ctrl; - data->chip.dev_ready = xway_dev_ready; + data->chip.legacy.cmd_ctrl = xway_cmd_ctrl; + data->chip.legacy.dev_ready = xway_dev_ready; data->chip.select_chip = xway_select_chip; - data->chip.write_buf = xway_write_buf; - data->chip.read_buf = xway_read_buf; - data->chip.read_byte = xway_read_byte; - data->chip.chip_delay = 30; + data->chip.legacy.write_buf = xway_write_buf; + data->chip.legacy.read_buf = xway_read_buf; + data->chip.legacy.read_byte = xway_read_byte; + data->chip.legacy.chip_delay = 30; data->chip.ecc.mode = NAND_ECC_SOFT; data->chip.ecc.algo = NAND_ECC_HAMMING; @@ -205,13 +206,13 @@ static int xway_nand_probe(struct platform_device *pdev) | cs_flag, EBU_NAND_CON); /* Scan to find existence of the device */ - err = nand_scan(mtd, 1); + err = nand_scan(&data->chip, 1); if (err) return err; err = mtd_device_register(mtd, NULL, 0); if (err) - nand_release(mtd); + nand_release(&data->chip); return err; } @@ -223,7 +224,7 @@ static int xway_nand_remove(struct platform_device *pdev) { struct xway_nand_data *data = platform_get_drvdata(pdev); - nand_release(nand_to_mtd(&data->chip)); + nand_release(&data->chip); return 0; } diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index f3bd86e13603..89227b1d036a 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -221,14 +221,18 @@ static int sm_correct_sector(uint8_t *buffer, struct sm_oob *oob) { uint8_t ecc[3]; - __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc); - if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE) < 0) + __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0) return -EIO; buffer += SM_SMALL_PAGE; - __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc); - if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE) < 0) + __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0) return -EIO; return 0; } @@ -393,11 +397,13 @@ restart: } if (ftl->smallpagenand) { - __nand_calculate_ecc(buf + boffset, - SM_SMALL_PAGE, oob.ecc1); + __nand_calculate_ecc(buf + boffset, SM_SMALL_PAGE, + oob.ecc1, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); __nand_calculate_ecc(buf + boffset + SM_SMALL_PAGE, - SM_SMALL_PAGE, oob.ecc2); + SM_SMALL_PAGE, oob.ecc2, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); } if (!sm_write_sector(ftl, zone, block, boffset, buf + boffset, &oob)) diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 8e714fbfa521..e24db817154e 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -959,7 +959,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf, return 0; } - dma_dst = dma_map_single(nor->dev, buf, len, DMA_DEV_TO_MEM); + dma_dst = dma_map_single(nor->dev, buf, len, DMA_FROM_DEVICE); if (dma_mapping_error(nor->dev, dma_dst)) { dev_err(nor->dev, "dma mapping failed\n"); return -ENOMEM; @@ -994,7 +994,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf, } err_unmap: - dma_unmap_single(nor->dev, dma_dst, len, DMA_DEV_TO_MEM); + dma_unmap_single(nor->dev, dma_dst, len, DMA_FROM_DEVICE); return 0; } diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 7d9620c7ff6c..1ff3430f82c8 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ_1_1_4_4B: return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; @@ -543,6 +544,9 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) /* trigger the LUT now */ seqid = fsl_qspi_get_seqid(q, cmd); + if (seqid < 0) + return seqid; + qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR); @@ -671,7 +675,7 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q) * causes the controller to clear the buffer, and use the sequence pointed * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash. */ -static void fsl_qspi_init_ahb_read(struct fsl_qspi *q) +static int fsl_qspi_init_ahb_read(struct fsl_qspi *q) { void __iomem *base = q->iobase; int seqid; @@ -696,8 +700,13 @@ static void fsl_qspi_init_ahb_read(struct fsl_qspi *q) /* Set the default lut sequence for AHB Read. */ seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode); + if (seqid < 0) + return seqid; + qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT, q->iobase + QUADSPI_BFGENCR); + + return 0; } /* This function was used to prepare and enable QSPI clock */ @@ -805,9 +814,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) fsl_qspi_init_lut(q); /* Init for AHB read */ - fsl_qspi_init_ahb_read(q); - - return 0; + return fsl_qspi_init_ahb_read(q); } static const struct of_device_id fsl_qspi_dt_ids[] = { diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c index c0976f2e3dd1..872b40922608 100644 --- a/drivers/mtd/spi-nor/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/intel-spi-pci.c @@ -65,6 +65,7 @@ static void intel_spi_pci_remove(struct pci_dev *pdev) static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, { }, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index f028277fb1ce..9407ca5f9443 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -18,6 +18,7 @@ #include <linux/math64.h> #include <linux/sizes.h> #include <linux/slab.h> +#include <linux/sort.h> #include <linux/mtd/mtd.h> #include <linux/of_platform.h> @@ -260,6 +261,18 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); + + if (!spi_nor_has_uniform_erase(nor)) { + struct spi_nor_erase_map *map = &nor->erase_map; + struct spi_nor_erase_type *erase; + int i; + + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { + erase = &map->erase_type[i]; + erase->opcode = + spi_nor_convert_3to4_erase(erase->opcode); + } + } } /* Enable/disable 4-byte addressing mode. */ @@ -497,6 +510,277 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); } +/** + * spi_nor_div_by_erase_size() - calculate remainder and update new dividend + * @erase: pointer to a structure that describes a SPI NOR erase type + * @dividend: dividend value + * @remainder: pointer to u32 remainder (will be updated) + * + * Return: the result of the division + */ +static u64 spi_nor_div_by_erase_size(const struct spi_nor_erase_type *erase, + u64 dividend, u32 *remainder) +{ + /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */ + *remainder = (u32)dividend & erase->size_mask; + return dividend >> erase->size_shift; +} + +/** + * spi_nor_find_best_erase_type() - find the best erase type for the given + * offset in the serial flash memory and the + * number of bytes to erase. The region in + * which the address fits is expected to be + * provided. + * @map: the erase map of the SPI NOR + * @region: pointer to a structure that describes a SPI NOR erase region + * @addr: offset in the serial flash memory + * @len: number of bytes to erase + * + * Return: a pointer to the best fitted erase type, NULL otherwise. + */ +static const struct spi_nor_erase_type * +spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, + const struct spi_nor_erase_region *region, + u64 addr, u32 len) +{ + const struct spi_nor_erase_type *erase; + u32 rem; + int i; + u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK; + + /* + * Erase types are ordered by size, with the biggest erase type at + * index 0. + */ + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + /* Does the erase region support the tested erase type? */ + if (!(erase_mask & BIT(i))) + continue; + + erase = &map->erase_type[i]; + + /* Don't erase more than what the user has asked for. */ + if (erase->size > len) + continue; + + /* Alignment is not mandatory for overlaid regions */ + if (region->offset & SNOR_OVERLAID_REGION) + return erase; + + spi_nor_div_by_erase_size(erase, addr, &rem); + if (rem) + continue; + else + return erase; + } + + return NULL; +} + +/** + * spi_nor_region_next() - get the next spi nor region + * @region: pointer to a structure that describes a SPI NOR erase region + * + * Return: the next spi nor region or NULL if last region. + */ +static struct spi_nor_erase_region * +spi_nor_region_next(struct spi_nor_erase_region *region) +{ + if (spi_nor_region_is_last(region)) + return NULL; + region++; + return region; +} + +/** + * spi_nor_find_erase_region() - find the region of the serial flash memory in + * which the offset fits + * @map: the erase map of the SPI NOR + * @addr: offset in the serial flash memory + * + * Return: a pointer to the spi_nor_erase_region struct, ERR_PTR(-errno) + * otherwise. + */ +static struct spi_nor_erase_region * +spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr) +{ + struct spi_nor_erase_region *region = map->regions; + u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK; + u64 region_end = region_start + region->size; + + while (addr < region_start || addr >= region_end) { + region = spi_nor_region_next(region); + if (!region) + return ERR_PTR(-EINVAL); + + region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK; + region_end = region_start + region->size; + } + + return region; +} + +/** + * spi_nor_init_erase_cmd() - initialize an erase command + * @region: pointer to a structure that describes a SPI NOR erase region + * @erase: pointer to a structure that describes a SPI NOR erase type + * + * Return: the pointer to the allocated erase command, ERR_PTR(-errno) + * otherwise. + */ +static struct spi_nor_erase_command * +spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region, + const struct spi_nor_erase_type *erase) +{ + struct spi_nor_erase_command *cmd; + + cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&cmd->list); + cmd->opcode = erase->opcode; + cmd->count = 1; + + if (region->offset & SNOR_OVERLAID_REGION) + cmd->size = region->size; + else + cmd->size = erase->size; + + return cmd; +} + +/** + * spi_nor_destroy_erase_cmd_list() - destroy erase command list + * @erase_list: list of erase commands + */ +static void spi_nor_destroy_erase_cmd_list(struct list_head *erase_list) +{ + struct spi_nor_erase_command *cmd, *next; + + list_for_each_entry_safe(cmd, next, erase_list, list) { + list_del(&cmd->list); + kfree(cmd); + } +} + +/** + * spi_nor_init_erase_cmd_list() - initialize erase command list + * @nor: pointer to a 'struct spi_nor' + * @erase_list: list of erase commands to be executed once we validate that the + * erase can be performed + * @addr: offset in the serial flash memory + * @len: number of bytes to erase + * + * Builds the list of best fitted erase commands and verifies if the erase can + * be performed. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_init_erase_cmd_list(struct spi_nor *nor, + struct list_head *erase_list, + u64 addr, u32 len) +{ + const struct spi_nor_erase_map *map = &nor->erase_map; + const struct spi_nor_erase_type *erase, *prev_erase = NULL; + struct spi_nor_erase_region *region; + struct spi_nor_erase_command *cmd = NULL; + u64 region_end; + int ret = -EINVAL; + + region = spi_nor_find_erase_region(map, addr); + if (IS_ERR(region)) + return PTR_ERR(region); + + region_end = spi_nor_region_end(region); + + while (len) { + erase = spi_nor_find_best_erase_type(map, region, addr, len); + if (!erase) + goto destroy_erase_cmd_list; + + if (prev_erase != erase || + region->offset & SNOR_OVERLAID_REGION) { + cmd = spi_nor_init_erase_cmd(region, erase); + if (IS_ERR(cmd)) { + ret = PTR_ERR(cmd); + goto destroy_erase_cmd_list; + } + + list_add_tail(&cmd->list, erase_list); + } else { + cmd->count++; + } + + addr += cmd->size; + len -= cmd->size; + + if (len && addr >= region_end) { + region = spi_nor_region_next(region); + if (!region) + goto destroy_erase_cmd_list; + region_end = spi_nor_region_end(region); + } + + prev_erase = erase; + } + + return 0; + +destroy_erase_cmd_list: + spi_nor_destroy_erase_cmd_list(erase_list); + return ret; +} + +/** + * spi_nor_erase_multi_sectors() - perform a non-uniform erase + * @nor: pointer to a 'struct spi_nor' + * @addr: offset in the serial flash memory + * @len: number of bytes to erase + * + * Build a list of best fitted erase commands and execute it once we validate + * that the erase can be performed. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len) +{ + LIST_HEAD(erase_list); + struct spi_nor_erase_command *cmd, *next; + int ret; + + ret = spi_nor_init_erase_cmd_list(nor, &erase_list, addr, len); + if (ret) + return ret; + + list_for_each_entry_safe(cmd, next, &erase_list, list) { + nor->erase_opcode = cmd->opcode; + while (cmd->count) { + write_enable(nor); + + ret = spi_nor_erase_sector(nor, addr); + if (ret) + goto destroy_erase_cmd_list; + + addr += cmd->size; + cmd->count--; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto destroy_erase_cmd_list; + } + list_del(&cmd->list); + kfree(cmd); + } + + return 0; + +destroy_erase_cmd_list: + spi_nor_destroy_erase_cmd_list(&erase_list); + return ret; +} + /* * Erase an address range on the nor chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. @@ -511,9 +795,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, (long long)instr->len); - div_u64_rem(instr->len, mtd->erasesize, &rem); - if (rem) - return -EINVAL; + if (spi_nor_has_uniform_erase(nor)) { + div_u64_rem(instr->len, mtd->erasesize, &rem); + if (rem) + return -EINVAL; + } addr = instr->addr; len = instr->len; @@ -552,7 +838,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) */ /* "sector"-at-a-time erase */ - } else { + } else if (spi_nor_has_uniform_erase(nor)) { while (len) { write_enable(nor); @@ -567,6 +853,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) if (ret) goto erase_err; } + + /* erase multiple sectors */ + } else { + ret = spi_nor_erase_multi_sectors(nor, addr, len); + if (ret) + goto erase_err; } write_disable(nor); @@ -1464,13 +1756,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, goto write_err; *retlen += written; i += written; - if (written != page_remain) { - dev_err(nor->dev, - "While writing %zu bytes written %zd bytes\n", - page_remain, written); - ret = -EIO; - goto write_err; - } } write_err: @@ -1864,6 +2149,36 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, */ /** + * spi_nor_read_raw() - raw read of serial flash memory. read_opcode, + * addr_width and read_dummy members of the struct spi_nor + * should be previously + * set. + * @nor: pointer to a 'struct spi_nor' + * @addr: offset in the serial flash memory + * @len: number of bytes to read + * @buf: buffer where the data is copied into + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf) +{ + int ret; + + while (len) { + ret = nor->read(nor, addr, len, buf); + if (!ret || ret > len) + return -EIO; + if (ret < 0) + return ret; + + buf += ret; + addr += ret; + len -= ret; + } + return 0; +} + +/** * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' * @addr: offset in the SFDP area to start reading data from @@ -1890,22 +2205,8 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, nor->addr_width = 3; nor->read_dummy = 8; - while (len) { - ret = nor->read(nor, addr, len, (u8 *)buf); - if (!ret || ret > len) { - ret = -EIO; - goto read_err; - } - if (ret < 0) - goto read_err; - - buf += ret; - addr += ret; - len -= ret; - } - ret = 0; + ret = spi_nor_read_raw(nor, addr, len, buf); -read_err: nor->read_opcode = read_opcode; nor->addr_width = addr_width; nor->read_dummy = read_dummy; @@ -2166,6 +2467,116 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = { static int spi_nor_hwcaps_read2cmd(u32 hwcaps); /** + * spi_nor_set_erase_type() - set a SPI NOR erase type + * @erase: pointer to a structure that describes a SPI NOR erase type + * @size: the size of the sector/block erased by the erase type + * @opcode: the SPI command op code to erase the sector/block + */ +static void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, + u32 size, u8 opcode) +{ + erase->size = size; + erase->opcode = opcode; + /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */ + erase->size_shift = ffs(erase->size) - 1; + erase->size_mask = (1 << erase->size_shift) - 1; +} + +/** + * spi_nor_set_erase_settings_from_bfpt() - set erase type settings from BFPT + * @erase: pointer to a structure that describes a SPI NOR erase type + * @size: the size of the sector/block erased by the erase type + * @opcode: the SPI command op code to erase the sector/block + * @i: erase type index as sorted in the Basic Flash Parameter Table + * + * The supported Erase Types will be sorted at init in ascending order, with + * the smallest Erase Type size being the first member in the erase_type array + * of the spi_nor_erase_map structure. Save the Erase Type index as sorted in + * the Basic Flash Parameter Table since it will be used later on to + * synchronize with the supported Erase Types defined in SFDP optional tables. + */ +static void +spi_nor_set_erase_settings_from_bfpt(struct spi_nor_erase_type *erase, + u32 size, u8 opcode, u8 i) +{ + erase->idx = i; + spi_nor_set_erase_type(erase, size, opcode); +} + +/** + * spi_nor_map_cmp_erase_type() - compare the map's erase types by size + * @l: member in the left half of the map's erase_type array + * @r: member in the right half of the map's erase_type array + * + * Comparison function used in the sort() call to sort in ascending order the + * map's erase types, the smallest erase type size being the first member in the + * sorted erase_type array. + * + * Return: the result of @l->size - @r->size + */ +static int spi_nor_map_cmp_erase_type(const void *l, const void *r) +{ + const struct spi_nor_erase_type *left = l, *right = r; + + return left->size - right->size; +} + +/** + * spi_nor_regions_sort_erase_types() - sort erase types in each region + * @map: the erase map of the SPI NOR + * + * Function assumes that the erase types defined in the erase map are already + * sorted in ascending order, with the smallest erase type size being the first + * member in the erase_type array. It replicates the sort done for the map's + * erase types. Each region's erase bitmask will indicate which erase types are + * supported from the sorted erase types defined in the erase map. + * Sort the all region's erase type at init in order to speed up the process of + * finding the best erase command at runtime. + */ +static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map) +{ + struct spi_nor_erase_region *region = map->regions; + struct spi_nor_erase_type *erase_type = map->erase_type; + int i; + u8 region_erase_mask, sorted_erase_mask; + + while (region) { + region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK; + + /* Replicate the sort done for the map's erase types. */ + sorted_erase_mask = 0; + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) + if (erase_type[i].size && + region_erase_mask & BIT(erase_type[i].idx)) + sorted_erase_mask |= BIT(i); + + /* Overwrite erase mask. */ + region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) | + sorted_erase_mask; + + region = spi_nor_region_next(region); + } +} + +/** + * spi_nor_init_uniform_erase_map() - Initialize uniform erase map + * @map: the erase map of the SPI NOR + * @erase_mask: bitmask encoding erase types that can erase the entire + * flash memory + * @flash_size: the spi nor flash memory size + */ +static void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map, + u8 erase_mask, u64 flash_size) +{ + /* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */ + map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) | + SNOR_LAST_REGION; + map->uniform_region.size = flash_size; + map->regions = &map->uniform_region; + map->uniform_erase_type = erase_mask; +} + +/** * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table. * @nor: pointer to a 'struct spi_nor' * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing @@ -2199,12 +2610,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, struct spi_nor_flash_parameter *params) { - struct mtd_info *mtd = &nor->mtd; + struct spi_nor_erase_map *map = &nor->erase_map; + struct spi_nor_erase_type *erase_type = map->erase_type; struct sfdp_bfpt bfpt; size_t len; int i, cmd, err; u32 addr; u16 half; + u8 erase_mask; /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */ if (bfpt_header->length < BFPT_DWORD_MAX_JESD216) @@ -2273,7 +2686,12 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, spi_nor_set_read_settings_from_bfpt(read, half, rd->proto); } - /* Sector Erase settings. */ + /* + * Sector Erase settings. Reinitialize the uniform erase map using the + * Erase Types defined in the bfpt table. + */ + erase_mask = 0; + memset(&nor->erase_map, 0, sizeof(nor->erase_map)); for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) { const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i]; u32 erasesize; @@ -2288,18 +2706,25 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, erasesize = 1U << erasesize; opcode = (half >> 8) & 0xff; -#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS - if (erasesize == SZ_4K) { - nor->erase_opcode = opcode; - mtd->erasesize = erasesize; - break; - } -#endif - if (!mtd->erasesize || mtd->erasesize < erasesize) { - nor->erase_opcode = opcode; - mtd->erasesize = erasesize; - } + erase_mask |= BIT(i); + spi_nor_set_erase_settings_from_bfpt(&erase_type[i], erasesize, + opcode, i); } + spi_nor_init_uniform_erase_map(map, erase_mask, params->size); + /* + * Sort all the map's Erase Types in ascending order with the smallest + * erase size being the first member in the erase_type array. + */ + sort(erase_type, SNOR_ERASE_TYPE_MAX, sizeof(erase_type[0]), + spi_nor_map_cmp_erase_type, NULL); + /* + * Sort the erase types in the uniform region in order to update the + * uniform_erase_type bitmask. The bitmask will be used later on when + * selecting the uniform erase. + */ + spi_nor_regions_sort_erase_types(map); + map->uniform_erase_type = map->uniform_region.offset & + SNOR_ERASE_TYPE_MASK; /* Stop here if not JESD216 rev A or later. */ if (bfpt_header->length < BFPT_DWORD_MAX) @@ -2341,6 +2766,277 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, return 0; } +#define SMPT_CMD_ADDRESS_LEN_MASK GENMASK(23, 22) +#define SMPT_CMD_ADDRESS_LEN_0 (0x0UL << 22) +#define SMPT_CMD_ADDRESS_LEN_3 (0x1UL << 22) +#define SMPT_CMD_ADDRESS_LEN_4 (0x2UL << 22) +#define SMPT_CMD_ADDRESS_LEN_USE_CURRENT (0x3UL << 22) + +#define SMPT_CMD_READ_DUMMY_MASK GENMASK(19, 16) +#define SMPT_CMD_READ_DUMMY_SHIFT 16 +#define SMPT_CMD_READ_DUMMY(_cmd) \ + (((_cmd) & SMPT_CMD_READ_DUMMY_MASK) >> SMPT_CMD_READ_DUMMY_SHIFT) +#define SMPT_CMD_READ_DUMMY_IS_VARIABLE 0xfUL + +#define SMPT_CMD_READ_DATA_MASK GENMASK(31, 24) +#define SMPT_CMD_READ_DATA_SHIFT 24 +#define SMPT_CMD_READ_DATA(_cmd) \ + (((_cmd) & SMPT_CMD_READ_DATA_MASK) >> SMPT_CMD_READ_DATA_SHIFT) + +#define SMPT_CMD_OPCODE_MASK GENMASK(15, 8) +#define SMPT_CMD_OPCODE_SHIFT 8 +#define SMPT_CMD_OPCODE(_cmd) \ + (((_cmd) & SMPT_CMD_OPCODE_MASK) >> SMPT_CMD_OPCODE_SHIFT) + +#define SMPT_MAP_REGION_COUNT_MASK GENMASK(23, 16) +#define SMPT_MAP_REGION_COUNT_SHIFT 16 +#define SMPT_MAP_REGION_COUNT(_header) \ + ((((_header) & SMPT_MAP_REGION_COUNT_MASK) >> \ + SMPT_MAP_REGION_COUNT_SHIFT) + 1) + +#define SMPT_MAP_ID_MASK GENMASK(15, 8) +#define SMPT_MAP_ID_SHIFT 8 +#define SMPT_MAP_ID(_header) \ + (((_header) & SMPT_MAP_ID_MASK) >> SMPT_MAP_ID_SHIFT) + +#define SMPT_MAP_REGION_SIZE_MASK GENMASK(31, 8) +#define SMPT_MAP_REGION_SIZE_SHIFT 8 +#define SMPT_MAP_REGION_SIZE(_region) \ + (((((_region) & SMPT_MAP_REGION_SIZE_MASK) >> \ + SMPT_MAP_REGION_SIZE_SHIFT) + 1) * 256) + +#define SMPT_MAP_REGION_ERASE_TYPE_MASK GENMASK(3, 0) +#define SMPT_MAP_REGION_ERASE_TYPE(_region) \ + ((_region) & SMPT_MAP_REGION_ERASE_TYPE_MASK) + +#define SMPT_DESC_TYPE_MAP BIT(1) +#define SMPT_DESC_END BIT(0) + +/** + * spi_nor_smpt_addr_width() - return the address width used in the + * configuration detection command. + * @nor: pointer to a 'struct spi_nor' + * @settings: configuration detection command descriptor, dword1 + */ +static u8 spi_nor_smpt_addr_width(const struct spi_nor *nor, const u32 settings) +{ + switch (settings & SMPT_CMD_ADDRESS_LEN_MASK) { + case SMPT_CMD_ADDRESS_LEN_0: + return 0; + case SMPT_CMD_ADDRESS_LEN_3: + return 3; + case SMPT_CMD_ADDRESS_LEN_4: + return 4; + case SMPT_CMD_ADDRESS_LEN_USE_CURRENT: + /* fall through */ + default: + return nor->addr_width; + } +} + +/** + * spi_nor_smpt_read_dummy() - return the configuration detection command read + * latency, in clock cycles. + * @nor: pointer to a 'struct spi_nor' + * @settings: configuration detection command descriptor, dword1 + * + * Return: the number of dummy cycles for an SMPT read + */ +static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) +{ + u8 read_dummy = SMPT_CMD_READ_DUMMY(settings); + + if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) + return nor->read_dummy; + return read_dummy; +} + +/** + * spi_nor_get_map_in_use() - get the configuration map in use + * @nor: pointer to a 'struct spi_nor' + * @smpt: pointer to the sector map parameter table + */ +static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt) +{ + const u32 *ret = NULL; + u32 i, addr; + int err; + u8 addr_width, read_opcode, read_dummy; + u8 read_data_mask, data_byte, map_id; + + addr_width = nor->addr_width; + read_dummy = nor->read_dummy; + read_opcode = nor->read_opcode; + + map_id = 0; + i = 0; + /* Determine if there are any optional Detection Command Descriptors */ + while (!(smpt[i] & SMPT_DESC_TYPE_MAP)) { + read_data_mask = SMPT_CMD_READ_DATA(smpt[i]); + nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]); + nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]); + nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]); + addr = smpt[i + 1]; + + err = spi_nor_read_raw(nor, addr, 1, &data_byte); + if (err) + goto out; + + /* + * Build an index value that is used to select the Sector Map + * Configuration that is currently in use. + */ + map_id = map_id << 1 | !!(data_byte & read_data_mask); + i = i + 2; + } + + /* Find the matching configuration map */ + while (SMPT_MAP_ID(smpt[i]) != map_id) { + if (smpt[i] & SMPT_DESC_END) + goto out; + /* increment the table index to the next map */ + i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1; + } + + ret = smpt + i; + /* fall through */ +out: + nor->addr_width = addr_width; + nor->read_dummy = read_dummy; + nor->read_opcode = read_opcode; + return ret; +} + +/** + * spi_nor_region_check_overlay() - set overlay bit when the region is overlaid + * @region: pointer to a structure that describes a SPI NOR erase region + * @erase: pointer to a structure that describes a SPI NOR erase type + * @erase_type: erase type bitmask + */ +static void +spi_nor_region_check_overlay(struct spi_nor_erase_region *region, + const struct spi_nor_erase_type *erase, + const u8 erase_type) +{ + int i; + + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { + if (!(erase_type & BIT(i))) + continue; + if (region->size & erase[i].size_mask) { + spi_nor_region_mark_overlay(region); + return; + } + } +} + +/** + * spi_nor_init_non_uniform_erase_map() - initialize the non-uniform erase map + * @nor: pointer to a 'struct spi_nor' + * @smpt: pointer to the sector map parameter table + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, + const u32 *smpt) +{ + struct spi_nor_erase_map *map = &nor->erase_map; + const struct spi_nor_erase_type *erase = map->erase_type; + struct spi_nor_erase_region *region; + u64 offset; + u32 region_count; + int i, j; + u8 erase_type; + + region_count = SMPT_MAP_REGION_COUNT(*smpt); + /* + * The regions will be freed when the driver detaches from the + * device. + */ + region = devm_kcalloc(nor->dev, region_count, sizeof(*region), + GFP_KERNEL); + if (!region) + return -ENOMEM; + map->regions = region; + + map->uniform_erase_type = 0xff; + offset = 0; + /* Populate regions. */ + for (i = 0; i < region_count; i++) { + j = i + 1; /* index for the region dword */ + region[i].size = SMPT_MAP_REGION_SIZE(smpt[j]); + erase_type = SMPT_MAP_REGION_ERASE_TYPE(smpt[j]); + region[i].offset = offset | erase_type; + + spi_nor_region_check_overlay(®ion[i], erase, erase_type); + + /* + * Save the erase types that are supported in all regions and + * can erase the entire flash memory. + */ + map->uniform_erase_type &= erase_type; + + offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) + + region[i].size; + } + + spi_nor_region_mark_end(®ion[i - 1]); + + return 0; +} + +/** + * spi_nor_parse_smpt() - parse Sector Map Parameter Table + * @nor: pointer to a 'struct spi_nor' + * @smpt_header: sector map parameter table header + * + * This table is optional, but when available, we parse it to identify the + * location and size of sectors within the main data array of the flash memory + * device and to identify which Erase Types are supported by each sector. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_smpt(struct spi_nor *nor, + const struct sfdp_parameter_header *smpt_header) +{ + const u32 *sector_map; + u32 *smpt; + size_t len; + u32 addr; + int i, ret; + + /* Read the Sector Map Parameter Table. */ + len = smpt_header->length * sizeof(*smpt); + smpt = kzalloc(len, GFP_KERNEL); + if (!smpt) + return -ENOMEM; + + addr = SFDP_PARAM_HEADER_PTP(smpt_header); + ret = spi_nor_read_sfdp(nor, addr, len, smpt); + if (ret) + goto out; + + /* Fix endianness of the SMPT DWORDs. */ + for (i = 0; i < smpt_header->length; i++) + smpt[i] = le32_to_cpu(smpt[i]); + + sector_map = spi_nor_get_map_in_use(nor, smpt); + if (!sector_map) { + ret = -EINVAL; + goto out; + } + + ret = spi_nor_init_non_uniform_erase_map(nor, sector_map); + if (ret) + goto out; + + spi_nor_regions_sort_erase_types(&nor->erase_map); + /* fall through */ +out: + kfree(smpt); + return ret; +} + /** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' @@ -2435,7 +3131,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, switch (SFDP_PARAM_HEADER_ID(param_header)) { case SFDP_SECTOR_MAP_ID: - dev_info(dev, "non-uniform erase sector maps are not supported yet.\n"); + err = spi_nor_parse_smpt(nor, param_header); break; default: @@ -2455,6 +3151,9 @@ static int spi_nor_init_params(struct spi_nor *nor, const struct flash_info *info, struct spi_nor_flash_parameter *params) { + struct spi_nor_erase_map *map = &nor->erase_map; + u8 i, erase_mask; + /* Set legacy flash parameters as default. */ memset(params, 0, sizeof(*params)); @@ -2494,6 +3193,28 @@ static int spi_nor_init_params(struct spi_nor *nor, spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], SPINOR_OP_PP, SNOR_PROTO_1_1_1); + /* + * Sector Erase settings. Sort Erase Types in ascending order, with the + * smallest erase size starting at BIT(0). + */ + erase_mask = 0; + i = 0; + if (info->flags & SECT_4K_PMC) { + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], 4096u, + SPINOR_OP_BE_4K_PMC); + i++; + } else if (info->flags & SECT_4K) { + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], 4096u, + SPINOR_OP_BE_4K); + i++; + } + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], info->sector_size, + SPINOR_OP_SE); + spi_nor_init_uniform_erase_map(map, erase_mask, params->size); + /* Select the procedure to set the Quad Enable bit. */ if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD | SNOR_HWCAPS_PP_QUAD)) { @@ -2521,20 +3242,20 @@ static int spi_nor_init_params(struct spi_nor *nor, params->quad_enable = info->quad_enable; } - /* Override the parameters with data read from SFDP tables. */ - nor->addr_width = 0; - nor->mtd.erasesize = 0; if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) && !(info->flags & SPI_NOR_SKIP_SFDP)) { struct spi_nor_flash_parameter sfdp_params; + struct spi_nor_erase_map prev_map; memcpy(&sfdp_params, params, sizeof(sfdp_params)); - if (spi_nor_parse_sfdp(nor, &sfdp_params)) { - nor->addr_width = 0; - nor->mtd.erasesize = 0; - } else { + memcpy(&prev_map, &nor->erase_map, sizeof(prev_map)); + + if (spi_nor_parse_sfdp(nor, &sfdp_params)) + /* restore previous erase map */ + memcpy(&nor->erase_map, &prev_map, + sizeof(nor->erase_map)); + else memcpy(params, &sfdp_params, sizeof(*params)); - } } return 0; @@ -2643,29 +3364,103 @@ static int spi_nor_select_pp(struct spi_nor *nor, return 0; } -static int spi_nor_select_erase(struct spi_nor *nor, - const struct flash_info *info) +/** + * spi_nor_select_uniform_erase() - select optimum uniform erase type + * @map: the erase map of the SPI NOR + * @wanted_size: the erase type size to search for. Contains the value of + * info->sector_size or of the "small sector" size in case + * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined. + * + * Once the optimum uniform sector erase command is found, disable all the + * other. + * + * Return: pointer to erase type on success, NULL otherwise. + */ +static const struct spi_nor_erase_type * +spi_nor_select_uniform_erase(struct spi_nor_erase_map *map, + const u32 wanted_size) { - struct mtd_info *mtd = &nor->mtd; + const struct spi_nor_erase_type *tested_erase, *erase = NULL; + int i; + u8 uniform_erase_type = map->uniform_erase_type; - /* Do nothing if already configured from SFDP. */ - if (mtd->erasesize) - return 0; + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + if (!(uniform_erase_type & BIT(i))) + continue; + + tested_erase = &map->erase_type[i]; + + /* + * If the current erase size is the one, stop here: + * we have found the right uniform Sector Erase command. + */ + if (tested_erase->size == wanted_size) { + erase = tested_erase; + break; + } + + /* + * Otherwise, the current erase size is still a valid canditate. + * Select the biggest valid candidate. + */ + if (!erase && tested_erase->size) + erase = tested_erase; + /* keep iterating to find the wanted_size */ + } + + if (!erase) + return NULL; + /* Disable all other Sector Erase commands. */ + map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK; + map->uniform_erase_type |= BIT(erase - map->erase_type); + return erase; +} + +static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size) +{ + struct spi_nor_erase_map *map = &nor->erase_map; + const struct spi_nor_erase_type *erase = NULL; + struct mtd_info *mtd = &nor->mtd; + int i; + + /* + * The previous implementation handling Sector Erase commands assumed + * that the SPI flash memory has an uniform layout then used only one + * of the supported erase sizes for all Sector Erase commands. + * So to be backward compatible, the new implementation also tries to + * manage the SPI flash memory as uniform with a single erase sector + * size, when possible. + */ #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS /* prefer "small sector" erase if possible */ - if (info->flags & SECT_4K) { - nor->erase_opcode = SPINOR_OP_BE_4K; - mtd->erasesize = 4096; - } else if (info->flags & SECT_4K_PMC) { - nor->erase_opcode = SPINOR_OP_BE_4K_PMC; - mtd->erasesize = 4096; - } else + wanted_size = 4096u; #endif - { - nor->erase_opcode = SPINOR_OP_SE; - mtd->erasesize = info->sector_size; + + if (spi_nor_has_uniform_erase(nor)) { + erase = spi_nor_select_uniform_erase(map, wanted_size); + if (!erase) + return -EINVAL; + nor->erase_opcode = erase->opcode; + mtd->erasesize = erase->size; + return 0; } + + /* + * For non-uniform SPI flash memory, set mtd->erasesize to the + * maximum erase sector size. No need to set nor->erase_opcode. + */ + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + if (map->erase_type[i].size) { + erase = &map->erase_type[i]; + break; + } + } + + if (!erase) + return -EINVAL; + + mtd->erasesize = erase->size; return 0; } @@ -2712,7 +3507,7 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, } /* Select the Sector Erase command. */ - err = spi_nor_select_erase(nor, info); + err = spi_nor_select_erase(nor, info->sector_size); if (err) { dev_err(nor->dev, "can't select erase settings supported by both the SPI controller and memory.\n"); diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index 88b6c81cebbe..c71523e94580 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c @@ -121,8 +121,10 @@ static int no_bit_error_verify(void *error_data, void *error_ecc, unsigned char calc_ecc[3]; int ret; - __nand_calculate_ecc(error_data, size, calc_ecc); - ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size); + __nand_calculate_ecc(error_data, size, calc_ecc, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); if (ret == 0 && !memcmp(correct_data, error_data, size)) return 0; @@ -149,8 +151,10 @@ static int single_bit_error_correct(void *error_data, void *error_ecc, unsigned char calc_ecc[3]; int ret; - __nand_calculate_ecc(error_data, size, calc_ecc); - ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size); + __nand_calculate_ecc(error_data, size, calc_ecc, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); if (ret == 1 && !memcmp(correct_data, error_data, size)) return 0; @@ -184,8 +188,10 @@ static int double_bit_error_detect(void *error_data, void *error_ecc, unsigned char calc_ecc[3]; int ret; - __nand_calculate_ecc(error_data, size, calc_ecc); - ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size); + __nand_calculate_ecc(error_data, size, calc_ecc, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); + ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); return (ret == -EBADMSG) ? 0 : -EINVAL; } @@ -259,7 +265,8 @@ static int nand_ecc_test_run(const size_t size) } prandom_bytes(correct_data, size); - __nand_calculate_ecc(correct_data, size, correct_ecc); + __nand_calculate_ecc(correct_data, size, correct_ecc, + IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)); for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) { nand_ecc_test[i].prepare(error_data, error_ecc, diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 6fdd9316db8b..02c1f2c014e8 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -17,20 +17,18 @@ struct mux_gpio { struct gpio_descs *gpios; - int *val; }; static int mux_gpio_set(struct mux_control *mux, int state) { struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip); - int i; + DECLARE_BITMAP(values, BITS_PER_TYPE(state)); - for (i = 0; i < mux_gpio->gpios->ndescs; i++) - mux_gpio->val[i] = (state >> i) & 1; + values[0] = state; gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, mux_gpio->gpios->desc, - mux_gpio->val); + mux_gpio->gpios->info, values); return 0; } @@ -58,13 +56,11 @@ static int mux_gpio_probe(struct platform_device *pdev) if (pins < 0) return pins; - mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) + - pins * sizeof(*mux_gpio->val)); + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio)); if (IS_ERR(mux_chip)) return PTR_ERR(mux_chip); mux_gpio = mux_chip_priv(mux_chip); - mux_gpio->val = (int *)(mux_gpio + 1); mux_chip->ops = &mux_gpio_ops; mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW); diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c index bc90764a8b8d..fe34576262bd 100644 --- a/drivers/net/phy/mdio-mux-gpio.c +++ b/drivers/net/phy/mdio-mux-gpio.c @@ -20,23 +20,21 @@ struct mdio_mux_gpio_state { struct gpio_descs *gpios; void *mux_handle; - int values[]; }; static int mdio_mux_gpio_switch_fn(int current_child, int desired_child, void *data) { struct mdio_mux_gpio_state *s = data; - unsigned int n; + DECLARE_BITMAP(values, BITS_PER_TYPE(desired_child)); if (current_child == desired_child) return 0; - for (n = 0; n < s->gpios->ndescs; n++) - s->values[n] = (desired_child >> n) & 1; + values[0] = desired_child; gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc, - s->values); + s->gpios->info, values); return 0; } @@ -51,8 +49,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpios)) return PTR_ERR(gpios); - s = devm_kzalloc(&pdev->dev, struct_size(s, values, gpios->ndescs), - GFP_KERNEL); + s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); if (!s) { gpiod_put_array(gpios); return -ENOMEM; diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c index 62e9cb167aad..db45c6bbb7bb 100644 --- a/drivers/nvdimm/blk.c +++ b/drivers/nvdimm/blk.c @@ -290,7 +290,7 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk) } set_capacity(disk, available_disk_size >> SECTOR_SHIFT); - device_add_disk(dev, disk); + device_add_disk(dev, disk, NULL); revalidate_disk(disk); return 0; } diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 0360c015f658..b123b0dcf274 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -1556,7 +1556,7 @@ static int btt_blk_init(struct btt *btt) } } set_capacity(btt->btt_disk, btt->nlba * btt->sector_size >> 9); - device_add_disk(&btt->nd_btt->dev, btt->btt_disk); + device_add_disk(&btt->nd_btt->dev, btt->btt_disk, NULL); btt->nd_btt->size = btt->nlba * (u64)btt->sector_size; revalidate_disk(btt->btt_disk); diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 6071e2942053..a75d10c23d80 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -474,7 +474,7 @@ static int pmem_attach_disk(struct device *dev, gendev = disk_to_dev(disk); gendev->groups = pmem_attribute_groups; - device_add_disk(dev, disk); + device_add_disk(dev, disk, NULL); if (devm_add_action_or_reset(dev, pmem_release_disk, pmem)) return -ENOMEM; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index dd8ec1dd9219..9e4a30b05bd2 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -971,7 +971,7 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid, uuid_copy(&ids->uuid, data + pos + sizeof(*cur)); break; default: - /* Skip unnkown types */ + /* Skip unknown types */ len = cur->nidl; break; } @@ -1132,7 +1132,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) return nvme_submit_user_cmd(ns->queue, &c, (void __user *)(uintptr_t)io.addr, length, - metadata, meta_len, io.slba, NULL, 0); + metadata, meta_len, lower_32_bits(io.slba), NULL, 0); } static u32 nvme_known_admin_effects(u8 opcode) @@ -2076,7 +2076,7 @@ static void nvme_init_subnqn(struct nvme_subsystem *subsys, struct nvme_ctrl *ct nqnlen = strnlen(id->subnqn, NVMF_NQN_SIZE); if (nqnlen > 0 && nqnlen < NVMF_NQN_SIZE) { - strncpy(subsys->subnqn, id->subnqn, NVMF_NQN_SIZE); + strlcpy(subsys->subnqn, id->subnqn, NVMF_NQN_SIZE); return; } @@ -2729,11 +2729,19 @@ static umode_t nvme_ns_id_attrs_are_visible(struct kobject *kobj, return a->mode; } -const struct attribute_group nvme_ns_id_attr_group = { +static const struct attribute_group nvme_ns_id_attr_group = { .attrs = nvme_ns_id_attrs, .is_visible = nvme_ns_id_attrs_are_visible, }; +const struct attribute_group *nvme_ns_id_attr_groups[] = { + &nvme_ns_id_attr_group, +#ifdef CONFIG_NVM + &nvme_nvm_attr_group, +#endif + NULL, +}; + #define nvme_show_str_function(field) \ static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -2900,9 +2908,14 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl, unsigned nsid, struct nvme_id_ns *id) { struct nvme_ns_head *head; + size_t size = sizeof(*head); int ret = -ENOMEM; - head = kzalloc(sizeof(*head), GFP_KERNEL); +#ifdef CONFIG_NVME_MULTIPATH + size += num_possible_nodes() * sizeof(struct nvme_ns *); +#endif + + head = kzalloc(size, GFP_KERNEL); if (!head) goto out; ret = ida_simple_get(&ctrl->subsys->ns_ida, 1, 0, GFP_KERNEL); @@ -3099,14 +3112,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) nvme_get_ctrl(ctrl); - device_add_disk(ctrl->device, ns->disk); - if (sysfs_create_group(&disk_to_dev(ns->disk)->kobj, - &nvme_ns_id_attr_group)) - pr_warn("%s: failed to create sysfs group for identification\n", - ns->disk->disk_name); - if (ns->ndev && nvme_nvm_register_sysfs(ns)) - pr_warn("%s: failed to register lightnvm sysfs group for identification\n", - ns->disk->disk_name); + device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups); nvme_mpath_add_disk(ns, id); nvme_fault_inject_init(ns); @@ -3132,10 +3138,6 @@ static void nvme_ns_remove(struct nvme_ns *ns) nvme_fault_inject_fini(ns); if (ns->disk && ns->disk->flags & GENHD_FL_UP) { - sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, - &nvme_ns_id_attr_group); - if (ns->ndev) - nvme_nvm_unregister_sysfs(ns); del_gendisk(ns->disk); blk_cleanup_queue(ns->queue); if (blk_get_integrity(ns->disk)) @@ -3143,8 +3145,8 @@ static void nvme_ns_remove(struct nvme_ns *ns) } mutex_lock(&ns->ctrl->subsys->lock); - nvme_mpath_clear_current_path(ns); list_del_rcu(&ns->siblings); + nvme_mpath_clear_current_path(ns); mutex_unlock(&ns->ctrl->subsys->lock); down_write(&ns->ctrl->namespaces_rwsem); @@ -3411,16 +3413,21 @@ static void nvme_fw_act_work(struct work_struct *work) static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result) { - switch ((result & 0xff00) >> 8) { + u32 aer_notice_type = (result & 0xff00) >> 8; + + switch (aer_notice_type) { case NVME_AER_NOTICE_NS_CHANGED: + trace_nvme_async_event(ctrl, aer_notice_type); set_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events); nvme_queue_scan(ctrl); break; case NVME_AER_NOTICE_FW_ACT_STARTING: + trace_nvme_async_event(ctrl, aer_notice_type); queue_work(nvme_wq, &ctrl->fw_act_work); break; #ifdef CONFIG_NVME_MULTIPATH case NVME_AER_NOTICE_ANA: + trace_nvme_async_event(ctrl, aer_notice_type); if (!ctrl->ana_log_buf) break; queue_work(nvme_wq, &ctrl->ana_work); @@ -3435,11 +3442,12 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, volatile union nvme_result *res) { u32 result = le32_to_cpu(res->u32); + u32 aer_type = result & 0x07; if (le16_to_cpu(status) >> 1 != NVME_SC_SUCCESS) return; - switch (result & 0x7) { + switch (aer_type) { case NVME_AER_NOTICE: nvme_handle_aen_notice(ctrl, result); break; @@ -3447,6 +3455,7 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, case NVME_AER_SMART: case NVME_AER_CSS: case NVME_AER_VS: + trace_nvme_async_event(ctrl, aer_type); ctrl->aen_result = result; break; default: diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 206d63cb1afc..bd0969db6225 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -552,8 +552,11 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl, ctrl->state != NVME_CTRL_DEAD && !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH)) return BLK_STS_RESOURCE; - nvme_req(rq)->status = NVME_SC_ABORT_REQ; - return BLK_STS_IOERR; + + nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR; + blk_mq_start_request(rq); + nvme_complete_rq(rq); + return BLK_STS_OK; } EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command); @@ -865,6 +868,36 @@ static int nvmf_check_required_opts(struct nvmf_ctrl_options *opts, return 0; } +bool nvmf_ip_options_match(struct nvme_ctrl *ctrl, + struct nvmf_ctrl_options *opts) +{ + if (!nvmf_ctlr_matches_baseopts(ctrl, opts) || + strcmp(opts->traddr, ctrl->opts->traddr) || + strcmp(opts->trsvcid, ctrl->opts->trsvcid)) + return false; + + /* + * Checking the local address is rough. In most cases, none is specified + * and the host port is selected by the stack. + * + * Assume no match if: + * - local address is specified and address is not the same + * - local address is not specified but remote is, or vice versa + * (admin using specific host_traddr when it matters). + */ + if ((opts->mask & NVMF_OPT_HOST_TRADDR) && + (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)) { + if (strcmp(opts->host_traddr, ctrl->opts->host_traddr)) + return false; + } else if ((opts->mask & NVMF_OPT_HOST_TRADDR) || + (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)) { + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(nvmf_ip_options_match); + static int nvmf_check_allowed_opts(struct nvmf_ctrl_options *opts, unsigned int allowed_opts) { diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index aa2fdb2a2e8f..6ea6275f332a 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -166,6 +166,8 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl, struct request *rq); bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq, bool queue_live); +bool nvmf_ip_options_match(struct nvme_ctrl *ctrl, + struct nvmf_ctrl_options *opts); static inline bool nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq, bool queue_live) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 611e70cae754..e52b9d3c0bd6 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -20,6 +20,7 @@ #include <uapi/scsi/fc/fc_fs.h> #include <uapi/scsi/fc/fc_els.h> #include <linux/delay.h> +#include <linux/overflow.h> #include "nvme.h" #include "fabrics.h" @@ -104,6 +105,12 @@ struct nvme_fc_fcp_op { struct nvme_fc_ersp_iu rsp_iu; }; +struct nvme_fcp_op_w_sgl { + struct nvme_fc_fcp_op op; + struct scatterlist sgl[SG_CHUNK_SIZE]; + uint8_t priv[0]; +}; + struct nvme_fc_lport { struct nvme_fc_local_port localport; @@ -122,6 +129,7 @@ struct nvme_fc_rport { struct list_head endp_list; /* for lport->endp_list */ struct list_head ctrl_list; struct list_head ls_req_list; + struct list_head disc_list; struct device *dev; /* physical device for dma */ struct nvme_fc_lport *lport; spinlock_t lock; @@ -210,7 +218,6 @@ static DEFINE_IDA(nvme_fc_ctrl_cnt); * These items are short-term. They will eventually be moved into * a generic FC class. See comments in module init. */ -static struct class *fc_class; static struct device *fc_udev_device; @@ -317,7 +324,7 @@ out_done: * @template: LLDD entrypoints and operational parameters for the port * @dev: physical hardware device node port corresponds to. Will be * used for DMA mappings - * @lport_p: pointer to a local port pointer. Upon success, the routine + * @portptr: pointer to a local port pointer. Upon success, the routine * will allocate a nvme_fc_local_port structure and place its * address in the local port pointer. Upon failure, local port * pointer will be set to 0. @@ -425,8 +432,7 @@ EXPORT_SYMBOL_GPL(nvme_fc_register_localport); * nvme_fc_unregister_localport - transport entry point called by an * LLDD to deregister/remove a previously * registered a NVME host FC port. - * @localport: pointer to the (registered) local port that is to be - * deregistered. + * @portptr: pointer to the (registered) local port that is to be deregistered. * * Returns: * a completion status. Must be 0 upon success; a negative errno @@ -507,6 +513,7 @@ nvme_fc_free_rport(struct kref *ref) list_del(&rport->endp_list); spin_unlock_irqrestore(&nvme_fc_lock, flags); + WARN_ON(!list_empty(&rport->disc_list)); ida_simple_remove(&lport->endp_cnt, rport->remoteport.port_num); kfree(rport); @@ -631,7 +638,7 @@ __nvme_fc_set_dev_loss_tmo(struct nvme_fc_rport *rport, * @localport: pointer to the (registered) local port that the remote * subsystem port is connected to. * @pinfo: pointer to information about the port to be registered - * @rport_p: pointer to a remote port pointer. Upon success, the routine + * @portptr: pointer to a remote port pointer. Upon success, the routine * will allocate a nvme_fc_remote_port structure and place its * address in the remote port pointer. Upon failure, remote port * pointer will be set to 0. @@ -694,6 +701,7 @@ nvme_fc_register_remoteport(struct nvme_fc_local_port *localport, INIT_LIST_HEAD(&newrec->endp_list); INIT_LIST_HEAD(&newrec->ctrl_list); INIT_LIST_HEAD(&newrec->ls_req_list); + INIT_LIST_HEAD(&newrec->disc_list); kref_init(&newrec->ref); atomic_set(&newrec->act_ctrl_cnt, 0); spin_lock_init(&newrec->lock); @@ -807,8 +815,8 @@ nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl) * nvme_fc_unregister_remoteport - transport entry point called by an * LLDD to deregister/remove a previously * registered a NVME subsystem FC port. - * @remoteport: pointer to the (registered) remote port that is to be - * deregistered. + * @portptr: pointer to the (registered) remote port that is to be + * deregistered. * * Returns: * a completion status. Must be 0 upon success; a negative errno @@ -1385,7 +1393,7 @@ nvme_fc_disconnect_assoc_done(struct nvmefc_ls_req *lsreq, int status) __nvme_fc_finish_ls_req(lsop); - /* fc-nvme iniator doesn't care about success or failure of cmd */ + /* fc-nvme initiator doesn't care about success or failure of cmd */ kfree(lsop); } @@ -1685,6 +1693,8 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, struct nvme_fc_fcp_op *op, struct request *rq, u32 rqno) { + struct nvme_fcp_op_w_sgl *op_w_sgl = + container_of(op, typeof(*op_w_sgl), op); struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu; int ret = 0; @@ -1694,7 +1704,6 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl, op->fcp_req.rspaddr = &op->rsp_iu; op->fcp_req.rsplen = sizeof(op->rsp_iu); op->fcp_req.done = nvme_fc_fcpio_done; - op->fcp_req.first_sgl = (struct scatterlist *)&op[1]; op->fcp_req.private = &op->fcp_req.first_sgl[SG_CHUNK_SIZE]; op->ctrl = ctrl; op->queue = queue; @@ -1733,12 +1742,17 @@ nvme_fc_init_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx, unsigned int numa_node) { struct nvme_fc_ctrl *ctrl = set->driver_data; - struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq); + struct nvme_fcp_op_w_sgl *op = blk_mq_rq_to_pdu(rq); int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0; struct nvme_fc_queue *queue = &ctrl->queues[queue_idx]; + int res; nvme_req(rq)->ctrl = &ctrl->ctrl; - return __nvme_fc_init_request(ctrl, queue, op, rq, queue->rqcnt++); + res = __nvme_fc_init_request(ctrl, queue, &op->op, rq, queue->rqcnt++); + if (res) + return res; + op->op.fcp_req.first_sgl = &op->sgl[0]; + return res; } static int @@ -1768,7 +1782,6 @@ nvme_fc_init_aen_ops(struct nvme_fc_ctrl *ctrl) } aen_op->flags = FCOP_FLAGS_AEN; - aen_op->fcp_req.first_sgl = NULL; /* no sg list */ aen_op->fcp_req.private = private; memset(sqe, 0, sizeof(*sqe)); @@ -2422,10 +2435,9 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl) ctrl->tag_set.reserved_tags = 1; /* fabric connect */ ctrl->tag_set.numa_node = NUMA_NO_NODE; ctrl->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; - ctrl->tag_set.cmd_size = sizeof(struct nvme_fc_fcp_op) + - (SG_CHUNK_SIZE * - sizeof(struct scatterlist)) + - ctrl->lport->ops->fcprqst_priv_sz; + ctrl->tag_set.cmd_size = + struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, + ctrl->lport->ops->fcprqst_priv_sz); ctrl->tag_set.driver_data = ctrl; ctrl->tag_set.nr_hw_queues = ctrl->ctrl.queue_count - 1; ctrl->tag_set.timeout = NVME_IO_TIMEOUT; @@ -3027,10 +3039,9 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, ctrl->admin_tag_set.queue_depth = NVME_AQ_MQ_TAG_DEPTH; ctrl->admin_tag_set.reserved_tags = 2; /* fabric connect + Keep-Alive */ ctrl->admin_tag_set.numa_node = NUMA_NO_NODE; - ctrl->admin_tag_set.cmd_size = sizeof(struct nvme_fc_fcp_op) + - (SG_CHUNK_SIZE * - sizeof(struct scatterlist)) + - ctrl->lport->ops->fcprqst_priv_sz; + ctrl->admin_tag_set.cmd_size = + struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv, + ctrl->lport->ops->fcprqst_priv_sz); ctrl->admin_tag_set.driver_data = ctrl; ctrl->admin_tag_set.nr_hw_queues = 1; ctrl->admin_tag_set.timeout = ADMIN_TIMEOUT; @@ -3159,7 +3170,7 @@ nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen) substring_t wwn = { name, &name[sizeof(name)-1] }; int nnoffset, pnoffset; - /* validate it string one of the 2 allowed formats */ + /* validate if string is one of the 2 allowed formats */ if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH && !strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) && !strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET], @@ -3254,6 +3265,90 @@ static struct nvmf_transport_ops nvme_fc_transport = { .create_ctrl = nvme_fc_create_ctrl, }; +/* Arbitrary successive failures max. With lots of subsystems could be high */ +#define DISCOVERY_MAX_FAIL 20 + +static ssize_t nvme_fc_nvme_discovery_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long flags; + LIST_HEAD(local_disc_list); + struct nvme_fc_lport *lport; + struct nvme_fc_rport *rport; + int failcnt = 0; + + spin_lock_irqsave(&nvme_fc_lock, flags); +restart: + list_for_each_entry(lport, &nvme_fc_lport_list, port_list) { + list_for_each_entry(rport, &lport->endp_list, endp_list) { + if (!nvme_fc_lport_get(lport)) + continue; + if (!nvme_fc_rport_get(rport)) { + /* + * This is a temporary condition. Upon restart + * this rport will be gone from the list. + * + * Revert the lport put and retry. Anything + * added to the list already will be skipped (as + * they are no longer list_empty). Loops should + * resume at rports that were not yet seen. + */ + nvme_fc_lport_put(lport); + + if (failcnt++ < DISCOVERY_MAX_FAIL) + goto restart; + + pr_err("nvme_discovery: too many reference " + "failures\n"); + goto process_local_list; + } + if (list_empty(&rport->disc_list)) + list_add_tail(&rport->disc_list, + &local_disc_list); + } + } + +process_local_list: + while (!list_empty(&local_disc_list)) { + rport = list_first_entry(&local_disc_list, + struct nvme_fc_rport, disc_list); + list_del_init(&rport->disc_list); + spin_unlock_irqrestore(&nvme_fc_lock, flags); + + lport = rport->lport; + /* signal discovery. Won't hurt if it repeats */ + nvme_fc_signal_discovery_scan(lport, rport); + nvme_fc_rport_put(rport); + nvme_fc_lport_put(lport); + + spin_lock_irqsave(&nvme_fc_lock, flags); + } + spin_unlock_irqrestore(&nvme_fc_lock, flags); + + return count; +} +static DEVICE_ATTR(nvme_discovery, 0200, NULL, nvme_fc_nvme_discovery_store); + +static struct attribute *nvme_fc_attrs[] = { + &dev_attr_nvme_discovery.attr, + NULL +}; + +static struct attribute_group nvme_fc_attr_group = { + .attrs = nvme_fc_attrs, +}; + +static const struct attribute_group *nvme_fc_attr_groups[] = { + &nvme_fc_attr_group, + NULL +}; + +static struct class fc_class = { + .name = "fc", + .dev_groups = nvme_fc_attr_groups, + .owner = THIS_MODULE, +}; + static int __init nvme_fc_init_module(void) { int ret; @@ -3272,16 +3367,16 @@ static int __init nvme_fc_init_module(void) * put in place, this code will move to a more generic * location for the class. */ - fc_class = class_create(THIS_MODULE, "fc"); - if (IS_ERR(fc_class)) { + ret = class_register(&fc_class); + if (ret) { pr_err("couldn't register class fc\n"); - return PTR_ERR(fc_class); + return ret; } /* * Create a device for the FC-centric udev events */ - fc_udev_device = device_create(fc_class, NULL, MKDEV(0, 0), NULL, + fc_udev_device = device_create(&fc_class, NULL, MKDEV(0, 0), NULL, "fc_udev_device"); if (IS_ERR(fc_udev_device)) { pr_err("couldn't create fc_udev device!\n"); @@ -3296,9 +3391,9 @@ static int __init nvme_fc_init_module(void) return 0; out_destroy_device: - device_destroy(fc_class, MKDEV(0, 0)); + device_destroy(&fc_class, MKDEV(0, 0)); out_destroy_class: - class_destroy(fc_class); + class_unregister(&fc_class); return ret; } @@ -3313,8 +3408,8 @@ static void __exit nvme_fc_exit_module(void) ida_destroy(&nvme_fc_local_port_cnt); ida_destroy(&nvme_fc_ctrl_cnt); - device_destroy(fc_class, MKDEV(0, 0)); - class_destroy(fc_class); + device_destroy(&fc_class, MKDEV(0, 0)); + class_unregister(&fc_class); } module_init(nvme_fc_init_module); diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 6fe5923c95d4..a4f3b263cd6c 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -567,13 +567,13 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas, * Expect the lba in device format */ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev, - struct nvm_chk_meta *meta, - sector_t slba, int nchks) + sector_t slba, int nchks, + struct nvm_chk_meta *meta) { struct nvm_geo *geo = &ndev->geo; struct nvme_ns *ns = ndev->q->queuedata; struct nvme_ctrl *ctrl = ns->ctrl; - struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta; + struct nvme_nvm_chk_meta *dev_meta, *dev_meta_off; struct ppa_addr ppa; size_t left = nchks * sizeof(struct nvme_nvm_chk_meta); size_t log_pos, offset, len; @@ -585,6 +585,10 @@ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev, */ max_len = min_t(unsigned int, ctrl->max_hw_sectors << 9, 256 * 1024); + dev_meta = kmalloc(max_len, GFP_KERNEL); + if (!dev_meta) + return -ENOMEM; + /* Normalize lba address space to obtain log offset */ ppa.ppa = slba; ppa = dev_to_generic_addr(ndev, ppa); @@ -598,6 +602,9 @@ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev, while (left) { len = min_t(unsigned int, left, max_len); + memset(dev_meta, 0, max_len); + dev_meta_off = dev_meta; + ret = nvme_get_log(ctrl, ns->head->ns_id, NVME_NVM_LOG_REPORT_CHUNK, 0, dev_meta, len, offset); @@ -607,21 +614,23 @@ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev, } for (i = 0; i < len; i += sizeof(struct nvme_nvm_chk_meta)) { - meta->state = dev_meta->state; - meta->type = dev_meta->type; - meta->wi = dev_meta->wi; - meta->slba = le64_to_cpu(dev_meta->slba); - meta->cnlb = le64_to_cpu(dev_meta->cnlb); - meta->wp = le64_to_cpu(dev_meta->wp); + meta->state = dev_meta_off->state; + meta->type = dev_meta_off->type; + meta->wi = dev_meta_off->wi; + meta->slba = le64_to_cpu(dev_meta_off->slba); + meta->cnlb = le64_to_cpu(dev_meta_off->cnlb); + meta->wp = le64_to_cpu(dev_meta_off->wp); meta++; - dev_meta++; + dev_meta_off++; } offset += len; left -= len; } + kfree(dev_meta); + return ret; } @@ -968,6 +977,9 @@ void nvme_nvm_update_nvm_info(struct nvme_ns *ns) struct nvm_dev *ndev = ns->ndev; struct nvm_geo *geo = &ndev->geo; + if (geo->version == NVM_OCSSD_SPEC_12) + return; + geo->csecs = 1 << ns->lba_shift; geo->sos = ns->ms; } @@ -1190,10 +1202,29 @@ static NVM_DEV_ATTR_12_RO(multiplane_modes); static NVM_DEV_ATTR_12_RO(media_capabilities); static NVM_DEV_ATTR_12_RO(max_phys_secs); -static struct attribute *nvm_dev_attrs_12[] = { +/* 2.0 values */ +static NVM_DEV_ATTR_20_RO(groups); +static NVM_DEV_ATTR_20_RO(punits); +static NVM_DEV_ATTR_20_RO(chunks); +static NVM_DEV_ATTR_20_RO(clba); +static NVM_DEV_ATTR_20_RO(ws_min); +static NVM_DEV_ATTR_20_RO(ws_opt); +static NVM_DEV_ATTR_20_RO(maxoc); +static NVM_DEV_ATTR_20_RO(maxocpu); +static NVM_DEV_ATTR_20_RO(mw_cunits); +static NVM_DEV_ATTR_20_RO(write_typ); +static NVM_DEV_ATTR_20_RO(write_max); +static NVM_DEV_ATTR_20_RO(reset_typ); +static NVM_DEV_ATTR_20_RO(reset_max); + +static struct attribute *nvm_dev_attrs[] = { + /* version agnostic attrs */ &dev_attr_version.attr, &dev_attr_capabilities.attr, + &dev_attr_read_typ.attr, + &dev_attr_read_max.attr, + /* 1.2 attrs */ &dev_attr_vendor_opcode.attr, &dev_attr_device_mode.attr, &dev_attr_media_manager.attr, @@ -1208,8 +1239,6 @@ static struct attribute *nvm_dev_attrs_12[] = { &dev_attr_page_size.attr, &dev_attr_hw_sector_size.attr, &dev_attr_oob_sector_size.attr, - &dev_attr_read_typ.attr, - &dev_attr_read_max.attr, &dev_attr_prog_typ.attr, &dev_attr_prog_max.attr, &dev_attr_erase_typ.attr, @@ -1218,33 +1247,7 @@ static struct attribute *nvm_dev_attrs_12[] = { &dev_attr_media_capabilities.attr, &dev_attr_max_phys_secs.attr, - NULL, -}; - -static const struct attribute_group nvm_dev_attr_group_12 = { - .name = "lightnvm", - .attrs = nvm_dev_attrs_12, -}; - -/* 2.0 values */ -static NVM_DEV_ATTR_20_RO(groups); -static NVM_DEV_ATTR_20_RO(punits); -static NVM_DEV_ATTR_20_RO(chunks); -static NVM_DEV_ATTR_20_RO(clba); -static NVM_DEV_ATTR_20_RO(ws_min); -static NVM_DEV_ATTR_20_RO(ws_opt); -static NVM_DEV_ATTR_20_RO(maxoc); -static NVM_DEV_ATTR_20_RO(maxocpu); -static NVM_DEV_ATTR_20_RO(mw_cunits); -static NVM_DEV_ATTR_20_RO(write_typ); -static NVM_DEV_ATTR_20_RO(write_max); -static NVM_DEV_ATTR_20_RO(reset_typ); -static NVM_DEV_ATTR_20_RO(reset_max); - -static struct attribute *nvm_dev_attrs_20[] = { - &dev_attr_version.attr, - &dev_attr_capabilities.attr, - + /* 2.0 attrs */ &dev_attr_groups.attr, &dev_attr_punits.attr, &dev_attr_chunks.attr, @@ -1255,8 +1258,6 @@ static struct attribute *nvm_dev_attrs_20[] = { &dev_attr_maxocpu.attr, &dev_attr_mw_cunits.attr, - &dev_attr_read_typ.attr, - &dev_attr_read_max.attr, &dev_attr_write_typ.attr, &dev_attr_write_max.attr, &dev_attr_reset_typ.attr, @@ -1265,44 +1266,38 @@ static struct attribute *nvm_dev_attrs_20[] = { NULL, }; -static const struct attribute_group nvm_dev_attr_group_20 = { - .name = "lightnvm", - .attrs = nvm_dev_attrs_20, -}; - -int nvme_nvm_register_sysfs(struct nvme_ns *ns) +static umode_t nvm_dev_attrs_visible(struct kobject *kobj, + struct attribute *attr, int index) { + struct device *dev = container_of(kobj, struct device, kobj); + struct gendisk *disk = dev_to_disk(dev); + struct nvme_ns *ns = disk->private_data; struct nvm_dev *ndev = ns->ndev; - struct nvm_geo *geo = &ndev->geo; + struct device_attribute *dev_attr = + container_of(attr, typeof(*dev_attr), attr); if (!ndev) - return -EINVAL; - - switch (geo->major_ver_id) { - case 1: - return sysfs_create_group(&disk_to_dev(ns->disk)->kobj, - &nvm_dev_attr_group_12); - case 2: - return sysfs_create_group(&disk_to_dev(ns->disk)->kobj, - &nvm_dev_attr_group_20); - } + return 0; - return -EINVAL; -} + if (dev_attr->show == nvm_dev_attr_show) + return attr->mode; -void nvme_nvm_unregister_sysfs(struct nvme_ns *ns) -{ - struct nvm_dev *ndev = ns->ndev; - struct nvm_geo *geo = &ndev->geo; - - switch (geo->major_ver_id) { + switch (ndev->geo.major_ver_id) { case 1: - sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, - &nvm_dev_attr_group_12); + if (dev_attr->show == nvm_dev_attr_show_12) + return attr->mode; break; case 2: - sysfs_remove_group(&disk_to_dev(ns->disk)->kobj, - &nvm_dev_attr_group_20); + if (dev_attr->show == nvm_dev_attr_show_20) + return attr->mode; break; } + + return 0; } + +const struct attribute_group nvme_nvm_attr_group = { + .name = "lightnvm", + .attrs = nvm_dev_attrs, + .is_visible = nvm_dev_attrs_visible, +}; diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 9fe3fff818b8..5e3cc8c59a39 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -77,6 +77,13 @@ void nvme_failover_req(struct request *req) queue_work(nvme_wq, &ns->ctrl->ana_work); } break; + case NVME_SC_HOST_PATH_ERROR: + /* + * Temporary transport disruption in talking to the controller. + * Try to send on a new path. + */ + nvme_mpath_clear_current_path(ns); + break; default: /* * Reset the controller for any non-ANA error as we don't know @@ -110,29 +117,55 @@ static const char *nvme_ana_state_names[] = { [NVME_ANA_CHANGE] = "change", }; -static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head) +void nvme_mpath_clear_current_path(struct nvme_ns *ns) +{ + struct nvme_ns_head *head = ns->head; + int node; + + if (!head) + return; + + for_each_node(node) { + if (ns == rcu_access_pointer(head->current_path[node])) + rcu_assign_pointer(head->current_path[node], NULL); + } +} + +static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node) { - struct nvme_ns *ns, *fallback = NULL; + int found_distance = INT_MAX, fallback_distance = INT_MAX, distance; + struct nvme_ns *found = NULL, *fallback = NULL, *ns; list_for_each_entry_rcu(ns, &head->list, siblings) { if (ns->ctrl->state != NVME_CTRL_LIVE || test_bit(NVME_NS_ANA_PENDING, &ns->flags)) continue; + + distance = node_distance(node, dev_to_node(ns->ctrl->dev)); + switch (ns->ana_state) { case NVME_ANA_OPTIMIZED: - rcu_assign_pointer(head->current_path, ns); - return ns; + if (distance < found_distance) { + found_distance = distance; + found = ns; + } + break; case NVME_ANA_NONOPTIMIZED: - fallback = ns; + if (distance < fallback_distance) { + fallback_distance = distance; + fallback = ns; + } break; default: break; } } - if (fallback) - rcu_assign_pointer(head->current_path, fallback); - return fallback; + if (!found) + found = fallback; + if (found) + rcu_assign_pointer(head->current_path[node], found); + return found; } static inline bool nvme_path_is_optimized(struct nvme_ns *ns) @@ -143,10 +176,12 @@ static inline bool nvme_path_is_optimized(struct nvme_ns *ns) inline struct nvme_ns *nvme_find_path(struct nvme_ns_head *head) { - struct nvme_ns *ns = srcu_dereference(head->current_path, &head->srcu); + int node = numa_node_id(); + struct nvme_ns *ns; + ns = srcu_dereference(head->current_path[node], &head->srcu); if (unlikely(!ns || !nvme_path_is_optimized(ns))) - ns = __nvme_find_path(head); + ns = __nvme_find_path(head, node); return ns; } @@ -193,7 +228,7 @@ static bool nvme_ns_head_poll(struct request_queue *q, blk_qc_t qc) int srcu_idx; srcu_idx = srcu_read_lock(&head->srcu); - ns = srcu_dereference(head->current_path, &head->srcu); + ns = srcu_dereference(head->current_path[numa_node_id()], &head->srcu); if (likely(ns && nvme_path_is_optimized(ns))) found = ns->queue->poll_fn(q, qc); srcu_read_unlock(&head->srcu, srcu_idx); @@ -282,12 +317,17 @@ static void nvme_mpath_set_live(struct nvme_ns *ns) if (!head->disk) return; - if (!(head->disk->flags & GENHD_FL_UP)) { - device_add_disk(&head->subsys->dev, head->disk); - if (sysfs_create_group(&disk_to_dev(head->disk)->kobj, - &nvme_ns_id_attr_group)) - dev_warn(&head->subsys->dev, - "failed to create id group.\n"); + if (!(head->disk->flags & GENHD_FL_UP)) + device_add_disk(&head->subsys->dev, head->disk, + nvme_ns_id_attr_groups); + + if (nvme_path_is_optimized(ns)) { + int node, srcu_idx; + + srcu_idx = srcu_read_lock(&head->srcu); + for_each_node(node) + __nvme_find_path(head, node); + srcu_read_unlock(&head->srcu, srcu_idx); } kblockd_schedule_work(&ns->head->requeue_work); @@ -494,11 +534,8 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head) { if (!head->disk) return; - if (head->disk->flags & GENHD_FL_UP) { - sysfs_remove_group(&disk_to_dev(head->disk)->kobj, - &nvme_ns_id_attr_group); + if (head->disk->flags & GENHD_FL_UP) del_gendisk(head->disk); - } blk_set_queue_dying(head->disk->queue); /* make sure all pending bios are cleaned up */ kblockd_schedule_work(&head->requeue_work); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index bb4a2003c097..9fefba039d1e 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -277,14 +277,6 @@ struct nvme_ns_ids { * only ever has a single entry for private namespaces. */ struct nvme_ns_head { -#ifdef CONFIG_NVME_MULTIPATH - struct gendisk *disk; - struct nvme_ns __rcu *current_path; - struct bio_list requeue_list; - spinlock_t requeue_lock; - struct work_struct requeue_work; - struct mutex lock; -#endif struct list_head list; struct srcu_struct srcu; struct nvme_subsystem *subsys; @@ -293,6 +285,14 @@ struct nvme_ns_head { struct list_head entry; struct kref ref; int instance; +#ifdef CONFIG_NVME_MULTIPATH + struct gendisk *disk; + struct bio_list requeue_list; + spinlock_t requeue_lock; + struct work_struct requeue_work; + struct mutex lock; + struct nvme_ns __rcu *current_path[]; +#endif }; #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS @@ -459,7 +459,7 @@ int nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl); int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, void *log, size_t size, u64 offset); -extern const struct attribute_group nvme_ns_id_attr_group; +extern const struct attribute_group *nvme_ns_id_attr_groups[]; extern const struct block_device_operations nvme_ns_head_ops; #ifdef CONFIG_NVME_MULTIPATH @@ -474,14 +474,7 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head); int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id); void nvme_mpath_uninit(struct nvme_ctrl *ctrl); void nvme_mpath_stop(struct nvme_ctrl *ctrl); - -static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) -{ - struct nvme_ns_head *head = ns->head; - - if (head && ns == rcu_access_pointer(head->current_path)) - rcu_assign_pointer(head->current_path, NULL); -} +void nvme_mpath_clear_current_path(struct nvme_ns *ns); struct nvme_ns *nvme_find_path(struct nvme_ns_head *head); static inline void nvme_mpath_check_last_path(struct nvme_ns *ns) @@ -551,8 +544,7 @@ static inline void nvme_mpath_stop(struct nvme_ctrl *ctrl) void nvme_nvm_update_nvm_info(struct nvme_ns *ns); int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node); void nvme_nvm_unregister(struct nvme_ns *ns); -int nvme_nvm_register_sysfs(struct nvme_ns *ns); -void nvme_nvm_unregister_sysfs(struct nvme_ns *ns); +extern const struct attribute_group nvme_nvm_attr_group; int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg); #else static inline void nvme_nvm_update_nvm_info(struct nvme_ns *ns) {}; @@ -563,11 +555,6 @@ static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, } static inline void nvme_nvm_unregister(struct nvme_ns *ns) {}; -static inline int nvme_nvm_register_sysfs(struct nvme_ns *ns) -{ - return 0; -} -static inline void nvme_nvm_unregister_sysfs(struct nvme_ns *ns) {}; static inline int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg) { diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index d668682f91df..4e023cd007e1 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -772,10 +772,10 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req, if (!dma_map_sg(dev->dev, &iod->meta_sg, 1, dma_dir)) goto out_unmap; - } - if (blk_integrity_rq(req)) cmnd->rw.metadata = cpu_to_le64(sg_dma_address(&iod->meta_sg)); + } + return BLK_STS_OK; out_unmap: @@ -1249,7 +1249,7 @@ static void nvme_free_queues(struct nvme_dev *dev, int lowest) /** * nvme_suspend_queue - put queue into suspended state - * @nvmeq - queue to suspend + * @nvmeq: queue to suspend */ static int nvme_suspend_queue(struct nvme_queue *nvmeq) { @@ -2564,13 +2564,12 @@ static void nvme_remove(struct pci_dev *pdev) struct nvme_dev *dev = pci_get_drvdata(pdev); nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING); - - cancel_work_sync(&dev->ctrl.reset_work); pci_set_drvdata(pdev, NULL); if (!pci_device_is_present(pdev)) { nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DEAD); nvme_dev_disable(dev, true); + nvme_dev_remove_admin(dev); } flush_work(&dev->ctrl.reset_work); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index dc042017c293..d181cafedc58 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -233,8 +233,15 @@ static void nvme_rdma_qp_event(struct ib_event *event, void *context) static int nvme_rdma_wait_for_cm(struct nvme_rdma_queue *queue) { - wait_for_completion_interruptible_timeout(&queue->cm_done, + int ret; + + ret = wait_for_completion_interruptible_timeout(&queue->cm_done, msecs_to_jiffies(NVME_RDMA_CONNECT_TIMEOUT_MS) + 1); + if (ret < 0) + return ret; + if (ret == 0) + return -ETIMEDOUT; + WARN_ON_ONCE(queue->cm_error > 0); return queue->cm_error; } @@ -1849,54 +1856,6 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = { .stop_ctrl = nvme_rdma_stop_ctrl, }; -static inline bool -__nvme_rdma_options_match(struct nvme_rdma_ctrl *ctrl, - struct nvmf_ctrl_options *opts) -{ - char *stdport = __stringify(NVME_RDMA_IP_PORT); - - - if (!nvmf_ctlr_matches_baseopts(&ctrl->ctrl, opts) || - strcmp(opts->traddr, ctrl->ctrl.opts->traddr)) - return false; - - if (opts->mask & NVMF_OPT_TRSVCID && - ctrl->ctrl.opts->mask & NVMF_OPT_TRSVCID) { - if (strcmp(opts->trsvcid, ctrl->ctrl.opts->trsvcid)) - return false; - } else if (opts->mask & NVMF_OPT_TRSVCID) { - if (strcmp(opts->trsvcid, stdport)) - return false; - } else if (ctrl->ctrl.opts->mask & NVMF_OPT_TRSVCID) { - if (strcmp(stdport, ctrl->ctrl.opts->trsvcid)) - return false; - } - /* else, it's a match as both have stdport. Fall to next checks */ - - /* - * checking the local address is rough. In most cases, one - * is not specified and the host port is selected by the stack. - * - * Assume no match if: - * local address is specified and address is not the same - * local address is not specified but remote is, or vice versa - * (admin using specific host_traddr when it matters). - */ - if (opts->mask & NVMF_OPT_HOST_TRADDR && - ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR) { - if (strcmp(opts->host_traddr, ctrl->ctrl.opts->host_traddr)) - return false; - } else if (opts->mask & NVMF_OPT_HOST_TRADDR || - ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR) - return false; - /* - * if neither controller had an host port specified, assume it's - * a match as everything else matched. - */ - - return true; -} - /* * Fails a connection request if it matches an existing controller * (association) with the same tuple: @@ -1917,7 +1876,7 @@ nvme_rdma_existing_controller(struct nvmf_ctrl_options *opts) mutex_lock(&nvme_rdma_ctrl_mutex); list_for_each_entry(ctrl, &nvme_rdma_ctrl_list, list) { - found = __nvme_rdma_options_match(ctrl, opts); + found = nvmf_ip_options_match(&ctrl->ctrl, opts); if (found) break; } @@ -1932,7 +1891,6 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev, struct nvme_rdma_ctrl *ctrl; int ret; bool changed; - char *port; ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) @@ -1940,15 +1898,21 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev, ctrl->ctrl.opts = opts; INIT_LIST_HEAD(&ctrl->list); - if (opts->mask & NVMF_OPT_TRSVCID) - port = opts->trsvcid; - else - port = __stringify(NVME_RDMA_IP_PORT); + if (!(opts->mask & NVMF_OPT_TRSVCID)) { + opts->trsvcid = + kstrdup(__stringify(NVME_RDMA_IP_PORT), GFP_KERNEL); + if (!opts->trsvcid) { + ret = -ENOMEM; + goto out_free_ctrl; + } + opts->mask |= NVMF_OPT_TRSVCID; + } ret = inet_pton_with_scope(&init_net, AF_UNSPEC, - opts->traddr, port, &ctrl->addr); + opts->traddr, opts->trsvcid, &ctrl->addr); if (ret) { - pr_err("malformed address passed: %s:%s\n", opts->traddr, port); + pr_err("malformed address passed: %s:%s\n", + opts->traddr, opts->trsvcid); goto out_free_ctrl; } diff --git a/drivers/nvme/host/trace.h b/drivers/nvme/host/trace.h index a490790d6691..196d5bd56718 100644 --- a/drivers/nvme/host/trace.h +++ b/drivers/nvme/host/trace.h @@ -156,6 +156,34 @@ TRACE_EVENT(nvme_complete_rq, ); +#define aer_name(aer) { aer, #aer } + +TRACE_EVENT(nvme_async_event, + TP_PROTO(struct nvme_ctrl *ctrl, u32 result), + TP_ARGS(ctrl, result), + TP_STRUCT__entry( + __field(int, ctrl_id) + __field(u32, result) + ), + TP_fast_assign( + __entry->ctrl_id = ctrl->instance; + __entry->result = result; + ), + TP_printk("nvme%d: NVME_AEN=%#08x [%s]", + __entry->ctrl_id, __entry->result, + __print_symbolic(__entry->result, + aer_name(NVME_AER_NOTICE_NS_CHANGED), + aer_name(NVME_AER_NOTICE_ANA), + aer_name(NVME_AER_NOTICE_FW_ACT_STARTING), + aer_name(NVME_AER_ERROR), + aer_name(NVME_AER_SMART), + aer_name(NVME_AER_CSS), + aer_name(NVME_AER_VS)) + ) +); + +#undef aer_name + #endif /* _TRACE_NVME_H */ #undef TRACE_INCLUDE_PATH diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 2008fa62a373..1179f6314323 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -58,7 +58,7 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req, ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->get_log_page.nsid); if (!ns) { - pr_err("nvmet : Could not find namespace id : %d\n", + pr_err("Could not find namespace id : %d\n", le32_to_cpu(req->cmd->get_log_page.nsid)); return NVME_SC_INVALID_NS; } @@ -353,7 +353,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) if (req->port->inline_data_size) id->sgls |= cpu_to_le32(1 << 20); - strcpy(id->subnqn, ctrl->subsys->subsysnqn); + strlcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn)); /* Max command capsule size is sqe + single page of in-capsule data */ id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) + diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index b5ec96abd048..0acdff9e6842 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -1105,8 +1105,7 @@ static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port, if (!port) return NULL; - if (!strncmp(NVME_DISC_SUBSYS_NAME, subsysnqn, - NVMF_NQN_SIZE)) { + if (!strcmp(NVME_DISC_SUBSYS_NAME, subsysnqn)) { if (!kref_get_unless_zero(&nvmet_disc_subsys->ref)) return NULL; return nvmet_disc_subsys; diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c index eae29f493a07..bc0aa0bf1543 100644 --- a/drivers/nvme/target/discovery.c +++ b/drivers/nvme/target/discovery.c @@ -174,7 +174,7 @@ static void nvmet_execute_identify_disc_ctrl(struct nvmet_req *req) if (req->port->inline_data_size) id->sgls |= cpu_to_le32(1 << 20); - strcpy(id->subnqn, ctrl->subsys->subsysnqn); + strlcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn)); status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id)); @@ -219,12 +219,10 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req) return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; } default: - pr_err("unsupported cmd %d\n", cmd->common.opcode); + pr_err("unhandled cmd %d\n", cmd->common.opcode); return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; } - pr_err("unhandled cmd %d\n", cmd->common.opcode); - return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; } int __init nvmet_init_discovery(void) diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 29b4b236afd8..409081a03b24 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -110,11 +110,19 @@ struct nvmet_fc_tgtport { struct list_head ls_busylist; struct list_head assoc_list; struct ida assoc_cnt; - struct nvmet_port *port; + struct nvmet_fc_port_entry *pe; struct kref ref; u32 max_sg_cnt; }; +struct nvmet_fc_port_entry { + struct nvmet_fc_tgtport *tgtport; + struct nvmet_port *port; + u64 node_name; + u64 port_name; + struct list_head pe_list; +}; + struct nvmet_fc_defer_fcp_req { struct list_head req_list; struct nvmefc_tgt_fcp_req *fcp_req; @@ -132,7 +140,6 @@ struct nvmet_fc_tgt_queue { atomic_t zrspcnt; atomic_t rsn; spinlock_t qlock; - struct nvmet_port *port; struct nvmet_cq nvme_cq; struct nvmet_sq nvme_sq; struct nvmet_fc_tgt_assoc *assoc; @@ -221,6 +228,7 @@ static DEFINE_SPINLOCK(nvmet_fc_tgtlock); static LIST_HEAD(nvmet_fc_target_list); static DEFINE_IDA(nvmet_fc_tgtport_cnt); +static LIST_HEAD(nvmet_fc_portentry_list); static void nvmet_fc_handle_ls_rqst_work(struct work_struct *work); @@ -645,7 +653,6 @@ nvmet_fc_alloc_target_queue(struct nvmet_fc_tgt_assoc *assoc, queue->qid = qid; queue->sqsize = sqsize; queue->assoc = assoc; - queue->port = assoc->tgtport->port; queue->cpu = nvmet_fc_queue_to_cpu(assoc->tgtport, qid); INIT_LIST_HEAD(&queue->fod_list); INIT_LIST_HEAD(&queue->avail_defer_list); @@ -957,6 +964,83 @@ nvmet_fc_find_target_assoc(struct nvmet_fc_tgtport *tgtport, return ret; } +static void +nvmet_fc_portentry_bind(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_port_entry *pe, + struct nvmet_port *port) +{ + lockdep_assert_held(&nvmet_fc_tgtlock); + + pe->tgtport = tgtport; + tgtport->pe = pe; + + pe->port = port; + port->priv = pe; + + pe->node_name = tgtport->fc_target_port.node_name; + pe->port_name = tgtport->fc_target_port.port_name; + INIT_LIST_HEAD(&pe->pe_list); + + list_add_tail(&pe->pe_list, &nvmet_fc_portentry_list); +} + +static void +nvmet_fc_portentry_unbind(struct nvmet_fc_port_entry *pe) +{ + unsigned long flags; + + spin_lock_irqsave(&nvmet_fc_tgtlock, flags); + if (pe->tgtport) + pe->tgtport->pe = NULL; + list_del(&pe->pe_list); + spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); +} + +/* + * called when a targetport deregisters. Breaks the relationship + * with the nvmet port, but leaves the port_entry in place so that + * re-registration can resume operation. + */ +static void +nvmet_fc_portentry_unbind_tgt(struct nvmet_fc_tgtport *tgtport) +{ + struct nvmet_fc_port_entry *pe; + unsigned long flags; + + spin_lock_irqsave(&nvmet_fc_tgtlock, flags); + pe = tgtport->pe; + if (pe) + pe->tgtport = NULL; + tgtport->pe = NULL; + spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); +} + +/* + * called when a new targetport is registered. Looks in the + * existing nvmet port_entries to see if the nvmet layer is + * configured for the targetport's wwn's. (the targetport existed, + * nvmet configured, the lldd unregistered the tgtport, and is now + * reregistering the same targetport). If so, set the nvmet port + * port entry on the targetport. + */ +static void +nvmet_fc_portentry_rebind_tgt(struct nvmet_fc_tgtport *tgtport) +{ + struct nvmet_fc_port_entry *pe; + unsigned long flags; + + spin_lock_irqsave(&nvmet_fc_tgtlock, flags); + list_for_each_entry(pe, &nvmet_fc_portentry_list, pe_list) { + if (tgtport->fc_target_port.node_name == pe->node_name && + tgtport->fc_target_port.port_name == pe->port_name) { + WARN_ON(pe->tgtport); + tgtport->pe = pe; + pe->tgtport = tgtport; + break; + } + } + spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); +} /** * nvme_fc_register_targetport - transport entry point called by an @@ -1034,6 +1118,8 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo, goto out_free_newrec; } + nvmet_fc_portentry_rebind_tgt(newrec); + spin_lock_irqsave(&nvmet_fc_tgtlock, flags); list_add_tail(&newrec->tgt_list, &nvmet_fc_target_list); spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); @@ -1159,8 +1245,8 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl) * nvme_fc_unregister_targetport - transport entry point called by an * LLDD to deregister/remove a previously * registered a local NVME subsystem FC port. - * @tgtport: pointer to the (registered) target port that is to be - * deregistered. + * @target_port: pointer to the (registered) target port that is to be + * deregistered. * * Returns: * a completion status. Must be 0 upon success; a negative errno @@ -1171,6 +1257,8 @@ nvmet_fc_unregister_targetport(struct nvmet_fc_target_port *target_port) { struct nvmet_fc_tgtport *tgtport = targetport_to_tgtport(target_port); + nvmet_fc_portentry_unbind_tgt(tgtport); + /* terminate any outstanding associations */ __nvmet_fc_free_assocs(tgtport); @@ -1661,7 +1749,7 @@ nvmet_fc_handle_ls_rqst_work(struct work_struct *work) * * If this routine returns error, the LLDD should abort the exchange. * - * @tgtport: pointer to the (registered) target port the LS was + * @target_port: pointer to the (registered) target port the LS was * received on. * @lsreq: pointer to a lsreq request structure to be used to reference * the exchange corresponding to the LS. @@ -2147,7 +2235,7 @@ nvmet_fc_fcp_nvme_cmd_done(struct nvmet_req *nvme_req) /* - * Actual processing routine for received FC-NVME LS Requests from the LLD + * Actual processing routine for received FC-NVME I/O Requests from the LLD */ static void nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport, @@ -2158,6 +2246,13 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport, int ret; /* + * if there is no nvmet mapping to the targetport there + * shouldn't be requests. just terminate them. + */ + if (!tgtport->pe) + goto transport_error; + + /* * Fused commands are currently not supported in the linux * implementation. * @@ -2184,7 +2279,7 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport, fod->req.cmd = &fod->cmdiubuf.sqe; fod->req.rsp = &fod->rspiubuf.cqe; - fod->req.port = fod->queue->port; + fod->req.port = tgtport->pe->port; /* clear any response payload */ memset(&fod->rspiubuf, 0, sizeof(fod->rspiubuf)); @@ -2468,7 +2563,7 @@ nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen) substring_t wwn = { name, &name[sizeof(name)-1] }; int nnoffset, pnoffset; - /* validate it string one of the 2 allowed formats */ + /* validate if string is one of the 2 allowed formats */ if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH && !strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) && !strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET], @@ -2508,6 +2603,7 @@ static int nvmet_fc_add_port(struct nvmet_port *port) { struct nvmet_fc_tgtport *tgtport; + struct nvmet_fc_port_entry *pe; struct nvmet_fc_traddr traddr = { 0L, 0L }; unsigned long flags; int ret; @@ -2524,24 +2620,40 @@ nvmet_fc_add_port(struct nvmet_port *port) if (ret) return ret; + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return -ENOMEM; + ret = -ENXIO; spin_lock_irqsave(&nvmet_fc_tgtlock, flags); list_for_each_entry(tgtport, &nvmet_fc_target_list, tgt_list) { if ((tgtport->fc_target_port.node_name == traddr.nn) && (tgtport->fc_target_port.port_name == traddr.pn)) { - tgtport->port = port; - ret = 0; + /* a FC port can only be 1 nvmet port id */ + if (!tgtport->pe) { + nvmet_fc_portentry_bind(tgtport, pe, port); + ret = 0; + } else + ret = -EALREADY; break; } } spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags); + + if (ret) + kfree(pe); + return ret; } static void nvmet_fc_remove_port(struct nvmet_port *port) { - /* nothing to do */ + struct nvmet_fc_port_entry *pe = port->priv; + + nvmet_fc_portentry_unbind(pe); + + kfree(pe); } static const struct nvmet_fabrics_ops nvmet_fc_tgt_fcp_ops = { diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index 5251689a1d9a..291f4121f516 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -648,6 +648,7 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport, break; /* Fall-Thru to RSP handling */ + /* FALLTHRU */ case NVMET_FCOP_RSP: if (fcpreq) { diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c index 7bc9f6240432..f93fb5711142 100644 --- a/drivers/nvme/target/io-cmd-bdev.c +++ b/drivers/nvme/target/io-cmd-bdev.c @@ -58,7 +58,7 @@ static void nvmet_bio_done(struct bio *bio) static void nvmet_bdev_execute_rw(struct nvmet_req *req) { int sg_cnt = req->sg_cnt; - struct bio *bio = &req->b.inline_bio; + struct bio *bio; struct scatterlist *sg; sector_t sector; blk_qc_t cookie; @@ -81,7 +81,12 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) sector = le64_to_cpu(req->cmd->rw.slba); sector <<= (req->ns->blksize_shift - 9); - bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec)); + if (req->data_len <= NVMET_MAX_INLINE_DATA_LEN) { + bio = &req->b.inline_bio; + bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec)); + } else { + bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES)); + } bio_set_dev(bio, req->ns->bdev); bio->bi_iter.bi_sector = sector; bio->bi_private = req; diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c index 81a9dc5290a8..39d972e2595f 100644 --- a/drivers/nvme/target/io-cmd-file.c +++ b/drivers/nvme/target/io-cmd-file.c @@ -246,7 +246,8 @@ static void nvmet_file_execute_discard(struct nvmet_req *req) break; offset = le64_to_cpu(range.slba) << req->ns->blksize_shift; - len = le32_to_cpu(range.nlb) << req->ns->blksize_shift; + len = le32_to_cpu(range.nlb); + len <<= req->ns->blksize_shift; if (offset + len > req->ns->size) { ret = NVME_SC_LBA_RANGE | NVME_SC_DNR; break; diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index ec9af4ee03b6..08f7b57a1203 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -264,6 +264,7 @@ struct nvmet_fabrics_ops { }; #define NVMET_MAX_INLINE_BIOVEC 8 +#define NVMET_MAX_INLINE_DATA_LEN NVMET_MAX_INLINE_BIOVEC * PAGE_SIZE struct nvmet_req { struct nvme_command *cmd; diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index bfc4da660bb4..bd265aceb90c 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -122,6 +122,7 @@ struct nvmet_rdma_device { int inline_page_count; }; +static struct workqueue_struct *nvmet_rdma_delete_wq; static bool nvmet_rdma_use_srq; module_param_named(use_srq, nvmet_rdma_use_srq, bool, 0444); MODULE_PARM_DESC(use_srq, "Use shared receive queue."); @@ -1267,12 +1268,12 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id, if (queue->host_qid == 0) { /* Let inflight controller teardown complete */ - flush_scheduled_work(); + flush_workqueue(nvmet_rdma_delete_wq); } ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn); if (ret) { - schedule_work(&queue->release_work); + queue_work(nvmet_rdma_delete_wq, &queue->release_work); /* Destroying rdma_cm id is not needed here */ return 0; } @@ -1337,7 +1338,7 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue) if (disconnect) { rdma_disconnect(queue->cm_id); - schedule_work(&queue->release_work); + queue_work(nvmet_rdma_delete_wq, &queue->release_work); } } @@ -1367,7 +1368,7 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id, mutex_unlock(&nvmet_rdma_queue_mutex); pr_err("failed to connect queue %d\n", queue->idx); - schedule_work(&queue->release_work); + queue_work(nvmet_rdma_delete_wq, &queue->release_work); } /** @@ -1649,8 +1650,17 @@ static int __init nvmet_rdma_init(void) if (ret) goto err_ib_client; + nvmet_rdma_delete_wq = alloc_workqueue("nvmet-rdma-delete-wq", + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0); + if (!nvmet_rdma_delete_wq) { + ret = -ENOMEM; + goto err_unreg_transport; + } + return 0; +err_unreg_transport: + nvmet_unregister_transport(&nvmet_rdma_ops); err_ib_client: ib_unregister_client(&nvmet_rdma_ib_client); return ret; @@ -1658,6 +1668,7 @@ err_ib_client: static void __exit nvmet_rdma_exit(void) { + destroy_workqueue(nvmet_rdma_delete_wq); nvmet_unregister_transport(&nvmet_rdma_ops); ib_unregister_client(&nvmet_rdma_ib_client); WARN_ON_ONCE(!list_empty(&nvmet_rdma_queue_list)); diff --git a/drivers/of/device.c b/drivers/of/device.c index 5957cd4fa262..c7fa5a9697c9 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -170,18 +170,6 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma) } EXPORT_SYMBOL_GPL(of_dma_configure); -/** - * of_dma_deconfigure - Clean up DMA configuration - * @dev: Device for which to clean up DMA configuration - * - * Clean up all configuration performed by of_dma_configure_ops() and free all - * resources that have been allocated. - */ -void of_dma_deconfigure(struct device *dev) -{ - arch_teardown_dma_ops(dev); -} - int of_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 31ff03dbeb83..2c2df4e4fc14 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -48,9 +48,14 @@ static struct opp_device *_find_opp_dev(const struct device *dev, static struct opp_table *_find_opp_table_unlocked(struct device *dev) { struct opp_table *opp_table; + bool found; list_for_each_entry(opp_table, &opp_tables, node) { - if (_find_opp_dev(dev, opp_table)) { + mutex_lock(&opp_table->lock); + found = !!_find_opp_dev(dev, opp_table); + mutex_unlock(&opp_table->lock); + + if (found) { _get_opp_table_kref(opp_table); return opp_table; @@ -313,7 +318,7 @@ int dev_pm_opp_get_opp_count(struct device *dev) count = PTR_ERR(opp_table); dev_dbg(dev, "%s: OPP table not found (%d)\n", __func__, count); - return 0; + return count; } count = _get_opp_count(opp_table); @@ -754,8 +759,8 @@ static void _remove_opp_dev(struct opp_device *opp_dev, kfree(opp_dev); } -struct opp_device *_add_opp_dev(const struct device *dev, - struct opp_table *opp_table) +static struct opp_device *_add_opp_dev_unlocked(const struct device *dev, + struct opp_table *opp_table) { struct opp_device *opp_dev; int ret; @@ -766,6 +771,7 @@ struct opp_device *_add_opp_dev(const struct device *dev, /* Initialize opp-dev */ opp_dev->dev = dev; + list_add(&opp_dev->node, &opp_table->dev_list); /* Create debugfs entries for the opp_table */ @@ -777,7 +783,19 @@ struct opp_device *_add_opp_dev(const struct device *dev, return opp_dev; } -static struct opp_table *_allocate_opp_table(struct device *dev) +struct opp_device *_add_opp_dev(const struct device *dev, + struct opp_table *opp_table) +{ + struct opp_device *opp_dev; + + mutex_lock(&opp_table->lock); + opp_dev = _add_opp_dev_unlocked(dev, opp_table); + mutex_unlock(&opp_table->lock); + + return opp_dev; +} + +static struct opp_table *_allocate_opp_table(struct device *dev, int index) { struct opp_table *opp_table; struct opp_device *opp_dev; @@ -791,6 +809,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev) if (!opp_table) return NULL; + mutex_init(&opp_table->lock); INIT_LIST_HEAD(&opp_table->dev_list); opp_dev = _add_opp_dev(dev, opp_table); @@ -799,7 +818,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev) return NULL; } - _of_init_opp_table(opp_table, dev); + _of_init_opp_table(opp_table, dev, index); /* Find clk for the device */ opp_table->clk = clk_get(dev, NULL); @@ -812,7 +831,6 @@ static struct opp_table *_allocate_opp_table(struct device *dev) BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head); INIT_LIST_HEAD(&opp_table->opp_list); - mutex_init(&opp_table->lock); kref_init(&opp_table->kref); /* Secure the device table modification */ @@ -825,7 +843,7 @@ void _get_opp_table_kref(struct opp_table *opp_table) kref_get(&opp_table->kref); } -struct opp_table *dev_pm_opp_get_opp_table(struct device *dev) +static struct opp_table *_opp_get_opp_table(struct device *dev, int index) { struct opp_table *opp_table; @@ -836,31 +854,56 @@ struct opp_table *dev_pm_opp_get_opp_table(struct device *dev) if (!IS_ERR(opp_table)) goto unlock; - opp_table = _allocate_opp_table(dev); + opp_table = _managed_opp(dev, index); + if (opp_table) { + if (!_add_opp_dev_unlocked(dev, opp_table)) { + dev_pm_opp_put_opp_table(opp_table); + opp_table = NULL; + } + goto unlock; + } + + opp_table = _allocate_opp_table(dev, index); unlock: mutex_unlock(&opp_table_lock); return opp_table; } + +struct opp_table *dev_pm_opp_get_opp_table(struct device *dev) +{ + return _opp_get_opp_table(dev, 0); +} EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table); +struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev, + int index) +{ + return _opp_get_opp_table(dev, index); +} + static void _opp_table_kref_release(struct kref *kref) { struct opp_table *opp_table = container_of(kref, struct opp_table, kref); - struct opp_device *opp_dev; + struct opp_device *opp_dev, *temp; /* Release clk */ if (!IS_ERR(opp_table->clk)) clk_put(opp_table->clk); - opp_dev = list_first_entry(&opp_table->dev_list, struct opp_device, - node); + WARN_ON(!list_empty(&opp_table->opp_list)); - _remove_opp_dev(opp_dev, opp_table); + list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node) { + /* + * The OPP table is getting removed, drop the performance state + * constraints. + */ + if (opp_table->genpd_performance_state) + dev_pm_genpd_set_performance_state((struct device *)(opp_dev->dev), 0); - /* dev_list must be empty now */ - WARN_ON(!list_empty(&opp_table->dev_list)); + _remove_opp_dev(opp_dev, opp_table); + } mutex_destroy(&opp_table->lock); list_del(&opp_table->node); @@ -869,6 +912,33 @@ static void _opp_table_kref_release(struct kref *kref) mutex_unlock(&opp_table_lock); } +void _opp_remove_all_static(struct opp_table *opp_table) +{ + struct dev_pm_opp *opp, *tmp; + + list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) { + if (!opp->dynamic) + dev_pm_opp_put(opp); + } + + opp_table->parsed_static_opps = false; +} + +static void _opp_table_list_kref_release(struct kref *kref) +{ + struct opp_table *opp_table = container_of(kref, struct opp_table, + list_kref); + + _opp_remove_all_static(opp_table); + mutex_unlock(&opp_table_lock); +} + +void _put_opp_list_kref(struct opp_table *opp_table) +{ + kref_put_mutex(&opp_table->list_kref, _opp_table_list_kref_release, + &opp_table_lock); +} + void dev_pm_opp_put_opp_table(struct opp_table *opp_table) { kref_put_mutex(&opp_table->kref, _opp_table_kref_release, @@ -896,7 +966,6 @@ static void _opp_kref_release(struct kref *kref) kfree(opp); mutex_unlock(&opp_table->lock); - dev_pm_opp_put_opp_table(opp_table); } void dev_pm_opp_get(struct dev_pm_opp *opp) @@ -940,11 +1009,15 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) if (found) { dev_pm_opp_put(opp); + + /* Drop the reference taken by dev_pm_opp_add() */ + dev_pm_opp_put_opp_table(opp_table); } else { dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n", __func__, freq); } + /* Drop the reference taken by _find_opp_table() */ dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_remove); @@ -1062,9 +1135,6 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, new_opp->opp_table = opp_table; kref_init(&new_opp->kref); - /* Get a reference to the OPP table */ - _get_opp_table_kref(opp_table); - ret = opp_debug_create_one(new_opp, opp_table); if (ret) dev_err(dev, "%s: Failed to register opp to debugfs (%d)\n", @@ -1543,8 +1613,9 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) return -ENOMEM; ret = _opp_add_v1(opp_table, dev, freq, u_volt, true); + if (ret) + dev_pm_opp_put_opp_table(opp_table); - dev_pm_opp_put_opp_table(opp_table); return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_add); @@ -1707,35 +1778,7 @@ int dev_pm_opp_unregister_notifier(struct device *dev, } EXPORT_SYMBOL(dev_pm_opp_unregister_notifier); -/* - * Free OPPs either created using static entries present in DT or even the - * dynamically added entries based on remove_all param. - */ -void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, - bool remove_all) -{ - struct dev_pm_opp *opp, *tmp; - - /* Find if opp_table manages a single device */ - if (list_is_singular(&opp_table->dev_list)) { - /* Free static OPPs */ - list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) { - if (remove_all || !opp->dynamic) - dev_pm_opp_put(opp); - } - - /* - * The OPP table is getting removed, drop the performance state - * constraints. - */ - if (opp_table->genpd_performance_state) - dev_pm_genpd_set_performance_state(dev, 0); - } else { - _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table); - } -} - -void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all) +void _dev_pm_opp_find_and_remove_table(struct device *dev) { struct opp_table *opp_table; @@ -1752,8 +1795,12 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all) return; } - _dev_pm_opp_remove_table(opp_table, dev, remove_all); + _put_opp_list_kref(opp_table); + + /* Drop reference taken by _find_opp_table() */ + dev_pm_opp_put_opp_table(opp_table); + /* Drop reference taken while the OPP table was added */ dev_pm_opp_put_opp_table(opp_table); } @@ -1766,6 +1813,6 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all) */ void dev_pm_opp_remove_table(struct device *dev) { - _dev_pm_opp_find_and_remove_table(dev, true); + _dev_pm_opp_find_and_remove_table(dev); } EXPORT_SYMBOL_GPL(dev_pm_opp_remove_table); diff --git a/drivers/opp/cpu.c b/drivers/opp/cpu.c index 0c0910709435..ab6d07e78945 100644 --- a/drivers/opp/cpu.c +++ b/drivers/opp/cpu.c @@ -108,7 +108,8 @@ void dev_pm_opp_free_cpufreq_table(struct device *dev, EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table); #endif /* CONFIG_CPU_FREQ */ -void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of) +void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, + int last_cpu) { struct device *cpu_dev; int cpu; @@ -116,6 +117,9 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of) WARN_ON(cpumask_empty(cpumask)); for_each_cpu(cpu, cpumask) { + if (cpu == last_cpu) + break; + cpu_dev = get_cpu_device(cpu); if (!cpu_dev) { pr_err("%s: failed to get cpu%d device\n", __func__, @@ -123,10 +127,7 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of) continue; } - if (of) - dev_pm_opp_of_remove_table(cpu_dev); - else - dev_pm_opp_remove_table(cpu_dev); + _dev_pm_opp_find_and_remove_table(cpu_dev); } } @@ -140,7 +141,7 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of) */ void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask) { - _dev_pm_opp_cpumask_remove_table(cpumask, false); + _dev_pm_opp_cpumask_remove_table(cpumask, -1); } EXPORT_SYMBOL_GPL(dev_pm_opp_cpumask_remove_table); @@ -222,8 +223,10 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) cpumask_clear(cpumask); if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) { + mutex_lock(&opp_table->lock); list_for_each_entry(opp_dev, &opp_table->dev_list, node) cpumask_set_cpu(opp_dev->dev->id, cpumask); + mutex_unlock(&opp_table->lock); } else { cpumask_set_cpu(cpu_dev->id, cpumask); } diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 7af0ddec936b..5a4b47958073 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -23,11 +23,32 @@ #include "opp.h" -static struct opp_table *_managed_opp(const struct device_node *np) +/* + * Returns opp descriptor node for a device node, caller must + * do of_node_put(). + */ +static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np, + int index) +{ + /* "operating-points-v2" can be an array for power domain providers */ + return of_parse_phandle(np, "operating-points-v2", index); +} + +/* Returns opp descriptor node for a device, caller must do of_node_put() */ +struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) +{ + return _opp_of_get_opp_desc_node(dev->of_node, 0); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); + +struct opp_table *_managed_opp(struct device *dev, int index) { struct opp_table *opp_table, *managed_table = NULL; + struct device_node *np; - mutex_lock(&opp_table_lock); + np = _opp_of_get_opp_desc_node(dev->of_node, index); + if (!np) + return NULL; list_for_each_entry(opp_table, &opp_tables, node) { if (opp_table->np == np) { @@ -47,29 +68,45 @@ static struct opp_table *_managed_opp(const struct device_node *np) } } - mutex_unlock(&opp_table_lock); + of_node_put(np); return managed_table; } -void _of_init_opp_table(struct opp_table *opp_table, struct device *dev) +void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, + int index) { - struct device_node *np; + struct device_node *np, *opp_np; + u32 val; /* * Only required for backward compatibility with v1 bindings, but isn't * harmful for other cases. And so we do it unconditionally. */ np = of_node_get(dev->of_node); - if (np) { - u32 val; - - if (!of_property_read_u32(np, "clock-latency", &val)) - opp_table->clock_latency_ns_max = val; - of_property_read_u32(np, "voltage-tolerance", - &opp_table->voltage_tolerance_v1); - of_node_put(np); - } + if (!np) + return; + + if (!of_property_read_u32(np, "clock-latency", &val)) + opp_table->clock_latency_ns_max = val; + of_property_read_u32(np, "voltage-tolerance", + &opp_table->voltage_tolerance_v1); + + /* Get OPP table node */ + opp_np = _opp_of_get_opp_desc_node(np, index); + of_node_put(np); + + if (!opp_np) + return; + + if (of_property_read_bool(opp_np, "opp-shared")) + opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; + else + opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE; + + opp_table->np = opp_np; + + of_node_put(opp_np); } static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table, @@ -245,26 +282,10 @@ free_microvolt: */ void dev_pm_opp_of_remove_table(struct device *dev) { - _dev_pm_opp_find_and_remove_table(dev, false); + _dev_pm_opp_find_and_remove_table(dev); } EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); -/* Returns opp descriptor node for a device node, caller must - * do of_node_put() */ -static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np, - int index) -{ - /* "operating-points-v2" can be an array for power domain providers */ - return of_parse_phandle(np, "operating-points-v2", index); -} - -/* Returns opp descriptor node for a device, caller must do of_node_put() */ -struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) -{ - return _opp_of_get_opp_desc_node(dev->of_node, 0); -} -EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); - /** * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings) * @opp_table: OPP table @@ -276,15 +297,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); * removed by dev_pm_opp_remove. * * Return: - * 0 On success OR + * Valid OPP pointer: + * On success + * NULL: * Duplicate OPPs (both freq and volt are same) and opp->available - * -EEXIST Freq are same and volt are different OR + * OR if the OPP is not supported by hardware. + * ERR_PTR(-EEXIST): + * Freq are same and volt are different OR * Duplicate OPPs (both freq and volt are same) and !opp->available - * -ENOMEM Memory allocation failure - * -EINVAL Failed parsing the OPP node + * ERR_PTR(-ENOMEM): + * Memory allocation failure + * ERR_PTR(-EINVAL): + * Failed parsing the OPP node */ -static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, - struct device_node *np) +static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table, + struct device *dev, struct device_node *np) { struct dev_pm_opp *new_opp; u64 rate = 0; @@ -294,7 +321,7 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, new_opp = _opp_allocate(opp_table); if (!new_opp) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ret = of_property_read_u64(np, "opp-hz", &rate); if (ret < 0) { @@ -369,52 +396,47 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, * frequency/voltage list. */ blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp); - return 0; + return new_opp; free_opp: _opp_free(new_opp); - return ret; + return ERR_PTR(ret); } /* Initializes OPP tables based on new bindings */ -static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) +static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table) { struct device_node *np; - struct opp_table *opp_table; - int ret = 0, count = 0, pstate_count = 0; + int ret, count = 0, pstate_count = 0; struct dev_pm_opp *opp; - opp_table = _managed_opp(opp_np); - if (opp_table) { - /* OPPs are already managed */ - if (!_add_opp_dev(dev, opp_table)) - ret = -ENOMEM; - goto put_opp_table; + /* OPP table is already initialized for the device */ + if (opp_table->parsed_static_opps) { + kref_get(&opp_table->list_kref); + return 0; } - opp_table = dev_pm_opp_get_opp_table(dev); - if (!opp_table) - return -ENOMEM; + kref_init(&opp_table->list_kref); /* We have opp-table node now, iterate over it and add OPPs */ - for_each_available_child_of_node(opp_np, np) { - count++; - - ret = _opp_add_static_v2(opp_table, dev, np); - if (ret) { + for_each_available_child_of_node(opp_table->np, np) { + opp = _opp_add_static_v2(opp_table, dev, np); + if (IS_ERR(opp)) { + ret = PTR_ERR(opp); dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, ret); - _dev_pm_opp_remove_table(opp_table, dev, false); of_node_put(np); - goto put_opp_table; + goto put_list_kref; + } else if (opp) { + count++; } } /* There should be one of more OPP defined */ if (WARN_ON(!count)) { ret = -ENOENT; - goto put_opp_table; + goto put_list_kref; } list_for_each_entry(opp, &opp_table->opp_list, node) @@ -425,28 +447,25 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) dev_err(dev, "Not all nodes have performance state set (%d: %d)\n", count, pstate_count); ret = -ENOENT; - goto put_opp_table; + goto put_list_kref; } if (pstate_count) opp_table->genpd_performance_state = true; - opp_table->np = opp_np; - if (of_property_read_bool(opp_np, "opp-shared")) - opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; - else - opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE; + opp_table->parsed_static_opps = true; -put_opp_table: - dev_pm_opp_put_opp_table(opp_table); + return 0; + +put_list_kref: + _put_opp_list_kref(opp_table); return ret; } /* Initializes OPP tables based on old-deprecated bindings */ -static int _of_add_opp_table_v1(struct device *dev) +static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table) { - struct opp_table *opp_table; const struct property *prop; const __be32 *val; int nr, ret = 0; @@ -467,9 +486,7 @@ static int _of_add_opp_table_v1(struct device *dev) return -EINVAL; } - opp_table = dev_pm_opp_get_opp_table(dev); - if (!opp_table) - return -ENOMEM; + kref_init(&opp_table->list_kref); val = prop->value; while (nr) { @@ -480,13 +497,12 @@ static int _of_add_opp_table_v1(struct device *dev) if (ret) { dev_err(dev, "%s: Failed to add OPP %ld (%d)\n", __func__, freq, ret); - _dev_pm_opp_remove_table(opp_table, dev, false); - break; + _put_opp_list_kref(opp_table); + return ret; } nr -= 2; } - dev_pm_opp_put_opp_table(opp_table); return ret; } @@ -509,24 +525,24 @@ static int _of_add_opp_table_v1(struct device *dev) */ int dev_pm_opp_of_add_table(struct device *dev) { - struct device_node *opp_np; + struct opp_table *opp_table; int ret; + opp_table = dev_pm_opp_get_opp_table_indexed(dev, 0); + if (!opp_table) + return -ENOMEM; + /* - * OPPs have two version of bindings now. The older one is deprecated, - * try for the new binding first. + * OPPs have two version of bindings now. Also try the old (v1) + * bindings for backward compatibility with older dtbs. */ - opp_np = dev_pm_opp_of_get_opp_desc_node(dev); - if (!opp_np) { - /* - * Try old-deprecated bindings for backward compatibility with - * older dtbs. - */ - return _of_add_opp_table_v1(dev); - } + if (opp_table->np) + ret = _of_add_opp_table_v2(dev, opp_table); + else + ret = _of_add_opp_table_v1(dev, opp_table); - ret = _of_add_opp_table_v2(dev, opp_np); - of_node_put(opp_np); + if (ret) + dev_pm_opp_put_opp_table(opp_table); return ret; } @@ -553,28 +569,29 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); */ int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) { - struct device_node *opp_np; + struct opp_table *opp_table; int ret, count; -again: - opp_np = _opp_of_get_opp_desc_node(dev->of_node, index); - if (!opp_np) { + if (index) { /* * If only one phandle is present, then the same OPP table * applies for all index requests. */ count = of_count_phandle_with_args(dev->of_node, "operating-points-v2", NULL); - if (count == 1 && index) { - index = 0; - goto again; - } + if (count != 1) + return -ENODEV; - return -ENODEV; + index = 0; } - ret = _of_add_opp_table_v2(dev, opp_np); - of_node_put(opp_np); + opp_table = dev_pm_opp_get_opp_table_indexed(dev, index); + if (!opp_table) + return -ENOMEM; + + ret = _of_add_opp_table_v2(dev, opp_table); + if (ret) + dev_pm_opp_put_opp_table(opp_table); return ret; } @@ -591,7 +608,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed); */ void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask) { - _dev_pm_opp_cpumask_remove_table(cpumask, true); + _dev_pm_opp_cpumask_remove_table(cpumask, -1); } EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table); @@ -604,16 +621,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table); int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) { struct device *cpu_dev; - int cpu, ret = 0; + int cpu, ret; - WARN_ON(cpumask_empty(cpumask)); + if (WARN_ON(cpumask_empty(cpumask))) + return -ENODEV; for_each_cpu(cpu, cpumask) { cpu_dev = get_cpu_device(cpu); if (!cpu_dev) { pr_err("%s: failed to get cpu%d device\n", __func__, cpu); - continue; + ret = -ENODEV; + goto remove_table; } ret = dev_pm_opp_of_add_table(cpu_dev); @@ -625,12 +644,16 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) pr_debug("%s: couldn't find opp table for cpu:%d, %d\n", __func__, cpu, ret); - /* Free all other OPPs */ - dev_pm_opp_of_cpumask_remove_table(cpumask); - break; + goto remove_table; } } + return 0; + +remove_table: + /* Free all other OPPs */ + _dev_pm_opp_cpumask_remove_table(cpumask, cpu); + return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table); diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 7c540fd063b2..9c6544b4f4f9 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -126,9 +126,11 @@ enum opp_table_access { * @dev_list: list of devices that share these OPPs * @opp_list: table of opps * @kref: for reference count of the table. - * @lock: mutex protecting the opp_list. + * @list_kref: for reference count of the OPP list. + * @lock: mutex protecting the opp_list and dev_list. * @np: struct device_node pointer for opp's DT node. * @clock_latency_ns_max: Max clock latency in nanoseconds. + * @parsed_static_opps: True if OPPs are initialized from DT. * @shared_opp: OPP is shared between multiple devices. * @suspend_opp: Pointer to OPP to be used during device suspend. * @supported_hw: Array of version number to support. @@ -156,6 +158,7 @@ struct opp_table { struct list_head dev_list; struct list_head opp_list; struct kref kref; + struct kref list_kref; struct mutex lock; struct device_node *np; @@ -164,6 +167,7 @@ struct opp_table { /* For backward compatibility with v1 bindings */ unsigned int voltage_tolerance_v1; + bool parsed_static_opps; enum opp_table_access shared_opp; struct dev_pm_opp *suspend_opp; @@ -186,23 +190,26 @@ struct opp_table { /* Routines internal to opp core */ void dev_pm_opp_get(struct dev_pm_opp *opp); +void _opp_remove_all_static(struct opp_table *opp_table); void _get_opp_table_kref(struct opp_table *opp_table); int _get_opp_count(struct opp_table *opp_table); struct opp_table *_find_opp_table(struct device *dev); struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); -void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all); -void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all); +void _dev_pm_opp_find_and_remove_table(struct device *dev); struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); void _opp_free(struct dev_pm_opp *opp); int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available); int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); -void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of); +void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu); struct opp_table *_add_opp_table(struct device *dev); +void _put_opp_list_kref(struct opp_table *opp_table); #ifdef CONFIG_OF -void _of_init_opp_table(struct opp_table *opp_table, struct device *dev); +void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index); +struct opp_table *_managed_opp(struct device *dev, int index); #else -static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev) {} +static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {} +static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; } #endif #ifdef CONFIG_DEBUG_FS diff --git a/drivers/parisc/Makefile b/drivers/parisc/Makefile index 3cd5e6cb8478..99fa6a89e0b9 100644 --- a/drivers/parisc/Makefile +++ b/drivers/parisc/Makefile @@ -8,9 +8,6 @@ obj-$(CONFIG_IOSAPIC) += iosapic.o obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o obj-$(CONFIG_PCI_LBA) += lba_pci.o - -# Only use one of them: ccio-rm-dma is for PCX-W systems *only* -# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o obj-$(CONFIG_GSC) += gsc.o diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 614823617b8b..701a7d6a74d5 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -609,14 +609,13 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, ** PCX-T'? Don't know. (eg C110 or similar K-class) ** ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit". - ** Hopefully we can patch (NOP) these out at boot time somehow. ** ** "Since PCX-U employs an offset hash that is incompatible with ** the real mode coherence index generation of U2, the PDIR entry ** must be flushed to memory to retain coherence." */ - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); - asm volatile("sync"); + asm_io_fdc(pdir_ptr); + asm_io_sync(); } /** @@ -682,17 +681,14 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) ** PCX-U/U+ do. (eg C200/C240) ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". - ** - ** Hopefully someone figures out how to patch (NOP) the - ** FDC/SYNC out at boot time. */ - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7])); + asm_io_fdc(pdir_ptr); iovp += IOVP_SIZE; byte_cnt -= IOVP_SIZE; } - asm volatile("sync"); + asm_io_sync(); ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); } diff --git a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c deleted file mode 100644 index df7932af48b7..000000000000 --- a/drivers/parisc/ccio-rm-dma.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * ccio-rm-dma.c: - * DMA management routines for first generation cache-coherent machines. - * "Real Mode" operation refers to U2/Uturn chip operation. The chip - * can perform coherency checks w/o using the I/O MMU. That's all we - * need until support for more than 4GB phys mem is needed. - * - * This is the trivial case - basically what x86 does. - * - * Drawbacks of using Real Mode are: - * o outbound DMA is slower since one isn't using the prefetching - * U2 can do for outbound DMA. - * o Ability to do scatter/gather in HW is also lost. - * o only known to work with PCX-W processor. (eg C360) - * (PCX-U/U+ are not coherent with U2 in real mode.) - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * - * Original version/author: - * CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc - * cvs -z3 co linux/arch/parisc/kernel/dma-rm.c - * - * (C) Copyright 2000 Philipp Rumpf <prumpf@tux.org> - * - * - * Adopted for The Puffin Group's parisc-linux port by Grant Grundler. - * (C) Copyright 2000 Grant Grundler <grundler@puffin.external.hp.com> - * - */ - -#include <linux/types.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/pci.h> -#include <linux/gfp.h> - -#include <linux/uaccess.h> - -#include <asm/io.h> -#include <asm/hardware.h> -#include <asm/page.h> - -/* Only chose "ccio" since that's what HP-UX calls it.... -** Make it easier for folks to migrate from one to the other :^) -*/ -#define MODULE_NAME "ccio" - -#define U2_IOA_RUNWAY 0x580 -#define U2_BC_GSC 0x501 -#define UTURN_IOA_RUNWAY 0x581 -#define UTURN_BC_GSC 0x502 - -#define IS_U2(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \ -) - -#define IS_UTURN(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \ -) - -static int ccio_dma_supported( struct pci_dev *dev, u64 mask) -{ - if (dev == NULL) { - printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); - BUG(); - return(0); - } - - /* only support 32-bit devices (ie PCI/GSC) */ - return((int) (mask >= 0xffffffffUL)); -} - - -static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size, - dma_addr_t *handle) -{ - void *ret; - - ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *handle = virt_to_phys(ret); - } - return ret; -} - -static void ccio_free_consistent(struct pci_dev *dev, size_t size, - void *vaddr, dma_addr_t handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} - -static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size, - int direction) -{ - return virt_to_phys(ptr); -} - -static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr, - size_t size, int direction) -{ - /* Nothing to do */ -} - - -static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ - int tmp = nents; - - /* KISS: map each buffer separately. */ - while (nents) { - sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); - sg_dma_len(sglist) = sglist->length; - nents--; - sglist++; - } - - return tmp; -} - - -static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ -#if 0 - while (nents) { - ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); - nents--; - sglist++; - } - return; -#else - /* Do nothing (copied from current ccio_unmap_single() :^) */ -#endif -} - - -static struct pci_dma_ops ccio_ops = { - ccio_dma_supported, - ccio_alloc_consistent, - ccio_free_consistent, - ccio_map_single, - ccio_unmap_single, - ccio_map_sg, - ccio_unmap_sg, - NULL, /* dma_sync_single_for_cpu : NOP for U2 */ - NULL, /* dma_sync_single_for_device : NOP for U2 */ - NULL, /* dma_sync_sg_for_cpu : ditto */ - NULL, /* dma_sync_sg_for_device : ditto */ -}; - - -/* -** Determine if u2 should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ -static int __init -ccio_probe(struct parisc_device *dev) -{ - printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME, - dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn", - dev->hpa.start); - -/* -** FIXME - should check U2 registers to verify it's really running -** in "Real Mode". -*/ - -#if 0 -/* will need this for "Virtual Mode" operation */ - ccio_hw_init(ccio_dev); - ccio_common_init(ccio_dev); -#endif - hppa_dma_ops = &ccio_ops; - return 0; -} - -static const struct parisc_device_id ccio_tbl[] __initconst = { - { HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc }, - { HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc }, - { 0, } -}; - -static struct parisc_driver ccio_driver __refdata = { - .name = "U2/Uturn", - .id_table = ccio_tbl, - .probe = ccio_probe, -}; - -void __init ccio_init(void) -{ - register_parisc_driver(&ccio_driver); -} diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 7390fb8ca9d1..dfeea458a789 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -382,7 +382,7 @@ ilr_again: DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n", __func__, irq, intr_dev, mask); generic_handle_irq(irq); - mask &= ~(1 << local_irq); + mask &= ~DINO_MASK_IRQ(local_irq); } while (mask); /* Support for level triggered IRQ lines. @@ -396,9 +396,8 @@ ilr_again: if (mask) { if (--ilr_loop > 0) goto ilr_again; - printk(KERN_ERR "Dino 0x%px: stuck interrupt %d\n", + pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n", dino_dev->hba.base_addr, mask); - return IRQ_NONE; } return IRQ_HANDLED; } diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 11de0eccf968..c1e599a429af 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -587,8 +587,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, * (bit #61, big endian), we have to flush and sync every time * IO-PDIR is changed in Ike/Astro. */ - if (ioc_needs_fdc) - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); + asm_io_fdc(pdir_ptr); } @@ -641,8 +640,8 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) do { /* clear I/O Pdir entry "valid" bit first */ ((u8 *) pdir_ptr)[7] = 0; + asm_io_fdc(pdir_ptr); if (ioc_needs_fdc) { - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); #if 0 entries_per_cacheline = L1_CACHE_SHIFT - 3; #endif @@ -661,8 +660,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) ** could dump core on HPMC. */ ((u8 *) pdir_ptr)[7] = 0; - if (ioc_needs_fdc) - asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr)); + asm_io_fdc(pdir_ptr); WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM); } @@ -773,8 +771,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, } /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ - if (ioc_needs_fdc) - asm volatile("sync" : : ); + asm_io_sync(); #ifdef ASSERT_PDIR_SANITY sba_check_pdir(ioc,"Check after sba_map_single()"); @@ -858,8 +855,7 @@ sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size, sba_free_range(ioc, iova, size); /* If fdc's were issued, force fdc's to be visible now */ - if (ioc_needs_fdc) - asm volatile("sync" : : ); + asm_io_sync(); READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ #endif /* DELAYED_RESOURCE_CNT == 0 */ @@ -1008,8 +1004,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); /* force FDC ops in io_pdir_entry() to be visible to IOMMU */ - if (ioc_needs_fdc) - asm volatile("sync" : : ); + asm_io_sync(); #ifdef ASSERT_PDIR_SANITY if (sba_check_pdir(ioc,"Check after sba_map_sg()")) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index fd2dbd7eed7b..f31ed62d518c 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -404,12 +404,10 @@ static int vmd_dma_supported(struct device *dev, u64 mask) return vmd_dma_ops(dev)->dma_supported(to_vmd_dev(dev), mask); } -#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK static u64 vmd_get_required_mask(struct device *dev) { return vmd_dma_ops(dev)->get_required_mask(to_vmd_dev(dev)); } -#endif static void vmd_teardown_dma_ops(struct vmd_dev *vmd) { @@ -450,9 +448,7 @@ static void vmd_setup_dma_ops(struct vmd_dev *vmd) ASSIGN_VMD_DMA_OPS(source, dest, sync_sg_for_device); ASSIGN_VMD_DMA_OPS(source, dest, mapping_error); ASSIGN_VMD_DMA_OPS(source, dest, dma_supported); -#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK ASSIGN_VMD_DMA_OPS(source, dest, get_required_mask); -#endif add_dma_domain(domain); } #undef ASSIGN_VMD_DMA_OPS diff --git a/drivers/pci/pci-mid.c b/drivers/pci/pci-mid.c index 314e135014dc..30fbe2ea6eab 100644 --- a/drivers/pci/pci-mid.c +++ b/drivers/pci/pci-mid.c @@ -62,8 +62,8 @@ static const struct pci_platform_pm_ops mid_pci_platform_pm = { * arch/x86/platform/intel-mid/pwr.c. */ static const struct x86_cpu_id lpss_cpu_ids[] = { - ICPU(INTEL_FAM6_ATOM_PENWELL), - ICPU(INTEL_FAM6_ATOM_MERRIFIELD), + ICPU(INTEL_FAM6_ATOM_SALTWELL_MID), + ICPU(INTEL_FAM6_ATOM_SILVERMONT_MID), {} }; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 18802096148e..41ce410f7f97 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -284,7 +284,7 @@ int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev) io_on.stop = s->io[i].res->end; s->ops->set_io_map(s, &io_off); - mdelay(40); + msleep(40); s->ops->set_io_map(s, &io_on); } unlock: @@ -567,7 +567,7 @@ int pcmcia_enable_device(struct pcmcia_device *p_dev) !(flags & CONF_ENABLE_PULSE_IRQ)) option |= COR_LEVEL_REQ; pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option); - mdelay(40); + msleep(40); } if (p_dev->config_regs & PRESENT_STATUS) pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status); diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h index 01098c841f87..8ac7b138c094 100644 --- a/drivers/pcmcia/ricoh.h +++ b/drivers/pcmcia/ricoh.h @@ -119,6 +119,10 @@ #define RL5C4XX_MISC_CONTROL 0x2F /* 8 bit */ #define RL5C4XX_ZV_ENABLE 0x08 +/* Misc Control 3 Register */ +#define RL5C4XX_MISC3 0x00A2 /* 16 bit */ +#define RL5C47X_MISC3_CB_CLKRUN_DIS BIT(1) + #ifdef __YENTA_H #define rl_misc(socket) ((socket)->private[0]) @@ -156,6 +160,35 @@ static void ricoh_set_zv(struct yenta_socket *socket) } } +static void ricoh_set_clkrun(struct yenta_socket *socket, bool quiet) +{ + u16 misc3; + + /* + * RL5C475II likely has this setting, too, however no datasheet + * is publicly available for this chip + */ + if (socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C476 && + socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C478) + return; + + if (socket->dev->revision < 0x80) + return; + + misc3 = config_readw(socket, RL5C4XX_MISC3); + if (misc3 & RL5C47X_MISC3_CB_CLKRUN_DIS) { + if (!quiet) + dev_dbg(&socket->dev->dev, + "CLKRUN feature already disabled\n"); + } else if (disable_clkrun) { + if (!quiet) + dev_info(&socket->dev->dev, + "Disabling CLKRUN feature\n"); + misc3 |= RL5C47X_MISC3_CB_CLKRUN_DIS; + config_writew(socket, RL5C4XX_MISC3, misc3); + } +} + static void ricoh_save_state(struct yenta_socket *socket) { rl_misc(socket) = config_readw(socket, RL5C4XX_MISC); @@ -172,6 +205,7 @@ static void ricoh_restore_state(struct yenta_socket *socket) config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); config_writew(socket, RL5C4XX_CONFIG, rl_config(socket)); + ricoh_set_clkrun(socket, true); } @@ -197,6 +231,7 @@ static int ricoh_override(struct yenta_socket *socket) config_writew(socket, RL5C4XX_CONFIG, config); ricoh_set_zv(socket); + ricoh_set_clkrun(socket, false); return 0; } diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index c5f2344c189b..3a8c84bb174d 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -351,19 +351,20 @@ static int soc_common_pcmcia_config_skt( if (ret == 0) { struct gpio_desc *descs[2]; - int values[2], n = 0; + DECLARE_BITMAP(values, 2); + int n = 0; if (skt->gpio_reset) { descs[n] = skt->gpio_reset; - values[n++] = !!(state->flags & SS_RESET); + __assign_bit(n++, values, state->flags & SS_RESET); } if (skt->gpio_bus_enable) { descs[n] = skt->gpio_bus_enable; - values[n++] = !!(state->flags & SS_OUTPUT_ENA); + __assign_bit(n++, values, state->flags & SS_OUTPUT_ENA); } if (n) - gpiod_set_array_value_cansleep(n, descs, values); + gpiod_set_array_value_cansleep(n, descs, NULL, values); /* * This really needs a better solution. The IRQ diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index ab3da2262f0f..ac6a3f46b1e6 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -26,7 +26,8 @@ static bool disable_clkrun; module_param(disable_clkrun, bool, 0444); -MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option"); +MODULE_PARM_DESC(disable_clkrun, + "If PC card doesn't function properly, please try this option (TI and Ricoh bridges only)"); static bool isa_probe = 1; module_param(isa_probe, bool, 0444); diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c index 96075cecb0ae..933bd8410fc2 100644 --- a/drivers/perf/arm_pmu_platform.c +++ b/drivers/perf/arm_pmu_platform.c @@ -77,14 +77,14 @@ static int pmu_parse_irq_affinity(struct device_node *node, int i) dn = of_parse_phandle(node, "interrupt-affinity", i); if (!dn) { - pr_warn("failed to parse interrupt-affinity[%d] for %s\n", - i, node->name); + pr_warn("failed to parse interrupt-affinity[%d] for %pOFn\n", + i, node); return -EINVAL; } cpu = of_cpu_node_to_id(dn); if (cpu < 0) { - pr_warn("failed to find logical CPU for %s\n", dn->name); + pr_warn("failed to find logical CPU for %pOFn\n", dn); cpu = nr_cpu_ids; } diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c index 0075fb0bef8c..25d456a323c2 100644 --- a/drivers/phy/motorola/phy-mapphone-mdm6600.c +++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c @@ -157,15 +157,13 @@ static const struct phy_ops gpio_usb_ops = { */ static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val) { - int values[PHY_MDM6600_NR_CMD_LINES]; - int i; + DECLARE_BITMAP(values, PHY_MDM6600_NR_CMD_LINES); - val &= (1 << PHY_MDM6600_NR_CMD_LINES) - 1; - for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++) - values[i] = (val & BIT(i)) >> i; + values[0] = val; gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES, - ddata->cmd_gpios->desc, values); + ddata->cmd_gpios->desc, + ddata->cmd_gpios->info, values); } /** @@ -176,7 +174,7 @@ static void phy_mdm6600_status(struct work_struct *work) { struct phy_mdm6600 *ddata; struct device *dev; - int values[PHY_MDM6600_NR_STATUS_LINES]; + DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES); int error, i, val = 0; ddata = container_of(work, struct phy_mdm6600, status_work.work); @@ -184,16 +182,17 @@ static void phy_mdm6600_status(struct work_struct *work) error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES, ddata->status_gpios->desc, + ddata->status_gpios->info, values); if (error) return; for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) { - val |= values[i] << i; + val |= test_bit(i, values) << i; dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n", - __func__, i, values[i], val); + __func__, i, test_bit(i, values), val); } - ddata->status = val; + ddata->status = values[0]; dev_info(dev, "modem status: %i %s\n", ddata->status, diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e86752be1f19..4d8c00eac742 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -195,6 +195,16 @@ config PINCTRL_RZA1 help This selects pinctrl driver for Renesas RZ/A1 platforms. +config PINCTRL_RZN1 + bool "Renesas RZ/N1 pinctrl driver" + depends on OF + depends on ARCH_RZN1 || COMPILE_TEST + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + help + This selects pinctrl driver for Renesas RZ/N1 devices. + config PINCTRL_SINGLE tristate "One-register-per-pin type device tree based pinctrl driver" depends on OF @@ -309,12 +319,14 @@ config PINCTRL_ZYNQ config PINCTRL_INGENIC bool "Pinctrl driver for the Ingenic JZ47xx SoCs" - default y + default MACH_INGENIC depends on OF - depends on MACH_INGENIC || COMPILE_TEST + depends on MIPS || COMPILE_TEST select GENERIC_PINCONF select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS + select GPIOLIB + select GPIOLIB_IRQCHIP select REGMAP_MMIO config PINCTRL_RK805 @@ -346,6 +358,7 @@ source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/intel/Kconfig" source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/nomadik/Kconfig" +source "drivers/pinctrl/nuvoton/Kconfig" source "drivers/pinctrl/pxa/Kconfig" source "drivers/pinctrl/qcom/Kconfig" source "drivers/pinctrl/samsung/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 46ef9bd52096..18a13c1e2c21 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_RZA1) += pinctrl-rza1.o +obj-$(CONFIG_PINCTRL_RZN1) += pinctrl-rzn1.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_SIRF) += sirf/ obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o @@ -51,6 +52,7 @@ obj-y += freescale/ obj-$(CONFIG_X86) += intel/ obj-y += mvebu/ obj-y += nomadik/ +obj-$(CONFIG_ARCH_NPCM7XX) += nuvoton/ obj-$(CONFIG_PINCTRL_PXA) += pxa/ obj-$(CONFIG_ARCH_QCOM) += qcom/ obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c index aefe3c33dffd..eb87ab774269 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c @@ -715,7 +715,7 @@ int aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset, pmap = find_pinconf_map(param, MAP_TYPE_ARG, arg); - if (unlikely(WARN_ON(!pmap))) + if (WARN_ON(!pmap)) return -EINVAL; val = pmap->val << pconf->bit; diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig index 0f38d51f47c6..c8575399d6f7 100644 --- a/drivers/pinctrl/bcm/Kconfig +++ b/drivers/pinctrl/bcm/Kconfig @@ -73,6 +73,19 @@ config PINCTRL_CYGNUS_MUX configuration, with the exception that certain individual pins can be overridden to GPIO function +config PINCTRL_NS + bool "Broadcom Northstar pins driver" + depends on OF && (ARCH_BCM_5301X || COMPILE_TEST) + select PINMUX + select GENERIC_PINCONF + default ARCH_BCM_5301X + help + Say yes here to enable the Broadcom NS SoC pins driver. + + The Broadcom Northstar pins driver supports muxing multi-purpose pins + that can be used for various functions (e.g. SPI, I2C, UART) as well + as GPIOs. + config PINCTRL_NSP_GPIO bool "Broadcom NSP GPIO (with PINCONF) driver" depends on OF_GPIO && (ARCH_BCM_NSP || COMPILE_TEST) diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile index 80ceb9dae944..79d5e49fdd9a 100644 --- a/drivers/pinctrl/bcm/Makefile +++ b/drivers/pinctrl/bcm/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_IPROC_GPIO) += pinctrl-iproc-gpio.o obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o +obj-$(CONFIG_PINCTRL_NS) += pinctrl-ns.o obj-$(CONFIG_PINCTRL_NSP_GPIO) += pinctrl-nsp-gpio.o obj-$(CONFIG_PINCTRL_NS2_MUX) += pinctrl-ns2-mux.o obj-$(CONFIG_PINCTRL_NSP_MUX) += pinctrl-nsp-mux.o diff --git a/drivers/pinctrl/bcm/pinctrl-ns.c b/drivers/pinctrl/bcm/pinctrl-ns.c new file mode 100644 index 000000000000..d7f8175d2c1c --- /dev/null +++ b/drivers/pinctrl/bcm/pinctrl-ns.c @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Rafał Miłecki <rafal@milecki.pl> + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define FLAG_BCM4708 BIT(1) +#define FLAG_BCM4709 BIT(2) +#define FLAG_BCM53012 BIT(3) + +struct ns_pinctrl { + struct device *dev; + unsigned int chipset_flag; + struct pinctrl_dev *pctldev; + void __iomem *base; + + struct pinctrl_desc pctldesc; + struct ns_pinctrl_group *groups; + unsigned int num_groups; + struct ns_pinctrl_function *functions; + unsigned int num_functions; +}; + +/* + * Pins + */ + +static const struct pinctrl_pin_desc ns_pinctrl_pins[] = { + { 0, "spi_clk", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 1, "spi_ss", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 2, "spi_mosi", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 3, "spi_miso", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 4, "i2c_scl", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 5, "i2c_sda", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 6, "mdc", (void *)(FLAG_BCM4709 | FLAG_BCM53012) }, + { 7, "mdio", (void *)(FLAG_BCM4709 | FLAG_BCM53012) }, + { 8, "pwm0", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 9, "pwm1", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 10, "pwm2", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 11, "pwm3", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 12, "uart1_rx", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 13, "uart1_tx", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 14, "uart1_cts", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 15, "uart1_rts", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) }, + { 16, "uart2_rx", (void *)(FLAG_BCM4709 | FLAG_BCM53012) }, + { 17, "uart2_tx", (void *)(FLAG_BCM4709 | FLAG_BCM53012) }, +/* TODO { ??, "xtal_out", (void *)(FLAG_BCM4709) }, */ + { 22, "sdio_pwr", (void *)(FLAG_BCM4709 | FLAG_BCM53012) }, + { 23, "sdio_en_1p8v", (void *)(FLAG_BCM4709 | FLAG_BCM53012) }, +}; + +/* + * Groups + */ + +struct ns_pinctrl_group { + const char *name; + const unsigned int *pins; + const unsigned int num_pins; + unsigned int chipsets; +}; + +static const unsigned int spi_pins[] = { 0, 1, 2, 3 }; +static const unsigned int i2c_pins[] = { 4, 5 }; +static const unsigned int mdio_pins[] = { 6, 7 }; +static const unsigned int pwm0_pins[] = { 8 }; +static const unsigned int pwm1_pins[] = { 9 }; +static const unsigned int pwm2_pins[] = { 10 }; +static const unsigned int pwm3_pins[] = { 11 }; +static const unsigned int uart1_pins[] = { 12, 13, 14, 15 }; +static const unsigned int uart2_pins[] = { 16, 17 }; +static const unsigned int sdio_pwr_pins[] = { 22 }; +static const unsigned int sdio_1p8v_pins[] = { 23 }; + +#define NS_GROUP(_name, _pins, _chipsets) \ +{ \ + .name = _name, \ + .pins = _pins, \ + .num_pins = ARRAY_SIZE(_pins), \ + .chipsets = _chipsets, \ +} + +static const struct ns_pinctrl_group ns_pinctrl_groups[] = { + NS_GROUP("spi_grp", spi_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("i2c_grp", i2c_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("mdio_grp", mdio_pins, FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("pwm0_grp", pwm0_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("pwm1_grp", pwm1_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("pwm2_grp", pwm2_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("pwm3_grp", pwm3_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("uart1_grp", uart1_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("uart2_grp", uart2_pins, FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("sdio_pwr_grp", sdio_pwr_pins, FLAG_BCM4709 | FLAG_BCM53012), + NS_GROUP("sdio_1p8v_grp", sdio_1p8v_pins, FLAG_BCM4709 | FLAG_BCM53012), +}; + +/* + * Functions + */ + +struct ns_pinctrl_function { + const char *name; + const char * const *groups; + const unsigned int num_groups; + unsigned int chipsets; +}; + +static const char * const spi_groups[] = { "spi_grp" }; +static const char * const i2c_groups[] = { "i2c_grp" }; +static const char * const mdio_groups[] = { "mdio_grp" }; +static const char * const pwm_groups[] = { "pwm0_grp", "pwm1_grp", "pwm2_grp", + "pwm3_grp" }; +static const char * const uart1_groups[] = { "uart1_grp" }; +static const char * const uart2_groups[] = { "uart2_grp" }; +static const char * const sdio_groups[] = { "sdio_pwr_grp", "sdio_1p8v_grp" }; + +#define NS_FUNCTION(_name, _groups, _chipsets) \ +{ \ + .name = _name, \ + .groups = _groups, \ + .num_groups = ARRAY_SIZE(_groups), \ + .chipsets = _chipsets, \ +} + +static const struct ns_pinctrl_function ns_pinctrl_functions[] = { + NS_FUNCTION("spi", spi_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_FUNCTION("i2c", i2c_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_FUNCTION("mdio", mdio_groups, FLAG_BCM4709 | FLAG_BCM53012), + NS_FUNCTION("pwm", pwm_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_FUNCTION("uart1", uart1_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012), + NS_FUNCTION("uart2", uart2_groups, FLAG_BCM4709 | FLAG_BCM53012), + NS_FUNCTION("sdio", sdio_groups, FLAG_BCM4709 | FLAG_BCM53012), +}; + +/* + * Groups code + */ + +static int ns_pinctrl_get_groups_count(struct pinctrl_dev *pctrl_dev) +{ + struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + + return ns_pinctrl->num_groups; +} + +static const char *ns_pinctrl_get_group_name(struct pinctrl_dev *pctrl_dev, + unsigned int selector) +{ + struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + + return ns_pinctrl->groups[selector].name; +} + +static int ns_pinctrl_get_group_pins(struct pinctrl_dev *pctrl_dev, + unsigned int selector, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + + *pins = ns_pinctrl->groups[selector].pins; + *num_pins = ns_pinctrl->groups[selector].num_pins; + + return 0; +} + +static const struct pinctrl_ops ns_pinctrl_ops = { + .get_groups_count = ns_pinctrl_get_groups_count, + .get_group_name = ns_pinctrl_get_group_name, + .get_group_pins = ns_pinctrl_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +/* + * Functions code + */ + +static int ns_pinctrl_get_functions_count(struct pinctrl_dev *pctrl_dev) +{ + struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + + return ns_pinctrl->num_functions; +} + +static const char *ns_pinctrl_get_function_name(struct pinctrl_dev *pctrl_dev, + unsigned int selector) +{ + struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + + return ns_pinctrl->functions[selector].name; +} + +static int ns_pinctrl_get_function_groups(struct pinctrl_dev *pctrl_dev, + unsigned int selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + + *groups = ns_pinctrl->functions[selector].groups; + *num_groups = ns_pinctrl->functions[selector].num_groups; + + return 0; +} + +static int ns_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev, + unsigned int func_select, + unsigned int grp_select) +{ + struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + u32 unset = 0; + u32 tmp; + int i; + + for (i = 0; i < ns_pinctrl->groups[grp_select].num_pins; i++) { + int pin_number = ns_pinctrl->groups[grp_select].pins[i]; + + unset |= BIT(pin_number); + } + + tmp = readl(ns_pinctrl->base); + tmp &= ~unset; + writel(tmp, ns_pinctrl->base); + + return 0; +} + +static const struct pinmux_ops ns_pinctrl_pmxops = { + .get_functions_count = ns_pinctrl_get_functions_count, + .get_function_name = ns_pinctrl_get_function_name, + .get_function_groups = ns_pinctrl_get_function_groups, + .set_mux = ns_pinctrl_set_mux, +}; + +/* + * Controller code + */ + +static struct pinctrl_desc ns_pinctrl_desc = { + .name = "pinctrl-ns", + .pctlops = &ns_pinctrl_ops, + .pmxops = &ns_pinctrl_pmxops, +}; + +static const struct of_device_id ns_pinctrl_of_match_table[] = { + { .compatible = "brcm,bcm4708-pinmux", .data = (void *)FLAG_BCM4708, }, + { .compatible = "brcm,bcm4709-pinmux", .data = (void *)FLAG_BCM4709, }, + { .compatible = "brcm,bcm53012-pinmux", .data = (void *)FLAG_BCM53012, }, + { } +}; + +static int ns_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; + struct ns_pinctrl *ns_pinctrl; + struct pinctrl_desc *pctldesc; + struct pinctrl_pin_desc *pin; + struct ns_pinctrl_group *group; + struct ns_pinctrl_function *function; + struct resource *res; + int i; + + ns_pinctrl = devm_kzalloc(dev, sizeof(*ns_pinctrl), GFP_KERNEL); + if (!ns_pinctrl) + return -ENOMEM; + pctldesc = &ns_pinctrl->pctldesc; + platform_set_drvdata(pdev, ns_pinctrl); + + /* Set basic properties */ + + ns_pinctrl->dev = dev; + + of_id = of_match_device(ns_pinctrl_of_match_table, dev); + if (!of_id) + return -EINVAL; + ns_pinctrl->chipset_flag = (uintptr_t)of_id->data; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "cru_gpio_control"); + ns_pinctrl->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ns_pinctrl->base)) { + dev_err(dev, "Failed to map pinctrl regs\n"); + return PTR_ERR(ns_pinctrl->base); + } + + memcpy(pctldesc, &ns_pinctrl_desc, sizeof(*pctldesc)); + + /* Set pinctrl properties */ + + pctldesc->pins = devm_kcalloc(dev, ARRAY_SIZE(ns_pinctrl_pins), + sizeof(struct pinctrl_pin_desc), + GFP_KERNEL); + if (!pctldesc->pins) + return -ENOMEM; + for (i = 0, pin = (struct pinctrl_pin_desc *)&pctldesc->pins[0]; + i < ARRAY_SIZE(ns_pinctrl_pins); i++) { + const struct pinctrl_pin_desc *src = &ns_pinctrl_pins[i]; + unsigned int chipsets = (uintptr_t)src->drv_data; + + if (chipsets & ns_pinctrl->chipset_flag) { + memcpy(pin++, src, sizeof(*src)); + pctldesc->npins++; + } + } + + ns_pinctrl->groups = devm_kcalloc(dev, ARRAY_SIZE(ns_pinctrl_groups), + sizeof(struct ns_pinctrl_group), + GFP_KERNEL); + if (!ns_pinctrl->groups) + return -ENOMEM; + for (i = 0, group = &ns_pinctrl->groups[0]; + i < ARRAY_SIZE(ns_pinctrl_groups); i++) { + const struct ns_pinctrl_group *src = &ns_pinctrl_groups[i]; + + if (src->chipsets & ns_pinctrl->chipset_flag) { + memcpy(group++, src, sizeof(*src)); + ns_pinctrl->num_groups++; + } + } + + ns_pinctrl->functions = devm_kcalloc(dev, + ARRAY_SIZE(ns_pinctrl_functions), + sizeof(struct ns_pinctrl_function), + GFP_KERNEL); + if (!ns_pinctrl->functions) + return -ENOMEM; + for (i = 0, function = &ns_pinctrl->functions[0]; + i < ARRAY_SIZE(ns_pinctrl_functions); i++) { + const struct ns_pinctrl_function *src = &ns_pinctrl_functions[i]; + + if (src->chipsets & ns_pinctrl->chipset_flag) { + memcpy(function++, src, sizeof(*src)); + ns_pinctrl->num_functions++; + } + } + + /* Register */ + + ns_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, ns_pinctrl); + if (IS_ERR(ns_pinctrl->pctldev)) { + dev_err(dev, "Failed to register pinctrl\n"); + return PTR_ERR(ns_pinctrl->pctldev); + } + + return 0; +} + +static struct platform_driver ns_pinctrl_driver = { + .probe = ns_pinctrl_probe, + .driver = { + .name = "ns-pinmux", + .of_match_table = ns_pinctrl_of_match_table, + }, +}; + +module_platform_driver(ns_pinctrl_driver); + +MODULE_AUTHOR("Rafał Miłecki"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, ns_pinctrl_of_match_table); diff --git a/drivers/pinctrl/berlin/berlin.c b/drivers/pinctrl/berlin/berlin.c index b5903fffb3d0..b17a03cf87be 100644 --- a/drivers/pinctrl/berlin/berlin.c +++ b/drivers/pinctrl/berlin/berlin.c @@ -64,16 +64,14 @@ static int berlin_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrl_dev, ret = of_property_read_string(node, "function", &function_name); if (ret) { dev_err(pctrl->dev, - "missing function property in node %s\n", - node->name); + "missing function property in node %pOFn\n", node); return -EINVAL; } ngroups = of_property_count_strings(node, "groups"); if (ngroups < 0) { dev_err(pctrl->dev, - "missing groups property in node %s\n", - node->name); + "missing groups property in node %pOFn\n", node); return -EINVAL; } diff --git a/drivers/pinctrl/cirrus/pinctrl-madera-core.c b/drivers/pinctrl/cirrus/pinctrl-madera-core.c index c4f4d904e4a6..a5dda832024a 100644 --- a/drivers/pinctrl/cirrus/pinctrl-madera-core.c +++ b/drivers/pinctrl/cirrus/pinctrl-madera-core.c @@ -550,7 +550,7 @@ static void __maybe_unused madera_pin_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " DRV=%umA", madera_pin_unmake_drv_str(priv, conf[1])); if (conf[0] & MADERA_GP1_IP_CFG_MASK) - seq_puts(s, "SCHMITT"); + seq_puts(s, " SCHMITT"); } @@ -608,7 +608,7 @@ static int madera_mux_set_mux(struct pinctrl_dev *pctldev, unsigned int n_chip_groups = priv->chip->n_pin_groups; const char *func_name = madera_mux_funcs[selector].name; unsigned int reg; - int i, ret; + int i, ret = 0; dev_dbg(priv->dev, "%s selecting %u (%s) for group %u (%s)\n", __func__, selector, func_name, group, @@ -801,7 +801,7 @@ static int madera_pin_conf_get(struct pinctrl_dev *pctldev, unsigned int pin, result = 1; break; default: - break; + return -ENOTSUPP; } *config = pinconf_to_config_packed(param, result); @@ -905,7 +905,7 @@ static int madera_pin_conf_set(struct pinctrl_dev *pctldev, unsigned int pin, conf[1] &= ~MADERA_GP1_DIR; break; default: - break; + return -ENOTSUPP; } ++configs; @@ -971,10 +971,10 @@ static int madera_pin_conf_group_set(struct pinctrl_dev *pctldev, } static const struct pinconf_ops madera_pin_conf_ops = { + .is_generic = true, .pin_config_get = madera_pin_conf_get, .pin_config_set = madera_pin_conf_set, .pin_config_group_set = madera_pin_conf_group_set, - }; static struct pinctrl_desc madera_pin_desc = { diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index a3dd777e3ce8..c6ff4d5fa482 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -627,7 +627,7 @@ static int pinctrl_generic_group_name_to_selector(struct pinctrl_dev *pctldev, while (selector < ngroups) { const char *gname = ops->get_group_name(pctldev, selector); - if (!strcmp(function, gname)) + if (gname && !strcmp(function, gname)) return selector; selector++; @@ -743,7 +743,7 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, while (group_selector < ngroups) { const char *gname = pctlops->get_group_name(pctldev, group_selector); - if (!strcmp(gname, pin_group)) { + if (gname && !strcmp(gname, pin_group)) { dev_dbg(pctldev->dev, "found group selector %u for %s\n", group_selector, diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index b04edc22dad7..4e8cf0e357c6 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -69,8 +69,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, */ grp = imx_pinctrl_find_group_by_name(pctldev, np->name); if (!grp) { - dev_err(ipctl->dev, "unable to find group for node %s\n", - np->name); + dev_err(ipctl->dev, "unable to find group for node %pOFn\n", np); return -EINVAL; } @@ -434,7 +433,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np, int i; u32 config; - dev_dbg(ipctl->dev, "group(%d): %s\n", index, np->name); + dev_dbg(ipctl->dev, "group(%d): %pOFn\n", index, np); if (info->flags & SHARE_MUX_CONF_REG) pin_size = FSL_PIN_SHARE_SIZE; @@ -544,7 +543,7 @@ static int imx_pinctrl_parse_functions(struct device_node *np, struct group_desc *grp; u32 i = 0; - dev_dbg(pctl->dev, "parse function(%d): %s\n", index, np->name); + dev_dbg(pctl->dev, "parse function(%d): %pOFn\n", index, np); func = pinmux_generic_get_function(pctl, index); if (!func) diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index deb7870b3d1a..7e29e3fecdb2 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -233,8 +233,8 @@ static int imx1_dt_node_to_map(struct pinctrl_dev *pctldev, */ grp = imx1_pinctrl_find_group_by_name(info, np->name); if (!grp) { - dev_err(info->dev, "unable to find group for node %s\n", - np->name); + dev_err(info->dev, "unable to find group for node %pOFn\n", + np); return -EINVAL; } @@ -466,7 +466,7 @@ static int imx1_pinctrl_parse_groups(struct device_node *np, const __be32 *list; int i; - dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + dev_dbg(info->dev, "group(%d): %pOFn\n", index, np); /* Initialise group */ grp->name = np->name; @@ -477,8 +477,8 @@ static int imx1_pinctrl_parse_groups(struct device_node *np, list = of_get_property(np, "fsl,pins", &size); /* we do not check return since it's safe node passed down */ if (!size || size % 12) { - dev_notice(info->dev, "Not a valid fsl,pins property (%s)\n", - np->name); + dev_notice(info->dev, "Not a valid fsl,pins property (%pOFn)\n", + np); return -EINVAL; } @@ -513,7 +513,7 @@ static int imx1_pinctrl_parse_functions(struct device_node *np, static u32 grp_index; u32 i = 0; - dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np); func = &info->functions[index]; diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c index a612e46ca51c..641b3088876f 100644 --- a/drivers/pinctrl/freescale/pinctrl-mxs.c +++ b/drivers/pinctrl/freescale/pinctrl-mxs.c @@ -556,4 +556,3 @@ err: iounmap(d->base); return ret; } -EXPORT_SYMBOL_GPL(mxs_pinctrl_probe); diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index f38d596efa05..6d1a43c0c251 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -6,18 +6,19 @@ * Author: Mathias Nyman <mathias.nyman@linux.intel.com> */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/types.h> +#include <linux/acpi.h> #include <linux/bitops.h> -#include <linux/interrupt.h> -#include <linux/gpio.h> #include <linux/gpio/driver.h> -#include <linux/acpi.h> -#include <linux/platform_device.h> -#include <linux/seq_file.h> +#include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/seq_file.h> + #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/pinconf.h> @@ -682,7 +683,7 @@ static const struct pinctrl_pin_desc byt_ncore_pins[] = { PINCTRL_PIN(27, "GPIO_NCORE27"), }; -static unsigned const byt_ncore_pins_map[BYT_NGPIO_NCORE] = { +static const unsigned int byt_ncore_pins_map[BYT_NGPIO_NCORE] = { 19, 18, 17, 20, 21, 22, 24, 25, 23, 16, 14, 15, 12, 26, 27, 1, 4, 8, 11, 0, 3, 6, 10, 13, 2, 5, 9, 7, @@ -926,7 +927,7 @@ static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, return 0; } -static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset) +static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned int offset) { /* SCORE pin 92-93 */ if (!strcmp(vg->soc_data->uid, BYT_SCORE_ACPI_UID) && @@ -1310,7 +1311,7 @@ static const struct pinctrl_desc byt_pinctrl_desc = { .owner = THIS_MODULE, }; -static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) +static int byt_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct byt_gpio *vg = gpiochip_get_data(chip); void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG); @@ -1324,7 +1325,7 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(val & BYT_LEVEL); } -static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static void byt_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct byt_gpio *vg = gpiochip_get_data(chip); void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG); @@ -1358,9 +1359,9 @@ static int byt_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) raw_spin_unlock_irqrestore(&vg->lock, flags); if (!(value & BYT_OUTPUT_EN)) - return GPIOF_DIR_OUT; + return 0; if (!(value & BYT_INPUT_EN)) - return GPIOF_DIR_IN; + return 1; return -EINVAL; } @@ -1495,7 +1496,7 @@ static void byt_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct byt_gpio *vg = gpiochip_get_data(gc); - unsigned offset = irqd_to_hwirq(d); + unsigned int offset = irqd_to_hwirq(d); void __iomem *reg; reg = byt_gpio_reg(vg, offset, BYT_INT_STAT_REG); @@ -1519,7 +1520,7 @@ static void byt_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct byt_gpio *vg = gpiochip_get_data(gc); - unsigned offset = irqd_to_hwirq(d); + unsigned int offset = irqd_to_hwirq(d); unsigned long flags; void __iomem *reg; u32 value; @@ -1775,13 +1776,11 @@ static const struct acpi_device_id byt_gpio_acpi_match[] = { { "INT33FC", (kernel_ulong_t)byt_soc_data }, { } }; -MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match); static int byt_pinctrl_probe(struct platform_device *pdev) { const struct byt_pinctrl_soc_data *soc_data = NULL; const struct byt_pinctrl_soc_data **soc_table; - const struct acpi_device_id *acpi_id; struct acpi_device *acpi_dev; struct byt_gpio *vg; int i, ret; @@ -1790,11 +1789,7 @@ static int byt_pinctrl_probe(struct platform_device *pdev) if (!acpi_dev) return -ENODEV; - acpi_id = acpi_match_device(byt_gpio_acpi_match, &pdev->dev); - if (!acpi_id) - return -ENODEV; - - soc_table = (const struct byt_pinctrl_soc_data **)acpi_id->driver_data; + soc_table = (const struct byt_pinctrl_soc_data **)device_get_match_data(&pdev->dev); for (i = 0; soc_table[i]; i++) { if (!strcmp(acpi_dev->pnp.unique_id, soc_table[i]->uid)) { diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c index 8b1c7b59ad3e..68fefd4618bd 100644 --- a/drivers/pinctrl/intel/pinctrl-broxton.c +++ b/drivers/pinctrl/intel/pinctrl-broxton.c @@ -6,10 +6,10 @@ * Author: Mika Westerberg <mika.westerberg@linux.intel.com> */ -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" @@ -117,17 +117,17 @@ static const struct pinctrl_pin_desc bxt_north_pins[] = { PINCTRL_PIN(82, "TDO"), }; -static const unsigned bxt_north_pwm0_pins[] = { 34 }; -static const unsigned bxt_north_pwm1_pins[] = { 35 }; -static const unsigned bxt_north_pwm2_pins[] = { 36 }; -static const unsigned bxt_north_pwm3_pins[] = { 37 }; -static const unsigned bxt_north_uart0_pins[] = { 38, 39, 40, 41 }; -static const unsigned bxt_north_uart1_pins[] = { 42, 43, 44, 45 }; -static const unsigned bxt_north_uart2_pins[] = { 46, 47, 48, 49 }; -static const unsigned bxt_north_uart0b_pins[] = { 50, 51, 52, 53 }; -static const unsigned bxt_north_uart1b_pins[] = { 54, 55, 56, 57 }; -static const unsigned bxt_north_uart2b_pins[] = { 58, 59, 60, 61 }; -static const unsigned bxt_north_uart3_pins[] = { 58, 59, 60, 61 }; +static const unsigned int bxt_north_pwm0_pins[] = { 34 }; +static const unsigned int bxt_north_pwm1_pins[] = { 35 }; +static const unsigned int bxt_north_pwm2_pins[] = { 36 }; +static const unsigned int bxt_north_pwm3_pins[] = { 37 }; +static const unsigned int bxt_north_uart0_pins[] = { 38, 39, 40, 41 }; +static const unsigned int bxt_north_uart1_pins[] = { 42, 43, 44, 45 }; +static const unsigned int bxt_north_uart2_pins[] = { 46, 47, 48, 49 }; +static const unsigned int bxt_north_uart0b_pins[] = { 50, 51, 52, 53 }; +static const unsigned int bxt_north_uart1b_pins[] = { 54, 55, 56, 57 }; +static const unsigned int bxt_north_uart2b_pins[] = { 58, 59, 60, 61 }; +static const unsigned int bxt_north_uart3_pins[] = { 58, 59, 60, 61 }; static const struct intel_pingroup bxt_north_groups[] = { PIN_GROUP("pwm0_grp", bxt_north_pwm0_pins, 1), @@ -260,12 +260,12 @@ static const struct pinctrl_pin_desc bxt_northwest_pins[] = { PINCTRL_PIN(71, "GP_SSP_2_TXD"), }; -static const unsigned bxt_northwest_ssp0_pins[] = { 53, 54, 55, 56, 57, 58 }; -static const unsigned bxt_northwest_ssp1_pins[] = { +static const unsigned int bxt_northwest_ssp0_pins[] = { 53, 54, 55, 56, 57, 58 }; +static const unsigned int bxt_northwest_ssp1_pins[] = { 59, 60, 61, 62, 63, 64, 65 }; -static const unsigned bxt_northwest_ssp2_pins[] = { 66, 67, 68, 69, 70, 71 }; -static const unsigned bxt_northwest_uart3_pins[] = { 67, 68, 69, 70 }; +static const unsigned int bxt_northwest_ssp2_pins[] = { 66, 67, 68, 69, 70, 71 }; +static const unsigned int bxt_northwest_uart3_pins[] = { 67, 68, 69, 70 }; static const struct intel_pingroup bxt_northwest_groups[] = { PIN_GROUP("ssp0_grp", bxt_northwest_ssp0_pins, 1), @@ -347,17 +347,17 @@ static const struct pinctrl_pin_desc bxt_west_pins[] = { PINCTRL_PIN(41, "OSC_CLK_OUT_3"), }; -static const unsigned bxt_west_i2c0_pins[] = { 0, 1 }; -static const unsigned bxt_west_i2c1_pins[] = { 2, 3 }; -static const unsigned bxt_west_i2c2_pins[] = { 4, 5 }; -static const unsigned bxt_west_i2c3_pins[] = { 6, 7 }; -static const unsigned bxt_west_i2c4_pins[] = { 8, 9 }; -static const unsigned bxt_west_i2c5_pins[] = { 10, 11 }; -static const unsigned bxt_west_i2c6_pins[] = { 12, 13 }; -static const unsigned bxt_west_i2c7_pins[] = { 14, 15 }; -static const unsigned bxt_west_i2c5b_pins[] = { 16, 17 }; -static const unsigned bxt_west_i2c6b_pins[] = { 18, 19 }; -static const unsigned bxt_west_i2c7b_pins[] = { 20, 21 }; +static const unsigned int bxt_west_i2c0_pins[] = { 0, 1 }; +static const unsigned int bxt_west_i2c1_pins[] = { 2, 3 }; +static const unsigned int bxt_west_i2c2_pins[] = { 4, 5 }; +static const unsigned int bxt_west_i2c3_pins[] = { 6, 7 }; +static const unsigned int bxt_west_i2c4_pins[] = { 8, 9 }; +static const unsigned int bxt_west_i2c5_pins[] = { 10, 11 }; +static const unsigned int bxt_west_i2c6_pins[] = { 12, 13 }; +static const unsigned int bxt_west_i2c7_pins[] = { 14, 15 }; +static const unsigned int bxt_west_i2c5b_pins[] = { 16, 17 }; +static const unsigned int bxt_west_i2c6b_pins[] = { 18, 19 }; +static const unsigned int bxt_west_i2c7b_pins[] = { 20, 21 }; static const struct intel_pingroup bxt_west_groups[] = { PIN_GROUP("i2c0_grp", bxt_west_i2c0_pins, 1), @@ -443,13 +443,13 @@ static const struct pinctrl_pin_desc bxt_southwest_pins[] = { PINCTRL_PIN(30, "SDCARD_LVL_WP"), }; -static const unsigned bxt_southwest_emmc0_pins[] = { +static const unsigned int bxt_southwest_emmc0_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 26, }; -static const unsigned bxt_southwest_sdio_pins[] = { +static const unsigned int bxt_southwest_sdio_pins[] = { 10, 11, 12, 13, 14, 15, 27, }; -static const unsigned bxt_southwest_sdcard_pins[] = { +static const unsigned int bxt_southwest_sdcard_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, }; @@ -611,13 +611,13 @@ static const struct pinctrl_pin_desc apl_north_pins[] = { PINCTRL_PIN(77, "SVID0_CLK"), }; -static const unsigned apl_north_pwm0_pins[] = { 34 }; -static const unsigned apl_north_pwm1_pins[] = { 35 }; -static const unsigned apl_north_pwm2_pins[] = { 36 }; -static const unsigned apl_north_pwm3_pins[] = { 37 }; -static const unsigned apl_north_uart0_pins[] = { 38, 39, 40, 41 }; -static const unsigned apl_north_uart1_pins[] = { 42, 43, 44, 45 }; -static const unsigned apl_north_uart2_pins[] = { 46, 47, 48, 49 }; +static const unsigned int apl_north_pwm0_pins[] = { 34 }; +static const unsigned int apl_north_pwm1_pins[] = { 35 }; +static const unsigned int apl_north_pwm2_pins[] = { 36 }; +static const unsigned int apl_north_pwm3_pins[] = { 37 }; +static const unsigned int apl_north_uart0_pins[] = { 38, 39, 40, 41 }; +static const unsigned int apl_north_uart1_pins[] = { 42, 43, 44, 45 }; +static const unsigned int apl_north_uart2_pins[] = { 46, 47, 48, 49 }; static const struct intel_pingroup apl_north_groups[] = { PIN_GROUP("pwm0_grp", apl_north_pwm0_pins, 1), @@ -743,10 +743,10 @@ static const struct pinctrl_pin_desc apl_northwest_pins[] = { PINCTRL_PIN(76, "GP_SSP_2_TXD"), }; -static const unsigned apl_northwest_ssp0_pins[] = { 61, 62, 63, 64, 65 }; -static const unsigned apl_northwest_ssp1_pins[] = { 66, 67, 68, 69, 70 }; -static const unsigned apl_northwest_ssp2_pins[] = { 71, 72, 73, 74, 75, 76 }; -static const unsigned apl_northwest_uart3_pins[] = { 67, 68, 69, 70 }; +static const unsigned int apl_northwest_ssp0_pins[] = { 61, 62, 63, 64, 65 }; +static const unsigned int apl_northwest_ssp1_pins[] = { 66, 67, 68, 69, 70 }; +static const unsigned int apl_northwest_ssp2_pins[] = { 71, 72, 73, 74, 75, 76 }; +static const unsigned int apl_northwest_uart3_pins[] = { 67, 68, 69, 70 }; static const struct intel_pingroup apl_northwest_groups[] = { PIN_GROUP("ssp0_grp", apl_northwest_ssp0_pins, 1), @@ -833,15 +833,15 @@ static const struct pinctrl_pin_desc apl_west_pins[] = { PINCTRL_PIN(46, "SUSPWRDNACK"), }; -static const unsigned apl_west_i2c0_pins[] = { 0, 1 }; -static const unsigned apl_west_i2c1_pins[] = { 2, 3 }; -static const unsigned apl_west_i2c2_pins[] = { 4, 5 }; -static const unsigned apl_west_i2c3_pins[] = { 6, 7 }; -static const unsigned apl_west_i2c4_pins[] = { 8, 9 }; -static const unsigned apl_west_i2c5_pins[] = { 10, 11 }; -static const unsigned apl_west_i2c6_pins[] = { 12, 13 }; -static const unsigned apl_west_i2c7_pins[] = { 14, 15 }; -static const unsigned apl_west_uart2_pins[] = { 20, 21, 22, 34 }; +static const unsigned int apl_west_i2c0_pins[] = { 0, 1 }; +static const unsigned int apl_west_i2c1_pins[] = { 2, 3 }; +static const unsigned int apl_west_i2c2_pins[] = { 4, 5 }; +static const unsigned int apl_west_i2c3_pins[] = { 6, 7 }; +static const unsigned int apl_west_i2c4_pins[] = { 8, 9 }; +static const unsigned int apl_west_i2c5_pins[] = { 10, 11 }; +static const unsigned int apl_west_i2c6_pins[] = { 12, 13 }; +static const unsigned int apl_west_i2c7_pins[] = { 14, 15 }; +static const unsigned int apl_west_uart2_pins[] = { 20, 21, 22, 34 }; static const struct intel_pingroup apl_west_groups[] = { PIN_GROUP("i2c0_grp", apl_west_i2c0_pins, 1), @@ -939,16 +939,16 @@ static const struct pinctrl_pin_desc apl_southwest_pins[] = { PINCTRL_PIN(42, "LPC_FRAMEB"), }; -static const unsigned apl_southwest_emmc0_pins[] = { +static const unsigned int apl_southwest_emmc0_pins[] = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 29, }; -static const unsigned apl_southwest_sdio_pins[] = { +static const unsigned int apl_southwest_sdio_pins[] = { 14, 15, 16, 17, 18, 19, 30, }; -static const unsigned apl_southwest_sdcard_pins[] = { +static const unsigned int apl_southwest_sdcard_pins[] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, }; -static const unsigned apl_southwest_i2c7_pins[] = { 32, 33 }; +static const unsigned int apl_southwest_i2c7_pins[] = { 32, 33 }; static const struct intel_pingroup apl_southwest_groups[] = { PIN_GROUP("emmc0_grp", apl_southwest_emmc0_pins, 1), @@ -1008,50 +1008,10 @@ static const struct platform_device_id bxt_pinctrl_platform_ids[] = { static int bxt_pinctrl_probe(struct platform_device *pdev) { - const struct intel_pinctrl_soc_data *soc_data = NULL; - const struct intel_pinctrl_soc_data **soc_table; - struct acpi_device *adev; - int i; - - adev = ACPI_COMPANION(&pdev->dev); - if (adev) { - const struct acpi_device_id *id; - - id = acpi_match_device(bxt_pinctrl_acpi_match, &pdev->dev); - if (!id) - return -ENODEV; - - soc_table = (const struct intel_pinctrl_soc_data **) - id->driver_data; - - for (i = 0; soc_table[i]; i++) { - if (!strcmp(adev->pnp.unique_id, soc_table[i]->uid)) { - soc_data = soc_table[i]; - break; - } - } - } else { - const struct platform_device_id *pid; - - pid = platform_get_device_id(pdev); - if (!pid) - return -ENODEV; - - soc_table = (const struct intel_pinctrl_soc_data **) - pid->driver_data; - soc_data = soc_table[pdev->id]; - } - - if (!soc_data) - return -ENODEV; - - return intel_pinctrl_probe(pdev, soc_data); + return intel_pinctrl_probe_by_uid(pdev); } -static const struct dev_pm_ops bxt_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(bxt_pinctrl_pm_ops); static struct platform_driver bxt_pinctrl_driver = { .probe = bxt_pinctrl_probe, diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c index e7f45d96b0cb..fb121b3ed2f2 100644 --- a/drivers/pinctrl/intel/pinctrl-cannonlake.c +++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c @@ -7,10 +7,10 @@ * Mika Westerberg <mika.westerberg@linux.intel.com> */ -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" @@ -835,21 +835,10 @@ MODULE_DEVICE_TABLE(acpi, cnl_pinctrl_acpi_match); static int cnl_pinctrl_probe(struct platform_device *pdev) { - const struct intel_pinctrl_soc_data *soc_data; - const struct acpi_device_id *id; - - id = acpi_match_device(cnl_pinctrl_acpi_match, &pdev->dev); - if (!id || !id->driver_data) - return -ENODEV; - - soc_data = (const struct intel_pinctrl_soc_data *)id->driver_data; - return intel_pinctrl_probe(pdev, soc_data); + return intel_pinctrl_probe_by_hid(pdev); } -static const struct dev_pm_ops cnl_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(cnl_pinctrl_pm_ops); static struct platform_driver cnl_pinctrl_driver = { .probe = cnl_pinctrl_probe, diff --git a/drivers/pinctrl/intel/pinctrl-cedarfork.c b/drivers/pinctrl/intel/pinctrl-cedarfork.c index c788e37e338e..7e068fc61ce1 100644 --- a/drivers/pinctrl/intel/pinctrl-cedarfork.c +++ b/drivers/pinctrl/intel/pinctrl-cedarfork.c @@ -9,7 +9,7 @@ #include <linux/acpi.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" @@ -335,10 +335,7 @@ static int cdf_pinctrl_probe(struct platform_device *pdev) return intel_pinctrl_probe(pdev, &cdf_soc_data); } -static const struct dev_pm_ops cdf_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(cdf_pinctrl_pm_ops); static const struct acpi_device_id cdf_pinctrl_acpi_match[] = { { "INTC3001" }, diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index 6d31ad799987..9b0f4b9ef482 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -10,19 +10,20 @@ * Alan Cox <alan@linux.intel.com> */ +#include <linux/acpi.h> #include <linux/dmi.h> +#include <linux/gpio/driver.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> +#include <linux/platform_device.h> #include <linux/types.h> -#include <linux/gpio.h> -#include <linux/gpio/driver.h> -#include <linux/acpi.h> + #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> -#include <linux/platform_device.h> + +#include "pinctrl-intel.h" #define CHV_INTSTAT 0x300 #define CHV_INTMASK 0x380 @@ -73,7 +74,7 @@ * @invert_oe: Invert OE for this pin */ struct chv_alternate_function { - unsigned pin; + unsigned int pin; u8 mode; bool invert_oe; }; @@ -90,7 +91,7 @@ struct chv_alternate_function { */ struct chv_pingroup { const char *name; - const unsigned *pins; + const unsigned int *pins; size_t npins; struct chv_alternate_function altfunc; const struct chv_alternate_function *overrides; @@ -98,25 +99,13 @@ struct chv_pingroup { }; /** - * struct chv_function - A CHV pinmux function - * @name: Name of the function - * @groups: An array of groups for this function - * @ngroups: Number of groups in @groups - */ -struct chv_function { - const char *name; - const char * const *groups; - size_t ngroups; -}; - -/** * struct chv_gpio_pinrange - A range of pins that can be used as GPIOs * @base: Start pin number * @npins: Number of pins in this range */ struct chv_gpio_pinrange { - unsigned base; - unsigned npins; + unsigned int base; + unsigned int npins; }; /** @@ -131,6 +120,7 @@ struct chv_gpio_pinrange { * @gpio_ranges: An array of GPIO ranges in this community * @ngpio_ranges: Number of GPIO ranges * @nirqs: Total number of IRQs this community can generate + * @acpi_space_id: An address space ID for ACPI OpRegion handler */ struct chv_community { const char *uid; @@ -138,7 +128,7 @@ struct chv_community { size_t npins; const struct chv_pingroup *groups; size_t ngroups; - const struct chv_function *functions; + const struct intel_function *functions; size_t nfunctions; const struct chv_gpio_pinrange *gpio_ranges; size_t ngpio_ranges; @@ -161,6 +151,8 @@ struct chv_pin_context { * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO * offset (in GPIO number space) * @community: Community this pinctrl instance represents + * @saved_intmask: Interrupt mask saved for system sleep + * @saved_pin_context: Pointer to a context of the pins saved for system sleep * * The first group in @groups is expected to contain all pins that can be * used as GPIOs. @@ -184,7 +176,7 @@ struct chv_pinctrl { .invert_oe = (i), \ } -#define PIN_GROUP(n, p, m, i) \ +#define PIN_GROUP_WITH_ALT(n, p, m, i) \ { \ .name = (n), \ .pins = (p), \ @@ -204,13 +196,6 @@ struct chv_pinctrl { .noverrides = ARRAY_SIZE((o)), \ } -#define FUNCTION(n, g) \ - { \ - .name = (n), \ - .groups = (g), \ - .ngroups = ARRAY_SIZE((g)), \ - } - #define GPIO_PINRANGE(start, end) \ { \ .base = (start), \ @@ -282,7 +267,6 @@ static const struct pinctrl_pin_desc southwest_pins[] = { PINCTRL_PIN(97, "GP_SSP_2_TXD"), }; -static const unsigned southwest_fspi_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; static const unsigned southwest_uart0_pins[] = { 16, 20 }; static const unsigned southwest_uart1_pins[] = { 15, 16, 18, 20 }; static const unsigned southwest_uart2_pins[] = { 17, 19, 21, 22 }; @@ -298,7 +282,6 @@ static const unsigned southwest_i2c4_pins[] = { 46, 50 }; static const unsigned southwest_i2c5_pins[] = { 45, 48 }; static const unsigned southwest_i2c6_pins[] = { 47, 51 }; static const unsigned southwest_i2c_nfc_pins[] = { 49, 52 }; -static const unsigned southwest_smbus_pins[] = { 79, 81, 82 }; static const unsigned southwest_spi3_pins[] = { 76, 79, 80, 81, 82 }; /* LPE I2S TXD pins need to have invert_oe set */ @@ -318,18 +301,18 @@ static const struct chv_alternate_function southwest_spi3_altfuncs[] = { }; static const struct chv_pingroup southwest_groups[] = { - PIN_GROUP("uart0_grp", southwest_uart0_pins, 2, false), - PIN_GROUP("uart1_grp", southwest_uart1_pins, 1, false), - PIN_GROUP("uart2_grp", southwest_uart2_pins, 1, false), - PIN_GROUP("hda_grp", southwest_hda_pins, 2, false), - PIN_GROUP("i2c0_grp", southwest_i2c0_pins, 1, true), - PIN_GROUP("i2c1_grp", southwest_i2c1_pins, 1, true), - PIN_GROUP("i2c2_grp", southwest_i2c2_pins, 1, true), - PIN_GROUP("i2c3_grp", southwest_i2c3_pins, 1, true), - PIN_GROUP("i2c4_grp", southwest_i2c4_pins, 1, true), - PIN_GROUP("i2c5_grp", southwest_i2c5_pins, 1, true), - PIN_GROUP("i2c6_grp", southwest_i2c6_pins, 1, true), - PIN_GROUP("i2c_nfc_grp", southwest_i2c_nfc_pins, 2, true), + PIN_GROUP_WITH_ALT("uart0_grp", southwest_uart0_pins, 2, false), + PIN_GROUP_WITH_ALT("uart1_grp", southwest_uart1_pins, 1, false), + PIN_GROUP_WITH_ALT("uart2_grp", southwest_uart2_pins, 1, false), + PIN_GROUP_WITH_ALT("hda_grp", southwest_hda_pins, 2, false), + PIN_GROUP_WITH_ALT("i2c0_grp", southwest_i2c0_pins, 1, true), + PIN_GROUP_WITH_ALT("i2c1_grp", southwest_i2c1_pins, 1, true), + PIN_GROUP_WITH_ALT("i2c2_grp", southwest_i2c2_pins, 1, true), + PIN_GROUP_WITH_ALT("i2c3_grp", southwest_i2c3_pins, 1, true), + PIN_GROUP_WITH_ALT("i2c4_grp", southwest_i2c4_pins, 1, true), + PIN_GROUP_WITH_ALT("i2c5_grp", southwest_i2c5_pins, 1, true), + PIN_GROUP_WITH_ALT("i2c6_grp", southwest_i2c6_pins, 1, true), + PIN_GROUP_WITH_ALT("i2c_nfc_grp", southwest_i2c_nfc_pins, 2, true), PIN_GROUP_WITH_OVERRIDE("lpe_grp", southwest_lpe_pins, 1, false, southwest_lpe_altfuncs), @@ -356,7 +339,7 @@ static const char * const southwest_spi3_groups[] = { "spi3_grp" }; * Only do pinmuxing for certain LPSS devices for now. Rest of the pins are * enabled only as GPIOs. */ -static const struct chv_function southwest_functions[] = { +static const struct intel_function southwest_functions[] = { FUNCTION("uart0", southwest_uart0_groups), FUNCTION("uart1", southwest_uart1_groups), FUNCTION("uart2", southwest_uart2_groups), @@ -610,13 +593,13 @@ static const unsigned southeast_spi1_pins[] = { 60, 61, 62, 64, 66 }; static const unsigned southeast_spi2_pins[] = { 2, 3, 4, 6, 7 }; static const struct chv_pingroup southeast_groups[] = { - PIN_GROUP("pwm0_grp", southeast_pwm0_pins, 1, false), - PIN_GROUP("pwm1_grp", southeast_pwm1_pins, 1, false), - PIN_GROUP("sdmmc1_grp", southeast_sdmmc1_pins, 1, false), - PIN_GROUP("sdmmc2_grp", southeast_sdmmc2_pins, 1, false), - PIN_GROUP("sdmmc3_grp", southeast_sdmmc3_pins, 1, false), - PIN_GROUP("spi1_grp", southeast_spi1_pins, 1, false), - PIN_GROUP("spi2_grp", southeast_spi2_pins, 4, false), + PIN_GROUP_WITH_ALT("pwm0_grp", southeast_pwm0_pins, 1, false), + PIN_GROUP_WITH_ALT("pwm1_grp", southeast_pwm1_pins, 1, false), + PIN_GROUP_WITH_ALT("sdmmc1_grp", southeast_sdmmc1_pins, 1, false), + PIN_GROUP_WITH_ALT("sdmmc2_grp", southeast_sdmmc2_pins, 1, false), + PIN_GROUP_WITH_ALT("sdmmc3_grp", southeast_sdmmc3_pins, 1, false), + PIN_GROUP_WITH_ALT("spi1_grp", southeast_spi1_pins, 1, false), + PIN_GROUP_WITH_ALT("spi2_grp", southeast_spi2_pins, 4, false), }; static const char * const southeast_pwm0_groups[] = { "pwm0_grp" }; @@ -627,7 +610,7 @@ static const char * const southeast_sdmmc3_groups[] = { "sdmmc3_grp" }; static const char * const southeast_spi1_groups[] = { "spi1_grp" }; static const char * const southeast_spi2_groups[] = { "spi2_grp" }; -static const struct chv_function southeast_functions[] = { +static const struct intel_function southeast_functions[] = { FUNCTION("pwm0", southeast_pwm0_groups), FUNCTION("pwm1", southeast_pwm1_groups), FUNCTION("sdmmc1", southeast_sdmmc1_groups), @@ -678,11 +661,11 @@ static const struct chv_community *chv_communities[] = { */ static DEFINE_RAW_SPINLOCK(chv_lock); -static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset, - unsigned reg) +static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned int offset, + unsigned int reg) { - unsigned family_no = offset / MAX_FAMILY_PAD_GPIO_NO; - unsigned pad_no = offset % MAX_FAMILY_PAD_GPIO_NO; + unsigned int family_no = offset / MAX_FAMILY_PAD_GPIO_NO; + unsigned int pad_no = offset % MAX_FAMILY_PAD_GPIO_NO; offset = FAMILY_PAD_REGS_OFF + FAMILY_PAD_REGS_SIZE * family_no + GPIO_REGS_SIZE * pad_no; @@ -698,7 +681,7 @@ static void chv_writel(u32 value, void __iomem *reg) } /* When Pad Cfg is locked, driver can only change GPIOTXState or GPIORXState */ -static bool chv_pad_locked(struct chv_pinctrl *pctrl, unsigned offset) +static bool chv_pad_locked(struct chv_pinctrl *pctrl, unsigned int offset) { void __iomem *reg; @@ -714,15 +697,15 @@ static int chv_get_groups_count(struct pinctrl_dev *pctldev) } static const char *chv_get_group_name(struct pinctrl_dev *pctldev, - unsigned group) + unsigned int group) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); return pctrl->community->groups[group].name; } -static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, - const unsigned **pins, unsigned *npins) +static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, + const unsigned int **pins, unsigned int *npins) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -732,7 +715,7 @@ static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, } static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned offset) + unsigned int offset) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); unsigned long flags; @@ -779,7 +762,7 @@ static int chv_get_functions_count(struct pinctrl_dev *pctldev) } static const char *chv_get_function_name(struct pinctrl_dev *pctldev, - unsigned function) + unsigned int function) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -787,9 +770,9 @@ static const char *chv_get_function_name(struct pinctrl_dev *pctldev, } static int chv_get_function_groups(struct pinctrl_dev *pctldev, - unsigned function, + unsigned int function, const char * const **groups, - unsigned * const ngroups) + unsigned int * const ngroups) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -798,8 +781,8 @@ static int chv_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, - unsigned group) +static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct chv_pingroup *grp; @@ -865,7 +848,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, - unsigned offset) + unsigned int offset) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); unsigned long flags; @@ -925,7 +908,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, static void chv_gpio_disable_free(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, - unsigned offset) + unsigned int offset) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); unsigned long flags; @@ -943,7 +926,7 @@ static void chv_gpio_disable_free(struct pinctrl_dev *pctldev, static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, - unsigned offset, bool input) + unsigned int offset, bool input) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); @@ -974,7 +957,7 @@ static const struct pinmux_ops chv_pinmux_ops = { .gpio_set_direction = chv_gpio_set_direction, }; -static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin, +static int chv_config_get(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *config) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -1054,7 +1037,7 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin, return 0; } -static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, +static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned int pin, enum pin_config_param param, u32 arg) { void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL0); @@ -1141,8 +1124,8 @@ static int chv_config_set_oden(struct chv_pinctrl *pctrl, unsigned int pin, return 0; } -static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin, - unsigned long *configs, unsigned nconfigs) +static int chv_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int nconfigs) { struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); enum pin_config_param param; @@ -1243,7 +1226,7 @@ static struct pinctrl_desc chv_pinctrl_desc = { .owner = THIS_MODULE, }; -static int chv_gpio_get(struct gpio_chip *chip, unsigned offset) +static int chv_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct chv_pinctrl *pctrl = gpiochip_get_data(chip); unsigned long flags; @@ -1261,7 +1244,7 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(ctrl0 & CHV_PADCTRL0_GPIORXSTATE); } -static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static void chv_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct chv_pinctrl *pctrl = gpiochip_get_data(chip); unsigned long flags; @@ -1283,7 +1266,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) raw_spin_unlock_irqrestore(&chv_lock, flags); } -static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { struct chv_pinctrl *pctrl = gpiochip_get_data(chip); u32 ctrl0, direction; @@ -1299,12 +1282,12 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) return direction != CHV_PADCTRL0_GPIOCFG_GPO; } -static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { return pinctrl_gpio_direction_input(chip->base + offset); } -static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset, +static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { chv_gpio_set(chip, offset, value); @@ -1388,7 +1371,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct chv_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = irqd_to_hwirq(d); + unsigned int pin = irqd_to_hwirq(d); irq_flow_handler_t handler; unsigned long flags; u32 intsel, value; @@ -1415,11 +1398,11 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) return 0; } -static int chv_gpio_irq_type(struct irq_data *d, unsigned type) +static int chv_gpio_irq_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct chv_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = irqd_to_hwirq(d); + unsigned int pin = irqd_to_hwirq(d); unsigned long flags; u32 value; diff --git a/drivers/pinctrl/intel/pinctrl-denverton.c b/drivers/pinctrl/intel/pinctrl-denverton.c index f321ab0d76e5..88bc55281b83 100644 --- a/drivers/pinctrl/intel/pinctrl-denverton.c +++ b/drivers/pinctrl/intel/pinctrl-denverton.c @@ -9,7 +9,7 @@ #include <linux/acpi.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" @@ -262,10 +262,7 @@ static int dnv_pinctrl_probe(struct platform_device *pdev) return intel_pinctrl_probe(pdev, &dnv_soc_data); } -static const struct dev_pm_ops dnv_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(dnv_pinctrl_pm_ops); static const struct acpi_device_id dnv_pinctrl_acpi_match[] = { { "INTC3000" }, diff --git a/drivers/pinctrl/intel/pinctrl-geminilake.c b/drivers/pinctrl/intel/pinctrl-geminilake.c index 5c4c96752fc1..67600314454c 100644 --- a/drivers/pinctrl/intel/pinctrl-geminilake.c +++ b/drivers/pinctrl/intel/pinctrl-geminilake.c @@ -6,17 +6,17 @@ * Author: Mika Westerberg <mika.westerberg@linux.intel.com> */ -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" #define GLK_PAD_OWN 0x020 -#define GLK_HOSTSW_OWN 0x0b0 #define GLK_PADCFGLOCK 0x080 +#define GLK_HOSTSW_OWN 0x0b0 #define GLK_GPI_IE 0x110 #define GLK_COMMUNITY(s, e) \ @@ -58,16 +58,16 @@ static const struct pinctrl_pin_desc glk_northwest_pins[] = { PINCTRL_PIN(23, "GPIO_23"), PINCTRL_PIN(24, "GPIO_24"), PINCTRL_PIN(25, "GPIO_25"), - PINCTRL_PIN(26, "GPIO_26"), - PINCTRL_PIN(27, "GPIO_27"), - PINCTRL_PIN(28, "GPIO_28"), - PINCTRL_PIN(29, "GPIO_29"), - PINCTRL_PIN(30, "GPIO_30"), - PINCTRL_PIN(31, "GPIO_31"), - PINCTRL_PIN(32, "GPIO_32"), - PINCTRL_PIN(33, "GPIO_33"), - PINCTRL_PIN(34, "GPIO_34"), - PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(26, "ISH_GPIO_0"), + PINCTRL_PIN(27, "ISH_GPIO_1"), + PINCTRL_PIN(28, "ISH_GPIO_2"), + PINCTRL_PIN(29, "ISH_GPIO_3"), + PINCTRL_PIN(30, "ISH_GPIO_4"), + PINCTRL_PIN(31, "ISH_GPIO_5"), + PINCTRL_PIN(32, "ISH_GPIO_6"), + PINCTRL_PIN(33, "ISH_GPIO_7"), + PINCTRL_PIN(34, "ISH_GPIO_8"), + PINCTRL_PIN(35, "ISH_GPIO_9"), PINCTRL_PIN(36, "GPIO_36"), PINCTRL_PIN(37, "GPIO_37"), PINCTRL_PIN(38, "GPIO_38"), @@ -195,12 +195,12 @@ static const struct pinctrl_pin_desc glk_north_pins[] = { PINCTRL_PIN(5, "LPSS_SPI_0_FS1"), PINCTRL_PIN(6, "LPSS_SPI_0_RXD"), PINCTRL_PIN(7, "LPSS_SPI_0_TXD"), - PINCTRL_PIN(8, "LPSS_SPI_1_CLK"), - PINCTRL_PIN(9, "LPSS_SPI_1_FS0"), - PINCTRL_PIN(10, "LPSS_SPI_1_FS1"), - PINCTRL_PIN(11, "LPSS_SPI_1_FS2"), - PINCTRL_PIN(12, "LPSS_SPI_1_RXD"), - PINCTRL_PIN(13, "LPSS_SPI_1_TXD"), + PINCTRL_PIN(8, "LPSS_SPI_2_CLK"), + PINCTRL_PIN(9, "LPSS_SPI_2_FS0"), + PINCTRL_PIN(10, "LPSS_SPI_2_FS1"), + PINCTRL_PIN(11, "LPSS_SPI_2_FS2"), + PINCTRL_PIN(12, "LPSS_SPI_2_RXD"), + PINCTRL_PIN(13, "LPSS_SPI_2_TXD"), PINCTRL_PIN(14, "FST_SPI_CS0_B"), PINCTRL_PIN(15, "FST_SPI_CS1_B"), PINCTRL_PIN(16, "FST_SPI_MOSI_IO0"), @@ -215,8 +215,8 @@ static const struct pinctrl_pin_desc glk_north_pins[] = { PINCTRL_PIN(25, "PMU_SLP_S3_B"), PINCTRL_PIN(26, "PMU_SLP_S4_B"), PINCTRL_PIN(27, "SUSPWRDNACK"), - PINCTRL_PIN(28, "EMMC_PWR_EN_B"), - PINCTRL_PIN(29, "PMU_AC_PRESENT"), + PINCTRL_PIN(28, "EMMC_DNX_PWR_EN_B"), + PINCTRL_PIN(29, "GPIO_105"), PINCTRL_PIN(30, "PMU_BATLOW_B"), PINCTRL_PIN(31, "PMU_RESETBUTTON_B"), PINCTRL_PIN(32, "PMU_SUSCLK"), @@ -449,42 +449,15 @@ static const struct intel_pinctrl_soc_data *glk_pinctrl_soc_data[] = { }; static const struct acpi_device_id glk_pinctrl_acpi_match[] = { - { "INT3453" }, + { "INT3453", (kernel_ulong_t)glk_pinctrl_soc_data }, { } }; MODULE_DEVICE_TABLE(acpi, glk_pinctrl_acpi_match); -static int glk_pinctrl_probe(struct platform_device *pdev) -{ - const struct intel_pinctrl_soc_data *soc_data = NULL; - struct acpi_device *adev; - int i; - - adev = ACPI_COMPANION(&pdev->dev); - if (!adev) - return -ENODEV; - - for (i = 0; glk_pinctrl_soc_data[i]; i++) { - if (!strcmp(adev->pnp.unique_id, - glk_pinctrl_soc_data[i]->uid)) { - soc_data = glk_pinctrl_soc_data[i]; - break; - } - } - - if (!soc_data) - return -ENODEV; - - return intel_pinctrl_probe(pdev, soc_data); -} - -static const struct dev_pm_ops glk_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(glk_pinctrl_pm_ops); static struct platform_driver glk_pinctrl_driver = { - .probe = glk_pinctrl_probe, + .probe = intel_pinctrl_probe_by_uid, .driver = { .name = "geminilake-pinctrl", .acpi_match_table = glk_pinctrl_acpi_match, diff --git a/drivers/pinctrl/intel/pinctrl-icelake.c b/drivers/pinctrl/intel/pinctrl-icelake.c index 630b966ce081..f33a5deafb97 100644 --- a/drivers/pinctrl/intel/pinctrl-icelake.c +++ b/drivers/pinctrl/intel/pinctrl-icelake.c @@ -10,7 +10,7 @@ #include <linux/acpi.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" @@ -408,10 +408,7 @@ static int icl_pinctrl_probe(struct platform_device *pdev) return intel_pinctrl_probe(pdev, &icllp_soc_data); } -static const struct dev_pm_ops icl_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(icl_pinctrl_pm_ops); static const struct acpi_device_id icl_pinctrl_acpi_match[] = { { "INT3455" }, diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 1ea3438ea67e..8cda7b535b02 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -7,11 +7,14 @@ * Mika Westerberg <mika.westerberg@linux.intel.com> */ +#include <linux/acpi.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/gpio/driver.h> #include <linux/log2.h> #include <linux/platform_device.h> +#include <linux/property.h> + #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/pinconf.h> @@ -115,7 +118,7 @@ struct intel_pinctrl { #define padgroup_offset(g, p) ((p) - (g)->base) static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, - unsigned pin) + unsigned int pin) { struct intel_community *community; int i; @@ -133,7 +136,7 @@ static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, static const struct intel_padgroup * intel_community_get_padgroup(const struct intel_community *community, - unsigned pin) + unsigned int pin) { int i; @@ -147,11 +150,11 @@ intel_community_get_padgroup(const struct intel_community *community, return NULL; } -static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin, - unsigned reg) +static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, + unsigned int pin, unsigned int reg) { const struct intel_community *community; - unsigned padno; + unsigned int padno; size_t nregs; community = intel_get_community(pctrl, pin); @@ -167,11 +170,11 @@ static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin, return community->pad_regs + reg + padno * nregs * 4; } -static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin) +static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin) { const struct intel_community *community; const struct intel_padgroup *padgrp; - unsigned gpp, offset, gpp_offset; + unsigned int gpp, offset, gpp_offset; void __iomem *padown; community = intel_get_community(pctrl, pin); @@ -192,11 +195,11 @@ static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin) return !(readl(padown) & PADOWN_MASK(gpp_offset)); } -static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned pin) +static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin) { const struct intel_community *community; const struct intel_padgroup *padgrp; - unsigned offset, gpp_offset; + unsigned int offset, gpp_offset; void __iomem *hostown; community = intel_get_community(pctrl, pin); @@ -216,11 +219,11 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned pin) return !(readl(hostown) & BIT(gpp_offset)); } -static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin) +static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin) { struct intel_community *community; const struct intel_padgroup *padgrp; - unsigned offset, gpp_offset; + unsigned int offset, gpp_offset; u32 value; community = intel_get_community(pctrl, pin); @@ -253,7 +256,7 @@ static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin) return false; } -static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned pin) +static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin) { return intel_pad_owned_by_host(pctrl, pin) && !intel_pad_locked(pctrl, pin); @@ -267,15 +270,15 @@ static int intel_get_groups_count(struct pinctrl_dev *pctldev) } static const char *intel_get_group_name(struct pinctrl_dev *pctldev, - unsigned group) + unsigned int group) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); return pctrl->soc->groups[group].name; } -static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, - const unsigned **pins, unsigned *npins) +static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, + const unsigned int **pins, unsigned int *npins) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -285,7 +288,7 @@ static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, } static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned pin) + unsigned int pin) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *padcfg; @@ -344,7 +347,7 @@ static int intel_get_functions_count(struct pinctrl_dev *pctldev) } static const char *intel_get_function_name(struct pinctrl_dev *pctldev, - unsigned function) + unsigned int function) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -352,9 +355,9 @@ static const char *intel_get_function_name(struct pinctrl_dev *pctldev, } static int intel_get_function_groups(struct pinctrl_dev *pctldev, - unsigned function, + unsigned int function, const char * const **groups, - unsigned * const ngroups) + unsigned int * const ngroups) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -363,8 +366,8 @@ static int intel_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, - unsigned group) +static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct intel_pingroup *grp = &pctrl->soc->groups[group]; @@ -436,7 +439,7 @@ static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, - unsigned pin) + unsigned int pin) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *padcfg0; @@ -461,7 +464,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, static int intel_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, - unsigned pin, bool input) + unsigned int pin, bool input) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *padcfg0; @@ -486,7 +489,7 @@ static const struct pinmux_ops intel_pinmux_ops = { .gpio_set_direction = intel_gpio_set_direction, }; -static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin, +static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *config) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -575,11 +578,11 @@ static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin, return 0; } -static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin, +static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin, unsigned long config) { - unsigned param = pinconf_to_config_param(config); - unsigned arg = pinconf_to_config_argument(config); + unsigned int param = pinconf_to_config_param(config); + unsigned int arg = pinconf_to_config_argument(config); const struct intel_community *community; void __iomem *padcfg1; unsigned long flags; @@ -653,8 +656,8 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin, return ret; } -static int intel_config_set_debounce(struct intel_pinctrl *pctrl, unsigned pin, - unsigned debounce) +static int intel_config_set_debounce(struct intel_pinctrl *pctrl, + unsigned int pin, unsigned int debounce) { void __iomem *padcfg0, *padcfg2; unsigned long flags; @@ -700,8 +703,8 @@ exit_unlock: return ret; } -static int intel_config_set(struct pinctrl_dev *pctldev, unsigned pin, - unsigned long *configs, unsigned nconfigs) +static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int nconfigs) { struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); int i, ret; @@ -751,14 +754,14 @@ static const struct pinctrl_desc intel_pinctrl_desc = { * intel_gpio_to_pin() - Translate from GPIO offset to pin number * @pctrl: Pinctrl structure * @offset: GPIO offset from gpiolib - * @commmunity: Community is filled here if not %NULL + * @community: Community is filled here if not %NULL * @padgrp: Pad group is filled here if not %NULL * * When coming through gpiolib irqchip, the GPIO offset is not * automatically translated to pinctrl pin number. This function can be * used to find out the corresponding pinctrl pin. */ -static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset, +static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset, const struct intel_community **community, const struct intel_padgroup **padgrp) { @@ -792,7 +795,7 @@ static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset, return -EINVAL; } -static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) +static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct intel_pinctrl *pctrl = gpiochip_get_data(chip); void __iomem *reg; @@ -814,7 +817,8 @@ static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(padcfg0 & PADCFG0_GPIORXSTATE); } -static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct intel_pinctrl *pctrl = gpiochip_get_data(chip); unsigned long flags; @@ -863,12 +867,12 @@ static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) return !!(padcfg0 & PADCFG0_GPIOTXDIS); } -static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { return pinctrl_gpio_direction_input(chip->base + offset); } -static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned offset, +static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { intel_gpio_set(chip, offset, value); @@ -897,7 +901,7 @@ static void intel_gpio_irq_ack(struct irq_data *d) pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); if (pin >= 0) { - unsigned gpp, gpp_offset, is_offset; + unsigned int gpp, gpp_offset, is_offset; gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); @@ -919,7 +923,7 @@ static void intel_gpio_irq_enable(struct irq_data *d) pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); if (pin >= 0) { - unsigned gpp, gpp_offset, is_offset; + unsigned int gpp, gpp_offset, is_offset; unsigned long flags; u32 value; @@ -948,7 +952,7 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); if (pin >= 0) { - unsigned gpp, gpp_offset; + unsigned int gpp, gpp_offset; unsigned long flags; void __iomem *reg; u32 value; @@ -979,11 +983,11 @@ static void intel_gpio_irq_unmask(struct irq_data *d) intel_gpio_irq_mask_unmask(d, false); } -static int intel_gpio_irq_type(struct irq_data *d, unsigned type) +static int intel_gpio_irq_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); + unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); unsigned long flags; void __iomem *reg; u32 value; @@ -1040,7 +1044,7 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); + unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); if (on) enable_irq_wake(pctrl->irq); @@ -1135,7 +1139,7 @@ static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl, static unsigned intel_gpio_ngpio(const struct intel_pinctrl *pctrl) { const struct intel_community *community; - unsigned ngpio = 0; + unsigned int ngpio = 0; int i, j; for (i = 0; i < pctrl->ncommunities; i++) { @@ -1211,8 +1215,8 @@ static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, struct intel_community *community) { struct intel_padgroup *gpps; - unsigned npins = community->npins; - unsigned padown_num = 0; + unsigned int npins = community->npins; + unsigned int padown_num = 0; size_t ngpps, i; if (community->gpps) @@ -1228,7 +1232,7 @@ static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, if (community->gpps) { gpps[i] = community->gpps[i]; } else { - unsigned gpp_size = community->gpp_size; + unsigned int gpp_size = community->gpp_size; gpps[i].reg_num = i; gpps[i].base = community->pin_base + i * gpp_size; @@ -1398,8 +1402,52 @@ int intel_pinctrl_probe(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(intel_pinctrl_probe); +int intel_pinctrl_probe_by_hid(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data; + + data = device_get_match_data(&pdev->dev); + return intel_pinctrl_probe(pdev, data); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid); + +int intel_pinctrl_probe_by_uid(struct platform_device *pdev) +{ + const struct intel_pinctrl_soc_data *data = NULL; + const struct intel_pinctrl_soc_data **table; + struct acpi_device *adev; + unsigned int i; + + adev = ACPI_COMPANION(&pdev->dev); + if (adev) { + const void *match = device_get_match_data(&pdev->dev); + + table = (const struct intel_pinctrl_soc_data **)match; + for (i = 0; table[i]; i++) { + if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { + data = table[i]; + break; + } + } + } else { + const struct platform_device_id *id; + + id = platform_get_device_id(pdev); + if (!id) + return -ENODEV; + + table = (const struct intel_pinctrl_soc_data **)id->driver_data; + data = table[pdev->id]; + } + if (!data) + return -ENODEV; + + return intel_pinctrl_probe(pdev, data); +} +EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid); + #ifdef CONFIG_PM_SLEEP -static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin) +static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) { const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); @@ -1450,7 +1498,7 @@ int intel_pinctrl_suspend(struct device *dev) for (i = 0; i < pctrl->ncommunities; i++) { struct intel_community *community = &pctrl->communities[i]; void __iomem *base; - unsigned gpp; + unsigned int gpp; base = community->regs + community->ie_offset; for (gpp = 0; gpp < community->ngpps; gpp++) @@ -1468,7 +1516,7 @@ static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) for (i = 0; i < pctrl->ncommunities; i++) { const struct intel_community *community; void __iomem *base; - unsigned gpp; + unsigned int gpp; community = &pctrl->communities[i]; base = community->regs; @@ -1532,7 +1580,7 @@ int intel_pinctrl_resume(struct device *dev) for (i = 0; i < pctrl->ncommunities; i++) { struct intel_community *community = &pctrl->communities[i]; void __iomem *base; - unsigned gpp; + unsigned int gpp; base = community->regs + community->ie_offset; for (gpp = 0; gpp < community->ngpps; gpp++) { diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h index 1785abf157e4..9fb4645f3c55 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.h +++ b/drivers/pinctrl/intel/pinctrl-intel.h @@ -10,6 +10,8 @@ #ifndef PINCTRL_INTEL_H #define PINCTRL_INTEL_H +#include <linux/pm.h> + struct pinctrl_pin_desc; struct platform_device; struct device; @@ -25,10 +27,10 @@ struct device; */ struct intel_pingroup { const char *name; - const unsigned *pins; + const unsigned int *pins; size_t npins; unsigned short mode; - const unsigned *modes; + const unsigned int *modes; }; /** @@ -56,11 +58,11 @@ struct intel_function { * to specify them. */ struct intel_padgroup { - unsigned reg_num; - unsigned base; - unsigned size; + unsigned int reg_num; + unsigned int base; + unsigned int size; int gpio_base; - unsigned padown_num; + unsigned int padown_num; }; /** @@ -96,17 +98,17 @@ struct intel_padgroup { * pass custom @gpps and @ngpps instead. */ struct intel_community { - unsigned barno; - unsigned padown_offset; - unsigned padcfglock_offset; - unsigned hostown_offset; - unsigned is_offset; - unsigned ie_offset; - unsigned pin_base; - unsigned gpp_size; - unsigned gpp_num_padown_regs; + unsigned int barno; + unsigned int padown_offset; + unsigned int padcfglock_offset; + unsigned int hostown_offset; + unsigned int is_offset; + unsigned int ie_offset; + unsigned int pin_base; + unsigned int gpp_size; + unsigned int gpp_num_padown_regs; size_t npins; - unsigned features; + unsigned int features; const struct intel_padgroup *gpps; size_t ngpps; /* Reserved for the core driver */ @@ -173,9 +175,17 @@ struct intel_pinctrl_soc_data { int intel_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data); +int intel_pinctrl_probe_by_hid(struct platform_device *pdev); +int intel_pinctrl_probe_by_uid(struct platform_device *pdev); + #ifdef CONFIG_PM_SLEEP int intel_pinctrl_suspend(struct device *dev); int intel_pinctrl_resume(struct device *dev); #endif +#define INTEL_PINCTRL_PM_OPS(_name) \ +const struct dev_pm_ops _name = { \ + SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, intel_pinctrl_resume) \ +} + #endif /* PINCTRL_INTEL_H */ diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c index 99894647eddd..70ea9c518460 100644 --- a/drivers/pinctrl/intel/pinctrl-lewisburg.c +++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c @@ -9,7 +9,7 @@ #include <linux/acpi.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" @@ -313,10 +313,7 @@ static int lbg_pinctrl_probe(struct platform_device *pdev) return intel_pinctrl_probe(pdev, &lbg_soc_data); } -static const struct dev_pm_ops lbg_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(lbg_pinctrl_pm_ops); static const struct acpi_device_id lbg_pinctrl_acpi_match[] = { { "INT3536" }, diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c index 4fa69f988c7b..2e9988dac55f 100644 --- a/drivers/pinctrl/intel/pinctrl-merrifield.c +++ b/drivers/pinctrl/intel/pinctrl-merrifield.c @@ -476,6 +476,34 @@ static void __iomem *mrfld_get_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin return family->regs + BUFCFG_OFFSET + bufno * 4; } +static int mrfld_read_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin, u32 *value) +{ + void __iomem *bufcfg; + + if (!mrfld_buf_available(mp, pin)) + return -EBUSY; + + bufcfg = mrfld_get_bufcfg(mp, pin); + *value = readl(bufcfg); + + return 0; +} + +static void mrfld_update_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin, + u32 bits, u32 mask) +{ + void __iomem *bufcfg; + u32 value; + + bufcfg = mrfld_get_bufcfg(mp, pin); + value = readl(bufcfg); + + value &= ~mask; + value |= bits & mask; + + writel(value, bufcfg); +} + static int mrfld_get_groups_count(struct pinctrl_dev *pctldev) { struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev); @@ -505,17 +533,15 @@ static void mrfld_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned int pin) { struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev); - void __iomem *bufcfg; u32 value, mode; + int ret; - if (!mrfld_buf_available(mp, pin)) { + ret = mrfld_read_bufcfg(mp, pin, &value); + if (ret) { seq_puts(s, "not available"); return; } - bufcfg = mrfld_get_bufcfg(mp, pin); - value = readl(bufcfg); - mode = (value & BUFCFG_PINMODE_MASK) >> BUFCFG_PINMODE_SHIFT; if (!mode) seq_puts(s, "GPIO "); @@ -559,21 +585,6 @@ static int mrfld_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static void mrfld_update_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin, - u32 bits, u32 mask) -{ - void __iomem *bufcfg; - u32 value; - - bufcfg = mrfld_get_bufcfg(mp, pin); - value = readl(bufcfg); - - value &= ~mask; - value |= bits & mask; - - writel(value, bufcfg); -} - static int mrfld_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int group) @@ -637,11 +648,12 @@ static int mrfld_config_get(struct pinctrl_dev *pctldev, unsigned int pin, enum pin_config_param param = pinconf_to_config_param(*config); u32 value, term; u16 arg = 0; + int ret; - if (!mrfld_buf_available(mp, pin)) + ret = mrfld_read_bufcfg(mp, pin, &value); + if (ret) return -ENOTSUPP; - value = readl(mrfld_get_bufcfg(mp, pin)); term = (value & BUFCFG_PUPD_VAL_MASK) >> BUFCFG_PUPD_VAL_SHIFT; switch (param) { diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c index 7984392104fe..38a7c811ff58 100644 --- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c +++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c @@ -7,10 +7,10 @@ * Mika Westerberg <mika.westerberg@linux.intel.com> */ -#include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/pm.h> + #include <linux/pinctrl/pinctrl.h> #include "pinctrl-intel.h" @@ -593,21 +593,10 @@ MODULE_DEVICE_TABLE(acpi, spt_pinctrl_acpi_match); static int spt_pinctrl_probe(struct platform_device *pdev) { - const struct intel_pinctrl_soc_data *soc_data; - const struct acpi_device_id *id; - - id = acpi_match_device(spt_pinctrl_acpi_match, &pdev->dev); - if (!id || !id->driver_data) - return -ENODEV; - - soc_data = (const struct intel_pinctrl_soc_data *)id->driver_data; - return intel_pinctrl_probe(pdev, soc_data); + return intel_pinctrl_probe_by_hid(pdev); } -static const struct dev_pm_ops spt_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, - intel_pinctrl_resume) -}; +static INTEL_PINCTRL_PM_OPS(spt_pinctrl_pm_ops); static struct platform_driver spt_pinctrl_driver = { .probe = spt_pinctrl_probe, diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index 9905dc672f6b..9d142e1da567 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -3,7 +3,8 @@ menu "MediaTek pinctrl drivers" config EINT_MTK bool "MediaTek External Interrupt Support" - depends on PINCTRL_MTK || PINCTRL_MT7622 || COMPILE_TEST + depends on PINCTRL_MTK || PINCTRL_MTK_MOORE || COMPILE_TEST + select GPIOLIB select IRQ_DOMAIN config PINCTRL_MTK @@ -15,6 +16,24 @@ config PINCTRL_MTK select EINT_MTK select OF_GPIO +config PINCTRL_MTK_MOORE + bool "MediaTek Moore Core that implements generic binding" + depends on OF + select GENERIC_PINCONF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GPIOLIB + select OF_GPIO + +config PINCTRL_MTK_PARIS + bool "MediaTek Paris Core that implements vendor binding" + depends on OF + select PINMUX + select GENERIC_PINCONF + select GPIOLIB + select EINT_MTK + select OF_GPIO + # For ARMv7 SoCs config PINCTRL_MT2701 bool "Mediatek MT2701 pin control" @@ -23,6 +42,12 @@ config PINCTRL_MT2701 default MACH_MT2701 select PINCTRL_MTK +config PINCTRL_MT7623 + bool "Mediatek MT7623 pin control with generic binding" + depends on MACH_MT7623 || COMPILE_TEST + depends on PINCTRL_MTK_MOORE + default y + config PINCTRL_MT8135 bool "Mediatek MT8135 pin control" depends on MACH_MT8135 || COMPILE_TEST @@ -45,15 +70,18 @@ config PINCTRL_MT2712 default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK +config PINCTRL_MT6765 + bool "Mediatek MT6765 pin control" + depends on OF + depends on ARM64 || COMPILE_TEST + default ARM64 && ARCH_MEDIATEK + select PINCTRL_MTK_PARIS + config PINCTRL_MT7622 bool "MediaTek MT7622 pin control" - depends on OF depends on ARM64 || COMPILE_TEST - select GENERIC_PINCONF - select GENERIC_PINCTRL_GROUPS - select GENERIC_PINMUX_FUNCTIONS - select GPIOLIB - select OF_GPIO + depends on PINCTRL_MTK_MOORE + default y config PINCTRL_MT8173 bool "Mediatek MT8173 pin control" @@ -62,6 +90,13 @@ config PINCTRL_MT8173 default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK +config PINCTRL_MT8183 + bool "Mediatek MT8183 pin control" + depends on OF + depends on ARM64 || COMPILE_TEST + default ARM64 && ARCH_MEDIATEK + select PINCTRL_MTK_PARIS + # For PMIC config PINCTRL_MT6397 bool "Mediatek MT6397 pin control" diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile index 3de7156df345..70d800054f69 100644 --- a/drivers/pinctrl/mediatek/Makefile +++ b/drivers/pinctrl/mediatek/Makefile @@ -2,12 +2,17 @@ # Core obj-$(CONFIG_EINT_MTK) += mtk-eint.o obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o +obj-$(CONFIG_PINCTRL_MTK_MOORE) += pinctrl-moore.o pinctrl-mtk-common-v2.o +obj-$(CONFIG_PINCTRL_MTK_PARIS) += pinctrl-paris.o pinctrl-mtk-common-v2.o # SoC Drivers obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o obj-$(CONFIG_PINCTRL_MT2712) += pinctrl-mt2712.o obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o +obj-$(CONFIG_PINCTRL_MT6765) += pinctrl-mt6765.o obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o +obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o +obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c index a613e546717a..f464f8cd274b 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.c +++ b/drivers/pinctrl/mediatek/mtk-eint.c @@ -11,7 +11,7 @@ #include <linux/delay.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/io.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h index c286a9b940f2..48468d0fae68 100644 --- a/drivers/pinctrl/mediatek/mtk-eint.h +++ b/drivers/pinctrl/mediatek/mtk-eint.h @@ -92,13 +92,13 @@ static inline int mtk_eint_do_resume(struct mtk_eint *eint) return -EOPNOTSUPP; } -int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n, +static inline int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n, unsigned int debounce) { return -EOPNOTSUPP; } -int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n) +static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n) { return -EOPNOTSUPP; } diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c new file mode 100644 index 000000000000..3133ec0f2e67 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-moore.c @@ -0,0 +1,690 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek Pinctrl Moore Driver, which implement the generic dt-binding + * pinctrl-bindings.txt for MediaTek SoC. + * + * Copyright (C) 2017-2018 MediaTek Inc. + * Author: Sean Wang <sean.wang@mediatek.com> + * + */ + +#include <linux/gpio/driver.h> +#include "pinctrl-moore.h" + +#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME + +/* Custom pinconf parameters */ +#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) +#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) +#define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) +#define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) + +static const struct pinconf_generic_params mtk_custom_bindings[] = { + {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, + {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, + {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, + {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item mtk_conf_items[] = { + PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), + PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), + PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), + PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), +}; +#endif + +static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned int group) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + struct function_desc *func; + struct group_desc *grp; + int i; + + func = pinmux_generic_get_function(pctldev, selector); + if (!func) + return -EINVAL; + + grp = pinctrl_generic_get_group(pctldev, group); + if (!grp) + return -EINVAL; + + dev_dbg(pctldev->dev, "enable function %s group %s\n", + func->name, grp->name); + + for (i = 0; i < grp->num_pins; i++) { + const struct mtk_pin_desc *desc; + int *pin_modes = grp->data; + int pin = grp->pins[i]; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, + pin_modes[i]); + } + + return 0; +} + +static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, + hw->soc->gpio_m); +} + +static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin, bool input) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + /* hardware would take 0 as input direction */ + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input); +} + +static int mtk_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + u32 param = pinconf_to_config_param(*config); + int val, val2, err, reg, ret = 1; + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (hw->soc->bias_disable_get) { + err = hw->soc->bias_disable_get(hw, desc, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (hw->soc->bias_get) { + err = hw->soc->bias_get(hw, desc, 1, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (hw->soc->bias_get) { + err = hw->soc->bias_get(hw, desc, 0, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_SLEW_RATE: + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &val); + if (err) + return err; + + if (!val) + return -EINVAL; + + break; + case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_OUTPUT_ENABLE: + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); + if (err) + return err; + + /* HW takes input mode as zero; output mode as non-zero */ + if ((val && param == PIN_CONFIG_INPUT_ENABLE) || + (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) + return -EINVAL; + + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); + if (err) + return err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &val2); + if (err) + return err; + + if (val || !val2) + return -EINVAL; + + break; + case PIN_CONFIG_DRIVE_STRENGTH: + if (hw->soc->drive_get) { + err = hw->soc->drive_get(hw, desc, &ret); + if (err) + return err; + } else { + err = -ENOTSUPP; + } + break; + case MTK_PIN_CONFIG_TDSEL: + case MTK_PIN_CONFIG_RDSEL: + reg = (param == MTK_PIN_CONFIG_TDSEL) ? + PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; + + err = mtk_hw_get_value(hw, desc, reg, &val); + if (err) + return err; + + ret = val; + + break; + case MTK_PIN_CONFIG_PU_ADV: + case MTK_PIN_CONFIG_PD_ADV: + if (hw->soc->adv_pull_get) { + bool pullup; + + pullup = param == MTK_PIN_CONFIG_PU_ADV; + err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, ret); + + return 0; +} + +static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + u32 reg, param, arg; + int cfg, err = 0; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + for (cfg = 0; cfg < num_configs; cfg++) { + param = pinconf_to_config_param(configs[cfg]); + arg = pinconf_to_config_argument(configs[cfg]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (hw->soc->bias_disable_set) { + err = hw->soc->bias_disable_set(hw, desc); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (hw->soc->bias_set) { + err = hw->soc->bias_set(hw, desc, 1); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (hw->soc->bias_set) { + err = hw->soc->bias_set(hw, desc, 0); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_OUTPUT_ENABLE: + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, + MTK_DISABLE); + if (err) + goto err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + MTK_OUTPUT); + if (err) + goto err; + break; + case PIN_CONFIG_INPUT_ENABLE: + + if (hw->soc->ies_present) { + mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, + MTK_ENABLE); + } + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + MTK_INPUT); + if (err) + goto err; + break; + case PIN_CONFIG_SLEW_RATE: + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR, + arg); + if (err) + goto err; + + break; + case PIN_CONFIG_OUTPUT: + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + MTK_OUTPUT); + if (err) + goto err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, + arg); + if (err) + goto err; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + /* arg = 1: Input mode & SMT enable ; + * arg = 0: Output mode & SMT disable + */ + arg = arg ? 2 : 1; + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + arg & 1); + if (err) + goto err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, + !!(arg & 2)); + if (err) + goto err; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + if (hw->soc->drive_set) { + err = hw->soc->drive_set(hw, desc, arg); + if (err) + return err; + } else { + err = -ENOTSUPP; + } + break; + case MTK_PIN_CONFIG_TDSEL: + case MTK_PIN_CONFIG_RDSEL: + reg = (param == MTK_PIN_CONFIG_TDSEL) ? + PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; + + err = mtk_hw_set_value(hw, desc, reg, arg); + if (err) + goto err; + break; + case MTK_PIN_CONFIG_PU_ADV: + case MTK_PIN_CONFIG_PD_ADV: + if (hw->soc->adv_pull_set) { + bool pullup; + + pullup = param == MTK_PIN_CONFIG_PU_ADV; + err = hw->soc->adv_pull_set(hw, desc, pullup, + arg); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + default: + err = -ENOTSUPP; + } + } +err: + return err; +} + +static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *config) +{ + const unsigned int *pins; + unsigned int i, npins, old = 0; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + for (i = 0; i < npins; i++) { + if (mtk_pinconf_get(pctldev, pins[i], config)) + return -ENOTSUPP; + + /* configs do not match between two pins */ + if (i && old != *config) + return -ENOTSUPP; + + old = *config; + } + + return 0; +} + +static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *configs, + unsigned int num_configs) +{ + const unsigned int *pins; + unsigned int i, npins; + int ret; + + ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + for (i = 0; i < npins; i++) { + ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinctrl_ops mtk_pctlops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static const struct pinmux_ops mtk_pmxops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = mtk_pinmux_set_mux, + .gpio_request_enable = mtk_pinmux_gpio_request_enable, + .gpio_set_direction = mtk_pinmux_gpio_set_direction, + .strict = true, +}; + +static const struct pinconf_ops mtk_confops = { + .is_generic = true, + .pin_config_get = mtk_pinconf_get, + .pin_config_set = mtk_pinconf_set, + .pin_config_group_get = mtk_pinconf_group_get, + .pin_config_group_set = mtk_pinconf_group_set, + .pin_config_config_dbg_show = pinconf_generic_dump_config, +}; + +static struct pinctrl_desc mtk_desc = { + .name = PINCTRL_PINCTRL_DEV, + .pctlops = &mtk_pctlops, + .pmxops = &mtk_pmxops, + .confops = &mtk_confops, + .owner = THIS_MODULE, +}; + +static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + int value, err; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); + if (err) + return err; + + return !!value; +} + +static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; + + mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); +} + +static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) +{ + return pinctrl_gpio_direction_input(chip->base + gpio); +} + +static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, + int value) +{ + mtk_gpio_set(chip, gpio, value); + + return pinctrl_gpio_direction_output(chip->base + gpio); +} + +static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + + if (!hw->eint) + return -ENOTSUPP; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; + + if (desc->eint.eint_n == (u16)EINT_NA) + return -ENOTSUPP; + + return mtk_eint_find_irq(hw->eint, desc->eint.eint_n); +} + +static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + u32 debounce; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; + + if (!hw->eint || + pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || + desc->eint.eint_n == (u16)EINT_NA) + return -ENOTSUPP; + + debounce = pinconf_to_config_argument(config); + + return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); +} + +static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np) +{ + struct gpio_chip *chip = &hw->chip; + int ret; + + chip->label = PINCTRL_PINCTRL_DEV; + chip->parent = hw->dev; + chip->request = gpiochip_generic_request; + chip->free = gpiochip_generic_free; + chip->direction_input = mtk_gpio_direction_input; + chip->direction_output = mtk_gpio_direction_output; + chip->get = mtk_gpio_get; + chip->set = mtk_gpio_set; + chip->to_irq = mtk_gpio_to_irq, + chip->set_config = mtk_gpio_set_config, + chip->base = -1; + chip->ngpio = hw->soc->npins; + chip->of_node = np; + chip->of_gpio_n_cells = 2; + + ret = gpiochip_add_data(chip, hw); + if (ret < 0) + return ret; + + /* Just for backward compatible for these old pinctrl nodes without + * "gpio-ranges" property. Otherwise, called directly from a + * DeviceTree-supported pinctrl driver is DEPRECATED. + * Please see Section 2.1 of + * Documentation/devicetree/bindings/gpio/gpio.txt on how to + * bind pinctrl and gpio drivers via the "gpio-ranges" property. + */ + if (!of_find_property(np, "gpio-ranges", NULL)) { + ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0, + chip->ngpio); + if (ret < 0) { + gpiochip_remove(chip); + return ret; + } + } + + return 0; +} + +static int mtk_build_groups(struct mtk_pinctrl *hw) +{ + int err, i; + + for (i = 0; i < hw->soc->ngrps; i++) { + const struct group_desc *group = hw->soc->grps + i; + + err = pinctrl_generic_add_group(hw->pctrl, group->name, + group->pins, group->num_pins, + group->data); + if (err < 0) { + dev_err(hw->dev, "Failed to register group %s\n", + group->name); + return err; + } + } + + return 0; +} + +static int mtk_build_functions(struct mtk_pinctrl *hw) +{ + int i, err; + + for (i = 0; i < hw->soc->nfuncs ; i++) { + const struct function_desc *func = hw->soc->funcs + i; + + err = pinmux_generic_add_function(hw->pctrl, func->name, + func->group_names, + func->num_group_names, + func->data); + if (err < 0) { + dev_err(hw->dev, "Failed to register function %s\n", + func->name); + return err; + } + } + + return 0; +} + +int mtk_moore_pinctrl_probe(struct platform_device *pdev, + const struct mtk_pin_soc *soc) +{ + struct pinctrl_pin_desc *pins; + struct resource *res; + struct mtk_pinctrl *hw; + int err, i; + + hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return -ENOMEM; + + hw->soc = soc; + hw->dev = &pdev->dev; + + if (!hw->soc->nbase_names) { + dev_err(&pdev->dev, + "SoC should be assigned at least one register base\n"); + return -EINVAL; + } + + hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names, + sizeof(*hw->base), GFP_KERNEL); + if (!hw->base) + return -ENOMEM; + + for (i = 0; i < hw->soc->nbase_names; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + hw->soc->base_names[i]); + if (!res) { + dev_err(&pdev->dev, "missing IO resource\n"); + return -ENXIO; + } + + hw->base[i] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->base[i])) + return PTR_ERR(hw->base[i]); + } + + hw->nbase = hw->soc->nbase_names; + + /* Copy from internal struct mtk_pin_desc to register to the core */ + pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins), + GFP_KERNEL); + if (!pins) + return -ENOMEM; + + for (i = 0; i < hw->soc->npins; i++) { + pins[i].number = hw->soc->pins[i].number; + pins[i].name = hw->soc->pins[i].name; + } + + /* Setup pins descriptions per SoC types */ + mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; + mtk_desc.npins = hw->soc->npins; + mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); + mtk_desc.custom_params = mtk_custom_bindings; +#ifdef CONFIG_DEBUG_FS + mtk_desc.custom_conf_items = mtk_conf_items; +#endif + + err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, + &hw->pctrl); + if (err) + return err; + + /* Setup groups descriptions per SoC types */ + err = mtk_build_groups(hw); + if (err) { + dev_err(&pdev->dev, "Failed to build groups\n"); + return err; + } + + /* Setup functions descriptions per SoC types */ + err = mtk_build_functions(hw); + if (err) { + dev_err(&pdev->dev, "Failed to build functions\n"); + return err; + } + + /* For able to make pinctrl_claim_hogs, we must not enable pinctrl + * until all groups and functions are being added one. + */ + err = pinctrl_enable(hw->pctrl); + if (err) + return err; + + err = mtk_build_eint(hw, pdev); + if (err) + dev_warn(&pdev->dev, + "Failed to add EINT, but pinctrl still can work\n"); + + /* Build gpiochip should be after pinctrl_enable is done */ + err = mtk_build_gpiochip(hw, pdev->dev.of_node); + if (err) { + dev_err(&pdev->dev, "Failed to add gpio_chip\n"); + return err; + } + + platform_set_drvdata(pdev, hw); + + return 0; +} diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.h b/drivers/pinctrl/mediatek/pinctrl-moore.h new file mode 100644 index 000000000000..e1b4b82b9d3d --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-moore.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017-2018 MediaTek Inc. + * + * Author: Sean Wang <sean.wang@mediatek.com> + * + */ +#ifndef __PINCTRL_MOORE_H +#define __PINCTRL_MOORE_H + +#include <linux/io.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> + +#include "../core.h" +#include "../pinconf.h" +#include "../pinmux.h" +#include "mtk-eint.h" +#include "pinctrl-mtk-common-v2.h" + +#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), } + +#define MTK_PIN(_number, _name, _eint_m, _eint_n, _drv_n) { \ + .number = _number, \ + .name = _name, \ + .eint = { \ + .eint_m = _eint_m, \ + .eint_n = _eint_n, \ + }, \ + .drv_n = _drv_n, \ + .funcs = NULL, \ + } + +#define PINCTRL_PIN_GROUP(name, id) \ + { \ + name, \ + id##_pins, \ + ARRAY_SIZE(id##_pins), \ + id##_funcs, \ + } + +int mtk_moore_pinctrl_probe(struct platform_device *pdev, + const struct mtk_pin_soc *soc); + +#endif /* __PINCTRL_MOORE_H */ diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6765.c b/drivers/pinctrl/mediatek/pinctrl-mt6765.c new file mode 100644 index 000000000000..32451e8693be --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt6765.c @@ -0,0 +1,1108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: ZH Chen <zh.chen@mediatek.com> + * + */ + +#include "pinctrl-mtk-mt6765.h" +#include "pinctrl-paris.h" + +/* MT6765 have multiple bases to program pin configuration listed as the below: + * iocfg[0]:0x10005000, iocfg[1]:0x10002C00, iocfg[2]:0x10002800, + * iocfg[3]:0x10002A00, iocfg[4]:0x10002000, iocfg[5]:0x10002200, + * iocfg[6]:0x10002500, iocfg[7]:0x10002600. + * _i_base could be used to indicate what base the pin should be mapped into. + */ + +#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 0) + +#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 1) + +static const struct mtk_pin_field_calc mt6765_pin_mode_range[] = { + PIN_FIELD(0, 202, 0x300, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt6765_pin_dir_range[] = { + PIN_FIELD(0, 202, 0x0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_di_range[] = { + PIN_FIELD(0, 202, 0x200, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_do_range[] = { + PIN_FIELD(0, 202, 0x100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_smt_range[] = { + PINS_FIELD_BASE(0, 3, 2, 0x00b0, 0x10, 4, 1), + PINS_FIELD_BASE(4, 7, 2, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(8, 8, 3, 0x0080, 0x10, 3, 1), + PINS_FIELD_BASE(9, 11, 2, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(12, 12, 5, 0x0060, 0x10, 9, 1), + PINS_FIELD_BASE(13, 16, 6, 0x00b0, 0x10, 10, 1), + PINS_FIELD_BASE(17, 20, 6, 0x00b0, 0x10, 8, 1), + PINS_FIELD_BASE(21, 24, 6, 0x00b0, 0x10, 9, 1), + PINS_FIELD_BASE(25, 28, 6, 0x00b0, 0x10, 7, 1), + PIN_FIELD_BASE(29, 29, 6, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(30, 30, 6, 0x00b0, 0x10, 1, 1), + PINS_FIELD_BASE(31, 34, 6, 0x00b0, 0x10, 2, 1), + PINS_FIELD_BASE(35, 36, 6, 0x00b0, 0x10, 5, 1), + PIN_FIELD_BASE(37, 37, 6, 0x00b0, 0x10, 6, 1), + PIN_FIELD_BASE(38, 38, 6, 0x00b0, 0x10, 4, 1), + PINS_FIELD_BASE(39, 40, 6, 0x00b0, 0x10, 3, 1), + PINS_FIELD_BASE(41, 42, 7, 0x00c0, 0x10, 6, 1), + PIN_FIELD_BASE(43, 43, 7, 0x00c0, 0x10, 3, 1), + PIN_FIELD_BASE(44, 44, 7, 0x00c0, 0x10, 4, 1), + PIN_FIELD_BASE(45, 45, 7, 0x00c0, 0x10, 8, 1), + PINS_FIELD_BASE(46, 47, 7, 0x00c0, 0x10, 7, 1), + PIN_FIELD_BASE(48, 48, 7, 0x00c0, 0x10, 15, 1), + PIN_FIELD_BASE(49, 49, 7, 0x00c0, 0x10, 17, 1), + PIN_FIELD_BASE(50, 50, 7, 0x00c0, 0x10, 14, 1), + PIN_FIELD_BASE(51, 51, 7, 0x00c0, 0x10, 16, 1), + PINS_FIELD_BASE(52, 57, 7, 0x00c0, 0x10, 0, 1), + PINS_FIELD_BASE(58, 60, 7, 0x00c0, 0x10, 12, 1), + PINS_FIELD_BASE(61, 62, 3, 0x0080, 0x10, 5, 1), + PINS_FIELD_BASE(63, 64, 3, 0x0080, 0x10, 4, 1), + PINS_FIELD_BASE(65, 66, 3, 0x0080, 0x10, 7, 1), + PINS_FIELD_BASE(67, 68, 3, 0x0080, 0x10, 6, 1), + PINS_FIELD_BASE(69, 73, 3, 0x0080, 0x10, 1, 1), + PINS_FIELD_BASE(74, 78, 3, 0x0080, 0x10, 2, 1), + PINS_FIELD_BASE(79, 80, 3, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(81, 81, 3, 0x0080, 0x10, 12, 1), + PIN_FIELD_BASE(82, 82, 3, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(83, 83, 3, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(84, 84, 3, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(85, 85, 7, 0x00c0, 0x10, 12, 1), + PIN_FIELD_BASE(86, 86, 7, 0x00c0, 0x10, 13, 1), + PIN_FIELD_BASE(87, 87, 7, 0x00c0, 0x10, 2, 1), + PIN_FIELD_BASE(88, 88, 7, 0x00c0, 0x10, 1, 1), + PIN_FIELD_BASE(89, 89, 2, 0x00b0, 0x10, 13, 1), + PIN_FIELD_BASE(90, 90, 3, 0x0080, 0x10, 8, 1), + PINS_FIELD_BASE(91, 92, 2, 0x00b0, 0x10, 8, 1), + PINS_FIELD_BASE(93, 94, 2, 0x00b0, 0x10, 7, 1), + PINS_FIELD_BASE(95, 96, 2, 0x00b0, 0x10, 14, 1), + PINS_FIELD_BASE(97, 98, 2, 0x00b0, 0x10, 2, 1), + PIN_FIELD_BASE(99, 99, 2, 0x00b0, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 2, 0x00b0, 0x10, 1, 1), + PINS_FIELD_BASE(101, 102, 2, 0x00b0, 0x10, 3, 1), + PIN_FIELD_BASE(103, 103, 2, 0x00b0, 0x10, 9, 1), + PIN_FIELD_BASE(104, 104, 2, 0x00b0, 0x10, 11, 1), + PIN_FIELD_BASE(105, 105, 2, 0x00b0, 0x10, 10, 1), + PIN_FIELD_BASE(106, 106, 2, 0x00b0, 0x10, 12, 1), + PIN_FIELD_BASE(107, 107, 1, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(108, 108, 1, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(109, 109, 1, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(110, 110, 1, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(111, 111, 1, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(112, 112, 1, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(113, 113, 1, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(114, 114, 1, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(115, 115, 1, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(116, 116, 1, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(117, 117, 1, 0x0080, 0x10, 12, 1), + PIN_FIELD_BASE(118, 118, 1, 0x0080, 0x10, 13, 1), + PIN_FIELD_BASE(119, 119, 1, 0x0080, 0x10, 14, 1), + PIN_FIELD_BASE(120, 120, 1, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(121, 121, 1, 0x0080, 0x10, 8, 1), + PIN_FIELD_BASE(122, 122, 4, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(123, 123, 4, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(124, 124, 4, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(125, 125, 4, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(126, 126, 4, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(127, 127, 4, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(128, 128, 4, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(129, 129, 4, 0x0080, 0x10, 8, 1), + PIN_FIELD_BASE(130, 130, 4, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(131, 131, 4, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(132, 132, 4, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(133, 133, 4, 0x0080, 0x10, 12, 1), + PIN_FIELD_BASE(134, 134, 5, 0x0060, 0x10, 11, 1), + PIN_FIELD_BASE(135, 135, 5, 0x0060, 0x10, 13, 1), + PIN_FIELD_BASE(136, 136, 5, 0x0060, 0x10, 1, 1), + PIN_FIELD_BASE(137, 137, 5, 0x0060, 0x10, 7, 1), + PIN_FIELD_BASE(138, 138, 5, 0x0060, 0x10, 4, 1), + PIN_FIELD_BASE(139, 139, 5, 0x0060, 0x10, 5, 1), + PIN_FIELD_BASE(140, 140, 5, 0x0060, 0x10, 0, 1), + PIN_FIELD_BASE(141, 141, 5, 0x0060, 0x10, 6, 1), + PIN_FIELD_BASE(142, 142, 5, 0x0060, 0x10, 2, 1), + PIN_FIELD_BASE(143, 143, 5, 0x0060, 0x10, 3, 1), + PINS_FIELD_BASE(144, 147, 5, 0x0060, 0x10, 10, 1), + PINS_FIELD_BASE(148, 149, 5, 0x0060, 0x10, 12, 1), + PINS_FIELD_BASE(150, 151, 7, 0x00c0, 0x10, 9, 1), + PINS_FIELD_BASE(152, 153, 7, 0x00c0, 0x10, 10, 1), + PIN_FIELD_BASE(154, 154, 7, 0x00c0, 0x10, 11, 1), + PINS_FIELD_BASE(155, 158, 3, 0x0080, 0x10, 13, 1), + PIN_FIELD_BASE(159, 159, 7, 0x00c0, 0x10, 11, 1), + PIN_FIELD_BASE(160, 160, 5, 0x0060, 0x10, 8, 1), + PIN_FIELD_BASE(161, 161, 1, 0x0080, 0x10, 15, 1), + PIN_FIELD_BASE(162, 162, 1, 0x0080, 0x10, 16, 1), + PINS_FIELD_BASE(163, 170, 4, 0x0080, 0x10, 0, 1), + PINS_FIELD_BASE(171, 179, 7, 0x00c0, 0x10, 5, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_pd_range[] = { + PIN_FIELD_BASE(0, 0, 2, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(1, 1, 2, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(2, 2, 2, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(3, 3, 2, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(4, 4, 2, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(5, 5, 2, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(6, 6, 2, 0x0040, 0x10, 14, 1), + PIN_FIELD_BASE(7, 7, 2, 0x0040, 0x10, 15, 1), + PIN_FIELD_BASE(8, 8, 3, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(9, 9, 2, 0x0040, 0x10, 16, 1), + PIN_FIELD_BASE(10, 10, 2, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 2, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(12, 12, 5, 0x0030, 0x10, 9, 1), + PIN_FIELD_BASE(13, 13, 6, 0x0040, 0x10, 14, 1), + PIN_FIELD_BASE(14, 14, 6, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(15, 15, 6, 0x0040, 0x10, 15, 1), + PIN_FIELD_BASE(16, 16, 6, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(17, 17, 6, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(18, 18, 6, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(19, 19, 6, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(20, 20, 6, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(21, 21, 6, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(22, 22, 6, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(23, 23, 6, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(24, 24, 6, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(25, 25, 6, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(26, 26, 6, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(27, 27, 6, 0x0040, 0x10, 3, 1), + PINS_FIELD_BASE(28, 40, 6, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(41, 41, 7, 0x0060, 0x10, 19, 1), + PIN_FIELD_BASE(42, 42, 7, 0x0060, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 7, 0x0060, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 7, 0x0060, 0x10, 10, 1), + PIN_FIELD_BASE(45, 45, 7, 0x0060, 0x10, 22, 1), + PIN_FIELD_BASE(46, 46, 7, 0x0060, 0x10, 21, 1), + PIN_FIELD_BASE(47, 47, 7, 0x0060, 0x10, 20, 1), + PIN_FIELD_BASE(48, 48, 7, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 7, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(50, 50, 7, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(51, 51, 7, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(52, 52, 7, 0x0060, 0x10, 1, 1), + PIN_FIELD_BASE(53, 53, 7, 0x0060, 0x10, 0, 1), + PIN_FIELD_BASE(54, 54, 7, 0x0060, 0x10, 5, 1), + PIN_FIELD_BASE(55, 55, 7, 0x0060, 0x10, 3, 1), + PIN_FIELD_BASE(56, 56, 7, 0x0060, 0x10, 4, 1), + PIN_FIELD_BASE(57, 57, 7, 0x0060, 0x10, 2, 1), + PIN_FIELD_BASE(58, 58, 7, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(59, 59, 7, 0x0060, 0x10, 31, 1), + PIN_FIELD_BASE(60, 60, 7, 0x0060, 0x10, 30, 1), + PIN_FIELD_BASE(61, 61, 3, 0x0040, 0x10, 18, 1), + PIN_FIELD_BASE(62, 62, 3, 0x0040, 0x10, 14, 1), + PIN_FIELD_BASE(63, 63, 3, 0x0040, 0x10, 17, 1), + PIN_FIELD_BASE(64, 64, 3, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(65, 65, 3, 0x0040, 0x10, 20, 1), + PIN_FIELD_BASE(66, 66, 3, 0x0040, 0x10, 16, 1), + PIN_FIELD_BASE(67, 67, 3, 0x0040, 0x10, 19, 1), + PIN_FIELD_BASE(68, 68, 3, 0x0040, 0x10, 15, 1), + PIN_FIELD_BASE(69, 69, 3, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(70, 70, 3, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(71, 71, 3, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(72, 72, 3, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(73, 73, 3, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(74, 74, 3, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(75, 75, 3, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(76, 76, 3, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(77, 77, 3, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 3, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(79, 79, 3, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(80, 80, 3, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(81, 81, 3, 0x0040, 0x10, 25, 1), + PIN_FIELD_BASE(82, 82, 3, 0x0040, 0x10, 24, 1), + PIN_FIELD_BASE(83, 83, 3, 0x0040, 0x10, 22, 1), + PIN_FIELD_BASE(84, 84, 3, 0x0040, 0x10, 23, 1), + PIN_FIELD_BASE(85, 85, 7, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(86, 86, 7, 0x0060, 0x10, 29, 1), + PIN_FIELD_BASE(87, 87, 7, 0x0060, 0x10, 7, 1), + PIN_FIELD_BASE(88, 88, 7, 0x0060, 0x10, 6, 1), + PIN_FIELD_BASE(89, 89, 2, 0x0040, 0x10, 21, 1), + PINS_FIELD_BASE(90, 94, 3, 0x0040, 0x10, 21, 1), + PIN_FIELD_BASE(95, 95, 2, 0x0040, 0x10, 22, 1), + PIN_FIELD_BASE(96, 96, 2, 0x0040, 0x10, 23, 1), + PIN_FIELD_BASE(97, 97, 2, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(98, 98, 2, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(99, 99, 2, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 2, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(101, 101, 2, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(102, 102, 2, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(103, 103, 2, 0x0040, 0x10, 17, 1), + PIN_FIELD_BASE(104, 104, 2, 0x0040, 0x10, 19, 1), + PIN_FIELD_BASE(105, 105, 2, 0x0040, 0x10, 18, 1), + PIN_FIELD_BASE(106, 106, 2, 0x0040, 0x10, 20, 1), + PIN_FIELD_BASE(107, 107, 1, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(108, 108, 1, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(109, 109, 1, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(110, 110, 1, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(111, 111, 1, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(112, 112, 1, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(113, 113, 1, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(114, 114, 1, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(115, 115, 1, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(116, 116, 1, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(117, 117, 1, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(118, 118, 1, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(119, 119, 1, 0x0040, 0x10, 14, 1), + PIN_FIELD_BASE(120, 120, 1, 0x0040, 0x10, 11, 1), + PINS_FIELD_BASE(121, 133, 1, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(134, 134, 5, 0x0030, 0x10, 14, 1), + PIN_FIELD_BASE(135, 135, 5, 0x0030, 0x10, 19, 1), + PIN_FIELD_BASE(136, 136, 5, 0x0030, 0x10, 1, 1), + PIN_FIELD_BASE(137, 137, 5, 0x0030, 0x10, 7, 1), + PIN_FIELD_BASE(138, 138, 5, 0x0030, 0x10, 4, 1), + PIN_FIELD_BASE(139, 139, 5, 0x0030, 0x10, 5, 1), + PIN_FIELD_BASE(140, 140, 5, 0x0030, 0x10, 0, 1), + PIN_FIELD_BASE(141, 141, 5, 0x0030, 0x10, 6, 1), + PIN_FIELD_BASE(142, 142, 5, 0x0030, 0x10, 2, 1), + PIN_FIELD_BASE(143, 143, 5, 0x0030, 0x10, 3, 1), + PIN_FIELD_BASE(144, 144, 5, 0x0030, 0x10, 12, 1), + PIN_FIELD_BASE(145, 145, 5, 0x0030, 0x10, 11, 1), + PIN_FIELD_BASE(146, 146, 5, 0x0030, 0x10, 13, 1), + PIN_FIELD_BASE(147, 147, 5, 0x0030, 0x10, 10, 1), + PIN_FIELD_BASE(148, 148, 5, 0x0030, 0x10, 15, 1), + PIN_FIELD_BASE(149, 149, 5, 0x0030, 0x10, 16, 1), + PIN_FIELD_BASE(150, 150, 7, 0x0060, 0x10, 23, 1), + PIN_FIELD_BASE(151, 151, 7, 0x0060, 0x10, 24, 1), + PIN_FIELD_BASE(152, 152, 7, 0x0060, 0x10, 25, 1), + PIN_FIELD_BASE(153, 153, 7, 0x0060, 0x10, 26, 1), + PIN_FIELD_BASE(154, 154, 7, 0x0060, 0x10, 28, 1), + PIN_FIELD_BASE(155, 155, 3, 0x0040, 0x10, 28, 1), + PIN_FIELD_BASE(156, 156, 3, 0x0040, 0x10, 27, 1), + PIN_FIELD_BASE(157, 157, 3, 0x0040, 0x10, 29, 1), + PIN_FIELD_BASE(158, 158, 3, 0x0040, 0x10, 26, 1), + PIN_FIELD_BASE(159, 159, 7, 0x0060, 0x10, 27, 1), + PIN_FIELD_BASE(160, 160, 5, 0x0030, 0x10, 8, 1), + PIN_FIELD_BASE(161, 161, 1, 0x0040, 0x10, 15, 1), + PIN_FIELD_BASE(162, 162, 1, 0x0040, 0x10, 16, 1), + PIN_FIELD_BASE(163, 163, 4, 0x0020, 0x10, 0, 1), + PIN_FIELD_BASE(164, 164, 4, 0x0020, 0x10, 1, 1), + PIN_FIELD_BASE(165, 165, 4, 0x0020, 0x10, 2, 1), + PIN_FIELD_BASE(166, 166, 4, 0x0020, 0x10, 3, 1), + PIN_FIELD_BASE(167, 167, 4, 0x0020, 0x10, 4, 1), + PIN_FIELD_BASE(168, 168, 4, 0x0020, 0x10, 5, 1), + PIN_FIELD_BASE(169, 169, 4, 0x0020, 0x10, 6, 1), + PIN_FIELD_BASE(170, 170, 4, 0x0020, 0x10, 7, 1), + PIN_FIELD_BASE(171, 171, 7, 0x0060, 0x10, 17, 1), + PIN_FIELD_BASE(172, 172, 7, 0x0060, 0x10, 18, 1), + PIN_FIELD_BASE(173, 173, 7, 0x0060, 0x10, 11, 1), + PIN_FIELD_BASE(174, 174, 7, 0x0060, 0x10, 12, 1), + PIN_FIELD_BASE(175, 175, 7, 0x0060, 0x10, 13, 1), + PIN_FIELD_BASE(176, 176, 7, 0x0060, 0x10, 14, 1), + PIN_FIELD_BASE(177, 177, 7, 0x0060, 0x10, 15, 1), + PINS_FIELD_BASE(178, 179, 7, 0x0060, 0x10, 16, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_pu_range[] = { + PIN_FIELD_BASE(0, 0, 2, 0x0060, 0x10, 6, 1), + PIN_FIELD_BASE(1, 1, 2, 0x0060, 0x10, 7, 1), + PIN_FIELD_BASE(2, 2, 2, 0x0060, 0x10, 10, 1), + PIN_FIELD_BASE(3, 3, 2, 0x0060, 0x10, 11, 1), + PIN_FIELD_BASE(4, 4, 2, 0x0060, 0x10, 12, 1), + PIN_FIELD_BASE(5, 5, 2, 0x0060, 0x10, 13, 1), + PIN_FIELD_BASE(6, 6, 2, 0x0060, 0x10, 14, 1), + PIN_FIELD_BASE(7, 7, 2, 0x0060, 0x10, 15, 1), + PIN_FIELD_BASE(8, 8, 3, 0x0050, 0x10, 12, 1), + PIN_FIELD_BASE(9, 9, 2, 0x0060, 0x10, 16, 1), + PIN_FIELD_BASE(10, 10, 2, 0x0060, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 2, 0x0060, 0x10, 9, 1), + PIN_FIELD_BASE(12, 12, 5, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(13, 13, 6, 0x0060, 0x10, 14, 1), + PIN_FIELD_BASE(14, 14, 6, 0x0060, 0x10, 13, 1), + PIN_FIELD_BASE(15, 15, 6, 0x0060, 0x10, 15, 1), + PIN_FIELD_BASE(16, 16, 6, 0x0060, 0x10, 12, 1), + PIN_FIELD_BASE(17, 17, 6, 0x0060, 0x10, 7, 1), + PIN_FIELD_BASE(18, 18, 6, 0x0060, 0x10, 4, 1), + PIN_FIELD_BASE(19, 19, 6, 0x0060, 0x10, 6, 1), + PIN_FIELD_BASE(20, 20, 6, 0x0060, 0x10, 5, 1), + PIN_FIELD_BASE(21, 21, 6, 0x0060, 0x10, 10, 1), + PIN_FIELD_BASE(22, 22, 6, 0x0060, 0x10, 9, 1), + PIN_FIELD_BASE(23, 23, 6, 0x0060, 0x10, 11, 1), + PIN_FIELD_BASE(24, 24, 6, 0x0060, 0x10, 8, 1), + PIN_FIELD_BASE(25, 25, 6, 0x0060, 0x10, 2, 1), + PIN_FIELD_BASE(26, 26, 6, 0x0060, 0x10, 1, 1), + PIN_FIELD_BASE(27, 27, 6, 0x0060, 0x10, 3, 1), + PINS_FIELD_BASE(28, 40, 6, 0x0060, 0x10, 0, 1), + PIN_FIELD_BASE(41, 41, 7, 0x0080, 0x10, 19, 1), + PIN_FIELD_BASE(42, 42, 7, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 7, 0x0080, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 7, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(45, 45, 7, 0x0080, 0x10, 22, 1), + PIN_FIELD_BASE(46, 46, 7, 0x0080, 0x10, 21, 1), + PIN_FIELD_BASE(47, 47, 7, 0x0080, 0x10, 20, 1), + PIN_FIELD_BASE(48, 48, 7, 0x0090, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 7, 0x0090, 0x10, 5, 1), + PIN_FIELD_BASE(50, 50, 7, 0x0090, 0x10, 2, 1), + PIN_FIELD_BASE(51, 51, 7, 0x0090, 0x10, 4, 1), + PIN_FIELD_BASE(52, 52, 7, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(53, 53, 7, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(54, 54, 7, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(55, 55, 7, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(56, 56, 7, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(57, 57, 7, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(58, 58, 7, 0x0090, 0x10, 0, 1), + PIN_FIELD_BASE(59, 59, 7, 0x0080, 0x10, 31, 1), + PIN_FIELD_BASE(60, 60, 7, 0x0080, 0x10, 30, 1), + PIN_FIELD_BASE(61, 61, 3, 0x0050, 0x10, 18, 1), + PIN_FIELD_BASE(62, 62, 3, 0x0050, 0x10, 14, 1), + PIN_FIELD_BASE(63, 63, 3, 0x0050, 0x10, 17, 1), + PIN_FIELD_BASE(64, 64, 3, 0x0050, 0x10, 13, 1), + PIN_FIELD_BASE(65, 65, 3, 0x0050, 0x10, 20, 1), + PIN_FIELD_BASE(66, 66, 3, 0x0050, 0x10, 16, 1), + PIN_FIELD_BASE(67, 67, 3, 0x0050, 0x10, 19, 1), + PIN_FIELD_BASE(68, 68, 3, 0x0050, 0x10, 15, 1), + PIN_FIELD_BASE(69, 69, 3, 0x0050, 0x10, 8, 1), + PIN_FIELD_BASE(70, 70, 3, 0x0050, 0x10, 7, 1), + PIN_FIELD_BASE(71, 71, 3, 0x0050, 0x10, 6, 1), + PIN_FIELD_BASE(72, 72, 3, 0x0050, 0x10, 5, 1), + PIN_FIELD_BASE(73, 73, 3, 0x0050, 0x10, 4, 1), + PIN_FIELD_BASE(74, 74, 3, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(75, 75, 3, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(76, 76, 3, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(77, 77, 3, 0x0050, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 3, 0x0050, 0x10, 9, 1), + PIN_FIELD_BASE(79, 79, 3, 0x0050, 0x10, 11, 1), + PIN_FIELD_BASE(80, 80, 3, 0x0050, 0x10, 10, 1), + PIN_FIELD_BASE(81, 81, 3, 0x0050, 0x10, 25, 1), + PIN_FIELD_BASE(82, 82, 3, 0x0050, 0x10, 24, 1), + PIN_FIELD_BASE(83, 83, 3, 0x0050, 0x10, 22, 1), + PIN_FIELD_BASE(84, 84, 3, 0x0050, 0x10, 23, 1), + PIN_FIELD_BASE(85, 85, 7, 0x0090, 0x10, 1, 1), + PIN_FIELD_BASE(86, 86, 7, 0x0080, 0x10, 29, 1), + PIN_FIELD_BASE(87, 87, 7, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(88, 88, 7, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(89, 89, 2, 0x0060, 0x10, 21, 1), + PINS_FIELD_BASE(90, 94, 3, 0x0050, 0x10, 21, 1), + PIN_FIELD_BASE(95, 95, 2, 0x0060, 0x10, 22, 1), + PIN_FIELD_BASE(96, 96, 2, 0x0060, 0x10, 23, 1), + PIN_FIELD_BASE(97, 97, 2, 0x0060, 0x10, 2, 1), + PIN_FIELD_BASE(98, 98, 2, 0x0060, 0x10, 3, 1), + PIN_FIELD_BASE(99, 99, 2, 0x0060, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 2, 0x0060, 0x10, 1, 1), + PIN_FIELD_BASE(101, 101, 2, 0x0060, 0x10, 4, 1), + PIN_FIELD_BASE(102, 102, 2, 0x0060, 0x10, 5, 1), + PIN_FIELD_BASE(103, 103, 2, 0x0060, 0x10, 17, 1), + PIN_FIELD_BASE(104, 104, 2, 0x0060, 0x10, 19, 1), + PIN_FIELD_BASE(105, 105, 2, 0x0060, 0x10, 18, 1), + PIN_FIELD_BASE(106, 106, 2, 0x0060, 0x10, 20, 1), + PIN_FIELD_BASE(107, 107, 1, 0x0050, 0x10, 4, 1), + PIN_FIELD_BASE(108, 108, 1, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(109, 109, 1, 0x0050, 0x10, 5, 1), + PIN_FIELD_BASE(110, 110, 1, 0x0050, 0x10, 0, 1), + PIN_FIELD_BASE(111, 111, 1, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(112, 112, 1, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(113, 113, 1, 0x0050, 0x10, 9, 1), + PIN_FIELD_BASE(114, 114, 1, 0x0050, 0x10, 10, 1), + PIN_FIELD_BASE(115, 115, 1, 0x0050, 0x10, 6, 1), + PIN_FIELD_BASE(116, 116, 1, 0x0050, 0x10, 7, 1), + PIN_FIELD_BASE(117, 117, 1, 0x0050, 0x10, 12, 1), + PIN_FIELD_BASE(118, 118, 1, 0x0050, 0x10, 13, 1), + PIN_FIELD_BASE(119, 119, 1, 0x0050, 0x10, 14, 1), + PIN_FIELD_BASE(120, 120, 1, 0x0050, 0x10, 11, 1), + PINS_FIELD_BASE(121, 133, 1, 0x0050, 0x10, 8, 1), + PIN_FIELD_BASE(134, 134, 5, 0x0040, 0x10, 14, 1), + PIN_FIELD_BASE(135, 135, 5, 0x0040, 0x10, 19, 1), + PIN_FIELD_BASE(136, 136, 5, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(137, 137, 5, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(138, 138, 5, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(139, 139, 5, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(140, 140, 5, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(141, 141, 5, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(142, 142, 5, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(143, 143, 5, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(144, 144, 5, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(145, 145, 5, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(146, 146, 5, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(147, 147, 5, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(148, 148, 5, 0x0040, 0x10, 15, 1), + PIN_FIELD_BASE(149, 149, 5, 0x0040, 0x10, 16, 1), + PIN_FIELD_BASE(150, 150, 7, 0x0080, 0x10, 23, 1), + PIN_FIELD_BASE(151, 151, 7, 0x0080, 0x10, 24, 1), + PIN_FIELD_BASE(152, 152, 7, 0x0080, 0x10, 25, 1), + PIN_FIELD_BASE(153, 153, 7, 0x0080, 0x10, 26, 1), + PIN_FIELD_BASE(154, 154, 7, 0x0080, 0x10, 28, 1), + PIN_FIELD_BASE(155, 155, 3, 0x0050, 0x10, 28, 1), + PIN_FIELD_BASE(156, 156, 3, 0x0050, 0x10, 27, 1), + PIN_FIELD_BASE(157, 157, 3, 0x0050, 0x10, 29, 1), + PIN_FIELD_BASE(158, 158, 3, 0x0050, 0x10, 26, 1), + PIN_FIELD_BASE(159, 159, 7, 0x0080, 0x10, 27, 1), + PIN_FIELD_BASE(160, 160, 5, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(161, 161, 1, 0x0050, 0x10, 15, 1), + PIN_FIELD_BASE(162, 162, 1, 0x0050, 0x10, 16, 1), + PIN_FIELD_BASE(163, 163, 4, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(164, 164, 4, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(165, 165, 4, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(166, 166, 4, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(167, 167, 4, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(168, 168, 4, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(169, 169, 4, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(170, 170, 4, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(171, 171, 7, 0x0080, 0x10, 17, 1), + PIN_FIELD_BASE(172, 172, 7, 0x0080, 0x10, 18, 1), + PIN_FIELD_BASE(173, 173, 7, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(174, 174, 7, 0x0080, 0x10, 12, 1), + PIN_FIELD_BASE(175, 175, 7, 0x0080, 0x10, 13, 1), + PIN_FIELD_BASE(176, 176, 7, 0x0080, 0x10, 14, 1), + PIN_FIELD_BASE(177, 177, 7, 0x0080, 0x10, 15, 1), + PINS_FIELD_BASE(178, 179, 7, 0x0080, 0x10, 16, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_tdsel_range[] = { + PINS_FIELD_BASE(0, 3, 2, 0x00c0, 0x10, 16, 4), + PINS_FIELD_BASE(4, 7, 2, 0x00c0, 0x10, 20, 4), + PIN_FIELD_BASE(8, 8, 3, 0x0090, 0x10, 12, 4), + PINS_FIELD_BASE(9, 11, 2, 0x00c0, 0x10, 24, 4), + PIN_FIELD_BASE(12, 12, 5, 0x0080, 0x10, 4, 4), + PINS_FIELD_BASE(13, 16, 6, 0x00e0, 0x10, 8, 4), + PINS_FIELD_BASE(17, 20, 6, 0x00e0, 0x10, 0, 4), + PINS_FIELD_BASE(21, 24, 6, 0x00e0, 0x10, 4, 4), + PINS_FIELD_BASE(25, 28, 6, 0x00d0, 0x10, 28, 4), + PIN_FIELD_BASE(29, 29, 6, 0x00d0, 0x10, 0, 4), + PIN_FIELD_BASE(30, 30, 6, 0x00d0, 0x10, 4, 4), + PINS_FIELD_BASE(31, 34, 6, 0x00d0, 0x10, 8, 4), + PINS_FIELD_BASE(35, 36, 6, 0x00d0, 0x10, 20, 4), + PIN_FIELD_BASE(37, 37, 6, 0x00d0, 0x10, 24, 4), + PIN_FIELD_BASE(38, 38, 6, 0x00d0, 0x10, 16, 4), + PINS_FIELD_BASE(39, 40, 6, 0x00d0, 0x10, 12, 4), + PINS_FIELD_BASE(41, 42, 7, 0x00d0, 0x10, 24, 4), + PIN_FIELD_BASE(43, 43, 7, 0x00d0, 0x10, 12, 4), + PIN_FIELD_BASE(44, 44, 7, 0x00d0, 0x10, 16, 4), + PIN_FIELD_BASE(45, 45, 7, 0x00e0, 0x10, 0, 4), + PINS_FIELD_BASE(46, 47, 7, 0x00d0, 0x10, 28, 4), + PINS_FIELD_BASE(48, 49, 7, 0x00e0, 0x10, 28, 4), + PINS_FIELD_BASE(50, 51, 7, 0x00e0, 0x10, 24, 4), + PINS_FIELD_BASE(52, 57, 7, 0x00d0, 0x10, 0, 4), + PINS_FIELD_BASE(58, 60, 7, 0x00e0, 0x10, 16, 4), + PINS_FIELD_BASE(61, 62, 3, 0x0090, 0x10, 20, 4), + PINS_FIELD_BASE(63, 64, 3, 0x0090, 0x10, 16, 4), + PINS_FIELD_BASE(65, 66, 3, 0x0090, 0x10, 28, 4), + PINS_FIELD_BASE(67, 68, 3, 0x0090, 0x10, 24, 4), + PINS_FIELD_BASE(69, 73, 3, 0x0090, 0x10, 4, 4), + PINS_FIELD_BASE(74, 78, 3, 0x0090, 0x10, 8, 4), + PINS_FIELD_BASE(79, 80, 3, 0x0090, 0x10, 0, 4), + PIN_FIELD_BASE(81, 81, 3, 0x00a0, 0x10, 8, 4), + PINS_FIELD_BASE(82, 83, 3, 0x00a0, 0x10, 4, 4), + PIN_FIELD_BASE(84, 84, 3, 0x00a0, 0x10, 8, 4), + PIN_FIELD_BASE(85, 85, 7, 0x00e0, 0x10, 16, 4), + PIN_FIELD_BASE(86, 86, 7, 0x00e0, 0x10, 20, 4), + PIN_FIELD_BASE(87, 87, 7, 0x00d0, 0x10, 8, 4), + PIN_FIELD_BASE(88, 88, 7, 0x00d0, 0x10, 4, 4), + PIN_FIELD_BASE(89, 89, 2, 0x00d0, 0x10, 12, 4), + PIN_FIELD_BASE(90, 90, 3, 0x00a0, 0x10, 0, 4), + PINS_FIELD_BASE(91, 92, 2, 0x00d0, 0x10, 0, 4), + PINS_FIELD_BASE(93, 94, 2, 0x00c0, 0x10, 28, 4), + PINS_FIELD_BASE(95, 96, 2, 0x00d0, 0x10, 16, 4), + PINS_FIELD_BASE(97, 98, 2, 0x00c0, 0x10, 8, 4), + PIN_FIELD_BASE(99, 99, 2, 0x00c0, 0x10, 0, 4), + PIN_FIELD_BASE(100, 100, 2, 0x00c0, 0x10, 4, 4), + PINS_FIELD_BASE(101, 102, 2, 0x00c0, 0x10, 12, 4), + PINS_FIELD_BASE(103, 104, 2, 0x00d0, 0x10, 4, 4), + PINS_FIELD_BASE(105, 106, 2, 0x00d0, 0x10, 8, 4), + PIN_FIELD_BASE(107, 107, 1, 0x0090, 0x10, 16, 4), + PIN_FIELD_BASE(108, 108, 1, 0x0090, 0x10, 12, 4), + PIN_FIELD_BASE(109, 109, 1, 0x0090, 0x10, 20, 4), + PIN_FIELD_BASE(110, 110, 1, 0x0090, 0x10, 0, 4), + PIN_FIELD_BASE(111, 111, 1, 0x0090, 0x10, 4, 4), + PIN_FIELD_BASE(112, 112, 1, 0x0090, 0x10, 8, 4), + PIN_FIELD_BASE(113, 113, 1, 0x00a0, 0x10, 4, 4), + PIN_FIELD_BASE(114, 114, 1, 0x00a0, 0x10, 8, 4), + PIN_FIELD_BASE(115, 115, 1, 0x0090, 0x10, 24, 4), + PIN_FIELD_BASE(116, 116, 1, 0x0090, 0x10, 28, 4), + PIN_FIELD_BASE(117, 117, 1, 0x00a0, 0x10, 16, 4), + PIN_FIELD_BASE(118, 118, 1, 0x00a0, 0x10, 20, 4), + PIN_FIELD_BASE(119, 119, 1, 0x00a0, 0x10, 24, 4), + PIN_FIELD_BASE(120, 120, 1, 0x00a0, 0x10, 12, 4), + PIN_FIELD_BASE(121, 121, 1, 0x00a0, 0x10, 0, 4), + PIN_FIELD_BASE(122, 122, 4, 0x0090, 0x10, 8, 4), + PIN_FIELD_BASE(123, 123, 4, 0x0090, 0x10, 12, 4), + PIN_FIELD_BASE(124, 124, 4, 0x0090, 0x10, 4, 4), + PINS_FIELD_BASE(125, 130, 4, 0x0090, 0x10, 12, 4), + PIN_FIELD_BASE(131, 131, 4, 0x0090, 0x10, 16, 4), + PIN_FIELD_BASE(132, 132, 4, 0x0090, 0x10, 12, 4), + PIN_FIELD_BASE(133, 133, 4, 0x0090, 0x10, 20, 4), + PIN_FIELD_BASE(134, 134, 5, 0x0080, 0x10, 12, 4), + PIN_FIELD_BASE(135, 135, 5, 0x0080, 0x10, 20, 4), + PIN_FIELD_BASE(136, 136, 5, 0x0070, 0x10, 4, 4), + PIN_FIELD_BASE(137, 137, 5, 0x0070, 0x10, 28, 4), + PIN_FIELD_BASE(138, 138, 5, 0x0070, 0x10, 16, 4), + PIN_FIELD_BASE(139, 139, 5, 0x0070, 0x10, 20, 4), + PIN_FIELD_BASE(140, 140, 5, 0x0070, 0x10, 0, 4), + PIN_FIELD_BASE(141, 141, 5, 0x0070, 0x10, 24, 4), + PIN_FIELD_BASE(142, 142, 5, 0x0070, 0x10, 8, 4), + PIN_FIELD_BASE(143, 143, 5, 0x0070, 0x10, 12, 4), + PINS_FIELD_BASE(144, 147, 5, 0x0080, 0x10, 8, 4), + PINS_FIELD_BASE(148, 149, 5, 0x0080, 0x10, 16, 4), + PINS_FIELD_BASE(150, 151, 7, 0x00e0, 0x10, 4, 4), + PINS_FIELD_BASE(152, 153, 7, 0x00e0, 0x10, 8, 4), + PIN_FIELD_BASE(154, 154, 7, 0x00e0, 0x10, 12, 4), + PINS_FIELD_BASE(155, 158, 3, 0x00a0, 0x10, 12, 4), + PIN_FIELD_BASE(159, 159, 7, 0x00e0, 0x10, 12, 4), + PIN_FIELD_BASE(160, 160, 5, 0x0080, 0x10, 0, 4), + PINS_FIELD_BASE(161, 162, 1, 0x00a0, 0x10, 28, 4), + PINS_FIELD_BASE(163, 170, 4, 0x0090, 0x10, 0, 4), + PINS_FIELD_BASE(171, 179, 7, 0x00d0, 0x10, 20, 4), +}; + +static const struct mtk_pin_field_calc mt6765_pin_rdsel_range[] = { + PINS_FIELD_BASE(0, 3, 2, 0x0090, 0x10, 8, 2), + PINS_FIELD_BASE(4, 7, 2, 0x0090, 0x10, 10, 2), + PIN_FIELD_BASE(8, 8, 3, 0x0060, 0x10, 6, 2), + PINS_FIELD_BASE(9, 11, 2, 0x0090, 0x10, 12, 2), + PIN_FIELD_BASE(12, 12, 5, 0x0050, 0x10, 18, 2), + PINS_FIELD_BASE(13, 16, 6, 0x00a0, 0x10, 18, 2), + PINS_FIELD_BASE(17, 20, 6, 0x00a0, 0x10, 14, 2), + PINS_FIELD_BASE(21, 24, 6, 0x00a0, 0x10, 16, 2), + PINS_FIELD_BASE(25, 28, 6, 0x00a0, 0x10, 12, 2), + PIN_FIELD_BASE(29, 29, 6, 0x0090, 0x10, 0, 6), + PIN_FIELD_BASE(30, 30, 6, 0x0090, 0x10, 6, 6), + PINS_FIELD_BASE(31, 34, 6, 0x0090, 0x10, 12, 6), + PINS_FIELD_BASE(35, 36, 6, 0x00a0, 0x10, 0, 6), + PIN_FIELD_BASE(37, 37, 6, 0x00a0, 0x10, 6, 6), + PIN_FIELD_BASE(38, 38, 6, 0x0090, 0x10, 24, 6), + PINS_FIELD_BASE(39, 40, 6, 0x0090, 0x10, 18, 6), + PINS_FIELD_BASE(41, 42, 7, 0x00a0, 0x10, 12, 2), + PIN_FIELD_BASE(43, 43, 7, 0x00a0, 0x10, 6, 2), + PIN_FIELD_BASE(44, 44, 7, 0x00a0, 0x10, 8, 2), + PIN_FIELD_BASE(45, 45, 7, 0x00a0, 0x10, 16, 2), + PINS_FIELD_BASE(46, 47, 7, 0x00a0, 0x10, 14, 2), + PINS_FIELD_BASE(48, 49, 7, 0x00a0, 0x10, 30, 2), + PINS_FIELD_BASE(50, 51, 7, 0x00a0, 0x10, 28, 2), + PINS_FIELD_BASE(52, 57, 7, 0x00a0, 0x10, 0, 2), + PINS_FIELD_BASE(58, 60, 7, 0x00a0, 0x10, 24, 2), + PINS_FIELD_BASE(61, 62, 3, 0x0060, 0x10, 10, 2), + PINS_FIELD_BASE(63, 64, 3, 0x0060, 0x10, 8, 2), + PINS_FIELD_BASE(65, 66, 3, 0x0060, 0x10, 14, 2), + PINS_FIELD_BASE(67, 68, 3, 0x0060, 0x10, 12, 2), + PINS_FIELD_BASE(69, 73, 3, 0x0060, 0x10, 2, 2), + PINS_FIELD_BASE(74, 78, 3, 0x0060, 0x10, 4, 2), + PINS_FIELD_BASE(79, 80, 3, 0x0060, 0x10, 0, 2), + PIN_FIELD_BASE(81, 81, 3, 0x0060, 0x10, 20, 2), + PINS_FIELD_BASE(82, 83, 3, 0x0060, 0x10, 18, 2), + PIN_FIELD_BASE(84, 84, 3, 0x0060, 0x10, 20, 2), + PIN_FIELD_BASE(85, 85, 7, 0x00a0, 0x10, 24, 2), + PIN_FIELD_BASE(86, 86, 7, 0x00a0, 0x10, 26, 2), + PIN_FIELD_BASE(87, 87, 7, 0x00a0, 0x10, 4, 2), + PIN_FIELD_BASE(88, 88, 7, 0x00a0, 0x10, 2, 2), + PIN_FIELD_BASE(89, 89, 2, 0x0090, 0x10, 22, 2), + PIN_FIELD_BASE(90, 90, 3, 0x0060, 0x10, 16, 2), + PINS_FIELD_BASE(91, 92, 2, 0x0090, 0x10, 16, 2), + PINS_FIELD_BASE(93, 94, 2, 0x0090, 0x10, 14, 2), + PINS_FIELD_BASE(95, 96, 2, 0x0090, 0x10, 24, 2), + PINS_FIELD_BASE(97, 98, 2, 0x0090, 0x10, 4, 2), + PIN_FIELD_BASE(99, 99, 2, 0x0090, 0x10, 0, 2), + PIN_FIELD_BASE(100, 100, 2, 0x0090, 0x10, 2, 2), + PINS_FIELD_BASE(101, 102, 2, 0x0090, 0x10, 6, 2), + PINS_FIELD_BASE(103, 104, 2, 0x0090, 0x10, 18, 2), + PINS_FIELD_BASE(105, 106, 2, 0x0090, 0x10, 20, 2), + PIN_FIELD_BASE(107, 107, 1, 0x0060, 0x10, 8, 2), + PIN_FIELD_BASE(108, 108, 1, 0x0060, 0x10, 6, 2), + PIN_FIELD_BASE(109, 109, 1, 0x0060, 0x10, 10, 2), + PIN_FIELD_BASE(110, 110, 1, 0x0060, 0x10, 0, 2), + PIN_FIELD_BASE(111, 111, 1, 0x0060, 0x10, 2, 2), + PIN_FIELD_BASE(112, 112, 1, 0x0060, 0x10, 4, 2), + PIN_FIELD_BASE(113, 113, 1, 0x0060, 0x10, 18, 2), + PIN_FIELD_BASE(114, 114, 1, 0x0060, 0x10, 20, 2), + PIN_FIELD_BASE(115, 115, 1, 0x0060, 0x10, 12, 2), + PIN_FIELD_BASE(116, 116, 1, 0x0060, 0x10, 14, 2), + PIN_FIELD_BASE(117, 117, 1, 0x0060, 0x10, 24, 2), + PIN_FIELD_BASE(118, 118, 1, 0x0060, 0x10, 26, 2), + PIN_FIELD_BASE(119, 119, 1, 0x0060, 0x10, 28, 2), + PIN_FIELD_BASE(120, 120, 1, 0x0060, 0x10, 22, 2), + PIN_FIELD_BASE(121, 121, 1, 0x0060, 0x10, 16, 2), + PIN_FIELD_BASE(122, 122, 4, 0x0070, 0x10, 8, 6), + PIN_FIELD_BASE(123, 123, 4, 0x0070, 0x10, 14, 6), + PIN_FIELD_BASE(124, 124, 4, 0x0070, 0x10, 2, 6), + PINS_FIELD_BASE(125, 130, 4, 0x0070, 0x10, 14, 6), + PIN_FIELD_BASE(131, 131, 4, 0x0070, 0x10, 20, 6), + PIN_FIELD_BASE(132, 132, 4, 0x0070, 0x10, 14, 6), + PIN_FIELD_BASE(133, 133, 4, 0x0070, 0x10, 26, 6), + PIN_FIELD_BASE(134, 134, 5, 0x0050, 0x10, 22, 2), + PIN_FIELD_BASE(135, 135, 5, 0x0050, 0x10, 30, 2), + PIN_FIELD_BASE(136, 136, 5, 0x0050, 0x10, 2, 2), + PIN_FIELD_BASE(137, 137, 5, 0x0050, 0x10, 14, 2), + PIN_FIELD_BASE(138, 138, 5, 0x0050, 0x10, 8, 2), + PIN_FIELD_BASE(139, 139, 5, 0x0050, 0x10, 10, 2), + PIN_FIELD_BASE(140, 140, 5, 0x0050, 0x10, 0, 2), + PIN_FIELD_BASE(141, 141, 5, 0x0050, 0x10, 12, 2), + PIN_FIELD_BASE(142, 142, 5, 0x0050, 0x10, 4, 2), + PIN_FIELD_BASE(143, 143, 5, 0x0050, 0x10, 6, 2), + PINS_FIELD_BASE(144, 147, 5, 0x0050, 0x10, 20, 2), + PINS_FIELD_BASE(148, 149, 5, 0x0050, 0x10, 24, 2), + PINS_FIELD_BASE(150, 151, 7, 0x00a0, 0x10, 18, 2), + PINS_FIELD_BASE(152, 153, 7, 0x00a0, 0x10, 20, 2), + PIN_FIELD_BASE(154, 154, 7, 0x00a0, 0x10, 22, 2), + PINS_FIELD_BASE(155, 158, 3, 0x0060, 0x10, 22, 2), + PIN_FIELD_BASE(159, 159, 7, 0x00a0, 0x10, 22, 2), + PIN_FIELD_BASE(160, 160, 5, 0x0050, 0x10, 16, 2), + PINS_FIELD_BASE(161, 162, 1, 0x0060, 0x10, 30, 2), + PINS_FIELD_BASE(163, 170, 4, 0x0070, 0x10, 0, 2), + PINS_FIELD_BASE(171, 179, 7, 0x00a0, 0x10, 10, 2), +}; + +static const struct mtk_pin_field_calc mt6765_pin_drv_range[] = { + PINS_FIELD_BASE(0, 2, 2, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(3, 3, 2, 0x0000, 0x10, 15, 3), + PINS_FIELD_BASE(4, 6, 2, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(7, 7, 2, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(8, 8, 3, 0x0000, 0x10, 9, 3), + PINS_FIELD_BASE(9, 11, 2, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(12, 12, 5, 0x0000, 0x10, 27, 3), + PINS_FIELD_BASE(13, 15, 6, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(16, 16, 6, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(17, 17, 6, 0x0000, 0x10, 23, 3), + PIN_FIELD_BASE(18, 18, 6, 0x0000, 0x10, 26, 3), + PINS_FIELD_BASE(19, 20, 6, 0x0000, 0x10, 23, 3), + PINS_FIELD_BASE(21, 23, 6, 0x0000, 0x10, 29, 3), + PIN_FIELD_BASE(24, 24, 6, 0x0010, 0x10, 0, 3), + PINS_FIELD_BASE(25, 27, 6, 0x0000, 0x10, 17, 3), + PIN_FIELD_BASE(28, 28, 6, 0x0000, 0x10, 20, 3), + PIN_FIELD_BASE(29, 29, 6, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(30, 30, 6, 0x0000, 0x10, 3, 3), + PINS_FIELD_BASE(31, 34, 6, 0x0000, 0x10, 6, 3), + PINS_FIELD_BASE(35, 36, 6, 0x0000, 0x10, 13, 2), + PIN_FIELD_BASE(37, 37, 6, 0x0000, 0x10, 15, 2), + PIN_FIELD_BASE(38, 38, 6, 0x0000, 0x10, 11, 2), + PINS_FIELD_BASE(39, 40, 6, 0x0000, 0x10, 9, 2), + PINS_FIELD_BASE(41, 42, 7, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(43, 43, 7, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(44, 44, 7, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(45, 45, 7, 0x0000, 0x10, 27, 3), + PINS_FIELD_BASE(46, 47, 7, 0x0000, 0x10, 24, 3), + PINS_FIELD_BASE(48, 49, 7, 0x0010, 0x10, 18, 3), + PINS_FIELD_BASE(50, 51, 7, 0x0010, 0x10, 15, 3), + PINS_FIELD_BASE(52, 57, 7, 0x0000, 0x10, 0, 3), + PINS_FIELD_BASE(58, 60, 7, 0x0010, 0x10, 9, 3), + PINS_FIELD_BASE(61, 62, 3, 0x0000, 0x10, 15, 3), + PINS_FIELD_BASE(63, 64, 3, 0x0000, 0x10, 12, 3), + PINS_FIELD_BASE(65, 66, 3, 0x0000, 0x10, 21, 3), + PINS_FIELD_BASE(67, 68, 3, 0x0000, 0x10, 18, 3), + PINS_FIELD_BASE(69, 73, 3, 0x0000, 0x10, 3, 3), + PINS_FIELD_BASE(74, 78, 3, 0x0000, 0x10, 6, 3), + PINS_FIELD_BASE(79, 80, 3, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(81, 81, 3, 0x0010, 0x10, 0, 3), + PINS_FIELD_BASE(82, 83, 3, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(84, 84, 3, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(85, 85, 7, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(86, 86, 7, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(87, 87, 7, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(88, 88, 7, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(89, 89, 2, 0x0010, 0x10, 15, 3), + PIN_FIELD_BASE(90, 90, 3, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(91, 91, 2, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(92, 92, 2, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(93, 93, 2, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(94, 94, 2, 0x0010, 0x10, 0, 3), + PINS_FIELD_BASE(95, 96, 2, 0x0010, 0x10, 18, 3), + PINS_FIELD_BASE(97, 98, 2, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(99, 99, 2, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(100, 100, 2, 0x0000, 0x10, 3, 3), + PINS_FIELD_BASE(101, 102, 2, 0x0000, 0x10, 9, 3), + PINS_FIELD_BASE(103, 104, 2, 0x0010, 0x10, 9, 3), + PINS_FIELD_BASE(105, 106, 2, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(107, 107, 1, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(108, 108, 1, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(109, 109, 1, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(110, 110, 1, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(111, 111, 1, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(112, 112, 1, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(113, 113, 1, 0x0000, 0x10, 27, 3), + PIN_FIELD_BASE(114, 114, 1, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(115, 115, 1, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(116, 116, 1, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(117, 117, 1, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(118, 118, 1, 0x0010, 0x10, 9, 3), + PIN_FIELD_BASE(119, 119, 1, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(120, 120, 1, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(121, 121, 1, 0x0000, 0x10, 24, 3), + PIN_FIELD_BASE(122, 122, 4, 0x0000, 0x10, 9, 3), + PIN_FIELD_BASE(123, 123, 4, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(124, 124, 4, 0x0000, 0x10, 6, 3), + PINS_FIELD_BASE(125, 130, 4, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(131, 131, 4, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(132, 132, 4, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(133, 133, 4, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(134, 134, 5, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(135, 135, 5, 0x0010, 0x10, 12, 3), + PIN_FIELD_BASE(136, 136, 5, 0x0000, 0x10, 3, 3), + PIN_FIELD_BASE(137, 137, 5, 0x0000, 0x10, 21, 3), + PIN_FIELD_BASE(138, 138, 5, 0x0000, 0x10, 12, 3), + PIN_FIELD_BASE(139, 139, 5, 0x0000, 0x10, 15, 3), + PIN_FIELD_BASE(140, 140, 5, 0x0000, 0x10, 0, 3), + PIN_FIELD_BASE(141, 141, 5, 0x0000, 0x10, 18, 3), + PIN_FIELD_BASE(142, 142, 5, 0x0000, 0x10, 6, 3), + PIN_FIELD_BASE(143, 143, 5, 0x0000, 0x10, 9, 3), + PINS_FIELD_BASE(144, 146, 5, 0x0010, 0x10, 0, 3), + PIN_FIELD_BASE(147, 147, 5, 0x0010, 0x10, 3, 3), + PINS_FIELD_BASE(148, 149, 5, 0x0010, 0x10, 9, 3), + PINS_FIELD_BASE(150, 151, 7, 0x0010, 0x10, 0, 3), + PINS_FIELD_BASE(152, 153, 7, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(154, 154, 7, 0x0010, 0x10, 6, 3), + PINS_FIELD_BASE(155, 157, 3, 0x0010, 0x10, 3, 3), + PIN_FIELD_BASE(158, 158, 3, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(159, 159, 7, 0x0010, 0x10, 6, 3), + PIN_FIELD_BASE(160, 160, 5, 0x0000, 0x10, 24, 3), + PINS_FIELD_BASE(161, 162, 1, 0x0010, 0x10, 15, 3), + PINS_FIELD_BASE(163, 166, 4, 0x0000, 0x10, 0, 3), + PINS_FIELD_BASE(167, 170, 4, 0x0000, 0x10, 3, 3), + PINS_FIELD_BASE(171, 174, 7, 0x0000, 0x10, 18, 3), + PINS_FIELD_BASE(175, 179, 7, 0x0000, 0x10, 15, 3), +}; + +static const struct mtk_pin_field_calc mt6765_pin_pupd_range[] = { + PINS_FIELD_BASE(0, 28, 0, 0x0050, 0x10, 18, 1), + PIN_FIELD_BASE(29, 29, 6, 0x0050, 0x10, 0, 1), + PIN_FIELD_BASE(30, 30, 6, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(31, 31, 6, 0x0050, 0x10, 5, 1), + PIN_FIELD_BASE(32, 32, 6, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 6, 0x0050, 0x10, 4, 1), + PIN_FIELD_BASE(34, 34, 6, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(35, 35, 6, 0x0050, 0x10, 10, 1), + PIN_FIELD_BASE(36, 36, 6, 0x0050, 0x10, 11, 1), + PIN_FIELD_BASE(37, 37, 6, 0x0050, 0x10, 9, 1), + PIN_FIELD_BASE(38, 38, 6, 0x0050, 0x10, 6, 1), + PIN_FIELD_BASE(39, 39, 6, 0x0050, 0x10, 8, 1), + PINS_FIELD_BASE(40, 90, 6, 0x0050, 0x10, 7, 1), + PIN_FIELD_BASE(91, 91, 2, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(92, 92, 2, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(93, 93, 2, 0x0050, 0x10, 0, 1), + PINS_FIELD_BASE(94, 121, 2, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(122, 122, 4, 0x0030, 0x10, 1, 1), + PIN_FIELD_BASE(123, 123, 4, 0x0030, 0x10, 2, 1), + PIN_FIELD_BASE(124, 124, 4, 0x0030, 0x10, 0, 1), + PIN_FIELD_BASE(125, 125, 4, 0x0030, 0x10, 4, 1), + PIN_FIELD_BASE(126, 126, 4, 0x0030, 0x10, 6, 1), + PIN_FIELD_BASE(127, 127, 4, 0x0030, 0x10, 8, 1), + PIN_FIELD_BASE(128, 128, 4, 0x0030, 0x10, 3, 1), + PIN_FIELD_BASE(129, 129, 4, 0x0030, 0x10, 7, 1), + PIN_FIELD_BASE(130, 130, 4, 0x0030, 0x10, 9, 1), + PIN_FIELD_BASE(131, 131, 4, 0x0030, 0x10, 10, 1), + PIN_FIELD_BASE(132, 132, 4, 0x0030, 0x10, 5, 1), + PINS_FIELD_BASE(133, 179, 4, 0x0030, 0x10, 11, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_r0_range[] = { + PINS_FIELD_BASE(0, 28, 4, 0x0030, 0x10, 11, 1), + PIN_FIELD_BASE(29, 29, 6, 0x0070, 0x10, 0, 1), + PIN_FIELD_BASE(30, 30, 6, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(31, 31, 6, 0x0070, 0x10, 5, 1), + PIN_FIELD_BASE(32, 32, 6, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 6, 0x0070, 0x10, 4, 1), + PIN_FIELD_BASE(34, 34, 6, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(35, 35, 6, 0x0070, 0x10, 10, 1), + PIN_FIELD_BASE(36, 36, 6, 0x0070, 0x10, 11, 1), + PIN_FIELD_BASE(37, 37, 6, 0x0070, 0x10, 9, 1), + PIN_FIELD_BASE(38, 38, 6, 0x0070, 0x10, 6, 1), + PIN_FIELD_BASE(39, 39, 6, 0x0070, 0x10, 8, 1), + PINS_FIELD_BASE(40, 90, 6, 0x0070, 0x10, 7, 1), + PIN_FIELD_BASE(91, 91, 2, 0x0070, 0x10, 3, 1), + PIN_FIELD_BASE(92, 92, 2, 0x0070, 0x10, 2, 1), + PIN_FIELD_BASE(93, 93, 2, 0x0070, 0x10, 0, 1), + PINS_FIELD_BASE(94, 121, 2, 0x0070, 0x10, 1, 1), + PIN_FIELD_BASE(122, 122, 4, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(124, 124, 4, 0x0050, 0x10, 0, 1), + PIN_FIELD_BASE(125, 125, 4, 0x0050, 0x10, 4, 1), + PIN_FIELD_BASE(126, 126, 4, 0x0050, 0x10, 6, 1), + PIN_FIELD_BASE(127, 127, 4, 0x0050, 0x10, 8, 1), + PIN_FIELD_BASE(128, 128, 4, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(129, 129, 4, 0x0050, 0x10, 7, 1), + PIN_FIELD_BASE(130, 130, 4, 0x0050, 0x10, 9, 1), + PIN_FIELD_BASE(131, 131, 4, 0x0050, 0x10, 10, 1), + PIN_FIELD_BASE(132, 132, 4, 0x0050, 0x10, 5, 1), + PINS_FIELD_BASE(133, 179, 4, 0x0050, 0x10, 11, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_r1_range[] = { + PINS_FIELD_BASE(0, 28, 4, 0x0050, 0x10, 11, 1), + PIN_FIELD_BASE(29, 29, 6, 0x0080, 0x10, 0, 1), + PIN_FIELD_BASE(30, 30, 6, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(31, 31, 6, 0x0080, 0x10, 5, 1), + PIN_FIELD_BASE(32, 32, 6, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 6, 0x0080, 0x10, 4, 1), + PIN_FIELD_BASE(34, 34, 6, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(35, 35, 6, 0x0080, 0x10, 10, 1), + PIN_FIELD_BASE(36, 36, 6, 0x0080, 0x10, 11, 1), + PIN_FIELD_BASE(37, 37, 6, 0x0080, 0x10, 9, 1), + PIN_FIELD_BASE(38, 38, 6, 0x0080, 0x10, 6, 1), + PIN_FIELD_BASE(39, 39, 6, 0x0080, 0x10, 8, 1), + PINS_FIELD_BASE(40, 90, 6, 0x0080, 0x10, 7, 1), + PIN_FIELD_BASE(91, 91, 2, 0x0080, 0x10, 3, 1), + PIN_FIELD_BASE(92, 92, 2, 0x0080, 0x10, 2, 1), + PIN_FIELD_BASE(93, 93, 2, 0x0080, 0x10, 0, 1), + PINS_FIELD_BASE(94, 121, 2, 0x0080, 0x10, 1, 1), + PIN_FIELD_BASE(122, 122, 4, 0x0060, 0x10, 1, 1), + PIN_FIELD_BASE(123, 123, 4, 0x0060, 0x10, 2, 1), + PIN_FIELD_BASE(124, 124, 4, 0x0060, 0x10, 0, 1), + PIN_FIELD_BASE(125, 125, 4, 0x0060, 0x10, 4, 1), + PIN_FIELD_BASE(126, 126, 4, 0x0060, 0x10, 6, 1), + PIN_FIELD_BASE(127, 127, 4, 0x0060, 0x10, 8, 1), + PIN_FIELD_BASE(128, 128, 4, 0x0060, 0x10, 3, 1), + PIN_FIELD_BASE(129, 129, 4, 0x0060, 0x10, 7, 1), + PIN_FIELD_BASE(130, 130, 4, 0x0060, 0x10, 9, 1), + PIN_FIELD_BASE(131, 131, 4, 0x0060, 0x10, 10, 1), + PIN_FIELD_BASE(132, 132, 4, 0x0060, 0x10, 5, 1), + PINS_FIELD_BASE(133, 179, 4, 0x0060, 0x10, 11, 1), +}; + +static const struct mtk_pin_field_calc mt6765_pin_ies_range[] = { + PIN_FIELD_BASE(0, 0, 2, 0x0030, 0x10, 6, 1), + PIN_FIELD_BASE(1, 1, 2, 0x0030, 0x10, 7, 1), + PIN_FIELD_BASE(2, 2, 2, 0x0030, 0x10, 10, 1), + PIN_FIELD_BASE(3, 3, 2, 0x0030, 0x10, 11, 1), + PIN_FIELD_BASE(4, 4, 2, 0x0030, 0x10, 12, 1), + PIN_FIELD_BASE(5, 5, 2, 0x0030, 0x10, 13, 1), + PIN_FIELD_BASE(6, 6, 2, 0x0030, 0x10, 14, 1), + PIN_FIELD_BASE(7, 7, 2, 0x0030, 0x10, 15, 1), + PIN_FIELD_BASE(8, 8, 3, 0x0030, 0x10, 12, 1), + PIN_FIELD_BASE(9, 9, 2, 0x0030, 0x10, 16, 1), + PIN_FIELD_BASE(10, 10, 2, 0x0030, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 2, 0x0030, 0x10, 9, 1), + PIN_FIELD_BASE(12, 12, 5, 0x0020, 0x10, 9, 1), + PIN_FIELD_BASE(13, 13, 6, 0x0020, 0x10, 26, 1), + PIN_FIELD_BASE(14, 14, 6, 0x0020, 0x10, 25, 1), + PIN_FIELD_BASE(15, 15, 6, 0x0020, 0x10, 27, 1), + PIN_FIELD_BASE(16, 16, 6, 0x0020, 0x10, 24, 1), + PIN_FIELD_BASE(17, 17, 6, 0x0020, 0x10, 19, 1), + PIN_FIELD_BASE(18, 18, 6, 0x0020, 0x10, 16, 1), + PIN_FIELD_BASE(19, 19, 6, 0x0020, 0x10, 18, 1), + PIN_FIELD_BASE(20, 20, 6, 0x0020, 0x10, 17, 1), + PIN_FIELD_BASE(21, 21, 6, 0x0020, 0x10, 22, 1), + PIN_FIELD_BASE(22, 22, 6, 0x0020, 0x10, 21, 1), + PIN_FIELD_BASE(23, 23, 6, 0x0020, 0x10, 23, 1), + PIN_FIELD_BASE(24, 24, 6, 0x0020, 0x10, 20, 1), + PIN_FIELD_BASE(25, 25, 6, 0x0020, 0x10, 14, 1), + PIN_FIELD_BASE(26, 26, 6, 0x0020, 0x10, 13, 1), + PIN_FIELD_BASE(27, 27, 6, 0x0020, 0x10, 15, 1), + PIN_FIELD_BASE(28, 28, 6, 0x0020, 0x10, 12, 1), + PIN_FIELD_BASE(29, 29, 6, 0x0020, 0x10, 0, 1), + PIN_FIELD_BASE(30, 30, 6, 0x0020, 0x10, 1, 1), + PIN_FIELD_BASE(31, 31, 6, 0x0020, 0x10, 5, 1), + PIN_FIELD_BASE(32, 32, 6, 0x0020, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 6, 0x0020, 0x10, 4, 1), + PIN_FIELD_BASE(34, 34, 6, 0x0020, 0x10, 3, 1), + PIN_FIELD_BASE(35, 35, 6, 0x0020, 0x10, 10, 1), + PIN_FIELD_BASE(36, 36, 6, 0x0020, 0x10, 11, 1), + PIN_FIELD_BASE(37, 37, 6, 0x0020, 0x10, 9, 1), + PIN_FIELD_BASE(38, 38, 6, 0x0020, 0x10, 6, 1), + PIN_FIELD_BASE(39, 39, 6, 0x0020, 0x10, 8, 1), + PIN_FIELD_BASE(40, 40, 6, 0x0020, 0x10, 7, 1), + PIN_FIELD_BASE(41, 41, 7, 0x0040, 0x10, 19, 1), + PIN_FIELD_BASE(42, 42, 7, 0x0040, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 7, 0x0040, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 7, 0x0040, 0x10, 10, 1), + PIN_FIELD_BASE(45, 45, 7, 0x0040, 0x10, 22, 1), + PIN_FIELD_BASE(46, 46, 7, 0x0040, 0x10, 21, 1), + PIN_FIELD_BASE(47, 47, 7, 0x0040, 0x10, 20, 1), + PIN_FIELD_BASE(48, 48, 7, 0x0050, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 7, 0x0050, 0x10, 5, 1), + PIN_FIELD_BASE(50, 50, 7, 0x0050, 0x10, 2, 1), + PIN_FIELD_BASE(51, 51, 7, 0x0050, 0x10, 4, 1), + PIN_FIELD_BASE(52, 52, 7, 0x0040, 0x10, 1, 1), + PIN_FIELD_BASE(53, 53, 7, 0x0040, 0x10, 0, 1), + PIN_FIELD_BASE(54, 54, 7, 0x0040, 0x10, 5, 1), + PIN_FIELD_BASE(55, 55, 7, 0x0040, 0x10, 3, 1), + PIN_FIELD_BASE(56, 56, 7, 0x0040, 0x10, 4, 1), + PIN_FIELD_BASE(57, 57, 7, 0x0040, 0x10, 2, 1), + PIN_FIELD_BASE(58, 58, 7, 0x0050, 0x10, 0, 1), + PIN_FIELD_BASE(59, 59, 7, 0x0040, 0x10, 31, 1), + PIN_FIELD_BASE(60, 60, 7, 0x0040, 0x10, 30, 1), + PIN_FIELD_BASE(61, 61, 3, 0x0030, 0x10, 18, 1), + PIN_FIELD_BASE(62, 62, 3, 0x0030, 0x10, 14, 1), + PIN_FIELD_BASE(63, 63, 3, 0x0030, 0x10, 17, 1), + PIN_FIELD_BASE(64, 64, 3, 0x0030, 0x10, 13, 1), + PIN_FIELD_BASE(65, 65, 3, 0x0030, 0x10, 20, 1), + PIN_FIELD_BASE(66, 66, 3, 0x0030, 0x10, 16, 1), + PIN_FIELD_BASE(67, 67, 3, 0x0030, 0x10, 19, 1), + PIN_FIELD_BASE(68, 68, 3, 0x0030, 0x10, 15, 1), + PIN_FIELD_BASE(69, 69, 3, 0x0030, 0x10, 8, 1), + PIN_FIELD_BASE(70, 70, 3, 0x0030, 0x10, 7, 1), + PIN_FIELD_BASE(71, 71, 3, 0x0030, 0x10, 6, 1), + PIN_FIELD_BASE(72, 72, 3, 0x0030, 0x10, 5, 1), + PIN_FIELD_BASE(73, 73, 3, 0x0030, 0x10, 4, 1), + PIN_FIELD_BASE(74, 74, 3, 0x0030, 0x10, 3, 1), + PIN_FIELD_BASE(75, 75, 3, 0x0030, 0x10, 2, 1), + PIN_FIELD_BASE(76, 76, 3, 0x0030, 0x10, 1, 1), + PIN_FIELD_BASE(77, 77, 3, 0x0030, 0x10, 0, 1), + PIN_FIELD_BASE(78, 78, 3, 0x0030, 0x10, 9, 1), + PIN_FIELD_BASE(79, 79, 3, 0x0030, 0x10, 11, 1), + PIN_FIELD_BASE(80, 80, 3, 0x0030, 0x10, 10, 1), + PIN_FIELD_BASE(81, 81, 3, 0x0030, 0x10, 25, 1), + PIN_FIELD_BASE(82, 82, 3, 0x0030, 0x10, 24, 1), + PIN_FIELD_BASE(83, 83, 3, 0x0030, 0x10, 22, 1), + PIN_FIELD_BASE(84, 84, 3, 0x0030, 0x10, 23, 1), + PIN_FIELD_BASE(85, 85, 7, 0x0050, 0x10, 1, 1), + PIN_FIELD_BASE(86, 86, 7, 0x0040, 0x10, 29, 1), + PIN_FIELD_BASE(87, 87, 7, 0x0040, 0x10, 7, 1), + PIN_FIELD_BASE(88, 88, 7, 0x0040, 0x10, 6, 1), + PIN_FIELD_BASE(89, 89, 2, 0x0030, 0x10, 25, 1), + PIN_FIELD_BASE(90, 90, 3, 0x0030, 0x10, 21, 1), + PIN_FIELD_BASE(91, 91, 2, 0x0030, 0x10, 20, 1), + PIN_FIELD_BASE(92, 92, 2, 0x0030, 0x10, 19, 1), + PIN_FIELD_BASE(93, 93, 2, 0x0030, 0x10, 17, 1), + PIN_FIELD_BASE(94, 94, 2, 0x0030, 0x10, 18, 1), + PIN_FIELD_BASE(95, 95, 2, 0x0030, 0x10, 26, 1), + PIN_FIELD_BASE(96, 96, 2, 0x0030, 0x10, 27, 1), + PIN_FIELD_BASE(97, 97, 2, 0x0030, 0x10, 2, 1), + PIN_FIELD_BASE(98, 98, 2, 0x0030, 0x10, 3, 1), + PIN_FIELD_BASE(99, 99, 2, 0x0030, 0x10, 0, 1), + PIN_FIELD_BASE(100, 100, 2, 0x0030, 0x10, 1, 1), + PIN_FIELD_BASE(101, 101, 2, 0x0030, 0x10, 4, 1), + PIN_FIELD_BASE(102, 102, 2, 0x0030, 0x10, 5, 1), + PIN_FIELD_BASE(103, 103, 2, 0x0030, 0x10, 21, 1), + PIN_FIELD_BASE(104, 104, 2, 0x0030, 0x10, 23, 1), + PIN_FIELD_BASE(105, 105, 2, 0x0030, 0x10, 22, 1), + PIN_FIELD_BASE(106, 106, 2, 0x0030, 0x10, 24, 1), + PIN_FIELD_BASE(107, 107, 1, 0x0030, 0x10, 4, 1), + PIN_FIELD_BASE(108, 108, 1, 0x0030, 0x10, 3, 1), + PIN_FIELD_BASE(109, 109, 1, 0x0030, 0x10, 5, 1), + PIN_FIELD_BASE(110, 110, 1, 0x0030, 0x10, 0, 1), + PIN_FIELD_BASE(111, 111, 1, 0x0030, 0x10, 1, 1), + PIN_FIELD_BASE(112, 112, 1, 0x0030, 0x10, 2, 1), + PIN_FIELD_BASE(113, 113, 1, 0x0030, 0x10, 9, 1), + PIN_FIELD_BASE(114, 114, 1, 0x0030, 0x10, 10, 1), + PIN_FIELD_BASE(115, 115, 1, 0x0030, 0x10, 6, 1), + PIN_FIELD_BASE(116, 116, 1, 0x0030, 0x10, 7, 1), + PIN_FIELD_BASE(117, 117, 1, 0x0030, 0x10, 12, 1), + PIN_FIELD_BASE(118, 118, 1, 0x0030, 0x10, 13, 1), + PIN_FIELD_BASE(119, 119, 1, 0x0030, 0x10, 14, 1), + PIN_FIELD_BASE(120, 120, 1, 0x0030, 0x10, 11, 1), + PIN_FIELD_BASE(121, 121, 1, 0x0030, 0x10, 8, 1), + PIN_FIELD_BASE(122, 122, 4, 0x0010, 0x10, 9, 1), + PIN_FIELD_BASE(123, 123, 4, 0x0010, 0x10, 10, 1), + PIN_FIELD_BASE(124, 124, 4, 0x0010, 0x10, 8, 1), + PIN_FIELD_BASE(125, 125, 4, 0x0010, 0x10, 12, 1), + PIN_FIELD_BASE(126, 126, 4, 0x0010, 0x10, 14, 1), + PIN_FIELD_BASE(127, 127, 4, 0x0010, 0x10, 16, 1), + PIN_FIELD_BASE(128, 128, 4, 0x0010, 0x10, 11, 1), + PIN_FIELD_BASE(129, 129, 4, 0x0010, 0x10, 15, 1), + PIN_FIELD_BASE(130, 130, 4, 0x0010, 0x10, 17, 1), + PIN_FIELD_BASE(131, 131, 4, 0x0010, 0x10, 18, 1), + PIN_FIELD_BASE(132, 132, 4, 0x0010, 0x10, 13, 1), + PIN_FIELD_BASE(133, 133, 4, 0x0010, 0x10, 19, 1), + PIN_FIELD_BASE(134, 134, 5, 0x0020, 0x10, 14, 1), + PIN_FIELD_BASE(135, 135, 5, 0x0020, 0x10, 17, 1), + PIN_FIELD_BASE(136, 136, 5, 0x0020, 0x10, 1, 1), + PIN_FIELD_BASE(137, 137, 5, 0x0020, 0x10, 7, 1), + PIN_FIELD_BASE(138, 138, 5, 0x0020, 0x10, 4, 1), + PIN_FIELD_BASE(139, 139, 5, 0x0020, 0x10, 5, 1), + PIN_FIELD_BASE(140, 140, 5, 0x0020, 0x10, 0, 1), + PIN_FIELD_BASE(141, 141, 5, 0x0020, 0x10, 6, 1), + PIN_FIELD_BASE(142, 142, 5, 0x0020, 0x10, 2, 1), + PIN_FIELD_BASE(143, 143, 5, 0x0020, 0x10, 3, 1), + PIN_FIELD_BASE(144, 144, 5, 0x0020, 0x10, 12, 1), + PIN_FIELD_BASE(145, 145, 5, 0x0020, 0x10, 11, 1), + PIN_FIELD_BASE(146, 146, 5, 0x0020, 0x10, 13, 1), + PIN_FIELD_BASE(147, 147, 5, 0x0020, 0x10, 10, 1), + PIN_FIELD_BASE(148, 148, 5, 0x0020, 0x10, 15, 1), + PIN_FIELD_BASE(149, 149, 5, 0x0020, 0x10, 16, 1), + PIN_FIELD_BASE(150, 150, 7, 0x0040, 0x10, 23, 1), + PIN_FIELD_BASE(151, 151, 7, 0x0040, 0x10, 24, 1), + PIN_FIELD_BASE(152, 152, 7, 0x0040, 0x10, 25, 1), + PIN_FIELD_BASE(153, 153, 7, 0x0040, 0x10, 26, 1), + PIN_FIELD_BASE(154, 154, 7, 0x0040, 0x10, 28, 1), + PIN_FIELD_BASE(155, 155, 3, 0x0030, 0x10, 28, 1), + PIN_FIELD_BASE(156, 156, 3, 0x0030, 0x10, 27, 1), + PIN_FIELD_BASE(157, 157, 3, 0x0030, 0x10, 29, 1), + PIN_FIELD_BASE(158, 158, 3, 0x0030, 0x10, 26, 1), + PIN_FIELD_BASE(159, 159, 7, 0x0040, 0x10, 27, 1), + PIN_FIELD_BASE(160, 160, 5, 0x0020, 0x10, 8, 1), + PIN_FIELD_BASE(161, 161, 1, 0x0030, 0x10, 15, 1), + PIN_FIELD_BASE(162, 162, 1, 0x0030, 0x10, 16, 1), + PIN_FIELD_BASE(163, 163, 4, 0x0010, 0x10, 0, 1), + PIN_FIELD_BASE(164, 164, 4, 0x0010, 0x10, 1, 1), + PIN_FIELD_BASE(165, 165, 4, 0x0010, 0x10, 2, 1), + PIN_FIELD_BASE(166, 166, 4, 0x0010, 0x10, 3, 1), + PIN_FIELD_BASE(167, 167, 4, 0x0010, 0x10, 4, 1), + PIN_FIELD_BASE(168, 168, 4, 0x0010, 0x10, 5, 1), + PIN_FIELD_BASE(169, 169, 4, 0x0010, 0x10, 6, 1), + PIN_FIELD_BASE(170, 170, 4, 0x0010, 0x10, 7, 1), + PIN_FIELD_BASE(171, 171, 7, 0x0040, 0x10, 17, 1), + PIN_FIELD_BASE(172, 172, 7, 0x0040, 0x10, 18, 1), + PIN_FIELD_BASE(173, 173, 7, 0x0040, 0x10, 11, 1), + PIN_FIELD_BASE(174, 174, 7, 0x0040, 0x10, 12, 1), + PIN_FIELD_BASE(175, 175, 7, 0x0040, 0x10, 13, 1), + PIN_FIELD_BASE(176, 176, 7, 0x0040, 0x10, 14, 1), + PIN_FIELD_BASE(177, 177, 7, 0x0040, 0x10, 15, 1), + PINS_FIELD_BASE(178, 179, 7, 0x0040, 0x10, 16, 1), +}; + +static const struct mtk_pin_reg_calc mt6765_reg_cals[PINCTRL_PIN_REG_MAX] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt6765_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt6765_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt6765_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt6765_pin_do_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt6765_pin_smt_range), + [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt6765_pin_pd_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt6765_pin_pu_range), + [PINCTRL_PIN_REG_TDSEL] = MTK_RANGE(mt6765_pin_tdsel_range), + [PINCTRL_PIN_REG_RDSEL] = MTK_RANGE(mt6765_pin_rdsel_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt6765_pin_drv_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt6765_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt6765_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt6765_pin_r1_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt6765_pin_ies_range), +}; + +static const char * const mt6765_pinctrl_register_base_names[] = { + "iocfg0", "iocfg1", "iocfg2", "iocfg3", "iocfg4", "iocfg5", + "iocfg6", "iocfg7", +}; + +static const struct mtk_eint_hw mt6765_eint_hw = { + .port_mask = 7, + .ports = 6, + .ap_num = 160, + .db_cnt = 13, +}; + +static const struct mtk_pin_soc mt6765_data = { + .reg_cal = mt6765_reg_cals, + .pins = mtk_pins_mt6765, + .npins = ARRAY_SIZE(mtk_pins_mt6765), + .ngrps = ARRAY_SIZE(mtk_pins_mt6765), + .eint_hw = &mt6765_eint_hw, + .gpio_m = 0, + .ies_present = true, + .base_names = mt6765_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt6765_pinctrl_register_base_names), + .bias_disable_set = mtk_pinconf_bias_disable_set, + .bias_disable_get = mtk_pinconf_bias_disable_get, + .bias_set = mtk_pinconf_bias_set, + .bias_get = mtk_pinconf_bias_get, + .drive_set = mtk_pinconf_drive_set_rev1, + .drive_get = mtk_pinconf_drive_get_rev1, + .adv_pull_get = mtk_pinconf_adv_pull_get, + .adv_pull_set = mtk_pinconf_adv_pull_set, +}; + +static const struct of_device_id mt6765_pinctrl_of_match[] = { + { .compatible = "mediatek,mt6765-pinctrl", }, + { } +}; + +static int mt6765_pinctrl_probe(struct platform_device *pdev) +{ + return mtk_paris_pinctrl_probe(pdev, &mt6765_data); +} + +static struct platform_driver mt6765_pinctrl_driver = { + .driver = { + .name = "mt6765-pinctrl", + .of_match_table = mt6765_pinctrl_of_match, + }, + .probe = mt6765_pinctrl_probe, +}; + +static int __init mt6765_pinctrl_init(void) +{ + return platform_driver_register(&mt6765_pinctrl_driver); +} +arch_initcall(mt6765_pinctrl_init); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c index 6f931b85701b..ce4a8a0cc19c 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c @@ -1,297 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * MediaTek MT7622 Pinctrl Driver + * Copyright (C) 2017-2018 MediaTek Inc. * - * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com> + * Author: Sean Wang <sean.wang@mediatek.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/gpio.h> -#include <linux/gpio/driver.h> -#include <linux/io.h> -#include <linux/init.h> -#include <linux/mfd/syscon.h> -#include <linux/of.h> -#include <linux/of_irq.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> -#include <linux/pinctrl/pinctrl.h> -#include <linux/pinctrl/pinmux.h> -#include <linux/pinctrl/pinconf.h> -#include <linux/pinctrl/pinconf-generic.h> -#include <linux/regmap.h> - -#include "../core.h" -#include "../pinconf.h" -#include "../pinmux.h" -#include "mtk-eint.h" - -#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME -#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), } -#define PINCTRL_PIN_GROUP(name, id) \ - { \ - name, \ - id##_pins, \ - ARRAY_SIZE(id##_pins), \ - id##_funcs, \ - } - -#define MTK_GPIO_MODE 1 -#define MTK_INPUT 0 -#define MTK_OUTPUT 1 -#define MTK_DISABLE 0 -#define MTK_ENABLE 1 - -/* Custom pinconf parameters */ -#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) -#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) - -/* List these attributes which could be modified for the pin */ -enum { - PINCTRL_PIN_REG_MODE, - PINCTRL_PIN_REG_DIR, - PINCTRL_PIN_REG_DI, - PINCTRL_PIN_REG_DO, - PINCTRL_PIN_REG_SR, - PINCTRL_PIN_REG_SMT, - PINCTRL_PIN_REG_PD, - PINCTRL_PIN_REG_PU, - PINCTRL_PIN_REG_E4, - PINCTRL_PIN_REG_E8, - PINCTRL_PIN_REG_TDSEL, - PINCTRL_PIN_REG_RDSEL, - PINCTRL_PIN_REG_MAX, -}; - -/* struct mtk_pin_field - the structure that holds the information of the field - * used to describe the attribute for the pin - * @offset: the register offset relative to the base address - * @mask: the mask used to filter out the field from the register - * @bitpos: the start bit relative to the register - * @next: the indication that the field would be extended to the - next register */ -struct mtk_pin_field { - u32 offset; - u32 mask; - u8 bitpos; - u8 next; -}; -/* struct mtk_pin_field_calc - the structure that holds the range providing - * the guide used to look up the relevant field - * @s_pin: the start pin within the range - * @e_pin: the end pin within the range - * @s_addr: the start address for the range - * @x_addrs: the address distance between two consecutive registers - * within the range - * @s_bit: the start bit for the first register within the range - * @x_bits: the bit distance between two consecutive pins within - * the range - */ -struct mtk_pin_field_calc { - u16 s_pin; - u16 e_pin; - u32 s_addr; - u8 x_addrs; - u8 s_bit; - u8 x_bits; -}; +#include "pinctrl-moore.h" -/* struct mtk_pin_reg_calc - the structure that holds all ranges used to - * determine which register the pin would make use of - * for certain pin attribute. - * @range: the start address for the range - * @nranges: the number of items in the range - */ -struct mtk_pin_reg_calc { - const struct mtk_pin_field_calc *range; - unsigned int nranges; -}; - -/* struct mtk_pin_soc - the structure that holds SoC-specific data */ -struct mtk_pin_soc { - const struct mtk_pin_reg_calc *reg_cal; - const struct pinctrl_pin_desc *pins; - unsigned int npins; - const struct group_desc *grps; - unsigned int ngrps; - const struct function_desc *funcs; - unsigned int nfuncs; - const struct mtk_eint_regs *eint_regs; - const struct mtk_eint_hw *eint_hw; -}; - -struct mtk_pinctrl { - struct pinctrl_dev *pctrl; - void __iomem *base; - struct device *dev; - struct gpio_chip chip; - const struct mtk_pin_soc *soc; - struct mtk_eint *eint; -}; +#define MT7622_PIN(_number, _name) \ + MTK_PIN(_number, _name, 1, _number, DRV_GRP0) static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = { - {0, 0, 0x320, 0x10, 16, 4}, - {1, 4, 0x3a0, 0x10, 16, 4}, - {5, 5, 0x320, 0x10, 0, 4}, - {6, 6, 0x300, 0x10, 4, 4}, - {7, 7, 0x300, 0x10, 4, 4}, - {8, 9, 0x350, 0x10, 20, 4}, - {10, 10, 0x300, 0x10, 8, 4}, - {11, 11, 0x300, 0x10, 8, 4}, - {12, 12, 0x300, 0x10, 8, 4}, - {13, 13, 0x300, 0x10, 8, 4}, - {14, 15, 0x320, 0x10, 4, 4}, - {16, 17, 0x320, 0x10, 20, 4}, - {18, 21, 0x310, 0x10, 16, 4}, - {22, 22, 0x380, 0x10, 16, 4}, - {23, 23, 0x300, 0x10, 24, 4}, - {24, 24, 0x300, 0x10, 24, 4}, - {25, 25, 0x300, 0x10, 12, 4}, - {25, 25, 0x300, 0x10, 12, 4}, - {26, 26, 0x300, 0x10, 12, 4}, - {27, 27, 0x300, 0x10, 12, 4}, - {28, 28, 0x300, 0x10, 12, 4}, - {29, 29, 0x300, 0x10, 12, 4}, - {30, 30, 0x300, 0x10, 12, 4}, - {31, 31, 0x300, 0x10, 12, 4}, - {32, 32, 0x300, 0x10, 12, 4}, - {33, 33, 0x300, 0x10, 12, 4}, - {34, 34, 0x300, 0x10, 12, 4}, - {35, 35, 0x300, 0x10, 12, 4}, - {36, 36, 0x300, 0x10, 12, 4}, - {37, 37, 0x300, 0x10, 20, 4}, - {38, 38, 0x300, 0x10, 20, 4}, - {39, 39, 0x300, 0x10, 20, 4}, - {40, 40, 0x300, 0x10, 20, 4}, - {41, 41, 0x300, 0x10, 20, 4}, - {42, 42, 0x300, 0x10, 20, 4}, - {43, 43, 0x300, 0x10, 20, 4}, - {44, 44, 0x300, 0x10, 20, 4}, - {45, 46, 0x300, 0x10, 20, 4}, - {47, 47, 0x300, 0x10, 20, 4}, - {48, 48, 0x300, 0x10, 20, 4}, - {49, 49, 0x300, 0x10, 20, 4}, - {50, 50, 0x300, 0x10, 20, 4}, - {51, 70, 0x330, 0x10, 4, 4}, - {71, 71, 0x300, 0x10, 16, 4}, - {72, 72, 0x300, 0x10, 16, 4}, - {73, 76, 0x310, 0x10, 0, 4}, - {77, 77, 0x320, 0x10, 28, 4}, - {78, 78, 0x320, 0x10, 12, 4}, - {79, 82, 0x3a0, 0x10, 0, 4}, - {83, 83, 0x350, 0x10, 28, 4}, - {84, 84, 0x330, 0x10, 0, 4}, - {85, 90, 0x360, 0x10, 4, 4}, - {91, 94, 0x390, 0x10, 16, 4}, - {95, 97, 0x380, 0x10, 20, 4}, - {98, 101, 0x390, 0x10, 0, 4}, - {102, 102, 0x360, 0x10, 0, 4}, + PIN_FIELD(0, 0, 0x320, 0x10, 16, 4), + PIN_FIELD(1, 4, 0x3a0, 0x10, 16, 4), + PIN_FIELD(5, 5, 0x320, 0x10, 0, 4), + PINS_FIELD(6, 7, 0x300, 0x10, 4, 4), + PIN_FIELD(8, 9, 0x350, 0x10, 20, 4), + PINS_FIELD(10, 13, 0x300, 0x10, 8, 4), + PIN_FIELD(14, 15, 0x320, 0x10, 4, 4), + PIN_FIELD(16, 17, 0x320, 0x10, 20, 4), + PIN_FIELD(18, 21, 0x310, 0x10, 16, 4), + PIN_FIELD(22, 22, 0x380, 0x10, 16, 4), + PINS_FIELD(23, 24, 0x300, 0x10, 24, 4), + PINS_FIELD(25, 36, 0x300, 0x10, 12, 4), + PINS_FIELD(37, 50, 0x300, 0x10, 20, 4), + PIN_FIELD(51, 70, 0x330, 0x10, 4, 4), + PINS_FIELD(71, 72, 0x300, 0x10, 16, 4), + PIN_FIELD(73, 76, 0x310, 0x10, 0, 4), + PIN_FIELD(77, 77, 0x320, 0x10, 28, 4), + PIN_FIELD(78, 78, 0x320, 0x10, 12, 4), + PIN_FIELD(79, 82, 0x3a0, 0x10, 0, 4), + PIN_FIELD(83, 83, 0x350, 0x10, 28, 4), + PIN_FIELD(84, 84, 0x330, 0x10, 0, 4), + PIN_FIELD(85, 90, 0x360, 0x10, 4, 4), + PIN_FIELD(91, 94, 0x390, 0x10, 16, 4), + PIN_FIELD(95, 97, 0x380, 0x10, 20, 4), + PIN_FIELD(98, 101, 0x390, 0x10, 0, 4), + PIN_FIELD(102, 102, 0x360, 0x10, 0, 4), }; static const struct mtk_pin_field_calc mt7622_pin_dir_range[] = { - {0, 102, 0x0, 0x10, 0, 1}, + PIN_FIELD(0, 102, 0x0, 0x10, 0, 1), }; static const struct mtk_pin_field_calc mt7622_pin_di_range[] = { - {0, 102, 0x200, 0x10, 0, 1}, + PIN_FIELD(0, 102, 0x200, 0x10, 0, 1), }; static const struct mtk_pin_field_calc mt7622_pin_do_range[] = { - {0, 102, 0x100, 0x10, 0, 1}, + PIN_FIELD(0, 102, 0x100, 0x10, 0, 1), }; static const struct mtk_pin_field_calc mt7622_pin_sr_range[] = { - {0, 31, 0x910, 0x10, 0, 1}, - {32, 50, 0xa10, 0x10, 0, 1}, - {51, 70, 0x810, 0x10, 0, 1}, - {71, 72, 0xb10, 0x10, 0, 1}, - {73, 86, 0xb10, 0x10, 4, 1}, - {87, 90, 0xc10, 0x10, 0, 1}, - {91, 102, 0xb10, 0x10, 18, 1}, + PIN_FIELD(0, 31, 0x910, 0x10, 0, 1), + PIN_FIELD(32, 50, 0xa10, 0x10, 0, 1), + PIN_FIELD(51, 70, 0x810, 0x10, 0, 1), + PIN_FIELD(71, 72, 0xb10, 0x10, 0, 1), + PIN_FIELD(73, 86, 0xb10, 0x10, 4, 1), + PIN_FIELD(87, 90, 0xc10, 0x10, 0, 1), + PIN_FIELD(91, 102, 0xb10, 0x10, 18, 1), }; static const struct mtk_pin_field_calc mt7622_pin_smt_range[] = { - {0, 31, 0x920, 0x10, 0, 1}, - {32, 50, 0xa20, 0x10, 0, 1}, - {51, 70, 0x820, 0x10, 0, 1}, - {71, 72, 0xb20, 0x10, 0, 1}, - {73, 86, 0xb20, 0x10, 4, 1}, - {87, 90, 0xc20, 0x10, 0, 1}, - {91, 102, 0xb20, 0x10, 18, 1}, + PIN_FIELD(0, 31, 0x920, 0x10, 0, 1), + PIN_FIELD(32, 50, 0xa20, 0x10, 0, 1), + PIN_FIELD(51, 70, 0x820, 0x10, 0, 1), + PIN_FIELD(71, 72, 0xb20, 0x10, 0, 1), + PIN_FIELD(73, 86, 0xb20, 0x10, 4, 1), + PIN_FIELD(87, 90, 0xc20, 0x10, 0, 1), + PIN_FIELD(91, 102, 0xb20, 0x10, 18, 1), }; static const struct mtk_pin_field_calc mt7622_pin_pu_range[] = { - {0, 31, 0x930, 0x10, 0, 1}, - {32, 50, 0xa30, 0x10, 0, 1}, - {51, 70, 0x830, 0x10, 0, 1}, - {71, 72, 0xb30, 0x10, 0, 1}, - {73, 86, 0xb30, 0x10, 4, 1}, - {87, 90, 0xc30, 0x10, 0, 1}, - {91, 102, 0xb30, 0x10, 18, 1}, + PIN_FIELD(0, 31, 0x930, 0x10, 0, 1), + PIN_FIELD(32, 50, 0xa30, 0x10, 0, 1), + PIN_FIELD(51, 70, 0x830, 0x10, 0, 1), + PIN_FIELD(71, 72, 0xb30, 0x10, 0, 1), + PIN_FIELD(73, 86, 0xb30, 0x10, 4, 1), + PIN_FIELD(87, 90, 0xc30, 0x10, 0, 1), + PIN_FIELD(91, 102, 0xb30, 0x10, 18, 1), }; static const struct mtk_pin_field_calc mt7622_pin_pd_range[] = { - {0, 31, 0x940, 0x10, 0, 1}, - {32, 50, 0xa40, 0x10, 0, 1}, - {51, 70, 0x840, 0x10, 0, 1}, - {71, 72, 0xb40, 0x10, 0, 1}, - {73, 86, 0xb40, 0x10, 4, 1}, - {87, 90, 0xc40, 0x10, 0, 1}, - {91, 102, 0xb40, 0x10, 18, 1}, + PIN_FIELD(0, 31, 0x940, 0x10, 0, 1), + PIN_FIELD(32, 50, 0xa40, 0x10, 0, 1), + PIN_FIELD(51, 70, 0x840, 0x10, 0, 1), + PIN_FIELD(71, 72, 0xb40, 0x10, 0, 1), + PIN_FIELD(73, 86, 0xb40, 0x10, 4, 1), + PIN_FIELD(87, 90, 0xc40, 0x10, 0, 1), + PIN_FIELD(91, 102, 0xb40, 0x10, 18, 1), }; static const struct mtk_pin_field_calc mt7622_pin_e4_range[] = { - {0, 31, 0x960, 0x10, 0, 1}, - {32, 50, 0xa60, 0x10, 0, 1}, - {51, 70, 0x860, 0x10, 0, 1}, - {71, 72, 0xb60, 0x10, 0, 1}, - {73, 86, 0xb60, 0x10, 4, 1}, - {87, 90, 0xc60, 0x10, 0, 1}, - {91, 102, 0xb60, 0x10, 18, 1}, + PIN_FIELD(0, 31, 0x960, 0x10, 0, 1), + PIN_FIELD(32, 50, 0xa60, 0x10, 0, 1), + PIN_FIELD(51, 70, 0x860, 0x10, 0, 1), + PIN_FIELD(71, 72, 0xb60, 0x10, 0, 1), + PIN_FIELD(73, 86, 0xb60, 0x10, 4, 1), + PIN_FIELD(87, 90, 0xc60, 0x10, 0, 1), + PIN_FIELD(91, 102, 0xb60, 0x10, 18, 1), }; static const struct mtk_pin_field_calc mt7622_pin_e8_range[] = { - {0, 31, 0x970, 0x10, 0, 1}, - {32, 50, 0xa70, 0x10, 0, 1}, - {51, 70, 0x870, 0x10, 0, 1}, - {71, 72, 0xb70, 0x10, 0, 1}, - {73, 86, 0xb70, 0x10, 4, 1}, - {87, 90, 0xc70, 0x10, 0, 1}, - {91, 102, 0xb70, 0x10, 18, 1}, + PIN_FIELD(0, 31, 0x970, 0x10, 0, 1), + PIN_FIELD(32, 50, 0xa70, 0x10, 0, 1), + PIN_FIELD(51, 70, 0x870, 0x10, 0, 1), + PIN_FIELD(71, 72, 0xb70, 0x10, 0, 1), + PIN_FIELD(73, 86, 0xb70, 0x10, 4, 1), + PIN_FIELD(87, 90, 0xc70, 0x10, 0, 1), + PIN_FIELD(91, 102, 0xb70, 0x10, 18, 1), }; static const struct mtk_pin_field_calc mt7622_pin_tdsel_range[] = { - {0, 31, 0x980, 0x4, 0, 4}, - {32, 50, 0xa80, 0x4, 0, 4}, - {51, 70, 0x880, 0x4, 0, 4}, - {71, 72, 0xb80, 0x4, 0, 4}, - {73, 86, 0xb80, 0x4, 16, 4}, - {87, 90, 0xc80, 0x4, 0, 4}, - {91, 102, 0xb88, 0x4, 8, 4}, + PIN_FIELD(0, 31, 0x980, 0x4, 0, 4), + PIN_FIELD(32, 50, 0xa80, 0x4, 0, 4), + PIN_FIELD(51, 70, 0x880, 0x4, 0, 4), + PIN_FIELD(71, 72, 0xb80, 0x4, 0, 4), + PIN_FIELD(73, 86, 0xb80, 0x4, 16, 4), + PIN_FIELD(87, 90, 0xc80, 0x4, 0, 4), + PIN_FIELD(91, 102, 0xb88, 0x4, 8, 4), }; static const struct mtk_pin_field_calc mt7622_pin_rdsel_range[] = { - {0, 31, 0x990, 0x4, 0, 6}, - {32, 50, 0xa90, 0x4, 0, 6}, - {51, 58, 0x890, 0x4, 0, 6}, - {59, 60, 0x894, 0x4, 28, 6}, - {61, 62, 0x894, 0x4, 16, 6}, - {63, 66, 0x898, 0x4, 8, 6}, - {67, 68, 0x89c, 0x4, 12, 6}, - {69, 70, 0x89c, 0x4, 0, 6}, - {71, 72, 0xb90, 0x4, 0, 6}, - {73, 86, 0xb90, 0x4, 24, 6}, - {87, 90, 0xc90, 0x4, 0, 6}, - {91, 102, 0xb9c, 0x4, 12, 6}, + PIN_FIELD(0, 31, 0x990, 0x4, 0, 6), + PIN_FIELD(32, 50, 0xa90, 0x4, 0, 6), + PIN_FIELD(51, 58, 0x890, 0x4, 0, 6), + PIN_FIELD(59, 60, 0x894, 0x4, 28, 6), + PIN_FIELD(61, 62, 0x894, 0x4, 16, 6), + PIN_FIELD(63, 66, 0x898, 0x4, 8, 6), + PIN_FIELD(67, 68, 0x89c, 0x4, 12, 6), + PIN_FIELD(69, 70, 0x89c, 0x4, 0, 6), + PIN_FIELD(71, 72, 0xb90, 0x4, 0, 6), + PIN_FIELD(73, 86, 0xb90, 0x4, 24, 6), + PIN_FIELD(87, 90, 0xc90, 0x4, 0, 6), + PIN_FIELD(91, 102, 0xb9c, 0x4, 12, 6), }; static const struct mtk_pin_reg_calc mt7622_reg_cals[PINCTRL_PIN_REG_MAX] = { @@ -309,110 +152,110 @@ static const struct mtk_pin_reg_calc mt7622_reg_cals[PINCTRL_PIN_REG_MAX] = { [PINCTRL_PIN_REG_RDSEL] = MTK_RANGE(mt7622_pin_rdsel_range), }; -static const struct pinctrl_pin_desc mt7622_pins[] = { - PINCTRL_PIN(0, "GPIO_A"), - PINCTRL_PIN(1, "I2S1_IN"), - PINCTRL_PIN(2, "I2S1_OUT"), - PINCTRL_PIN(3, "I2S_BCLK"), - PINCTRL_PIN(4, "I2S_WS"), - PINCTRL_PIN(5, "I2S_MCLK"), - PINCTRL_PIN(6, "TXD0"), - PINCTRL_PIN(7, "RXD0"), - PINCTRL_PIN(8, "SPI_WP"), - PINCTRL_PIN(9, "SPI_HOLD"), - PINCTRL_PIN(10, "SPI_CLK"), - PINCTRL_PIN(11, "SPI_MOSI"), - PINCTRL_PIN(12, "SPI_MISO"), - PINCTRL_PIN(13, "SPI_CS"), - PINCTRL_PIN(14, "I2C_SDA"), - PINCTRL_PIN(15, "I2C_SCL"), - PINCTRL_PIN(16, "I2S2_IN"), - PINCTRL_PIN(17, "I2S3_IN"), - PINCTRL_PIN(18, "I2S4_IN"), - PINCTRL_PIN(19, "I2S2_OUT"), - PINCTRL_PIN(20, "I2S3_OUT"), - PINCTRL_PIN(21, "I2S4_OUT"), - PINCTRL_PIN(22, "GPIO_B"), - PINCTRL_PIN(23, "MDC"), - PINCTRL_PIN(24, "MDIO"), - PINCTRL_PIN(25, "G2_TXD0"), - PINCTRL_PIN(26, "G2_TXD1"), - PINCTRL_PIN(27, "G2_TXD2"), - PINCTRL_PIN(28, "G2_TXD3"), - PINCTRL_PIN(29, "G2_TXEN"), - PINCTRL_PIN(30, "G2_TXC"), - PINCTRL_PIN(31, "G2_RXD0"), - PINCTRL_PIN(32, "G2_RXD1"), - PINCTRL_PIN(33, "G2_RXD2"), - PINCTRL_PIN(34, "G2_RXD3"), - PINCTRL_PIN(35, "G2_RXDV"), - PINCTRL_PIN(36, "G2_RXC"), - PINCTRL_PIN(37, "NCEB"), - PINCTRL_PIN(38, "NWEB"), - PINCTRL_PIN(39, "NREB"), - PINCTRL_PIN(40, "NDL4"), - PINCTRL_PIN(41, "NDL5"), - PINCTRL_PIN(42, "NDL6"), - PINCTRL_PIN(43, "NDL7"), - PINCTRL_PIN(44, "NRB"), - PINCTRL_PIN(45, "NCLE"), - PINCTRL_PIN(46, "NALE"), - PINCTRL_PIN(47, "NDL0"), - PINCTRL_PIN(48, "NDL1"), - PINCTRL_PIN(49, "NDL2"), - PINCTRL_PIN(50, "NDL3"), - PINCTRL_PIN(51, "MDI_TP_P0"), - PINCTRL_PIN(52, "MDI_TN_P0"), - PINCTRL_PIN(53, "MDI_RP_P0"), - PINCTRL_PIN(54, "MDI_RN_P0"), - PINCTRL_PIN(55, "MDI_TP_P1"), - PINCTRL_PIN(56, "MDI_TN_P1"), - PINCTRL_PIN(57, "MDI_RP_P1"), - PINCTRL_PIN(58, "MDI_RN_P1"), - PINCTRL_PIN(59, "MDI_RP_P2"), - PINCTRL_PIN(60, "MDI_RN_P2"), - PINCTRL_PIN(61, "MDI_TP_P2"), - PINCTRL_PIN(62, "MDI_TN_P2"), - PINCTRL_PIN(63, "MDI_TP_P3"), - PINCTRL_PIN(64, "MDI_TN_P3"), - PINCTRL_PIN(65, "MDI_RP_P3"), - PINCTRL_PIN(66, "MDI_RN_P3"), - PINCTRL_PIN(67, "MDI_RP_P4"), - PINCTRL_PIN(68, "MDI_RN_P4"), - PINCTRL_PIN(69, "MDI_TP_P4"), - PINCTRL_PIN(70, "MDI_TN_P4"), - PINCTRL_PIN(71, "PMIC_SCL"), - PINCTRL_PIN(72, "PMIC_SDA"), - PINCTRL_PIN(73, "SPIC1_CLK"), - PINCTRL_PIN(74, "SPIC1_MOSI"), - PINCTRL_PIN(75, "SPIC1_MISO"), - PINCTRL_PIN(76, "SPIC1_CS"), - PINCTRL_PIN(77, "GPIO_D"), - PINCTRL_PIN(78, "WATCHDOG"), - PINCTRL_PIN(79, "RTS3_N"), - PINCTRL_PIN(80, "CTS3_N"), - PINCTRL_PIN(81, "TXD3"), - PINCTRL_PIN(82, "RXD3"), - PINCTRL_PIN(83, "PERST0_N"), - PINCTRL_PIN(84, "PERST1_N"), - PINCTRL_PIN(85, "WLED_N"), - PINCTRL_PIN(86, "EPHY_LED0_N"), - PINCTRL_PIN(87, "AUXIN0"), - PINCTRL_PIN(88, "AUXIN1"), - PINCTRL_PIN(89, "AUXIN2"), - PINCTRL_PIN(90, "AUXIN3"), - PINCTRL_PIN(91, "TXD4"), - PINCTRL_PIN(92, "RXD4"), - PINCTRL_PIN(93, "RTS4_N"), - PINCTRL_PIN(94, "CTS4_N"), - PINCTRL_PIN(95, "PWM1"), - PINCTRL_PIN(96, "PWM2"), - PINCTRL_PIN(97, "PWM3"), - PINCTRL_PIN(98, "PWM4"), - PINCTRL_PIN(99, "PWM5"), - PINCTRL_PIN(100, "PWM6"), - PINCTRL_PIN(101, "PWM7"), - PINCTRL_PIN(102, "GPIO_E"), +static const struct mtk_pin_desc mt7622_pins[] = { + MT7622_PIN(0, "GPIO_A"), + MT7622_PIN(1, "I2S1_IN"), + MT7622_PIN(2, "I2S1_OUT"), + MT7622_PIN(3, "I2S_BCLK"), + MT7622_PIN(4, "I2S_WS"), + MT7622_PIN(5, "I2S_MCLK"), + MT7622_PIN(6, "TXD0"), + MT7622_PIN(7, "RXD0"), + MT7622_PIN(8, "SPI_WP"), + MT7622_PIN(9, "SPI_HOLD"), + MT7622_PIN(10, "SPI_CLK"), + MT7622_PIN(11, "SPI_MOSI"), + MT7622_PIN(12, "SPI_MISO"), + MT7622_PIN(13, "SPI_CS"), + MT7622_PIN(14, "I2C_SDA"), + MT7622_PIN(15, "I2C_SCL"), + MT7622_PIN(16, "I2S2_IN"), + MT7622_PIN(17, "I2S3_IN"), + MT7622_PIN(18, "I2S4_IN"), + MT7622_PIN(19, "I2S2_OUT"), + MT7622_PIN(20, "I2S3_OUT"), + MT7622_PIN(21, "I2S4_OUT"), + MT7622_PIN(22, "GPIO_B"), + MT7622_PIN(23, "MDC"), + MT7622_PIN(24, "MDIO"), + MT7622_PIN(25, "G2_TXD0"), + MT7622_PIN(26, "G2_TXD1"), + MT7622_PIN(27, "G2_TXD2"), + MT7622_PIN(28, "G2_TXD3"), + MT7622_PIN(29, "G2_TXEN"), + MT7622_PIN(30, "G2_TXC"), + MT7622_PIN(31, "G2_RXD0"), + MT7622_PIN(32, "G2_RXD1"), + MT7622_PIN(33, "G2_RXD2"), + MT7622_PIN(34, "G2_RXD3"), + MT7622_PIN(35, "G2_RXDV"), + MT7622_PIN(36, "G2_RXC"), + MT7622_PIN(37, "NCEB"), + MT7622_PIN(38, "NWEB"), + MT7622_PIN(39, "NREB"), + MT7622_PIN(40, "NDL4"), + MT7622_PIN(41, "NDL5"), + MT7622_PIN(42, "NDL6"), + MT7622_PIN(43, "NDL7"), + MT7622_PIN(44, "NRB"), + MT7622_PIN(45, "NCLE"), + MT7622_PIN(46, "NALE"), + MT7622_PIN(47, "NDL0"), + MT7622_PIN(48, "NDL1"), + MT7622_PIN(49, "NDL2"), + MT7622_PIN(50, "NDL3"), + MT7622_PIN(51, "MDI_TP_P0"), + MT7622_PIN(52, "MDI_TN_P0"), + MT7622_PIN(53, "MDI_RP_P0"), + MT7622_PIN(54, "MDI_RN_P0"), + MT7622_PIN(55, "MDI_TP_P1"), + MT7622_PIN(56, "MDI_TN_P1"), + MT7622_PIN(57, "MDI_RP_P1"), + MT7622_PIN(58, "MDI_RN_P1"), + MT7622_PIN(59, "MDI_RP_P2"), + MT7622_PIN(60, "MDI_RN_P2"), + MT7622_PIN(61, "MDI_TP_P2"), + MT7622_PIN(62, "MDI_TN_P2"), + MT7622_PIN(63, "MDI_TP_P3"), + MT7622_PIN(64, "MDI_TN_P3"), + MT7622_PIN(65, "MDI_RP_P3"), + MT7622_PIN(66, "MDI_RN_P3"), + MT7622_PIN(67, "MDI_RP_P4"), + MT7622_PIN(68, "MDI_RN_P4"), + MT7622_PIN(69, "MDI_TP_P4"), + MT7622_PIN(70, "MDI_TN_P4"), + MT7622_PIN(71, "PMIC_SCL"), + MT7622_PIN(72, "PMIC_SDA"), + MT7622_PIN(73, "SPIC1_CLK"), + MT7622_PIN(74, "SPIC1_MOSI"), + MT7622_PIN(75, "SPIC1_MISO"), + MT7622_PIN(76, "SPIC1_CS"), + MT7622_PIN(77, "GPIO_D"), + MT7622_PIN(78, "WATCHDOG"), + MT7622_PIN(79, "RTS3_N"), + MT7622_PIN(80, "CTS3_N"), + MT7622_PIN(81, "TXD3"), + MT7622_PIN(82, "RXD3"), + MT7622_PIN(83, "PERST0_N"), + MT7622_PIN(84, "PERST1_N"), + MT7622_PIN(85, "WLED_N"), + MT7622_PIN(86, "EPHY_LED0_N"), + MT7622_PIN(87, "AUXIN0"), + MT7622_PIN(88, "AUXIN1"), + MT7622_PIN(89, "AUXIN2"), + MT7622_PIN(90, "AUXIN3"), + MT7622_PIN(91, "TXD4"), + MT7622_PIN(92, "RXD4"), + MT7622_PIN(93, "RTS4_N"), + MT7622_PIN(94, "CTS4_N"), + MT7622_PIN(95, "PWM1"), + MT7622_PIN(96, "PWM2"), + MT7622_PIN(97, "PWM3"), + MT7622_PIN(98, "PWM4"), + MT7622_PIN(99, "PWM5"), + MT7622_PIN(100, "PWM6"), + MT7622_PIN(101, "PWM7"), + MT7622_PIN(102, "GPIO_E"), }; /* List all groups consisting of these pins dedicated to the enablement of @@ -906,18 +749,6 @@ static const struct function_desc mt7622_functions[] = { {"watchdog", mt7622_wdt_groups, ARRAY_SIZE(mt7622_wdt_groups)}, }; -static const struct pinconf_generic_params mtk_custom_bindings[] = { - {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, - {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, -}; - -#ifdef CONFIG_DEBUG_FS -static const struct pin_config_item mtk_conf_items[] = { - PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), - PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), -}; -#endif - static const struct mtk_eint_hw mt7622_eint_hw = { .port_mask = 7, .ports = 7, @@ -934,830 +765,38 @@ static const struct mtk_pin_soc mt7622_data = { .funcs = mt7622_functions, .nfuncs = ARRAY_SIZE(mt7622_functions), .eint_hw = &mt7622_eint_hw, -}; - -static void mtk_w32(struct mtk_pinctrl *pctl, u32 reg, u32 val) -{ - writel_relaxed(val, pctl->base + reg); -} - -static u32 mtk_r32(struct mtk_pinctrl *pctl, u32 reg) -{ - return readl_relaxed(pctl->base + reg); -} - -static void mtk_rmw(struct mtk_pinctrl *pctl, u32 reg, u32 mask, u32 set) -{ - u32 val; - - val = mtk_r32(pctl, reg); - val &= ~mask; - val |= set; - mtk_w32(pctl, reg, val); -} - -static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw, int pin, - const struct mtk_pin_reg_calc *rc, - struct mtk_pin_field *pfd) -{ - const struct mtk_pin_field_calc *c, *e; - u32 bits; - - c = rc->range; - e = c + rc->nranges; - - while (c < e) { - if (pin >= c->s_pin && pin <= c->e_pin) - break; - c++; - } - - if (c >= e) { - dev_err(hw->dev, "Out of range for pin = %d\n", pin); - return -EINVAL; - } - - /* Caculated bits as the overall offset the pin is located at */ - bits = c->s_bit + (pin - c->s_pin) * (c->x_bits); - - /* Fill pfd from bits and 32-bit register applied is assumed */ - pfd->offset = c->s_addr + c->x_addrs * (bits / 32); - pfd->bitpos = bits % 32; - pfd->mask = (1 << c->x_bits) - 1; - - /* pfd->next is used for indicating that bit wrapping-around happens - * which requires the manipulation for bit 0 starting in the next - * register to form the complete field read/write. - */ - pfd->next = pfd->bitpos + c->x_bits - 1 > 31 ? c->x_addrs : 0; - - return 0; -} - -static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw, int pin, - int field, struct mtk_pin_field *pfd) -{ - const struct mtk_pin_reg_calc *rc; - - if (field < 0 || field >= PINCTRL_PIN_REG_MAX) { - dev_err(hw->dev, "Invalid Field %d\n", field); - return -EINVAL; - } - - if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) { - rc = &hw->soc->reg_cal[field]; - } else { - dev_err(hw->dev, "Undefined range for field %d\n", field); - return -EINVAL; - } - - return mtk_hw_pin_field_lookup(hw, pin, rc, pfd); -} - -static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l) -{ - *l = 32 - pf->bitpos; - *h = get_count_order(pf->mask) - *l; -} - -static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw, - struct mtk_pin_field *pf, int value) -{ - int nbits_l, nbits_h; - - mtk_hw_bits_part(pf, &nbits_h, &nbits_l); - - mtk_rmw(hw, pf->offset, pf->mask << pf->bitpos, - (value & pf->mask) << pf->bitpos); - - mtk_rmw(hw, pf->offset + pf->next, BIT(nbits_h) - 1, - (value & pf->mask) >> nbits_l); -} - -static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw, - struct mtk_pin_field *pf, int *value) -{ - int nbits_l, nbits_h, h, l; - - mtk_hw_bits_part(pf, &nbits_h, &nbits_l); - - l = (mtk_r32(hw, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1); - h = (mtk_r32(hw, pf->offset + pf->next)) & (BIT(nbits_h) - 1); - - *value = (h << nbits_l) | l; -} - -static int mtk_hw_set_value(struct mtk_pinctrl *hw, int pin, int field, - int value) -{ - struct mtk_pin_field pf; - int err; - - err = mtk_hw_pin_field_get(hw, pin, field, &pf); - if (err) - return err; - - if (!pf.next) - mtk_rmw(hw, pf.offset, pf.mask << pf.bitpos, - (value & pf.mask) << pf.bitpos); - else - mtk_hw_write_cross_field(hw, &pf, value); - - return 0; -} - -static int mtk_hw_get_value(struct mtk_pinctrl *hw, int pin, int field, - int *value) -{ - struct mtk_pin_field pf; - int err; - - err = mtk_hw_pin_field_get(hw, pin, field, &pf); - if (err) - return err; - - if (!pf.next) - *value = (mtk_r32(hw, pf.offset) >> pf.bitpos) & pf.mask; - else - mtk_hw_read_cross_field(hw, &pf, value); - - return 0; -} - -static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, - unsigned int selector, unsigned int group) -{ - struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - struct function_desc *func; - struct group_desc *grp; - int i; - - func = pinmux_generic_get_function(pctldev, selector); - if (!func) - return -EINVAL; - - grp = pinctrl_generic_get_group(pctldev, group); - if (!grp) - return -EINVAL; - - dev_dbg(pctldev->dev, "enable function %s group %s\n", - func->name, grp->name); - - for (i = 0; i < grp->num_pins; i++) { - int *pin_modes = grp->data; - - mtk_hw_set_value(hw, grp->pins[i], PINCTRL_PIN_REG_MODE, - pin_modes[i]); - } - - return 0; -} - -static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned int pin) -{ - struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - - return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_MODE, MTK_GPIO_MODE); -} - -static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned int pin, bool input) -{ - struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - - /* hardware would take 0 as input direction */ - return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, !input); -} - -static int mtk_pinconf_get(struct pinctrl_dev *pctldev, - unsigned int pin, unsigned long *config) -{ - struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - u32 param = pinconf_to_config_param(*config); - int val, val2, err, reg, ret = 1; - - switch (param) { - case PIN_CONFIG_BIAS_DISABLE: - err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PU, &val); - if (err) - return err; - - err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PD, &val2); - if (err) - return err; - - if (val || val2) - return -EINVAL; - - break; - case PIN_CONFIG_BIAS_PULL_UP: - case PIN_CONFIG_BIAS_PULL_DOWN: - case PIN_CONFIG_SLEW_RATE: - reg = (param == PIN_CONFIG_BIAS_PULL_UP) ? - PINCTRL_PIN_REG_PU : - (param == PIN_CONFIG_BIAS_PULL_DOWN) ? - PINCTRL_PIN_REG_PD : PINCTRL_PIN_REG_SR; - - err = mtk_hw_get_value(hw, pin, reg, &val); - if (err) - return err; - - if (!val) - return -EINVAL; - - break; - case PIN_CONFIG_INPUT_ENABLE: - case PIN_CONFIG_OUTPUT_ENABLE: - err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val); - if (err) - return err; - - /* HW takes input mode as zero; output mode as non-zero */ - if ((val && param == PIN_CONFIG_INPUT_ENABLE) || - (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) - return -EINVAL; - - break; - case PIN_CONFIG_INPUT_SCHMITT_ENABLE: - err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val); - if (err) - return err; - - err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_SMT, &val2); - if (err) - return err; - - if (val || !val2) - return -EINVAL; - - break; - case PIN_CONFIG_DRIVE_STRENGTH: - err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E4, &val); - if (err) - return err; - - err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E8, &val2); - if (err) - return err; - - /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1) - * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1) - */ - ret = ((val2 << 1) + val + 1) * 4; - - break; - case MTK_PIN_CONFIG_TDSEL: - case MTK_PIN_CONFIG_RDSEL: - reg = (param == MTK_PIN_CONFIG_TDSEL) ? - PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; - - err = mtk_hw_get_value(hw, pin, reg, &val); - if (err) - return err; - - ret = val; - - break; - default: - return -ENOTSUPP; - } - - *config = pinconf_to_config_packed(param, ret); - - return 0; -} - -static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - unsigned long *configs, unsigned int num_configs) -{ - struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - u32 reg, param, arg; - int cfg, err = 0; - - for (cfg = 0; cfg < num_configs; cfg++) { - param = pinconf_to_config_param(configs[cfg]); - arg = pinconf_to_config_argument(configs[cfg]); - - switch (param) { - case PIN_CONFIG_BIAS_DISABLE: - case PIN_CONFIG_BIAS_PULL_UP: - case PIN_CONFIG_BIAS_PULL_DOWN: - arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 : - (param == PIN_CONFIG_BIAS_PULL_UP) ? 1 : 2; - - err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PU, - arg & 1); - if (err) - goto err; - - err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PD, - !!(arg & 2)); - if (err) - goto err; - break; - case PIN_CONFIG_OUTPUT_ENABLE: - err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT, - MTK_DISABLE); - if (err) - goto err; - /* else: fall through */ - case PIN_CONFIG_INPUT_ENABLE: - case PIN_CONFIG_SLEW_RATE: - reg = (param == PIN_CONFIG_SLEW_RATE) ? - PINCTRL_PIN_REG_SR : PINCTRL_PIN_REG_DIR; - - arg = (param == PIN_CONFIG_INPUT_ENABLE) ? 0 : - (param == PIN_CONFIG_OUTPUT_ENABLE) ? 1 : arg; - err = mtk_hw_set_value(hw, pin, reg, arg); - if (err) - goto err; - - break; - case PIN_CONFIG_OUTPUT: - err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, - MTK_OUTPUT); - if (err) - goto err; - - err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DO, - arg); - if (err) - goto err; - break; - case PIN_CONFIG_INPUT_SCHMITT_ENABLE: - /* arg = 1: Input mode & SMT enable ; - * arg = 0: Output mode & SMT disable - */ - arg = arg ? 2 : 1; - err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, - arg & 1); - if (err) - goto err; - - err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT, - !!(arg & 2)); - if (err) - goto err; - break; - case PIN_CONFIG_DRIVE_STRENGTH: - /* 4mA when (e8, e4) = (0, 0); - * 8mA when (e8, e4) = (0, 1); - * 12mA when (e8, e4) = (1, 0); - * 16mA when (e8, e4) = (1, 1) - */ - if (!(arg % 4) && (arg >= 4 && arg <= 16)) { - arg = arg / 4 - 1; - err = mtk_hw_set_value(hw, pin, - PINCTRL_PIN_REG_E4, - arg & 0x1); - if (err) - goto err; - - err = mtk_hw_set_value(hw, pin, - PINCTRL_PIN_REG_E8, - (arg & 0x2) >> 1); - if (err) - goto err; - } else { - err = -ENOTSUPP; - } - break; - case MTK_PIN_CONFIG_TDSEL: - case MTK_PIN_CONFIG_RDSEL: - reg = (param == MTK_PIN_CONFIG_TDSEL) ? - PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; - - err = mtk_hw_set_value(hw, pin, reg, arg); - if (err) - goto err; - break; - default: - err = -ENOTSUPP; - } - } -err: - return err; -} - -static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev, - unsigned int group, unsigned long *config) -{ - const unsigned int *pins; - unsigned int i, npins, old = 0; - int ret; - - ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); - if (ret) - return ret; - - for (i = 0; i < npins; i++) { - if (mtk_pinconf_get(pctldev, pins[i], config)) - return -ENOTSUPP; - - /* configs do not match between two pins */ - if (i && old != *config) - return -ENOTSUPP; - - old = *config; - } - - return 0; -} - -static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev, - unsigned int group, unsigned long *configs, - unsigned int num_configs) -{ - const unsigned int *pins; - unsigned int i, npins; - int ret; - - ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); - if (ret) - return ret; - - for (i = 0; i < npins; i++) { - ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs); - if (ret) - return ret; - } - - return 0; -} - -static const struct pinctrl_ops mtk_pctlops = { - .get_groups_count = pinctrl_generic_get_group_count, - .get_group_name = pinctrl_generic_get_group_name, - .get_group_pins = pinctrl_generic_get_group_pins, - .dt_node_to_map = pinconf_generic_dt_node_to_map_all, - .dt_free_map = pinconf_generic_dt_free_map, -}; - -static const struct pinmux_ops mtk_pmxops = { - .get_functions_count = pinmux_generic_get_function_count, - .get_function_name = pinmux_generic_get_function_name, - .get_function_groups = pinmux_generic_get_function_groups, - .set_mux = mtk_pinmux_set_mux, - .gpio_request_enable = mtk_pinmux_gpio_request_enable, - .gpio_set_direction = mtk_pinmux_gpio_set_direction, - .strict = true, -}; - -static const struct pinconf_ops mtk_confops = { - .is_generic = true, - .pin_config_get = mtk_pinconf_get, - .pin_config_set = mtk_pinconf_set, - .pin_config_group_get = mtk_pinconf_group_get, - .pin_config_group_set = mtk_pinconf_group_set, - .pin_config_config_dbg_show = pinconf_generic_dump_config, -}; - -static struct pinctrl_desc mtk_desc = { - .name = PINCTRL_PINCTRL_DEV, - .pctlops = &mtk_pctlops, - .pmxops = &mtk_pmxops, - .confops = &mtk_confops, - .owner = THIS_MODULE, -}; - -static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) -{ - struct mtk_pinctrl *hw = gpiochip_get_data(chip); - int value, err; - - err = mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value); - if (err) - return err; - - return !!value; -} - -static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) -{ - struct mtk_pinctrl *hw = gpiochip_get_data(chip); - - mtk_hw_set_value(hw, gpio, PINCTRL_PIN_REG_DO, !!value); -} - -static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) -{ - return pinctrl_gpio_direction_input(chip->base + gpio); -} - -static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, - int value) -{ - mtk_gpio_set(chip, gpio, value); - - return pinctrl_gpio_direction_output(chip->base + gpio); -} - -static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct mtk_pinctrl *hw = gpiochip_get_data(chip); - unsigned long eint_n; - - if (!hw->eint) - return -ENOTSUPP; - - eint_n = offset; - - return mtk_eint_find_irq(hw->eint, eint_n); -} - -static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, - unsigned long config) -{ - struct mtk_pinctrl *hw = gpiochip_get_data(chip); - unsigned long eint_n; - u32 debounce; - - if (!hw->eint || - pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) - return -ENOTSUPP; - - debounce = pinconf_to_config_argument(config); - eint_n = offset; - - return mtk_eint_set_debounce(hw->eint, eint_n, debounce); -} - -static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np) -{ - struct gpio_chip *chip = &hw->chip; - int ret; - - chip->label = PINCTRL_PINCTRL_DEV; - chip->parent = hw->dev; - chip->request = gpiochip_generic_request; - chip->free = gpiochip_generic_free; - chip->direction_input = mtk_gpio_direction_input; - chip->direction_output = mtk_gpio_direction_output; - chip->get = mtk_gpio_get; - chip->set = mtk_gpio_set; - chip->to_irq = mtk_gpio_to_irq, - chip->set_config = mtk_gpio_set_config, - chip->base = -1; - chip->ngpio = hw->soc->npins; - chip->of_node = np; - chip->of_gpio_n_cells = 2; - - ret = gpiochip_add_data(chip, hw); - if (ret < 0) - return ret; - - /* Just for backward compatible for these old pinctrl nodes without - * "gpio-ranges" property. Otherwise, called directly from a - * DeviceTree-supported pinctrl driver is DEPRECATED. - * Please see Section 2.1 of - * Documentation/devicetree/bindings/gpio/gpio.txt on how to - * bind pinctrl and gpio drivers via the "gpio-ranges" property. - */ - if (!of_find_property(np, "gpio-ranges", NULL)) { - ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0, - chip->ngpio); - if (ret < 0) { - gpiochip_remove(chip); - return ret; - } - } - - return 0; -} - -static int mtk_build_groups(struct mtk_pinctrl *hw) -{ - int err, i; - - for (i = 0; i < hw->soc->ngrps; i++) { - const struct group_desc *group = hw->soc->grps + i; - - err = pinctrl_generic_add_group(hw->pctrl, group->name, - group->pins, group->num_pins, - group->data); - if (err < 0) { - dev_err(hw->dev, "Failed to register group %s\n", - group->name); - return err; - } - } - - return 0; -} - -static int mtk_build_functions(struct mtk_pinctrl *hw) -{ - int i, err; - - for (i = 0; i < hw->soc->nfuncs ; i++) { - const struct function_desc *func = hw->soc->funcs + i; - - err = pinmux_generic_add_function(hw->pctrl, func->name, - func->group_names, - func->num_group_names, - func->data); - if (err < 0) { - dev_err(hw->dev, "Failed to register function %s\n", - func->name); - return err; - } - } - - return 0; -} - -static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n, - unsigned int *gpio_n, - struct gpio_chip **gpio_chip) -{ - struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; - - *gpio_chip = &hw->chip; - *gpio_n = eint_n; - - return 0; -} - -static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n) -{ - struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; - struct gpio_chip *gpio_chip; - unsigned int gpio_n; - int err; - - err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); - if (err) - return err; - - return mtk_gpio_get(gpio_chip, gpio_n); -} - -static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n) -{ - struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; - struct gpio_chip *gpio_chip; - unsigned int gpio_n; - int err; - - err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); - if (err) - return err; - - err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE, - MTK_GPIO_MODE); - if (err) - return err; - - err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT); - if (err) - return err; - - err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE); - if (err) - return err; - - return 0; -} - -static const struct mtk_eint_xt mtk_eint_xt = { - .get_gpio_n = mtk_xt_get_gpio_n, - .get_gpio_state = mtk_xt_get_gpio_state, - .set_gpio_as_eint = mtk_xt_set_gpio_as_eint, -}; - -static int -mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct resource *res; - - if (!IS_ENABLED(CONFIG_EINT_MTK)) - return 0; - - if (!of_property_read_bool(np, "interrupt-controller")) - return -ENODEV; - - hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL); - if (!hw->eint) - return -ENOMEM; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint"); - if (!res) { - dev_err(&pdev->dev, "Unable to get eint resource\n"); - return -ENODEV; - } - - hw->eint->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hw->eint->base)) - return PTR_ERR(hw->eint->base); - - hw->eint->irq = irq_of_parse_and_map(np, 0); - if (!hw->eint->irq) - return -EINVAL; - - hw->eint->dev = &pdev->dev; - hw->eint->hw = hw->soc->eint_hw; - hw->eint->pctl = hw; - hw->eint->gpio_xlate = &mtk_eint_xt; - - return mtk_eint_do_init(hw->eint); -} - -static const struct of_device_id mtk_pinctrl_of_match[] = { - { .compatible = "mediatek,mt7622-pinctrl", .data = &mt7622_data}, + .gpio_m = 1, + .ies_present = false, + .base_names = mtk_default_register_base_names, + .nbase_names = ARRAY_SIZE(mtk_default_register_base_names), + .bias_disable_set = mtk_pinconf_bias_disable_set, + .bias_disable_get = mtk_pinconf_bias_disable_get, + .bias_set = mtk_pinconf_bias_set, + .bias_get = mtk_pinconf_bias_get, + .drive_set = mtk_pinconf_drive_set, + .drive_get = mtk_pinconf_drive_get, +}; + +static const struct of_device_id mt7622_pinctrl_of_match[] = { + { .compatible = "mediatek,mt7622-pinctrl", }, { } }; -static int mtk_pinctrl_probe(struct platform_device *pdev) +static int mt7622_pinctrl_probe(struct platform_device *pdev) { - struct resource *res; - struct mtk_pinctrl *hw; - const struct of_device_id *of_id = - of_match_device(mtk_pinctrl_of_match, &pdev->dev); - int err; - - hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); - if (!hw) - return -ENOMEM; - - hw->soc = of_id->data; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "missing IO resource\n"); - return -ENXIO; - } - - hw->dev = &pdev->dev; - hw->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hw->base)) - return PTR_ERR(hw->base); - - /* Setup pins descriptions per SoC types */ - mtk_desc.pins = hw->soc->pins; - mtk_desc.npins = hw->soc->npins; - mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); - mtk_desc.custom_params = mtk_custom_bindings; -#ifdef CONFIG_DEBUG_FS - mtk_desc.custom_conf_items = mtk_conf_items; -#endif - - err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, - &hw->pctrl); - if (err) - return err; - - /* Setup groups descriptions per SoC types */ - err = mtk_build_groups(hw); - if (err) { - dev_err(&pdev->dev, "Failed to build groups\n"); - return err; - } - - /* Setup functions descriptions per SoC types */ - err = mtk_build_functions(hw); - if (err) { - dev_err(&pdev->dev, "Failed to build functions\n"); - return err; - } - - /* For able to make pinctrl_claim_hogs, we must not enable pinctrl - * until all groups and functions are being added one. - */ - err = pinctrl_enable(hw->pctrl); - if (err) - return err; - - err = mtk_build_eint(hw, pdev); - if (err) - dev_warn(&pdev->dev, - "Failed to add EINT, but pinctrl still can work\n"); - - /* Build gpiochip should be after pinctrl_enable is done */ - err = mtk_build_gpiochip(hw, pdev->dev.of_node); - if (err) { - dev_err(&pdev->dev, "Failed to add gpio_chip\n"); - return err; - } - - platform_set_drvdata(pdev, hw); - - return 0; + return mtk_moore_pinctrl_probe(pdev, &mt7622_data); } -static struct platform_driver mtk_pinctrl_driver = { +static struct platform_driver mt7622_pinctrl_driver = { .driver = { - .name = "mtk-pinctrl", - .of_match_table = mtk_pinctrl_of_match, + .name = "mt7622-pinctrl", + .of_match_table = mt7622_pinctrl_of_match, }, - .probe = mtk_pinctrl_probe, + .probe = mt7622_pinctrl_probe, }; -static int __init mtk_pinctrl_init(void) +static int __init mt7622_pinctrl_init(void) { - return platform_driver_register(&mtk_pinctrl_driver); + return platform_driver_register(&mt7622_pinctrl_driver); } -arch_initcall(mtk_pinctrl_init); +arch_initcall(mt7622_pinctrl_init); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c new file mode 100644 index 000000000000..b8d9d31db74f --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c @@ -0,0 +1,1441 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The MT7623 driver based on Linux generic pinctrl binding. + * + * Copyright (C) 2015 - 2018 MediaTek Inc. + * Author: Biao Huang <biao.huang@mediatek.com> + * Ryder Lee <ryder.lee@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + */ + +#include "pinctrl-moore.h" + +#define PIN_BOND_REG0 0xb10 +#define PIN_BOND_REG1 0xf20 +#define PIN_BOND_REG2 0xef0 +#define BOND_PCIE_CLR (0x77 << 3) +#define BOND_I2S_CLR 0x3 +#define BOND_MSDC0E_CLR 0x1 + +#define PIN_FIELD15(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 15, false) + +#define PIN_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 16, 0) + +#define PINS_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 16, 1) + +#define MT7623_PIN(_number, _name, _eint_n, _drv_grp) \ + MTK_PIN(_number, _name, 0, _eint_n, _drv_grp) + +static const struct mtk_pin_field_calc mt7623_pin_mode_range[] = { + PIN_FIELD15(0, 278, 0x760, 0x10, 0, 3), +}; + +static const struct mtk_pin_field_calc mt7623_pin_dir_range[] = { + PIN_FIELD16(0, 175, 0x0, 0x10, 0, 1), + PIN_FIELD16(176, 278, 0xc0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_di_range[] = { + PIN_FIELD16(0, 278, 0x630, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_do_range[] = { + PIN_FIELD16(0, 278, 0x500, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_ies_range[] = { + PINS_FIELD16(0, 6, 0xb20, 0x10, 0, 1), + PINS_FIELD16(7, 9, 0xb20, 0x10, 1, 1), + PINS_FIELD16(10, 13, 0xb30, 0x10, 3, 1), + PINS_FIELD16(14, 15, 0xb30, 0x10, 13, 1), + PINS_FIELD16(16, 17, 0xb40, 0x10, 7, 1), + PINS_FIELD16(18, 29, 0xb40, 0x10, 13, 1), + PINS_FIELD16(30, 32, 0xb40, 0x10, 7, 1), + PINS_FIELD16(33, 37, 0xb40, 0x10, 13, 1), + PIN_FIELD16(38, 38, 0xb20, 0x10, 13, 1), + PINS_FIELD16(39, 42, 0xb40, 0x10, 13, 1), + PINS_FIELD16(43, 45, 0xb20, 0x10, 10, 1), + PINS_FIELD16(47, 48, 0xb20, 0x10, 11, 1), + PIN_FIELD16(49, 49, 0xb20, 0x10, 12, 1), + PINS_FIELD16(50, 52, 0xb20, 0x10, 13, 1), + PINS_FIELD16(53, 56, 0xb20, 0x10, 14, 1), + PINS_FIELD16(57, 58, 0xb20, 0x10, 15, 1), + PIN_FIELD16(59, 59, 0xb30, 0x10, 10, 1), + PINS_FIELD16(60, 62, 0xb30, 0x10, 0, 1), + PINS_FIELD16(63, 65, 0xb30, 0x10, 1, 1), + PINS_FIELD16(66, 71, 0xb30, 0x10, 2, 1), + PINS_FIELD16(72, 74, 0xb20, 0x10, 12, 1), + PINS_FIELD16(75, 76, 0xb30, 0x10, 3, 1), + PINS_FIELD16(77, 78, 0xb30, 0x10, 4, 1), + PINS_FIELD16(79, 82, 0xb30, 0x10, 5, 1), + PINS_FIELD16(83, 84, 0xb30, 0x10, 2, 1), + PIN_FIELD16(85, 85, 0xda0, 0x10, 4, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 4, 1), + PINS_FIELD16(87, 90, 0xdb0, 0x10, 4, 1), + PINS_FIELD16(101, 104, 0xb30, 0x10, 6, 1), + PIN_FIELD16(105, 105, 0xd40, 0x10, 4, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 4, 1), + PINS_FIELD16(107, 110, 0xd50, 0x10, 4, 1), + PINS_FIELD16(111, 115, 0xce0, 0x10, 4, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 4, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 4, 1), + PINS_FIELD16(118, 121, 0xce0, 0x10, 4, 1), + PINS_FIELD16(122, 125, 0xb30, 0x10, 7, 1), + PIN_FIELD16(126, 126, 0xb20, 0x10, 12, 1), + PINS_FIELD16(127, 142, 0xb30, 0x10, 9, 1), + PINS_FIELD16(143, 160, 0xb30, 0x10, 10, 1), + PINS_FIELD16(161, 168, 0xb30, 0x10, 12, 1), + PINS_FIELD16(169, 183, 0xb30, 0x10, 10, 1), + PINS_FIELD16(184, 186, 0xb30, 0x10, 9, 1), + PIN_FIELD16(187, 187, 0xb30, 0x10, 14, 1), + PIN_FIELD16(188, 188, 0xb20, 0x10, 13, 1), + PINS_FIELD16(189, 193, 0xb30, 0x10, 15, 1), + PINS_FIELD16(194, 198, 0xb40, 0x10, 0, 1), + PIN_FIELD16(199, 199, 0xb20, 0x10, 1, 1), + PINS_FIELD16(200, 202, 0xb40, 0x10, 1, 1), + PINS_FIELD16(203, 207, 0xb40, 0x10, 2, 1), + PINS_FIELD16(208, 209, 0xb40, 0x10, 3, 1), + PIN_FIELD16(210, 210, 0xb40, 0x10, 4, 1), + PINS_FIELD16(211, 235, 0xb40, 0x10, 5, 1), + PINS_FIELD16(236, 241, 0xb40, 0x10, 6, 1), + PINS_FIELD16(242, 243, 0xb40, 0x10, 7, 1), + PINS_FIELD16(244, 247, 0xb40, 0x10, 8, 1), + PIN_FIELD16(248, 248, 0xb40, 0x10, 9, 1), + PINS_FIELD16(249, 257, 0xfc0, 0x10, 4, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 4, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 4, 1), + PIN_FIELD16(260, 260, 0x3a0, 0x10, 4, 1), + PIN_FIELD16(261, 261, 0xd50, 0x10, 4, 1), + PINS_FIELD16(262, 277, 0xb40, 0x10, 12, 1), + PIN_FIELD16(278, 278, 0xb40, 0x10, 13, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_smt_range[] = { + PINS_FIELD16(0, 6, 0xb50, 0x10, 0, 1), + PINS_FIELD16(7, 9, 0xb50, 0x10, 1, 1), + PINS_FIELD16(10, 13, 0xb60, 0x10, 3, 1), + PINS_FIELD16(14, 15, 0xb60, 0x10, 13, 1), + PINS_FIELD16(16, 17, 0xb70, 0x10, 7, 1), + PINS_FIELD16(18, 29, 0xb70, 0x10, 13, 1), + PINS_FIELD16(30, 32, 0xb70, 0x10, 7, 1), + PINS_FIELD16(33, 37, 0xb70, 0x10, 13, 1), + PIN_FIELD16(38, 38, 0xb50, 0x10, 13, 1), + PINS_FIELD16(39, 42, 0xb70, 0x10, 13, 1), + PINS_FIELD16(43, 45, 0xb50, 0x10, 10, 1), + PINS_FIELD16(47, 48, 0xb50, 0x10, 11, 1), + PIN_FIELD16(49, 49, 0xb50, 0x10, 12, 1), + PINS_FIELD16(50, 52, 0xb50, 0x10, 13, 1), + PINS_FIELD16(53, 56, 0xb50, 0x10, 14, 1), + PINS_FIELD16(57, 58, 0xb50, 0x10, 15, 1), + PIN_FIELD16(59, 59, 0xb60, 0x10, 10, 1), + PINS_FIELD16(60, 62, 0xb60, 0x10, 0, 1), + PINS_FIELD16(63, 65, 0xb60, 0x10, 1, 1), + PINS_FIELD16(66, 71, 0xb60, 0x10, 2, 1), + PINS_FIELD16(72, 74, 0xb50, 0x10, 12, 1), + PINS_FIELD16(75, 76, 0xb60, 0x10, 3, 1), + PINS_FIELD16(77, 78, 0xb60, 0x10, 4, 1), + PINS_FIELD16(79, 82, 0xb60, 0x10, 5, 1), + PINS_FIELD16(83, 84, 0xb60, 0x10, 2, 1), + PIN_FIELD16(85, 85, 0xda0, 0x10, 11, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 11, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 3, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 7, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 11, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 15, 1), + PINS_FIELD16(101, 104, 0xb60, 0x10, 6, 1), + PIN_FIELD16(105, 105, 0xd40, 0x10, 11, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 11, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 3, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 7, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 11, 1), + PIN_FIELD16(110, 110, 0xd60, 0x10, 15, 1), + PIN_FIELD16(111, 111, 0xd00, 0x10, 15, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 11, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 7, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 3, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 3, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 11, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 11, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 15, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 7, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 3, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 7, 1), + PINS_FIELD16(122, 125, 0xb60, 0x10, 7, 1), + PIN_FIELD16(126, 126, 0xb50, 0x10, 12, 1), + PINS_FIELD16(127, 142, 0xb60, 0x10, 9, 1), + PINS_FIELD16(143, 160, 0xb60, 0x10, 10, 1), + PINS_FIELD16(161, 168, 0xb60, 0x10, 12, 1), + PINS_FIELD16(169, 183, 0xb60, 0x10, 10, 1), + PINS_FIELD16(184, 186, 0xb60, 0x10, 9, 1), + PIN_FIELD16(187, 187, 0xb60, 0x10, 14, 1), + PIN_FIELD16(188, 188, 0xb50, 0x10, 13, 1), + PINS_FIELD16(189, 193, 0xb60, 0x10, 15, 1), + PINS_FIELD16(194, 198, 0xb70, 0x10, 0, 1), + PIN_FIELD16(199, 199, 0xb50, 0x10, 1, 1), + PINS_FIELD16(200, 202, 0xb70, 0x10, 1, 1), + PINS_FIELD16(203, 207, 0xb70, 0x10, 2, 1), + PINS_FIELD16(208, 209, 0xb70, 0x10, 3, 1), + PIN_FIELD16(210, 210, 0xb70, 0x10, 4, 1), + PINS_FIELD16(211, 235, 0xb70, 0x10, 5, 1), + PINS_FIELD16(236, 241, 0xb70, 0x10, 6, 1), + PINS_FIELD16(242, 243, 0xb70, 0x10, 7, 1), + PINS_FIELD16(244, 247, 0xb70, 0x10, 8, 1), + PIN_FIELD16(248, 248, 0xb70, 0x10, 9, 10), + PIN_FIELD16(249, 249, 0x140, 0x10, 3, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 15, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 11, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 7, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 3, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 15, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 11, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 7, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 3, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 11, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 11, 1), + PIN_FIELD16(260, 260, 0x3a0, 0x10, 11, 1), + PIN_FIELD16(261, 261, 0x0b0, 0x10, 3, 1), + PINS_FIELD16(262, 277, 0xb70, 0x10, 12, 1), + PIN_FIELD16(278, 278, 0xb70, 0x10, 13, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_pullen_range[] = { + PIN_FIELD16(0, 278, 0x150, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_pullsel_range[] = { + PIN_FIELD16(0, 278, 0x280, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_drv_range[] = { + PINS_FIELD16(0, 6, 0xf50, 0x10, 0, 4), + PINS_FIELD16(7, 9, 0xf50, 0x10, 4, 4), + PINS_FIELD16(10, 13, 0xf50, 0x10, 4, 4), + PINS_FIELD16(14, 15, 0xf50, 0x10, 12, 4), + PINS_FIELD16(16, 17, 0xf60, 0x10, 0, 4), + PINS_FIELD16(18, 21, 0xf60, 0x10, 0, 4), + PINS_FIELD16(22, 26, 0xf60, 0x10, 8, 4), + PINS_FIELD16(27, 29, 0xf60, 0x10, 12, 4), + PINS_FIELD16(30, 32, 0xf60, 0x10, 0, 4), + PINS_FIELD16(33, 37, 0xf70, 0x10, 0, 4), + PIN_FIELD16(38, 38, 0xf70, 0x10, 4, 4), + PINS_FIELD16(39, 42, 0xf70, 0x10, 8, 4), + PINS_FIELD16(43, 45, 0xf70, 0x10, 12, 4), + PINS_FIELD16(47, 48, 0xf80, 0x10, 0, 4), + PIN_FIELD16(49, 49, 0xf80, 0x10, 4, 4), + PINS_FIELD16(50, 52, 0xf70, 0x10, 4, 4), + PINS_FIELD16(53, 56, 0xf80, 0x10, 12, 4), + PINS_FIELD16(60, 62, 0xf90, 0x10, 8, 4), + PINS_FIELD16(63, 65, 0xf90, 0x10, 12, 4), + PINS_FIELD16(66, 71, 0xfa0, 0x10, 0, 4), + PINS_FIELD16(72, 74, 0xf80, 0x10, 4, 4), + PIN_FIELD16(85, 85, 0xda0, 0x10, 0, 4), + PIN_FIELD16(86, 86, 0xd90, 0x10, 0, 4), + PINS_FIELD16(87, 90, 0xdb0, 0x10, 0, 4), + PIN_FIELD16(105, 105, 0xd40, 0x10, 0, 4), + PIN_FIELD16(106, 106, 0xd30, 0x10, 0, 4), + PINS_FIELD16(107, 110, 0xd50, 0x10, 0, 4), + PINS_FIELD16(111, 115, 0xce0, 0x10, 0, 4), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 0, 4), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 0, 4), + PINS_FIELD16(118, 121, 0xce0, 0x10, 0, 4), + PIN_FIELD16(126, 126, 0xf80, 0x10, 4, 4), + PIN_FIELD16(188, 188, 0xf70, 0x10, 4, 4), + PINS_FIELD16(189, 193, 0xfe0, 0x10, 8, 4), + PINS_FIELD16(194, 198, 0xfe0, 0x10, 12, 4), + PIN_FIELD16(199, 199, 0xf50, 0x10, 4, 4), + PINS_FIELD16(200, 202, 0xfd0, 0x10, 0, 4), + PINS_FIELD16(203, 207, 0xfd0, 0x10, 4, 4), + PINS_FIELD16(208, 209, 0xfd0, 0x10, 8, 4), + PIN_FIELD16(210, 210, 0xfd0, 0x10, 12, 4), + PINS_FIELD16(211, 235, 0xff0, 0x10, 0, 4), + PINS_FIELD16(236, 241, 0xff0, 0x10, 4, 4), + PINS_FIELD16(242, 243, 0xff0, 0x10, 8, 4), + PIN_FIELD16(248, 248, 0xf00, 0x10, 0, 4), + PINS_FIELD16(249, 256, 0xfc0, 0x10, 0, 4), + PIN_FIELD16(257, 257, 0xce0, 0x10, 0, 4), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 0, 4), + PIN_FIELD16(259, 259, 0xc90, 0x10, 0, 4), + PIN_FIELD16(260, 260, 0x3a0, 0x10, 0, 4), + PIN_FIELD16(261, 261, 0xd50, 0x10, 0, 4), + PINS_FIELD16(262, 277, 0xf00, 0x10, 8, 4), + PIN_FIELD16(278, 278, 0xf70, 0x10, 8, 4), +}; + +static const struct mtk_pin_field_calc mt7623_pin_tdsel_range[] = { + PINS_FIELD16(262, 276, 0x4c0, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt7623_pin_pupd_range[] = { + /* MSDC0 */ + PIN_FIELD16(111, 111, 0xd00, 0x10, 12, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 8, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 4, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 0, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 0, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 8, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 8, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 12, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 8, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 4, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 0, 1), + /* MSDC1 */ + PIN_FIELD16(105, 105, 0xd40, 0x10, 8, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 8, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 0, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 10, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 4, 1), + PIN_FIELD16(110, 110, 0xc60, 0x10, 12, 1), + /* MSDC1 */ + PIN_FIELD16(85, 85, 0xda0, 0x10, 8, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 8, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 0, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 10, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 4, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 12, 1), + /* MSDC0E */ + PIN_FIELD16(249, 249, 0x140, 0x10, 0, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 12, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 8, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 4, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 0, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 12, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 8, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 4, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 0, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 8, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 8, 1), + PIN_FIELD16(261, 261, 0x140, 0x10, 8, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_r1_range[] = { + /* MSDC0 */ + PIN_FIELD16(111, 111, 0xd00, 0x10, 13, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 9, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 5, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 1, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 1, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 9, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 9, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 13, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 9, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 5, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 1, 1), + /* MSDC1 */ + PIN_FIELD16(105, 105, 0xd40, 0x10, 9, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 9, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 1, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 9, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 5, 1), + PIN_FIELD16(110, 110, 0xc60, 0x10, 13, 1), + /* MSDC2 */ + PIN_FIELD16(85, 85, 0xda0, 0x10, 9, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 9, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 1, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 9, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 5, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 13, 1), + /* MSDC0E */ + PIN_FIELD16(249, 249, 0x140, 0x10, 1, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 13, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 9, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 5, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 1, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 13, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 9, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 5, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 1, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 9, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 9, 1), + PIN_FIELD16(261, 261, 0x140, 0x10, 9, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_r0_range[] = { + /* MSDC0 */ + PIN_FIELD16(111, 111, 0xd00, 0x10, 14, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 10, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 6, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 2, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 2, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 10, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 10, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 14, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 10, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 6, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 2, 1), + /* MSDC1 */ + PIN_FIELD16(105, 105, 0xd40, 0x10, 10, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 10, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 2, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 8, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 6, 1), + PIN_FIELD16(110, 110, 0xc60, 0x10, 14, 1), + /* MSDC2 */ + PIN_FIELD16(85, 85, 0xda0, 0x10, 10, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 10, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 2, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 8, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 6, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 14, 1), + /* MSDC0E */ + PIN_FIELD16(249, 249, 0x140, 0x10, 2, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 14, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 10, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 6, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 2, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 14, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 10, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 6, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 5, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 10, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 10, 1), + PIN_FIELD16(261, 261, 0x140, 0x10, 10, 1), +}; + +static const struct mtk_pin_reg_calc mt7623_reg_cals[] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7623_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7623_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7623_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7623_pin_do_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7623_pin_smt_range), + [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7623_pin_pullsel_range), + [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7623_pin_pullen_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7623_pin_drv_range), + [PINCTRL_PIN_REG_TDSEL] = MTK_RANGE(mt7623_pin_tdsel_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7623_pin_ies_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7623_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7623_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7623_pin_r1_range), +}; + +static const struct mtk_pin_desc mt7623_pins[] = { + MT7623_PIN(0, "PWRAP_SPI0_MI", 148, DRV_GRP3), + MT7623_PIN(1, "PWRAP_SPI0_MO", 149, DRV_GRP3), + MT7623_PIN(2, "PWRAP_INT", 150, DRV_GRP3), + MT7623_PIN(3, "PWRAP_SPI0_CK", 151, DRV_GRP3), + MT7623_PIN(4, "PWRAP_SPI0_CSN", 152, DRV_GRP3), + MT7623_PIN(5, "PWRAP_SPI0_CK2", 153, DRV_GRP3), + MT7623_PIN(6, "PWRAP_SPI0_CSN2", 154, DRV_GRP3), + MT7623_PIN(7, "SPI1_CSN", 155, DRV_GRP3), + MT7623_PIN(8, "SPI1_MI", 156, DRV_GRP3), + MT7623_PIN(9, "SPI1_MO", 157, DRV_GRP3), + MT7623_PIN(10, "RTC32K_CK", 158, DRV_GRP3), + MT7623_PIN(11, "WATCHDOG", 159, DRV_GRP3), + MT7623_PIN(12, "SRCLKENA", 160, DRV_GRP3), + MT7623_PIN(13, "SRCLKENAI", 161, DRV_GRP3), + MT7623_PIN(14, "URXD2", 162, DRV_GRP1), + MT7623_PIN(15, "UTXD2", 163, DRV_GRP1), + MT7623_PIN(16, "I2S5_DATA_IN", 164, DRV_GRP1), + MT7623_PIN(17, "I2S5_BCK", 165, DRV_GRP1), + MT7623_PIN(18, "PCM_CLK", 166, DRV_GRP1), + MT7623_PIN(19, "PCM_SYNC", 167, DRV_GRP1), + MT7623_PIN(20, "PCM_RX", EINT_NA, DRV_GRP1), + MT7623_PIN(21, "PCM_TX", EINT_NA, DRV_GRP1), + MT7623_PIN(22, "EINT0", 0, DRV_GRP1), + MT7623_PIN(23, "EINT1", 1, DRV_GRP1), + MT7623_PIN(24, "EINT2", 2, DRV_GRP1), + MT7623_PIN(25, "EINT3", 3, DRV_GRP1), + MT7623_PIN(26, "EINT4", 4, DRV_GRP1), + MT7623_PIN(27, "EINT5", 5, DRV_GRP1), + MT7623_PIN(28, "EINT6", 6, DRV_GRP1), + MT7623_PIN(29, "EINT7", 7, DRV_GRP1), + MT7623_PIN(30, "I2S5_LRCK", 12, DRV_GRP1), + MT7623_PIN(31, "I2S5_MCLK", 13, DRV_GRP1), + MT7623_PIN(32, "I2S5_DATA", 14, DRV_GRP1), + MT7623_PIN(33, "I2S1_DATA", 15, DRV_GRP1), + MT7623_PIN(34, "I2S1_DATA_IN", 16, DRV_GRP1), + MT7623_PIN(35, "I2S1_BCK", 17, DRV_GRP1), + MT7623_PIN(36, "I2S1_LRCK", 18, DRV_GRP1), + MT7623_PIN(37, "I2S1_MCLK", 19, DRV_GRP1), + MT7623_PIN(38, "I2S2_DATA", 20, DRV_GRP1), + MT7623_PIN(39, "JTMS", 21, DRV_GRP3), + MT7623_PIN(40, "JTCK", 22, DRV_GRP3), + MT7623_PIN(41, "JTDI", 23, DRV_GRP3), + MT7623_PIN(42, "JTDO", 24, DRV_GRP3), + MT7623_PIN(43, "NCLE", 25, DRV_GRP1), + MT7623_PIN(44, "NCEB1", 26, DRV_GRP1), + MT7623_PIN(45, "NCEB0", 27, DRV_GRP1), + MT7623_PIN(46, "IR", 28, DRV_FIXED), + MT7623_PIN(47, "NREB", 29, DRV_GRP1), + MT7623_PIN(48, "NRNB", 30, DRV_GRP1), + MT7623_PIN(49, "I2S0_DATA", 31, DRV_GRP1), + MT7623_PIN(50, "I2S2_BCK", 32, DRV_GRP1), + MT7623_PIN(51, "I2S2_DATA_IN", 33, DRV_GRP1), + MT7623_PIN(52, "I2S2_LRCK", 34, DRV_GRP1), + MT7623_PIN(53, "SPI0_CSN", 35, DRV_GRP1), + MT7623_PIN(54, "SPI0_CK", 36, DRV_GRP1), + MT7623_PIN(55, "SPI0_MI", 37, DRV_GRP1), + MT7623_PIN(56, "SPI0_MO", 38, DRV_GRP1), + MT7623_PIN(57, "SDA1", 39, DRV_FIXED), + MT7623_PIN(58, "SCL1", 40, DRV_FIXED), + MT7623_PIN(59, "RAMBUF_I_CLK", EINT_NA, DRV_FIXED), + MT7623_PIN(60, "WB_RSTB", 41, DRV_GRP3), + MT7623_PIN(61, "F2W_DATA", 42, DRV_GRP3), + MT7623_PIN(62, "F2W_CLK", 43, DRV_GRP3), + MT7623_PIN(63, "WB_SCLK", 44, DRV_GRP3), + MT7623_PIN(64, "WB_SDATA", 45, DRV_GRP3), + MT7623_PIN(65, "WB_SEN", 46, DRV_GRP3), + MT7623_PIN(66, "WB_CRTL0", 47, DRV_GRP3), + MT7623_PIN(67, "WB_CRTL1", 48, DRV_GRP3), + MT7623_PIN(68, "WB_CRTL2", 49, DRV_GRP3), + MT7623_PIN(69, "WB_CRTL3", 50, DRV_GRP3), + MT7623_PIN(70, "WB_CRTL4", 51, DRV_GRP3), + MT7623_PIN(71, "WB_CRTL5", 52, DRV_GRP3), + MT7623_PIN(72, "I2S0_DATA_IN", 53, DRV_GRP1), + MT7623_PIN(73, "I2S0_LRCK", 54, DRV_GRP1), + MT7623_PIN(74, "I2S0_BCK", 55, DRV_GRP1), + MT7623_PIN(75, "SDA0", 56, DRV_FIXED), + MT7623_PIN(76, "SCL0", 57, DRV_FIXED), + MT7623_PIN(77, "SDA2", 58, DRV_FIXED), + MT7623_PIN(78, "SCL2", 59, DRV_FIXED), + MT7623_PIN(79, "URXD0", 60, DRV_FIXED), + MT7623_PIN(80, "UTXD0", 61, DRV_FIXED), + MT7623_PIN(81, "URXD1", 62, DRV_FIXED), + MT7623_PIN(82, "UTXD1", 63, DRV_FIXED), + MT7623_PIN(83, "LCM_RST", 64, DRV_FIXED), + MT7623_PIN(84, "DSI_TE", 65, DRV_FIXED), + MT7623_PIN(85, "MSDC2_CMD", 66, DRV_GRP4), + MT7623_PIN(86, "MSDC2_CLK", 67, DRV_GRP4), + MT7623_PIN(87, "MSDC2_DAT0", 68, DRV_GRP4), + MT7623_PIN(88, "MSDC2_DAT1", 69, DRV_GRP4), + MT7623_PIN(89, "MSDC2_DAT2", 70, DRV_GRP4), + MT7623_PIN(90, "MSDC2_DAT3", 71, DRV_GRP4), + MT7623_PIN(91, "TDN3", EINT_NA, DRV_FIXED), + MT7623_PIN(92, "TDP3", EINT_NA, DRV_FIXED), + MT7623_PIN(93, "TDN2", EINT_NA, DRV_FIXED), + MT7623_PIN(94, "TDP2", EINT_NA, DRV_FIXED), + MT7623_PIN(95, "TCN", EINT_NA, DRV_FIXED), + MT7623_PIN(96, "TCP", EINT_NA, DRV_FIXED), + MT7623_PIN(97, "TDN1", EINT_NA, DRV_FIXED), + MT7623_PIN(98, "TDP1", EINT_NA, DRV_FIXED), + MT7623_PIN(99, "TDN0", EINT_NA, DRV_FIXED), + MT7623_PIN(100, "TDP0", EINT_NA, DRV_FIXED), + MT7623_PIN(101, "SPI2_CSN", 74, DRV_FIXED), + MT7623_PIN(102, "SPI2_MI", 75, DRV_FIXED), + MT7623_PIN(103, "SPI2_MO", 76, DRV_FIXED), + MT7623_PIN(104, "SPI2_CLK", 77, DRV_FIXED), + MT7623_PIN(105, "MSDC1_CMD", 78, DRV_GRP4), + MT7623_PIN(106, "MSDC1_CLK", 79, DRV_GRP4), + MT7623_PIN(107, "MSDC1_DAT0", 80, DRV_GRP4), + MT7623_PIN(108, "MSDC1_DAT1", 81, DRV_GRP4), + MT7623_PIN(109, "MSDC1_DAT2", 82, DRV_GRP4), + MT7623_PIN(110, "MSDC1_DAT3", 83, DRV_GRP4), + MT7623_PIN(111, "MSDC0_DAT7", 84, DRV_GRP4), + MT7623_PIN(112, "MSDC0_DAT6", 85, DRV_GRP4), + MT7623_PIN(113, "MSDC0_DAT5", 86, DRV_GRP4), + MT7623_PIN(114, "MSDC0_DAT4", 87, DRV_GRP4), + MT7623_PIN(115, "MSDC0_RSTB", 88, DRV_GRP4), + MT7623_PIN(116, "MSDC0_CMD", 89, DRV_GRP4), + MT7623_PIN(117, "MSDC0_CLK", 90, DRV_GRP4), + MT7623_PIN(118, "MSDC0_DAT3", 91, DRV_GRP4), + MT7623_PIN(119, "MSDC0_DAT2", 92, DRV_GRP4), + MT7623_PIN(120, "MSDC0_DAT1", 93, DRV_GRP4), + MT7623_PIN(121, "MSDC0_DAT0", 94, DRV_GRP4), + MT7623_PIN(122, "CEC", 95, DRV_FIXED), + MT7623_PIN(123, "HTPLG", 96, DRV_FIXED), + MT7623_PIN(124, "HDMISCK", 97, DRV_FIXED), + MT7623_PIN(125, "HDMISD", 98, DRV_FIXED), + MT7623_PIN(126, "I2S0_MCLK", 99, DRV_GRP1), + MT7623_PIN(127, "RAMBUF_IDATA0", EINT_NA, DRV_FIXED), + MT7623_PIN(128, "RAMBUF_IDATA1", EINT_NA, DRV_FIXED), + MT7623_PIN(129, "RAMBUF_IDATA2", EINT_NA, DRV_FIXED), + MT7623_PIN(130, "RAMBUF_IDATA3", EINT_NA, DRV_FIXED), + MT7623_PIN(131, "RAMBUF_IDATA4", EINT_NA, DRV_FIXED), + MT7623_PIN(132, "RAMBUF_IDATA5", EINT_NA, DRV_FIXED), + MT7623_PIN(133, "RAMBUF_IDATA6", EINT_NA, DRV_FIXED), + MT7623_PIN(134, "RAMBUF_IDATA7", EINT_NA, DRV_FIXED), + MT7623_PIN(135, "RAMBUF_IDATA8", EINT_NA, DRV_FIXED), + MT7623_PIN(136, "RAMBUF_IDATA9", EINT_NA, DRV_FIXED), + MT7623_PIN(137, "RAMBUF_IDATA10", EINT_NA, DRV_FIXED), + MT7623_PIN(138, "RAMBUF_IDATA11", EINT_NA, DRV_FIXED), + MT7623_PIN(139, "RAMBUF_IDATA12", EINT_NA, DRV_FIXED), + MT7623_PIN(140, "RAMBUF_IDATA13", EINT_NA, DRV_FIXED), + MT7623_PIN(141, "RAMBUF_IDATA14", EINT_NA, DRV_FIXED), + MT7623_PIN(142, "RAMBUF_IDATA15", EINT_NA, DRV_FIXED), + MT7623_PIN(143, "RAMBUF_ODATA0", EINT_NA, DRV_FIXED), + MT7623_PIN(144, "RAMBUF_ODATA1", EINT_NA, DRV_FIXED), + MT7623_PIN(145, "RAMBUF_ODATA2", EINT_NA, DRV_FIXED), + MT7623_PIN(146, "RAMBUF_ODATA3", EINT_NA, DRV_FIXED), + MT7623_PIN(147, "RAMBUF_ODATA4", EINT_NA, DRV_FIXED), + MT7623_PIN(148, "RAMBUF_ODATA5", EINT_NA, DRV_FIXED), + MT7623_PIN(149, "RAMBUF_ODATA6", EINT_NA, DRV_FIXED), + MT7623_PIN(150, "RAMBUF_ODATA7", EINT_NA, DRV_FIXED), + MT7623_PIN(151, "RAMBUF_ODATA8", EINT_NA, DRV_FIXED), + MT7623_PIN(152, "RAMBUF_ODATA9", EINT_NA, DRV_FIXED), + MT7623_PIN(153, "RAMBUF_ODATA10", EINT_NA, DRV_FIXED), + MT7623_PIN(154, "RAMBUF_ODATA11", EINT_NA, DRV_FIXED), + MT7623_PIN(155, "RAMBUF_ODATA12", EINT_NA, DRV_FIXED), + MT7623_PIN(156, "RAMBUF_ODATA13", EINT_NA, DRV_FIXED), + MT7623_PIN(157, "RAMBUF_ODATA14", EINT_NA, DRV_FIXED), + MT7623_PIN(158, "RAMBUF_ODATA15", EINT_NA, DRV_FIXED), + MT7623_PIN(159, "RAMBUF_BE0", EINT_NA, DRV_FIXED), + MT7623_PIN(160, "RAMBUF_BE1", EINT_NA, DRV_FIXED), + MT7623_PIN(161, "AP2PT_INT", EINT_NA, DRV_FIXED), + MT7623_PIN(162, "AP2PT_INT_CLR", EINT_NA, DRV_FIXED), + MT7623_PIN(163, "PT2AP_INT", EINT_NA, DRV_FIXED), + MT7623_PIN(164, "PT2AP_INT_CLR", EINT_NA, DRV_FIXED), + MT7623_PIN(165, "AP2UP_INT", EINT_NA, DRV_FIXED), + MT7623_PIN(166, "AP2UP_INT_CLR", EINT_NA, DRV_FIXED), + MT7623_PIN(167, "UP2AP_INT", EINT_NA, DRV_FIXED), + MT7623_PIN(168, "UP2AP_INT_CLR", EINT_NA, DRV_FIXED), + MT7623_PIN(169, "RAMBUF_ADDR0", EINT_NA, DRV_FIXED), + MT7623_PIN(170, "RAMBUF_ADDR1", EINT_NA, DRV_FIXED), + MT7623_PIN(171, "RAMBUF_ADDR2", EINT_NA, DRV_FIXED), + MT7623_PIN(172, "RAMBUF_ADDR3", EINT_NA, DRV_FIXED), + MT7623_PIN(173, "RAMBUF_ADDR4", EINT_NA, DRV_FIXED), + MT7623_PIN(174, "RAMBUF_ADDR5", EINT_NA, DRV_FIXED), + MT7623_PIN(175, "RAMBUF_ADDR6", EINT_NA, DRV_FIXED), + MT7623_PIN(176, "RAMBUF_ADDR7", EINT_NA, DRV_FIXED), + MT7623_PIN(177, "RAMBUF_ADDR8", EINT_NA, DRV_FIXED), + MT7623_PIN(178, "RAMBUF_ADDR9", EINT_NA, DRV_FIXED), + MT7623_PIN(179, "RAMBUF_ADDR10", EINT_NA, DRV_FIXED), + MT7623_PIN(180, "RAMBUF_RW", EINT_NA, DRV_FIXED), + MT7623_PIN(181, "RAMBUF_LAST", EINT_NA, DRV_FIXED), + MT7623_PIN(182, "RAMBUF_HP", EINT_NA, DRV_FIXED), + MT7623_PIN(183, "RAMBUF_REQ", EINT_NA, DRV_FIXED), + MT7623_PIN(184, "RAMBUF_ALE", EINT_NA, DRV_FIXED), + MT7623_PIN(185, "RAMBUF_DLE", EINT_NA, DRV_FIXED), + MT7623_PIN(186, "RAMBUF_WDLE", EINT_NA, DRV_FIXED), + MT7623_PIN(187, "RAMBUF_O_CLK", EINT_NA, DRV_FIXED), + MT7623_PIN(188, "I2S2_MCLK", 100, DRV_GRP1), + MT7623_PIN(189, "I2S3_DATA", 101, DRV_GRP1), + MT7623_PIN(190, "I2S3_DATA_IN", 102, DRV_GRP1), + MT7623_PIN(191, "I2S3_BCK", 103, DRV_GRP1), + MT7623_PIN(192, "I2S3_LRCK", 104, DRV_GRP1), + MT7623_PIN(193, "I2S3_MCLK", 105, DRV_GRP1), + MT7623_PIN(194, "I2S4_DATA", 106, DRV_GRP1), + MT7623_PIN(195, "I2S4_DATA_IN", 107, DRV_GRP1), + MT7623_PIN(196, "I2S4_BCK", 108, DRV_GRP1), + MT7623_PIN(197, "I2S4_LRCK", 109, DRV_GRP1), + MT7623_PIN(198, "I2S4_MCLK", 110, DRV_GRP1), + MT7623_PIN(199, "SPI1_CLK", 111, DRV_GRP3), + MT7623_PIN(200, "SPDIF_OUT", 112, DRV_GRP1), + MT7623_PIN(201, "SPDIF_IN0", 113, DRV_GRP1), + MT7623_PIN(202, "SPDIF_IN1", 114, DRV_GRP1), + MT7623_PIN(203, "PWM0", 115, DRV_GRP1), + MT7623_PIN(204, "PWM1", 116, DRV_GRP1), + MT7623_PIN(205, "PWM2", 117, DRV_GRP1), + MT7623_PIN(206, "PWM3", 118, DRV_GRP1), + MT7623_PIN(207, "PWM4", 119, DRV_GRP1), + MT7623_PIN(208, "AUD_EXT_CK1", 120, DRV_GRP1), + MT7623_PIN(209, "AUD_EXT_CK2", 121, DRV_GRP1), + MT7623_PIN(210, "AUD_CLOCK", EINT_NA, DRV_GRP3), + MT7623_PIN(211, "DVP_RESET", EINT_NA, DRV_GRP3), + MT7623_PIN(212, "DVP_CLOCK", EINT_NA, DRV_GRP3), + MT7623_PIN(213, "DVP_CS", EINT_NA, DRV_GRP3), + MT7623_PIN(214, "DVP_CK", EINT_NA, DRV_GRP3), + MT7623_PIN(215, "DVP_DI", EINT_NA, DRV_GRP3), + MT7623_PIN(216, "DVP_DO", EINT_NA, DRV_GRP3), + MT7623_PIN(217, "AP_CS", EINT_NA, DRV_GRP3), + MT7623_PIN(218, "AP_CK", EINT_NA, DRV_GRP3), + MT7623_PIN(219, "AP_DI", EINT_NA, DRV_GRP3), + MT7623_PIN(220, "AP_DO", EINT_NA, DRV_GRP3), + MT7623_PIN(221, "DVD_BCLK", EINT_NA, DRV_GRP3), + MT7623_PIN(222, "T8032_CLK", EINT_NA, DRV_GRP3), + MT7623_PIN(223, "AP_BCLK", EINT_NA, DRV_GRP3), + MT7623_PIN(224, "HOST_CS", EINT_NA, DRV_GRP3), + MT7623_PIN(225, "HOST_CK", EINT_NA, DRV_GRP3), + MT7623_PIN(226, "HOST_DO0", EINT_NA, DRV_GRP3), + MT7623_PIN(227, "HOST_DO1", EINT_NA, DRV_GRP3), + MT7623_PIN(228, "SLV_CS", EINT_NA, DRV_GRP3), + MT7623_PIN(229, "SLV_CK", EINT_NA, DRV_GRP3), + MT7623_PIN(230, "SLV_DI0", EINT_NA, DRV_GRP3), + MT7623_PIN(231, "SLV_DI1", EINT_NA, DRV_GRP3), + MT7623_PIN(232, "AP2DSP_INT", EINT_NA, DRV_GRP3), + MT7623_PIN(233, "AP2DSP_INT_CLR", EINT_NA, DRV_GRP3), + MT7623_PIN(234, "DSP2AP_INT", EINT_NA, DRV_GRP3), + MT7623_PIN(235, "DSP2AP_INT_CLR", EINT_NA, DRV_GRP3), + MT7623_PIN(236, "EXT_SDIO3", 122, DRV_GRP1), + MT7623_PIN(237, "EXT_SDIO2", 123, DRV_GRP1), + MT7623_PIN(238, "EXT_SDIO1", 124, DRV_GRP1), + MT7623_PIN(239, "EXT_SDIO0", 125, DRV_GRP1), + MT7623_PIN(240, "EXT_XCS", 126, DRV_GRP1), + MT7623_PIN(241, "EXT_SCK", 127, DRV_GRP1), + MT7623_PIN(242, "URTS2", 128, DRV_GRP1), + MT7623_PIN(243, "UCTS2", 129, DRV_GRP1), + MT7623_PIN(244, "HDMI_SDA_RX", 130, DRV_FIXED), + MT7623_PIN(245, "HDMI_SCL_RX", 131, DRV_FIXED), + MT7623_PIN(246, "MHL_SENCE", 132, DRV_FIXED), + MT7623_PIN(247, "HDMI_HPD_CBUS_RX", 69, DRV_FIXED), + MT7623_PIN(248, "HDMI_TESTOUTP_RX", 133, DRV_GRP1), + MT7623_PIN(249, "MSDC0E_RSTB", 134, DRV_GRP4), + MT7623_PIN(250, "MSDC0E_DAT7", 135, DRV_GRP4), + MT7623_PIN(251, "MSDC0E_DAT6", 136, DRV_GRP4), + MT7623_PIN(252, "MSDC0E_DAT5", 137, DRV_GRP4), + MT7623_PIN(253, "MSDC0E_DAT4", 138, DRV_GRP4), + MT7623_PIN(254, "MSDC0E_DAT3", 139, DRV_GRP4), + MT7623_PIN(255, "MSDC0E_DAT2", 140, DRV_GRP4), + MT7623_PIN(256, "MSDC0E_DAT1", 141, DRV_GRP4), + MT7623_PIN(257, "MSDC0E_DAT0", 142, DRV_GRP4), + MT7623_PIN(258, "MSDC0E_CMD", 143, DRV_GRP4), + MT7623_PIN(259, "MSDC0E_CLK", 144, DRV_GRP4), + MT7623_PIN(260, "MSDC0E_DSL", 145, DRV_GRP4), + MT7623_PIN(261, "MSDC1_INS", 146, DRV_GRP4), + MT7623_PIN(262, "G2_TXEN", 8, DRV_GRP1), + MT7623_PIN(263, "G2_TXD3", 9, DRV_GRP1), + MT7623_PIN(264, "G2_TXD2", 10, DRV_GRP1), + MT7623_PIN(265, "G2_TXD1", 11, DRV_GRP1), + MT7623_PIN(266, "G2_TXD0", EINT_NA, DRV_GRP1), + MT7623_PIN(267, "G2_TXC", EINT_NA, DRV_GRP1), + MT7623_PIN(268, "G2_RXC", EINT_NA, DRV_GRP1), + MT7623_PIN(269, "G2_RXD0", EINT_NA, DRV_GRP1), + MT7623_PIN(270, "G2_RXD1", EINT_NA, DRV_GRP1), + MT7623_PIN(271, "G2_RXD2", EINT_NA, DRV_GRP1), + MT7623_PIN(272, "G2_RXD3", EINT_NA, DRV_GRP1), + MT7623_PIN(273, "ESW_INT", 168, DRV_GRP1), + MT7623_PIN(274, "G2_RXDV", EINT_NA, DRV_GRP1), + MT7623_PIN(275, "MDC", EINT_NA, DRV_GRP1), + MT7623_PIN(276, "MDIO", EINT_NA, DRV_GRP1), + MT7623_PIN(277, "ESW_RST", EINT_NA, DRV_GRP1), + MT7623_PIN(278, "JTAG_RESET", 147, DRV_GRP3), + MT7623_PIN(279, "USB3_RES_BOND", EINT_NA, DRV_GRP1), +}; + +/* List all groups consisting of these pins dedicated to the enablement of + * certain hardware block and the corresponding mode for all of the pins. + * The hardware probably has multiple combinations of these pinouts. + */ + +/* AUDIO EXT CLK */ +static int mt7623_aud_ext_clk0_pins[] = { 208, }; +static int mt7623_aud_ext_clk0_funcs[] = { 1, }; +static int mt7623_aud_ext_clk1_pins[] = { 209, }; +static int mt7623_aud_ext_clk1_funcs[] = { 1, }; + +/* DISP PWM */ +static int mt7623_disp_pwm_0_pins[] = { 72, }; +static int mt7623_disp_pwm_0_funcs[] = { 5, }; +static int mt7623_disp_pwm_1_pins[] = { 203, }; +static int mt7623_disp_pwm_1_funcs[] = { 2, }; +static int mt7623_disp_pwm_2_pins[] = { 208, }; +static int mt7623_disp_pwm_2_funcs[] = { 5, }; + +/* ESW */ +static int mt7623_esw_int_pins[] = { 273, }; +static int mt7623_esw_int_funcs[] = { 1, }; +static int mt7623_esw_rst_pins[] = { 277, }; +static int mt7623_esw_rst_funcs[] = { 1, }; + +/* EPHY */ +static int mt7623_ephy_pins[] = { 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 274, }; +static int mt7623_ephy_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; + +/* EXT_SDIO */ +static int mt7623_ext_sdio_pins[] = { 236, 237, 238, 239, 240, 241, }; +static int mt7623_ext_sdio_funcs[] = { 1, 1, 1, 1, 1, 1, }; + +/* HDMI RX */ +static int mt7623_hdmi_rx_pins[] = { 247, 248, }; +static int mt7623_hdmi_rx_funcs[] = { 1, 1 }; +static int mt7623_hdmi_rx_i2c_pins[] = { 244, 245, }; +static int mt7623_hdmi_rx_i2c_funcs[] = { 1, 1 }; + +/* HDMI TX */ +static int mt7623_hdmi_cec_pins[] = { 122, }; +static int mt7623_hdmi_cec_funcs[] = { 1, }; +static int mt7623_hdmi_htplg_pins[] = { 123, }; +static int mt7623_hdmi_htplg_funcs[] = { 1, }; +static int mt7623_hdmi_i2c_pins[] = { 124, 125, }; +static int mt7623_hdmi_i2c_funcs[] = { 1, 1 }; + +/* I2C */ +static int mt7623_i2c0_pins[] = { 75, 76, }; +static int mt7623_i2c0_funcs[] = { 1, 1, }; +static int mt7623_i2c1_0_pins[] = { 57, 58, }; +static int mt7623_i2c1_0_funcs[] = { 1, 1, }; +static int mt7623_i2c1_1_pins[] = { 242, 243, }; +static int mt7623_i2c1_1_funcs[] = { 4, 4, }; +static int mt7623_i2c1_2_pins[] = { 85, 86, }; +static int mt7623_i2c1_2_funcs[] = { 3, 3, }; +static int mt7623_i2c1_3_pins[] = { 105, 106, }; +static int mt7623_i2c1_3_funcs[] = { 3, 3, }; +static int mt7623_i2c1_4_pins[] = { 124, 125, }; +static int mt7623_i2c1_4_funcs[] = { 4, 4, }; +static int mt7623_i2c2_0_pins[] = { 77, 78, }; +static int mt7623_i2c2_0_funcs[] = { 1, 1, }; +static int mt7623_i2c2_1_pins[] = { 89, 90, }; +static int mt7623_i2c2_1_funcs[] = { 3, 3, }; +static int mt7623_i2c2_2_pins[] = { 109, 110, }; +static int mt7623_i2c2_2_funcs[] = { 3, 3, }; +static int mt7623_i2c2_3_pins[] = { 122, 123, }; +static int mt7623_i2c2_3_funcs[] = { 4, 4, }; + +/* I2S */ +static int mt7623_i2s0_pins[] = { 49, 72, 73, 74, 126, }; +static int mt7623_i2s0_funcs[] = { 1, 1, 1, 1, 1, }; +static int mt7623_i2s1_pins[] = { 33, 34, 35, 36, 37, }; +static int mt7623_i2s1_funcs[] = { 1, 1, 1, 1, 1, }; +static int mt7623_i2s2_bclk_lrclk_mclk_pins[] = { 50, 52, 188, }; +static int mt7623_i2s2_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, }; +static int mt7623_i2s2_data_in_pins[] = { 51, }; +static int mt7623_i2s2_data_in_funcs[] = { 1, }; +static int mt7623_i2s2_data_0_pins[] = { 203, }; +static int mt7623_i2s2_data_0_funcs[] = { 9, }; +static int mt7623_i2s2_data_1_pins[] = { 38, }; +static int mt7623_i2s2_data_1_funcs[] = { 4, }; +static int mt7623_i2s3_bclk_lrclk_mclk_pins[] = { 191, 192, 193, }; +static int mt7623_i2s3_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, }; +static int mt7623_i2s3_data_in_pins[] = { 190, }; +static int mt7623_i2s3_data_in_funcs[] = { 1, }; +static int mt7623_i2s3_data_0_pins[] = { 204, }; +static int mt7623_i2s3_data_0_funcs[] = { 9, }; +static int mt7623_i2s3_data_1_pins[] = { 2, }; +static int mt7623_i2s3_data_1_funcs[] = { 0, }; +static int mt7623_i2s4_pins[] = { 194, 195, 196, 197, 198, }; +static int mt7623_i2s4_funcs[] = { 1, 1, 1, 1, 1, }; +static int mt7623_i2s5_pins[] = { 16, 17, 30, 31, 32, }; +static int mt7623_i2s5_funcs[] = { 1, 1, 1, 1, 1, }; + +/* IR */ +static int mt7623_ir_pins[] = { 46, }; +static int mt7623_ir_funcs[] = { 1, }; + +/* LCD */ +static int mt7623_mipi_tx_pins[] = { 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, }; +static int mt7623_mipi_tx_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; +static int mt7623_dsi_te_pins[] = { 84, }; +static int mt7623_dsi_te_funcs[] = { 1, }; +static int mt7623_lcm_rst_pins[] = { 83, }; +static int mt7623_lcm_rst_funcs[] = { 1, }; + +/* MDC/MDIO */ +static int mt7623_mdc_mdio_pins[] = { 275, 276, }; +static int mt7623_mdc_mdio_funcs[] = { 1, 1, }; + +/* MSDC */ +static int mt7623_msdc0_pins[] = { 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, }; +static int mt7623_msdc0_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; +static int mt7623_msdc1_pins[] = { 105, 106, 107, 108, 109, 110, }; +static int mt7623_msdc1_funcs[] = { 1, 1, 1, 1, 1, 1, }; +static int mt7623_msdc1_ins_pins[] = { 261, }; +static int mt7623_msdc1_ins_funcs[] = { 1, }; +static int mt7623_msdc1_wp_0_pins[] = { 29, }; +static int mt7623_msdc1_wp_0_funcs[] = { 1, }; +static int mt7623_msdc1_wp_1_pins[] = { 55, }; +static int mt7623_msdc1_wp_1_funcs[] = { 3, }; +static int mt7623_msdc1_wp_2_pins[] = { 209, }; +static int mt7623_msdc1_wp_2_funcs[] = { 2, }; +static int mt7623_msdc2_pins[] = { 85, 86, 87, 88, 89, 90, }; +static int mt7623_msdc2_funcs[] = { 1, 1, 1, 1, 1, 1, }; +static int mt7623_msdc3_pins[] = { 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, }; +static int mt7623_msdc3_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; + +/* NAND */ +static int mt7623_nandc_pins[] = { 43, 47, 48, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, }; +static int mt7623_nandc_funcs[] = { 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, }; +static int mt7623_nandc_ceb0_pins[] = { 45, }; +static int mt7623_nandc_ceb0_funcs[] = { 1, }; +static int mt7623_nandc_ceb1_pins[] = { 44, }; +static int mt7623_nandc_ceb1_funcs[] = { 1, }; + +/* RTC */ +static int mt7623_rtc_pins[] = { 10, }; +static int mt7623_rtc_funcs[] = { 1, }; + +/* OTG */ +static int mt7623_otg_iddig0_0_pins[] = { 29, }; +static int mt7623_otg_iddig0_0_funcs[] = { 1, }; +static int mt7623_otg_iddig0_1_pins[] = { 44, }; +static int mt7623_otg_iddig0_1_funcs[] = { 2, }; +static int mt7623_otg_iddig0_2_pins[] = { 236, }; +static int mt7623_otg_iddig0_2_funcs[] = { 2, }; +static int mt7623_otg_iddig1_0_pins[] = { 27, }; +static int mt7623_otg_iddig1_0_funcs[] = { 2, }; +static int mt7623_otg_iddig1_1_pins[] = { 47, }; +static int mt7623_otg_iddig1_1_funcs[] = { 2, }; +static int mt7623_otg_iddig1_2_pins[] = { 238, }; +static int mt7623_otg_iddig1_2_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus0_0_pins[] = { 28, }; +static int mt7623_otg_drv_vbus0_0_funcs[] = { 1, }; +static int mt7623_otg_drv_vbus0_1_pins[] = { 45, }; +static int mt7623_otg_drv_vbus0_1_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus0_2_pins[] = { 237, }; +static int mt7623_otg_drv_vbus0_2_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus1_0_pins[] = { 26, }; +static int mt7623_otg_drv_vbus1_0_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus1_1_pins[] = { 48, }; +static int mt7623_otg_drv_vbus1_1_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus1_2_pins[] = { 239, }; +static int mt7623_otg_drv_vbus1_2_funcs[] = { 2, }; + +/* PCIE */ +static int mt7623_pcie0_0_perst_pins[] = { 208, }; +static int mt7623_pcie0_0_perst_funcs[] = { 3, }; +static int mt7623_pcie0_1_perst_pins[] = { 22, }; +static int mt7623_pcie0_1_perst_funcs[] = { 2, }; +static int mt7623_pcie1_0_perst_pins[] = { 209, }; +static int mt7623_pcie1_0_perst_funcs[] = { 3, }; +static int mt7623_pcie1_1_perst_pins[] = { 23, }; +static int mt7623_pcie1_1_perst_funcs[] = { 2, }; +static int mt7623_pcie2_0_perst_pins[] = { 24, }; +static int mt7623_pcie2_0_perst_funcs[] = { 2, }; +static int mt7623_pcie2_1_perst_pins[] = { 29, }; +static int mt7623_pcie2_1_perst_funcs[] = { 6, }; +static int mt7623_pcie0_0_wake_pins[] = { 28, }; +static int mt7623_pcie0_0_wake_funcs[] = { 6, }; +static int mt7623_pcie0_1_wake_pins[] = { 251, }; +static int mt7623_pcie0_1_wake_funcs[] = { 6, }; +static int mt7623_pcie1_0_wake_pins[] = { 27, }; +static int mt7623_pcie1_0_wake_funcs[] = { 6, }; +static int mt7623_pcie1_1_wake_pins[] = { 253, }; +static int mt7623_pcie1_1_wake_funcs[] = { 6, }; +static int mt7623_pcie2_0_wake_pins[] = { 26, }; +static int mt7623_pcie2_0_wake_funcs[] = { 6, }; +static int mt7623_pcie2_1_wake_pins[] = { 255, }; +static int mt7623_pcie2_1_wake_funcs[] = { 6, }; +static int mt7623_pcie0_clkreq_pins[] = { 250, }; +static int mt7623_pcie0_clkreq_funcs[] = { 6, }; +static int mt7623_pcie1_clkreq_pins[] = { 252, }; +static int mt7623_pcie1_clkreq_funcs[] = { 6, }; +static int mt7623_pcie2_clkreq_pins[] = { 254, }; +static int mt7623_pcie2_clkreq_funcs[] = { 6, }; + +/* the pcie_*_rev are only used for MT7623 */ +static int mt7623_pcie0_0_rev_perst_pins[] = { 208, }; +static int mt7623_pcie0_0_rev_perst_funcs[] = { 11, }; +static int mt7623_pcie0_1_rev_perst_pins[] = { 22, }; +static int mt7623_pcie0_1_rev_perst_funcs[] = { 10, }; +static int mt7623_pcie1_0_rev_perst_pins[] = { 209, }; +static int mt7623_pcie1_0_rev_perst_funcs[] = { 11, }; +static int mt7623_pcie1_1_rev_perst_pins[] = { 23, }; +static int mt7623_pcie1_1_rev_perst_funcs[] = { 10, }; +static int mt7623_pcie2_0_rev_perst_pins[] = { 24, }; +static int mt7623_pcie2_0_rev_perst_funcs[] = { 11, }; +static int mt7623_pcie2_1_rev_perst_pins[] = { 29, }; +static int mt7623_pcie2_1_rev_perst_funcs[] = { 14, }; + +/* PCM */ +static int mt7623_pcm_clk_0_pins[] = { 18, }; +static int mt7623_pcm_clk_0_funcs[] = { 1, }; +static int mt7623_pcm_clk_1_pins[] = { 17, }; +static int mt7623_pcm_clk_1_funcs[] = { 3, }; +static int mt7623_pcm_clk_2_pins[] = { 35, }; +static int mt7623_pcm_clk_2_funcs[] = { 3, }; +static int mt7623_pcm_clk_3_pins[] = { 50, }; +static int mt7623_pcm_clk_3_funcs[] = { 3, }; +static int mt7623_pcm_clk_4_pins[] = { 74, }; +static int mt7623_pcm_clk_4_funcs[] = { 3, }; +static int mt7623_pcm_clk_5_pins[] = { 191, }; +static int mt7623_pcm_clk_5_funcs[] = { 3, }; +static int mt7623_pcm_clk_6_pins[] = { 196, }; +static int mt7623_pcm_clk_6_funcs[] = { 3, }; +static int mt7623_pcm_sync_0_pins[] = { 19, }; +static int mt7623_pcm_sync_0_funcs[] = { 1, }; +static int mt7623_pcm_sync_1_pins[] = { 30, }; +static int mt7623_pcm_sync_1_funcs[] = { 3, }; +static int mt7623_pcm_sync_2_pins[] = { 36, }; +static int mt7623_pcm_sync_2_funcs[] = { 3, }; +static int mt7623_pcm_sync_3_pins[] = { 52, }; +static int mt7623_pcm_sync_3_funcs[] = { 31, }; +static int mt7623_pcm_sync_4_pins[] = { 73, }; +static int mt7623_pcm_sync_4_funcs[] = { 3, }; +static int mt7623_pcm_sync_5_pins[] = { 192, }; +static int mt7623_pcm_sync_5_funcs[] = { 3, }; +static int mt7623_pcm_sync_6_pins[] = { 197, }; +static int mt7623_pcm_sync_6_funcs[] = { 3, }; +static int mt7623_pcm_rx_0_pins[] = { 20, }; +static int mt7623_pcm_rx_0_funcs[] = { 1, }; +static int mt7623_pcm_rx_1_pins[] = { 16, }; +static int mt7623_pcm_rx_1_funcs[] = { 3, }; +static int mt7623_pcm_rx_2_pins[] = { 34, }; +static int mt7623_pcm_rx_2_funcs[] = { 3, }; +static int mt7623_pcm_rx_3_pins[] = { 51, }; +static int mt7623_pcm_rx_3_funcs[] = { 3, }; +static int mt7623_pcm_rx_4_pins[] = { 72, }; +static int mt7623_pcm_rx_4_funcs[] = { 3, }; +static int mt7623_pcm_rx_5_pins[] = { 190, }; +static int mt7623_pcm_rx_5_funcs[] = { 3, }; +static int mt7623_pcm_rx_6_pins[] = { 195, }; +static int mt7623_pcm_rx_6_funcs[] = { 3, }; +static int mt7623_pcm_tx_0_pins[] = { 21, }; +static int mt7623_pcm_tx_0_funcs[] = { 1, }; +static int mt7623_pcm_tx_1_pins[] = { 32, }; +static int mt7623_pcm_tx_1_funcs[] = { 3, }; +static int mt7623_pcm_tx_2_pins[] = { 33, }; +static int mt7623_pcm_tx_2_funcs[] = { 3, }; +static int mt7623_pcm_tx_3_pins[] = { 38, }; +static int mt7623_pcm_tx_3_funcs[] = { 3, }; +static int mt7623_pcm_tx_4_pins[] = { 49, }; +static int mt7623_pcm_tx_4_funcs[] = { 3, }; +static int mt7623_pcm_tx_5_pins[] = { 189, }; +static int mt7623_pcm_tx_5_funcs[] = { 3, }; +static int mt7623_pcm_tx_6_pins[] = { 194, }; +static int mt7623_pcm_tx_6_funcs[] = { 3, }; + +/* PWM */ +static int mt7623_pwm_ch1_0_pins[] = { 203, }; +static int mt7623_pwm_ch1_0_funcs[] = { 1, }; +static int mt7623_pwm_ch1_1_pins[] = { 208, }; +static int mt7623_pwm_ch1_1_funcs[] = { 2, }; +static int mt7623_pwm_ch1_2_pins[] = { 72, }; +static int mt7623_pwm_ch1_2_funcs[] = { 4, }; +static int mt7623_pwm_ch1_3_pins[] = { 88, }; +static int mt7623_pwm_ch1_3_funcs[] = { 3, }; +static int mt7623_pwm_ch1_4_pins[] = { 108, }; +static int mt7623_pwm_ch1_4_funcs[] = { 3, }; +static int mt7623_pwm_ch2_0_pins[] = { 204, }; +static int mt7623_pwm_ch2_0_funcs[] = { 1, }; +static int mt7623_pwm_ch2_1_pins[] = { 53, }; +static int mt7623_pwm_ch2_1_funcs[] = { 5, }; +static int mt7623_pwm_ch2_2_pins[] = { 88, }; +static int mt7623_pwm_ch2_2_funcs[] = { 6, }; +static int mt7623_pwm_ch2_3_pins[] = { 108, }; +static int mt7623_pwm_ch2_3_funcs[] = { 6, }; +static int mt7623_pwm_ch2_4_pins[] = { 209, }; +static int mt7623_pwm_ch2_4_funcs[] = { 5, }; +static int mt7623_pwm_ch3_0_pins[] = { 205, }; +static int mt7623_pwm_ch3_0_funcs[] = { 1, }; +static int mt7623_pwm_ch3_1_pins[] = { 55, }; +static int mt7623_pwm_ch3_1_funcs[] = { 5, }; +static int mt7623_pwm_ch3_2_pins[] = { 89, }; +static int mt7623_pwm_ch3_2_funcs[] = { 6, }; +static int mt7623_pwm_ch3_3_pins[] = { 109, }; +static int mt7623_pwm_ch3_3_funcs[] = { 6, }; +static int mt7623_pwm_ch4_0_pins[] = { 206, }; +static int mt7623_pwm_ch4_0_funcs[] = { 1, }; +static int mt7623_pwm_ch4_1_pins[] = { 90, }; +static int mt7623_pwm_ch4_1_funcs[] = { 6, }; +static int mt7623_pwm_ch4_2_pins[] = { 110, }; +static int mt7623_pwm_ch4_2_funcs[] = { 6, }; +static int mt7623_pwm_ch4_3_pins[] = { 124, }; +static int mt7623_pwm_ch4_3_funcs[] = { 5, }; +static int mt7623_pwm_ch5_0_pins[] = { 207, }; +static int mt7623_pwm_ch5_0_funcs[] = { 1, }; +static int mt7623_pwm_ch5_1_pins[] = { 125, }; +static int mt7623_pwm_ch5_1_funcs[] = { 5, }; + +/* PWRAP */ +static int mt7623_pwrap_pins[] = { 0, 1, 2, 3, 4, 5, 6, }; +static int mt7623_pwrap_funcs[] = { 1, 1, 1, 1, 1, 1, 1, }; + +/* SPDIF */ +static int mt7623_spdif_in0_0_pins[] = { 56, }; +static int mt7623_spdif_in0_0_funcs[] = { 3, }; +static int mt7623_spdif_in0_1_pins[] = { 201, }; +static int mt7623_spdif_in0_1_funcs[] = { 1, }; +static int mt7623_spdif_in1_0_pins[] = { 54, }; +static int mt7623_spdif_in1_0_funcs[] = { 3, }; +static int mt7623_spdif_in1_1_pins[] = { 202, }; +static int mt7623_spdif_in1_1_funcs[] = { 1, }; +static int mt7623_spdif_out_pins[] = { 202, }; +static int mt7623_spdif_out_funcs[] = { 1, }; + +/* SPI */ +static int mt7623_spi0_pins[] = { 53, 54, 55, 56, }; +static int mt7623_spi0_funcs[] = { 1, 1, 1, 1, }; +static int mt7623_spi1_pins[] = { 7, 199, 8, 9, }; +static int mt7623_spi1_funcs[] = { 1, 1, 1, 1, }; +static int mt7623_spi2_pins[] = { 101, 104, 102, 103, }; +static int mt7623_spi2_funcs[] = { 1, 1, 1, 1, }; + +/* UART */ +static int mt7623_uart0_0_txd_rxd_pins[] = { 79, 80, }; +static int mt7623_uart0_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7623_uart0_1_txd_rxd_pins[] = { 87, 88, }; +static int mt7623_uart0_1_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart0_2_txd_rxd_pins[] = { 107, 108, }; +static int mt7623_uart0_2_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart0_3_txd_rxd_pins[] = { 123, 122, }; +static int mt7623_uart0_3_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart0_rts_cts_pins[] = { 22, 23, }; +static int mt7623_uart0_rts_cts_funcs[] = { 1, 1, }; +static int mt7623_uart1_0_txd_rxd_pins[] = { 81, 82, }; +static int mt7623_uart1_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7623_uart1_1_txd_rxd_pins[] = { 89, 90, }; +static int mt7623_uart1_1_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart1_2_txd_rxd_pins[] = { 109, 110, }; +static int mt7623_uart1_2_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart1_rts_cts_pins[] = { 24, 25, }; +static int mt7623_uart1_rts_cts_funcs[] = { 1, 1, }; +static int mt7623_uart2_0_txd_rxd_pins[] = { 14, 15, }; +static int mt7623_uart2_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7623_uart2_1_txd_rxd_pins[] = { 200, 201, }; +static int mt7623_uart2_1_txd_rxd_funcs[] = { 6, 6, }; +static int mt7623_uart2_rts_cts_pins[] = { 242, 243, }; +static int mt7623_uart2_rts_cts_funcs[] = { 1, 1, }; +static int mt7623_uart3_txd_rxd_pins[] = { 242, 243, }; +static int mt7623_uart3_txd_rxd_funcs[] = { 2, 2, }; +static int mt7623_uart3_rts_cts_pins[] = { 26, 27, }; +static int mt7623_uart3_rts_cts_funcs[] = { 1, 1, }; + +/* Watchdog */ +static int mt7623_watchdog_0_pins[] = { 11, }; +static int mt7623_watchdog_0_funcs[] = { 1, }; +static int mt7623_watchdog_1_pins[] = { 121, }; +static int mt7623_watchdog_1_funcs[] = { 5, }; + +static const struct group_desc mt7623_groups[] = { + PINCTRL_PIN_GROUP("aud_ext_clk0", mt7623_aud_ext_clk0), + PINCTRL_PIN_GROUP("aud_ext_clk1", mt7623_aud_ext_clk1), + PINCTRL_PIN_GROUP("dsi_te", mt7623_dsi_te), + PINCTRL_PIN_GROUP("disp_pwm_0", mt7623_disp_pwm_0), + PINCTRL_PIN_GROUP("disp_pwm_1", mt7623_disp_pwm_1), + PINCTRL_PIN_GROUP("disp_pwm_2", mt7623_disp_pwm_2), + PINCTRL_PIN_GROUP("ephy", mt7623_ephy), + PINCTRL_PIN_GROUP("esw_int", mt7623_esw_int), + PINCTRL_PIN_GROUP("esw_rst", mt7623_esw_rst), + PINCTRL_PIN_GROUP("ext_sdio", mt7623_ext_sdio), + PINCTRL_PIN_GROUP("hdmi_cec", mt7623_hdmi_cec), + PINCTRL_PIN_GROUP("hdmi_htplg", mt7623_hdmi_htplg), + PINCTRL_PIN_GROUP("hdmi_i2c", mt7623_hdmi_i2c), + PINCTRL_PIN_GROUP("hdmi_rx", mt7623_hdmi_rx), + PINCTRL_PIN_GROUP("hdmi_rx_i2c", mt7623_hdmi_rx_i2c), + PINCTRL_PIN_GROUP("i2c0", mt7623_i2c0), + PINCTRL_PIN_GROUP("i2c1_0", mt7623_i2c1_0), + PINCTRL_PIN_GROUP("i2c1_1", mt7623_i2c1_1), + PINCTRL_PIN_GROUP("i2c1_2", mt7623_i2c1_2), + PINCTRL_PIN_GROUP("i2c1_3", mt7623_i2c1_3), + PINCTRL_PIN_GROUP("i2c1_4", mt7623_i2c1_4), + PINCTRL_PIN_GROUP("i2c2_0", mt7623_i2c2_0), + PINCTRL_PIN_GROUP("i2c2_1", mt7623_i2c2_1), + PINCTRL_PIN_GROUP("i2c2_2", mt7623_i2c2_2), + PINCTRL_PIN_GROUP("i2c2_3", mt7623_i2c2_3), + PINCTRL_PIN_GROUP("i2s0", mt7623_i2s0), + PINCTRL_PIN_GROUP("i2s1", mt7623_i2s1), + PINCTRL_PIN_GROUP("i2s4", mt7623_i2s4), + PINCTRL_PIN_GROUP("i2s5", mt7623_i2s5), + PINCTRL_PIN_GROUP("i2s2_bclk_lrclk_mclk", mt7623_i2s2_bclk_lrclk_mclk), + PINCTRL_PIN_GROUP("i2s3_bclk_lrclk_mclk", mt7623_i2s3_bclk_lrclk_mclk), + PINCTRL_PIN_GROUP("i2s2_data_in", mt7623_i2s2_data_in), + PINCTRL_PIN_GROUP("i2s3_data_in", mt7623_i2s3_data_in), + PINCTRL_PIN_GROUP("i2s2_data_0", mt7623_i2s2_data_0), + PINCTRL_PIN_GROUP("i2s2_data_1", mt7623_i2s2_data_1), + PINCTRL_PIN_GROUP("i2s3_data_0", mt7623_i2s3_data_0), + PINCTRL_PIN_GROUP("i2s3_data_1", mt7623_i2s3_data_1), + PINCTRL_PIN_GROUP("ir", mt7623_ir), + PINCTRL_PIN_GROUP("lcm_rst", mt7623_lcm_rst), + PINCTRL_PIN_GROUP("mdc_mdio", mt7623_mdc_mdio), + PINCTRL_PIN_GROUP("mipi_tx", mt7623_mipi_tx), + PINCTRL_PIN_GROUP("msdc0", mt7623_msdc0), + PINCTRL_PIN_GROUP("msdc1", mt7623_msdc1), + PINCTRL_PIN_GROUP("msdc1_ins", mt7623_msdc1_ins), + PINCTRL_PIN_GROUP("msdc1_wp_0", mt7623_msdc1_wp_0), + PINCTRL_PIN_GROUP("msdc1_wp_1", mt7623_msdc1_wp_1), + PINCTRL_PIN_GROUP("msdc1_wp_2", mt7623_msdc1_wp_2), + PINCTRL_PIN_GROUP("msdc2", mt7623_msdc2), + PINCTRL_PIN_GROUP("msdc3", mt7623_msdc3), + PINCTRL_PIN_GROUP("nandc", mt7623_nandc), + PINCTRL_PIN_GROUP("nandc_ceb0", mt7623_nandc_ceb0), + PINCTRL_PIN_GROUP("nandc_ceb1", mt7623_nandc_ceb1), + PINCTRL_PIN_GROUP("otg_iddig0_0", mt7623_otg_iddig0_0), + PINCTRL_PIN_GROUP("otg_iddig0_1", mt7623_otg_iddig0_1), + PINCTRL_PIN_GROUP("otg_iddig0_2", mt7623_otg_iddig0_2), + PINCTRL_PIN_GROUP("otg_iddig1_0", mt7623_otg_iddig1_0), + PINCTRL_PIN_GROUP("otg_iddig1_1", mt7623_otg_iddig1_1), + PINCTRL_PIN_GROUP("otg_iddig1_2", mt7623_otg_iddig1_2), + PINCTRL_PIN_GROUP("otg_drv_vbus0_0", mt7623_otg_drv_vbus0_0), + PINCTRL_PIN_GROUP("otg_drv_vbus0_1", mt7623_otg_drv_vbus0_1), + PINCTRL_PIN_GROUP("otg_drv_vbus0_2", mt7623_otg_drv_vbus0_2), + PINCTRL_PIN_GROUP("otg_drv_vbus1_0", mt7623_otg_drv_vbus1_0), + PINCTRL_PIN_GROUP("otg_drv_vbus1_1", mt7623_otg_drv_vbus1_1), + PINCTRL_PIN_GROUP("otg_drv_vbus1_2", mt7623_otg_drv_vbus1_2), + PINCTRL_PIN_GROUP("pcie0_0_perst", mt7623_pcie0_0_perst), + PINCTRL_PIN_GROUP("pcie0_1_perst", mt7623_pcie0_1_perst), + PINCTRL_PIN_GROUP("pcie1_0_perst", mt7623_pcie1_0_perst), + PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst), + PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst), + PINCTRL_PIN_GROUP("pcie0_0_rev_perst", mt7623_pcie0_0_rev_perst), + PINCTRL_PIN_GROUP("pcie0_1_rev_perst", mt7623_pcie0_1_rev_perst), + PINCTRL_PIN_GROUP("pcie1_0_rev_perst", mt7623_pcie1_0_rev_perst), + PINCTRL_PIN_GROUP("pcie1_1_rev_perst", mt7623_pcie1_1_rev_perst), + PINCTRL_PIN_GROUP("pcie2_0_rev_perst", mt7623_pcie2_0_rev_perst), + PINCTRL_PIN_GROUP("pcie2_1_rev_perst", mt7623_pcie2_1_rev_perst), + PINCTRL_PIN_GROUP("pcie2_0_perst", mt7623_pcie2_0_perst), + PINCTRL_PIN_GROUP("pcie2_1_perst", mt7623_pcie2_1_perst), + PINCTRL_PIN_GROUP("pcie0_0_wake", mt7623_pcie0_0_wake), + PINCTRL_PIN_GROUP("pcie0_1_wake", mt7623_pcie0_1_wake), + PINCTRL_PIN_GROUP("pcie1_0_wake", mt7623_pcie1_0_wake), + PINCTRL_PIN_GROUP("pcie1_1_wake", mt7623_pcie1_1_wake), + PINCTRL_PIN_GROUP("pcie2_0_wake", mt7623_pcie2_0_wake), + PINCTRL_PIN_GROUP("pcie2_1_wake", mt7623_pcie2_1_wake), + PINCTRL_PIN_GROUP("pcie0_clkreq", mt7623_pcie0_clkreq), + PINCTRL_PIN_GROUP("pcie1_clkreq", mt7623_pcie1_clkreq), + PINCTRL_PIN_GROUP("pcie2_clkreq", mt7623_pcie2_clkreq), + PINCTRL_PIN_GROUP("pcm_clk_0", mt7623_pcm_clk_0), + PINCTRL_PIN_GROUP("pcm_clk_1", mt7623_pcm_clk_1), + PINCTRL_PIN_GROUP("pcm_clk_2", mt7623_pcm_clk_2), + PINCTRL_PIN_GROUP("pcm_clk_3", mt7623_pcm_clk_3), + PINCTRL_PIN_GROUP("pcm_clk_4", mt7623_pcm_clk_4), + PINCTRL_PIN_GROUP("pcm_clk_5", mt7623_pcm_clk_5), + PINCTRL_PIN_GROUP("pcm_clk_6", mt7623_pcm_clk_6), + PINCTRL_PIN_GROUP("pcm_sync_0", mt7623_pcm_sync_0), + PINCTRL_PIN_GROUP("pcm_sync_1", mt7623_pcm_sync_1), + PINCTRL_PIN_GROUP("pcm_sync_2", mt7623_pcm_sync_2), + PINCTRL_PIN_GROUP("pcm_sync_3", mt7623_pcm_sync_3), + PINCTRL_PIN_GROUP("pcm_sync_4", mt7623_pcm_sync_4), + PINCTRL_PIN_GROUP("pcm_sync_5", mt7623_pcm_sync_5), + PINCTRL_PIN_GROUP("pcm_sync_6", mt7623_pcm_sync_6), + PINCTRL_PIN_GROUP("pcm_rx_0", mt7623_pcm_rx_0), + PINCTRL_PIN_GROUP("pcm_rx_1", mt7623_pcm_rx_1), + PINCTRL_PIN_GROUP("pcm_rx_2", mt7623_pcm_rx_2), + PINCTRL_PIN_GROUP("pcm_rx_3", mt7623_pcm_rx_3), + PINCTRL_PIN_GROUP("pcm_rx_4", mt7623_pcm_rx_4), + PINCTRL_PIN_GROUP("pcm_rx_5", mt7623_pcm_rx_5), + PINCTRL_PIN_GROUP("pcm_rx_6", mt7623_pcm_rx_6), + PINCTRL_PIN_GROUP("pcm_tx_0", mt7623_pcm_tx_0), + PINCTRL_PIN_GROUP("pcm_tx_1", mt7623_pcm_tx_1), + PINCTRL_PIN_GROUP("pcm_tx_2", mt7623_pcm_tx_2), + PINCTRL_PIN_GROUP("pcm_tx_3", mt7623_pcm_tx_3), + PINCTRL_PIN_GROUP("pcm_tx_4", mt7623_pcm_tx_4), + PINCTRL_PIN_GROUP("pcm_tx_5", mt7623_pcm_tx_5), + PINCTRL_PIN_GROUP("pcm_tx_6", mt7623_pcm_tx_6), + PINCTRL_PIN_GROUP("pwm_ch1_0", mt7623_pwm_ch1_0), + PINCTRL_PIN_GROUP("pwm_ch1_1", mt7623_pwm_ch1_1), + PINCTRL_PIN_GROUP("pwm_ch1_2", mt7623_pwm_ch1_2), + PINCTRL_PIN_GROUP("pwm_ch1_3", mt7623_pwm_ch1_3), + PINCTRL_PIN_GROUP("pwm_ch1_4", mt7623_pwm_ch1_4), + PINCTRL_PIN_GROUP("pwm_ch2_0", mt7623_pwm_ch2_0), + PINCTRL_PIN_GROUP("pwm_ch2_1", mt7623_pwm_ch2_1), + PINCTRL_PIN_GROUP("pwm_ch2_2", mt7623_pwm_ch2_2), + PINCTRL_PIN_GROUP("pwm_ch2_3", mt7623_pwm_ch2_3), + PINCTRL_PIN_GROUP("pwm_ch2_4", mt7623_pwm_ch2_4), + PINCTRL_PIN_GROUP("pwm_ch3_0", mt7623_pwm_ch3_0), + PINCTRL_PIN_GROUP("pwm_ch3_1", mt7623_pwm_ch3_1), + PINCTRL_PIN_GROUP("pwm_ch3_2", mt7623_pwm_ch3_2), + PINCTRL_PIN_GROUP("pwm_ch3_3", mt7623_pwm_ch3_3), + PINCTRL_PIN_GROUP("pwm_ch4_0", mt7623_pwm_ch4_0), + PINCTRL_PIN_GROUP("pwm_ch4_1", mt7623_pwm_ch4_1), + PINCTRL_PIN_GROUP("pwm_ch4_2", mt7623_pwm_ch4_2), + PINCTRL_PIN_GROUP("pwm_ch4_3", mt7623_pwm_ch4_3), + PINCTRL_PIN_GROUP("pwm_ch5_0", mt7623_pwm_ch5_0), + PINCTRL_PIN_GROUP("pwm_ch5_1", mt7623_pwm_ch5_1), + PINCTRL_PIN_GROUP("pwrap", mt7623_pwrap), + PINCTRL_PIN_GROUP("rtc", mt7623_rtc), + PINCTRL_PIN_GROUP("spdif_in0_0", mt7623_spdif_in0_0), + PINCTRL_PIN_GROUP("spdif_in0_1", mt7623_spdif_in0_1), + PINCTRL_PIN_GROUP("spdif_in1_0", mt7623_spdif_in1_0), + PINCTRL_PIN_GROUP("spdif_in1_1", mt7623_spdif_in1_1), + PINCTRL_PIN_GROUP("spdif_out", mt7623_spdif_out), + PINCTRL_PIN_GROUP("spi0", mt7623_spi0), + PINCTRL_PIN_GROUP("spi1", mt7623_spi1), + PINCTRL_PIN_GROUP("spi2", mt7623_spi2), + PINCTRL_PIN_GROUP("uart0_0_txd_rxd", mt7623_uart0_0_txd_rxd), + PINCTRL_PIN_GROUP("uart0_1_txd_rxd", mt7623_uart0_1_txd_rxd), + PINCTRL_PIN_GROUP("uart0_2_txd_rxd", mt7623_uart0_2_txd_rxd), + PINCTRL_PIN_GROUP("uart0_3_txd_rxd", mt7623_uart0_3_txd_rxd), + PINCTRL_PIN_GROUP("uart1_0_txd_rxd", mt7623_uart1_0_txd_rxd), + PINCTRL_PIN_GROUP("uart1_1_txd_rxd", mt7623_uart1_1_txd_rxd), + PINCTRL_PIN_GROUP("uart1_2_txd_rxd", mt7623_uart1_2_txd_rxd), + PINCTRL_PIN_GROUP("uart2_0_txd_rxd", mt7623_uart2_0_txd_rxd), + PINCTRL_PIN_GROUP("uart2_1_txd_rxd", mt7623_uart2_1_txd_rxd), + PINCTRL_PIN_GROUP("uart3_txd_rxd", mt7623_uart3_txd_rxd), + PINCTRL_PIN_GROUP("uart0_rts_cts", mt7623_uart0_rts_cts), + PINCTRL_PIN_GROUP("uart1_rts_cts", mt7623_uart1_rts_cts), + PINCTRL_PIN_GROUP("uart2_rts_cts", mt7623_uart2_rts_cts), + PINCTRL_PIN_GROUP("uart3_rts_cts", mt7623_uart3_rts_cts), + PINCTRL_PIN_GROUP("watchdog_0", mt7623_watchdog_0), + PINCTRL_PIN_GROUP("watchdog_1", mt7623_watchdog_1), +}; + +/* Joint those groups owning the same capability in user point of view which + * allows that people tend to use through the device tree. + */ +static const char *mt7623_aud_clk_groups[] = { "aud_ext_clk0", + "aud_ext_clk1", }; +static const char *mt7623_disp_pwm_groups[] = { "disp_pwm_0", "disp_pwm_1", + "disp_pwm_2", }; +static const char *mt7623_ethernet_groups[] = { "esw_int", "esw_rst", + "ephy", "mdc_mdio", }; +static const char *mt7623_ext_sdio_groups[] = { "ext_sdio", }; +static const char *mt7623_hdmi_groups[] = { "hdmi_cec", "hdmi_htplg", + "hdmi_i2c", "hdmi_rx", + "hdmi_rx_i2c", }; +static const char *mt7623_i2c_groups[] = { "i2c0", "i2c1_0", "i2c1_1", + "i2c1_2", "i2c1_3", "i2c1_4", + "i2c2_0", "i2c2_1", "i2c2_2", + "i2c2_3", }; +static const char *mt7623_i2s_groups[] = { "i2s0", "i2s1", + "i2s2_bclk_lrclk_mclk", + "i2s3_bclk_lrclk_mclk", + "i2s4", "i2s5", + "i2s2_data_in", "i2s3_data_in", + "i2s2_data_0", "i2s2_data_1", + "i2s3_data_0", "i2s3_data_1", }; +static const char *mt7623_ir_groups[] = { "ir", }; +static const char *mt7623_lcd_groups[] = { "dsi_te", "lcm_rst", "mipi_tx", }; +static const char *mt7623_msdc_groups[] = { "msdc0", "msdc1", "msdc1_ins", + "msdc1_wp_0", "msdc1_wp_1", + "msdc1_wp_2", "msdc2", + "msdc3", }; +static const char *mt7623_nandc_groups[] = { "nandc", "nandc_ceb0", + "nandc_ceb1", }; +static const char *mt7623_otg_groups[] = { "otg_iddig0_0", "otg_iddig0_1", + "otg_iddig0_2", "otg_iddig1_0", + "otg_iddig1_1", "otg_iddig1_2", + "otg_drv_vbus0_0", + "otg_drv_vbus0_1", + "otg_drv_vbus0_2", + "otg_drv_vbus1_0", + "otg_drv_vbus1_1", + "otg_drv_vbus1_2", }; +static const char *mt7623_pcie_groups[] = { "pcie0_0_perst", "pcie0_1_perst", + "pcie1_0_perst", "pcie1_1_perst", + "pcie2_0_perst", "pcie2_1_perst", + "pcie0_0_rev_perst", + "pcie0_1_rev_perst", + "pcie1_0_rev_perst", + "pcie1_1_rev_perst", + "pcie2_0_rev_perst", + "pcie2_1_rev_perst", + "pcie0_0_wake", "pcie0_1_wake", + "pcie2_0_wake", "pcie2_1_wake", + "pcie0_clkreq", "pcie1_clkreq", + "pcie2_clkreq", }; +static const char *mt7623_pcm_groups[] = { "pcm_clk_0", "pcm_clk_1", + "pcm_clk_2", "pcm_clk_3", + "pcm_clk_4", "pcm_clk_5", + "pcm_clk_6", "pcm_sync_0", + "pcm_sync_1", "pcm_sync_2", + "pcm_sync_3", "pcm_sync_4", + "pcm_sync_5", "pcm_sync_6", + "pcm_rx_0", "pcm_rx_1", + "pcm_rx_2", "pcm_rx_3", + "pcm_rx_4", "pcm_rx_5", + "pcm_rx_6", "pcm_tx_0", + "pcm_tx_1", "pcm_tx_2", + "pcm_tx_3", "pcm_tx_4", + "pcm_tx_5", "pcm_tx_6", }; +static const char *mt7623_pwm_groups[] = { "pwm_ch1_0", "pwm_ch1_1", + "pwm_ch1_2", "pwm_ch2_0", + "pwm_ch2_1", "pwm_ch2_2", + "pwm_ch3_0", "pwm_ch3_1", + "pwm_ch3_2", "pwm_ch4_0", + "pwm_ch4_1", "pwm_ch4_2", + "pwm_ch4_3", "pwm_ch5_0", + "pwm_ch5_1", "pwm_ch5_2", + "pwm_ch6_0", "pwm_ch6_1", + "pwm_ch6_2", "pwm_ch6_3", + "pwm_ch7_0", "pwm_ch7_1", + "pwm_ch7_2", }; +static const char *mt7623_pwrap_groups[] = { "pwrap", }; +static const char *mt7623_rtc_groups[] = { "rtc", }; +static const char *mt7623_spi_groups[] = { "spi0", "spi2", "spi2", }; +static const char *mt7623_spdif_groups[] = { "spdif_in0_0", "spdif_in0_1", + "spdif_in1_0", "spdif_in1_1", + "spdif_out", }; +static const char *mt7623_uart_groups[] = { "uart0_0_txd_rxd", + "uart0_1_txd_rxd", + "uart0_2_txd_rxd", + "uart0_3_txd_rxd", + "uart1_0_txd_rxd", + "uart1_1_txd_rxd", + "uart1_2_txd_rxd", + "uart2_0_txd_rxd", + "uart2_1_txd_rxd", + "uart3_txd_rxd", + "uart0_rts_cts", + "uart1_rts_cts", + "uart2_rts_cts", + "uart3_rts_cts", }; +static const char *mt7623_wdt_groups[] = { "watchdog_0", "watchdog_1", }; + +static const struct function_desc mt7623_functions[] = { + {"audck", mt7623_aud_clk_groups, ARRAY_SIZE(mt7623_aud_clk_groups)}, + {"disp", mt7623_disp_pwm_groups, ARRAY_SIZE(mt7623_disp_pwm_groups)}, + {"eth", mt7623_ethernet_groups, ARRAY_SIZE(mt7623_ethernet_groups)}, + {"sdio", mt7623_ext_sdio_groups, ARRAY_SIZE(mt7623_ext_sdio_groups)}, + {"hdmi", mt7623_hdmi_groups, ARRAY_SIZE(mt7623_hdmi_groups)}, + {"i2c", mt7623_i2c_groups, ARRAY_SIZE(mt7623_i2c_groups)}, + {"i2s", mt7623_i2s_groups, ARRAY_SIZE(mt7623_i2s_groups)}, + {"ir", mt7623_ir_groups, ARRAY_SIZE(mt7623_ir_groups)}, + {"lcd", mt7623_lcd_groups, ARRAY_SIZE(mt7623_lcd_groups)}, + {"msdc", mt7623_msdc_groups, ARRAY_SIZE(mt7623_msdc_groups)}, + {"nand", mt7623_nandc_groups, ARRAY_SIZE(mt7623_nandc_groups)}, + {"otg", mt7623_otg_groups, ARRAY_SIZE(mt7623_otg_groups)}, + {"pcie", mt7623_pcie_groups, ARRAY_SIZE(mt7623_pcie_groups)}, + {"pcm", mt7623_pcm_groups, ARRAY_SIZE(mt7623_pcm_groups)}, + {"pwm", mt7623_pwm_groups, ARRAY_SIZE(mt7623_pwm_groups)}, + {"pwrap", mt7623_pwrap_groups, ARRAY_SIZE(mt7623_pwrap_groups)}, + {"rtc", mt7623_rtc_groups, ARRAY_SIZE(mt7623_rtc_groups)}, + {"spi", mt7623_spi_groups, ARRAY_SIZE(mt7623_spi_groups)}, + {"spdif", mt7623_spdif_groups, ARRAY_SIZE(mt7623_spdif_groups)}, + {"uart", mt7623_uart_groups, ARRAY_SIZE(mt7623_uart_groups)}, + {"watchdog", mt7623_wdt_groups, ARRAY_SIZE(mt7623_wdt_groups)}, +}; + +static const struct mtk_eint_hw mt7623_eint_hw = { + .port_mask = 6, + .ports = 6, + .ap_num = 169, + .db_cnt = 20, +}; + +static struct mtk_pin_soc mt7623_data = { + .reg_cal = mt7623_reg_cals, + .pins = mt7623_pins, + .npins = ARRAY_SIZE(mt7623_pins), + .grps = mt7623_groups, + .ngrps = ARRAY_SIZE(mt7623_groups), + .funcs = mt7623_functions, + .nfuncs = ARRAY_SIZE(mt7623_functions), + .eint_hw = &mt7623_eint_hw, + .gpio_m = 0, + .ies_present = true, + .base_names = mtk_default_register_base_names, + .nbase_names = ARRAY_SIZE(mtk_default_register_base_names), + .bias_disable_set = mtk_pinconf_bias_disable_set_rev1, + .bias_disable_get = mtk_pinconf_bias_disable_get_rev1, + .bias_set = mtk_pinconf_bias_set_rev1, + .bias_get = mtk_pinconf_bias_get_rev1, + .drive_set = mtk_pinconf_drive_set_rev1, + .drive_get = mtk_pinconf_drive_get_rev1, + .adv_pull_get = mtk_pinconf_adv_pull_get, + .adv_pull_set = mtk_pinconf_adv_pull_set, +}; + +/* + * There are some specific pins have mux functions greater than 8, + * and if we want to switch thees high modes we need to disable + * bonding constraints firstly. + */ +static void mt7623_bonding_disable(struct platform_device *pdev) +{ + struct mtk_pinctrl *hw = platform_get_drvdata(pdev); + + mtk_rmw(hw, 0, PIN_BOND_REG0, BOND_PCIE_CLR, BOND_PCIE_CLR); + mtk_rmw(hw, 0, PIN_BOND_REG1, BOND_I2S_CLR, BOND_I2S_CLR); + mtk_rmw(hw, 0, PIN_BOND_REG2, BOND_MSDC0E_CLR, BOND_MSDC0E_CLR); +} + +static const struct of_device_id mt7623_pctrl_match[] = { + { .compatible = "mediatek,mt7623-moore-pinctrl", }, + {} +}; + +static int mt7623_pinctrl_probe(struct platform_device *pdev) +{ + int err; + + err = mtk_moore_pinctrl_probe(pdev, &mt7623_data); + if (err) + return err; + + mt7623_bonding_disable(pdev); + + return 0; +} + +static struct platform_driver mtk_pinctrl_driver = { + .probe = mt7623_pinctrl_probe, + .driver = { + .name = "mt7623-moore-pinctrl", + .of_match_table = mt7623_pctrl_match, + }, +}; + +static int __init mtk_pinctrl_init(void) +{ + return platform_driver_register(&mtk_pinctrl_driver); +} +arch_initcall(mtk_pinctrl_init); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8183.c b/drivers/pinctrl/mediatek/pinctrl-mt8183.c new file mode 100644 index 000000000000..6262fd3678ea --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt8183.c @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Zhiyong Tao <zhiyong.tao@mediatek.com> + * + */ + +#include "pinctrl-mtk-mt8183.h" +#include "pinctrl-paris.h" + +/* MT8183 have multiple bases to program pin configuration listed as the below: + * iocfg[0]:0x10005000, iocfg[1]:0x11F20000, iocfg[2]:0x11E80000, + * iocfg[3]:0x11E70000, iocfg[4]:0x11E90000, iocfg[5]:0x11D30000, + * iocfg[6]:0x11D20000, iocfg[7]:0x11C50000, iocfg[8]:0x11F30000. + * _i_based could be used to indicate what base the pin should be mapped into. + */ + +#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 0) + +#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 1) + +static const struct mtk_pin_field_calc mt8183_pin_mode_range[] = { + PIN_FIELD(0, 192, 0x300, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt8183_pin_dir_range[] = { + PIN_FIELD(0, 192, 0x0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_di_range[] = { + PIN_FIELD(0, 192, 0x200, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_do_range[] = { + PIN_FIELD(0, 192, 0x100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_ies_range[] = { + PINS_FIELD_BASE(0, 3, 6, 0x000, 0x10, 3, 1), + PINS_FIELD_BASE(4, 7, 6, 0x000, 0x10, 5, 1), + PIN_FIELD_BASE(8, 8, 6, 0x000, 0x10, 0, 1), + PINS_FIELD_BASE(9, 10, 6, 0x000, 0x10, 12, 1), + PIN_FIELD_BASE(11, 11, 1, 0x000, 0x10, 3, 1), + PIN_FIELD_BASE(12, 12, 1, 0x000, 0x10, 7, 1), + PINS_FIELD_BASE(13, 16, 2, 0x000, 0x10, 2, 1), + PINS_FIELD_BASE(17, 20, 2, 0x000, 0x10, 3, 1), + PINS_FIELD_BASE(21, 24, 2, 0x000, 0x10, 4, 1), + PINS_FIELD_BASE(25, 28, 2, 0x000, 0x10, 5, 1), + PIN_FIELD_BASE(29, 29, 2, 0x000, 0x10, 6, 1), + PIN_FIELD_BASE(30, 30, 2, 0x000, 0x10, 7, 1), + PINS_FIELD_BASE(31, 31, 2, 0x000, 0x10, 8, 1), + PINS_FIELD_BASE(32, 34, 2, 0x000, 0x10, 7, 1), + PINS_FIELD_BASE(35, 37, 3, 0x000, 0x10, 0, 1), + PINS_FIELD_BASE(38, 40, 3, 0x000, 0x10, 1, 1), + PINS_FIELD_BASE(41, 42, 3, 0x000, 0x10, 2, 1), + PINS_FIELD_BASE(43, 45, 3, 0x000, 0x10, 3, 1), + PINS_FIELD_BASE(46, 47, 3, 0x000, 0x10, 4, 1), + PINS_FIELD_BASE(48, 49, 3, 0x000, 0x10, 5, 1), + PINS_FIELD_BASE(50, 51, 4, 0x000, 0x10, 0, 1), + PINS_FIELD_BASE(52, 57, 4, 0x000, 0x10, 1, 1), + PINS_FIELD_BASE(58, 60, 4, 0x000, 0x10, 2, 1), + PINS_FIELD_BASE(61, 64, 5, 0x000, 0x10, 0, 1), + PINS_FIELD_BASE(65, 66, 5, 0x000, 0x10, 1, 1), + PINS_FIELD_BASE(67, 68, 5, 0x000, 0x10, 2, 1), + PINS_FIELD_BASE(69, 71, 5, 0x000, 0x10, 3, 1), + PINS_FIELD_BASE(72, 76, 5, 0x000, 0x10, 4, 1), + PINS_FIELD_BASE(77, 80, 5, 0x000, 0x10, 5, 1), + PIN_FIELD_BASE(81, 81, 5, 0x000, 0x10, 6, 1), + PINS_FIELD_BASE(82, 83, 5, 0x000, 0x10, 7, 1), + PIN_FIELD_BASE(84, 84, 5, 0x000, 0x10, 6, 1), + PINS_FIELD_BASE(85, 88, 5, 0x000, 0x10, 8, 1), + PIN_FIELD_BASE(89, 89, 6, 0x000, 0x10, 11, 1), + PIN_FIELD_BASE(90, 90, 6, 0x000, 0x10, 1, 1), + PINS_FIELD_BASE(91, 94, 6, 0x000, 0x10, 2, 1), + PINS_FIELD_BASE(95, 96, 6, 0x000, 0x10, 6, 1), + PINS_FIELD_BASE(97, 98, 6, 0x000, 0x10, 7, 1), + PIN_FIELD_BASE(99, 99, 6, 0x000, 0x10, 8, 1), + PIN_FIELD_BASE(100, 100, 6, 0x000, 0x10, 9, 1), + PINS_FIELD_BASE(101, 102, 6, 0x000, 0x10, 10, 1), + PINS_FIELD_BASE(103, 104, 6, 0x000, 0x10, 13, 1), + PINS_FIELD_BASE(105, 106, 6, 0x000, 0x10, 14, 1), + PIN_FIELD_BASE(107, 107, 7, 0x000, 0x10, 0, 1), + PIN_FIELD_BASE(108, 108, 7, 0x000, 0x10, 1, 1), + PIN_FIELD_BASE(109, 109, 7, 0x000, 0x10, 2, 1), + PIN_FIELD_BASE(110, 110, 7, 0x000, 0x10, 0, 1), + PIN_FIELD_BASE(111, 111, 7, 0x000, 0x10, 3, 1), + PIN_FIELD_BASE(112, 112, 7, 0x000, 0x10, 2, 1), + PIN_FIELD_BASE(113, 113, 7, 0x000, 0x10, 4, 1), + PIN_FIELD_BASE(114, 114, 7, 0x000, 0x10, 5, 1), + PIN_FIELD_BASE(115, 115, 7, 0x000, 0x10, 6, 1), + PIN_FIELD_BASE(116, 116, 7, 0x000, 0x10, 7, 1), + PIN_FIELD_BASE(117, 117, 7, 0x000, 0x10, 8, 1), + PIN_FIELD_BASE(118, 118, 7, 0x000, 0x10, 9, 1), + PIN_FIELD_BASE(119, 119, 7, 0x000, 0x10, 10, 1), + PIN_FIELD_BASE(120, 120, 7, 0x000, 0x10, 11, 1), + PIN_FIELD_BASE(121, 121, 7, 0x000, 0x10, 12, 1), + PIN_FIELD_BASE(122, 122, 8, 0x000, 0x10, 0, 1), + PIN_FIELD_BASE(123, 123, 8, 0x000, 0x10, 1, 1), + PIN_FIELD_BASE(124, 124, 8, 0x000, 0x10, 2, 1), + PINS_FIELD_BASE(125, 130, 8, 0x000, 0x10, 1, 1), + PIN_FIELD_BASE(131, 131, 8, 0x000, 0x10, 3, 1), + PIN_FIELD_BASE(132, 132, 8, 0x000, 0x10, 1, 1), + PIN_FIELD_BASE(133, 133, 8, 0x000, 0x10, 4, 1), + PIN_FIELD_BASE(134, 134, 1, 0x000, 0x10, 0, 1), + PIN_FIELD_BASE(135, 135, 1, 0x000, 0x10, 1, 1), + PINS_FIELD_BASE(136, 143, 1, 0x000, 0x10, 2, 1), + PINS_FIELD_BASE(144, 147, 1, 0x000, 0x10, 4, 1), + PIN_FIELD_BASE(148, 148, 1, 0x000, 0x10, 5, 1), + PIN_FIELD_BASE(149, 149, 1, 0x000, 0x10, 6, 1), + PINS_FIELD_BASE(150, 153, 1, 0x000, 0x10, 8, 1), + PIN_FIELD_BASE(154, 154, 1, 0x000, 0x10, 9, 1), + PINS_FIELD_BASE(155, 157, 1, 0x000, 0x10, 10, 1), + PINS_FIELD_BASE(158, 160, 1, 0x000, 0x10, 8, 1), + PINS_FIELD_BASE(161, 164, 2, 0x000, 0x10, 0, 1), + PINS_FIELD_BASE(165, 166, 2, 0x000, 0x10, 1, 1), + PINS_FIELD_BASE(167, 168, 4, 0x000, 0x10, 2, 1), + PIN_FIELD_BASE(169, 169, 4, 0x000, 0x10, 3, 1), + PINS_FIELD_BASE(170, 174, 4, 0x000, 0x10, 4, 1), + PINS_FIELD_BASE(175, 176, 4, 0x000, 0x10, 3, 1), + PINS_FIELD_BASE(177, 179, 6, 0x000, 0x10, 4, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_smt_range[] = { + PINS_FIELD_BASE(0, 3, 6, 0x010, 0x10, 3, 1), + PINS_FIELD_BASE(4, 7, 6, 0x010, 0x10, 5, 1), + PIN_FIELD_BASE(8, 8, 6, 0x010, 0x10, 0, 1), + PINS_FIELD_BASE(9, 10, 6, 0x010, 0x10, 12, 1), + PIN_FIELD_BASE(11, 11, 1, 0x010, 0x10, 3, 1), + PIN_FIELD_BASE(12, 12, 1, 0x010, 0x10, 7, 1), + PINS_FIELD_BASE(13, 16, 2, 0x010, 0x10, 2, 1), + PINS_FIELD_BASE(17, 20, 2, 0x010, 0x10, 3, 1), + PINS_FIELD_BASE(21, 24, 2, 0x010, 0x10, 4, 1), + PINS_FIELD_BASE(25, 28, 2, 0x010, 0x10, 5, 1), + PIN_FIELD_BASE(29, 29, 2, 0x010, 0x10, 6, 1), + PIN_FIELD_BASE(30, 30, 2, 0x010, 0x10, 7, 1), + PINS_FIELD_BASE(31, 31, 2, 0x010, 0x10, 8, 1), + PINS_FIELD_BASE(32, 34, 2, 0x010, 0x10, 7, 1), + PINS_FIELD_BASE(35, 37, 3, 0x010, 0x10, 0, 1), + PINS_FIELD_BASE(38, 40, 3, 0x010, 0x10, 1, 1), + PINS_FIELD_BASE(41, 42, 3, 0x010, 0x10, 2, 1), + PINS_FIELD_BASE(43, 45, 3, 0x010, 0x10, 3, 1), + PINS_FIELD_BASE(46, 47, 3, 0x010, 0x10, 4, 1), + PINS_FIELD_BASE(48, 49, 3, 0x010, 0x10, 5, 1), + PINS_FIELD_BASE(50, 51, 4, 0x010, 0x10, 0, 1), + PINS_FIELD_BASE(52, 57, 4, 0x010, 0x10, 1, 1), + PINS_FIELD_BASE(58, 60, 4, 0x010, 0x10, 2, 1), + PINS_FIELD_BASE(61, 64, 5, 0x010, 0x10, 0, 1), + PINS_FIELD_BASE(65, 66, 5, 0x010, 0x10, 1, 1), + PINS_FIELD_BASE(67, 68, 5, 0x010, 0x10, 2, 1), + PINS_FIELD_BASE(69, 71, 5, 0x010, 0x10, 3, 1), + PINS_FIELD_BASE(72, 76, 5, 0x010, 0x10, 4, 1), + PINS_FIELD_BASE(77, 80, 5, 0x010, 0x10, 5, 1), + PIN_FIELD_BASE(81, 81, 5, 0x010, 0x10, 6, 1), + PINS_FIELD_BASE(82, 83, 5, 0x010, 0x10, 7, 1), + PIN_FIELD_BASE(84, 84, 5, 0x010, 0x10, 6, 1), + PINS_FIELD_BASE(85, 88, 5, 0x010, 0x10, 8, 1), + PIN_FIELD_BASE(89, 89, 6, 0x010, 0x10, 11, 1), + PIN_FIELD_BASE(90, 90, 6, 0x010, 0x10, 1, 1), + PINS_FIELD_BASE(91, 94, 6, 0x010, 0x10, 2, 1), + PINS_FIELD_BASE(95, 96, 6, 0x010, 0x10, 6, 1), + PINS_FIELD_BASE(97, 98, 6, 0x010, 0x10, 7, 1), + PIN_FIELD_BASE(99, 99, 6, 0x010, 0x10, 8, 1), + PIN_FIELD_BASE(100, 100, 6, 0x010, 0x10, 9, 1), + PINS_FIELD_BASE(101, 102, 6, 0x010, 0x10, 10, 1), + PINS_FIELD_BASE(103, 104, 6, 0x010, 0x10, 13, 1), + PINS_FIELD_BASE(105, 106, 6, 0x010, 0x10, 14, 1), + PIN_FIELD_BASE(107, 107, 7, 0x010, 0x10, 0, 1), + PIN_FIELD_BASE(108, 108, 7, 0x010, 0x10, 1, 1), + PIN_FIELD_BASE(109, 109, 7, 0x010, 0x10, 2, 1), + PIN_FIELD_BASE(110, 110, 7, 0x010, 0x10, 0, 1), + PIN_FIELD_BASE(111, 111, 7, 0x010, 0x10, 3, 1), + PIN_FIELD_BASE(112, 112, 7, 0x010, 0x10, 2, 1), + PIN_FIELD_BASE(113, 113, 7, 0x010, 0x10, 4, 1), + PIN_FIELD_BASE(114, 114, 7, 0x010, 0x10, 5, 1), + PIN_FIELD_BASE(115, 115, 7, 0x010, 0x10, 6, 1), + PIN_FIELD_BASE(116, 116, 7, 0x010, 0x10, 7, 1), + PIN_FIELD_BASE(117, 117, 7, 0x010, 0x10, 8, 1), + PIN_FIELD_BASE(118, 118, 7, 0x010, 0x10, 9, 1), + PIN_FIELD_BASE(119, 119, 7, 0x010, 0x10, 10, 1), + PIN_FIELD_BASE(120, 120, 7, 0x010, 0x10, 11, 1), + PIN_FIELD_BASE(121, 121, 7, 0x010, 0x10, 12, 1), + PIN_FIELD_BASE(122, 122, 8, 0x010, 0x10, 0, 1), + PIN_FIELD_BASE(123, 123, 8, 0x010, 0x10, 1, 1), + PIN_FIELD_BASE(124, 124, 8, 0x010, 0x10, 2, 1), + PINS_FIELD_BASE(125, 130, 8, 0x010, 0x10, 1, 1), + PIN_FIELD_BASE(131, 131, 8, 0x010, 0x10, 3, 1), + PIN_FIELD_BASE(132, 132, 8, 0x010, 0x10, 1, 1), + PIN_FIELD_BASE(133, 133, 8, 0x010, 0x10, 4, 1), + PIN_FIELD_BASE(134, 134, 1, 0x010, 0x10, 0, 1), + PIN_FIELD_BASE(135, 135, 1, 0x010, 0x10, 1, 1), + PINS_FIELD_BASE(136, 143, 1, 0x010, 0x10, 2, 1), + PINS_FIELD_BASE(144, 147, 1, 0x010, 0x10, 4, 1), + PIN_FIELD_BASE(148, 148, 1, 0x010, 0x10, 5, 1), + PIN_FIELD_BASE(149, 149, 1, 0x010, 0x10, 6, 1), + PINS_FIELD_BASE(150, 153, 1, 0x010, 0x10, 8, 1), + PIN_FIELD_BASE(154, 154, 1, 0x010, 0x10, 9, 1), + PINS_FIELD_BASE(155, 157, 1, 0x010, 0x10, 10, 1), + PINS_FIELD_BASE(158, 160, 1, 0x010, 0x10, 8, 1), + PINS_FIELD_BASE(161, 164, 2, 0x010, 0x10, 0, 1), + PINS_FIELD_BASE(165, 166, 2, 0x010, 0x10, 1, 1), + PINS_FIELD_BASE(167, 168, 4, 0x010, 0x10, 2, 1), + PIN_FIELD_BASE(169, 169, 4, 0x010, 0x10, 3, 1), + PINS_FIELD_BASE(170, 174, 4, 0x010, 0x10, 4, 1), + PINS_FIELD_BASE(175, 176, 4, 0x010, 0x10, 3, 1), + PINS_FIELD_BASE(177, 179, 6, 0x010, 0x10, 4, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_pullen_range[] = { + PIN_FIELD_BASE(0, 3, 6, 0x060, 0x10, 6, 1), + PIN_FIELD_BASE(4, 7, 6, 0x060, 0x10, 11, 1), + PIN_FIELD_BASE(8, 8, 6, 0x060, 0x10, 0, 1), + PIN_FIELD_BASE(9, 10, 6, 0x060, 0x10, 26, 1), + PIN_FIELD_BASE(11, 11, 1, 0x060, 0x10, 10, 1), + PIN_FIELD_BASE(12, 12, 1, 0x060, 0x10, 17, 1), + PIN_FIELD_BASE(13, 28, 2, 0x060, 0x10, 6, 1), + PIN_FIELD_BASE(43, 49, 3, 0x060, 0x10, 8, 1), + PIN_FIELD_BASE(50, 60, 4, 0x060, 0x10, 0, 1), + PIN_FIELD_BASE(61, 88, 5, 0x060, 0x10, 0, 1), + PIN_FIELD_BASE(89, 89, 6, 0x060, 0x10, 24, 1), + PIN_FIELD_BASE(90, 90, 6, 0x060, 0x10, 1, 1), + PIN_FIELD_BASE(95, 95, 6, 0x060, 0x10, 15, 1), + PIN_FIELD_BASE(96, 102, 6, 0x060, 0x10, 17, 1), + PIN_FIELD_BASE(103, 106, 6, 0x060, 0x10, 28, 1), + PIN_FIELD_BASE(107, 121, 7, 0x060, 0x10, 0, 1), + PIN_FIELD_BASE(134, 143, 1, 0x060, 0x10, 0, 1), + PIN_FIELD_BASE(144, 149, 1, 0x060, 0x10, 11, 1), + PIN_FIELD_BASE(150, 160, 1, 0x060, 0x10, 18, 1), + PIN_FIELD_BASE(161, 166, 2, 0x060, 0x10, 0, 1), + PIN_FIELD_BASE(167, 176, 4, 0x060, 0x10, 11, 1), + PIN_FIELD_BASE(177, 177, 6, 0x060, 0x10, 10, 1), + PIN_FIELD_BASE(178, 178, 6, 0x060, 0x10, 16, 1), + PIN_FIELD_BASE(179, 179, 6, 0x060, 0x10, 25, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_pullsel_range[] = { + PIN_FIELD_BASE(0, 3, 6, 0x080, 0x10, 6, 1), + PIN_FIELD_BASE(4, 7, 6, 0x080, 0x10, 11, 1), + PIN_FIELD_BASE(8, 8, 6, 0x080, 0x10, 0, 1), + PIN_FIELD_BASE(9, 10, 6, 0x080, 0x10, 26, 1), + PIN_FIELD_BASE(11, 11, 1, 0x080, 0x10, 10, 1), + PIN_FIELD_BASE(12, 12, 1, 0x080, 0x10, 17, 1), + PIN_FIELD_BASE(13, 28, 2, 0x080, 0x10, 6, 1), + PIN_FIELD_BASE(43, 49, 3, 0x080, 0x10, 8, 1), + PIN_FIELD_BASE(50, 60, 4, 0x080, 0x10, 0, 1), + PIN_FIELD_BASE(61, 88, 5, 0x080, 0x10, 0, 1), + PIN_FIELD_BASE(89, 89, 6, 0x080, 0x10, 24, 1), + PIN_FIELD_BASE(90, 90, 6, 0x080, 0x10, 1, 1), + PIN_FIELD_BASE(95, 95, 6, 0x080, 0x10, 15, 1), + PIN_FIELD_BASE(96, 102, 6, 0x080, 0x10, 17, 1), + PIN_FIELD_BASE(103, 106, 6, 0x080, 0x10, 28, 1), + PIN_FIELD_BASE(107, 121, 7, 0x080, 0x10, 0, 1), + PIN_FIELD_BASE(134, 143, 1, 0x080, 0x10, 0, 1), + PIN_FIELD_BASE(144, 149, 1, 0x080, 0x10, 11, 1), + PIN_FIELD_BASE(150, 160, 1, 0x080, 0x10, 18, 1), + PIN_FIELD_BASE(161, 166, 2, 0x080, 0x10, 0, 1), + PIN_FIELD_BASE(167, 176, 4, 0x080, 0x10, 11, 1), + PIN_FIELD_BASE(177, 177, 6, 0x080, 0x10, 10, 1), + PIN_FIELD_BASE(178, 178, 6, 0x080, 0x10, 16, 1), + PIN_FIELD_BASE(179, 179, 6, 0x080, 0x10, 25, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_drv_range[] = { + PINS_FIELD_BASE(0, 3, 6, 0x0A0, 0x10, 12, 3), + PINS_FIELD_BASE(4, 7, 6, 0x0A0, 0x10, 20, 3), + PIN_FIELD_BASE(8, 8, 6, 0x0A0, 0x10, 0, 3), + PINS_FIELD_BASE(9, 10, 6, 0x0B0, 0x10, 16, 3), + PIN_FIELD_BASE(11, 11, 1, 0x0A0, 0x10, 12, 3), + PIN_FIELD_BASE(12, 12, 1, 0x0A0, 0x10, 28, 3), + PINS_FIELD_BASE(13, 16, 2, 0x0A0, 0x10, 8, 3), + PINS_FIELD_BASE(17, 20, 2, 0x0A0, 0x10, 12, 3), + PINS_FIELD_BASE(21, 24, 2, 0x0A0, 0x10, 16, 3), + PINS_FIELD_BASE(25, 28, 2, 0x0A0, 0x10, 20, 3), + PIN_FIELD_BASE(29, 29, 2, 0x0A0, 0x10, 24, 3), + PIN_FIELD_BASE(30, 30, 2, 0x0A0, 0x10, 28, 3), + PINS_FIELD_BASE(31, 31, 2, 0x0B0, 0x10, 0, 3), + PINS_FIELD_BASE(32, 34, 2, 0x0A0, 0x10, 28, 3), + PINS_FIELD_BASE(35, 37, 3, 0x0A0, 0x10, 0, 3), + PINS_FIELD_BASE(38, 40, 3, 0x0A0, 0x10, 4, 3), + PINS_FIELD_BASE(41, 42, 3, 0x0A0, 0x10, 8, 3), + PINS_FIELD_BASE(43, 45, 3, 0x0A0, 0x10, 12, 3), + PINS_FIELD_BASE(46, 47, 3, 0x0A0, 0x10, 16, 3), + PINS_FIELD_BASE(48, 49, 3, 0x0A0, 0x10, 20, 3), + PINS_FIELD_BASE(50, 51, 4, 0x0A0, 0x10, 0, 3), + PINS_FIELD_BASE(52, 57, 4, 0x0A0, 0x10, 4, 3), + PINS_FIELD_BASE(58, 60, 4, 0x0A0, 0x10, 8, 3), + PINS_FIELD_BASE(61, 64, 5, 0x0A0, 0x10, 0, 3), + PINS_FIELD_BASE(65, 66, 5, 0x0A0, 0x10, 4, 3), + PINS_FIELD_BASE(67, 68, 5, 0x0A0, 0x10, 8, 3), + PINS_FIELD_BASE(69, 71, 5, 0x0A0, 0x10, 12, 3), + PINS_FIELD_BASE(72, 76, 5, 0x0A0, 0x10, 16, 3), + PINS_FIELD_BASE(77, 80, 5, 0x0A0, 0x10, 20, 3), + PIN_FIELD_BASE(81, 81, 5, 0x0A0, 0x10, 24, 3), + PINS_FIELD_BASE(82, 83, 5, 0x0A0, 0x10, 28, 3), + PIN_FIELD_BASE(84, 84, 5, 0x0A0, 0x10, 24, 3), + PINS_FIELD_BASE(85, 88, 5, 0x0B0, 0x10, 0, 3), + PIN_FIELD_BASE(89, 89, 6, 0x0B0, 0x10, 12, 3), + PIN_FIELD_BASE(90, 90, 6, 0x0A0, 0x10, 4, 3), + PINS_FIELD_BASE(91, 94, 6, 0x0A0, 0x10, 8, 3), + PINS_FIELD_BASE(95, 96, 6, 0x0A0, 0x10, 24, 3), + PINS_FIELD_BASE(97, 98, 6, 0x0A0, 0x10, 28, 3), + PIN_FIELD_BASE(99, 99, 6, 0x0B0, 0x10, 0, 3), + PIN_FIELD_BASE(100, 100, 6, 0x0B0, 0x10, 4, 3), + PINS_FIELD_BASE(101, 102, 6, 0x0B0, 0x10, 8, 3), + PINS_FIELD_BASE(103, 104, 6, 0x0B0, 0x10, 20, 3), + PINS_FIELD_BASE(105, 106, 6, 0x0B0, 0x10, 24, 3), + PIN_FIELD_BASE(107, 107, 7, 0x0A0, 0x10, 0, 3), + PIN_FIELD_BASE(108, 108, 7, 0x0A0, 0x10, 4, 3), + PIN_FIELD_BASE(109, 109, 7, 0x0A0, 0x10, 8, 3), + PIN_FIELD_BASE(110, 110, 7, 0x0A0, 0x10, 0, 3), + PIN_FIELD_BASE(111, 111, 7, 0x0A0, 0x10, 4, 3), + PIN_FIELD_BASE(112, 112, 7, 0x0A0, 0x10, 8, 3), + PIN_FIELD_BASE(113, 113, 7, 0x0A0, 0x10, 16, 3), + PIN_FIELD_BASE(114, 114, 7, 0x0A0, 0x10, 20, 3), + PIN_FIELD_BASE(115, 115, 7, 0x0A0, 0x10, 24, 3), + PIN_FIELD_BASE(116, 116, 7, 0x0A0, 0x10, 28, 3), + PIN_FIELD_BASE(117, 117, 7, 0x0B0, 0x10, 0, 3), + PIN_FIELD_BASE(118, 118, 7, 0x0B0, 0x10, 4, 3), + PIN_FIELD_BASE(119, 119, 7, 0x0B0, 0x10, 8, 3), + PIN_FIELD_BASE(120, 120, 7, 0x0B0, 0x10, 12, 3), + PIN_FIELD_BASE(121, 121, 7, 0x0B0, 0x10, 16, 3), + PIN_FIELD_BASE(122, 122, 8, 0x0A0, 0x10, 0, 3), + PIN_FIELD_BASE(123, 123, 8, 0x0A0, 0x10, 4, 3), + PIN_FIELD_BASE(124, 124, 8, 0x0A0, 0x10, 8, 3), + PINS_FIELD_BASE(125, 130, 8, 0x0A0, 0x10, 4, 3), + PIN_FIELD_BASE(131, 131, 8, 0x0A0, 0x10, 12, 3), + PIN_FIELD_BASE(132, 132, 8, 0x0A0, 0x10, 4, 3), + PIN_FIELD_BASE(133, 133, 8, 0x0A0, 0x10, 16, 3), + PIN_FIELD_BASE(134, 134, 1, 0x0A0, 0x10, 0, 3), + PIN_FIELD_BASE(135, 135, 1, 0x0A0, 0x10, 4, 3), + PINS_FIELD_BASE(136, 143, 1, 0x0A0, 0x10, 8, 3), + PINS_FIELD_BASE(144, 147, 1, 0x0A0, 0x10, 16, 3), + PIN_FIELD_BASE(148, 148, 1, 0x0A0, 0x10, 20, 3), + PIN_FIELD_BASE(149, 149, 1, 0x0A0, 0x10, 24, 3), + PINS_FIELD_BASE(150, 153, 1, 0x0B0, 0x10, 0, 3), + PIN_FIELD_BASE(154, 154, 1, 0x0B0, 0x10, 4, 3), + PINS_FIELD_BASE(155, 157, 1, 0x0B0, 0x10, 8, 3), + PINS_FIELD_BASE(158, 160, 1, 0x0B0, 0x10, 0, 3), + PINS_FIELD_BASE(161, 164, 2, 0x0A0, 0x10, 0, 3), + PINS_FIELD_BASE(165, 166, 2, 0x0A0, 0x10, 4, 3), + PINS_FIELD_BASE(167, 168, 4, 0x0A0, 0x10, 8, 3), + PIN_FIELD_BASE(169, 169, 4, 0x0A0, 0x10, 12, 3), + PINS_FIELD_BASE(170, 174, 4, 0x0A0, 0x10, 16, 3), + PINS_FIELD_BASE(175, 176, 4, 0x0A0, 0x10, 12, 3), + PINS_FIELD_BASE(177, 179, 6, 0x0A0, 0x10, 16, 3), +}; + +static const struct mtk_pin_field_calc mt8183_pin_pupd_range[] = { + PIN_FIELD_BASE(29, 29, 2, 0x0C0, 0x10, 2, 1), + PIN_FIELD_BASE(30, 30, 2, 0x0C0, 0x10, 6, 1), + PIN_FIELD_BASE(31, 31, 2, 0x0C0, 0x10, 10, 1), + PIN_FIELD_BASE(32, 32, 2, 0x0C0, 0x10, 14, 1), + PIN_FIELD_BASE(33, 33, 2, 0x0C0, 0x10, 18, 1), + PIN_FIELD_BASE(34, 34, 2, 0x0C0, 0x10, 22, 1), + PIN_FIELD_BASE(35, 35, 3, 0x0C0, 0x10, 2, 1), + PIN_FIELD_BASE(36, 36, 3, 0x0C0, 0x10, 6, 1), + PIN_FIELD_BASE(37, 37, 3, 0x0C0, 0x10, 10, 1), + PIN_FIELD_BASE(38, 38, 3, 0x0C0, 0x10, 14, 1), + PIN_FIELD_BASE(39, 39, 3, 0x0C0, 0x10, 18, 1), + PIN_FIELD_BASE(40, 40, 3, 0x0C0, 0x10, 22, 1), + PIN_FIELD_BASE(41, 41, 3, 0x0C0, 0x10, 26, 1), + PIN_FIELD_BASE(42, 42, 3, 0x0C0, 0x10, 30, 1), + PIN_FIELD_BASE(91, 91, 6, 0x0C0, 0x10, 2, 1), + PIN_FIELD_BASE(92, 92, 6, 0x0C0, 0x10, 6, 1), + PIN_FIELD_BASE(93, 93, 6, 0x0C0, 0x10, 10, 1), + PIN_FIELD_BASE(94, 94, 6, 0x0C0, 0x10, 14, 1), + PIN_FIELD_BASE(122, 122, 8, 0x0C0, 0x10, 2, 1), + PIN_FIELD_BASE(123, 123, 8, 0x0C0, 0x10, 6, 1), + PIN_FIELD_BASE(124, 124, 8, 0x0C0, 0x10, 10, 1), + PIN_FIELD_BASE(125, 125, 8, 0x0C0, 0x10, 14, 1), + PIN_FIELD_BASE(126, 126, 8, 0x0C0, 0x10, 18, 1), + PIN_FIELD_BASE(127, 127, 8, 0x0C0, 0x10, 22, 1), + PIN_FIELD_BASE(128, 128, 8, 0x0C0, 0x10, 26, 1), + PIN_FIELD_BASE(129, 129, 8, 0x0C0, 0x10, 30, 1), + PIN_FIELD_BASE(130, 130, 8, 0x0D0, 0x10, 2, 1), + PIN_FIELD_BASE(131, 131, 8, 0x0D0, 0x10, 6, 1), + PIN_FIELD_BASE(132, 132, 8, 0x0D0, 0x10, 10, 1), + PIN_FIELD_BASE(133, 133, 8, 0x0D0, 0x10, 14, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_r0_range[] = { + PIN_FIELD_BASE(29, 29, 2, 0x0C0, 0x10, 0, 1), + PIN_FIELD_BASE(30, 30, 2, 0x0C0, 0x10, 4, 1), + PIN_FIELD_BASE(31, 31, 2, 0x0C0, 0x10, 8, 1), + PIN_FIELD_BASE(32, 32, 2, 0x0C0, 0x10, 12, 1), + PIN_FIELD_BASE(33, 33, 2, 0x0C0, 0x10, 16, 1), + PIN_FIELD_BASE(34, 34, 2, 0x0C0, 0x10, 20, 1), + PIN_FIELD_BASE(35, 35, 3, 0x0C0, 0x10, 0, 1), + PIN_FIELD_BASE(36, 36, 3, 0x0C0, 0x10, 4, 1), + PIN_FIELD_BASE(37, 37, 3, 0x0C0, 0x10, 8, 1), + PIN_FIELD_BASE(38, 38, 3, 0x0C0, 0x10, 12, 1), + PIN_FIELD_BASE(39, 39, 3, 0x0C0, 0x10, 16, 1), + PIN_FIELD_BASE(40, 40, 3, 0x0C0, 0x10, 20, 1), + PIN_FIELD_BASE(41, 41, 3, 0x0C0, 0x10, 24, 1), + PIN_FIELD_BASE(42, 42, 3, 0x0C0, 0x10, 28, 1), + PIN_FIELD_BASE(48, 48, 3, 0x0F0, 0x10, 18, 1), + PIN_FIELD_BASE(49, 49, 3, 0x0F0, 0x10, 13, 1), + PIN_FIELD_BASE(50, 50, 4, 0x0F0, 0x10, 10, 1), + PIN_FIELD_BASE(51, 51, 4, 0x0F0, 0x10, 5, 1), + PIN_FIELD_BASE(81, 81, 5, 0x0F0, 0x10, 7, 1), + PIN_FIELD_BASE(82, 82, 5, 0x0F0, 0x10, 5, 1), + PIN_FIELD_BASE(83, 83, 5, 0x0F0, 0x10, 15, 1), + PIN_FIELD_BASE(84, 84, 5, 0x0F0, 0x10, 17, 1), + PIN_FIELD_BASE(91, 91, 6, 0x0C0, 0x10, 0, 1), + PIN_FIELD_BASE(92, 92, 6, 0x0C0, 0x10, 4, 1), + PIN_FIELD_BASE(93, 93, 6, 0x0C0, 0x10, 8, 1), + PIN_FIELD_BASE(94, 94, 6, 0x0C0, 0x10, 12, 1), + PIN_FIELD_BASE(103, 103, 6, 0x0F0, 0x10, 20, 1), + PIN_FIELD_BASE(104, 104, 6, 0x0F0, 0x10, 10, 1), + PIN_FIELD_BASE(105, 105, 6, 0x0F0, 0x10, 22, 1), + PIN_FIELD_BASE(106, 106, 6, 0x0F0, 0x10, 12, 1), + PIN_FIELD_BASE(122, 122, 8, 0x0C0, 0x10, 0, 1), + PIN_FIELD_BASE(123, 123, 8, 0x0C0, 0x10, 4, 1), + PIN_FIELD_BASE(124, 124, 8, 0x0C0, 0x10, 8, 1), + PIN_FIELD_BASE(125, 125, 8, 0x0C0, 0x10, 12, 1), + PIN_FIELD_BASE(126, 126, 8, 0x0C0, 0x10, 16, 1), + PIN_FIELD_BASE(127, 127, 8, 0x0C0, 0x10, 20, 1), + PIN_FIELD_BASE(128, 128, 8, 0x0C0, 0x10, 24, 1), + PIN_FIELD_BASE(129, 129, 8, 0x0C0, 0x10, 28, 1), + PIN_FIELD_BASE(130, 130, 8, 0x0D0, 0x10, 0, 1), + PIN_FIELD_BASE(131, 131, 8, 0x0D0, 0x10, 4, 1), + PIN_FIELD_BASE(132, 132, 8, 0x0D0, 0x10, 8, 1), + PIN_FIELD_BASE(133, 133, 8, 0x0D0, 0x10, 12, 1), +}; + +static const struct mtk_pin_field_calc mt8183_pin_r1_range[] = { + PIN_FIELD_BASE(29, 29, 2, 0x0C0, 0x10, 1, 1), + PIN_FIELD_BASE(30, 30, 2, 0x0C0, 0x10, 5, 1), + PIN_FIELD_BASE(31, 31, 2, 0x0C0, 0x10, 9, 1), + PIN_FIELD_BASE(32, 32, 2, 0x0C0, 0x10, 13, 1), + PIN_FIELD_BASE(33, 33, 2, 0x0C0, 0x10, 17, 1), + PIN_FIELD_BASE(34, 34, 2, 0x0C0, 0x10, 21, 1), + PIN_FIELD_BASE(35, 35, 3, 0x0C0, 0x10, 1, 1), + PIN_FIELD_BASE(36, 36, 3, 0x0C0, 0x10, 5, 1), + PIN_FIELD_BASE(37, 37, 3, 0x0C0, 0x10, 9, 1), + PIN_FIELD_BASE(38, 38, 3, 0x0C0, 0x10, 13, 1), + PIN_FIELD_BASE(39, 39, 3, 0x0C0, 0x10, 17, 1), + PIN_FIELD_BASE(40, 40, 3, 0x0C0, 0x10, 21, 1), + PIN_FIELD_BASE(41, 41, 3, 0x0C0, 0x10, 25, 1), + PIN_FIELD_BASE(42, 42, 3, 0x0C0, 0x10, 29, 1), + PIN_FIELD_BASE(48, 48, 3, 0x0F0, 0x10, 19, 1), + PIN_FIELD_BASE(49, 49, 3, 0x0F0, 0x10, 14, 1), + PIN_FIELD_BASE(50, 50, 4, 0x0F0, 0x10, 11, 1), + PIN_FIELD_BASE(51, 51, 4, 0x0F0, 0x10, 6, 1), + PIN_FIELD_BASE(81, 81, 5, 0x0F0, 0x10, 8, 1), + PIN_FIELD_BASE(82, 82, 5, 0x0F0, 0x10, 6, 1), + PIN_FIELD_BASE(83, 83, 5, 0x0F0, 0x10, 16, 1), + PIN_FIELD_BASE(84, 84, 5, 0x0F0, 0x10, 18, 1), + PIN_FIELD_BASE(91, 91, 6, 0x0C0, 0x10, 1, 1), + PIN_FIELD_BASE(92, 92, 6, 0x0C0, 0x10, 5, 1), + PIN_FIELD_BASE(93, 93, 6, 0x0C0, 0x10, 9, 1), + PIN_FIELD_BASE(94, 94, 6, 0x0C0, 0x10, 13, 1), + PIN_FIELD_BASE(103, 103, 6, 0x0F0, 0x10, 21, 1), + PIN_FIELD_BASE(104, 104, 6, 0x0F0, 0x10, 11, 1), + PIN_FIELD_BASE(105, 105, 6, 0x0F0, 0x10, 23, 1), + PIN_FIELD_BASE(106, 106, 6, 0x0F0, 0x10, 13, 1), + PIN_FIELD_BASE(122, 122, 8, 0x0C0, 0x10, 1, 1), + PIN_FIELD_BASE(123, 123, 8, 0x0C0, 0x10, 5, 1), + PIN_FIELD_BASE(124, 124, 8, 0x0C0, 0x10, 9, 1), + PIN_FIELD_BASE(125, 125, 8, 0x0C0, 0x10, 13, 1), + PIN_FIELD_BASE(126, 126, 8, 0x0C0, 0x10, 17, 1), + PIN_FIELD_BASE(127, 127, 8, 0x0C0, 0x10, 21, 1), + PIN_FIELD_BASE(128, 128, 8, 0x0C0, 0x10, 25, 1), + PIN_FIELD_BASE(129, 129, 8, 0x0C0, 0x10, 29, 1), + PIN_FIELD_BASE(130, 130, 8, 0x0D0, 0x10, 1, 1), + PIN_FIELD_BASE(131, 131, 8, 0x0D0, 0x10, 5, 1), + PIN_FIELD_BASE(132, 132, 8, 0x0D0, 0x10, 9, 1), + PIN_FIELD_BASE(133, 133, 8, 0x0D0, 0x10, 13, 1), +}; + +static const struct mtk_pin_reg_calc mt8183_reg_cals[PINCTRL_PIN_REG_MAX] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt8183_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8183_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8183_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8183_pin_do_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8183_pin_smt_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8183_pin_ies_range), + [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt8183_pin_pullen_range), + [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt8183_pin_pullsel_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt8183_pin_drv_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt8183_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt8183_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt8183_pin_r1_range), +}; + +static const char * const mt8183_pinctrl_register_base_names[] = { + "iocfg0", "iocfg1", "iocfg2", "iocfg3", "iocfg4", "iocfg5", + "iocfg6", "iocfg7", "iocfg8", +}; + +static const struct mtk_eint_hw mt8183_eint_hw = { + .port_mask = 7, + .ports = 6, + .ap_num = 212, + .db_cnt = 13, +}; + +static const struct mtk_pin_soc mt8183_data = { + .reg_cal = mt8183_reg_cals, + .pins = mtk_pins_mt8183, + .npins = ARRAY_SIZE(mtk_pins_mt8183), + .ngrps = ARRAY_SIZE(mtk_pins_mt8183), + .eint_hw = &mt8183_eint_hw, + .gpio_m = 0, + .ies_present = true, + .base_names = mt8183_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt8183_pinctrl_register_base_names), + .bias_disable_set = mtk_pinconf_bias_disable_set_rev1, + .bias_disable_get = mtk_pinconf_bias_disable_get_rev1, + .bias_set = mtk_pinconf_bias_set_rev1, + .bias_get = mtk_pinconf_bias_get_rev1, + .drive_set = mtk_pinconf_drive_set_rev1, + .drive_get = mtk_pinconf_drive_get_rev1, + .adv_pull_get = mtk_pinconf_adv_pull_get, + .adv_pull_set = mtk_pinconf_adv_pull_set, +}; + +static const struct of_device_id mt8183_pinctrl_of_match[] = { + { .compatible = "mediatek,mt8183-pinctrl", }, + { } +}; + +static int mt8183_pinctrl_probe(struct platform_device *pdev) +{ + return mtk_paris_pinctrl_probe(pdev, &mt8183_data); +} + +static struct platform_driver mt8183_pinctrl_driver = { + .driver = { + .name = "mt8183-pinctrl", + .of_match_table = mt8183_pinctrl_of_match, + }, + .probe = mt8183_pinctrl_probe, +}; + +static int __init mt8183_pinctrl_init(void) +{ + return platform_driver_register(&mt8183_pinctrl_driver); +} +arch_initcall(mt8183_pinctrl_init); diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c new file mode 100644 index 000000000000..4a9e0d4c2bbc --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c @@ -0,0 +1,670 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Sean Wang <sean.wang@mediatek.com> + * + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/driver.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/of_irq.h> + +#include "mtk-eint.h" +#include "pinctrl-mtk-common-v2.h" + +/** + * struct mtk_drive_desc - the structure that holds the information + * of the driving current + * @min: the minimum current of this group + * @max: the maximum current of this group + * @step: the step current of this group + * @scal: the weight factor + * + * formula: output = ((input) / step - 1) * scal + */ +struct mtk_drive_desc { + u8 min; + u8 max; + u8 step; + u8 scal; +}; + +/* The groups of drive strength */ +static const struct mtk_drive_desc mtk_drive[] = { + [DRV_GRP0] = { 4, 16, 4, 1 }, + [DRV_GRP1] = { 4, 16, 4, 2 }, + [DRV_GRP2] = { 2, 8, 2, 1 }, + [DRV_GRP3] = { 2, 8, 2, 2 }, + [DRV_GRP4] = { 2, 16, 2, 1 }, +}; + +static void mtk_w32(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 val) +{ + writel_relaxed(val, pctl->base[i] + reg); +} + +static u32 mtk_r32(struct mtk_pinctrl *pctl, u8 i, u32 reg) +{ + return readl_relaxed(pctl->base[i] + reg); +} + +void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set) +{ + u32 val; + + val = mtk_r32(pctl, i, reg); + val &= ~mask; + val |= set; + mtk_w32(pctl, i, reg, val); +} + +static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, + int field, struct mtk_pin_field *pfd) +{ + const struct mtk_pin_field_calc *c, *e; + const struct mtk_pin_reg_calc *rc; + u32 bits; + + if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) { + rc = &hw->soc->reg_cal[field]; + } else { + dev_dbg(hw->dev, + "Not support field %d for pin %d (%s)\n", + field, desc->number, desc->name); + return -ENOTSUPP; + } + + c = rc->range; + e = c + rc->nranges; + + while (c < e) { + if (desc->number >= c->s_pin && desc->number <= c->e_pin) + break; + c++; + } + + if (c >= e) { + dev_dbg(hw->dev, "Not support field %d for pin = %d (%s)\n", + field, desc->number, desc->name); + return -ENOTSUPP; + } + + if (c->i_base > hw->nbase - 1) { + dev_err(hw->dev, + "Invalid base for field %d for pin = %d (%s)\n", + field, desc->number, desc->name); + return -EINVAL; + } + + /* Calculated bits as the overall offset the pin is located at, + * if c->fixed is held, that determines the all the pins in the + * range use the same field with the s_pin. + */ + bits = c->fixed ? c->s_bit : c->s_bit + + (desc->number - c->s_pin) * (c->x_bits); + + /* Fill pfd from bits. For example 32-bit register applied is assumed + * when c->sz_reg is equal to 32. + */ + pfd->index = c->i_base; + pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg); + pfd->bitpos = bits % c->sz_reg; + pfd->mask = (1 << c->x_bits) - 1; + + /* pfd->next is used for indicating that bit wrapping-around happens + * which requires the manipulation for bit 0 starting in the next + * register to form the complete field read/write. + */ + pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0; + + return 0; +} + +static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, + int field, struct mtk_pin_field *pfd) +{ + if (field < 0 || field >= PINCTRL_PIN_REG_MAX) { + dev_err(hw->dev, "Invalid Field %d\n", field); + return -EINVAL; + } + + return mtk_hw_pin_field_lookup(hw, desc, field, pfd); +} + +static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l) +{ + *l = 32 - pf->bitpos; + *h = get_count_order(pf->mask) - *l; +} + +static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw, + struct mtk_pin_field *pf, int value) +{ + int nbits_l, nbits_h; + + mtk_hw_bits_part(pf, &nbits_h, &nbits_l); + + mtk_rmw(hw, pf->index, pf->offset, pf->mask << pf->bitpos, + (value & pf->mask) << pf->bitpos); + + mtk_rmw(hw, pf->index, pf->offset + pf->next, BIT(nbits_h) - 1, + (value & pf->mask) >> nbits_l); +} + +static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw, + struct mtk_pin_field *pf, int *value) +{ + int nbits_l, nbits_h, h, l; + + mtk_hw_bits_part(pf, &nbits_h, &nbits_l); + + l = (mtk_r32(hw, pf->index, pf->offset) + >> pf->bitpos) & (BIT(nbits_l) - 1); + h = (mtk_r32(hw, pf->index, pf->offset + pf->next)) + & (BIT(nbits_h) - 1); + + *value = (h << nbits_l) | l; +} + +int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, + int field, int value) +{ + struct mtk_pin_field pf; + int err; + + err = mtk_hw_pin_field_get(hw, desc, field, &pf); + if (err) + return err; + + if (!pf.next) + mtk_rmw(hw, pf.index, pf.offset, pf.mask << pf.bitpos, + (value & pf.mask) << pf.bitpos); + else + mtk_hw_write_cross_field(hw, &pf, value); + + return 0; +} + +int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, + int field, int *value) +{ + struct mtk_pin_field pf; + int err; + + err = mtk_hw_pin_field_get(hw, desc, field, &pf); + if (err) + return err; + + if (!pf.next) + *value = (mtk_r32(hw, pf.index, pf.offset) + >> pf.bitpos) & pf.mask; + else + mtk_hw_read_cross_field(hw, &pf, value); + + return 0; +} + +static int mtk_xt_find_eint_num(struct mtk_pinctrl *hw, unsigned long eint_n) +{ + const struct mtk_pin_desc *desc; + int i = 0; + + desc = (const struct mtk_pin_desc *)hw->soc->pins; + + while (i < hw->soc->npins) { + if (desc[i].eint.eint_n == eint_n) + return desc[i].number; + i++; + } + + return EINT_NA; +} + +static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n, + unsigned int *gpio_n, + struct gpio_chip **gpio_chip) +{ + struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)hw->soc->pins; + *gpio_chip = &hw->chip; + + /* Be greedy to guess first gpio_n is equal to eint_n */ + if (desc[eint_n].eint.eint_n == eint_n) + *gpio_n = eint_n; + else + *gpio_n = mtk_xt_find_eint_num(hw, eint_n); + + return *gpio_n == EINT_NA ? -EINVAL : 0; +} + +static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n) +{ + struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; + const struct mtk_pin_desc *desc; + struct gpio_chip *gpio_chip; + unsigned int gpio_n; + int value, err; + + err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); + if (err) + return err; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); + if (err) + return err; + + return !!value; +} + +static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n) +{ + struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; + const struct mtk_pin_desc *desc; + struct gpio_chip *gpio_chip; + unsigned int gpio_n; + int err; + + err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); + if (err) + return err; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n]; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, + desc->eint.eint_m); + if (err) + return err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, MTK_INPUT); + if (err) + return err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, MTK_ENABLE); + if (err) + return err; + + return 0; +} + +static const struct mtk_eint_xt mtk_eint_xt = { + .get_gpio_n = mtk_xt_get_gpio_n, + .get_gpio_state = mtk_xt_get_gpio_state, + .set_gpio_as_eint = mtk_xt_set_gpio_as_eint, +}; + +int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + + if (!IS_ENABLED(CONFIG_EINT_MTK)) + return 0; + + if (!of_property_read_bool(np, "interrupt-controller")) + return -ENODEV; + + hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL); + if (!hw->eint) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint"); + if (!res) { + dev_err(&pdev->dev, "Unable to get eint resource\n"); + return -ENODEV; + } + + hw->eint->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->eint->base)) + return PTR_ERR(hw->eint->base); + + hw->eint->irq = irq_of_parse_and_map(np, 0); + if (!hw->eint->irq) + return -EINVAL; + + if (!hw->soc->eint_hw) + return -ENODEV; + + hw->eint->dev = &pdev->dev; + hw->eint->hw = hw->soc->eint_hw; + hw->eint->pctl = hw; + hw->eint->gpio_xlate = &mtk_eint_xt; + + return mtk_eint_do_init(hw->eint); +} + +/* Revision 0 */ +int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc) +{ + int err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, + MTK_DISABLE); + if (err) + return err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, + MTK_DISABLE); + if (err) + return err; + + return 0; +} + +int mtk_pinconf_bias_disable_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *res) +{ + int v, v2; + int err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &v); + if (err) + return err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &v2); + if (err) + return err; + + if (v == MTK_ENABLE || v2 == MTK_ENABLE) + return -EINVAL; + + *res = 1; + + return 0; +} + +int mtk_pinconf_bias_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup) +{ + int err, arg; + + arg = pullup ? 1 : 2; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, arg & 1); + if (err) + return err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, + !!(arg & 2)); + if (err) + return err; + + return 0; +} + +int mtk_pinconf_bias_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, int *res) +{ + int reg, err, v; + + reg = pullup ? PINCTRL_PIN_REG_PU : PINCTRL_PIN_REG_PD; + + err = mtk_hw_get_value(hw, desc, reg, &v); + if (err) + return err; + + if (!v) + return -EINVAL; + + *res = 1; + + return 0; +} + +/* Revision 1 */ +int mtk_pinconf_bias_disable_set_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc) +{ + int err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, + MTK_DISABLE); + if (err) + return err; + + return 0; +} + +int mtk_pinconf_bias_disable_get_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *res) +{ + int v, err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v); + if (err) + return err; + + if (v == MTK_ENABLE) + return -EINVAL; + + *res = 1; + + return 0; +} + +int mtk_pinconf_bias_set_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup) +{ + int err, arg; + + arg = pullup ? MTK_PULLUP : MTK_PULLDOWN; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, + MTK_ENABLE); + if (err) + return err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, arg); + if (err) + return err; + + return 0; +} + +int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + int *res) +{ + int err, v; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v); + if (err) + return err; + + if (v == MTK_DISABLE) + return -EINVAL; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, &v); + if (err) + return err; + + if (pullup ^ (v == MTK_PULLUP)) + return -EINVAL; + + *res = 1; + + return 0; +} + +/* Revision 0 */ +int mtk_pinconf_drive_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, u32 arg) +{ + const struct mtk_drive_desc *tb; + int err = -ENOTSUPP; + + tb = &mtk_drive[desc->drv_n]; + /* 4mA when (e8, e4) = (0, 0) + * 8mA when (e8, e4) = (0, 1) + * 12mA when (e8, e4) = (1, 0) + * 16mA when (e8, e4) = (1, 1) + */ + if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) { + arg = (arg / tb->step - 1) * tb->scal; + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E4, + arg & 0x1); + if (err) + return err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E8, + (arg & 0x2) >> 1); + if (err) + return err; + } + + return err; +} + +int mtk_pinconf_drive_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *val) +{ + const struct mtk_drive_desc *tb; + int err, val1, val2; + + tb = &mtk_drive[desc->drv_n]; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E4, &val1); + if (err) + return err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E8, &val2); + if (err) + return err; + + /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1) + * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1) + */ + *val = (((val2 << 1) + val1) / tb->scal + 1) * tb->step; + + return 0; +} + +/* Revision 1 */ +int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, u32 arg) +{ + const struct mtk_drive_desc *tb; + int err = -ENOTSUPP; + + tb = &mtk_drive[desc->drv_n]; + + if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) { + arg = (arg / tb->step - 1) * tb->scal; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV, + arg); + if (err) + return err; + } + + return err; +} + +int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *val) +{ + const struct mtk_drive_desc *tb; + int err, val1; + + tb = &mtk_drive[desc->drv_n]; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, &val1); + if (err) + return err; + + *val = ((val1 & 0x7) / tb->scal + 1) * tb->step; + + return 0; +} + +int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + u32 arg) +{ + int err; + + /* 10K off & 50K (75K) off, when (R0, R1) = (0, 0); + * 10K off & 50K (75K) on, when (R0, R1) = (0, 1); + * 10K on & 50K (75K) off, when (R0, R1) = (1, 0); + * 10K on & 50K (75K) on, when (R0, R1) = (1, 1) + */ + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, arg & 1); + if (err) + return 0; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1, + !!(arg & 2)); + if (err) + return 0; + + arg = pullup ? 0 : 1; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, arg); + + /* If PUPD register is not supported for that pin, let's fallback to + * general bias control. + */ + if (err == -ENOTSUPP) { + if (hw->soc->bias_set) { + err = hw->soc->bias_set(hw, desc, pullup); + if (err) + return err; + } else { + return -ENOTSUPP; + } + } + + return err; +} + +int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + u32 *val) +{ + u32 t, t2; + int err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, &t); + + /* If PUPD register is not supported for that pin, let's fallback to + * general bias control. + */ + if (err == -ENOTSUPP) { + if (hw->soc->bias_get) { + err = hw->soc->bias_get(hw, desc, pullup, val); + if (err) + return err; + } else { + return -ENOTSUPP; + } + } else { + /* t == 0 supposes PULLUP for the customized PULL setup */ + if (err) + return err; + + if (pullup ^ !t) + return -EINVAL; + } + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &t); + if (err) + return err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &t2); + if (err) + return err; + + *val = (t | t2 << 1) & 0x7; + + return 0; +} diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h new file mode 100644 index 000000000000..6d24522739d9 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h @@ -0,0 +1,291 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Sean Wang <sean.wang@mediatek.com> + * + */ + +#ifndef __PINCTRL_MTK_COMMON_V2_H +#define __PINCTRL_MTK_COMMON_V2_H + +#include <linux/gpio/driver.h> + +#define MTK_INPUT 0 +#define MTK_OUTPUT 1 +#define MTK_DISABLE 0 +#define MTK_ENABLE 1 +#define MTK_PULLDOWN 0 +#define MTK_PULLUP 1 + +#define EINT_NA U16_MAX +#define NO_EINT_SUPPORT EINT_NA + +#define PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, \ + _s_bit, _x_bits, _sz_reg, _fixed) { \ + .s_pin = _s_pin, \ + .e_pin = _e_pin, \ + .i_base = _i_base, \ + .s_addr = _s_addr, \ + .x_addrs = _x_addrs, \ + .s_bit = _s_bit, \ + .x_bits = _x_bits, \ + .sz_reg = _sz_reg, \ + .fixed = _fixed, \ + } + +#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 0) + +#define PINS_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 1) + +/* List these attributes which could be modified for the pin */ +enum { + PINCTRL_PIN_REG_MODE, + PINCTRL_PIN_REG_DIR, + PINCTRL_PIN_REG_DI, + PINCTRL_PIN_REG_DO, + PINCTRL_PIN_REG_SR, + PINCTRL_PIN_REG_SMT, + PINCTRL_PIN_REG_PD, + PINCTRL_PIN_REG_PU, + PINCTRL_PIN_REG_E4, + PINCTRL_PIN_REG_E8, + PINCTRL_PIN_REG_TDSEL, + PINCTRL_PIN_REG_RDSEL, + PINCTRL_PIN_REG_DRV, + PINCTRL_PIN_REG_PUPD, + PINCTRL_PIN_REG_R0, + PINCTRL_PIN_REG_R1, + PINCTRL_PIN_REG_IES, + PINCTRL_PIN_REG_PULLEN, + PINCTRL_PIN_REG_PULLSEL, + PINCTRL_PIN_REG_MAX, +}; + +/* Group the pins by the driving current */ +enum { + DRV_FIXED, + DRV_GRP0, + DRV_GRP1, + DRV_GRP2, + DRV_GRP3, + DRV_GRP4, + DRV_GRP_MAX, +}; + +static const char * const mtk_default_register_base_names[] = { + "base", +}; + +/* struct mtk_pin_field - the structure that holds the information of the field + * used to describe the attribute for the pin + * @base: the index pointing to the entry in base address list + * @offset: the register offset relative to the base address + * @mask: the mask used to filter out the field from the register + * @bitpos: the start bit relative to the register + * @next: the indication that the field would be extended to the + next register + */ +struct mtk_pin_field { + u8 index; + u32 offset; + u32 mask; + u8 bitpos; + u8 next; +}; + +/* struct mtk_pin_field_calc - the structure that holds the range providing + * the guide used to look up the relevant field + * @s_pin: the start pin within the range + * @e_pin: the end pin within the range + * @i_base: the index pointing to the entry in base address list + * @s_addr: the start address for the range + * @x_addrs: the address distance between two consecutive registers + * within the range + * @s_bit: the start bit for the first register within the range + * @x_bits: the bit distance between two consecutive pins within + * the range + * @sz_reg: the size of bits in a register + * @fixed: the consecutive pins share the same bits with the 1st + * pin + */ +struct mtk_pin_field_calc { + u16 s_pin; + u16 e_pin; + u8 i_base; + u32 s_addr; + u8 x_addrs; + u8 s_bit; + u8 x_bits; + u8 sz_reg; + u8 fixed; +}; + +/* struct mtk_pin_reg_calc - the structure that holds all ranges used to + * determine which register the pin would make use of + * for certain pin attribute. + * @range: the start address for the range + * @nranges: the number of items in the range + */ +struct mtk_pin_reg_calc { + const struct mtk_pin_field_calc *range; + unsigned int nranges; +}; + +/** + * struct mtk_func_desc - the structure that providing information + * all the funcs for this pin + * @name: the name of function + * @muxval: the mux to the function + */ +struct mtk_func_desc { + const char *name; + u8 muxval; +}; + +/** + * struct mtk_eint_desc - the structure that providing information + * for eint data per pin + * @eint_m: the eint mux for this pin + * @eitn_n: the eint number for this pin + */ +struct mtk_eint_desc { + u16 eint_m; + u16 eint_n; +}; + +/** + * struct mtk_pin_desc - the structure that providing information + * for each pin of chips + * @number: unique pin number from the global pin number space + * @name: name for this pin + * @eint: the eint data for this pin + * @drv_n: the index with the driving group + * @funcs: all available functions for this pins (only used in + * those drivers compatible to pinctrl-mtk-common.c-like + * ones) + */ +struct mtk_pin_desc { + unsigned int number; + const char *name; + struct mtk_eint_desc eint; + u8 drv_n; + struct mtk_func_desc *funcs; +}; + +struct mtk_pinctrl_group { + const char *name; + unsigned long config; + unsigned pin; +}; + +struct mtk_pinctrl; + +/* struct mtk_pin_soc - the structure that holds SoC-specific data */ +struct mtk_pin_soc { + const struct mtk_pin_reg_calc *reg_cal; + const struct mtk_pin_desc *pins; + unsigned int npins; + const struct group_desc *grps; + unsigned int ngrps; + const struct function_desc *funcs; + unsigned int nfuncs; + const struct mtk_eint_regs *eint_regs; + const struct mtk_eint_hw *eint_hw; + + /* Specific parameters per SoC */ + u8 gpio_m; + bool ies_present; + const char * const *base_names; + unsigned int nbase_names; + + /* Specific pinconfig operations */ + int (*bias_disable_set)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc); + int (*bias_disable_get)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *res); + int (*bias_set)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup); + int (*bias_get)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, int *res); + + int (*drive_set)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, u32 arg); + int (*drive_get)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *val); + + int (*adv_pull_set)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + u32 arg); + int (*adv_pull_get)(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + u32 *val); + + /* Specific driver data */ + void *driver_data; +}; + +struct mtk_pinctrl { + struct pinctrl_dev *pctrl; + void __iomem **base; + u8 nbase; + struct device *dev; + struct gpio_chip chip; + const struct mtk_pin_soc *soc; + struct mtk_eint *eint; + struct mtk_pinctrl_group *groups; + const char **grp_names; +}; + +void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set); + +int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, + int field, int value); +int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, + int field, int *value); + +int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev); + +int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc); +int mtk_pinconf_bias_disable_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *res); +int mtk_pinconf_bias_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup); +int mtk_pinconf_bias_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + int *res); + +int mtk_pinconf_bias_disable_set_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc); +int mtk_pinconf_bias_disable_get_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, + int *res); +int mtk_pinconf_bias_set_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup); +int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + int *res); + +int mtk_pinconf_drive_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, u32 arg); +int mtk_pinconf_drive_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *val); + +int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, u32 arg); +int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, int *val); + +int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + u32 arg); +int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, bool pullup, + u32 *val); + +#endif /* __PINCTRL_MTK_COMMON_V2_H */ diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 16ff56f93501..071623873ca5 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -514,8 +514,8 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, pins = of_find_property(node, "pinmux", NULL); if (!pins) { - dev_err(pctl->dev, "missing pins property in node %s .\n", - node->name); + dev_err(pctl->dev, "missing pins property in node %pOFn .\n", + node); return -EINVAL; } diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt6765.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6765.h new file mode 100644 index 000000000000..772563720461 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6765.h @@ -0,0 +1,1754 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: ZH Chen <zh.chen@mediatek.com> + * + */ + +#ifndef __PINCTRL_MTK_MT6765_H +#define __PINCTRL_MTK_MT6765_H + +#include "pinctrl-paris.h" + +static struct mtk_pin_desc mtk_pins_mt6765[] = { + MTK_PIN( + 0, "GPIO0", + MTK_EINT_FUNCTION(0, 0), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO0"), + MTK_FUNCTION(1, "UTXD1"), + MTK_FUNCTION(2, "CLKM0"), + MTK_FUNCTION(3, "MD_INT0"), + MTK_FUNCTION(4, "I2S0_MCK"), + MTK_FUNCTION(5, "MD_UTXD1"), + MTK_FUNCTION(6, "TP_GPIO0_AO"), + MTK_FUNCTION(7, "DBG_MON_B9") + ), + MTK_PIN( + 1, "GPIO1", + MTK_EINT_FUNCTION(0, 1), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO1"), + MTK_FUNCTION(1, "URXD1"), + MTK_FUNCTION(2, "CLKM1"), + MTK_FUNCTION(4, "I2S0_BCK"), + MTK_FUNCTION(5, "MD_URXD1"), + MTK_FUNCTION(6, "TP_GPIO1_AO"), + MTK_FUNCTION(7, "DBG_MON_B10") + ), + MTK_PIN( + 2, "GPIO2", + MTK_EINT_FUNCTION(0, 2), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO2"), + MTK_FUNCTION(1, "UCTS0"), + MTK_FUNCTION(2, "CLKM2"), + MTK_FUNCTION(3, "UTXD1"), + MTK_FUNCTION(4, "I2S0_LRCK"), + MTK_FUNCTION(5, "ANT_SEL6"), + MTK_FUNCTION(6, "TP_GPIO2_AO"), + MTK_FUNCTION(7, "DBG_MON_B11") + ), + MTK_PIN( + 3, "GPIO3", + MTK_EINT_FUNCTION(0, 3), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO3"), + MTK_FUNCTION(1, "URTS0"), + MTK_FUNCTION(2, "CLKM3"), + MTK_FUNCTION(3, "URXD1"), + MTK_FUNCTION(4, "I2S0_DI"), + MTK_FUNCTION(5, "ANT_SEL7"), + MTK_FUNCTION(6, "TP_GPIO3_AO"), + MTK_FUNCTION(7, "DBG_MON_B12") + ), + MTK_PIN( + 4, "GPIO4", + MTK_EINT_FUNCTION(0, 4), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO4"), + MTK_FUNCTION(1, "SPI1_B_MI"), + MTK_FUNCTION(2, "SCP_SPI1_MI"), + MTK_FUNCTION(3, "UCTS0"), + MTK_FUNCTION(4, "I2S3_MCK"), + MTK_FUNCTION(5, "SSPM_URXD_AO"), + MTK_FUNCTION(6, "TP_GPIO4_AO") + ), + MTK_PIN( + 5, "GPIO5", + MTK_EINT_FUNCTION(0, 5), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO5"), + MTK_FUNCTION(1, "SPI1_B_CSB"), + MTK_FUNCTION(2, "SCP_SPI1_CS"), + MTK_FUNCTION(3, "URTS0"), + MTK_FUNCTION(4, "I2S3_BCK"), + MTK_FUNCTION(5, "SSPM_UTXD_AO"), + MTK_FUNCTION(6, "TP_GPIO5_AO") + ), + MTK_PIN( + 6, "GPIO6", + MTK_EINT_FUNCTION(0, 6), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO6"), + MTK_FUNCTION(1, "SPI1_B_MO"), + MTK_FUNCTION(2, "SCP_SPI1_MO"), + MTK_FUNCTION(3, "PWM0"), + MTK_FUNCTION(4, "I2S3_LRCK"), + MTK_FUNCTION(5, "MD_UTXD0"), + MTK_FUNCTION(6, "TP_GPIO6_AO") + ), + MTK_PIN( + 7, "GPIO7", + MTK_EINT_FUNCTION(0, 7), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO7"), + MTK_FUNCTION(1, "SPI1_B_CLK"), + MTK_FUNCTION(2, "SCP_SPI1_CK"), + MTK_FUNCTION(3, "PWM1"), + MTK_FUNCTION(4, "I2S3_DO"), + MTK_FUNCTION(5, "MD_URXD0"), + MTK_FUNCTION(6, "TP_GPIO7_AO") + ), + MTK_PIN( + 8, "GPIO8", + MTK_EINT_FUNCTION(0, 8), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO8"), + MTK_FUNCTION(1, "UTXD1"), + MTK_FUNCTION(2, "SRCLKENAI0"), + MTK_FUNCTION(3, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(4, "ANT_SEL3"), + MTK_FUNCTION(5, "MFG_JTAG_TRSTN"), + MTK_FUNCTION(6, "I2S2_MCK"), + MTK_FUNCTION(7, "JTRSTN_SEL1") + ), + MTK_PIN( + 9, "GPIO9", + MTK_EINT_FUNCTION(0, 9), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO9"), + MTK_FUNCTION(1, "MD_INT0"), + MTK_FUNCTION(2, "CMMCLK2"), + MTK_FUNCTION(3, "CONN_MCU_TRST_B"), + MTK_FUNCTION(4, "IDDIG"), + MTK_FUNCTION(5, "SDA_6306"), + MTK_FUNCTION(6, "MCUPM_JTAG_TRSTN"), + MTK_FUNCTION(7, "DBG_MON_B22") + ), + MTK_PIN( + 10, "GPIO10", + MTK_EINT_FUNCTION(0, 10), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO10"), + MTK_FUNCTION(1, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(3, "CONN_MCU_DBGI_N"), + MTK_FUNCTION(4, "SRCLKENAI1"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(6, "CMVREF1"), + MTK_FUNCTION(7, "DBG_MON_B23") + ), + MTK_PIN( + 11, "GPIO11", + MTK_EINT_FUNCTION(0, 11), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO11"), + MTK_FUNCTION(1, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(2, "CLKM3"), + MTK_FUNCTION(3, "ANT_SEL6"), + MTK_FUNCTION(4, "SRCLKENAI0"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(6, "UCTS1"), + MTK_FUNCTION(7, "DBG_MON_B24") + ), + MTK_PIN( + 12, "GPIO12", + MTK_EINT_FUNCTION(0, 12), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO12"), + MTK_FUNCTION(1, "PWM0"), + MTK_FUNCTION(2, "SRCLKENAI1"), + MTK_FUNCTION(3, "EXT_FRAME_SYNC"), + MTK_FUNCTION(4, "MD_INT0"), + MTK_FUNCTION(5, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(6, "URTS1") + ), + MTK_PIN( + 13, "GPIO13", + MTK_EINT_FUNCTION(0, 13), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO13"), + MTK_FUNCTION(1, "ANT_SEL0"), + MTK_FUNCTION(2, "SPI4_MI"), + MTK_FUNCTION(3, "SCP_SPI0_MI"), + MTK_FUNCTION(4, "MD_URXD0"), + MTK_FUNCTION(5, "CLKM0"), + MTK_FUNCTION(6, "I2S0_MCK"), + MTK_FUNCTION(7, "DBG_MON_A0") + ), + MTK_PIN( + 14, "GPIO14", + MTK_EINT_FUNCTION(0, 14), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO14"), + MTK_FUNCTION(1, "ANT_SEL1"), + MTK_FUNCTION(2, "SPI4_CSB"), + MTK_FUNCTION(3, "SCP_SPI0_CS"), + MTK_FUNCTION(4, "MD_UTXD0"), + MTK_FUNCTION(5, "CLKM1"), + MTK_FUNCTION(6, "I2S0_BCK"), + MTK_FUNCTION(7, "DBG_MON_A1") + ), + MTK_PIN( + 15, "GPIO15", + MTK_EINT_FUNCTION(0, 15), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO15"), + MTK_FUNCTION(1, "ANT_SEL2"), + MTK_FUNCTION(2, "SPI4_MO"), + MTK_FUNCTION(3, "SCP_SPI0_MO"), + MTK_FUNCTION(4, "MD_URXD1"), + MTK_FUNCTION(5, "CLKM2"), + MTK_FUNCTION(6, "I2S0_LRCK"), + MTK_FUNCTION(7, "DBG_MON_A2") + ), + MTK_PIN( + 16, "GPIO16", + MTK_EINT_FUNCTION(0, 16), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO16"), + MTK_FUNCTION(1, "ANT_SEL3"), + MTK_FUNCTION(2, "SPI4_CLK"), + MTK_FUNCTION(3, "SCP_SPI0_CK"), + MTK_FUNCTION(4, "MD_UTXD1"), + MTK_FUNCTION(5, "CLKM3"), + MTK_FUNCTION(6, "I2S3_MCK"), + MTK_FUNCTION(7, "DBG_MON_A3") + ), + MTK_PIN( + 17, "GPIO17", + MTK_EINT_FUNCTION(0, 17), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO17"), + MTK_FUNCTION(1, "ANT_SEL4"), + MTK_FUNCTION(2, "SPI2_MO"), + MTK_FUNCTION(3, "SCP_SPI0_MO"), + MTK_FUNCTION(4, "PWM1"), + MTK_FUNCTION(5, "IDDIG"), + MTK_FUNCTION(6, "I2S0_DI"), + MTK_FUNCTION(7, "DBG_MON_A4") + ), + MTK_PIN( + 18, "GPIO18", + MTK_EINT_FUNCTION(0, 18), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO18"), + MTK_FUNCTION(1, "ANT_SEL5"), + MTK_FUNCTION(2, "SPI2_CLK"), + MTK_FUNCTION(3, "SCP_SPI0_CK"), + MTK_FUNCTION(4, "MD_INT0"), + MTK_FUNCTION(5, "USB_DRVVBUS"), + MTK_FUNCTION(6, "I2S3_BCK"), + MTK_FUNCTION(7, "DBG_MON_A5") + ), + MTK_PIN( + 19, "GPIO19", + MTK_EINT_FUNCTION(0, 19), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO19"), + MTK_FUNCTION(1, "ANT_SEL6"), + MTK_FUNCTION(2, "SPI2_MI"), + MTK_FUNCTION(3, "SCP_SPI0_MI"), + MTK_FUNCTION(4, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(6, "I2S3_LRCK"), + MTK_FUNCTION(7, "DBG_MON_A6") + ), + MTK_PIN( + 20, "GPIO20", + MTK_EINT_FUNCTION(0, 20), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO20"), + MTK_FUNCTION(1, "ANT_SEL7"), + MTK_FUNCTION(2, "SPI2_CSB"), + MTK_FUNCTION(3, "SCP_SPI0_CS"), + MTK_FUNCTION(4, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(5, "CMMCLK3"), + MTK_FUNCTION(6, "I2S3_DO"), + MTK_FUNCTION(7, "DBG_MON_A7") + ), + MTK_PIN( + 21, "GPIO21", + MTK_EINT_FUNCTION(0, 21), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO21"), + MTK_FUNCTION(1, "SPI3_MI"), + MTK_FUNCTION(2, "SRCLKENAI1"), + MTK_FUNCTION(3, "DAP_MD32_SWD"), + MTK_FUNCTION(4, "CMVREF0"), + MTK_FUNCTION(5, "SCP_SPI0_MI"), + MTK_FUNCTION(6, "I2S2_MCK"), + MTK_FUNCTION(7, "DBG_MON_A8") + ), + MTK_PIN( + 22, "GPIO22", + MTK_EINT_FUNCTION(0, 22), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO22"), + MTK_FUNCTION(1, "SPI3_CSB"), + MTK_FUNCTION(2, "SRCLKENAI0"), + MTK_FUNCTION(3, "DAP_MD32_SWCK"), + MTK_FUNCTION(4, "CMVREF1"), + MTK_FUNCTION(5, "SCP_SPI0_CS"), + MTK_FUNCTION(6, "I2S2_BCK"), + MTK_FUNCTION(7, "DBG_MON_A9") + ), + MTK_PIN( + 23, "GPIO23", + MTK_EINT_FUNCTION(0, 23), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO23"), + MTK_FUNCTION(1, "SPI3_MO"), + MTK_FUNCTION(2, "PWM0"), + MTK_FUNCTION(3, "KPROW7"), + MTK_FUNCTION(4, "ANT_SEL3"), + MTK_FUNCTION(5, "SCP_SPI0_MO"), + MTK_FUNCTION(6, "I2S2_LRCK"), + MTK_FUNCTION(7, "DBG_MON_A10") + ), + MTK_PIN( + 24, "GPIO24", + MTK_EINT_FUNCTION(0, 24), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO24"), + MTK_FUNCTION(1, "SPI3_CLK"), + MTK_FUNCTION(2, "UDI_TCK"), + MTK_FUNCTION(3, "IO_JTAG_TCK"), + MTK_FUNCTION(4, "SSPM_JTAG_TCK"), + MTK_FUNCTION(5, "SCP_SPI0_CK"), + MTK_FUNCTION(6, "I2S2_DI"), + MTK_FUNCTION(7, "DBG_MON_A11") + ), + MTK_PIN( + 25, "GPIO25", + MTK_EINT_FUNCTION(0, 25), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO25"), + MTK_FUNCTION(1, "SPI1_A_MI"), + MTK_FUNCTION(2, "UDI_TMS"), + MTK_FUNCTION(3, "IO_JTAG_TMS"), + MTK_FUNCTION(4, "SSPM_JTAG_TMS"), + MTK_FUNCTION(5, "KPROW3"), + MTK_FUNCTION(6, "I2S1_MCK"), + MTK_FUNCTION(7, "DBG_MON_A12") + ), + MTK_PIN( + 26, "GPIO26", + MTK_EINT_FUNCTION(0, 26), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO26"), + MTK_FUNCTION(1, "SPI1_A_CSB"), + MTK_FUNCTION(2, "UDI_TDI"), + MTK_FUNCTION(3, "IO_JTAG_TDI"), + MTK_FUNCTION(4, "SSPM_JTAG_TDI"), + MTK_FUNCTION(5, "KPROW4"), + MTK_FUNCTION(6, "I2S1_BCK"), + MTK_FUNCTION(7, "DBG_MON_A13") + ), + MTK_PIN( + 27, "GPIO27", + MTK_EINT_FUNCTION(0, 27), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO27"), + MTK_FUNCTION(1, "SPI1_A_MO"), + MTK_FUNCTION(2, "UDI_TDO"), + MTK_FUNCTION(3, "IO_JTAG_TDO"), + MTK_FUNCTION(4, "SSPM_JTAG_TDO"), + MTK_FUNCTION(5, "KPROW5"), + MTK_FUNCTION(6, "I2S1_LRCK"), + MTK_FUNCTION(7, "DBG_MON_A14") + ), + MTK_PIN( + 28, "GPIO28", + MTK_EINT_FUNCTION(0, 28), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO28"), + MTK_FUNCTION(1, "SPI1_A_CLK"), + MTK_FUNCTION(2, "UDI_NTRST"), + MTK_FUNCTION(3, "IO_JTAG_TRSTN"), + MTK_FUNCTION(4, "SSPM_JTAG_TRSTN"), + MTK_FUNCTION(5, "KPROW6"), + MTK_FUNCTION(6, "I2S1_DO"), + MTK_FUNCTION(7, "DBG_MON_A15") + ), + MTK_PIN( + 29, "GPIO29", + MTK_EINT_FUNCTION(0, 29), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO29"), + MTK_FUNCTION(1, "MSDC1_CLK"), + MTK_FUNCTION(2, "IO_JTAG_TCK"), + MTK_FUNCTION(3, "UDI_TCK"), + MTK_FUNCTION(4, "CONN_DSP_JCK"), + MTK_FUNCTION(5, "SSPM_JTAG_TCK"), + MTK_FUNCTION(6, "CONN_MCU_AICE_TCKC"), + MTK_FUNCTION(7, "DAP_MD32_SWCK") + ), + MTK_PIN( + 30, "GPIO30", + MTK_EINT_FUNCTION(0, 30), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO30"), + MTK_FUNCTION(1, "MSDC1_CMD"), + MTK_FUNCTION(2, "IO_JTAG_TMS"), + MTK_FUNCTION(3, "UDI_TMS"), + MTK_FUNCTION(4, "CONN_DSP_JMS"), + MTK_FUNCTION(5, "SSPM_JTAG_TMS"), + MTK_FUNCTION(6, "CONN_MCU_AICE_TMSC"), + MTK_FUNCTION(7, "DAP_MD32_SWD") + ), + MTK_PIN( + 31, "GPIO31", + MTK_EINT_FUNCTION(0, 31), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO31"), + MTK_FUNCTION(1, "MSDC1_DAT3") + ), + MTK_PIN( + 32, "GPIO32", + MTK_EINT_FUNCTION(0, 32), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO32"), + MTK_FUNCTION(1, "MSDC1_DAT0"), + MTK_FUNCTION(2, "IO_JTAG_TDI"), + MTK_FUNCTION(3, "UDI_TDI"), + MTK_FUNCTION(4, "CONN_DSP_JDI"), + MTK_FUNCTION(5, "SSPM_JTAG_TDI") + ), + MTK_PIN( + 33, "GPIO33", + MTK_EINT_FUNCTION(0, 33), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO33"), + MTK_FUNCTION(1, "MSDC1_DAT2"), + MTK_FUNCTION(2, "IO_JTAG_TRSTN"), + MTK_FUNCTION(3, "UDI_NTRST"), + MTK_FUNCTION(4, "CONN_DSP_JINTP"), + MTK_FUNCTION(5, "SSPM_JTAG_TRSTN") + ), + MTK_PIN( + 34, "GPIO34", + MTK_EINT_FUNCTION(0, 34), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO34"), + MTK_FUNCTION(1, "MSDC1_DAT1"), + MTK_FUNCTION(2, "IO_JTAG_TDO"), + MTK_FUNCTION(3, "UDI_TDO"), + MTK_FUNCTION(4, "CONN_DSP_JDO"), + MTK_FUNCTION(5, "SSPM_JTAG_TDO") + ), + MTK_PIN( + 35, "GPIO35", + MTK_EINT_FUNCTION(0, 35), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO35"), + MTK_FUNCTION(1, "MD1_SIM2_SIO"), + MTK_FUNCTION(2, "CCU_JTAG_TDO"), + MTK_FUNCTION(3, "MD1_SIM1_SIO"), + MTK_FUNCTION(5, "SCP_JTAG_TDO"), + MTK_FUNCTION(6, "CONN_DSP_JDO"), + MTK_FUNCTION(7, "DBG_MON_A16") + ), + MTK_PIN( + 36, "GPIO36", + MTK_EINT_FUNCTION(0, 36), + DRV_GRP0, + MTK_FUNCTION(0, "GPIO36"), + MTK_FUNCTION(1, "MD1_SIM2_SRST"), + MTK_FUNCTION(2, "CCU_JTAG_TMS"), + MTK_FUNCTION(3, "MD1_SIM1_SRST"), + MTK_FUNCTION(4, "CONN_MCU_AICE_TMSC"), + MTK_FUNCTION(5, "SCP_JTAG_TMS"), + MTK_FUNCTION(6, "CONN_DSP_JMS"), + MTK_FUNCTION(7, "DBG_MON_A17") + ), + MTK_PIN( + 37, "GPIO37", + MTK_EINT_FUNCTION(0, 37), + DRV_GRP0, + MTK_FUNCTION(0, "GPIO37"), + MTK_FUNCTION(1, "MD1_SIM2_SCLK"), + MTK_FUNCTION(2, "CCU_JTAG_TDI"), + MTK_FUNCTION(3, "MD1_SIM1_SCLK"), + MTK_FUNCTION(5, "SCP_JTAG_TDI"), + MTK_FUNCTION(6, "CONN_DSP_JDI"), + MTK_FUNCTION(7, "DBG_MON_A18") + ), + MTK_PIN( + 38, "GPIO38", + MTK_EINT_FUNCTION(0, 38), + DRV_GRP0, + MTK_FUNCTION(0, "GPIO38"), + MTK_FUNCTION(1, "MD1_SIM1_SCLK"), + MTK_FUNCTION(3, "MD1_SIM2_SCLK"), + MTK_FUNCTION(7, "DBG_MON_A19") + ), + MTK_PIN( + 39, "GPIO39", + MTK_EINT_FUNCTION(0, 39), + DRV_GRP0, + MTK_FUNCTION(0, "GPIO39"), + MTK_FUNCTION(1, "MD1_SIM1_SRST"), + MTK_FUNCTION(2, "CCU_JTAG_TCK"), + MTK_FUNCTION(3, "MD1_SIM2_SRST"), + MTK_FUNCTION(4, "CONN_MCU_AICE_TCKC"), + MTK_FUNCTION(5, "SCP_JTAG_TCK"), + MTK_FUNCTION(6, "CONN_DSP_JCK"), + MTK_FUNCTION(7, "DBG_MON_A20") + ), + MTK_PIN( + 40, "GPIO40", + MTK_EINT_FUNCTION(0, 40), + DRV_GRP0, + MTK_FUNCTION(0, "GPIO40"), + MTK_FUNCTION(1, "MD1_SIM1_SIO"), + MTK_FUNCTION(2, "CCU_JTAG_TRST"), + MTK_FUNCTION(3, "MD1_SIM2_SIO"), + MTK_FUNCTION(5, "SCP_JTAG_TRSTN"), + MTK_FUNCTION(6, "CONN_DSP_JINTP"), + MTK_FUNCTION(7, "DBG_MON_A21") + ), + MTK_PIN( + 41, "GPIO41", + MTK_EINT_FUNCTION(0, 41), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO41"), + MTK_FUNCTION(1, "IDDIG"), + MTK_FUNCTION(2, "URXD1"), + MTK_FUNCTION(3, "UCTS0"), + MTK_FUNCTION(4, "KPCOL2"), + MTK_FUNCTION(5, "SSPM_UTXD_AO"), + MTK_FUNCTION(6, "MD_INT0"), + MTK_FUNCTION(7, "DBG_MON_A22") + ), + MTK_PIN( + 42, "GPIO42", + MTK_EINT_FUNCTION(0, 42), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO42"), + MTK_FUNCTION(1, "USB_DRVVBUS"), + MTK_FUNCTION(2, "UTXD1"), + MTK_FUNCTION(3, "URTS0"), + MTK_FUNCTION(4, "KPROW2"), + MTK_FUNCTION(5, "SSPM_URXD_AO"), + MTK_FUNCTION(6, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(7, "DBG_MON_A23") + ), + MTK_PIN( + 43, "GPIO43", + MTK_EINT_FUNCTION(0, 43), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO43"), + MTK_FUNCTION(1, "DISP_PWM"), + MTK_FUNCTION(7, "DBG_MON_A24") + ), + MTK_PIN( + 44, "GPIO44", + MTK_EINT_FUNCTION(0, 44), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO44"), + MTK_FUNCTION(1, "DSI_TE"), + MTK_FUNCTION(7, "DBG_MON_A25") + ), + MTK_PIN( + 45, "GPIO45", + MTK_EINT_FUNCTION(0, 45), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO45"), + MTK_FUNCTION(1, "LCM_RST"), + MTK_FUNCTION(7, "DBG_MON_A26") + ), + MTK_PIN( + 46, "GPIO46", + MTK_EINT_FUNCTION(0, 46), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO46"), + MTK_FUNCTION(1, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(2, "UCTS0"), + MTK_FUNCTION(3, "UCTS1"), + MTK_FUNCTION(4, "IDDIG"), + MTK_FUNCTION(5, "SCL_6306"), + MTK_FUNCTION(6, "TP_UCTS1_AO"), + MTK_FUNCTION(7, "DBG_MON_A27") + ), + MTK_PIN( + 47, "GPIO47", + MTK_EINT_FUNCTION(0, 47), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO47"), + MTK_FUNCTION(1, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(2, "URTS0"), + MTK_FUNCTION(3, "URTS1"), + MTK_FUNCTION(4, "USB_DRVVBUS"), + MTK_FUNCTION(5, "SDA_6306"), + MTK_FUNCTION(6, "TP_URTS1_AO"), + MTK_FUNCTION(7, "DBG_MON_A28") + ), + MTK_PIN( + 48, "GPIO48", + MTK_EINT_FUNCTION(0, 48), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO48"), + MTK_FUNCTION(1, "SCL5"), + MTK_FUNCTION(7, "DBG_MON_A29") + ), + MTK_PIN( + 49, "GPIO49", + MTK_EINT_FUNCTION(0, 49), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO49"), + MTK_FUNCTION(1, "SDA5"), + MTK_FUNCTION(7, "DBG_MON_A30") + ), + MTK_PIN( + 50, "GPIO50", + MTK_EINT_FUNCTION(0, 50), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO50"), + MTK_FUNCTION(1, "SCL3"), + MTK_FUNCTION(2, "URXD1"), + MTK_FUNCTION(3, "MD_URXD1"), + MTK_FUNCTION(4, "SSPM_URXD_AO"), + MTK_FUNCTION(5, "IDDIG"), + MTK_FUNCTION(6, "TP_URXD1_AO"), + MTK_FUNCTION(7, "DBG_MON_A31") + ), + MTK_PIN( + 51, "GPIO51", + MTK_EINT_FUNCTION(0, 51), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO51"), + MTK_FUNCTION(1, "SDA3"), + MTK_FUNCTION(2, "UTXD1"), + MTK_FUNCTION(3, "MD_UTXD1"), + MTK_FUNCTION(4, "SSPM_UTXD_AO"), + MTK_FUNCTION(5, "USB_DRVVBUS"), + MTK_FUNCTION(6, "TP_UTXD1_AO"), + MTK_FUNCTION(7, "DBG_MON_A32") + ), + MTK_PIN( + 52, "GPIO52", + MTK_EINT_FUNCTION(0, 52), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO52"), + MTK_FUNCTION(1, "BPI_BUS15") + ), + MTK_PIN( + 53, "GPIO53", + MTK_EINT_FUNCTION(0, 53), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO53"), + MTK_FUNCTION(1, "BPI_BUS13") + ), + MTK_PIN( + 54, "GPIO54", + MTK_EINT_FUNCTION(0, 54), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO54"), + MTK_FUNCTION(1, "BPI_BUS12") + ), + MTK_PIN( + 55, "GPIO55", + MTK_EINT_FUNCTION(0, 55), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO55"), + MTK_FUNCTION(1, "BPI_BUS8") + ), + MTK_PIN( + 56, "GPIO56", + MTK_EINT_FUNCTION(0, 56), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO56"), + MTK_FUNCTION(1, "BPI_BUS9"), + MTK_FUNCTION(2, "SCL_6306") + ), + MTK_PIN( + 57, "GPIO57", + MTK_EINT_FUNCTION(0, 57), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO57"), + MTK_FUNCTION(1, "BPI_BUS10"), + MTK_FUNCTION(2, "SDA_6306") + ), + MTK_PIN( + 58, "GPIO58", + MTK_EINT_FUNCTION(0, 58), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO58"), + MTK_FUNCTION(1, "RFIC0_BSI_D2") + ), + MTK_PIN( + 59, "GPIO59", + MTK_EINT_FUNCTION(0, 59), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO59"), + MTK_FUNCTION(1, "RFIC0_BSI_D1") + ), + MTK_PIN( + 60, "GPIO60", + MTK_EINT_FUNCTION(0, 60), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO60"), + MTK_FUNCTION(1, "RFIC0_BSI_D0") + ), + MTK_PIN( + 61, "GPIO61", + MTK_EINT_FUNCTION(0, 61), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO61"), + MTK_FUNCTION(1, "MIPI1_SDATA") + ), + MTK_PIN( + 62, "GPIO62", + MTK_EINT_FUNCTION(0, 62), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO62"), + MTK_FUNCTION(1, "MIPI1_SCLK") + ), + MTK_PIN( + 63, "GPIO63", + MTK_EINT_FUNCTION(0, 63), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO63"), + MTK_FUNCTION(1, "MIPI0_SDATA") + ), + MTK_PIN( + 64, "GPIO64", + MTK_EINT_FUNCTION(0, 64), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO64"), + MTK_FUNCTION(1, "MIPI0_SCLK") + ), + MTK_PIN( + 65, "GPIO65", + MTK_EINT_FUNCTION(0, 65), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO65"), + MTK_FUNCTION(1, "MIPI3_SDATA"), + MTK_FUNCTION(2, "BPI_BUS16") + ), + MTK_PIN( + 66, "GPIO66", + MTK_EINT_FUNCTION(0, 66), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO66"), + MTK_FUNCTION(1, "MIPI3_SCLK"), + MTK_FUNCTION(2, "BPI_BUS17") + ), + MTK_PIN( + 67, "GPIO67", + MTK_EINT_FUNCTION(0, 67), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO67"), + MTK_FUNCTION(1, "MIPI2_SDATA") + ), + MTK_PIN( + 68, "GPIO68", + MTK_EINT_FUNCTION(0, 68), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO68"), + MTK_FUNCTION(1, "MIPI2_SCLK") + ), + MTK_PIN( + 69, "GPIO69", + MTK_EINT_FUNCTION(0, 69), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO69"), + MTK_FUNCTION(1, "BPI_BUS7") + ), + MTK_PIN( + 70, "GPIO70", + MTK_EINT_FUNCTION(0, 70), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO70"), + MTK_FUNCTION(1, "BPI_BUS6") + ), + MTK_PIN( + 71, "GPIO71", + MTK_EINT_FUNCTION(0, 71), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO71"), + MTK_FUNCTION(1, "BPI_BUS5") + ), + MTK_PIN( + 72, "GPIO72", + MTK_EINT_FUNCTION(0, 72), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO72"), + MTK_FUNCTION(1, "BPI_BUS4") + ), + MTK_PIN( + 73, "GPIO73", + MTK_EINT_FUNCTION(0, 73), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO73"), + MTK_FUNCTION(1, "BPI_BUS3") + ), + MTK_PIN( + 74, "GPIO74", + MTK_EINT_FUNCTION(0, 74), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO74"), + MTK_FUNCTION(1, "BPI_BUS2") + ), + MTK_PIN( + 75, "GPIO75", + MTK_EINT_FUNCTION(0, 75), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO75"), + MTK_FUNCTION(1, "BPI_BUS1") + ), + MTK_PIN( + 76, "GPIO76", + MTK_EINT_FUNCTION(0, 76), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO76"), + MTK_FUNCTION(1, "BPI_BUS0") + ), + MTK_PIN( + 77, "GPIO77", + MTK_EINT_FUNCTION(0, 77), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO77"), + MTK_FUNCTION(1, "BPI_BUS14") + ), + MTK_PIN( + 78, "GPIO78", + MTK_EINT_FUNCTION(0, 78), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO78"), + MTK_FUNCTION(1, "BPI_BUS11") + ), + MTK_PIN( + 79, "GPIO79", + MTK_EINT_FUNCTION(0, 79), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO79"), + MTK_FUNCTION(1, "BPI_PA_VM1"), + MTK_FUNCTION(2, "MIPI4_SDATA") + ), + MTK_PIN( + 80, "GPIO80", + MTK_EINT_FUNCTION(0, 80), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO80"), + MTK_FUNCTION(1, "BPI_PA_VM0"), + MTK_FUNCTION(2, "MIPI4_SCLK") + ), + MTK_PIN( + 81, "GPIO81", + MTK_EINT_FUNCTION(0, 81), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO81"), + MTK_FUNCTION(1, "SDA1"), + MTK_FUNCTION(7, "DBG_MON_B0") + ), + MTK_PIN( + 82, "GPIO82", + MTK_EINT_FUNCTION(0, 82), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO82"), + MTK_FUNCTION(1, "SDA0"), + MTK_FUNCTION(7, "DBG_MON_B1") + ), + MTK_PIN( + 83, "GPIO83", + MTK_EINT_FUNCTION(0, 83), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO83"), + MTK_FUNCTION(1, "SCL0"), + MTK_FUNCTION(7, "DBG_MON_B2") + ), + MTK_PIN( + 84, "GPIO84", + MTK_EINT_FUNCTION(0, 84), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO84"), + MTK_FUNCTION(1, "SCL1"), + MTK_FUNCTION(7, "DBG_MON_B3") + ), + MTK_PIN( + 85, "GPIO85", + MTK_EINT_FUNCTION(0, 85), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO85"), + MTK_FUNCTION(1, "RFIC0_BSI_EN") + ), + MTK_PIN( + 86, "GPIO86", + MTK_EINT_FUNCTION(0, 86), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO86"), + MTK_FUNCTION(1, "RFIC0_BSI_CK") + ), + MTK_PIN( + 87, "GPIO87", + MTK_EINT_FUNCTION(0, 87), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO87"), + MTK_FUNCTION(2, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(3, "CMVREF0"), + MTK_FUNCTION(4, "MD_URXD0"), + MTK_FUNCTION(5, "AGPS_SYNC"), + MTK_FUNCTION(6, "EXT_FRAME_SYNC") + ), + MTK_PIN( + 88, "GPIO88", + MTK_EINT_FUNCTION(0, 88), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO88"), + MTK_FUNCTION(1, "CMMCLK3"), + MTK_FUNCTION(2, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(3, "CMVREF1"), + MTK_FUNCTION(4, "MD_UTXD0"), + MTK_FUNCTION(5, "AGPS_SYNC"), + MTK_FUNCTION(6, "DVFSRC_EXT_REQ") + ), + MTK_PIN( + 89, "GPIO89", + MTK_EINT_FUNCTION(0, 89), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO89"), + MTK_FUNCTION(1, "SRCLKENAI0"), + MTK_FUNCTION(2, "PWM2"), + MTK_FUNCTION(3, "MD_INT0"), + MTK_FUNCTION(4, "USB_DRVVBUS"), + MTK_FUNCTION(5, "SCL_6306"), + MTK_FUNCTION(6, "TP_GPIO4_AO"), + MTK_FUNCTION(7, "DBG_MON_B21") + ), + MTK_PIN( + 90, "GPIO90", + MTK_EINT_FUNCTION(0, 90), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO90"), + MTK_FUNCTION(1, "URXD1"), + MTK_FUNCTION(2, "PWM0"), + MTK_FUNCTION(3, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(4, "ANT_SEL4"), + MTK_FUNCTION(5, "USB_DRVVBUS"), + MTK_FUNCTION(6, "I2S2_BCK"), + MTK_FUNCTION(7, "DBG_MON_B4") + ), + MTK_PIN( + 91, "GPIO91", + MTK_EINT_FUNCTION(0, 91), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO91"), + MTK_FUNCTION(1, "KPROW1"), + MTK_FUNCTION(2, "PWM2"), + MTK_FUNCTION(3, "MD_INT0"), + MTK_FUNCTION(4, "ANT_SEL5"), + MTK_FUNCTION(5, "IDDIG"), + MTK_FUNCTION(6, "I2S2_LRCK"), + MTK_FUNCTION(7, "DBG_MON_B5") + ), + MTK_PIN( + 92, "GPIO92", + MTK_EINT_FUNCTION(0, 92), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO92"), + MTK_FUNCTION(1, "KPROW0"), + MTK_FUNCTION(5, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(6, "I2S2_DI"), + MTK_FUNCTION(7, "DBG_MON_B6") + ), + MTK_PIN( + 93, "GPIO93", + MTK_EINT_FUNCTION(0, 93), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO93"), + MTK_FUNCTION(1, "KPCOL0"), + MTK_FUNCTION(7, "DBG_MON_B7") + ), + MTK_PIN( + 94, "GPIO94", + MTK_EINT_FUNCTION(0, 94), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO94"), + MTK_FUNCTION(1, "KPCOL1"), + MTK_FUNCTION(5, "CMFLASH"), + MTK_FUNCTION(6, "CMVREF0"), + MTK_FUNCTION(7, "DBG_MON_B8") + ), + MTK_PIN( + 95, "GPIO95", + MTK_EINT_FUNCTION(0, 95), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO95"), + MTK_FUNCTION(1, "URXD0"), + MTK_FUNCTION(2, "UTXD0"), + MTK_FUNCTION(3, "MD_URXD0"), + MTK_FUNCTION(4, "PTA_RXD"), + MTK_FUNCTION(5, "SSPM_URXD_AO"), + MTK_FUNCTION(6, "WIFI_RXD") + ), + MTK_PIN( + 96, "GPIO96", + MTK_EINT_FUNCTION(0, 96), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO96"), + MTK_FUNCTION(1, "UTXD0"), + MTK_FUNCTION(2, "URXD0"), + MTK_FUNCTION(3, "MD_UTXD0"), + MTK_FUNCTION(4, "PTA_TXD"), + MTK_FUNCTION(5, "SSPM_UTXD_AO"), + MTK_FUNCTION(6, "WIFI_TXD") + ), + MTK_PIN( + 97, "GPIO97", + MTK_EINT_FUNCTION(0, 97), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO97"), + MTK_FUNCTION(1, "UCTS0"), + MTK_FUNCTION(2, "I2S1_MCK"), + MTK_FUNCTION(3, "CONN_MCU_TDO"), + MTK_FUNCTION(4, "SPI5_MI"), + MTK_FUNCTION(5, "SCL_6306"), + MTK_FUNCTION(6, "MCUPM_JTAG_TDO"), + MTK_FUNCTION(7, "DBG_MON_B15") + ), + MTK_PIN( + 98, "GPIO98", + MTK_EINT_FUNCTION(0, 98), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO98"), + MTK_FUNCTION(1, "URTS0"), + MTK_FUNCTION(2, "I2S1_BCK"), + MTK_FUNCTION(3, "CONN_MCU_TMS"), + MTK_FUNCTION(4, "SPI5_CSB"), + MTK_FUNCTION(6, "MCUPM_JTAG_TMS"), + MTK_FUNCTION(7, "DBG_MON_B16") + ), + MTK_PIN( + 99, "GPIO99", + MTK_EINT_FUNCTION(0, 99), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO99"), + MTK_FUNCTION(1, "CMMCLK0"), + MTK_FUNCTION(4, "AUXIF_CLK"), + MTK_FUNCTION(5, "PTA_RXD"), + MTK_FUNCTION(6, "CONN_UART0_RXD"), + MTK_FUNCTION(7, "DBG_MON_B17") + ), + + MTK_PIN( + 100, "GPIO100", + MTK_EINT_FUNCTION(0, 100), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO100"), + MTK_FUNCTION(1, "CMMCLK1"), + MTK_FUNCTION(4, "AUXIF_ST"), + MTK_FUNCTION(5, "PTA_TXD"), + MTK_FUNCTION(6, "CONN_UART0_TXD"), + MTK_FUNCTION(7, "DBG_MON_B18") + ), + MTK_PIN( + 101, "GPIO101", + MTK_EINT_FUNCTION(0, 101), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO101"), + MTK_FUNCTION(1, "CMFLASH"), + MTK_FUNCTION(2, "I2S1_LRCK"), + MTK_FUNCTION(3, "CONN_MCU_TCK"), + MTK_FUNCTION(4, "SPI5_MO"), + MTK_FUNCTION(6, "MCUPM_JTAG_TCK"), + MTK_FUNCTION(7, "DBG_MON_B19") + ), + MTK_PIN( + 102, "GPIO102", + MTK_EINT_FUNCTION(0, 102), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO102"), + MTK_FUNCTION(1, "CMVREF0"), + MTK_FUNCTION(2, "I2S1_DO"), + MTK_FUNCTION(3, "CONN_MCU_TDI"), + MTK_FUNCTION(4, "SPI5_CLK"), + MTK_FUNCTION(5, "AGPS_SYNC"), + MTK_FUNCTION(6, "MCUPM_JTAG_TDI"), + MTK_FUNCTION(7, "DBG_MON_B20") + ), + MTK_PIN( + 103, "GPIO103", + MTK_EINT_FUNCTION(0, 103), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO103"), + MTK_FUNCTION(1, "SCL2"), + MTK_FUNCTION(2, "TP_UTXD1_AO"), + MTK_FUNCTION(3, "MD_UTXD0"), + MTK_FUNCTION(4, "MD_UTXD1"), + MTK_FUNCTION(5, "TP_URTS2_AO"), + MTK_FUNCTION(6, "WIFI_TXD"), + MTK_FUNCTION(7, "DBG_MON_B25") + ), + MTK_PIN( + 104, "GPIO104", + MTK_EINT_FUNCTION(0, 104), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO104"), + MTK_FUNCTION(1, "SDA2"), + MTK_FUNCTION(2, "TP_URXD1_AO"), + MTK_FUNCTION(3, "MD_URXD0"), + MTK_FUNCTION(4, "MD_URXD1"), + MTK_FUNCTION(5, "TP_UCTS2_AO"), + MTK_FUNCTION(6, "WIFI_RXD"), + MTK_FUNCTION(7, "DBG_MON_B26") + ), + MTK_PIN( + 105, "GPIO105", + MTK_EINT_FUNCTION(0, 105), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO105"), + MTK_FUNCTION(1, "SCL4"), + MTK_FUNCTION(3, "MD_UTXD1"), + MTK_FUNCTION(4, "MD_UTXD0"), + MTK_FUNCTION(5, "TP_UTXD2_AO"), + MTK_FUNCTION(6, "PTA_TXD"), + MTK_FUNCTION(7, "DBG_MON_B27") + ), + MTK_PIN( + 106, "GPIO106", + MTK_EINT_FUNCTION(0, 106), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO106"), + MTK_FUNCTION(1, "SDA4"), + MTK_FUNCTION(3, "MD_URXD1"), + MTK_FUNCTION(4, "MD_URXD0"), + MTK_FUNCTION(5, "TP_URXD2_AO"), + MTK_FUNCTION(6, "PTA_RXD"), + MTK_FUNCTION(7, "DBG_MON_B28") + ), + MTK_PIN( + 107, "GPIO107", + MTK_EINT_FUNCTION(0, 107), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO107"), + MTK_FUNCTION(1, "UTXD1"), + MTK_FUNCTION(2, "MD_UTXD0"), + MTK_FUNCTION(3, "SDA_6306"), + MTK_FUNCTION(4, "KPCOL3"), + MTK_FUNCTION(5, "CMVREF0"), + MTK_FUNCTION(6, "URTS0"), + MTK_FUNCTION(7, "DBG_MON_B29") + ), + MTK_PIN( + 108, "GPIO108", + MTK_EINT_FUNCTION(0, 108), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO108"), + MTK_FUNCTION(1, "CMMCLK2"), + MTK_FUNCTION(2, "MD_INT0"), + MTK_FUNCTION(3, "CONN_MCU_DBGACK_N"), + MTK_FUNCTION(4, "KPCOL4"), + MTK_FUNCTION(6, "I2S3_MCK"), + MTK_FUNCTION(7, "DBG_MON_B30") + ), + MTK_PIN( + 109, "GPIO109", + MTK_EINT_FUNCTION(0, 109), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO109"), + MTK_FUNCTION(1, "URXD1"), + MTK_FUNCTION(2, "MD_URXD0"), + MTK_FUNCTION(3, "ANT_SEL7"), + MTK_FUNCTION(4, "KPCOL5"), + MTK_FUNCTION(5, "CMVREF1"), + MTK_FUNCTION(6, "UCTS0"), + MTK_FUNCTION(7, "DBG_MON_B31") + ), + MTK_PIN( + 110, "GPIO110", + MTK_EINT_FUNCTION(0, 110), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO110"), + MTK_FUNCTION(1, "ANT_SEL0"), + MTK_FUNCTION(2, "CLKM0"), + MTK_FUNCTION(3, "PWM3"), + MTK_FUNCTION(4, "MD_INT0"), + MTK_FUNCTION(5, "IDDIG"), + MTK_FUNCTION(6, "I2S3_BCK"), + MTK_FUNCTION(7, "DBG_MON_B13") + ), + MTK_PIN( + 111, "GPIO111", + MTK_EINT_FUNCTION(0, 111), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO111"), + MTK_FUNCTION(1, "ANT_SEL1"), + MTK_FUNCTION(2, "CLKM1"), + MTK_FUNCTION(3, "PWM4"), + MTK_FUNCTION(4, "PTA_RXD"), + MTK_FUNCTION(5, "CMVREF0"), + MTK_FUNCTION(6, "I2S3_LRCK"), + MTK_FUNCTION(7, "DBG_MON_B14") + ), + MTK_PIN( + 112, "GPIO112", + MTK_EINT_FUNCTION(0, 112), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO112"), + MTK_FUNCTION(1, "ANT_SEL2"), + MTK_FUNCTION(2, "CLKM2"), + MTK_FUNCTION(3, "PWM5"), + MTK_FUNCTION(4, "PTA_TXD"), + MTK_FUNCTION(5, "CMVREF1"), + MTK_FUNCTION(6, "I2S3_DO") + ), + MTK_PIN( + 113, "GPIO113", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO113"), + MTK_FUNCTION(1, "CONN_TOP_CLK") + ), + MTK_PIN( + 114, "GPIO114", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO114"), + MTK_FUNCTION(1, "CONN_TOP_DATA") + ), + MTK_PIN( + 115, "GPIO115", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO115"), + MTK_FUNCTION(1, "CONN_BT_CLK") + ), + MTK_PIN( + 116, "GPIO116", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO116"), + MTK_FUNCTION(1, "CONN_BT_DATA") + ), + MTK_PIN( + 117, "GPIO117", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO117"), + MTK_FUNCTION(1, "CONN_WF_CTRL0") + ), + MTK_PIN( + 118, "GPIO118", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO118"), + MTK_FUNCTION(1, "CONN_WF_CTRL1") + ), + MTK_PIN( + 119, "GPIO119", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO119"), + MTK_FUNCTION(1, "CONN_WF_CTRL2") + ), + MTK_PIN( + 120, "GPIO120", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO120"), + MTK_FUNCTION(1, "CONN_WB_PTA") + ), + MTK_PIN( + 121, "GPIO121", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO121"), + MTK_FUNCTION(1, "CONN_HRST_B") + ), + MTK_PIN( + 122, "GPIO122", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO122"), + MTK_FUNCTION(1, "MSDC0_CMD"), + MTK_FUNCTION(2, "MSDC0_CMD") + ), + MTK_PIN( + 123, "GPIO123", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO123"), + MTK_FUNCTION(1, "MSDC0_DAT0"), + MTK_FUNCTION(2, "MSDC0_DAT4") + ), + MTK_PIN( + 124, "GPIO124", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO124"), + MTK_FUNCTION(1, "MSDC0_CLK"), + MTK_FUNCTION(2, "MSDC0_CLK") + ), + MTK_PIN( + 125, "GPIO125", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO125"), + MTK_FUNCTION(1, "MSDC0_DAT2"), + MTK_FUNCTION(2, "MSDC0_DAT5") + ), + MTK_PIN( + 126, "GPIO126", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO126"), + MTK_FUNCTION(1, "MSDC0_DAT4"), + MTK_FUNCTION(2, "MSDC0_DAT2") + ), + MTK_PIN( + 127, "GPIO127", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO127"), + MTK_FUNCTION(1, "MSDC0_DAT6"), + MTK_FUNCTION(2, "MSDC0_DAT1") + ), + MTK_PIN( + 128, "GPIO128", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO128"), + MTK_FUNCTION(1, "MSDC0_DAT1"), + MTK_FUNCTION(2, "MSDC0_DAT6") + ), + MTK_PIN( + 129, "GPIO129", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO129"), + MTK_FUNCTION(1, "MSDC0_DAT5"), + MTK_FUNCTION(2, "MSDC0_DAT0") + ), + MTK_PIN( + 130, "GPIO130", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO130"), + MTK_FUNCTION(1, "MSDC0_DAT7"), + MTK_FUNCTION(2, "MSDC0_DAT7") + ), + MTK_PIN( + 131, "GPIO131", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO131"), + MTK_FUNCTION(1, "MSDC0_DSL"), + MTK_FUNCTION(2, "MSDC0_DSL") + ), + MTK_PIN( + 132, "GPIO132", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO132"), + MTK_FUNCTION(1, "MSDC0_DAT3"), + MTK_FUNCTION(2, "MSDC0_DAT3") + ), + MTK_PIN( + 133, "GPIO133", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO133"), + MTK_FUNCTION(1, "MSDC0_RSTB"), + MTK_FUNCTION(2, "MSDC0_RSTB") + ), + MTK_PIN( + 134, "GPIO134", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO134"), + MTK_FUNCTION(1, "RTC32K_CK") + ), + MTK_PIN( + 135, "GPIO135", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO135"), + MTK_FUNCTION(1, "WATCHDOG") + ), + MTK_PIN( + 136, "GPIO136", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO136"), + MTK_FUNCTION(1, "AUD_CLK_MOSI"), + MTK_FUNCTION(2, "AUD_CLK_MISO"), + MTK_FUNCTION(3, "I2S1_MCK") + ), + MTK_PIN( + 137, "GPIO137", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO137"), + MTK_FUNCTION(1, "AUD_SYNC_MOSI"), + MTK_FUNCTION(2, "AUD_SYNC_MISO"), + MTK_FUNCTION(3, "I2S1_BCK") + ), + MTK_PIN( + 138, "GPIO138", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO138"), + MTK_FUNCTION(1, "AUD_DAT_MOSI0"), + MTK_FUNCTION(2, "AUD_DAT_MISO0"), + MTK_FUNCTION(3, "I2S1_LRCK") + ), + MTK_PIN( + 139, "GPIO139", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO139"), + MTK_FUNCTION(1, "AUD_DAT_MOSI1"), + MTK_FUNCTION(2, "AUD_DAT_MISO1"), + MTK_FUNCTION(3, "I2S1_DO") + ), + MTK_PIN( + 140, "GPIO140", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO140"), + MTK_FUNCTION(1, "AUD_CLK_MISO"), + MTK_FUNCTION(2, "AUD_CLK_MOSI"), + MTK_FUNCTION(3, "I2S2_MCK") + ), + MTK_PIN( + 141, "GPIO141", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO141"), + MTK_FUNCTION(1, "AUD_SYNC_MISO"), + MTK_FUNCTION(2, "AUD_SYNC_MOSI"), + MTK_FUNCTION(3, "I2S2_BCK") + ), + MTK_PIN( + 142, "GPIO142", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO142"), + MTK_FUNCTION(1, "AUD_DAT_MISO0"), + MTK_FUNCTION(2, "AUD_DAT_MOSI0"), + MTK_FUNCTION(3, "I2S2_LRCK") + ), + MTK_PIN( + 143, "GPIO143", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO143"), + MTK_FUNCTION(1, "AUD_DAT_MISO1"), + MTK_FUNCTION(2, "AUD_DAT_MOSI1"), + MTK_FUNCTION(3, "I2S2_DI") + ), + MTK_PIN( + 144, "GPIO144", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO144"), + MTK_FUNCTION(1, "PWRAP_SPI0_MI"), + MTK_FUNCTION(2, "PWRAP_SPI0_MO") + ), + MTK_PIN( + 145, "GPIO145", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO145"), + MTK_FUNCTION(1, "PWRAP_SPI0_CSN") + ), + MTK_PIN( + 146, "GPIO146", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO146"), + MTK_FUNCTION(1, "PWRAP_SPI0_MO"), + MTK_FUNCTION(2, "PWRAP_SPI0_MI") + ), + MTK_PIN( + 147, "GPIO147", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO147"), + MTK_FUNCTION(1, "PWRAP_SPI0_CK") + ), + MTK_PIN( + 148, "GPIO148", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO148"), + MTK_FUNCTION(1, "SRCLKENA0") + ), + MTK_PIN( + 149, "GPIO149", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO149"), + MTK_FUNCTION(1, "SRCLKENA1") + ), + MTK_PIN( + 150, "GPIO150", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO150"), + MTK_FUNCTION(1, "PWM0"), + MTK_FUNCTION(2, "CMFLASH"), + MTK_FUNCTION(3, "ANT_SEL3"), + MTK_FUNCTION(5, "MD_URXD0"), + MTK_FUNCTION(6, "TP_URXD2_AO") + ), + MTK_PIN( + 151, "GPIO151", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO151"), + MTK_FUNCTION(1, "PWM1"), + MTK_FUNCTION(2, "CMVREF0"), + MTK_FUNCTION(3, "ANT_SEL4"), + MTK_FUNCTION(5, "MD_UTXD0"), + MTK_FUNCTION(6, "TP_UTXD2_AO") + ), + MTK_PIN( + 152, "GPIO152", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO152"), + MTK_FUNCTION(1, "PWM2"), + MTK_FUNCTION(2, "CMVREF1"), + MTK_FUNCTION(3, "ANT_SEL5"), + MTK_FUNCTION(5, "MD_URXD1"), + MTK_FUNCTION(6, "TP_UCTS1_AO") + ), + MTK_PIN( + 153, "GPIO153", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO153"), + MTK_FUNCTION(1, "PWM3"), + MTK_FUNCTION(2, "CLKM0"), + MTK_FUNCTION(3, "ANT_SEL6"), + MTK_FUNCTION(5, "MD_UTXD1"), + MTK_FUNCTION(6, "TP_URTS1_AO") + ), + MTK_PIN( + 154, "GPIO154", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO154"), + MTK_FUNCTION(1, "PWM5"), + MTK_FUNCTION(2, "CLKM2"), + MTK_FUNCTION(3, "USB_DRVVBUS"), + MTK_FUNCTION(5, "PTA_TXD"), + MTK_FUNCTION(6, "CONN_UART0_TXD") + ), + MTK_PIN( + 155, "GPIO155", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO155"), + MTK_FUNCTION(1, "SPI0_MI"), + MTK_FUNCTION(2, "IDDIG"), + MTK_FUNCTION(3, "AGPS_SYNC"), + MTK_FUNCTION(4, "TP_GPIO0_AO"), + MTK_FUNCTION(5, "MFG_JTAG_TDO"), + MTK_FUNCTION(6, "DFD_TDO"), + MTK_FUNCTION(7, "JTDO_SEL1") + ), + MTK_PIN( + 156, "GPIO156", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO156"), + MTK_FUNCTION(1, "SPI0_CSB"), + MTK_FUNCTION(2, "USB_DRVVBUS"), + MTK_FUNCTION(3, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(4, "TP_GPIO1_AO"), + MTK_FUNCTION(5, "MFG_JTAG_TMS"), + MTK_FUNCTION(6, "DFD_TMS"), + MTK_FUNCTION(7, "JTMS_SEL1") + ), + MTK_PIN( + 157, "GPIO157", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO157"), + MTK_FUNCTION(1, "SPI0_MO"), + MTK_FUNCTION(2, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(3, "CLKM0"), + MTK_FUNCTION(4, "TP_GPIO2_AO"), + MTK_FUNCTION(5, "MFG_JTAG_TDI"), + MTK_FUNCTION(6, "DFD_TDI"), + MTK_FUNCTION(7, "JTDI_SEL1") + ), + MTK_PIN( + 158, "GPIO158", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO158"), + MTK_FUNCTION(1, "SPI0_CLK"), + MTK_FUNCTION(2, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(3, "EXT_FRAME_SYNC"), + MTK_FUNCTION(4, "TP_GPIO3_AO"), + MTK_FUNCTION(5, "MFG_JTAG_TCK"), + MTK_FUNCTION(6, "DFD_TCK_XI"), + MTK_FUNCTION(7, "JTCK_SEL1") + ), + MTK_PIN( + 159, "GPIO159", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO159"), + MTK_FUNCTION(1, "PWM4"), + MTK_FUNCTION(2, "CLKM1"), + MTK_FUNCTION(3, "ANT_SEL7"), + MTK_FUNCTION(5, "PTA_RXD"), + MTK_FUNCTION(6, "CONN_UART0_RXD") + ), + MTK_PIN( + 160, "GPIO160", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO160"), + MTK_FUNCTION(1, "CLKM0"), + MTK_FUNCTION(2, "PWM2"), + MTK_FUNCTION(3, "EXT_FRAME_SYNC"), + MTK_FUNCTION(4, "TP_GPIO5_AO"), + MTK_FUNCTION(5, "AGPS_SYNC"), + MTK_FUNCTION(6, "DVFSRC_EXT_REQ") + ), + MTK_PIN( + 161, "GPIO161", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO161"), + MTK_FUNCTION(1, "SCL6"), + MTK_FUNCTION(2, "SCL_6306"), + MTK_FUNCTION(3, "TP_GPIO6_AO"), + MTK_FUNCTION(4, "KPCOL6"), + MTK_FUNCTION(5, "PTA_RXD"), + MTK_FUNCTION(6, "CONN_UART0_RXD") + ), + MTK_PIN( + 162, "GPIO162", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO162"), + MTK_FUNCTION(1, "SDA6"), + MTK_FUNCTION(2, "SDA_6306"), + MTK_FUNCTION(3, "TP_GPIO7_AO"), + MTK_FUNCTION(4, "KPCOL7"), + MTK_FUNCTION(5, "PTA_TXD"), + MTK_FUNCTION(6, "CONN_UART0_TXD") + ), + MTK_PIN( + 163, "GPIO163", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO163") + ), + MTK_PIN( + 164, "GPIO164", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO164") + ), + MTK_PIN( + 165, "GPIO165", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO165") + ), + MTK_PIN( + 166, "GPIO166", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO166") + ), + MTK_PIN( + 167, "GPIO167", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO167") + ), + MTK_PIN( + 168, "GPIO168", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO168") + ), + MTK_PIN( + 169, "GPIO169", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO169") + ), + MTK_PIN( + 170, "GPIO170", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO170") + ), + MTK_PIN( + 171, "GPIO171", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO171") + ), + MTK_PIN( + 172, "GPIO172", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO172") + ), + MTK_PIN( + 173, "GPIO173", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO173") + ), + MTK_PIN( + 174, "GPIO174", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO174") + ), + MTK_PIN( + 175, "GPIO175", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO175") + ), + MTK_PIN( + 176, "GPIO176", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO176") + ), + MTK_PIN( + 177, "GPIO177", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO177") + ), + MTK_PIN( + 178, "GPIO178", + MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO178") + ), + MTK_PIN( + 179, "GPIO179", + MTK_EINT_FUNCTION(0, 151), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO179") + ), +}; + +#endif /* __PINCTRL_MTK_MT6765_H */ diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8183.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8183.h new file mode 100644 index 000000000000..79adf5b8a186 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8183.h @@ -0,0 +1,1916 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Zhiyong Tao <zhiyong.tao@mediatek.com> + * + */ + +#ifndef __PINCTRL_MTK_MT8183_H +#define __PINCTRL_MTK_MT8183_H + +#include "pinctrl-paris.h" + +static struct mtk_pin_desc mtk_pins_mt8183[] = { + MTK_PIN( + 0, "GPIO0", + MTK_EINT_FUNCTION(0, 0), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO0"), + MTK_FUNCTION(1, "MRG_SYNC"), + MTK_FUNCTION(2, "PCM0_SYNC"), + MTK_FUNCTION(3, "TP_GPIO0_AO"), + MTK_FUNCTION(4, "SRCLKENAI0"), + MTK_FUNCTION(5, "SCP_SPI2_CS"), + MTK_FUNCTION(6, "I2S3_MCK"), + MTK_FUNCTION(7, "SPI2_CSB") + ), + MTK_PIN( + 1, "GPIO1", + MTK_EINT_FUNCTION(0, 1), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO1"), + MTK_FUNCTION(1, "MRG_CLK"), + MTK_FUNCTION(2, "PCM0_CLK"), + MTK_FUNCTION(3, "TP_GPIO1_AO"), + MTK_FUNCTION(4, "CLKM3"), + MTK_FUNCTION(5, "SCP_SPI2_MO"), + MTK_FUNCTION(6, "I2S3_BCK"), + MTK_FUNCTION(7, "SPI2_MO") + ), + MTK_PIN( + 2, "GPIO2", + MTK_EINT_FUNCTION(0, 2), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO2"), + MTK_FUNCTION(1, "MRG_DO"), + MTK_FUNCTION(2, "PCM0_DO"), + MTK_FUNCTION(3, "TP_GPIO2_AO"), + MTK_FUNCTION(4, "SCL6"), + MTK_FUNCTION(5, "SCP_SPI2_CK"), + MTK_FUNCTION(6, "I2S3_LRCK"), + MTK_FUNCTION(7, "SPI2_CLK") + ), + MTK_PIN( + 3, "GPIO3", + MTK_EINT_FUNCTION(0, 3), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO3"), + MTK_FUNCTION(1, "MRG_DI"), + MTK_FUNCTION(2, "PCM0_DI"), + MTK_FUNCTION(3, "TP_GPIO3_AO"), + MTK_FUNCTION(4, "SDA6"), + MTK_FUNCTION(5, "TDM_MCK"), + MTK_FUNCTION(6, "I2S3_DO"), + MTK_FUNCTION(7, "SCP_VREQ_VAO") + ), + MTK_PIN( + 4, "GPIO4", + MTK_EINT_FUNCTION(0, 4), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO4"), + MTK_FUNCTION(1, "PWM_B"), + MTK_FUNCTION(2, "I2S0_MCK"), + MTK_FUNCTION(3, "SSPM_UTXD_AO"), + MTK_FUNCTION(4, "MD_URXD1"), + MTK_FUNCTION(5, "TDM_BCK"), + MTK_FUNCTION(6, "TP_GPIO4_AO"), + MTK_FUNCTION(7, "DAP_MD32_SWD") + ), + MTK_PIN( + 5, "GPIO5", + MTK_EINT_FUNCTION(0, 5), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO5"), + MTK_FUNCTION(1, "PWM_C"), + MTK_FUNCTION(2, "I2S0_BCK"), + MTK_FUNCTION(3, "SSPM_URXD_AO"), + MTK_FUNCTION(4, "MD_UTXD1"), + MTK_FUNCTION(5, "TDM_LRCK"), + MTK_FUNCTION(6, "TP_GPIO5_AO"), + MTK_FUNCTION(7, "DAP_MD32_SWCK") + ), + MTK_PIN( + 6, "GPIO6", + MTK_EINT_FUNCTION(0, 6), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO6"), + MTK_FUNCTION(1, "PWM_A"), + MTK_FUNCTION(2, "I2S0_LRCK"), + MTK_FUNCTION(3, "IDDIG"), + MTK_FUNCTION(4, "MD_URXD0"), + MTK_FUNCTION(5, "TDM_DATA0"), + MTK_FUNCTION(6, "TP_GPIO6_AO"), + MTK_FUNCTION(7, "CMFLASH") + ), + MTK_PIN( + 7, "GPIO7", + MTK_EINT_FUNCTION(0, 7), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO7"), + MTK_FUNCTION(1, "SPI1_B_MI"), + MTK_FUNCTION(2, "I2S0_DI"), + MTK_FUNCTION(3, "USB_DRVVBUS"), + MTK_FUNCTION(4, "MD_UTXD0"), + MTK_FUNCTION(5, "TDM_DATA1"), + MTK_FUNCTION(6, "TP_GPIO7_AO"), + MTK_FUNCTION(7, "DVFSRC_EXT_REQ") + ), + MTK_PIN( + 8, "GPIO8", + MTK_EINT_FUNCTION(0, 8), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO8"), + MTK_FUNCTION(1, "SPI1_B_CSB"), + MTK_FUNCTION(2, "ANT_SEL3"), + MTK_FUNCTION(3, "SCL7"), + MTK_FUNCTION(4, "CONN_MCU_TRST_B"), + MTK_FUNCTION(5, "TDM_DATA2"), + MTK_FUNCTION(6, "MD_INT0"), + MTK_FUNCTION(7, "JTRSTN_SEL1") + ), + MTK_PIN( + 9, "GPIO9", + MTK_EINT_FUNCTION(0, 9), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO9"), + MTK_FUNCTION(1, "SPI1_B_MO"), + MTK_FUNCTION(2, "ANT_SEL4"), + MTK_FUNCTION(3, "CMMCLK2"), + MTK_FUNCTION(4, "CONN_MCU_DBGACK_N"), + MTK_FUNCTION(5, "SSPM_JTAG_TRSTN"), + MTK_FUNCTION(6, "IO_JTAG_TRSTN"), + MTK_FUNCTION(7, "DBG_MON_B10") + ), + MTK_PIN( + 10, "GPIO10", + MTK_EINT_FUNCTION(0, 10), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO10"), + MTK_FUNCTION(1, "SPI1_B_CLK"), + MTK_FUNCTION(2, "ANT_SEL5"), + MTK_FUNCTION(3, "CMMCLK3"), + MTK_FUNCTION(4, "CONN_MCU_DBGI_N"), + MTK_FUNCTION(5, "TDM_DATA3"), + MTK_FUNCTION(6, "EXT_FRAME_SYNC"), + MTK_FUNCTION(7, "DBG_MON_B11") + ), + MTK_PIN( + 11, "GPIO11", + MTK_EINT_FUNCTION(0, 11), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO11"), + MTK_FUNCTION(1, "TP_URXD1_AO"), + MTK_FUNCTION(2, "IDDIG"), + MTK_FUNCTION(3, "SCL6"), + MTK_FUNCTION(4, "UCTS1"), + MTK_FUNCTION(5, "UCTS0"), + MTK_FUNCTION(6, "SRCLKENAI1"), + MTK_FUNCTION(7, "I2S5_MCK") + ), + MTK_PIN( + 12, "GPIO12", + MTK_EINT_FUNCTION(0, 12), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO12"), + MTK_FUNCTION(1, "TP_UTXD1_AO"), + MTK_FUNCTION(2, "USB_DRVVBUS"), + MTK_FUNCTION(3, "SDA6"), + MTK_FUNCTION(4, "URTS1"), + MTK_FUNCTION(5, "URTS0"), + MTK_FUNCTION(6, "I2S2_DI2"), + MTK_FUNCTION(7, "I2S5_BCK") + ), + MTK_PIN( + 13, "GPIO13", + MTK_EINT_FUNCTION(0, 13), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO13"), + MTK_FUNCTION(1, "DBPI_D0"), + MTK_FUNCTION(2, "SPI5_MI"), + MTK_FUNCTION(3, "PCM0_SYNC"), + MTK_FUNCTION(4, "MD_URXD0"), + MTK_FUNCTION(5, "ANT_SEL3"), + MTK_FUNCTION(6, "I2S0_MCK"), + MTK_FUNCTION(7, "DBG_MON_B15") + ), + MTK_PIN( + 14, "GPIO14", + MTK_EINT_FUNCTION(0, 14), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO14"), + MTK_FUNCTION(1, "DBPI_D1"), + MTK_FUNCTION(2, "SPI5_CSB"), + MTK_FUNCTION(3, "PCM0_CLK"), + MTK_FUNCTION(4, "MD_UTXD0"), + MTK_FUNCTION(5, "ANT_SEL4"), + MTK_FUNCTION(6, "I2S0_BCK"), + MTK_FUNCTION(7, "DBG_MON_B16") + ), + MTK_PIN( + 15, "GPIO15", + MTK_EINT_FUNCTION(0, 15), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO15"), + MTK_FUNCTION(1, "DBPI_D2"), + MTK_FUNCTION(2, "SPI5_MO"), + MTK_FUNCTION(3, "PCM0_DO"), + MTK_FUNCTION(4, "MD_URXD1"), + MTK_FUNCTION(5, "ANT_SEL5"), + MTK_FUNCTION(6, "I2S0_LRCK"), + MTK_FUNCTION(7, "DBG_MON_B17") + ), + MTK_PIN( + 16, "GPIO16", + MTK_EINT_FUNCTION(0, 16), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO16"), + MTK_FUNCTION(1, "DBPI_D3"), + MTK_FUNCTION(2, "SPI5_CLK"), + MTK_FUNCTION(3, "PCM0_DI"), + MTK_FUNCTION(4, "MD_UTXD1"), + MTK_FUNCTION(5, "ANT_SEL6"), + MTK_FUNCTION(6, "I2S0_DI"), + MTK_FUNCTION(7, "DBG_MON_B23") + ), + MTK_PIN( + 17, "GPIO17", + MTK_EINT_FUNCTION(0, 17), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO17"), + MTK_FUNCTION(1, "DBPI_D4"), + MTK_FUNCTION(2, "SPI4_MI"), + MTK_FUNCTION(3, "CONN_MCU_TRST_B"), + MTK_FUNCTION(4, "MD_INT0"), + MTK_FUNCTION(5, "ANT_SEL7"), + MTK_FUNCTION(6, "I2S3_MCK"), + MTK_FUNCTION(7, "DBG_MON_A1") + ), + MTK_PIN( + 18, "GPIO18", + MTK_EINT_FUNCTION(0, 18), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO18"), + MTK_FUNCTION(1, "DBPI_D5"), + MTK_FUNCTION(2, "SPI4_CSB"), + MTK_FUNCTION(3, "CONN_MCU_DBGI_N"), + MTK_FUNCTION(4, "MD_INT0"), + MTK_FUNCTION(5, "SCP_VREQ_VAO"), + MTK_FUNCTION(6, "I2S3_BCK"), + MTK_FUNCTION(7, "DBG_MON_A2") + ), + MTK_PIN( + 19, "GPIO19", + MTK_EINT_FUNCTION(0, 19), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO19"), + MTK_FUNCTION(1, "DBPI_D6"), + MTK_FUNCTION(2, "SPI4_MO"), + MTK_FUNCTION(3, "CONN_MCU_TDO"), + MTK_FUNCTION(4, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(5, "URXD1"), + MTK_FUNCTION(6, "I2S3_LRCK"), + MTK_FUNCTION(7, "DBG_MON_A3") + ), + MTK_PIN( + 20, "GPIO20", + MTK_EINT_FUNCTION(0, 20), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO20"), + MTK_FUNCTION(1, "DBPI_D7"), + MTK_FUNCTION(2, "SPI4_CLK"), + MTK_FUNCTION(3, "CONN_MCU_DBGACK_N"), + MTK_FUNCTION(4, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(5, "UTXD1"), + MTK_FUNCTION(6, "I2S3_DO"), + MTK_FUNCTION(7, "DBG_MON_A19") + ), + MTK_PIN( + 21, "GPIO21", + MTK_EINT_FUNCTION(0, 21), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO21"), + MTK_FUNCTION(1, "DBPI_D8"), + MTK_FUNCTION(2, "SPI3_MI"), + MTK_FUNCTION(3, "CONN_MCU_TMS"), + MTK_FUNCTION(4, "DAP_MD32_SWD"), + MTK_FUNCTION(5, "CONN_MCU_AICE_TMSC"), + MTK_FUNCTION(6, "I2S2_MCK"), + MTK_FUNCTION(7, "DBG_MON_B5") + ), + MTK_PIN( + 22, "GPIO22", + MTK_EINT_FUNCTION(0, 22), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO22"), + MTK_FUNCTION(1, "DBPI_D9"), + MTK_FUNCTION(2, "SPI3_CSB"), + MTK_FUNCTION(3, "CONN_MCU_TCK"), + MTK_FUNCTION(4, "DAP_MD32_SWCK"), + MTK_FUNCTION(5, "CONN_MCU_AICE_TCKC"), + MTK_FUNCTION(6, "I2S2_BCK"), + MTK_FUNCTION(7, "DBG_MON_B6") + ), + MTK_PIN( + 23, "GPIO23", + MTK_EINT_FUNCTION(0, 23), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO23"), + MTK_FUNCTION(1, "DBPI_D10"), + MTK_FUNCTION(2, "SPI3_MO"), + MTK_FUNCTION(3, "CONN_MCU_TDI"), + MTK_FUNCTION(4, "UCTS1"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(6, "I2S2_LRCK"), + MTK_FUNCTION(7, "DBG_MON_B7") + ), + MTK_PIN( + 24, "GPIO24", + MTK_EINT_FUNCTION(0, 24), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO24"), + MTK_FUNCTION(1, "DBPI_D11"), + MTK_FUNCTION(2, "SPI3_CLK"), + MTK_FUNCTION(3, "SRCLKENAI0"), + MTK_FUNCTION(4, "URTS1"), + MTK_FUNCTION(5, "IO_JTAG_TCK"), + MTK_FUNCTION(6, "I2S2_DI"), + MTK_FUNCTION(7, "DBG_MON_B31") + ), + MTK_PIN( + 25, "GPIO25", + MTK_EINT_FUNCTION(0, 25), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO25"), + MTK_FUNCTION(1, "DBPI_HSYNC"), + MTK_FUNCTION(2, "ANT_SEL0"), + MTK_FUNCTION(3, "SCL6"), + MTK_FUNCTION(4, "KPCOL2"), + MTK_FUNCTION(5, "IO_JTAG_TMS"), + MTK_FUNCTION(6, "I2S1_MCK"), + MTK_FUNCTION(7, "DBG_MON_B0") + ), + MTK_PIN( + 26, "GPIO26", + MTK_EINT_FUNCTION(0, 26), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO26"), + MTK_FUNCTION(1, "DBPI_VSYNC"), + MTK_FUNCTION(2, "ANT_SEL1"), + MTK_FUNCTION(3, "SDA6"), + MTK_FUNCTION(4, "KPROW2"), + MTK_FUNCTION(5, "IO_JTAG_TDI"), + MTK_FUNCTION(6, "I2S1_BCK"), + MTK_FUNCTION(7, "DBG_MON_B1") + ), + MTK_PIN( + 27, "GPIO27", + MTK_EINT_FUNCTION(0, 27), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO27"), + MTK_FUNCTION(1, "DBPI_DE"), + MTK_FUNCTION(2, "ANT_SEL2"), + MTK_FUNCTION(3, "SCL7"), + MTK_FUNCTION(4, "DMIC_CLK"), + MTK_FUNCTION(5, "IO_JTAG_TDO"), + MTK_FUNCTION(6, "I2S1_LRCK"), + MTK_FUNCTION(7, "DBG_MON_B9") + ), + MTK_PIN( + 28, "GPIO28", + MTK_EINT_FUNCTION(0, 28), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO28"), + MTK_FUNCTION(1, "DBPI_CK"), + MTK_FUNCTION(2, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(3, "SDA7"), + MTK_FUNCTION(4, "DMIC_DAT"), + MTK_FUNCTION(5, "IO_JTAG_TRSTN"), + MTK_FUNCTION(6, "I2S1_DO"), + MTK_FUNCTION(7, "DBG_MON_B32") + ), + MTK_PIN( + 29, "GPIO29", + MTK_EINT_FUNCTION(0, 29), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO29"), + MTK_FUNCTION(1, "MSDC1_CLK"), + MTK_FUNCTION(2, "IO_JTAG_TCK"), + MTK_FUNCTION(3, "UDI_TCK"), + MTK_FUNCTION(4, "CONN_DSP_JCK"), + MTK_FUNCTION(5, "SSPM_JTAG_TCK"), + MTK_FUNCTION(6, "PCM1_CLK"), + MTK_FUNCTION(7, "DBG_MON_A6") + ), + MTK_PIN( + 30, "GPIO30", + MTK_EINT_FUNCTION(0, 30), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO30"), + MTK_FUNCTION(1, "MSDC1_DAT3"), + MTK_FUNCTION(2, "DAP_MD32_SWD"), + MTK_FUNCTION(3, "CONN_MCU_AICE_TMSC"), + MTK_FUNCTION(4, "CONN_DSP_JINTP"), + MTK_FUNCTION(5, "SSPM_JTAG_TRSTN"), + MTK_FUNCTION(6, "PCM1_DI"), + MTK_FUNCTION(7, "DBG_MON_A7") + ), + MTK_PIN( + 31, "GPIO31", + MTK_EINT_FUNCTION(0, 31), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO31"), + MTK_FUNCTION(1, "MSDC1_CMD"), + MTK_FUNCTION(2, "IO_JTAG_TMS"), + MTK_FUNCTION(3, "UDI_TMS"), + MTK_FUNCTION(4, "CONN_DSP_JMS"), + MTK_FUNCTION(5, "SSPM_JTAG_TMS"), + MTK_FUNCTION(6, "PCM1_SYNC"), + MTK_FUNCTION(7, "DBG_MON_A8") + ), + MTK_PIN( + 32, "GPIO32", + MTK_EINT_FUNCTION(0, 32), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO32"), + MTK_FUNCTION(1, "MSDC1_DAT0"), + MTK_FUNCTION(2, "IO_JTAG_TDI"), + MTK_FUNCTION(3, "UDI_TDI"), + MTK_FUNCTION(4, "CONN_DSP_JDI"), + MTK_FUNCTION(5, "SSPM_JTAG_TDI"), + MTK_FUNCTION(6, "PCM1_DO0"), + MTK_FUNCTION(7, "DBG_MON_A9") + ), + MTK_PIN( + 33, "GPIO33", + MTK_EINT_FUNCTION(0, 33), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO33"), + MTK_FUNCTION(1, "MSDC1_DAT2"), + MTK_FUNCTION(2, "IO_JTAG_TRSTN"), + MTK_FUNCTION(3, "UDI_NTRST"), + MTK_FUNCTION(4, "DAP_MD32_SWCK"), + MTK_FUNCTION(5, "CONN_MCU_AICE_TCKC"), + MTK_FUNCTION(6, "PCM1_DO2"), + MTK_FUNCTION(7, "DBG_MON_A10") + ), + MTK_PIN( + 34, "GPIO34", + MTK_EINT_FUNCTION(0, 34), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO34"), + MTK_FUNCTION(1, "MSDC1_DAT1"), + MTK_FUNCTION(2, "IO_JTAG_TDO"), + MTK_FUNCTION(3, "UDI_TDO"), + MTK_FUNCTION(4, "CONN_DSP_JDO"), + MTK_FUNCTION(5, "SSPM_JTAG_TDO"), + MTK_FUNCTION(6, "PCM1_DO1"), + MTK_FUNCTION(7, "DBG_MON_A11") + ), + MTK_PIN( + 35, "GPIO35", + MTK_EINT_FUNCTION(0, 35), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO35"), + MTK_FUNCTION(1, "MD1_SIM2_SIO"), + MTK_FUNCTION(2, "CCU_JTAG_TDO"), + MTK_FUNCTION(3, "MD1_SIM1_SIO"), + MTK_FUNCTION(5, "SCP_JTAG_TDO"), + MTK_FUNCTION(6, "CONN_DSP_JMS"), + MTK_FUNCTION(7, "DBG_MON_A28") + ), + MTK_PIN( + 36, "GPIO36", + MTK_EINT_FUNCTION(0, 36), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO36"), + MTK_FUNCTION(1, "MD1_SIM2_SRST"), + MTK_FUNCTION(2, "CCU_JTAG_TMS"), + MTK_FUNCTION(3, "MD1_SIM1_SRST"), + MTK_FUNCTION(4, "CONN_MCU_AICE_TMSC"), + MTK_FUNCTION(5, "SCP_JTAG_TMS"), + MTK_FUNCTION(6, "CONN_DSP_JINTP"), + MTK_FUNCTION(7, "DBG_MON_A29") + ), + MTK_PIN( + 37, "GPIO37", + MTK_EINT_FUNCTION(0, 37), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO37"), + MTK_FUNCTION(1, "MD1_SIM2_SCLK"), + MTK_FUNCTION(2, "CCU_JTAG_TDI"), + MTK_FUNCTION(3, "MD1_SIM1_SCLK"), + MTK_FUNCTION(5, "SCP_JTAG_TDI"), + MTK_FUNCTION(6, "CONN_DSP_JDO"), + MTK_FUNCTION(7, "DBG_MON_A30") + ), + MTK_PIN( + 38, "GPIO38", + MTK_EINT_FUNCTION(0, 38), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO38"), + MTK_FUNCTION(1, "MD1_SIM1_SCLK"), + MTK_FUNCTION(3, "MD1_SIM2_SCLK"), + MTK_FUNCTION(4, "CONN_MCU_AICE_TCKC"), + MTK_FUNCTION(7, "DBG_MON_A20") + ), + MTK_PIN( + 39, "GPIO39", + MTK_EINT_FUNCTION(0, 39), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO39"), + MTK_FUNCTION(1, "MD1_SIM1_SRST"), + MTK_FUNCTION(2, "CCU_JTAG_TCK"), + MTK_FUNCTION(3, "MD1_SIM2_SRST"), + MTK_FUNCTION(5, "SCP_JTAG_TCK"), + MTK_FUNCTION(6, "CONN_DSP_JCK"), + MTK_FUNCTION(7, "DBG_MON_A31") + ), + MTK_PIN( + 40, "GPIO40", + MTK_EINT_FUNCTION(0, 40), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO40"), + MTK_FUNCTION(1, "MD1_SIM1_SIO"), + MTK_FUNCTION(2, "CCU_JTAG_TRST"), + MTK_FUNCTION(3, "MD1_SIM2_SIO"), + MTK_FUNCTION(5, "SCP_JTAG_TRSTN"), + MTK_FUNCTION(6, "CONN_DSP_JDI"), + MTK_FUNCTION(7, "DBG_MON_A32") + ), + MTK_PIN( + 41, "GPIO41", + MTK_EINT_FUNCTION(0, 41), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO41"), + MTK_FUNCTION(1, "IDDIG"), + MTK_FUNCTION(2, "URXD1"), + MTK_FUNCTION(3, "UCTS0"), + MTK_FUNCTION(4, "SSPM_UTXD_AO"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(6, "DMIC_CLK") + ), + MTK_PIN( + 42, "GPIO42", + MTK_EINT_FUNCTION(0, 42), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO42"), + MTK_FUNCTION(1, "USB_DRVVBUS"), + MTK_FUNCTION(2, "UTXD1"), + MTK_FUNCTION(3, "URTS0"), + MTK_FUNCTION(4, "SSPM_URXD_AO"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(6, "DMIC_DAT") + ), + MTK_PIN( + 43, "GPIO43", + MTK_EINT_FUNCTION(0, 43), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO43"), + MTK_FUNCTION(1, "DISP_PWM") + ), + MTK_PIN( + 44, "GPIO44", + MTK_EINT_FUNCTION(0, 44), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO44"), + MTK_FUNCTION(1, "DSI_TE") + ), + MTK_PIN( + 45, "GPIO45", + MTK_EINT_FUNCTION(0, 45), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO45"), + MTK_FUNCTION(1, "LCM_RST") + ), + MTK_PIN( + 46, "GPIO46", + MTK_EINT_FUNCTION(0, 46), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO46"), + MTK_FUNCTION(1, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(2, "URXD1"), + MTK_FUNCTION(3, "UCTS1"), + MTK_FUNCTION(4, "CCU_UTXD_AO"), + MTK_FUNCTION(5, "TP_UCTS1_AO"), + MTK_FUNCTION(6, "IDDIG"), + MTK_FUNCTION(7, "I2S5_LRCK") + ), + MTK_PIN( + 47, "GPIO47", + MTK_EINT_FUNCTION(0, 47), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO47"), + MTK_FUNCTION(1, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(2, "UTXD1"), + MTK_FUNCTION(3, "URTS1"), + MTK_FUNCTION(4, "CCU_URXD_AO"), + MTK_FUNCTION(5, "TP_URTS1_AO"), + MTK_FUNCTION(6, "USB_DRVVBUS"), + MTK_FUNCTION(7, "I2S5_DO") + ), + MTK_PIN( + 48, "GPIO48", + MTK_EINT_FUNCTION(0, 48), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO48"), + MTK_FUNCTION(1, "SCL5") + ), + MTK_PIN( + 49, "GPIO49", + MTK_EINT_FUNCTION(0, 49), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO49"), + MTK_FUNCTION(1, "SDA5") + ), + MTK_PIN( + 50, "GPIO50", + MTK_EINT_FUNCTION(0, 50), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO50"), + MTK_FUNCTION(1, "SCL3") + ), + MTK_PIN( + 51, "GPIO51", + MTK_EINT_FUNCTION(0, 51), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO51"), + MTK_FUNCTION(1, "SDA3") + ), + MTK_PIN( + 52, "GPIO52", + MTK_EINT_FUNCTION(0, 52), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO52"), + MTK_FUNCTION(1, "BPI_ANT2") + ), + MTK_PIN( + 53, "GPIO53", + MTK_EINT_FUNCTION(0, 53), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO53"), + MTK_FUNCTION(1, "BPI_ANT0") + ), + MTK_PIN( + 54, "GPIO54", + MTK_EINT_FUNCTION(0, 54), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO54"), + MTK_FUNCTION(1, "BPI_OLAT1") + ), + MTK_PIN( + 55, "GPIO55", + MTK_EINT_FUNCTION(0, 55), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO55"), + MTK_FUNCTION(1, "BPI_BUS8") + ), + MTK_PIN( + 56, "GPIO56", + MTK_EINT_FUNCTION(0, 56), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO56"), + MTK_FUNCTION(1, "BPI_BUS9"), + MTK_FUNCTION(2, "SCL_6306") + ), + MTK_PIN( + 57, "GPIO57", + MTK_EINT_FUNCTION(0, 57), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO57"), + MTK_FUNCTION(1, "BPI_BUS10"), + MTK_FUNCTION(2, "SDA_6306") + ), + MTK_PIN( + 58, "GPIO58", + MTK_EINT_FUNCTION(0, 58), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO58"), + MTK_FUNCTION(1, "RFIC0_BSI_D2"), + MTK_FUNCTION(2, "SPM_BSI_D2"), + MTK_FUNCTION(3, "PWM_B") + ), + MTK_PIN( + 59, "GPIO59", + MTK_EINT_FUNCTION(0, 59), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO59"), + MTK_FUNCTION(1, "RFIC0_BSI_D1"), + MTK_FUNCTION(2, "SPM_BSI_D1") + ), + MTK_PIN( + 60, "GPIO60", + MTK_EINT_FUNCTION(0, 60), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO60"), + MTK_FUNCTION(1, "RFIC0_BSI_D0"), + MTK_FUNCTION(2, "SPM_BSI_D0") + ), + MTK_PIN( + 61, "GPIO61", + MTK_EINT_FUNCTION(0, 61), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO61"), + MTK_FUNCTION(1, "MIPI1_SDATA") + ), + MTK_PIN( + 62, "GPIO62", + MTK_EINT_FUNCTION(0, 62), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO62"), + MTK_FUNCTION(1, "MIPI1_SCLK") + ), + MTK_PIN( + 63, "GPIO63", + MTK_EINT_FUNCTION(0, 63), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO63"), + MTK_FUNCTION(1, "MIPI0_SDATA") + ), + MTK_PIN( + 64, "GPIO64", + MTK_EINT_FUNCTION(0, 64), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO64"), + MTK_FUNCTION(1, "MIPI0_SCLK") + ), + MTK_PIN( + 65, "GPIO65", + MTK_EINT_FUNCTION(0, 65), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO65"), + MTK_FUNCTION(1, "MIPI3_SDATA"), + MTK_FUNCTION(2, "BPI_OLAT2") + ), + MTK_PIN( + 66, "GPIO66", + MTK_EINT_FUNCTION(0, 66), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO66"), + MTK_FUNCTION(1, "MIPI3_SCLK"), + MTK_FUNCTION(2, "BPI_OLAT3") + ), + MTK_PIN( + 67, "GPIO67", + MTK_EINT_FUNCTION(0, 67), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO67"), + MTK_FUNCTION(1, "MIPI2_SDATA") + ), + MTK_PIN( + 68, "GPIO68", + MTK_EINT_FUNCTION(0, 68), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO68"), + MTK_FUNCTION(1, "MIPI2_SCLK") + ), + MTK_PIN( + 69, "GPIO69", + MTK_EINT_FUNCTION(0, 69), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO69"), + MTK_FUNCTION(1, "BPI_BUS7") + ), + MTK_PIN( + 70, "GPIO70", + MTK_EINT_FUNCTION(0, 70), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO70"), + MTK_FUNCTION(1, "BPI_BUS6") + ), + MTK_PIN( + 71, "GPIO71", + MTK_EINT_FUNCTION(0, 71), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO71"), + MTK_FUNCTION(1, "BPI_BUS5") + ), + MTK_PIN( + 72, "GPIO72", + MTK_EINT_FUNCTION(0, 72), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO72"), + MTK_FUNCTION(1, "BPI_BUS4") + ), + MTK_PIN( + 73, "GPIO73", + MTK_EINT_FUNCTION(0, 73), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO73"), + MTK_FUNCTION(1, "BPI_BUS3") + ), + MTK_PIN( + 74, "GPIO74", + MTK_EINT_FUNCTION(0, 74), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO74"), + MTK_FUNCTION(1, "BPI_BUS2") + ), + MTK_PIN( + 75, "GPIO75", + MTK_EINT_FUNCTION(0, 75), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO75"), + MTK_FUNCTION(1, "BPI_BUS1") + ), + MTK_PIN( + 76, "GPIO76", + MTK_EINT_FUNCTION(0, 76), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO76"), + MTK_FUNCTION(1, "BPI_BUS0") + ), + MTK_PIN( + 77, "GPIO77", + MTK_EINT_FUNCTION(0, 77), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO77"), + MTK_FUNCTION(1, "BPI_ANT1") + ), + MTK_PIN( + 78, "GPIO78", + MTK_EINT_FUNCTION(0, 78), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO78"), + MTK_FUNCTION(1, "BPI_OLAT0") + ), + MTK_PIN( + 79, "GPIO79", + MTK_EINT_FUNCTION(0, 79), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO79"), + MTK_FUNCTION(1, "BPI_PA_VM1"), + MTK_FUNCTION(2, "MIPI4_SDATA") + ), + MTK_PIN( + 80, "GPIO80", + MTK_EINT_FUNCTION(0, 80), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO80"), + MTK_FUNCTION(1, "BPI_PA_VM0"), + MTK_FUNCTION(2, "MIPI4_SCLK") + ), + MTK_PIN( + 81, "GPIO81", + MTK_EINT_FUNCTION(0, 81), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO81"), + MTK_FUNCTION(1, "SDA1") + ), + MTK_PIN( + 82, "GPIO82", + MTK_EINT_FUNCTION(0, 82), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO82"), + MTK_FUNCTION(1, "SDA0") + ), + MTK_PIN( + 83, "GPIO83", + MTK_EINT_FUNCTION(0, 83), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO83"), + MTK_FUNCTION(1, "SCL0") + ), + MTK_PIN( + 84, "GPIO84", + MTK_EINT_FUNCTION(0, 84), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO84"), + MTK_FUNCTION(1, "SCL1") + ), + MTK_PIN( + 85, "GPIO85", + MTK_EINT_FUNCTION(0, 85), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO85"), + MTK_FUNCTION(1, "SPI0_MI"), + MTK_FUNCTION(2, "SCP_SPI0_MI"), + MTK_FUNCTION(3, "CLKM3"), + MTK_FUNCTION(4, "I2S1_BCK"), + MTK_FUNCTION(5, "MFG_DFD_JTAG_TDO"), + MTK_FUNCTION(6, "DFD_TDO"), + MTK_FUNCTION(7, "JTDO_SEL1") + ), + MTK_PIN( + 86, "GPIO86", + MTK_EINT_FUNCTION(0, 86), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO86"), + MTK_FUNCTION(1, "SPI0_CSB"), + MTK_FUNCTION(2, "SCP_SPI0_CS"), + MTK_FUNCTION(3, "CLKM0"), + MTK_FUNCTION(4, "I2S1_LRCK"), + MTK_FUNCTION(5, "MFG_DFD_JTAG_TMS"), + MTK_FUNCTION(6, "DFD_TMS"), + MTK_FUNCTION(7, "JTMS_SEL1") + ), + MTK_PIN( + 87, "GPIO87", + MTK_EINT_FUNCTION(0, 87), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO87"), + MTK_FUNCTION(1, "SPI0_MO"), + MTK_FUNCTION(2, "SCP_SPI0_MO"), + MTK_FUNCTION(3, "SDA1"), + MTK_FUNCTION(4, "I2S1_DO"), + MTK_FUNCTION(5, "MFG_DFD_JTAG_TDI"), + MTK_FUNCTION(6, "DFD_TDI"), + MTK_FUNCTION(7, "JTDI_SEL1") + ), + MTK_PIN( + 88, "GPIO88", + MTK_EINT_FUNCTION(0, 88), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO88"), + MTK_FUNCTION(1, "SPI0_CLK"), + MTK_FUNCTION(2, "SCP_SPI0_CK"), + MTK_FUNCTION(3, "SCL1"), + MTK_FUNCTION(4, "I2S1_MCK"), + MTK_FUNCTION(5, "MFG_DFD_JTAG_TCK"), + MTK_FUNCTION(6, "DFD_TCK_XI"), + MTK_FUNCTION(7, "JTCK_SEL1") + ), + MTK_PIN( + 89, "GPIO89", + MTK_EINT_FUNCTION(0, 89), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO89"), + MTK_FUNCTION(1, "SRCLKENAI0"), + MTK_FUNCTION(2, "PWM_C"), + MTK_FUNCTION(3, "I2S5_BCK"), + MTK_FUNCTION(4, "ANT_SEL6"), + MTK_FUNCTION(5, "SDA8"), + MTK_FUNCTION(6, "CMVREF0"), + MTK_FUNCTION(7, "DBG_MON_A21") + ), + MTK_PIN( + 90, "GPIO90", + MTK_EINT_FUNCTION(0, 90), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO90"), + MTK_FUNCTION(1, "PWM_A"), + MTK_FUNCTION(2, "CMMCLK2"), + MTK_FUNCTION(3, "I2S5_LRCK"), + MTK_FUNCTION(4, "SCP_VREQ_VAO"), + MTK_FUNCTION(5, "SCL8"), + MTK_FUNCTION(6, "PTA_RXD"), + MTK_FUNCTION(7, "DBG_MON_A22") + ), + MTK_PIN( + 91, "GPIO91", + MTK_EINT_FUNCTION(0, 91), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO91"), + MTK_FUNCTION(1, "KPROW1"), + MTK_FUNCTION(2, "PWM_B"), + MTK_FUNCTION(3, "I2S5_DO"), + MTK_FUNCTION(4, "ANT_SEL7"), + MTK_FUNCTION(5, "CMMCLK3"), + MTK_FUNCTION(6, "PTA_TXD") + ), + MTK_PIN( + 92, "GPIO92", + MTK_EINT_FUNCTION(0, 92), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO92"), + MTK_FUNCTION(1, "KPROW0") + ), + MTK_PIN( + 93, "GPIO93", + MTK_EINT_FUNCTION(0, 93), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO93"), + MTK_FUNCTION(1, "KPCOL0"), + MTK_FUNCTION(7, "DBG_MON_B27") + ), + MTK_PIN( + 94, "GPIO94", + MTK_EINT_FUNCTION(0, 94), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO94"), + MTK_FUNCTION(1, "KPCOL1"), + MTK_FUNCTION(2, "I2S2_DI2"), + MTK_FUNCTION(3, "I2S5_MCK"), + MTK_FUNCTION(4, "CMMCLK2"), + MTK_FUNCTION(5, "SCP_SPI2_MI"), + MTK_FUNCTION(6, "SRCLKENAI1"), + MTK_FUNCTION(7, "SPI2_MI") + ), + MTK_PIN( + 95, "GPIO95", + MTK_EINT_FUNCTION(0, 95), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO95"), + MTK_FUNCTION(1, "URXD0"), + MTK_FUNCTION(2, "UTXD0"), + MTK_FUNCTION(3, "MD_URXD0"), + MTK_FUNCTION(4, "MD_URXD1"), + MTK_FUNCTION(5, "SSPM_URXD_AO"), + MTK_FUNCTION(6, "CCU_URXD_AO") + ), + MTK_PIN( + 96, "GPIO96", + MTK_EINT_FUNCTION(0, 96), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO96"), + MTK_FUNCTION(1, "UTXD0"), + MTK_FUNCTION(2, "URXD0"), + MTK_FUNCTION(3, "MD_UTXD0"), + MTK_FUNCTION(4, "MD_UTXD1"), + MTK_FUNCTION(5, "SSPM_UTXD_AO"), + MTK_FUNCTION(6, "CCU_UTXD_AO"), + MTK_FUNCTION(7, "DBG_MON_B2") + ), + MTK_PIN( + 97, "GPIO97", + MTK_EINT_FUNCTION(0, 97), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO97"), + MTK_FUNCTION(1, "UCTS0"), + MTK_FUNCTION(2, "I2S2_MCK"), + MTK_FUNCTION(3, "IDDIG"), + MTK_FUNCTION(4, "CONN_MCU_TDO"), + MTK_FUNCTION(5, "SSPM_JTAG_TDO"), + MTK_FUNCTION(6, "IO_JTAG_TDO"), + MTK_FUNCTION(7, "DBG_MON_B3") + ), + MTK_PIN( + 98, "GPIO98", + MTK_EINT_FUNCTION(0, 98), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO98"), + MTK_FUNCTION(1, "URTS0"), + MTK_FUNCTION(2, "I2S2_BCK"), + MTK_FUNCTION(3, "USB_DRVVBUS"), + MTK_FUNCTION(4, "CONN_MCU_TMS"), + MTK_FUNCTION(5, "SSPM_JTAG_TMS"), + MTK_FUNCTION(6, "IO_JTAG_TMS"), + MTK_FUNCTION(7, "DBG_MON_B4") + ), + MTK_PIN( + 99, "GPIO99", + MTK_EINT_FUNCTION(0, 99), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO99"), + MTK_FUNCTION(1, "CMMCLK0"), + MTK_FUNCTION(4, "CONN_MCU_AICE_TMSC"), + MTK_FUNCTION(7, "DBG_MON_B28") + ), + MTK_PIN( + 100, "GPIO100", + MTK_EINT_FUNCTION(0, 100), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO100"), + MTK_FUNCTION(1, "CMMCLK1"), + MTK_FUNCTION(2, "PWM_C"), + MTK_FUNCTION(3, "MD_INT1_C2K_UIM0_HOT_PLUG"), + MTK_FUNCTION(4, "CONN_MCU_AICE_TCKC"), + MTK_FUNCTION(7, "DBG_MON_B29") + ), + MTK_PIN( + 101, "GPIO101", + MTK_EINT_FUNCTION(0, 101), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO101"), + MTK_FUNCTION(1, "CLKM2"), + MTK_FUNCTION(2, "I2S2_LRCK"), + MTK_FUNCTION(3, "CMVREF1"), + MTK_FUNCTION(4, "CONN_MCU_TCK"), + MTK_FUNCTION(5, "SSPM_JTAG_TCK"), + MTK_FUNCTION(6, "IO_JTAG_TCK") + ), + MTK_PIN( + 102, "GPIO102", + MTK_EINT_FUNCTION(0, 102), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO102"), + MTK_FUNCTION(1, "CLKM1"), + MTK_FUNCTION(2, "I2S2_DI"), + MTK_FUNCTION(3, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(4, "CONN_MCU_TDI"), + MTK_FUNCTION(5, "SSPM_JTAG_TDI"), + MTK_FUNCTION(6, "IO_JTAG_TDI"), + MTK_FUNCTION(7, "DBG_MON_B8") + ), + MTK_PIN( + 103, "GPIO103", + MTK_EINT_FUNCTION(0, 103), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO103"), + MTK_FUNCTION(1, "SCL2") + ), + MTK_PIN( + 104, "GPIO104", + MTK_EINT_FUNCTION(0, 104), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO104"), + MTK_FUNCTION(1, "SDA2") + ), + MTK_PIN( + 105, "GPIO105", + MTK_EINT_FUNCTION(0, 105), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO105"), + MTK_FUNCTION(1, "SCL4") + ), + MTK_PIN( + 106, "GPIO106", + MTK_EINT_FUNCTION(0, 106), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO106"), + MTK_FUNCTION(1, "SDA4") + ), + MTK_PIN( + 107, "GPIO107", + MTK_EINT_FUNCTION(0, 107), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO107"), + MTK_FUNCTION(1, "DMIC_CLK"), + MTK_FUNCTION(2, "ANT_SEL0"), + MTK_FUNCTION(3, "CLKM0"), + MTK_FUNCTION(4, "SDA7"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(6, "PWM_A"), + MTK_FUNCTION(7, "DBG_MON_B12") + ), + MTK_PIN( + 108, "GPIO108", + MTK_EINT_FUNCTION(0, 108), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO108"), + MTK_FUNCTION(1, "CMMCLK2"), + MTK_FUNCTION(2, "ANT_SEL1"), + MTK_FUNCTION(3, "CLKM1"), + MTK_FUNCTION(4, "SCL8"), + MTK_FUNCTION(5, "DAP_MD32_SWD"), + MTK_FUNCTION(6, "PWM_B"), + MTK_FUNCTION(7, "DBG_MON_B13") + ), + MTK_PIN( + 109, "GPIO109", + MTK_EINT_FUNCTION(0, 109), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO109"), + MTK_FUNCTION(1, "DMIC_DAT"), + MTK_FUNCTION(2, "ANT_SEL2"), + MTK_FUNCTION(3, "CLKM2"), + MTK_FUNCTION(4, "SDA8"), + MTK_FUNCTION(5, "DAP_MD32_SWCK"), + MTK_FUNCTION(6, "PWM_C"), + MTK_FUNCTION(7, "DBG_MON_B14") + ), + MTK_PIN( + 110, "GPIO110", + MTK_EINT_FUNCTION(0, 110), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO110"), + MTK_FUNCTION(1, "SCL7"), + MTK_FUNCTION(2, "ANT_SEL0"), + MTK_FUNCTION(3, "TP_URXD1_AO"), + MTK_FUNCTION(4, "USB_DRVVBUS"), + MTK_FUNCTION(5, "SRCLKENAI1"), + MTK_FUNCTION(6, "KPCOL2"), + MTK_FUNCTION(7, "URXD1") + ), + MTK_PIN( + 111, "GPIO111", + MTK_EINT_FUNCTION(0, 111), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO111"), + MTK_FUNCTION(1, "CMMCLK3"), + MTK_FUNCTION(2, "ANT_SEL1"), + MTK_FUNCTION(3, "SRCLKENAI0"), + MTK_FUNCTION(4, "SCP_VREQ_VAO"), + MTK_FUNCTION(5, "MD_INT2_C2K_UIM1_HOT_PLUG"), + MTK_FUNCTION(7, "DVFSRC_EXT_REQ") + ), + MTK_PIN( + 112, "GPIO112", + MTK_EINT_FUNCTION(0, 112), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO112"), + MTK_FUNCTION(1, "SDA7"), + MTK_FUNCTION(2, "ANT_SEL2"), + MTK_FUNCTION(3, "TP_UTXD1_AO"), + MTK_FUNCTION(4, "IDDIG"), + MTK_FUNCTION(5, "AGPS_SYNC"), + MTK_FUNCTION(6, "KPROW2"), + MTK_FUNCTION(7, "UTXD1") + ), + MTK_PIN( + 113, "GPIO113", + MTK_EINT_FUNCTION(0, 113), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO113"), + MTK_FUNCTION(1, "CONN_TOP_CLK"), + MTK_FUNCTION(3, "SCL6"), + MTK_FUNCTION(4, "AUXIF_CLK0"), + MTK_FUNCTION(6, "TP_UCTS1_AO") + ), + MTK_PIN( + 114, "GPIO114", + MTK_EINT_FUNCTION(0, 114), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO114"), + MTK_FUNCTION(1, "CONN_TOP_DATA"), + MTK_FUNCTION(3, "SDA6"), + MTK_FUNCTION(4, "AUXIF_ST0"), + MTK_FUNCTION(6, "TP_URTS1_AO") + ), + MTK_PIN( + 115, "GPIO115", + MTK_EINT_FUNCTION(0, 115), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO115"), + MTK_FUNCTION(1, "CONN_BT_CLK"), + MTK_FUNCTION(2, "UTXD1"), + MTK_FUNCTION(3, "PTA_TXD"), + MTK_FUNCTION(4, "AUXIF_CLK1"), + MTK_FUNCTION(5, "DAP_MD32_SWD"), + MTK_FUNCTION(6, "TP_UTXD1_AO") + ), + MTK_PIN( + 116, "GPIO116", + MTK_EINT_FUNCTION(0, 116), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO116"), + MTK_FUNCTION(1, "CONN_BT_DATA"), + MTK_FUNCTION(2, "IPU_JTAG_TRST"), + MTK_FUNCTION(4, "AUXIF_ST1"), + MTK_FUNCTION(5, "DAP_MD32_SWCK"), + MTK_FUNCTION(6, "TP_URXD2_AO"), + MTK_FUNCTION(7, "DBG_MON_A0") + ), + MTK_PIN( + 117, "GPIO117", + MTK_EINT_FUNCTION(0, 117), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO117"), + MTK_FUNCTION(1, "CONN_WF_HB0"), + MTK_FUNCTION(2, "IPU_JTAG_TDO"), + MTK_FUNCTION(6, "TP_UTXD2_AO"), + MTK_FUNCTION(7, "DBG_MON_A4") + ), + MTK_PIN( + 118, "GPIO118", + MTK_EINT_FUNCTION(0, 118), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO118"), + MTK_FUNCTION(1, "CONN_WF_HB1"), + MTK_FUNCTION(2, "IPU_JTAG_TDI"), + MTK_FUNCTION(5, "SSPM_URXD_AO"), + MTK_FUNCTION(6, "TP_UCTS2_AO"), + MTK_FUNCTION(7, "DBG_MON_A5") + ), + MTK_PIN( + 119, "GPIO119", + MTK_EINT_FUNCTION(0, 119), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO119"), + MTK_FUNCTION(1, "CONN_WF_HB2"), + MTK_FUNCTION(2, "IPU_JTAG_TCK"), + MTK_FUNCTION(5, "SSPM_UTXD_AO"), + MTK_FUNCTION(6, "TP_URTS2_AO") + ), + MTK_PIN( + 120, "GPIO120", + MTK_EINT_FUNCTION(0, 120), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO120"), + MTK_FUNCTION(1, "CONN_WB_PTA"), + MTK_FUNCTION(2, "IPU_JTAG_TMS"), + MTK_FUNCTION(5, "CCU_URXD_AO") + ), + MTK_PIN( + 121, "GPIO121", + MTK_EINT_FUNCTION(0, 121), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO121"), + MTK_FUNCTION(1, "CONN_HRST_B"), + MTK_FUNCTION(2, "URXD1"), + MTK_FUNCTION(3, "PTA_RXD"), + MTK_FUNCTION(5, "CCU_UTXD_AO"), + MTK_FUNCTION(6, "TP_URXD1_AO") + ), + MTK_PIN( + 122, "GPIO122", + MTK_EINT_FUNCTION(0, 122), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO122"), + MTK_FUNCTION(1, "MSDC0_CMD"), + MTK_FUNCTION(2, "SSPM_URXD2_AO"), + MTK_FUNCTION(3, "ANT_SEL1"), + MTK_FUNCTION(7, "DBG_MON_A12") + ), + MTK_PIN( + 123, "GPIO123", + MTK_EINT_FUNCTION(0, 123), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO123"), + MTK_FUNCTION(1, "MSDC0_DAT0"), + MTK_FUNCTION(3, "ANT_SEL0"), + MTK_FUNCTION(7, "DBG_MON_A13") + ), + MTK_PIN( + 124, "GPIO124", + MTK_EINT_FUNCTION(0, 124), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO124"), + MTK_FUNCTION(1, "MSDC0_CLK"), + MTK_FUNCTION(7, "DBG_MON_A14") + ), + MTK_PIN( + 125, "GPIO125", + MTK_EINT_FUNCTION(0, 125), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO125"), + MTK_FUNCTION(1, "MSDC0_DAT2"), + MTK_FUNCTION(3, "MRG_CLK"), + MTK_FUNCTION(7, "DBG_MON_A15") + ), + MTK_PIN( + 126, "GPIO126", + MTK_EINT_FUNCTION(0, 126), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO126"), + MTK_FUNCTION(1, "MSDC0_DAT4"), + MTK_FUNCTION(3, "ANT_SEL5"), + MTK_FUNCTION(6, "UFS_MPHY_SCL"), + MTK_FUNCTION(7, "DBG_MON_A16") + ), + MTK_PIN( + 127, "GPIO127", + MTK_EINT_FUNCTION(0, 127), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO127"), + MTK_FUNCTION(1, "MSDC0_DAT6"), + MTK_FUNCTION(3, "ANT_SEL4"), + MTK_FUNCTION(6, "UFS_MPHY_SDA"), + MTK_FUNCTION(7, "DBG_MON_A17") + ), + MTK_PIN( + 128, "GPIO128", + MTK_EINT_FUNCTION(0, 128), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO128"), + MTK_FUNCTION(1, "MSDC0_DAT1"), + MTK_FUNCTION(3, "ANT_SEL2"), + MTK_FUNCTION(6, "UFS_UNIPRO_SDA"), + MTK_FUNCTION(7, "DBG_MON_A18") + ), + MTK_PIN( + 129, "GPIO129", + MTK_EINT_FUNCTION(0, 129), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO129"), + MTK_FUNCTION(1, "MSDC0_DAT5"), + MTK_FUNCTION(3, "ANT_SEL3"), + MTK_FUNCTION(6, "UFS_UNIPRO_SCL"), + MTK_FUNCTION(7, "DBG_MON_A23") + ), + MTK_PIN( + 130, "GPIO130", + MTK_EINT_FUNCTION(0, 130), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO130"), + MTK_FUNCTION(1, "MSDC0_DAT7"), + MTK_FUNCTION(3, "MRG_DO"), + MTK_FUNCTION(7, "DBG_MON_A24") + ), + MTK_PIN( + 131, "GPIO131", + MTK_EINT_FUNCTION(0, 131), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO131"), + MTK_FUNCTION(1, "MSDC0_DSL"), + MTK_FUNCTION(3, "MRG_SYNC"), + MTK_FUNCTION(7, "DBG_MON_A25") + ), + MTK_PIN( + 132, "GPIO132", + MTK_EINT_FUNCTION(0, 132), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO132"), + MTK_FUNCTION(1, "MSDC0_DAT3"), + MTK_FUNCTION(3, "MRG_DI"), + MTK_FUNCTION(7, "DBG_MON_A26") + ), + MTK_PIN( + 133, "GPIO133", + MTK_EINT_FUNCTION(0, 133), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO133"), + MTK_FUNCTION(1, "MSDC0_RSTB"), + MTK_FUNCTION(3, "AGPS_SYNC"), + MTK_FUNCTION(7, "DBG_MON_A27") + ), + MTK_PIN( + 134, "GPIO134", + MTK_EINT_FUNCTION(0, 134), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO134"), + MTK_FUNCTION(1, "RTC32K_CK") + ), + MTK_PIN( + 135, "GPIO135", + MTK_EINT_FUNCTION(0, 135), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO135"), + MTK_FUNCTION(1, "WATCHDOG") + ), + MTK_PIN( + 136, "GPIO136", + MTK_EINT_FUNCTION(0, 136), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO136"), + MTK_FUNCTION(1, "AUD_CLK_MOSI"), + MTK_FUNCTION(2, "AUD_CLK_MISO"), + MTK_FUNCTION(3, "I2S1_MCK"), + MTK_FUNCTION(6, "UFS_UNIPRO_SCL") + ), + MTK_PIN( + 137, "GPIO137", + MTK_EINT_FUNCTION(0, 137), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO137"), + MTK_FUNCTION(1, "AUD_SYNC_MOSI"), + MTK_FUNCTION(2, "AUD_SYNC_MISO"), + MTK_FUNCTION(3, "I2S1_BCK") + ), + MTK_PIN( + 138, "GPIO138", + MTK_EINT_FUNCTION(0, 138), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO138"), + MTK_FUNCTION(1, "AUD_DAT_MOSI0"), + MTK_FUNCTION(2, "AUD_DAT_MISO0"), + MTK_FUNCTION(3, "I2S1_LRCK"), + MTK_FUNCTION(7, "DBG_MON_B24") + ), + MTK_PIN( + 139, "GPIO139", + MTK_EINT_FUNCTION(0, 139), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO139"), + MTK_FUNCTION(1, "AUD_DAT_MOSI1"), + MTK_FUNCTION(2, "AUD_DAT_MISO1"), + MTK_FUNCTION(3, "I2S1_DO"), + MTK_FUNCTION(6, "UFS_MPHY_SDA") + ), + MTK_PIN( + 140, "GPIO140", + MTK_EINT_FUNCTION(0, 140), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO140"), + MTK_FUNCTION(1, "AUD_CLK_MISO"), + MTK_FUNCTION(2, "AUD_CLK_MOSI"), + MTK_FUNCTION(3, "I2S0_MCK"), + MTK_FUNCTION(6, "UFS_UNIPRO_SDA") + ), + MTK_PIN( + 141, "GPIO141", + MTK_EINT_FUNCTION(0, 141), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO141"), + MTK_FUNCTION(1, "AUD_SYNC_MISO"), + MTK_FUNCTION(2, "AUD_SYNC_MOSI"), + MTK_FUNCTION(3, "I2S0_BCK") + ), + MTK_PIN( + 142, "GPIO142", + MTK_EINT_FUNCTION(0, 142), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO142"), + MTK_FUNCTION(1, "AUD_DAT_MISO0"), + MTK_FUNCTION(2, "AUD_DAT_MOSI0"), + MTK_FUNCTION(3, "I2S0_LRCK"), + MTK_FUNCTION(4, "VOW_DAT_MISO"), + MTK_FUNCTION(7, "DBG_MON_B25") + ), + MTK_PIN( + 143, "GPIO143", + MTK_EINT_FUNCTION(0, 143), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO143"), + MTK_FUNCTION(1, "AUD_DAT_MISO1"), + MTK_FUNCTION(2, "AUD_DAT_MOSI1"), + MTK_FUNCTION(3, "I2S0_DI"), + MTK_FUNCTION(4, "VOW_CLK_MISO"), + MTK_FUNCTION(6, "UFS_MPHY_SCL"), + MTK_FUNCTION(7, "DBG_MON_B26") + ), + MTK_PIN( + 144, "GPIO144", + MTK_EINT_FUNCTION(0, 144), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO144"), + MTK_FUNCTION(1, "PWRAP_SPI0_MI"), + MTK_FUNCTION(2, "PWRAP_SPI0_MO") + ), + MTK_PIN( + 145, "GPIO145", + MTK_EINT_FUNCTION(0, 145), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO145"), + MTK_FUNCTION(1, "PWRAP_SPI0_CSN") + ), + MTK_PIN( + 146, "GPIO146", + MTK_EINT_FUNCTION(0, 146), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO146"), + MTK_FUNCTION(1, "PWRAP_SPI0_MO"), + MTK_FUNCTION(2, "PWRAP_SPI0_MI") + ), + MTK_PIN( + 147, "GPIO147", + MTK_EINT_FUNCTION(0, 147), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO147"), + MTK_FUNCTION(1, "PWRAP_SPI0_CK") + ), + MTK_PIN( + 148, "GPIO148", + MTK_EINT_FUNCTION(0, 148), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO148"), + MTK_FUNCTION(1, "SRCLKENA0") + ), + MTK_PIN( + 149, "GPIO149", + MTK_EINT_FUNCTION(0, 149), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO149"), + MTK_FUNCTION(1, "SRCLKENA1") + ), + MTK_PIN( + 150, "GPIO150", + MTK_EINT_FUNCTION(0, 150), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO150"), + MTK_FUNCTION(1, "PWM_A"), + MTK_FUNCTION(2, "CMFLASH"), + MTK_FUNCTION(3, "CLKM0"), + MTK_FUNCTION(7, "DBG_MON_B30") + ), + MTK_PIN( + 151, "GPIO151", + MTK_EINT_FUNCTION(0, 151), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO151"), + MTK_FUNCTION(1, "PWM_B"), + MTK_FUNCTION(2, "CMVREF0"), + MTK_FUNCTION(3, "CLKM1"), + MTK_FUNCTION(7, "DBG_MON_B20") + ), + MTK_PIN( + 152, "GPIO152", + MTK_EINT_FUNCTION(0, 152), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO152"), + MTK_FUNCTION(1, "PWM_C"), + MTK_FUNCTION(2, "CMFLASH"), + MTK_FUNCTION(3, "CLKM2"), + MTK_FUNCTION(7, "DBG_MON_B21") + ), + MTK_PIN( + 153, "GPIO153", + MTK_EINT_FUNCTION(0, 153), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO153"), + MTK_FUNCTION(1, "PWM_A"), + MTK_FUNCTION(2, "CMVREF0"), + MTK_FUNCTION(3, "CLKM3"), + MTK_FUNCTION(7, "DBG_MON_B22") + ), + MTK_PIN( + 154, "GPIO154", + MTK_EINT_FUNCTION(0, 154), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO154"), + MTK_FUNCTION(1, "SCP_VREQ_VAO"), + MTK_FUNCTION(2, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(7, "DBG_MON_B18") + ), + MTK_PIN( + 155, "GPIO155", + MTK_EINT_FUNCTION(0, 155), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO155"), + MTK_FUNCTION(1, "ANT_SEL0"), + MTK_FUNCTION(2, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(3, "CMVREF1"), + MTK_FUNCTION(7, "SCP_JTAG_TDI") + ), + MTK_PIN( + 156, "GPIO156", + MTK_EINT_FUNCTION(0, 156), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO156"), + MTK_FUNCTION(1, "ANT_SEL1"), + MTK_FUNCTION(2, "SRCLKENAI0"), + MTK_FUNCTION(3, "SCL6"), + MTK_FUNCTION(4, "KPCOL2"), + MTK_FUNCTION(5, "IDDIG"), + MTK_FUNCTION(7, "SCP_JTAG_TCK") + ), + MTK_PIN( + 157, "GPIO157", + MTK_EINT_FUNCTION(0, 157), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO157"), + MTK_FUNCTION(1, "ANT_SEL2"), + MTK_FUNCTION(2, "SRCLKENAI1"), + MTK_FUNCTION(3, "SDA6"), + MTK_FUNCTION(4, "KPROW2"), + MTK_FUNCTION(5, "USB_DRVVBUS"), + MTK_FUNCTION(7, "SCP_JTAG_TRSTN") + ), + MTK_PIN( + 158, "GPIO158", + MTK_EINT_FUNCTION(0, 158), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO158"), + MTK_FUNCTION(1, "ANT_SEL3") + ), + MTK_PIN( + 159, "GPIO159", + MTK_EINT_FUNCTION(0, 159), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO159"), + MTK_FUNCTION(1, "ANT_SEL4") + ), + MTK_PIN( + 160, "GPIO160", + MTK_EINT_FUNCTION(0, 160), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO160"), + MTK_FUNCTION(1, "ANT_SEL5") + ), + MTK_PIN( + 161, "GPIO161", + MTK_EINT_FUNCTION(0, 161), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO161"), + MTK_FUNCTION(1, "SPI1_A_MI"), + MTK_FUNCTION(2, "SCP_SPI1_MI"), + MTK_FUNCTION(3, "IDDIG"), + MTK_FUNCTION(4, "ANT_SEL6"), + MTK_FUNCTION(5, "KPCOL2"), + MTK_FUNCTION(6, "PTA_RXD"), + MTK_FUNCTION(7, "DBG_MON_B19") + ), + MTK_PIN( + 162, "GPIO162", + MTK_EINT_FUNCTION(0, 162), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO162"), + MTK_FUNCTION(1, "SPI1_A_CSB"), + MTK_FUNCTION(2, "SCP_SPI1_CS"), + MTK_FUNCTION(3, "USB_DRVVBUS"), + MTK_FUNCTION(4, "ANT_SEL5"), + MTK_FUNCTION(5, "KPROW2"), + MTK_FUNCTION(6, "PTA_TXD") + ), + MTK_PIN( + 163, "GPIO163", + MTK_EINT_FUNCTION(0, 163), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO163"), + MTK_FUNCTION(1, "SPI1_A_MO"), + MTK_FUNCTION(2, "SCP_SPI1_MO"), + MTK_FUNCTION(3, "SDA1"), + MTK_FUNCTION(4, "ANT_SEL4"), + MTK_FUNCTION(5, "CMMCLK2"), + MTK_FUNCTION(6, "DMIC_CLK") + ), + MTK_PIN( + 164, "GPIO164", + MTK_EINT_FUNCTION(0, 164), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO164"), + MTK_FUNCTION(1, "SPI1_A_CLK"), + MTK_FUNCTION(2, "SCP_SPI1_CK"), + MTK_FUNCTION(3, "SCL1"), + MTK_FUNCTION(4, "ANT_SEL3"), + MTK_FUNCTION(5, "CMMCLK3"), + MTK_FUNCTION(6, "DMIC_DAT") + ), + MTK_PIN( + 165, "GPIO165", + MTK_EINT_FUNCTION(0, 165), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO165"), + MTK_FUNCTION(1, "PWM_B"), + MTK_FUNCTION(2, "CMMCLK2"), + MTK_FUNCTION(3, "SCP_VREQ_VAO"), + MTK_FUNCTION(6, "TDM_MCK_2ND"), + MTK_FUNCTION(7, "SCP_JTAG_TDO") + ), + MTK_PIN( + 166, "GPIO166", + MTK_EINT_FUNCTION(0, 166), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO166"), + MTK_FUNCTION(1, "ANT_SEL6") + ), + MTK_PIN( + 167, "GPIO167", + MTK_EINT_FUNCTION(0, 167), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO167"), + MTK_FUNCTION(1, "RFIC0_BSI_EN"), + MTK_FUNCTION(2, "SPM_BSI_EN") + ), + MTK_PIN( + 168, "GPIO168", + MTK_EINT_FUNCTION(0, 168), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO168"), + MTK_FUNCTION(1, "RFIC0_BSI_CK"), + MTK_FUNCTION(2, "SPM_BSI_CK") + ), + MTK_PIN( + 169, "GPIO169", + MTK_EINT_FUNCTION(0, 169), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO169"), + MTK_FUNCTION(1, "PWM_C"), + MTK_FUNCTION(2, "CMMCLK3"), + MTK_FUNCTION(3, "CMVREF1"), + MTK_FUNCTION(4, "ANT_SEL7"), + MTK_FUNCTION(5, "AGPS_SYNC"), + MTK_FUNCTION(6, "TDM_BCK_2ND"), + MTK_FUNCTION(7, "SCP_JTAG_TMS") + ), + MTK_PIN( + 170, "GPIO170", + MTK_EINT_FUNCTION(0, 170), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO170"), + MTK_FUNCTION(1, "I2S1_BCK"), + MTK_FUNCTION(2, "I2S3_BCK"), + MTK_FUNCTION(3, "SCL7"), + MTK_FUNCTION(4, "I2S5_BCK"), + MTK_FUNCTION(5, "EXT_FRAME_SYNC"), + MTK_FUNCTION(6, "TDM_LRCK_2ND"), + MTK_FUNCTION(7, "ANT_SEL3") + ), + MTK_PIN( + 171, "GPIO171", + MTK_EINT_FUNCTION(0, 184), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO171"), + MTK_FUNCTION(1, "I2S1_LRCK"), + MTK_FUNCTION(2, "I2S3_LRCK"), + MTK_FUNCTION(3, "SDA7"), + MTK_FUNCTION(4, "I2S5_LRCK"), + MTK_FUNCTION(5, "URXD1"), + MTK_FUNCTION(6, "TDM_DATA0_2ND"), + MTK_FUNCTION(7, "ANT_SEL4") + ), + MTK_PIN( + 172, "GPIO172", + MTK_EINT_FUNCTION(0, 185), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO172"), + MTK_FUNCTION(1, "I2S1_DO"), + MTK_FUNCTION(2, "I2S3_DO"), + MTK_FUNCTION(3, "SCL8"), + MTK_FUNCTION(4, "I2S5_DO"), + MTK_FUNCTION(5, "UTXD1"), + MTK_FUNCTION(6, "TDM_DATA1_2ND"), + MTK_FUNCTION(7, "ANT_SEL5") + ), + MTK_PIN( + 173, "GPIO173", + MTK_EINT_FUNCTION(0, 186), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO173"), + MTK_FUNCTION(1, "I2S1_MCK"), + MTK_FUNCTION(2, "I2S3_MCK"), + MTK_FUNCTION(3, "SDA8"), + MTK_FUNCTION(4, "I2S5_MCK"), + MTK_FUNCTION(5, "UCTS0"), + MTK_FUNCTION(6, "TDM_DATA2_2ND"), + MTK_FUNCTION(7, "ANT_SEL6") + ), + MTK_PIN( + 174, "GPIO174", + MTK_EINT_FUNCTION(0, 187), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO174"), + MTK_FUNCTION(1, "I2S2_DI"), + MTK_FUNCTION(2, "I2S0_DI"), + MTK_FUNCTION(3, "DVFSRC_EXT_REQ"), + MTK_FUNCTION(4, "I2S2_DI2"), + MTK_FUNCTION(5, "URTS0"), + MTK_FUNCTION(6, "TDM_DATA3_2ND"), + MTK_FUNCTION(7, "ANT_SEL7") + ), + MTK_PIN( + 175, "GPIO175", + MTK_EINT_FUNCTION(0, 188), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO175"), + MTK_FUNCTION(1, "ANT_SEL7") + ), + MTK_PIN( + 176, "GPIO176", + MTK_EINT_FUNCTION(0, 189), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO176") + ), + MTK_PIN( + 177, "GPIO177", + MTK_EINT_FUNCTION(0, 190), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO177") + ), + MTK_PIN( + 178, "GPIO178", + MTK_EINT_FUNCTION(0, 191), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO178") + ), + MTK_PIN( + 179, "GPIO179", + MTK_EINT_FUNCTION(0, 192), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO179") + ), + MTK_PIN( + 180, "GPIO180", + MTK_EINT_FUNCTION(0, 171), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO180") + ), + MTK_PIN( + 181, "GPIO181", + MTK_EINT_FUNCTION(0, 172), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO181") + ), + MTK_PIN( + 182, "GPIO182", + MTK_EINT_FUNCTION(0, 173), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO182") + ), + MTK_PIN( + 183, "GPIO183", + MTK_EINT_FUNCTION(0, 174), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO183") + ), + MTK_PIN( + 184, "GPIO184", + MTK_EINT_FUNCTION(0, 175), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO184") + ), + MTK_PIN( + 185, "GPIO185", + MTK_EINT_FUNCTION(0, 177), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO185") + ), + MTK_PIN( + 186, "GPIO186", + MTK_EINT_FUNCTION(0, 178), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO186") + ), + MTK_PIN( + 187, "GPIO187", + MTK_EINT_FUNCTION(0, 179), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO187") + ), + MTK_PIN( + 188, "GPIO188", + MTK_EINT_FUNCTION(0, 180), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO188") + ), + MTK_PIN( + 189, "GPIO189", + MTK_EINT_FUNCTION(0, 181), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO189") + ), + MTK_PIN( + 190, "GPIO190", + MTK_EINT_FUNCTION(0, 182), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO190") + ), + MTK_PIN( + 191, "GPIO191", + MTK_EINT_FUNCTION(0, 183), + DRV_GRP4, + MTK_FUNCTION(0, "GPIO191") + ), +}; + +#endif /* __PINCTRL_MTK_MT8183_H */ diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c new file mode 100644 index 000000000000..d2179028f134 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-paris.c @@ -0,0 +1,907 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek Pinctrl Paris Driver, which implement the vendor per-pin + * bindings for MediaTek SoC. + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Sean Wang <sean.wang@mediatek.com> + * Zhiyong Tao <zhiyong.tao@mediatek.com> + * Hongzhou.Yang <hongzhou.yang@mediatek.com> + */ + +#include <linux/gpio/driver.h> +#include <dt-bindings/pinctrl/mt65xx.h> +#include "pinctrl-paris.h" + +#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME + +/* Custom pinconf parameters */ +#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) +#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) +#define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) +#define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) + +static const struct pinconf_generic_params mtk_custom_bindings[] = { + {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, + {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, + {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, + {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item mtk_conf_items[] = { + PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), + PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), + PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), + PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), +}; +#endif + +static const char * const mtk_gpio_functions[] = { + "func0", "func1", "func2", "func3", + "func4", "func5", "func6", "func7", + "func8", "func9", "func10", "func11", + "func12", "func13", "func14", "func15", +}; + +static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, + hw->soc->gpio_m); +} + +static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin, bool input) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + /* hardware would take 0 as input direction */ + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input); +} + +static int mtk_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + u32 param = pinconf_to_config_param(*config); + int val, val2, err, reg, ret = 1; + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (hw->soc->bias_disable_get) { + err = hw->soc->bias_disable_get(hw, desc, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (hw->soc->bias_get) { + err = hw->soc->bias_get(hw, desc, 1, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (hw->soc->bias_get) { + err = hw->soc->bias_get(hw, desc, 0, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_SLEW_RATE: + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &val); + if (err) + return err; + + if (!val) + return -EINVAL; + + break; + case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_OUTPUT_ENABLE: + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); + if (err) + return err; + + /* HW takes input mode as zero; output mode as non-zero */ + if ((val && param == PIN_CONFIG_INPUT_ENABLE) || + (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) + return -EINVAL; + + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); + if (err) + return err; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &val2); + if (err) + return err; + + if (val || !val2) + return -EINVAL; + + break; + case PIN_CONFIG_DRIVE_STRENGTH: + if (hw->soc->drive_get) { + err = hw->soc->drive_get(hw, desc, &ret); + if (err) + return err; + } else { + err = -ENOTSUPP; + } + break; + case MTK_PIN_CONFIG_TDSEL: + case MTK_PIN_CONFIG_RDSEL: + reg = (param == MTK_PIN_CONFIG_TDSEL) ? + PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; + + err = mtk_hw_get_value(hw, desc, reg, &val); + if (err) + return err; + + ret = val; + + break; + case MTK_PIN_CONFIG_PU_ADV: + case MTK_PIN_CONFIG_PD_ADV: + if (hw->soc->adv_pull_get) { + bool pullup; + + pullup = param == MTK_PIN_CONFIG_PU_ADV; + err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, ret); + + return 0; +} + +static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + enum pin_config_param param, + enum pin_config_param arg) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + int err = 0; + u32 reg; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + switch ((u32)param) { + case PIN_CONFIG_BIAS_DISABLE: + if (hw->soc->bias_disable_set) { + err = hw->soc->bias_disable_set(hw, desc); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (hw->soc->bias_set) { + err = hw->soc->bias_set(hw, desc, 1); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (hw->soc->bias_set) { + err = hw->soc->bias_set(hw, desc, 0); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case PIN_CONFIG_OUTPUT_ENABLE: + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, + MTK_DISABLE); + if (err) + goto err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + MTK_OUTPUT); + if (err) + goto err; + break; + case PIN_CONFIG_INPUT_ENABLE: + if (hw->soc->ies_present) { + mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, + MTK_ENABLE); + } + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + MTK_INPUT); + if (err) + goto err; + break; + case PIN_CONFIG_SLEW_RATE: + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR, + arg); + if (err) + goto err; + + break; + case PIN_CONFIG_OUTPUT: + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + MTK_OUTPUT); + if (err) + goto err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, + arg); + if (err) + goto err; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + /* arg = 1: Input mode & SMT enable ; + * arg = 0: Output mode & SMT disable + */ + arg = arg ? 2 : 1; + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, + arg & 1); + if (err) + goto err; + + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, + !!(arg & 2)); + if (err) + goto err; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + if (hw->soc->drive_set) { + err = hw->soc->drive_set(hw, desc, arg); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + case MTK_PIN_CONFIG_TDSEL: + case MTK_PIN_CONFIG_RDSEL: + reg = (param == MTK_PIN_CONFIG_TDSEL) ? + PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; + + err = mtk_hw_set_value(hw, desc, reg, arg); + if (err) + goto err; + break; + case MTK_PIN_CONFIG_PU_ADV: + case MTK_PIN_CONFIG_PD_ADV: + if (hw->soc->adv_pull_set) { + bool pullup; + + pullup = param == MTK_PIN_CONFIG_PU_ADV; + err = hw->soc->adv_pull_set(hw, desc, pullup, + arg); + if (err) + return err; + } else { + return -ENOTSUPP; + } + break; + default: + err = -ENOTSUPP; + } + +err: + return err; +} + +static struct mtk_pinctrl_group * +mtk_pctrl_find_group_by_pin(struct mtk_pinctrl *hw, u32 pin) +{ + int i; + + for (i = 0; i < hw->soc->ngrps; i++) { + struct mtk_pinctrl_group *grp = hw->groups + i; + + if (grp->pin == pin) + return grp; + } + + return NULL; +} + +static const struct mtk_func_desc * +mtk_pctrl_find_function_by_pin(struct mtk_pinctrl *hw, u32 pin_num, u32 fnum) +{ + const struct mtk_pin_desc *pin = hw->soc->pins + pin_num; + const struct mtk_func_desc *func = pin->funcs; + + while (func && func->name) { + if (func->muxval == fnum) + return func; + func++; + } + + return NULL; +} + +static bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *hw, u32 pin_num, + u32 fnum) +{ + int i; + + for (i = 0; i < hw->soc->npins; i++) { + const struct mtk_pin_desc *pin = hw->soc->pins + i; + + if (pin->number == pin_num) { + const struct mtk_func_desc *func = pin->funcs; + + while (func && func->name) { + if (func->muxval == fnum) + return true; + func++; + } + + break; + } + } + + return false; +} + +static int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl, + u32 pin, u32 fnum, + struct mtk_pinctrl_group *grp, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + bool ret; + + if (*num_maps == *reserved_maps) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = grp->name; + + ret = mtk_pctrl_is_function_valid(pctl, pin, fnum); + if (!ret) { + dev_err(pctl->dev, "invalid function %d on pin %d .\n", + fnum, pin); + return -EINVAL; + } + + (*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum]; + (*num_maps)++; + + return 0; +} + +static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *node, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + int num_pins, num_funcs, maps_per_pin, i, err; + struct mtk_pinctrl_group *grp; + unsigned int num_configs; + bool has_config = false; + unsigned long *configs; + u32 pinfunc, pin, func; + struct property *pins; + unsigned reserve = 0; + + pins = of_find_property(node, "pinmux", NULL); + if (!pins) { + dev_err(hw->dev, "missing pins property in node %s .\n", + node->name); + return -EINVAL; + } + + err = pinconf_generic_parse_dt_config(node, pctldev, &configs, + &num_configs); + if (err) + return err; + + if (num_configs) + has_config = true; + + num_pins = pins->length / sizeof(u32); + num_funcs = num_pins; + maps_per_pin = 0; + if (num_funcs) + maps_per_pin++; + if (has_config && num_pins >= 1) + maps_per_pin++; + + if (!num_pins || !maps_per_pin) { + err = -EINVAL; + goto exit; + } + + reserve = num_pins * maps_per_pin; + + err = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, + reserve); + if (err < 0) + goto exit; + + for (i = 0; i < num_pins; i++) { + err = of_property_read_u32_index(node, "pinmux", i, &pinfunc); + if (err) + goto exit; + + pin = MTK_GET_PIN_NO(pinfunc); + func = MTK_GET_PIN_FUNC(pinfunc); + + if (pin >= hw->soc->npins || + func >= ARRAY_SIZE(mtk_gpio_functions)) { + dev_err(hw->dev, "invalid pins value.\n"); + err = -EINVAL; + goto exit; + } + + grp = mtk_pctrl_find_group_by_pin(hw, pin); + if (!grp) { + dev_err(hw->dev, "unable to match pin %d to group\n", + pin); + err = -EINVAL; + goto exit; + } + + err = mtk_pctrl_dt_node_to_map_func(hw, pin, func, grp, map, + reserved_maps, num_maps); + if (err < 0) + goto exit; + + if (has_config) { + err = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, + num_maps, + grp->name, + configs, + num_configs, + PIN_MAP_TYPE_CONFIGS_GROUP); + if (err < 0) + goto exit; + } + } + + err = 0; + +exit: + kfree(configs); + return err; +} + +static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) +{ + struct device_node *np; + unsigned reserved_maps; + int ret; + + *map = NULL; + *num_maps = 0; + reserved_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, + num_maps); + if (ret < 0) { + pinctrl_utils_free_map(pctldev, *map, *num_maps); + of_node_put(np); + return ret; + } + } + + return 0; +} + +static int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + + return hw->soc->ngrps; +} + +static const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + + return hw->groups[group].name; +} + +static int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, + unsigned *num_pins) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + + *pins = (unsigned *)&hw->groups[group].pin; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops mtk_pctlops = { + .dt_node_to_map = mtk_pctrl_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, + .get_groups_count = mtk_pctrl_get_groups_count, + .get_group_name = mtk_pctrl_get_group_name, + .get_group_pins = mtk_pctrl_get_group_pins, +}; + +static int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(mtk_gpio_functions); +} + +static const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return mtk_gpio_functions[selector]; +} + +static int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + + *groups = hw->grp_names; + *num_groups = hw->soc->ngrps; + + return 0; +} + +static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + struct mtk_pinctrl_group *grp = hw->groups + group; + const struct mtk_func_desc *desc_func; + const struct mtk_pin_desc *desc; + bool ret; + + ret = mtk_pctrl_is_function_valid(hw, grp->pin, function); + if (!ret) { + dev_err(hw->dev, "invalid function %d on group %d .\n", + function, group); + return -EINVAL; + } + + desc_func = mtk_pctrl_find_function_by_pin(hw, grp->pin, function); + if (!desc_func) + return -EINVAL; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[grp->pin]; + mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, desc_func->muxval); + + return 0; +} + +static const struct pinmux_ops mtk_pmxops = { + .get_functions_count = mtk_pmx_get_funcs_cnt, + .get_function_name = mtk_pmx_get_func_name, + .get_function_groups = mtk_pmx_get_func_groups, + .set_mux = mtk_pmx_set_mux, + .gpio_set_direction = mtk_pinmux_gpio_set_direction, + .gpio_request_enable = mtk_pinmux_gpio_request_enable, +}; + +static int mtk_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group, + unsigned long *config) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + + *config = hw->groups[group].config; + + return 0; +} + +static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, + unsigned long *configs, unsigned num_configs) +{ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + struct mtk_pinctrl_group *grp = &hw->groups[group]; + int i, ret; + + for (i = 0; i < num_configs; i++) { + ret = mtk_pinconf_set(pctldev, grp->pin, + pinconf_to_config_param(configs[i]), + pinconf_to_config_argument(configs[i])); + if (ret < 0) + return ret; + + grp->config = configs[i]; + } + + return 0; +} + +static const struct pinconf_ops mtk_confops = { + .pin_config_get = mtk_pinconf_get, + .pin_config_group_get = mtk_pconf_group_get, + .pin_config_group_set = mtk_pconf_group_set, +}; + +static struct pinctrl_desc mtk_desc = { + .name = PINCTRL_PINCTRL_DEV, + .pctlops = &mtk_pctlops, + .pmxops = &mtk_pmxops, + .confops = &mtk_confops, + .owner = THIS_MODULE, +}; + +static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + int value, err; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &value); + if (err) + return err; + + return !value; +} + +static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + int value, err; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); + if (err) + return err; + + return !!value; +} + +static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; + + mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); +} + +static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) +{ + return pinctrl_gpio_direction_input(chip->base + gpio); +} + +static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, + int value) +{ + mtk_gpio_set(chip, gpio, value); + + return pinctrl_gpio_direction_output(chip->base + gpio); +} + +static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + + if (!hw->eint) + return -ENOTSUPP; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; + + if (desc->eint.eint_n == EINT_NA) + return -ENOTSUPP; + + return mtk_eint_find_irq(hw->eint, desc->eint.eint_n); +} + +static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; + u32 debounce; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; + + if (!hw->eint || + pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || + desc->eint.eint_n == EINT_NA) + return -ENOTSUPP; + + debounce = pinconf_to_config_argument(config); + + return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); +} + +static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np) +{ + struct gpio_chip *chip = &hw->chip; + int ret; + + chip->label = PINCTRL_PINCTRL_DEV; + chip->parent = hw->dev; + chip->request = gpiochip_generic_request; + chip->free = gpiochip_generic_free; + chip->get_direction = mtk_gpio_get_direction; + chip->direction_input = mtk_gpio_direction_input; + chip->direction_output = mtk_gpio_direction_output; + chip->get = mtk_gpio_get; + chip->set = mtk_gpio_set; + chip->to_irq = mtk_gpio_to_irq, + chip->set_config = mtk_gpio_set_config, + chip->base = -1; + chip->ngpio = hw->soc->npins; + chip->of_node = np; + chip->of_gpio_n_cells = 2; + + ret = gpiochip_add_data(chip, hw); + if (ret < 0) + return ret; + + return 0; +} + +static int mtk_pctrl_build_state(struct platform_device *pdev) +{ + struct mtk_pinctrl *hw = platform_get_drvdata(pdev); + int i; + + /* Allocate groups */ + hw->groups = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, + sizeof(*hw->groups), GFP_KERNEL); + if (!hw->groups) + return -ENOMEM; + + /* We assume that one pin is one group, use pin name as group name. */ + hw->grp_names = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, + sizeof(*hw->grp_names), GFP_KERNEL); + if (!hw->grp_names) + return -ENOMEM; + + for (i = 0; i < hw->soc->npins; i++) { + const struct mtk_pin_desc *pin = hw->soc->pins + i; + struct mtk_pinctrl_group *group = hw->groups + i; + + group->name = pin->name; + group->pin = pin->number; + + hw->grp_names[i] = pin->name; + } + + return 0; +} + +int mtk_paris_pinctrl_probe(struct platform_device *pdev, + const struct mtk_pin_soc *soc) +{ + struct pinctrl_pin_desc *pins; + struct mtk_pinctrl *hw; + struct resource *res; + int err, i; + + hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return -ENOMEM; + + platform_set_drvdata(pdev, hw); + hw->soc = soc; + hw->dev = &pdev->dev; + + if (!hw->soc->nbase_names) { + dev_err(&pdev->dev, + "SoC should be assigned at least one register base\n"); + return -EINVAL; + } + + hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names, + sizeof(*hw->base), GFP_KERNEL); + if (!hw->base) + return -ENOMEM; + + for (i = 0; i < hw->soc->nbase_names; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + hw->soc->base_names[i]); + if (!res) { + dev_err(&pdev->dev, "missing IO resource\n"); + return -ENXIO; + } + + hw->base[i] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->base[i])) + return PTR_ERR(hw->base[i]); + } + + hw->nbase = hw->soc->nbase_names; + + err = mtk_pctrl_build_state(pdev); + if (err) { + dev_err(&pdev->dev, "build state failed: %d\n", err); + return -EINVAL; + } + + /* Copy from internal struct mtk_pin_desc to register to the core */ + pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins), + GFP_KERNEL); + if (!pins) + return -ENOMEM; + + for (i = 0; i < hw->soc->npins; i++) { + pins[i].number = hw->soc->pins[i].number; + pins[i].name = hw->soc->pins[i].name; + } + + /* Setup pins descriptions per SoC types */ + mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; + mtk_desc.npins = hw->soc->npins; + mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); + mtk_desc.custom_params = mtk_custom_bindings; +#ifdef CONFIG_DEBUG_FS + mtk_desc.custom_conf_items = mtk_conf_items; +#endif + + err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, + &hw->pctrl); + if (err) + return err; + + err = pinctrl_enable(hw->pctrl); + if (err) + return err; + + err = mtk_build_eint(hw, pdev); + if (err) + dev_warn(&pdev->dev, + "Failed to add EINT, but pinctrl still can work\n"); + + /* Build gpiochip should be after pinctrl_enable is done */ + err = mtk_build_gpiochip(hw, pdev->dev.of_node); + if (err) { + dev_err(&pdev->dev, "Failed to add gpio_chip\n"); + return err; + } + + platform_set_drvdata(pdev, hw); + + return 0; +} diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h new file mode 100644 index 000000000000..37146caa667d --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-paris.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Sean Wang <sean.wang@mediatek.com> + * Zhiyong Tao <zhiyong.tao@mediatek.com> + * Hongzhou.Yang <hongzhou.yang@mediatek.com> + */ +#ifndef __PINCTRL_PARIS_H +#define __PINCTRL_PARIS_H + +#include <linux/io.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> + +#include "../core.h" +#include "../pinconf.h" +#include "../pinctrl-utils.h" +#include "../pinmux.h" +#include "mtk-eint.h" +#include "pinctrl-mtk-common-v2.h" + +#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), } + +#define MTK_EINT_FUNCTION(_eintmux, _eintnum) \ + { \ + .eint_m = _eintmux, \ + .eint_n = _eintnum, \ + } + +#define MTK_FUNCTION(_val, _name) \ + { \ + .muxval = _val, \ + .name = _name, \ + } + +#define MTK_PIN(_number, _name, _eint, _drv_n, ...) { \ + .number = _number, \ + .name = _name, \ + .eint = _eint, \ + .drv_n = _drv_n, \ + .funcs = (struct mtk_func_desc[]){ \ + __VA_ARGS__, { } }, \ + } + +#define PINCTRL_PIN_GROUP(name, id) \ + { \ + name, \ + id##_pins, \ + ARRAY_SIZE(id##_pins), \ + id##_funcs, \ + } + +int mtk_paris_pinctrl_probe(struct platform_device *pdev, + const struct mtk_pin_soc *soc); + +#endif /* __PINCTRL_PARIS_H */ diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index c80951d6caff..9ab537eb78a3 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -47,4 +47,10 @@ config PINCTRL_MESON_AXG config PINCTRL_MESON_AXG_PMX bool +config PINCTRL_MESON_G12A + bool "Meson g12a Soc pinctrl driver" + depends on ARM64 + select PINCTRL_MESON_AXG_PMX + default y + endif diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile index 3c6580c2d9d7..cf283f48f9d8 100644 --- a/drivers/pinctrl/meson/Makefile +++ b/drivers/pinctrl/meson/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o +obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c new file mode 100644 index 000000000000..d494492e98e9 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c @@ -0,0 +1,1404 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Pin controller and GPIO driver for Amlogic Meson G12A SoC. + * + * Copyright (c) 2018 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen <xingyu.chen@amlogic.com> + * Author: Yixun Lan <yixun.lan@amlogic.com> + */ + +#include <dt-bindings/gpio/meson-g12a-gpio.h> +#include "pinctrl-meson.h" +#include "pinctrl-meson-axg-pmx.h" + +static const struct pinctrl_pin_desc meson_g12a_periphs_pins[] = { + MESON_PIN(GPIOZ_0), + MESON_PIN(GPIOZ_1), + MESON_PIN(GPIOZ_2), + MESON_PIN(GPIOZ_3), + MESON_PIN(GPIOZ_4), + MESON_PIN(GPIOZ_5), + MESON_PIN(GPIOZ_6), + MESON_PIN(GPIOZ_7), + MESON_PIN(GPIOZ_8), + MESON_PIN(GPIOZ_9), + MESON_PIN(GPIOZ_10), + MESON_PIN(GPIOZ_11), + MESON_PIN(GPIOZ_12), + MESON_PIN(GPIOZ_13), + MESON_PIN(GPIOZ_14), + MESON_PIN(GPIOZ_15), + MESON_PIN(GPIOH_0), + MESON_PIN(GPIOH_1), + MESON_PIN(GPIOH_2), + MESON_PIN(GPIOH_3), + MESON_PIN(GPIOH_4), + MESON_PIN(GPIOH_5), + MESON_PIN(GPIOH_6), + MESON_PIN(GPIOH_7), + MESON_PIN(GPIOH_8), + MESON_PIN(BOOT_0), + MESON_PIN(BOOT_1), + MESON_PIN(BOOT_2), + MESON_PIN(BOOT_3), + MESON_PIN(BOOT_4), + MESON_PIN(BOOT_5), + MESON_PIN(BOOT_6), + MESON_PIN(BOOT_7), + MESON_PIN(BOOT_8), + MESON_PIN(BOOT_9), + MESON_PIN(BOOT_10), + MESON_PIN(BOOT_11), + MESON_PIN(BOOT_12), + MESON_PIN(BOOT_13), + MESON_PIN(BOOT_14), + MESON_PIN(BOOT_15), + MESON_PIN(GPIOC_0), + MESON_PIN(GPIOC_1), + MESON_PIN(GPIOC_2), + MESON_PIN(GPIOC_3), + MESON_PIN(GPIOC_4), + MESON_PIN(GPIOC_5), + MESON_PIN(GPIOC_6), + MESON_PIN(GPIOC_7), + MESON_PIN(GPIOA_0), + MESON_PIN(GPIOA_1), + MESON_PIN(GPIOA_2), + MESON_PIN(GPIOA_3), + MESON_PIN(GPIOA_4), + MESON_PIN(GPIOA_5), + MESON_PIN(GPIOA_6), + MESON_PIN(GPIOA_7), + MESON_PIN(GPIOA_8), + MESON_PIN(GPIOA_9), + MESON_PIN(GPIOA_10), + MESON_PIN(GPIOA_11), + MESON_PIN(GPIOA_12), + MESON_PIN(GPIOA_13), + MESON_PIN(GPIOA_14), + MESON_PIN(GPIOA_15), + MESON_PIN(GPIOX_0), + MESON_PIN(GPIOX_1), + MESON_PIN(GPIOX_2), + MESON_PIN(GPIOX_3), + MESON_PIN(GPIOX_4), + MESON_PIN(GPIOX_5), + MESON_PIN(GPIOX_6), + MESON_PIN(GPIOX_7), + MESON_PIN(GPIOX_8), + MESON_PIN(GPIOX_9), + MESON_PIN(GPIOX_10), + MESON_PIN(GPIOX_11), + MESON_PIN(GPIOX_12), + MESON_PIN(GPIOX_13), + MESON_PIN(GPIOX_14), + MESON_PIN(GPIOX_15), + MESON_PIN(GPIOX_16), + MESON_PIN(GPIOX_17), + MESON_PIN(GPIOX_18), + MESON_PIN(GPIOX_19), +}; + +static const struct pinctrl_pin_desc meson_g12a_aobus_pins[] = { + MESON_PIN(GPIOAO_0), + MESON_PIN(GPIOAO_1), + MESON_PIN(GPIOAO_2), + MESON_PIN(GPIOAO_3), + MESON_PIN(GPIOAO_4), + MESON_PIN(GPIOAO_5), + MESON_PIN(GPIOAO_6), + MESON_PIN(GPIOAO_7), + MESON_PIN(GPIOAO_8), + MESON_PIN(GPIOAO_9), + MESON_PIN(GPIOAO_10), + MESON_PIN(GPIOAO_11), + MESON_PIN(GPIOE_0), + MESON_PIN(GPIOE_1), + MESON_PIN(GPIOE_2), +}; + +/* emmc */ +static const unsigned int emmc_nand_d0_pins[] = { BOOT_0 }; +static const unsigned int emmc_nand_d1_pins[] = { BOOT_1 }; +static const unsigned int emmc_nand_d2_pins[] = { BOOT_2 }; +static const unsigned int emmc_nand_d3_pins[] = { BOOT_3 }; +static const unsigned int emmc_nand_d4_pins[] = { BOOT_4 }; +static const unsigned int emmc_nand_d5_pins[] = { BOOT_5 }; +static const unsigned int emmc_nand_d6_pins[] = { BOOT_6 }; +static const unsigned int emmc_nand_d7_pins[] = { BOOT_7 }; +static const unsigned int emmc_clk_pins[] = { BOOT_8 }; +static const unsigned int emmc_cmd_pins[] = { BOOT_10 }; +static const unsigned int emmc_nand_ds_pins[] = { BOOT_13 }; + +/* nand */ +static const unsigned int nand_wen_clk_pins[] = { BOOT_8 }; +static const unsigned int nand_ale_pins[] = { BOOT_9 }; +static const unsigned int nand_cle_pins[] = { BOOT_10 }; +static const unsigned int nand_ce0_pins[] = { BOOT_11 }; +static const unsigned int nand_ren_wr_pins[] = { BOOT_12 }; +static const unsigned int nand_rb0_pins[] = { BOOT_14 }; +static const unsigned int nand_ce1_pins[] = { BOOT_15 }; + +/* nor */ +static const unsigned int nor_hold_pins[] = { BOOT_3 }; +static const unsigned int nor_d_pins[] = { BOOT_4 }; +static const unsigned int nor_q_pins[] = { BOOT_5 }; +static const unsigned int nor_c_pins[] = { BOOT_6 }; +static const unsigned int nor_wp_pins[] = { BOOT_7 }; +static const unsigned int nor_cs_pins[] = { BOOT_14 }; + +/* sdio */ +static const unsigned int sdio_d0_pins[] = { GPIOX_0 }; +static const unsigned int sdio_d1_pins[] = { GPIOX_1 }; +static const unsigned int sdio_d2_pins[] = { GPIOX_2 }; +static const unsigned int sdio_d3_pins[] = { GPIOX_3 }; +static const unsigned int sdio_clk_pins[] = { GPIOX_4 }; +static const unsigned int sdio_cmd_pins[] = { GPIOX_5 }; + +/* sdcard */ +static const unsigned int sdcard_d0_c_pins[] = { GPIOC_0 }; +static const unsigned int sdcard_d1_c_pins[] = { GPIOC_1 }; +static const unsigned int sdcard_d2_c_pins[] = { GPIOC_2 }; +static const unsigned int sdcard_d3_c_pins[] = { GPIOC_3 }; +static const unsigned int sdcard_clk_c_pins[] = { GPIOC_4 }; +static const unsigned int sdcard_cmd_c_pins[] = { GPIOC_5 }; + +static const unsigned int sdcard_d0_z_pins[] = { GPIOZ_2 }; +static const unsigned int sdcard_d1_z_pins[] = { GPIOZ_3 }; +static const unsigned int sdcard_d2_z_pins[] = { GPIOZ_4 }; +static const unsigned int sdcard_d3_z_pins[] = { GPIOZ_5 }; +static const unsigned int sdcard_clk_z_pins[] = { GPIOZ_6 }; +static const unsigned int sdcard_cmd_z_pins[] = { GPIOZ_7 }; + +/* spi0 */ +static const unsigned int spi0_mosi_c_pins[] = { GPIOC_0 }; +static const unsigned int spi0_miso_c_pins[] = { GPIOC_1 }; +static const unsigned int spi0_ss0_c_pins[] = { GPIOC_2 }; +static const unsigned int spi0_clk_c_pins[] = { GPIOC_3 }; + +static const unsigned int spi0_mosi_x_pins[] = { GPIOX_8 }; +static const unsigned int spi0_miso_x_pins[] = { GPIOX_9 }; +static const unsigned int spi0_ss0_x_pins[] = { GPIOX_10 }; +static const unsigned int spi0_clk_x_pins[] = { GPIOX_11 }; + +/* spi1 */ +static const unsigned int spi1_mosi_pins[] = { GPIOH_4 }; +static const unsigned int spi1_miso_pins[] = { GPIOH_5 }; +static const unsigned int spi1_ss0_pins[] = { GPIOH_6 }; +static const unsigned int spi1_clk_pins[] = { GPIOH_7 }; + +/* i2c0 */ +static const unsigned int i2c0_sda_c_pins[] = { GPIOC_5 }; +static const unsigned int i2c0_sck_c_pins[] = { GPIOC_6 }; +static const unsigned int i2c0_sda_z0_pins[] = { GPIOZ_0 }; +static const unsigned int i2c0_sck_z1_pins[] = { GPIOZ_1 }; +static const unsigned int i2c0_sda_z7_pins[] = { GPIOZ_7 }; +static const unsigned int i2c0_sck_z8_pins[] = { GPIOZ_8 }; + +/* i2c1 */ +static const unsigned int i2c1_sda_x_pins[] = { GPIOX_10 }; +static const unsigned int i2c1_sck_x_pins[] = { GPIOX_11 }; +static const unsigned int i2c1_sda_h2_pins[] = { GPIOH_2 }; +static const unsigned int i2c1_sck_h3_pins[] = { GPIOH_3 }; +static const unsigned int i2c1_sda_h6_pins[] = { GPIOH_6 }; +static const unsigned int i2c1_sck_h7_pins[] = { GPIOH_7 }; + +/* i2c2 */ +static const unsigned int i2c2_sda_x_pins[] = { GPIOX_17 }; +static const unsigned int i2c2_sck_x_pins[] = { GPIOX_18 }; +static const unsigned int i2c2_sda_z_pins[] = { GPIOZ_14 }; +static const unsigned int i2c2_sck_z_pins[] = { GPIOZ_15 }; + +/* i2c3 */ +static const unsigned int i2c3_sda_h_pins[] = { GPIOH_0 }; +static const unsigned int i2c3_sck_h_pins[] = { GPIOH_1 }; +static const unsigned int i2c3_sda_a_pins[] = { GPIOA_14 }; +static const unsigned int i2c3_sck_a_pins[] = { GPIOA_15 }; + +/* uart_a */ +static const unsigned int uart_a_tx_pins[] = { GPIOX_12 }; +static const unsigned int uart_a_rx_pins[] = { GPIOX_13 }; +static const unsigned int uart_a_cts_pins[] = { GPIOX_14 }; +static const unsigned int uart_a_rts_pins[] = { GPIOX_15 }; + +/* uart_b */ +static const unsigned int uart_b_tx_pins[] = { GPIOX_6 }; +static const unsigned int uart_b_rx_pins[] = { GPIOX_7 }; + +/* uart_c */ +static const unsigned int uart_c_rts_pins[] = { GPIOH_4 }; +static const unsigned int uart_c_cts_pins[] = { GPIOH_5 }; +static const unsigned int uart_c_rx_pins[] = { GPIOH_6 }; +static const unsigned int uart_c_tx_pins[] = { GPIOH_7 }; + +/* uart_ao_a_c */ +static const unsigned int uart_ao_a_rx_c_pins[] = { GPIOC_2 }; +static const unsigned int uart_ao_a_tx_c_pins[] = { GPIOC_3 }; + +/* iso7816 */ +static const unsigned int iso7816_clk_c_pins[] = { GPIOC_5 }; +static const unsigned int iso7816_data_c_pins[] = { GPIOC_6 }; +static const unsigned int iso7816_clk_x_pins[] = { GPIOX_8 }; +static const unsigned int iso7816_data_x_pins[] = { GPIOX_9 }; +static const unsigned int iso7816_clk_h_pins[] = { GPIOH_6 }; +static const unsigned int iso7816_data_h_pins[] = { GPIOH_7 }; +static const unsigned int iso7816_clk_z_pins[] = { GPIOZ_0 }; +static const unsigned int iso7816_data_z_pins[] = { GPIOZ_1 }; + +/* eth */ +static const unsigned int eth_mdio_pins[] = { GPIOZ_0 }; +static const unsigned int eth_mdc_pins[] = { GPIOZ_1 }; +static const unsigned int eth_rgmii_rx_clk_pins[] = { GPIOZ_2 }; +static const unsigned int eth_rx_dv_pins[] = { GPIOZ_3 }; +static const unsigned int eth_rxd0_pins[] = { GPIOZ_4 }; +static const unsigned int eth_rxd1_pins[] = { GPIOZ_5 }; +static const unsigned int eth_rxd2_rgmii_pins[] = { GPIOZ_6 }; +static const unsigned int eth_rxd3_rgmii_pins[] = { GPIOZ_7 }; +static const unsigned int eth_rgmii_tx_clk_pins[] = { GPIOZ_8 }; +static const unsigned int eth_txen_pins[] = { GPIOZ_9 }; +static const unsigned int eth_txd0_pins[] = { GPIOZ_10 }; +static const unsigned int eth_txd1_pins[] = { GPIOZ_11 }; +static const unsigned int eth_txd2_rgmii_pins[] = { GPIOZ_12 }; +static const unsigned int eth_txd3_rgmii_pins[] = { GPIOZ_13 }; +static const unsigned int eth_link_led_pins[] = { GPIOZ_14 }; +static const unsigned int eth_act_led_pins[] = { GPIOZ_15 }; + +/* pwm_a */ +static const unsigned int pwm_a_pins[] = { GPIOX_6 }; + +/* pwm_b */ +static const unsigned int pwm_b_x7_pins[] = { GPIOX_7 }; +static const unsigned int pwm_b_x19_pins[] = { GPIOX_19 }; + +/* pwm_c */ +static const unsigned int pwm_c_c_pins[] = { GPIOC_4 }; +static const unsigned int pwm_c_x5_pins[] = { GPIOX_5 }; +static const unsigned int pwm_c_x8_pins[] = { GPIOX_8 }; + +/* pwm_d */ +static const unsigned int pwm_d_x3_pins[] = { GPIOX_3 }; +static const unsigned int pwm_d_x6_pins[] = { GPIOX_6 }; + +/* pwm_e */ +static const unsigned int pwm_e_pins[] = { GPIOX_16 }; + +/* pwm_f */ +static const unsigned int pwm_f_x_pins[] = { GPIOX_7 }; +static const unsigned int pwm_f_h_pins[] = { GPIOH_5 }; + +/* cec_ao */ +static const unsigned int cec_ao_a_h_pins[] = { GPIOH_3 }; +static const unsigned int cec_ao_b_h_pins[] = { GPIOH_3 }; + +/* jtag_b */ +static const unsigned int jtag_b_tdo_pins[] = { GPIOC_0 }; +static const unsigned int jtag_b_tdi_pins[] = { GPIOC_1 }; +static const unsigned int jtag_b_clk_pins[] = { GPIOC_4 }; +static const unsigned int jtag_b_tms_pins[] = { GPIOC_5 }; + +/* bt565_a */ +static const unsigned int bt565_a_vs_pins[] = { GPIOZ_0 }; +static const unsigned int bt565_a_hs_pins[] = { GPIOZ_1 }; +static const unsigned int bt565_a_clk_pins[] = { GPIOZ_3 }; +static const unsigned int bt565_a_din0_pins[] = { GPIOZ_4 }; +static const unsigned int bt565_a_din1_pins[] = { GPIOZ_5 }; +static const unsigned int bt565_a_din2_pins[] = { GPIOZ_6 }; +static const unsigned int bt565_a_din3_pins[] = { GPIOZ_7 }; +static const unsigned int bt565_a_din4_pins[] = { GPIOZ_8 }; +static const unsigned int bt565_a_din5_pins[] = { GPIOZ_9 }; +static const unsigned int bt565_a_din6_pins[] = { GPIOZ_10 }; +static const unsigned int bt565_a_din7_pins[] = { GPIOZ_11 }; + +/* tsin_a */ +static const unsigned int tsin_a_valid_pins[] = { GPIOX_2 }; +static const unsigned int tsin_a_sop_pins[] = { GPIOX_1 }; +static const unsigned int tsin_a_din0_pins[] = { GPIOX_0 }; +static const unsigned int tsin_a_clk_pins[] = { GPIOX_3 }; + +/* tsin_b */ +static const unsigned int tsin_b_valid_x_pins[] = { GPIOX_9 }; +static const unsigned int tsin_b_sop_x_pins[] = { GPIOX_8 }; +static const unsigned int tsin_b_din0_x_pins[] = { GPIOX_10 }; +static const unsigned int tsin_b_clk_x_pins[] = { GPIOX_11 }; + +static const unsigned int tsin_b_valid_z_pins[] = { GPIOZ_2 }; +static const unsigned int tsin_b_sop_z_pins[] = { GPIOZ_3 }; +static const unsigned int tsin_b_din0_z_pins[] = { GPIOZ_4 }; +static const unsigned int tsin_b_clk_z_pins[] = { GPIOZ_5 }; + +static const unsigned int tsin_b_fail_pins[] = { GPIOZ_6 }; +static const unsigned int tsin_b_din1_pins[] = { GPIOZ_7 }; +static const unsigned int tsin_b_din2_pins[] = { GPIOZ_8 }; +static const unsigned int tsin_b_din3_pins[] = { GPIOZ_9 }; +static const unsigned int tsin_b_din4_pins[] = { GPIOZ_10 }; +static const unsigned int tsin_b_din5_pins[] = { GPIOZ_11 }; +static const unsigned int tsin_b_din6_pins[] = { GPIOZ_12 }; +static const unsigned int tsin_b_din7_pins[] = { GPIOZ_13 }; + +/* hdmitx */ +static const unsigned int hdmitx_sda_pins[] = { GPIOH_0 }; +static const unsigned int hdmitx_sck_pins[] = { GPIOH_1 }; +static const unsigned int hdmitx_hpd_in_pins[] = { GPIOH_2 }; + +/* pdm */ +static const unsigned int pdm_din0_c_pins[] = { GPIOC_0 }; +static const unsigned int pdm_din1_c_pins[] = { GPIOC_1 }; +static const unsigned int pdm_din2_c_pins[] = { GPIOC_2 }; +static const unsigned int pdm_din3_c_pins[] = { GPIOC_3 }; +static const unsigned int pdm_dclk_c_pins[] = { GPIOC_4 }; + +static const unsigned int pdm_din0_x_pins[] = { GPIOX_0 }; +static const unsigned int pdm_din1_x_pins[] = { GPIOX_1 }; +static const unsigned int pdm_din2_x_pins[] = { GPIOX_2 }; +static const unsigned int pdm_din3_x_pins[] = { GPIOX_3 }; +static const unsigned int pdm_dclk_x_pins[] = { GPIOX_4 }; + +static const unsigned int pdm_din0_z_pins[] = { GPIOZ_2 }; +static const unsigned int pdm_din1_z_pins[] = { GPIOZ_3 }; +static const unsigned int pdm_din2_z_pins[] = { GPIOZ_4 }; +static const unsigned int pdm_din3_z_pins[] = { GPIOZ_5 }; +static const unsigned int pdm_dclk_z_pins[] = { GPIOZ_6 }; + +static const unsigned int pdm_din0_a_pins[] = { GPIOA_8 }; +static const unsigned int pdm_din1_a_pins[] = { GPIOA_9 }; +static const unsigned int pdm_din2_a_pins[] = { GPIOA_6 }; +static const unsigned int pdm_din3_a_pins[] = { GPIOA_5 }; +static const unsigned int pdm_dclk_a_pins[] = { GPIOA_7 }; + +/* spdif_in */ +static const unsigned int spdif_in_h_pins[] = { GPIOH_5 }; +static const unsigned int spdif_in_a10_pins[] = { GPIOA_10 }; +static const unsigned int spdif_in_a12_pins[] = { GPIOA_12 }; + +/* spdif_out */ +static const unsigned int spdif_out_h_pins[] = { GPIOH_4 }; +static const unsigned int spdif_out_a11_pins[] = { GPIOA_11 }; +static const unsigned int spdif_out_a13_pins[] = { GPIOA_13 }; + +/* mclk0 */ +static const unsigned int mclk0_a_pins[] = { GPIOA_0 }; + +/* mclk1 */ +static const unsigned int mclk1_x_pins[] = { GPIOX_5 }; +static const unsigned int mclk1_z_pins[] = { GPIOZ_8 }; +static const unsigned int mclk1_a_pins[] = { GPIOA_11 }; + +/* tdm */ +static const unsigned int tdm_a_slv_sclk_pins[] = { GPIOX_11 }; +static const unsigned int tdm_a_slv_fs_pins[] = { GPIOX_10 }; +static const unsigned int tdm_a_sclk_pins[] = { GPIOX_11 }; +static const unsigned int tdm_a_fs_pins[] = { GPIOX_10 }; +static const unsigned int tdm_a_din0_pins[] = { GPIOX_9 }; +static const unsigned int tdm_a_din1_pins[] = { GPIOX_8 }; +static const unsigned int tdm_a_dout0_pins[] = { GPIOX_9 }; +static const unsigned int tdm_a_dout1_pins[] = { GPIOX_8 }; + +static const unsigned int tdm_b_slv_sclk_pins[] = { GPIOA_1 }; +static const unsigned int tdm_b_slv_fs_pins[] = { GPIOA_2 }; +static const unsigned int tdm_b_sclk_pins[] = { GPIOA_1 }; +static const unsigned int tdm_b_fs_pins[] = { GPIOA_2 }; +static const unsigned int tdm_b_din0_pins[] = { GPIOA_3 }; +static const unsigned int tdm_b_din1_pins[] = { GPIOA_4 }; +static const unsigned int tdm_b_din2_pins[] = { GPIOA_5 }; +static const unsigned int tdm_b_din3_a_pins[] = { GPIOA_6 }; +static const unsigned int tdm_b_din3_h_pins[] = { GPIOH_5 }; +static const unsigned int tdm_b_dout0_pins[] = { GPIOA_3 }; +static const unsigned int tdm_b_dout1_pins[] = { GPIOA_4 }; +static const unsigned int tdm_b_dout2_pins[] = { GPIOA_5 }; +static const unsigned int tdm_b_dout3_a_pins[] = { GPIOA_6 }; +static const unsigned int tdm_b_dout3_h_pins[] = { GPIOH_5 }; + +static const unsigned int tdm_c_slv_sclk_a_pins[] = { GPIOA_12 }; +static const unsigned int tdm_c_slv_fs_a_pins[] = { GPIOA_13 }; +static const unsigned int tdm_c_slv_sclk_z_pins[] = { GPIOZ_7 }; +static const unsigned int tdm_c_slv_fs_z_pins[] = { GPIOZ_6 }; +static const unsigned int tdm_c_sclk_a_pins[] = { GPIOA_12 }; +static const unsigned int tdm_c_fs_a_pins[] = { GPIOA_13 }; +static const unsigned int tdm_c_sclk_z_pins[] = { GPIOZ_7 }; +static const unsigned int tdm_c_fs_z_pins[] = { GPIOZ_6 }; +static const unsigned int tdm_c_din0_a_pins[] = { GPIOA_10 }; +static const unsigned int tdm_c_din1_a_pins[] = { GPIOA_9 }; +static const unsigned int tdm_c_din2_a_pins[] = { GPIOA_8 }; +static const unsigned int tdm_c_din3_a_pins[] = { GPIOA_7 }; +static const unsigned int tdm_c_din0_z_pins[] = { GPIOZ_2 }; +static const unsigned int tdm_c_din1_z_pins[] = { GPIOZ_3 }; +static const unsigned int tdm_c_din2_z_pins[] = { GPIOZ_4 }; +static const unsigned int tdm_c_din3_z_pins[] = { GPIOZ_5 }; +static const unsigned int tdm_c_dout0_a_pins[] = { GPIOA_10 }; +static const unsigned int tdm_c_dout1_a_pins[] = { GPIOA_9 }; +static const unsigned int tdm_c_dout2_a_pins[] = { GPIOA_8 }; +static const unsigned int tdm_c_dout3_a_pins[] = { GPIOA_7 }; +static const unsigned int tdm_c_dout0_z_pins[] = { GPIOZ_2 }; +static const unsigned int tdm_c_dout1_z_pins[] = { GPIOZ_3 }; +static const unsigned int tdm_c_dout2_z_pins[] = { GPIOZ_4 }; +static const unsigned int tdm_c_dout3_z_pins[] = { GPIOZ_5 }; + +static struct meson_pmx_group meson_g12a_periphs_groups[] = { + GPIO_GROUP(GPIOZ_0), + GPIO_GROUP(GPIOZ_1), + GPIO_GROUP(GPIOZ_2), + GPIO_GROUP(GPIOZ_3), + GPIO_GROUP(GPIOZ_4), + GPIO_GROUP(GPIOZ_5), + GPIO_GROUP(GPIOZ_6), + GPIO_GROUP(GPIOZ_7), + GPIO_GROUP(GPIOZ_8), + GPIO_GROUP(GPIOZ_9), + GPIO_GROUP(GPIOZ_10), + GPIO_GROUP(GPIOZ_11), + GPIO_GROUP(GPIOZ_12), + GPIO_GROUP(GPIOZ_13), + GPIO_GROUP(GPIOZ_14), + GPIO_GROUP(GPIOZ_15), + GPIO_GROUP(GPIOH_0), + GPIO_GROUP(GPIOH_1), + GPIO_GROUP(GPIOH_2), + GPIO_GROUP(GPIOH_3), + GPIO_GROUP(GPIOH_4), + GPIO_GROUP(GPIOH_5), + GPIO_GROUP(GPIOH_6), + GPIO_GROUP(GPIOH_7), + GPIO_GROUP(GPIOH_8), + GPIO_GROUP(BOOT_0), + GPIO_GROUP(BOOT_1), + GPIO_GROUP(BOOT_2), + GPIO_GROUP(BOOT_3), + GPIO_GROUP(BOOT_4), + GPIO_GROUP(BOOT_5), + GPIO_GROUP(BOOT_6), + GPIO_GROUP(BOOT_7), + GPIO_GROUP(BOOT_8), + GPIO_GROUP(BOOT_9), + GPIO_GROUP(BOOT_10), + GPIO_GROUP(BOOT_11), + GPIO_GROUP(BOOT_12), + GPIO_GROUP(BOOT_13), + GPIO_GROUP(BOOT_14), + GPIO_GROUP(BOOT_15), + GPIO_GROUP(GPIOC_0), + GPIO_GROUP(GPIOC_1), + GPIO_GROUP(GPIOC_2), + GPIO_GROUP(GPIOC_3), + GPIO_GROUP(GPIOC_4), + GPIO_GROUP(GPIOC_5), + GPIO_GROUP(GPIOC_6), + GPIO_GROUP(GPIOC_7), + GPIO_GROUP(GPIOA_0), + GPIO_GROUP(GPIOA_1), + GPIO_GROUP(GPIOA_2), + GPIO_GROUP(GPIOA_3), + GPIO_GROUP(GPIOA_4), + GPIO_GROUP(GPIOA_5), + GPIO_GROUP(GPIOA_6), + GPIO_GROUP(GPIOA_7), + GPIO_GROUP(GPIOA_8), + GPIO_GROUP(GPIOA_9), + GPIO_GROUP(GPIOA_10), + GPIO_GROUP(GPIOA_11), + GPIO_GROUP(GPIOA_12), + GPIO_GROUP(GPIOA_13), + GPIO_GROUP(GPIOA_14), + GPIO_GROUP(GPIOA_15), + GPIO_GROUP(GPIOX_0), + GPIO_GROUP(GPIOX_1), + GPIO_GROUP(GPIOX_2), + GPIO_GROUP(GPIOX_3), + GPIO_GROUP(GPIOX_4), + GPIO_GROUP(GPIOX_5), + GPIO_GROUP(GPIOX_6), + GPIO_GROUP(GPIOX_7), + GPIO_GROUP(GPIOX_8), + GPIO_GROUP(GPIOX_9), + GPIO_GROUP(GPIOX_10), + GPIO_GROUP(GPIOX_11), + GPIO_GROUP(GPIOX_12), + GPIO_GROUP(GPIOX_13), + GPIO_GROUP(GPIOX_14), + GPIO_GROUP(GPIOX_15), + GPIO_GROUP(GPIOX_16), + GPIO_GROUP(GPIOX_17), + GPIO_GROUP(GPIOX_18), + GPIO_GROUP(GPIOX_19), + + /* bank BOOT */ + GROUP(emmc_nand_d0, 1), + GROUP(emmc_nand_d1, 1), + GROUP(emmc_nand_d2, 1), + GROUP(emmc_nand_d3, 1), + GROUP(emmc_nand_d4, 1), + GROUP(emmc_nand_d5, 1), + GROUP(emmc_nand_d6, 1), + GROUP(emmc_nand_d7, 1), + GROUP(emmc_clk, 1), + GROUP(emmc_cmd, 1), + GROUP(emmc_nand_ds, 1), + GROUP(nand_ce0, 2), + GROUP(nand_ale, 2), + GROUP(nand_cle, 2), + GROUP(nand_wen_clk, 2), + GROUP(nand_ren_wr, 2), + GROUP(nand_rb0, 2), + GROUP(nand_ce1, 2), + GROUP(nor_hold, 3), + GROUP(nor_d, 3), + GROUP(nor_q, 3), + GROUP(nor_c, 3), + GROUP(nor_wp, 3), + GROUP(nor_cs, 3), + + /* bank GPIOZ */ + GROUP(sdcard_d0_z, 5), + GROUP(sdcard_d1_z, 5), + GROUP(sdcard_d2_z, 5), + GROUP(sdcard_d3_z, 5), + GROUP(sdcard_clk_z, 5), + GROUP(sdcard_cmd_z, 5), + GROUP(i2c0_sda_z0, 4), + GROUP(i2c0_sck_z1, 4), + GROUP(i2c0_sda_z7, 7), + GROUP(i2c0_sck_z8, 7), + GROUP(i2c2_sda_z, 3), + GROUP(i2c2_sck_z, 3), + GROUP(iso7816_clk_z, 3), + GROUP(iso7816_data_z, 3), + GROUP(eth_mdio, 1), + GROUP(eth_mdc, 1), + GROUP(eth_rgmii_rx_clk, 1), + GROUP(eth_rx_dv, 1), + GROUP(eth_rxd0, 1), + GROUP(eth_rxd1, 1), + GROUP(eth_rxd2_rgmii, 1), + GROUP(eth_rxd3_rgmii, 1), + GROUP(eth_rgmii_tx_clk, 1), + GROUP(eth_txen, 1), + GROUP(eth_txd0, 1), + GROUP(eth_txd1, 1), + GROUP(eth_txd2_rgmii, 1), + GROUP(eth_txd3_rgmii, 1), + GROUP(eth_link_led, 1), + GROUP(eth_act_led, 1), + GROUP(bt565_a_vs, 2), + GROUP(bt565_a_hs, 2), + GROUP(bt565_a_clk, 2), + GROUP(bt565_a_din0, 2), + GROUP(bt565_a_din1, 2), + GROUP(bt565_a_din2, 2), + GROUP(bt565_a_din3, 2), + GROUP(bt565_a_din4, 2), + GROUP(bt565_a_din5, 2), + GROUP(bt565_a_din6, 2), + GROUP(bt565_a_din7, 2), + GROUP(tsin_b_valid_z, 3), + GROUP(tsin_b_sop_z, 3), + GROUP(tsin_b_din0_z, 3), + GROUP(tsin_b_clk_z, 3), + GROUP(tsin_b_fail, 3), + GROUP(tsin_b_din1, 3), + GROUP(tsin_b_din2, 3), + GROUP(tsin_b_din3, 3), + GROUP(tsin_b_din4, 3), + GROUP(tsin_b_din5, 3), + GROUP(tsin_b_din6, 3), + GROUP(tsin_b_din7, 3), + GROUP(pdm_din0_z, 7), + GROUP(pdm_din1_z, 7), + GROUP(pdm_din2_z, 7), + GROUP(pdm_din3_z, 7), + GROUP(pdm_dclk_z, 7), + GROUP(tdm_c_slv_sclk_z, 6), + GROUP(tdm_c_slv_fs_z, 6), + GROUP(tdm_c_din0_z, 6), + GROUP(tdm_c_din1_z, 6), + GROUP(tdm_c_din2_z, 6), + GROUP(tdm_c_din3_z, 6), + GROUP(tdm_c_sclk_z, 4), + GROUP(tdm_c_fs_z, 4), + GROUP(tdm_c_dout0_z, 4), + GROUP(tdm_c_dout1_z, 4), + GROUP(tdm_c_dout2_z, 4), + GROUP(tdm_c_dout3_z, 4), + GROUP(mclk1_z, 4), + + /* bank GPIOX */ + GROUP(sdio_d0, 1), + GROUP(sdio_d1, 1), + GROUP(sdio_d2, 1), + GROUP(sdio_d3, 1), + GROUP(sdio_clk, 1), + GROUP(sdio_cmd, 1), + GROUP(spi0_mosi_x, 4), + GROUP(spi0_miso_x, 4), + GROUP(spi0_ss0_x, 4), + GROUP(spi0_clk_x, 4), + GROUP(i2c1_sda_x, 5), + GROUP(i2c1_sck_x, 5), + GROUP(i2c2_sda_x, 1), + GROUP(i2c2_sck_x, 1), + GROUP(uart_a_tx, 1), + GROUP(uart_a_rx, 1), + GROUP(uart_a_cts, 1), + GROUP(uart_a_rts, 1), + GROUP(uart_b_tx, 2), + GROUP(uart_b_rx, 2), + GROUP(iso7816_clk_x, 6), + GROUP(iso7816_data_x, 6), + GROUP(pwm_a, 1), + GROUP(pwm_b_x7, 4), + GROUP(pwm_b_x19, 1), + GROUP(pwm_c_x5, 4), + GROUP(pwm_c_x8, 5), + GROUP(pwm_d_x3, 4), + GROUP(pwm_d_x6, 4), + GROUP(pwm_e, 1), + GROUP(pwm_f_x, 1), + GROUP(tsin_a_valid, 3), + GROUP(tsin_a_sop, 3), + GROUP(tsin_a_din0, 3), + GROUP(tsin_a_clk, 3), + GROUP(tsin_b_valid_x, 3), + GROUP(tsin_b_sop_x, 3), + GROUP(tsin_b_din0_x, 3), + GROUP(tsin_b_clk_x, 3), + GROUP(pdm_din0_x, 2), + GROUP(pdm_din1_x, 2), + GROUP(pdm_din2_x, 2), + GROUP(pdm_din3_x, 2), + GROUP(pdm_dclk_x, 2), + GROUP(tdm_a_slv_sclk, 2), + GROUP(tdm_a_slv_fs, 2), + GROUP(tdm_a_din0, 2), + GROUP(tdm_a_din1, 2), + GROUP(tdm_a_sclk, 1), + GROUP(tdm_a_fs, 1), + GROUP(tdm_a_dout0, 1), + GROUP(tdm_a_dout1, 1), + GROUP(mclk1_x, 2), + + /* bank GPIOC */ + GROUP(sdcard_d0_c, 1), + GROUP(sdcard_d1_c, 1), + GROUP(sdcard_d2_c, 1), + GROUP(sdcard_d3_c, 1), + GROUP(sdcard_clk_c, 1), + GROUP(sdcard_cmd_c, 1), + GROUP(spi0_mosi_c, 5), + GROUP(spi0_miso_c, 5), + GROUP(spi0_ss0_c, 5), + GROUP(spi0_clk_c, 5), + GROUP(i2c0_sda_c, 3), + GROUP(i2c0_sck_c, 3), + GROUP(uart_ao_a_rx_c, 2), + GROUP(uart_ao_a_tx_c, 2), + GROUP(iso7816_clk_c, 5), + GROUP(iso7816_data_c, 5), + GROUP(pwm_c_c, 5), + GROUP(jtag_b_tdo, 2), + GROUP(jtag_b_tdi, 2), + GROUP(jtag_b_clk, 2), + GROUP(jtag_b_tms, 2), + GROUP(pdm_din0_c, 4), + GROUP(pdm_din1_c, 4), + GROUP(pdm_din2_c, 4), + GROUP(pdm_din3_c, 4), + GROUP(pdm_dclk_c, 4), + + /* bank GPIOH */ + GROUP(spi1_mosi, 3), + GROUP(spi1_miso, 3), + GROUP(spi1_ss0, 3), + GROUP(spi1_clk, 3), + GROUP(i2c1_sda_h2, 2), + GROUP(i2c1_sck_h3, 2), + GROUP(i2c1_sda_h6, 4), + GROUP(i2c1_sck_h7, 4), + GROUP(i2c3_sda_h, 2), + GROUP(i2c3_sck_h, 2), + GROUP(uart_c_tx, 2), + GROUP(uart_c_rx, 2), + GROUP(uart_c_cts, 2), + GROUP(uart_c_rts, 2), + GROUP(iso7816_clk_h, 1), + GROUP(iso7816_data_h, 1), + GROUP(pwm_f_h, 4), + GROUP(cec_ao_a_h, 4), + GROUP(cec_ao_b_h, 5), + GROUP(hdmitx_sda, 1), + GROUP(hdmitx_sck, 1), + GROUP(hdmitx_hpd_in, 1), + GROUP(spdif_out_h, 1), + GROUP(spdif_in_h, 1), + GROUP(tdm_b_din3_h, 6), + GROUP(tdm_b_dout3_h, 5), + + /* bank GPIOA */ + GROUP(i2c3_sda_a, 2), + GROUP(i2c3_sck_a, 2), + GROUP(pdm_din0_a, 1), + GROUP(pdm_din1_a, 1), + GROUP(pdm_din2_a, 1), + GROUP(pdm_din3_a, 1), + GROUP(pdm_dclk_a, 1), + GROUP(spdif_in_a10, 1), + GROUP(spdif_in_a12, 1), + GROUP(spdif_out_a11, 1), + GROUP(spdif_out_a13, 1), + GROUP(tdm_b_slv_sclk, 2), + GROUP(tdm_b_slv_fs, 2), + GROUP(tdm_b_din0, 2), + GROUP(tdm_b_din1, 2), + GROUP(tdm_b_din2, 2), + GROUP(tdm_b_din3_a, 2), + GROUP(tdm_b_sclk, 1), + GROUP(tdm_b_fs, 1), + GROUP(tdm_b_dout0, 1), + GROUP(tdm_b_dout1, 1), + GROUP(tdm_b_dout2, 3), + GROUP(tdm_b_dout3_a, 3), + GROUP(tdm_c_slv_sclk_a, 3), + GROUP(tdm_c_slv_fs_a, 3), + GROUP(tdm_c_din0_a, 3), + GROUP(tdm_c_din1_a, 3), + GROUP(tdm_c_din2_a, 3), + GROUP(tdm_c_din3_a, 3), + GROUP(tdm_c_sclk_a, 2), + GROUP(tdm_c_fs_a, 2), + GROUP(tdm_c_dout0_a, 2), + GROUP(tdm_c_dout1_a, 2), + GROUP(tdm_c_dout2_a, 2), + GROUP(tdm_c_dout3_a, 2), + GROUP(mclk0_a, 1), + GROUP(mclk1_a, 2), +}; + +/* uart_ao_a */ +static const unsigned int uart_ao_a_tx_pins[] = { GPIOAO_0 }; +static const unsigned int uart_ao_a_rx_pins[] = { GPIOAO_1 }; +static const unsigned int uart_ao_a_cts_pins[] = { GPIOE_0 }; +static const unsigned int uart_ao_a_rts_pins[] = { GPIOE_1 }; + +/* uart_ao_b */ +static const unsigned int uart_ao_b_tx_2_pins[] = { GPIOAO_2 }; +static const unsigned int uart_ao_b_rx_3_pins[] = { GPIOAO_3 }; +static const unsigned int uart_ao_b_tx_8_pins[] = { GPIOAO_8 }; +static const unsigned int uart_ao_b_rx_9_pins[] = { GPIOAO_9 }; +static const unsigned int uart_ao_b_cts_pins[] = { GPIOE_0 }; +static const unsigned int uart_ao_b_rts_pins[] = { GPIOE_1 }; + +/* i2c_ao */ +static const unsigned int i2c_ao_sck_pins[] = { GPIOAO_2 }; +static const unsigned int i2c_ao_sda_pins[] = { GPIOAO_3 }; + +static const unsigned int i2c_ao_sck_e_pins[] = { GPIOE_0 }; +static const unsigned int i2c_ao_sda_e_pins[] = { GPIOE_1 }; + +/* i2c_ao_slave */ +static const unsigned int i2c_ao_slave_sck_pins[] = { GPIOAO_2 }; +static const unsigned int i2c_ao_slave_sda_pins[] = { GPIOAO_3 }; + +/* ir_in */ +static const unsigned int remote_ao_input_pins[] = { GPIOAO_5 }; + +/* ir_out */ +static const unsigned int remote_ao_out_pins[] = { GPIOAO_4 }; + +/* pwm_ao_a */ +static const unsigned int pwm_ao_a_pins[] = { GPIOAO_11 }; +static const unsigned int pwm_ao_a_hiz_pins[] = { GPIOAO_11 }; + +/* pwm_ao_b */ +static const unsigned int pwm_ao_b_pins[] = { GPIOE_0 }; + +/* pwm_ao_c */ +static const unsigned int pwm_ao_c_4_pins[] = { GPIOAO_4 }; +static const unsigned int pwm_ao_c_hiz_pins[] = { GPIOAO_4 }; +static const unsigned int pwm_ao_c_6_pins[] = { GPIOAO_6 }; + +/* pwm_ao_d */ +static const unsigned int pwm_ao_d_5_pins[] = { GPIOAO_5 }; +static const unsigned int pwm_ao_d_10_pins[] = { GPIOAO_10 }; +static const unsigned int pwm_ao_d_e_pins[] = { GPIOE_1 }; + +/* jtag_a */ +static const unsigned int jtag_a_tdi_pins[] = { GPIOAO_8 }; +static const unsigned int jtag_a_tdo_pins[] = { GPIOAO_9 }; +static const unsigned int jtag_a_clk_pins[] = { GPIOAO_6 }; +static const unsigned int jtag_a_tms_pins[] = { GPIOAO_7 }; + +/* cec_ao */ +static const unsigned int cec_ao_a_pins[] = { GPIOAO_10 }; +static const unsigned int cec_ao_b_pins[] = { GPIOAO_10 }; + +/* tsin_ao_a */ +static const unsigned int tsin_ao_asop_pins[] = { GPIOAO_6 }; +static const unsigned int tsin_ao_adin0_pins[] = { GPIOAO_7 }; +static const unsigned int tsin_ao_aclk_pins[] = { GPIOAO_8 }; +static const unsigned int tsin_ao_a_valid_pins[] = { GPIOAO_9 }; + +/* spdif_ao_out */ +static const unsigned int spdif_ao_out_pins[] = { GPIOAO_10 }; + +/* tdm_ao_b */ +static const unsigned int tdm_ao_b_slv_fs_pins[] = { GPIOAO_7 }; +static const unsigned int tdm_ao_b_slv_sclk_pins[] = { GPIOAO_8 }; +static const unsigned int tdm_ao_b_fs_pins[] = { GPIOAO_7 }; +static const unsigned int tdm_ao_b_sclk_pins[] = { GPIOAO_8 }; +static const unsigned int tdm_ao_b_din0_pins[] = { GPIOAO_4 }; +static const unsigned int tdm_ao_b_din1_pins[] = { GPIOAO_10 }; +static const unsigned int tdm_ao_b_din2_pins[] = { GPIOAO_6 }; +static const unsigned int tdm_ao_b_dout0_pins[] = { GPIOAO_4 }; +static const unsigned int tdm_ao_b_dout1_pins[] = { GPIOAO_10 }; +static const unsigned int tdm_ao_b_dout2_pins[] = { GPIOAO_6 }; + +/* mclk0_ao */ +static const unsigned int mclk0_ao_pins[] = { GPIOAO_9 }; + +static struct meson_pmx_group meson_g12a_aobus_groups[] = { + GPIO_GROUP(GPIOAO_0), + GPIO_GROUP(GPIOAO_1), + GPIO_GROUP(GPIOAO_2), + GPIO_GROUP(GPIOAO_3), + GPIO_GROUP(GPIOAO_4), + GPIO_GROUP(GPIOAO_5), + GPIO_GROUP(GPIOAO_6), + GPIO_GROUP(GPIOAO_7), + GPIO_GROUP(GPIOAO_8), + GPIO_GROUP(GPIOAO_9), + GPIO_GROUP(GPIOAO_10), + GPIO_GROUP(GPIOAO_11), + GPIO_GROUP(GPIOE_0), + GPIO_GROUP(GPIOE_1), + GPIO_GROUP(GPIOE_2), + + /* bank AO */ + GROUP(uart_ao_a_tx, 1), + GROUP(uart_ao_a_rx, 1), + GROUP(uart_ao_a_cts, 1), + GROUP(uart_ao_a_rts, 1), + GROUP(uart_ao_b_tx_2, 2), + GROUP(uart_ao_b_rx_3, 2), + GROUP(uart_ao_b_tx_8, 3), + GROUP(uart_ao_b_rx_9, 3), + GROUP(uart_ao_b_cts, 2), + GROUP(uart_ao_b_rts, 2), + GROUP(i2c_ao_sck, 1), + GROUP(i2c_ao_sda, 1), + GROUP(i2c_ao_sck_e, 4), + GROUP(i2c_ao_sda_e, 4), + GROUP(i2c_ao_slave_sck, 3), + GROUP(i2c_ao_slave_sda, 3), + GROUP(remote_ao_input, 1), + GROUP(remote_ao_out, 1), + GROUP(pwm_ao_a, 3), + GROUP(pwm_ao_a_hiz, 2), + GROUP(pwm_ao_b, 3), + GROUP(pwm_ao_c_4, 3), + GROUP(pwm_ao_c_hiz, 4), + GROUP(pwm_ao_c_6, 3), + GROUP(pwm_ao_d_5, 3), + GROUP(pwm_ao_d_10, 3), + GROUP(pwm_ao_d_e, 3), + GROUP(jtag_a_tdi, 1), + GROUP(jtag_a_tdo, 1), + GROUP(jtag_a_clk, 1), + GROUP(jtag_a_tms, 1), + GROUP(cec_ao_a, 1), + GROUP(cec_ao_b, 2), + GROUP(tsin_ao_asop, 4), + GROUP(tsin_ao_adin0, 4), + GROUP(tsin_ao_aclk, 4), + GROUP(tsin_ao_a_valid, 4), + GROUP(spdif_ao_out, 4), + GROUP(tdm_ao_b_dout0, 5), + GROUP(tdm_ao_b_dout1, 5), + GROUP(tdm_ao_b_dout2, 5), + GROUP(tdm_ao_b_fs, 5), + GROUP(tdm_ao_b_sclk, 5), + GROUP(tdm_ao_b_din0, 6), + GROUP(tdm_ao_b_din1, 6), + GROUP(tdm_ao_b_din2, 6), + GROUP(tdm_ao_b_slv_fs, 6), + GROUP(tdm_ao_b_slv_sclk, 6), + GROUP(mclk0_ao, 5), +}; + +static const char * const gpio_periphs_groups[] = { + "GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4", + "GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9", + "GPIOZ_10", "GPIOZ_11", "GPIOZ_12", "GPIOZ_13", "GPIOZ_14", + "GPIOZ_15", + + "GPIOH_0", "GPIOH_1", "GPIOH_2", "GPIOH_3", "GPIOH_4", + "GPIOH_5", "GPIOH_6", "GPIOH_7", "GPIOH_8", + + "BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4", + "BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9", + "BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14", + "BOOT_15", + + "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", + "GPIOC_5", "GPIOC_6", "GPIOC_7", + + "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", + "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", + "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", + "GPIOA_15", + + "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4", + "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9", + "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14", + "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19", +}; + +static const char * const emmc_groups[] = { + "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2", + "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5", + "emmc_nand_d6", "emmc_nand_d7", + "emmc_clk", "emmc_cmd", "emmc_nand_ds", +}; + +static const char * const nand_groups[] = { + "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2", + "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5", + "emmc_nand_d6", "emmc_nand_d7", + "nand_ce0", "nand_ale", "nand_cle", + "nand_wen_clk", "nand_ren_wr", "nand_rb0", + "emmc_nand_ds", "nand_ce1", +}; + +static const char * const nor_groups[] = { + "nor_d", "nor_q", "nor_c", "nor_cs", + "nor_hold", "nor_wp", +}; + +static const char * const sdio_groups[] = { + "sdio_d0", "sdio_d1", "sdio_d2", "sdio_d3", + "sdio_cmd", "sdio_clk", "sdio_dummy", +}; + +static const char * const sdcard_groups[] = { + "sdcard_d0_c", "sdcard_d1_c", "sdcard_d2_c", "sdcard_d3_c", + "sdcard_clk_c", "sdcard_cmd_c", + "sdcard_d0_z", "sdcard_d1_z", "sdcard_d2_z", "sdcard_d3_z", + "sdcard_clk_z", "sdcard_cmd_z", +}; + +static const char * const spi0_groups[] = { + "spi0_mosi_c", "spi0_miso_c", "spi0_ss0_c", "spi0_clk_c", + "spi0_mosi_x", "spi0_miso_x", "spi0_ss0_x", "spi0_clk_x", +}; + +static const char * const spi1_groups[] = { + "spi1_mosi", "spi1_miso", "spi1_ss0", "spi1_clk", +}; + +static const char * const i2c0_groups[] = { + "i2c0_sda_c", "i2c0_sck_c", + "i2c0_sda_z0", "i2c0_sck_z1", + "i2c0_sda_z7", "i2c0_sck_z8", +}; + +static const char * const i2c1_groups[] = { + "i2c1_sda_x", "i2c1_sck_x", + "i2c1_sda_h2", "i2c1_sck_h3", + "i2c1_sda_h6", "i2c1_sck_h7", +}; + +static const char * const i2c2_groups[] = { + "i2c2_sda_x", "i2c2_sck_x", + "i2c2_sda_z", "i2c2_sck_z", +}; + +static const char * const i2c3_groups[] = { + "i2c3_sda_h", "i2c3_sck_h", + "i2c3_sda_a", "i2c3_sck_a", +}; + +static const char * const uart_a_groups[] = { + "uart_a_tx", "uart_a_rx", "uart_a_cts", "uart_a_rts", +}; + +static const char * const uart_b_groups[] = { + "uart_b_tx", "uart_b_rx", +}; + +static const char * const uart_c_groups[] = { + "uart_c_tx", "uart_c_rx", "uart_c_cts", "uart_c_rts", +}; + +static const char * const uart_ao_a_c_groups[] = { + "uart_ao_a_rx_c", "uart_ao_a_tx_c", +}; + +static const char * const iso7816_groups[] = { + "iso7816_clk_c", "iso7816_data_c", + "iso7816_clk_x", "iso7816_data_x", + "iso7816_clk_h", "iso7816_data_h", + "iso7816_clk_z", "iso7816_data_z", +}; + +static const char * const eth_groups[] = { + "eth_rxd2_rgmii", "eth_rxd3_rgmii", "eth_rgmii_tx_clk", + "eth_txd2_rgmii", "eth_txd3_rgmii", "eth_rgmii_rx_clk", + "eth_txd0", "eth_txd1", "eth_txen", "eth_mdc", + "eth_rxd0", "eth_rxd1", "eth_rx_dv", "eth_mdio", + "eth_link_led", "eth_act_led", +}; + +static const char * const pwm_a_groups[] = { + "pwm_a", +}; + +static const char * const pwm_b_groups[] = { + "pwm_b_x7", "pwm_b_x19", +}; + +static const char * const pwm_c_groups[] = { + "pwm_c_c", "pwm_c_x5", "pwm_c_x8", +}; + +static const char * const pwm_d_groups[] = { + "pwm_d_x3", "pwm_d_x6", +}; + +static const char * const pwm_e_groups[] = { + "pwm_e", +}; + +static const char * const pwm_f_groups[] = { + "pwm_f_x", "pwm_f_h", +}; + +static const char * const cec_ao_a_h_groups[] = { + "cec_ao_a_h", +}; + +static const char * const cec_ao_b_h_groups[] = { + "cec_ao_b_h", +}; + +static const char * const jtag_b_groups[] = { + "jtag_b_tdi", "jtag_b_tdo", "jtag_b_clk", "jtag_b_tms", +}; + +static const char * const bt565_a_groups[] = { + "bt565_a_vs", "bt565_a_hs", "bt565_a_clk", + "bt565_a_din0", "bt565_a_din1", "bt565_a_din2", + "bt565_a_din3", "bt565_a_din4", "bt565_a_din5", + "bt565_a_din6", "bt565_a_din7", +}; + +static const char * const tsin_a_groups[] = { + "tsin_a_valid", "tsin_a_sop", "tsin_a_din0", + "tsin_a_clk", +}; + +static const char * const tsin_b_groups[] = { + "tsin_b_valid_x", "tsin_b_sop_x", "tsin_b_din0_x", "tsin_b_clk_x", + "tsin_b_valid_z", "tsin_b_sop_z", "tsin_b_din0_z", "tsin_b_clk_z", + "tsin_b_fail", "tsin_b_din1", "tsin_b_din2", "tsin_b_din3", + "tsin_b_din4", "tsin_b_din5", "tsin_b_din6", "tsin_b_din7", +}; + +static const char * const hdmitx_groups[] = { + "hdmitx_sda", "hdmitx_sck", "hdmitx_hpd_in", +}; + +static const char * const pdm_groups[] = { + "pdm_din0_c", "pdm_din1_c", "pdm_din2_c", "pdm_din3_c", + "pdm_dclk_c", + "pdm_din0_x", "pdm_din1_x", "pdm_din2_x", "pdm_din3_x", + "pdm_dclk_x", + "pdm_din0_z", "pdm_din1_z", "pdm_din2_z", "pdm_din3_z", + "pdm_dclk_z", + "pdm_din0_a", "pdm_din1_a", "pdm_din2_a", "pdm_din3_a", + "pdm_dclk_a", +}; + +static const char * const spdif_in_groups[] = { + "spdif_in_h", "spdif_in_a10", "spdif_in_a12", +}; + +static const char * const spdif_out_groups[] = { + "spdif_out_h", "spdif_out_a11", "spdif_out_a13", +}; + +static const char * const mclk0_groups[] = { + "mclk0_a", +}; + +static const char * const mclk1_groups[] = { + "mclk1_x", "mclk1_z", "mclk1_a", +}; + +static const char * const tdm_a_groups[] = { + "tdm_a_slv_sclk", "tdm_a_slv_fs", "tdm_a_sclk", "tdm_a_fs", + "tdm_a_din0", "tdm_a_din1", "tdm_a_dout0", "tdm_a_dout1", +}; + +static const char * const tdm_b_groups[] = { + "tdm_b_slv_sclk", "tdm_b_slv_fs", "tdm_b_sclk", "tdm_b_fs", + "tdm_b_din0", "tdm_b_din1", "tdm_b_din2", + "tdm_b_din3_a", "tdm_b_din3_h", + "tdm_b_dout0", "tdm_b_dout1", "tdm_b_dout2", + "tdm_b_dout3_a", "tdm_b_dout3_h", +}; + +static const char * const tdm_c_groups[] = { + "tdm_c_slv_sclk_a", "tdm_c_slv_fs_a", + "tdm_c_slv_sclk_z", "tdm_c_slv_fs_z", + "tdm_c_sclk_a", "tdm_c_fs_a", + "tdm_c_sclk_z", "tdm_c_fs_z", + "tdm_c_din0_a", "tdm_c_din1_a", + "tdm_c_din2_a", "tdm_c_din3_a", + "tdm_c_din0_z", "tdm_c_din1_z", + "tdm_c_din2_z", "tdm_c_din3_z", + "tdm_c_dout0_a", "tdm_c_dout1_a", + "tdm_c_dout2_a", "tdm_c_dout3_a", + "tdm_c_dout0_z", "tdm_c_dout1_z", + "tdm_c_dout2_z", "tdm_c_dout3_z", +}; + +static const char * const gpio_aobus_groups[] = { + "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4", + "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9", + "GPIOAO_10", "GPIOAO_11", "GPIOE_0", "GPIOE_1", "GPIOE_2", +}; + +static const char * const uart_ao_a_groups[] = { + "uart_ao_a_tx", "uart_ao_a_rx", + "uart_ao_a_cts", "uart_ao_a_rts", +}; + +static const char * const uart_ao_b_groups[] = { + "uart_ao_b_tx_2", "uart_ao_b_rx_3", + "uart_ao_b_tx_8", "uart_ao_b_rx_9", + "uart_ao_b_cts", "uart_ao_b_rts", +}; + +static const char * const i2c_ao_groups[] = { + "i2c_ao_sck", "i2c_ao_sda", + "i2c_ao_sck_e", "i2c_ao_sda_e", +}; + +static const char * const i2c_ao_slave_groups[] = { + "i2c_ao_slave_sck", "i2c_ao_slave_sda", +}; + +static const char * const remote_ao_input_groups[] = { + "remote_ao_input", +}; + +static const char * const remote_ao_out_groups[] = { + "remote_ao_out", +}; + +static const char * const pwm_ao_a_groups[] = { + "pwm_ao_a", "pwm_ao_a_hiz", +}; + +static const char * const pwm_ao_b_groups[] = { + "pwm_ao_b", +}; + +static const char * const pwm_ao_c_groups[] = { + "pwm_ao_c_4", "pwm_ao_c_hiz", + "pwm_ao_c_6", +}; + +static const char * const pwm_ao_d_groups[] = { + "pwm_ao_d_5", "pwm_ao_d_10", "pwm_ao_d_e", +}; + +static const char * const jtag_a_groups[] = { + "jtag_a_tdi", "jtag_a_tdo", "jtag_a_clk", "jtag_a_tms", +}; + +static const char * const cec_ao_a_groups[] = { + "cec_ao_a", +}; + +static const char * const cec_ao_b_groups[] = { + "cec_ao_b", +}; + +static const char * const tsin_ao_a_groups[] = { + "tsin_ao_asop", "tsin_ao_adin0", "tsin_ao_aclk", "tsin_ao_a_valid", +}; + +static const char * const spdif_ao_out_groups[] = { + "spdif_ao_out", +}; + +static const char * const tdm_ao_b_groups[] = { + "tdm_ao_b_dout0", "tdm_ao_b_dout1", "tdm_ao_b_dout2", + "tdm_ao_b_fs", "tdm_ao_b_sclk", + "tdm_ao_b_din0", "tdm_ao_b_din1", "tdm_ao_b_din2", + "tdm_ao_b_slv_fs", "tdm_ao_b_slv_sclk", +}; + +static const char * const mclk0_ao_groups[] = { + "mclk0_ao", +}; + +static struct meson_pmx_func meson_g12a_periphs_functions[] = { + FUNCTION(gpio_periphs), + FUNCTION(emmc), + FUNCTION(nor), + FUNCTION(spi0), + FUNCTION(spi1), + FUNCTION(sdio), + FUNCTION(nand), + FUNCTION(sdcard), + FUNCTION(i2c0), + FUNCTION(i2c1), + FUNCTION(i2c2), + FUNCTION(i2c3), + FUNCTION(uart_a), + FUNCTION(uart_b), + FUNCTION(uart_c), + FUNCTION(uart_ao_a_c), + FUNCTION(iso7816), + FUNCTION(eth), + FUNCTION(pwm_a), + FUNCTION(pwm_b), + FUNCTION(pwm_c), + FUNCTION(pwm_d), + FUNCTION(pwm_e), + FUNCTION(pwm_f), + FUNCTION(cec_ao_a_h), + FUNCTION(cec_ao_b_h), + FUNCTION(jtag_b), + FUNCTION(bt565_a), + FUNCTION(tsin_a), + FUNCTION(tsin_b), + FUNCTION(hdmitx), + FUNCTION(pdm), + FUNCTION(spdif_out), + FUNCTION(spdif_in), + FUNCTION(mclk0), + FUNCTION(mclk1), + FUNCTION(tdm_a), + FUNCTION(tdm_b), + FUNCTION(tdm_c), +}; + +static struct meson_pmx_func meson_g12a_aobus_functions[] = { + FUNCTION(gpio_aobus), + FUNCTION(uart_ao_a), + FUNCTION(uart_ao_b), + FUNCTION(i2c_ao), + FUNCTION(i2c_ao_slave), + FUNCTION(remote_ao_input), + FUNCTION(remote_ao_out), + FUNCTION(pwm_ao_a), + FUNCTION(pwm_ao_b), + FUNCTION(pwm_ao_c), + FUNCTION(pwm_ao_d), + FUNCTION(jtag_a), + FUNCTION(cec_ao_a), + FUNCTION(cec_ao_b), + FUNCTION(tsin_ao_a), + FUNCTION(spdif_ao_out), + FUNCTION(tdm_ao_b), + FUNCTION(mclk0_ao), +}; + +static struct meson_bank meson_g12a_periphs_banks[] = { + /* name first last irq pullen pull dir out in */ + BANK("Z", GPIOZ_0, GPIOZ_15, 12, 27, + 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), + BANK("H", GPIOH_0, GPIOH_8, 28, 36, + 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), + BANK("BOOT", BOOT_0, BOOT_15, 37, 52, + 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), + BANK("C", GPIOC_0, GPIOC_7, 53, 60, + 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), + BANK("A", GPIOA_0, GPIOA_15, 61, 76, + 5, 0, 5, 0, 16, 0, 17, 0, 18, 0), + BANK("X", GPIOX_0, GPIOX_19, 77, 96, + 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), +}; + +static struct meson_bank meson_g12a_aobus_banks[] = { + /* name first last irq pullen pull dir out in */ + BANK("AO", GPIOAO_0, GPIOAO_11, 0, 11, + 3, 0, 2, 0, 0, 0, 4, 0, 1, 0), + /* GPIOE actually located in the AO bank */ + BANK("E", GPIOE_0, GPIOE_2, 97, 99, + 3, 16, 2, 16, 0, 16, 4, 16, 1, 16), +}; + +static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = { + /* name first lask reg offset */ + BANK_PMX("Z", GPIOZ_0, GPIOZ_15, 0x6, 0), + BANK_PMX("H", GPIOH_0, GPIOH_8, 0xb, 0), + BANK_PMX("BOOT", BOOT_0, BOOT_15, 0x0, 0), + BANK_PMX("C", GPIOC_0, GPIOC_7, 0x9, 0), + BANK_PMX("A", GPIOA_0, GPIOA_15, 0xd, 0), + BANK_PMX("X", GPIOX_0, GPIOX_19, 0x3, 0), +}; + +static struct meson_axg_pmx_data meson_g12a_periphs_pmx_banks_data = { + .pmx_banks = meson_g12a_periphs_pmx_banks, + .num_pmx_banks = ARRAY_SIZE(meson_g12a_periphs_pmx_banks), +}; + +static struct meson_pmx_bank meson_g12a_aobus_pmx_banks[] = { + BANK_PMX("AO", GPIOAO_0, GPIOAO_11, 0x0, 0), + BANK_PMX("E", GPIOE_0, GPIOE_2, 0x1, 16), +}; + +static struct meson_axg_pmx_data meson_g12a_aobus_pmx_banks_data = { + .pmx_banks = meson_g12a_aobus_pmx_banks, + .num_pmx_banks = ARRAY_SIZE(meson_g12a_aobus_pmx_banks), +}; + +static struct meson_pinctrl_data meson_g12a_periphs_pinctrl_data = { + .name = "periphs-banks", + .pins = meson_g12a_periphs_pins, + .groups = meson_g12a_periphs_groups, + .funcs = meson_g12a_periphs_functions, + .banks = meson_g12a_periphs_banks, + .num_pins = ARRAY_SIZE(meson_g12a_periphs_pins), + .num_groups = ARRAY_SIZE(meson_g12a_periphs_groups), + .num_funcs = ARRAY_SIZE(meson_g12a_periphs_functions), + .num_banks = ARRAY_SIZE(meson_g12a_periphs_banks), + .pmx_ops = &meson_axg_pmx_ops, + .pmx_data = &meson_g12a_periphs_pmx_banks_data, +}; + +static struct meson_pinctrl_data meson_g12a_aobus_pinctrl_data = { + .name = "aobus-banks", + .pins = meson_g12a_aobus_pins, + .groups = meson_g12a_aobus_groups, + .funcs = meson_g12a_aobus_functions, + .banks = meson_g12a_aobus_banks, + .num_pins = ARRAY_SIZE(meson_g12a_aobus_pins), + .num_groups = ARRAY_SIZE(meson_g12a_aobus_groups), + .num_funcs = ARRAY_SIZE(meson_g12a_aobus_functions), + .num_banks = ARRAY_SIZE(meson_g12a_aobus_banks), + .pmx_ops = &meson_axg_pmx_ops, + .pmx_data = &meson_g12a_aobus_pmx_banks_data, +}; + +static const struct of_device_id meson_g12a_pinctrl_dt_match[] = { + { + .compatible = "amlogic,meson-g12a-periphs-pinctrl", + .data = &meson_g12a_periphs_pinctrl_data, + }, + { + .compatible = "amlogic,meson-g12a-aobus-pinctrl", + .data = &meson_g12a_aobus_pinctrl_data, + }, + { }, +}; + +static struct platform_driver meson_g12a_pinctrl_driver = { + .probe = meson_pinctrl_probe, + .driver = { + .name = "meson-g12a-pinctrl", + .of_match_table = meson_g12a_pinctrl_dt_match, + }, +}; + +builtin_platform_driver(meson_g12a_pinctrl_driver); diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 29a458da78db..f8b778a7d471 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -41,7 +41,7 @@ */ #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/io.h> #include <linux/of.h> @@ -451,7 +451,7 @@ static struct regmap *meson_map_resource(struct meson_pinctrl *pc, meson_regmap_config.max_register = resource_size(&res) - 4; meson_regmap_config.name = devm_kasprintf(pc->dev, GFP_KERNEL, - "%s-%s", node->name, + "%pOFn-%s", node, name); if (!meson_regmap_config.name) return ERR_PTR(-ENOMEM); diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h index 12a391109329..eff61ea1c67e 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.h +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -11,7 +11,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/pinctrl/pinctrl.h> #include <linux/platform_device.h> #include <linux/regmap.h> diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index d7ec7119701b..35ecb92483d5 100644 --- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -17,7 +17,7 @@ #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> @@ -413,14 +413,14 @@ static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, ret = of_property_read_string(np, "marvell,function", &function); if (ret) { dev_err(pctl->dev, - "missing marvell,function in node %s\n", np->name); + "missing marvell,function in node %pOFn\n", np); return 0; } nmaps = of_property_count_strings(np, "marvell,pins"); if (nmaps < 0) { dev_err(pctl->dev, - "missing marvell,pins in node %s\n", np->name); + "missing marvell,pins in node %pOFn\n", np); return 0; } diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8500.c b/drivers/pinctrl/nomadik/pinctrl-ab8500.c index 2ac2d0ad3025..0723627c7bc2 100644 --- a/drivers/pinctrl/nomadik/pinctrl-ab8500.c +++ b/drivers/pinctrl/nomadik/pinctrl-ab8500.c @@ -9,7 +9,7 @@ */ #include <linux/kernel.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/pinctrl/pinctrl.h> #include <linux/mfd/abx500/ab8500.h> #include "pinctrl-abx500.h" diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8505.c b/drivers/pinctrl/nomadik/pinctrl-ab8505.c index 42c6e1f7886b..2683509c1410 100644 --- a/drivers/pinctrl/nomadik/pinctrl-ab8505.c +++ b/drivers/pinctrl/nomadik/pinctrl-ab8505.c @@ -9,7 +9,7 @@ */ #include <linux/kernel.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/pinctrl/pinctrl.h> #include <linux/mfd/abx500/ab8500.h> #include "pinctrl-abx500.h" diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index e3689cc62a41..3d630a0544e1 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -18,7 +18,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index f0e7a8c114b2..4cc2c47f8778 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -17,7 +17,7 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -203,7 +203,7 @@ typedef unsigned long pin_cfg_t; #define GPIO_BLOCK_SHIFT 5 #define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) -#define NMK_MAX_BANKS DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP) +#define NMK_MAX_BANKS DIV_ROUND_UP(512, NMK_GPIO_PER_CHIP) /* Register in the logic block */ #define NMK_GPIO_DAT 0x00 @@ -971,7 +971,7 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, data_out ? "hi" : "lo", (mode < 0) ? "unknown" : modes[mode]); } else { - int irq = gpio_to_irq(gpio); + int irq = chip->to_irq(chip, offset); struct irq_desc *desc = irq_to_desc(irq); int pullidx = 0; int val; @@ -1051,7 +1051,7 @@ static struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np, gpio_pdev = of_find_device_by_node(np); if (!gpio_pdev) { - pr_err("populate \"%s\": device not found\n", np->name); + pr_err("populate \"%pOFn\": device not found\n", np); return ERR_PTR(-ENODEV); } if (of_property_read_u32(np, "gpio-bank", &id)) { @@ -1904,8 +1904,8 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) gpio_np = of_parse_phandle(np, "nomadik-gpio-chips", i); if (gpio_np) { dev_info(&pdev->dev, - "populate NMK GPIO %d \"%s\"\n", - i, gpio_np->name); + "populate NMK GPIO %d \"%pOFn\"\n", + i, gpio_np); nmk_chip = nmk_gpio_populate_chip(gpio_np, pdev); if (IS_ERR(nmk_chip)) dev_err(&pdev->dev, diff --git a/drivers/pinctrl/nuvoton/Kconfig b/drivers/pinctrl/nuvoton/Kconfig new file mode 100644 index 000000000000..6056841a3c32 --- /dev/null +++ b/drivers/pinctrl/nuvoton/Kconfig @@ -0,0 +1,12 @@ +config PINCTRL_NPCM7XX + bool "Pinctrl and GPIO driver for Nuvoton NPCM7XX" + depends on (ARCH_NPCM7XX || COMPILE_TEST) && OF + select PINMUX + select PINCONF + select GENERIC_PINCONF + select GPIOLIB + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say Y here to enable pin controller and GPIO support + for Nuvoton NPCM750/730/715/705 SoCs. diff --git a/drivers/pinctrl/nuvoton/Makefile b/drivers/pinctrl/nuvoton/Makefile new file mode 100644 index 000000000000..886d00784cef --- /dev/null +++ b/drivers/pinctrl/nuvoton/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +# Nuvoton pinctrl support + +obj-$(CONFIG_PINCTRL_NPCM7XX) += pinctrl-npcm7xx.o diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c new file mode 100644 index 000000000000..7ad50d9268aa --- /dev/null +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -0,0 +1,2072 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2016-2018 Nuvoton Technology corporation. +// Copyright (c) 2016, Dell Inc + +#include <linux/device.h> +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +/* GCR registers */ +#define NPCM7XX_GCR_PDID 0x00 +#define NPCM7XX_GCR_MFSEL1 0x0C +#define NPCM7XX_GCR_MFSEL2 0x10 +#define NPCM7XX_GCR_MFSEL3 0x64 +#define NPCM7XX_GCR_MFSEL4 0xb0 +#define NPCM7XX_GCR_CPCTL 0xD0 +#define NPCM7XX_GCR_CP2BST 0xD4 +#define NPCM7XX_GCR_B2CPNT 0xD8 +#define NPCM7XX_GCR_I2CSEGSEL 0xE0 +#define NPCM7XX_GCR_I2CSEGCTL 0xE4 +#define NPCM7XX_GCR_SRCNT 0x68 +#define NPCM7XX_GCR_FLOCKR1 0x74 +#define NPCM7XX_GCR_DSCNT 0x78 + +#define SRCNT_ESPI BIT(3) + +/* GPIO registers */ +#define NPCM7XX_GP_N_TLOCK1 0x00 +#define NPCM7XX_GP_N_DIN 0x04 /* Data IN */ +#define NPCM7XX_GP_N_POL 0x08 /* Polarity */ +#define NPCM7XX_GP_N_DOUT 0x0c /* Data OUT */ +#define NPCM7XX_GP_N_OE 0x10 /* Output Enable */ +#define NPCM7XX_GP_N_OTYP 0x14 +#define NPCM7XX_GP_N_MP 0x18 +#define NPCM7XX_GP_N_PU 0x1c /* Pull-up */ +#define NPCM7XX_GP_N_PD 0x20 /* Pull-down */ +#define NPCM7XX_GP_N_DBNC 0x24 /* Debounce */ +#define NPCM7XX_GP_N_EVTYP 0x28 /* Event Type */ +#define NPCM7XX_GP_N_EVBE 0x2c /* Event Both Edge */ +#define NPCM7XX_GP_N_OBL0 0x30 +#define NPCM7XX_GP_N_OBL1 0x34 +#define NPCM7XX_GP_N_OBL2 0x38 +#define NPCM7XX_GP_N_OBL3 0x3c +#define NPCM7XX_GP_N_EVEN 0x40 /* Event Enable */ +#define NPCM7XX_GP_N_EVENS 0x44 /* Event Set (enable) */ +#define NPCM7XX_GP_N_EVENC 0x48 /* Event Clear (disable) */ +#define NPCM7XX_GP_N_EVST 0x4c /* Event Status */ +#define NPCM7XX_GP_N_SPLCK 0x50 +#define NPCM7XX_GP_N_MPLCK 0x54 +#define NPCM7XX_GP_N_IEM 0x58 /* Input Enable */ +#define NPCM7XX_GP_N_OSRC 0x5c +#define NPCM7XX_GP_N_ODSC 0x60 +#define NPCM7XX_GP_N_DOS 0x68 /* Data OUT Set */ +#define NPCM7XX_GP_N_DOC 0x6c /* Data OUT Clear */ +#define NPCM7XX_GP_N_OES 0x70 /* Output Enable Set */ +#define NPCM7XX_GP_N_OEC 0x74 /* Output Enable Clear */ +#define NPCM7XX_GP_N_TLOCK2 0x7c + +#define NPCM7XX_GPIO_PER_BANK 32 +#define NPCM7XX_GPIO_BANK_NUM 8 +#define NPCM7XX_GCR_NONE 0 + +/* Structure for register banks */ +struct npcm7xx_gpio { + void __iomem *base; + struct gpio_chip gc; + int irqbase; + int irq; + void *priv; + struct irq_chip irq_chip; + u32 pinctrl_id; + int (*direction_input)(struct gpio_chip *chip, unsigned offset); + int (*direction_output)(struct gpio_chip *chip, unsigned offset, + int value); + int (*request)(struct gpio_chip *chip, unsigned offset); + void (*free)(struct gpio_chip *chip, unsigned offset); +}; + +struct npcm7xx_pinctrl { + struct pinctrl_dev *pctldev; + struct device *dev; + struct npcm7xx_gpio gpio_bank[NPCM7XX_GPIO_BANK_NUM]; + struct irq_domain *domain; + struct regmap *gcr_regmap; + void __iomem *regs; + u32 bank_num; +}; + +/* GPIO handling in the pinctrl driver */ +static void npcm_gpio_set(struct gpio_chip *gc, void __iomem *reg, + unsigned int pinmask) +{ + unsigned long flags; + unsigned long val; + + spin_lock_irqsave(&gc->bgpio_lock, flags); + + val = ioread32(reg) | pinmask; + iowrite32(val, reg); + + spin_unlock_irqrestore(&gc->bgpio_lock, flags); +} + +static void npcm_gpio_clr(struct gpio_chip *gc, void __iomem *reg, + unsigned int pinmask) +{ + unsigned long flags; + unsigned long val; + + spin_lock_irqsave(&gc->bgpio_lock, flags); + + val = ioread32(reg) & ~pinmask; + iowrite32(val, reg); + + spin_unlock_irqrestore(&gc->bgpio_lock, flags); +} + +static void npcmgpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct npcm7xx_gpio *bank = gpiochip_get_data(chip); + + seq_printf(s, "-- module %d [gpio%d - %d]\n", + bank->gc.base / bank->gc.ngpio, + bank->gc.base, + bank->gc.base + bank->gc.ngpio); + seq_printf(s, "DIN :%.8x DOUT:%.8x IE :%.8x OE :%.8x\n", + ioread32(bank->base + NPCM7XX_GP_N_DIN), + ioread32(bank->base + NPCM7XX_GP_N_DOUT), + ioread32(bank->base + NPCM7XX_GP_N_IEM), + ioread32(bank->base + NPCM7XX_GP_N_OE)); + seq_printf(s, "PU :%.8x PD :%.8x DB :%.8x POL :%.8x\n", + ioread32(bank->base + NPCM7XX_GP_N_PU), + ioread32(bank->base + NPCM7XX_GP_N_PD), + ioread32(bank->base + NPCM7XX_GP_N_DBNC), + ioread32(bank->base + NPCM7XX_GP_N_POL)); + seq_printf(s, "ETYP:%.8x EVBE:%.8x EVEN:%.8x EVST:%.8x\n", + ioread32(bank->base + NPCM7XX_GP_N_EVTYP), + ioread32(bank->base + NPCM7XX_GP_N_EVBE), + ioread32(bank->base + NPCM7XX_GP_N_EVEN), + ioread32(bank->base + NPCM7XX_GP_N_EVST)); + seq_printf(s, "OTYP:%.8x OSRC:%.8x ODSC:%.8x\n", + ioread32(bank->base + NPCM7XX_GP_N_OTYP), + ioread32(bank->base + NPCM7XX_GP_N_OSRC), + ioread32(bank->base + NPCM7XX_GP_N_ODSC)); + seq_printf(s, "OBL0:%.8x OBL1:%.8x OBL2:%.8x OBL3:%.8x\n", + ioread32(bank->base + NPCM7XX_GP_N_OBL0), + ioread32(bank->base + NPCM7XX_GP_N_OBL1), + ioread32(bank->base + NPCM7XX_GP_N_OBL2), + ioread32(bank->base + NPCM7XX_GP_N_OBL3)); + seq_printf(s, "SLCK:%.8x MLCK:%.8x\n", + ioread32(bank->base + NPCM7XX_GP_N_SPLCK), + ioread32(bank->base + NPCM7XX_GP_N_MPLCK)); +} + +static int npcmgpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + struct npcm7xx_gpio *bank = gpiochip_get_data(chip); + int ret; + + ret = pinctrl_gpio_direction_input(offset + chip->base); + if (ret) + return ret; + + return bank->direction_input(chip, offset); +} + +/* Set GPIO to Output with initial value */ +static int npcmgpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct npcm7xx_gpio *bank = gpiochip_get_data(chip); + int ret; + + dev_dbg(chip->parent, "gpio_direction_output: offset%d = %x\n", offset, + value); + + ret = pinctrl_gpio_direction_output(offset + chip->base); + if (ret) + return ret; + + return bank->direction_output(chip, offset, value); +} + +static int npcmgpio_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + struct npcm7xx_gpio *bank = gpiochip_get_data(chip); + int ret; + + dev_dbg(chip->parent, "gpio_request: offset%d\n", offset); + ret = pinctrl_gpio_request(offset + chip->base); + if (ret) + return ret; + + return bank->request(chip, offset); +} + +static void npcmgpio_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + dev_dbg(chip->parent, "gpio_free: offset%d\n", offset); + pinctrl_gpio_free(offset + chip->base); +} + +static void npcmgpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc; + struct irq_chip *chip; + struct npcm7xx_gpio *bank; + u32 sts, en, bit; + + gc = irq_desc_get_handler_data(desc); + bank = gpiochip_get_data(gc); + chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + sts = ioread32(bank->base + NPCM7XX_GP_N_EVST); + en = ioread32(bank->base + NPCM7XX_GP_N_EVEN); + dev_dbg(chip->parent_device, "==> got irq sts %.8x %.8x\n", sts, + en); + + sts &= en; + for_each_set_bit(bit, (const void *)&sts, NPCM7XX_GPIO_PER_BANK) + generic_handle_irq(irq_linear_revmap(gc->irq.domain, bit)); + chained_irq_exit(chip, desc); +} + +static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type) +{ + struct npcm7xx_gpio *bank = + gpiochip_get_data(irq_data_get_irq_chip_data(d)); + unsigned int gpio = BIT(d->hwirq); + + dev_dbg(d->chip->parent_device, "setirqtype: %u.%u = %u\n", gpio, + d->irq, type); + switch (type) { + case IRQ_TYPE_EDGE_RISING: + dev_dbg(d->chip->parent_device, "edge.rising\n"); + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + break; + case IRQ_TYPE_EDGE_FALLING: + dev_dbg(d->chip->parent_device, "edge.falling\n"); + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + break; + case IRQ_TYPE_EDGE_BOTH: + dev_dbg(d->chip->parent_device, "edge.both\n"); + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); + break; + case IRQ_TYPE_LEVEL_LOW: + dev_dbg(d->chip->parent_device, "level.low\n"); + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + break; + case IRQ_TYPE_LEVEL_HIGH: + dev_dbg(d->chip->parent_device, "level.high\n"); + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); + break; + default: + dev_dbg(d->chip->parent_device, "invalid irq type\n"); + return -EINVAL; + } + + if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVTYP, gpio); + irq_set_handler_locked(d, handle_level_irq); + } else if (type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_EDGE_RISING + | IRQ_TYPE_EDGE_FALLING)) { + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVTYP, gpio); + irq_set_handler_locked(d, handle_edge_irq); + } + + return 0; +} + +static void npcmgpio_irq_ack(struct irq_data *d) +{ + struct npcm7xx_gpio *bank = + gpiochip_get_data(irq_data_get_irq_chip_data(d)); + unsigned int gpio = d->hwirq; + + dev_dbg(d->chip->parent_device, "irq_ack: %u.%u\n", gpio, d->irq); + iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVST); +} + +/* Disable GPIO interrupt */ +static void npcmgpio_irq_mask(struct irq_data *d) +{ + struct npcm7xx_gpio *bank = + gpiochip_get_data(irq_data_get_irq_chip_data(d)); + unsigned int gpio = d->hwirq; + + /* Clear events */ + dev_dbg(d->chip->parent_device, "irq_mask: %u.%u\n", gpio, d->irq); + iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENC); +} + +/* Enable GPIO interrupt */ +static void npcmgpio_irq_unmask(struct irq_data *d) +{ + struct npcm7xx_gpio *bank = + gpiochip_get_data(irq_data_get_irq_chip_data(d)); + unsigned int gpio = d->hwirq; + + /* Enable events */ + dev_dbg(d->chip->parent_device, "irq_unmask: %u.%u\n", gpio, d->irq); + iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENS); +} + +static unsigned int npcmgpio_irq_startup(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + unsigned int gpio = d->hwirq; + + /* active-high, input, clear interrupt, enable interrupt */ + dev_dbg(d->chip->parent_device, "startup: %u.%u\n", gpio, d->irq); + npcmgpio_direction_input(gc, gpio); + npcmgpio_irq_ack(d); + npcmgpio_irq_unmask(d); + + return 0; +} + +static struct irq_chip npcmgpio_irqchip = { + .name = "NPCM7XX-GPIO-IRQ", + .irq_ack = npcmgpio_irq_ack, + .irq_unmask = npcmgpio_irq_unmask, + .irq_mask = npcmgpio_irq_mask, + .irq_set_type = npcmgpio_set_irq_type, + .irq_startup = npcmgpio_irq_startup, +}; + +/* pinmux handing in the pinctrl driver*/ +static const int smb0_pins[] = { 115, 114 }; +static const int smb0b_pins[] = { 195, 194 }; +static const int smb0c_pins[] = { 202, 196 }; +static const int smb0d_pins[] = { 198, 199 }; +static const int smb0den_pins[] = { 197 }; + +static const int smb1_pins[] = { 117, 116 }; +static const int smb1b_pins[] = { 126, 127 }; +static const int smb1c_pins[] = { 124, 125 }; +static const int smb1d_pins[] = { 4, 5 }; + +static const int smb2_pins[] = { 119, 118 }; +static const int smb2b_pins[] = { 122, 123 }; +static const int smb2c_pins[] = { 120, 121 }; +static const int smb2d_pins[] = { 6, 7 }; + +static const int smb3_pins[] = { 30, 31 }; +static const int smb3b_pins[] = { 39, 40 }; +static const int smb3c_pins[] = { 37, 38 }; +static const int smb3d_pins[] = { 59, 60 }; + +static const int smb4_pins[] = { 28, 29 }; +static const int smb4b_pins[] = { 18, 19 }; +static const int smb4c_pins[] = { 20, 21 }; +static const int smb4d_pins[] = { 22, 23 }; +static const int smb4den_pins[] = { 17 }; + +static const int smb5_pins[] = { 26, 27 }; +static const int smb5b_pins[] = { 13, 12 }; +static const int smb5c_pins[] = { 15, 14 }; +static const int smb5d_pins[] = { 94, 93 }; +static const int ga20kbc_pins[] = { 94, 93 }; + +static const int smb6_pins[] = { 172, 171 }; +static const int smb7_pins[] = { 174, 173 }; +static const int smb8_pins[] = { 129, 128 }; +static const int smb9_pins[] = { 131, 130 }; +static const int smb10_pins[] = { 133, 132 }; +static const int smb11_pins[] = { 135, 134 }; +static const int smb12_pins[] = { 221, 220 }; +static const int smb13_pins[] = { 223, 222 }; +static const int smb14_pins[] = { 22, 23 }; +static const int smb15_pins[] = { 20, 21 }; + +static const int fanin0_pins[] = { 64 }; +static const int fanin1_pins[] = { 65 }; +static const int fanin2_pins[] = { 66 }; +static const int fanin3_pins[] = { 67 }; +static const int fanin4_pins[] = { 68 }; +static const int fanin5_pins[] = { 69 }; +static const int fanin6_pins[] = { 70 }; +static const int fanin7_pins[] = { 71 }; +static const int fanin8_pins[] = { 72 }; +static const int fanin9_pins[] = { 73 }; +static const int fanin10_pins[] = { 74 }; +static const int fanin11_pins[] = { 75 }; +static const int fanin12_pins[] = { 76 }; +static const int fanin13_pins[] = { 77 }; +static const int fanin14_pins[] = { 78 }; +static const int fanin15_pins[] = { 79 }; +static const int faninx_pins[] = { 175, 176, 177, 203 }; + +static const int pwm0_pins[] = { 80 }; +static const int pwm1_pins[] = { 81 }; +static const int pwm2_pins[] = { 82 }; +static const int pwm3_pins[] = { 83 }; +static const int pwm4_pins[] = { 144 }; +static const int pwm5_pins[] = { 145 }; +static const int pwm6_pins[] = { 146 }; +static const int pwm7_pins[] = { 147 }; + +static const int uart1_pins[] = { 43, 44, 45, 46, 47, 61, 62, 63 }; +static const int uart2_pins[] = { 48, 49, 50, 51, 52, 53, 54, 55 }; + +/* RGMII 1 pin group */ +static const int rg1_pins[] = { 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107 }; +/* RGMII 1 MD interface pin group */ +static const int rg1mdio_pins[] = { 108, 109 }; + +/* RGMII 2 pin group */ +static const int rg2_pins[] = { 110, 111, 112, 113, 208, 209, 210, 211, 212, + 213, 214, 215 }; +/* RGMII 2 MD interface pin group */ +static const int rg2mdio_pins[] = { 216, 217 }; + +static const int ddr_pins[] = { 110, 111, 112, 113, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217 }; +/* Serial I/O Expander 1 */ +static const int iox1_pins[] = { 0, 1, 2, 3 }; +/* Serial I/O Expander 2 */ +static const int iox2_pins[] = { 4, 5, 6, 7 }; +/* Host Serial I/O Expander 2 */ +static const int ioxh_pins[] = { 10, 11, 24, 25 }; + +static const int mmc_pins[] = { 152, 154, 156, 157, 158, 159 }; +static const int mmcwp_pins[] = { 153 }; +static const int mmccd_pins[] = { 155 }; +static const int mmcrst_pins[] = { 155 }; +static const int mmc8_pins[] = { 148, 149, 150, 151 }; + +/* RMII 1 pin groups */ +static const int r1_pins[] = { 178, 179, 180, 181, 182, 193, 201 }; +static const int r1err_pins[] = { 56 }; +static const int r1md_pins[] = { 57, 58 }; + +/* RMII 2 pin groups */ +static const int r2_pins[] = { 84, 85, 86, 87, 88, 89, 200 }; +static const int r2err_pins[] = { 90 }; +static const int r2md_pins[] = { 91, 92 }; + +static const int sd1_pins[] = { 136, 137, 138, 139, 140, 141, 142, 143 }; +static const int sd1pwr_pins[] = { 143 }; + +static const int wdog1_pins[] = { 218 }; +static const int wdog2_pins[] = { 219 }; + +/* BMC serial port 0 */ +static const int bmcuart0a_pins[] = { 41, 42 }; +static const int bmcuart0b_pins[] = { 48, 49 }; + +static const int bmcuart1_pins[] = { 43, 44, 62, 63 }; + +/* System Control Interrupt and Power Management Event pin group */ +static const int scipme_pins[] = { 169 }; +/* System Management Interrupt pin group */ +static const int sci_pins[] = { 170 }; +/* Serial Interrupt Line pin group */ +static const int serirq_pins[] = { 162 }; + +static const int clkout_pins[] = { 160 }; +static const int clkreq_pins[] = { 231 }; + +static const int jtag2_pins[] = { 43, 44, 45, 46, 47 }; +/* Graphics SPI Clock pin group */ +static const int gspi_pins[] = { 12, 13, 14, 15 }; + +static const int spix_pins[] = { 224, 225, 226, 227, 229, 230 }; +static const int spixcs1_pins[] = { 228 }; + +static const int pspi1_pins[] = { 175, 176, 177 }; +static const int pspi2_pins[] = { 17, 18, 19 }; + +static const int spi0cs1_pins[] = { 32 }; + +static const int spi3_pins[] = { 183, 184, 185, 186 }; +static const int spi3cs1_pins[] = { 187 }; +static const int spi3quad_pins[] = { 188, 189 }; +static const int spi3cs2_pins[] = { 188 }; +static const int spi3cs3_pins[] = { 189 }; + +static const int ddc_pins[] = { 204, 205, 206, 207 }; + +static const int lpc_pins[] = { 95, 161, 163, 164, 165, 166, 167 }; +static const int lpcclk_pins[] = { 168 }; +static const int espi_pins[] = { 95, 161, 163, 164, 165, 166, 167, 168 }; + +static const int lkgpo0_pins[] = { 16 }; +static const int lkgpo1_pins[] = { 8 }; +static const int lkgpo2_pins[] = { 9 }; + +static const int nprd_smi_pins[] = { 190 }; + +/* + * pin: name, number + * group: name, npins, pins + * function: name, ngroups, groups + */ +struct npcm7xx_group { + const char *name; + const unsigned int *pins; + int npins; +}; + +#define NPCM7XX_GRPS \ + NPCM7XX_GRP(smb0), \ + NPCM7XX_GRP(smb0b), \ + NPCM7XX_GRP(smb0c), \ + NPCM7XX_GRP(smb0d), \ + NPCM7XX_GRP(smb0den), \ + NPCM7XX_GRP(smb1), \ + NPCM7XX_GRP(smb1b), \ + NPCM7XX_GRP(smb1c), \ + NPCM7XX_GRP(smb1d), \ + NPCM7XX_GRP(smb2), \ + NPCM7XX_GRP(smb2b), \ + NPCM7XX_GRP(smb2c), \ + NPCM7XX_GRP(smb2d), \ + NPCM7XX_GRP(smb3), \ + NPCM7XX_GRP(smb3b), \ + NPCM7XX_GRP(smb3c), \ + NPCM7XX_GRP(smb3d), \ + NPCM7XX_GRP(smb4), \ + NPCM7XX_GRP(smb4b), \ + NPCM7XX_GRP(smb4c), \ + NPCM7XX_GRP(smb4d), \ + NPCM7XX_GRP(smb4den), \ + NPCM7XX_GRP(smb5), \ + NPCM7XX_GRP(smb5b), \ + NPCM7XX_GRP(smb5c), \ + NPCM7XX_GRP(smb5d), \ + NPCM7XX_GRP(ga20kbc), \ + NPCM7XX_GRP(smb6), \ + NPCM7XX_GRP(smb7), \ + NPCM7XX_GRP(smb8), \ + NPCM7XX_GRP(smb9), \ + NPCM7XX_GRP(smb10), \ + NPCM7XX_GRP(smb11), \ + NPCM7XX_GRP(smb12), \ + NPCM7XX_GRP(smb13), \ + NPCM7XX_GRP(smb14), \ + NPCM7XX_GRP(smb15), \ + NPCM7XX_GRP(fanin0), \ + NPCM7XX_GRP(fanin1), \ + NPCM7XX_GRP(fanin2), \ + NPCM7XX_GRP(fanin3), \ + NPCM7XX_GRP(fanin4), \ + NPCM7XX_GRP(fanin5), \ + NPCM7XX_GRP(fanin6), \ + NPCM7XX_GRP(fanin7), \ + NPCM7XX_GRP(fanin8), \ + NPCM7XX_GRP(fanin9), \ + NPCM7XX_GRP(fanin10), \ + NPCM7XX_GRP(fanin11), \ + NPCM7XX_GRP(fanin12), \ + NPCM7XX_GRP(fanin13), \ + NPCM7XX_GRP(fanin14), \ + NPCM7XX_GRP(fanin15), \ + NPCM7XX_GRP(faninx), \ + NPCM7XX_GRP(pwm0), \ + NPCM7XX_GRP(pwm1), \ + NPCM7XX_GRP(pwm2), \ + NPCM7XX_GRP(pwm3), \ + NPCM7XX_GRP(pwm4), \ + NPCM7XX_GRP(pwm5), \ + NPCM7XX_GRP(pwm6), \ + NPCM7XX_GRP(pwm7), \ + NPCM7XX_GRP(rg1), \ + NPCM7XX_GRP(rg1mdio), \ + NPCM7XX_GRP(rg2), \ + NPCM7XX_GRP(rg2mdio), \ + NPCM7XX_GRP(ddr), \ + NPCM7XX_GRP(uart1), \ + NPCM7XX_GRP(uart2), \ + NPCM7XX_GRP(bmcuart0a), \ + NPCM7XX_GRP(bmcuart0b), \ + NPCM7XX_GRP(bmcuart1), \ + NPCM7XX_GRP(iox1), \ + NPCM7XX_GRP(iox2), \ + NPCM7XX_GRP(ioxh), \ + NPCM7XX_GRP(gspi), \ + NPCM7XX_GRP(mmc), \ + NPCM7XX_GRP(mmcwp), \ + NPCM7XX_GRP(mmccd), \ + NPCM7XX_GRP(mmcrst), \ + NPCM7XX_GRP(mmc8), \ + NPCM7XX_GRP(r1), \ + NPCM7XX_GRP(r1err), \ + NPCM7XX_GRP(r1md), \ + NPCM7XX_GRP(r2), \ + NPCM7XX_GRP(r2err), \ + NPCM7XX_GRP(r2md), \ + NPCM7XX_GRP(sd1), \ + NPCM7XX_GRP(sd1pwr), \ + NPCM7XX_GRP(wdog1), \ + NPCM7XX_GRP(wdog2), \ + NPCM7XX_GRP(scipme), \ + NPCM7XX_GRP(sci), \ + NPCM7XX_GRP(serirq), \ + NPCM7XX_GRP(jtag2), \ + NPCM7XX_GRP(spix), \ + NPCM7XX_GRP(spixcs1), \ + NPCM7XX_GRP(pspi1), \ + NPCM7XX_GRP(pspi2), \ + NPCM7XX_GRP(ddc), \ + NPCM7XX_GRP(clkreq), \ + NPCM7XX_GRP(clkout), \ + NPCM7XX_GRP(spi3), \ + NPCM7XX_GRP(spi3cs1), \ + NPCM7XX_GRP(spi3quad), \ + NPCM7XX_GRP(spi3cs2), \ + NPCM7XX_GRP(spi3cs3), \ + NPCM7XX_GRP(spi0cs1), \ + NPCM7XX_GRP(lpc), \ + NPCM7XX_GRP(lpcclk), \ + NPCM7XX_GRP(espi), \ + NPCM7XX_GRP(lkgpo0), \ + NPCM7XX_GRP(lkgpo1), \ + NPCM7XX_GRP(lkgpo2), \ + NPCM7XX_GRP(nprd_smi), \ + \ + +enum { +#define NPCM7XX_GRP(x) fn_ ## x + NPCM7XX_GRPS + /* add placeholder for none/gpio */ + NPCM7XX_GRP(none), + NPCM7XX_GRP(gpio), +#undef NPCM7XX_GRP +}; + +static struct npcm7xx_group npcm7xx_groups[] = { +#define NPCM7XX_GRP(x) { .name = #x, .pins = x ## _pins, \ + .npins = ARRAY_SIZE(x ## _pins) } + NPCM7XX_GRPS +#undef NPCM7XX_GRP +}; + +#define NPCM7XX_SFUNC(a) NPCM7XX_FUNC(a, #a) +#define NPCM7XX_FUNC(a, b...) static const char *a ## _grp[] = { b } +#define NPCM7XX_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ + .groups = nm ## _grp } +struct npcm7xx_func { + const char *name; + const unsigned int ngroups; + const char *const *groups; +}; + +NPCM7XX_SFUNC(smb0); +NPCM7XX_SFUNC(smb0b); +NPCM7XX_SFUNC(smb0c); +NPCM7XX_SFUNC(smb0d); +NPCM7XX_SFUNC(smb0den); +NPCM7XX_SFUNC(smb1); +NPCM7XX_SFUNC(smb1b); +NPCM7XX_SFUNC(smb1c); +NPCM7XX_SFUNC(smb1d); +NPCM7XX_SFUNC(smb2); +NPCM7XX_SFUNC(smb2b); +NPCM7XX_SFUNC(smb2c); +NPCM7XX_SFUNC(smb2d); +NPCM7XX_SFUNC(smb3); +NPCM7XX_SFUNC(smb3b); +NPCM7XX_SFUNC(smb3c); +NPCM7XX_SFUNC(smb3d); +NPCM7XX_SFUNC(smb4); +NPCM7XX_SFUNC(smb4b); +NPCM7XX_SFUNC(smb4c); +NPCM7XX_SFUNC(smb4d); +NPCM7XX_SFUNC(smb4den); +NPCM7XX_SFUNC(smb5); +NPCM7XX_SFUNC(smb5b); +NPCM7XX_SFUNC(smb5c); +NPCM7XX_SFUNC(smb5d); +NPCM7XX_SFUNC(ga20kbc); +NPCM7XX_SFUNC(smb6); +NPCM7XX_SFUNC(smb7); +NPCM7XX_SFUNC(smb8); +NPCM7XX_SFUNC(smb9); +NPCM7XX_SFUNC(smb10); +NPCM7XX_SFUNC(smb11); +NPCM7XX_SFUNC(smb12); +NPCM7XX_SFUNC(smb13); +NPCM7XX_SFUNC(smb14); +NPCM7XX_SFUNC(smb15); +NPCM7XX_SFUNC(fanin0); +NPCM7XX_SFUNC(fanin1); +NPCM7XX_SFUNC(fanin2); +NPCM7XX_SFUNC(fanin3); +NPCM7XX_SFUNC(fanin4); +NPCM7XX_SFUNC(fanin5); +NPCM7XX_SFUNC(fanin6); +NPCM7XX_SFUNC(fanin7); +NPCM7XX_SFUNC(fanin8); +NPCM7XX_SFUNC(fanin9); +NPCM7XX_SFUNC(fanin10); +NPCM7XX_SFUNC(fanin11); +NPCM7XX_SFUNC(fanin12); +NPCM7XX_SFUNC(fanin13); +NPCM7XX_SFUNC(fanin14); +NPCM7XX_SFUNC(fanin15); +NPCM7XX_SFUNC(faninx); +NPCM7XX_SFUNC(pwm0); +NPCM7XX_SFUNC(pwm1); +NPCM7XX_SFUNC(pwm2); +NPCM7XX_SFUNC(pwm3); +NPCM7XX_SFUNC(pwm4); +NPCM7XX_SFUNC(pwm5); +NPCM7XX_SFUNC(pwm6); +NPCM7XX_SFUNC(pwm7); +NPCM7XX_SFUNC(rg1); +NPCM7XX_SFUNC(rg1mdio); +NPCM7XX_SFUNC(rg2); +NPCM7XX_SFUNC(rg2mdio); +NPCM7XX_SFUNC(ddr); +NPCM7XX_SFUNC(uart1); +NPCM7XX_SFUNC(uart2); +NPCM7XX_SFUNC(bmcuart0a); +NPCM7XX_SFUNC(bmcuart0b); +NPCM7XX_SFUNC(bmcuart1); +NPCM7XX_SFUNC(iox1); +NPCM7XX_SFUNC(iox2); +NPCM7XX_SFUNC(ioxh); +NPCM7XX_SFUNC(gspi); +NPCM7XX_SFUNC(mmc); +NPCM7XX_SFUNC(mmcwp); +NPCM7XX_SFUNC(mmccd); +NPCM7XX_SFUNC(mmcrst); +NPCM7XX_SFUNC(mmc8); +NPCM7XX_SFUNC(r1); +NPCM7XX_SFUNC(r1err); +NPCM7XX_SFUNC(r1md); +NPCM7XX_SFUNC(r2); +NPCM7XX_SFUNC(r2err); +NPCM7XX_SFUNC(r2md); +NPCM7XX_SFUNC(sd1); +NPCM7XX_SFUNC(sd1pwr); +NPCM7XX_SFUNC(wdog1); +NPCM7XX_SFUNC(wdog2); +NPCM7XX_SFUNC(scipme); +NPCM7XX_SFUNC(sci); +NPCM7XX_SFUNC(serirq); +NPCM7XX_SFUNC(jtag2); +NPCM7XX_SFUNC(spix); +NPCM7XX_SFUNC(spixcs1); +NPCM7XX_SFUNC(pspi1); +NPCM7XX_SFUNC(pspi2); +NPCM7XX_SFUNC(ddc); +NPCM7XX_SFUNC(clkreq); +NPCM7XX_SFUNC(clkout); +NPCM7XX_SFUNC(spi3); +NPCM7XX_SFUNC(spi3cs1); +NPCM7XX_SFUNC(spi3quad); +NPCM7XX_SFUNC(spi3cs2); +NPCM7XX_SFUNC(spi3cs3); +NPCM7XX_SFUNC(spi0cs1); +NPCM7XX_SFUNC(lpc); +NPCM7XX_SFUNC(lpcclk); +NPCM7XX_SFUNC(espi); +NPCM7XX_SFUNC(lkgpo0); +NPCM7XX_SFUNC(lkgpo1); +NPCM7XX_SFUNC(lkgpo2); +NPCM7XX_SFUNC(nprd_smi); + +/* Function names */ +static struct npcm7xx_func npcm7xx_funcs[] = { + NPCM7XX_MKFUNC(smb0), + NPCM7XX_MKFUNC(smb0b), + NPCM7XX_MKFUNC(smb0c), + NPCM7XX_MKFUNC(smb0d), + NPCM7XX_MKFUNC(smb0den), + NPCM7XX_MKFUNC(smb1), + NPCM7XX_MKFUNC(smb1b), + NPCM7XX_MKFUNC(smb1c), + NPCM7XX_MKFUNC(smb1d), + NPCM7XX_MKFUNC(smb2), + NPCM7XX_MKFUNC(smb2b), + NPCM7XX_MKFUNC(smb2c), + NPCM7XX_MKFUNC(smb2d), + NPCM7XX_MKFUNC(smb3), + NPCM7XX_MKFUNC(smb3b), + NPCM7XX_MKFUNC(smb3c), + NPCM7XX_MKFUNC(smb3d), + NPCM7XX_MKFUNC(smb4), + NPCM7XX_MKFUNC(smb4b), + NPCM7XX_MKFUNC(smb4c), + NPCM7XX_MKFUNC(smb4d), + NPCM7XX_MKFUNC(smb4den), + NPCM7XX_MKFUNC(smb5), + NPCM7XX_MKFUNC(smb5b), + NPCM7XX_MKFUNC(smb5c), + NPCM7XX_MKFUNC(smb5d), + NPCM7XX_MKFUNC(ga20kbc), + NPCM7XX_MKFUNC(smb6), + NPCM7XX_MKFUNC(smb7), + NPCM7XX_MKFUNC(smb8), + NPCM7XX_MKFUNC(smb9), + NPCM7XX_MKFUNC(smb10), + NPCM7XX_MKFUNC(smb11), + NPCM7XX_MKFUNC(smb12), + NPCM7XX_MKFUNC(smb13), + NPCM7XX_MKFUNC(smb14), + NPCM7XX_MKFUNC(smb15), + NPCM7XX_MKFUNC(fanin0), + NPCM7XX_MKFUNC(fanin1), + NPCM7XX_MKFUNC(fanin2), + NPCM7XX_MKFUNC(fanin3), + NPCM7XX_MKFUNC(fanin4), + NPCM7XX_MKFUNC(fanin5), + NPCM7XX_MKFUNC(fanin6), + NPCM7XX_MKFUNC(fanin7), + NPCM7XX_MKFUNC(fanin8), + NPCM7XX_MKFUNC(fanin9), + NPCM7XX_MKFUNC(fanin10), + NPCM7XX_MKFUNC(fanin11), + NPCM7XX_MKFUNC(fanin12), + NPCM7XX_MKFUNC(fanin13), + NPCM7XX_MKFUNC(fanin14), + NPCM7XX_MKFUNC(fanin15), + NPCM7XX_MKFUNC(faninx), + NPCM7XX_MKFUNC(pwm0), + NPCM7XX_MKFUNC(pwm1), + NPCM7XX_MKFUNC(pwm2), + NPCM7XX_MKFUNC(pwm3), + NPCM7XX_MKFUNC(pwm4), + NPCM7XX_MKFUNC(pwm5), + NPCM7XX_MKFUNC(pwm6), + NPCM7XX_MKFUNC(pwm7), + NPCM7XX_MKFUNC(rg1), + NPCM7XX_MKFUNC(rg1mdio), + NPCM7XX_MKFUNC(rg2), + NPCM7XX_MKFUNC(rg2mdio), + NPCM7XX_MKFUNC(ddr), + NPCM7XX_MKFUNC(uart1), + NPCM7XX_MKFUNC(uart2), + NPCM7XX_MKFUNC(bmcuart0a), + NPCM7XX_MKFUNC(bmcuart0b), + NPCM7XX_MKFUNC(bmcuart1), + NPCM7XX_MKFUNC(iox1), + NPCM7XX_MKFUNC(iox2), + NPCM7XX_MKFUNC(ioxh), + NPCM7XX_MKFUNC(gspi), + NPCM7XX_MKFUNC(mmc), + NPCM7XX_MKFUNC(mmcwp), + NPCM7XX_MKFUNC(mmccd), + NPCM7XX_MKFUNC(mmcrst), + NPCM7XX_MKFUNC(mmc8), + NPCM7XX_MKFUNC(r1), + NPCM7XX_MKFUNC(r1err), + NPCM7XX_MKFUNC(r1md), + NPCM7XX_MKFUNC(r2), + NPCM7XX_MKFUNC(r2err), + NPCM7XX_MKFUNC(r2md), + NPCM7XX_MKFUNC(sd1), + NPCM7XX_MKFUNC(sd1pwr), + NPCM7XX_MKFUNC(wdog1), + NPCM7XX_MKFUNC(wdog2), + NPCM7XX_MKFUNC(scipme), + NPCM7XX_MKFUNC(sci), + NPCM7XX_MKFUNC(serirq), + NPCM7XX_MKFUNC(jtag2), + NPCM7XX_MKFUNC(spix), + NPCM7XX_MKFUNC(spixcs1), + NPCM7XX_MKFUNC(pspi1), + NPCM7XX_MKFUNC(pspi2), + NPCM7XX_MKFUNC(ddc), + NPCM7XX_MKFUNC(clkreq), + NPCM7XX_MKFUNC(clkout), + NPCM7XX_MKFUNC(spi3), + NPCM7XX_MKFUNC(spi3cs1), + NPCM7XX_MKFUNC(spi3quad), + NPCM7XX_MKFUNC(spi3cs2), + NPCM7XX_MKFUNC(spi3cs3), + NPCM7XX_MKFUNC(spi0cs1), + NPCM7XX_MKFUNC(lpc), + NPCM7XX_MKFUNC(lpcclk), + NPCM7XX_MKFUNC(espi), + NPCM7XX_MKFUNC(lkgpo0), + NPCM7XX_MKFUNC(lkgpo1), + NPCM7XX_MKFUNC(lkgpo2), + NPCM7XX_MKFUNC(nprd_smi), +}; + +#define NPCM7XX_PINCFG(a, b, c, d, e, f, g, h, i, j, k) \ + [a] { .fn0 = fn_ ## b, .reg0 = NPCM7XX_GCR_ ## c, .bit0 = d, \ + .fn1 = fn_ ## e, .reg1 = NPCM7XX_GCR_ ## f, .bit1 = g, \ + .fn2 = fn_ ## h, .reg2 = NPCM7XX_GCR_ ## i, .bit2 = j, \ + .flag = k } + +/* Drive strength controlled by NPCM7XX_GP_N_ODSC */ +#define DRIVE_STRENGTH_LO_SHIFT 8 +#define DRIVE_STRENGTH_HI_SHIFT 12 +#define DRIVE_STRENGTH_MASK 0x0000FF00 + +#define DS(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \ + ((hi) << DRIVE_STRENGTH_HI_SHIFT)) +#define DSLO(x) (((x) >> DRIVE_STRENGTH_LO_SHIFT) & 0xF) +#define DSHI(x) (((x) >> DRIVE_STRENGTH_HI_SHIFT) & 0xF) + +#define GPI 0x1 /* Not GPO */ +#define GPO 0x2 /* Not GPI */ +#define SLEW 0x4 /* Has Slew Control, NPCM7XX_GP_N_OSRC */ +#define SLEWLPC 0x8 /* Has Slew Control, SRCNT.3 */ + +struct npcm7xx_pincfg { + int flag; + int fn0, reg0, bit0; + int fn1, reg1, bit1; + int fn2, reg2, bit2; +}; + +static const struct npcm7xx_pincfg pincfg[] = { + /* PIN FUNCTION 1 FUNCTION 2 FUNCTION 3 FLAGS */ + NPCM7XX_PINCFG(0, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(3, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(4, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(5, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(6, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(7, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(12, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(13, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(14, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(15, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(20, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0), + NPCM7XX_PINCFG(21, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0), + NPCM7XX_PINCFG(22, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0), + NPCM7XX_PINCFG(23, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0), + NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(26, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(27, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(28, smb4, MFSEL1, 1, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(29, smb4, MFSEL1, 1, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(30, smb3, MFSEL1, 0, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(31, smb3, MFSEL1, 0, none, NONE, 0, none, NONE, 0, 0), + + NPCM7XX_PINCFG(32, spi0cs1, MFSEL1, 3, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(33, none, NONE, 0, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(34, none, NONE, 0, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(37, smb3c, I2CSEGSEL, 12, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(38, smb3c, I2CSEGSEL, 12, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(39, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(40, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(41, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, DS(2, 4) | GPO), + NPCM7XX_PINCFG(43, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0), + NPCM7XX_PINCFG(44, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0), + NPCM7XX_PINCFG(45, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)), + NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)), + NPCM7XX_PINCFG(48, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, GPO), + NPCM7XX_PINCFG(49, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, 0), + NPCM7XX_PINCFG(50, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(51, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, GPO), + NPCM7XX_PINCFG(52, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(53, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, GPO), + NPCM7XX_PINCFG(54, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(55, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(56, r1err, MFSEL1, 12, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(59, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(60, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(61, uart1, MFSEL1, 10, none, NONE, 0, none, NONE, 0, GPO), + NPCM7XX_PINCFG(62, uart1, MFSEL1, 10, bmcuart1, MFSEL3, 24, none, NONE, 0, GPO), + NPCM7XX_PINCFG(63, uart1, MFSEL1, 10, bmcuart1, MFSEL3, 24, none, NONE, 0, GPO), + + NPCM7XX_PINCFG(64, fanin0, MFSEL2, 0, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(65, fanin1, MFSEL2, 1, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(66, fanin2, MFSEL2, 2, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(67, fanin3, MFSEL2, 3, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(68, fanin4, MFSEL2, 4, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(69, fanin5, MFSEL2, 5, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(70, fanin6, MFSEL2, 6, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(71, fanin7, MFSEL2, 7, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(72, fanin8, MFSEL2, 8, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(73, fanin9, MFSEL2, 9, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(74, fanin10, MFSEL2, 10, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(75, fanin11, MFSEL2, 11, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(76, fanin12, MFSEL2, 12, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(77, fanin13, MFSEL2, 13, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(78, fanin14, MFSEL2, 14, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(79, fanin15, MFSEL2, 15, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(87, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(88, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(89, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(90, r2err, MFSEL1, 15, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(93, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0), + NPCM7XX_PINCFG(94, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0), + NPCM7XX_PINCFG(95, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0), + + NPCM7XX_PINCFG(96, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(97, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(98, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(99, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(100, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(101, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(102, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(103, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(104, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(105, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(106, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(107, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(108, rg1mdio, MFSEL4, 21, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(109, rg1mdio, MFSEL4, 21, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(110, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(111, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(112, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(113, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(114, smb0, MFSEL1, 6, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(115, smb0, MFSEL1, 6, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(116, smb1, MFSEL1, 7, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(117, smb1, MFSEL1, 7, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(118, smb2, MFSEL1, 8, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(119, smb2, MFSEL1, 8, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(120, smb2c, I2CSEGSEL, 9, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(121, smb2c, I2CSEGSEL, 9, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(122, smb2b, I2CSEGSEL, 8, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(123, smb2b, I2CSEGSEL, 8, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(124, smb1c, I2CSEGSEL, 6, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(125, smb1c, I2CSEGSEL, 6, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(126, smb1b, I2CSEGSEL, 5, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(127, smb1b, I2CSEGSEL, 5, none, NONE, 0, none, NONE, 0, SLEW), + + NPCM7XX_PINCFG(128, smb8, MFSEL4, 11, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(129, smb8, MFSEL4, 11, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(130, smb9, MFSEL4, 12, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(131, smb9, MFSEL4, 12, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(132, smb10, MFSEL4, 13, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(133, smb10, MFSEL4, 13, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(134, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(135, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(141, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(143, sd1, MFSEL3, 12, sd1pwr, MFSEL4, 5, none, NONE, 0, 0), + NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(153, mmcwp, FLOCKR1, 24, none, NONE, 0, none, NONE, 0, 0), /* Z1/A1 */ + NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(155, mmccd, MFSEL3, 25, mmcrst, MFSEL4, 6, none, NONE, 0, 0), /* Z1/A1 */ + NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + + NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, DS(8, 12)), + NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(163, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0), + NPCM7XX_PINCFG(164, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), + NPCM7XX_PINCFG(165, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), + NPCM7XX_PINCFG(166, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), + NPCM7XX_PINCFG(167, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), + NPCM7XX_PINCFG(168, lpcclk, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL3, 16, 0), + NPCM7XX_PINCFG(169, scipme, MFSEL3, 0, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(170, sci, MFSEL1, 22, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(171, smb6, MFSEL3, 1, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(172, smb6, MFSEL3, 1, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(173, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(174, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(181, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(182, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */ + + NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */ + NPCM7XX_PINCFG(193, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(194, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(195, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(196, smb0c, I2CSEGSEL, 1, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(197, smb0den, I2CSEGSEL, 22, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(198, smb0d, I2CSEGSEL, 2, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(199, smb0d, I2CSEGSEL, 2, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(200, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(201, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(202, smb0c, I2CSEGSEL, 1, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(204, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(205, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(208, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(209, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(210, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(211, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(212, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(213, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(214, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(215, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(216, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(217, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0), + NPCM7XX_PINCFG(218, wdog1, MFSEL3, 19, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(220, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(221, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(222, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0), + NPCM7XX_PINCFG(223, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0), + + NPCM7XX_PINCFG(224, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, SLEW), + NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(253, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC1 power */ + NPCM7XX_PINCFG(254, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC2 power */ + NPCM7XX_PINCFG(255, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* DACOSEL */ +}; + +/* number, name, drv_data */ +static const struct pinctrl_pin_desc npcm7xx_pins[] = { + PINCTRL_PIN(0, "GPIO0/IOX1DI"), + PINCTRL_PIN(1, "GPIO1/IOX1LD"), + PINCTRL_PIN(2, "GPIO2/IOX1CK"), + PINCTRL_PIN(3, "GPIO3/IOX1D0"), + PINCTRL_PIN(4, "GPIO4/IOX2DI/SMB1DSDA"), + PINCTRL_PIN(5, "GPIO5/IOX2LD/SMB1DSCL"), + PINCTRL_PIN(6, "GPIO6/IOX2CK/SMB2DSDA"), + PINCTRL_PIN(7, "GPIO7/IOX2D0/SMB2DSCL"), + PINCTRL_PIN(8, "GPIO8/LKGPO1"), + PINCTRL_PIN(9, "GPIO9/LKGPO2"), + PINCTRL_PIN(10, "GPIO10/IOXHLD"), + PINCTRL_PIN(11, "GPIO11/IOXHCK"), + PINCTRL_PIN(12, "GPIO12/GSPICK/SMB5BSCL"), + PINCTRL_PIN(13, "GPIO13/GSPIDO/SMB5BSDA"), + PINCTRL_PIN(14, "GPIO14/GSPIDI/SMB5CSCL"), + PINCTRL_PIN(15, "GPIO15/GSPICS/SMB5CSDA"), + PINCTRL_PIN(16, "GPIO16/LKGPO0"), + PINCTRL_PIN(17, "GPIO17/PSPI2DI/SMB4DEN"), + PINCTRL_PIN(18, "GPIO18/PSPI2D0/SMB4BSDA"), + PINCTRL_PIN(19, "GPIO19/PSPI2CK/SMB4BSCL"), + PINCTRL_PIN(20, "GPIO20/SMB4CSDA/SMB15SDA"), + PINCTRL_PIN(21, "GPIO21/SMB4CSCL/SMB15SCL"), + PINCTRL_PIN(22, "GPIO22/SMB4DSDA/SMB14SDA"), + PINCTRL_PIN(23, "GPIO23/SMB4DSCL/SMB14SCL"), + PINCTRL_PIN(24, "GPIO24/IOXHDO"), + PINCTRL_PIN(25, "GPIO25/IOXHDI"), + PINCTRL_PIN(26, "GPIO26/SMB5SDA"), + PINCTRL_PIN(27, "GPIO27/SMB5SCL"), + PINCTRL_PIN(28, "GPIO28/SMB4SDA"), + PINCTRL_PIN(29, "GPIO29/SMB4SCL"), + PINCTRL_PIN(30, "GPIO30/SMB3SDA"), + PINCTRL_PIN(31, "GPIO31/SMB3SCL"), + + PINCTRL_PIN(32, "GPIO32/nSPI0CS1"), + PINCTRL_PIN(33, "SPI0D2"), + PINCTRL_PIN(34, "SPI0D3"), + PINCTRL_PIN(37, "GPIO37/SMB3CSDA"), + PINCTRL_PIN(38, "GPIO38/SMB3CSCL"), + PINCTRL_PIN(39, "GPIO39/SMB3BSDA"), + PINCTRL_PIN(40, "GPIO40/SMB3BSCL"), + PINCTRL_PIN(41, "GPIO41/BSPRXD"), + PINCTRL_PIN(42, "GPO42/BSPTXD/STRAP11"), + PINCTRL_PIN(43, "GPIO43/RXD1/JTMS2/BU1RXD"), + PINCTRL_PIN(44, "GPIO44/nCTS1/JTDI2/BU1CTS"), + PINCTRL_PIN(45, "GPIO45/nDCD1/JTDO2"), + PINCTRL_PIN(46, "GPIO46/nDSR1/JTCK2"), + PINCTRL_PIN(47, "GPIO47/nRI1/JCP_RDY2"), + PINCTRL_PIN(48, "GPIO48/TXD2/BSPTXD"), + PINCTRL_PIN(49, "GPIO49/RXD2/BSPRXD"), + PINCTRL_PIN(50, "GPIO50/nCTS2"), + PINCTRL_PIN(51, "GPO51/nRTS2/STRAP2"), + PINCTRL_PIN(52, "GPIO52/nDCD2"), + PINCTRL_PIN(53, "GPO53/nDTR2_BOUT2/STRAP1"), + PINCTRL_PIN(54, "GPIO54/nDSR2"), + PINCTRL_PIN(55, "GPIO55/nRI2"), + PINCTRL_PIN(56, "GPIO56/R1RXERR"), + PINCTRL_PIN(57, "GPIO57/R1MDC"), + PINCTRL_PIN(58, "GPIO58/R1MDIO"), + PINCTRL_PIN(59, "GPIO59/SMB3DSDA"), + PINCTRL_PIN(60, "GPIO60/SMB3DSCL"), + PINCTRL_PIN(61, "GPO61/nDTR1_BOUT1/STRAP6"), + PINCTRL_PIN(62, "GPO62/nRTST1/STRAP5"), + PINCTRL_PIN(63, "GPO63/TXD1/STRAP4"), + + PINCTRL_PIN(64, "GPIO64/FANIN0"), + PINCTRL_PIN(65, "GPIO65/FANIN1"), + PINCTRL_PIN(66, "GPIO66/FANIN2"), + PINCTRL_PIN(67, "GPIO67/FANIN3"), + PINCTRL_PIN(68, "GPIO68/FANIN4"), + PINCTRL_PIN(69, "GPIO69/FANIN5"), + PINCTRL_PIN(70, "GPIO70/FANIN6"), + PINCTRL_PIN(71, "GPIO71/FANIN7"), + PINCTRL_PIN(72, "GPIO72/FANIN8"), + PINCTRL_PIN(73, "GPIO73/FANIN9"), + PINCTRL_PIN(74, "GPIO74/FANIN10"), + PINCTRL_PIN(75, "GPIO75/FANIN11"), + PINCTRL_PIN(76, "GPIO76/FANIN12"), + PINCTRL_PIN(77, "GPIO77/FANIN13"), + PINCTRL_PIN(78, "GPIO78/FANIN14"), + PINCTRL_PIN(79, "GPIO79/FANIN15"), + PINCTRL_PIN(80, "GPIO80/PWM0"), + PINCTRL_PIN(81, "GPIO81/PWM1"), + PINCTRL_PIN(82, "GPIO82/PWM2"), + PINCTRL_PIN(83, "GPIO83/PWM3"), + PINCTRL_PIN(84, "GPIO84/R2TXD0"), + PINCTRL_PIN(85, "GPIO85/R2TXD1"), + PINCTRL_PIN(86, "GPIO86/R2TXEN"), + PINCTRL_PIN(87, "GPIO87/R2RXD0"), + PINCTRL_PIN(88, "GPIO88/R2RXD1"), + PINCTRL_PIN(89, "GPIO89/R2CRSDV"), + PINCTRL_PIN(90, "GPIO90/R2RXERR"), + PINCTRL_PIN(91, "GPIO91/R2MDC"), + PINCTRL_PIN(92, "GPIO92/R2MDIO"), + PINCTRL_PIN(93, "GPIO93/GA20/SMB5DSCL"), + PINCTRL_PIN(94, "GPIO94/nKBRST/SMB5DSDA"), + PINCTRL_PIN(95, "GPIO95/nLRESET/nESPIRST"), + + PINCTRL_PIN(96, "GPIO96/RG1TXD0"), + PINCTRL_PIN(97, "GPIO97/RG1TXD1"), + PINCTRL_PIN(98, "GPIO98/RG1TXD2"), + PINCTRL_PIN(99, "GPIO99/RG1TXD3"), + PINCTRL_PIN(100, "GPIO100/RG1TXC"), + PINCTRL_PIN(101, "GPIO101/RG1TXCTL"), + PINCTRL_PIN(102, "GPIO102/RG1RXD0"), + PINCTRL_PIN(103, "GPIO103/RG1RXD1"), + PINCTRL_PIN(104, "GPIO104/RG1RXD2"), + PINCTRL_PIN(105, "GPIO105/RG1RXD3"), + PINCTRL_PIN(106, "GPIO106/RG1RXC"), + PINCTRL_PIN(107, "GPIO107/RG1RXCTL"), + PINCTRL_PIN(108, "GPIO108/RG1MDC"), + PINCTRL_PIN(109, "GPIO109/RG1MDIO"), + PINCTRL_PIN(110, "GPIO110/RG2TXD0/DDRV0"), + PINCTRL_PIN(111, "GPIO111/RG2TXD1/DDRV1"), + PINCTRL_PIN(112, "GPIO112/RG2TXD2/DDRV2"), + PINCTRL_PIN(113, "GPIO113/RG2TXD3/DDRV3"), + PINCTRL_PIN(114, "GPIO114/SMB0SCL"), + PINCTRL_PIN(115, "GPIO115/SMB0SDA"), + PINCTRL_PIN(116, "GPIO116/SMB1SCL"), + PINCTRL_PIN(117, "GPIO117/SMB1SDA"), + PINCTRL_PIN(118, "GPIO118/SMB2SCL"), + PINCTRL_PIN(119, "GPIO119/SMB2SDA"), + PINCTRL_PIN(120, "GPIO120/SMB2CSDA"), + PINCTRL_PIN(121, "GPIO121/SMB2CSCL"), + PINCTRL_PIN(122, "GPIO122/SMB2BSDA"), + PINCTRL_PIN(123, "GPIO123/SMB2BSCL"), + PINCTRL_PIN(124, "GPIO124/SMB1CSDA"), + PINCTRL_PIN(125, "GPIO125/SMB1CSCL"), + PINCTRL_PIN(126, "GPIO126/SMB1BSDA"), + PINCTRL_PIN(127, "GPIO127/SMB1BSCL"), + + PINCTRL_PIN(128, "GPIO128/SMB8SCL"), + PINCTRL_PIN(129, "GPIO129/SMB8SDA"), + PINCTRL_PIN(130, "GPIO130/SMB9SCL"), + PINCTRL_PIN(131, "GPIO131/SMB9SDA"), + PINCTRL_PIN(132, "GPIO132/SMB10SCL"), + PINCTRL_PIN(133, "GPIO133/SMB10SDA"), + PINCTRL_PIN(134, "GPIO134/SMB11SCL"), + PINCTRL_PIN(135, "GPIO135/SMB11SDA"), + PINCTRL_PIN(136, "GPIO136/SD1DT0"), + PINCTRL_PIN(137, "GPIO137/SD1DT1"), + PINCTRL_PIN(138, "GPIO138/SD1DT2"), + PINCTRL_PIN(139, "GPIO139/SD1DT3"), + PINCTRL_PIN(140, "GPIO140/SD1CLK"), + PINCTRL_PIN(141, "GPIO141/SD1WP"), + PINCTRL_PIN(142, "GPIO142/SD1CMD"), + PINCTRL_PIN(143, "GPIO143/SD1CD/SD1PWR"), + PINCTRL_PIN(144, "GPIO144/PWM4"), + PINCTRL_PIN(145, "GPIO145/PWM5"), + PINCTRL_PIN(146, "GPIO146/PWM6"), + PINCTRL_PIN(147, "GPIO147/PWM7"), + PINCTRL_PIN(148, "GPIO148/MMCDT4"), + PINCTRL_PIN(149, "GPIO149/MMCDT5"), + PINCTRL_PIN(150, "GPIO150/MMCDT6"), + PINCTRL_PIN(151, "GPIO151/MMCDT7"), + PINCTRL_PIN(152, "GPIO152/MMCCLK"), + PINCTRL_PIN(153, "GPIO153/MMCWP"), + PINCTRL_PIN(154, "GPIO154/MMCCMD"), + PINCTRL_PIN(155, "GPIO155/nMMCCD/nMMCRST"), + PINCTRL_PIN(156, "GPIO156/MMCDT0"), + PINCTRL_PIN(157, "GPIO157/MMCDT1"), + PINCTRL_PIN(158, "GPIO158/MMCDT2"), + PINCTRL_PIN(159, "GPIO159/MMCDT3"), + + PINCTRL_PIN(160, "GPIO160/CLKOUT/RNGOSCOUT"), + PINCTRL_PIN(161, "GPIO161/nLFRAME/nESPICS"), + PINCTRL_PIN(162, "GPIO162/SERIRQ"), + PINCTRL_PIN(163, "GPIO163/LCLK/ESPICLK"), + PINCTRL_PIN(164, "GPIO164/LAD0/ESPI_IO0"/*dscnt6*/), + PINCTRL_PIN(165, "GPIO165/LAD1/ESPI_IO1"/*dscnt6*/), + PINCTRL_PIN(166, "GPIO166/LAD2/ESPI_IO2"/*dscnt6*/), + PINCTRL_PIN(167, "GPIO167/LAD3/ESPI_IO3"/*dscnt6*/), + PINCTRL_PIN(168, "GPIO168/nCLKRUN/nESPIALERT"), + PINCTRL_PIN(169, "GPIO169/nSCIPME"), + PINCTRL_PIN(170, "GPIO170/nSMI"), + PINCTRL_PIN(171, "GPIO171/SMB6SCL"), + PINCTRL_PIN(172, "GPIO172/SMB6SDA"), + PINCTRL_PIN(173, "GPIO173/SMB7SCL"), + PINCTRL_PIN(174, "GPIO174/SMB7SDA"), + PINCTRL_PIN(175, "GPIO175/PSPI1CK/FANIN19"), + PINCTRL_PIN(176, "GPIO176/PSPI1DO/FANIN18"), + PINCTRL_PIN(177, "GPIO177/PSPI1DI/FANIN17"), + PINCTRL_PIN(178, "GPIO178/R1TXD0"), + PINCTRL_PIN(179, "GPIO179/R1TXD1"), + PINCTRL_PIN(180, "GPIO180/R1TXEN"), + PINCTRL_PIN(181, "GPIO181/R1RXD0"), + PINCTRL_PIN(182, "GPIO182/R1RXD1"), + PINCTRL_PIN(183, "GPIO183/SPI3CK"), + PINCTRL_PIN(184, "GPO184/SPI3D0/STRAP9"), + PINCTRL_PIN(185, "GPO185/SPI3D1/STRAP10"), + PINCTRL_PIN(186, "GPIO186/nSPI3CS0"), + PINCTRL_PIN(187, "GPIO187/nSPI3CS1"), + PINCTRL_PIN(188, "GPIO188/SPI3D2/nSPI3CS2"), + PINCTRL_PIN(189, "GPIO189/SPI3D3/nSPI3CS3"), + PINCTRL_PIN(190, "GPIO190/nPRD_SMI"), + PINCTRL_PIN(191, "GPIO191"), + + PINCTRL_PIN(192, "GPIO192"), + PINCTRL_PIN(193, "GPIO193/R1CRSDV"), + PINCTRL_PIN(194, "GPIO194/SMB0BSCL"), + PINCTRL_PIN(195, "GPIO195/SMB0BSDA"), + PINCTRL_PIN(196, "GPIO196/SMB0CSCL"), + PINCTRL_PIN(197, "GPIO197/SMB0DEN"), + PINCTRL_PIN(198, "GPIO198/SMB0DSDA"), + PINCTRL_PIN(199, "GPIO199/SMB0DSCL"), + PINCTRL_PIN(200, "GPIO200/R2CK"), + PINCTRL_PIN(201, "GPIO201/R1CK"), + PINCTRL_PIN(202, "GPIO202/SMB0CSDA"), + PINCTRL_PIN(203, "GPIO203/FANIN16"), + PINCTRL_PIN(204, "GPIO204/DDC2SCL"), + PINCTRL_PIN(205, "GPIO205/DDC2SDA"), + PINCTRL_PIN(206, "GPIO206/HSYNC2"), + PINCTRL_PIN(207, "GPIO207/VSYNC2"), + PINCTRL_PIN(208, "GPIO208/RG2TXC/DVCK"), + PINCTRL_PIN(209, "GPIO209/RG2TXCTL/DDRV4"), + PINCTRL_PIN(210, "GPIO210/RG2RXD0/DDRV5"), + PINCTRL_PIN(211, "GPIO211/RG2RXD1/DDRV6"), + PINCTRL_PIN(212, "GPIO212/RG2RXD2/DDRV7"), + PINCTRL_PIN(213, "GPIO213/RG2RXD3/DDRV8"), + PINCTRL_PIN(214, "GPIO214/RG2RXC/DDRV9"), + PINCTRL_PIN(215, "GPIO215/RG2RXCTL/DDRV10"), + PINCTRL_PIN(216, "GPIO216/RG2MDC/DDRV11"), + PINCTRL_PIN(217, "GPIO217/RG2MDIO/DVHSYNC"), + PINCTRL_PIN(218, "GPIO218/nWDO1"), + PINCTRL_PIN(219, "GPIO219/nWDO2"), + PINCTRL_PIN(220, "GPIO220/SMB12SCL"), + PINCTRL_PIN(221, "GPIO221/SMB12SDA"), + PINCTRL_PIN(222, "GPIO222/SMB13SCL"), + PINCTRL_PIN(223, "GPIO223/SMB13SDA"), + + PINCTRL_PIN(224, "GPIO224/SPIXCK"), + PINCTRL_PIN(225, "GPO225/SPIXD0/STRAP12"), + PINCTRL_PIN(226, "GPO226/SPIXD1/STRAP13"), + PINCTRL_PIN(227, "GPIO227/nSPIXCS0"), + PINCTRL_PIN(228, "GPIO228/nSPIXCS1"), + PINCTRL_PIN(229, "GPO229/SPIXD2/STRAP3"), + PINCTRL_PIN(230, "GPIO230/SPIXD3"), + PINCTRL_PIN(231, "GPIO231/nCLKREQ"), + PINCTRL_PIN(255, "GPI255/DACOSEL"), +}; + +/* Enable mode in pin group */ +static void npcm7xx_setfunc(struct regmap *gcr_regmap, const unsigned int *pin, + int pin_number, int mode) +{ + const struct npcm7xx_pincfg *cfg; + int i; + + for (i = 0 ; i < pin_number ; i++) { + cfg = &pincfg[pin[i]]; + if (mode == fn_gpio || cfg->fn0 == mode || cfg->fn1 == mode || cfg->fn2 == mode) { + if (cfg->reg0) + regmap_update_bits(gcr_regmap, cfg->reg0, + BIT(cfg->bit0), + !!(cfg->fn0 == mode) ? + BIT(cfg->bit0) : 0); + if (cfg->reg1) + regmap_update_bits(gcr_regmap, cfg->reg1, + BIT(cfg->bit1), + !!(cfg->fn1 == mode) ? + BIT(cfg->bit1) : 0); + if (cfg->reg2) + regmap_update_bits(gcr_regmap, cfg->reg2, + BIT(cfg->bit2), + !!(cfg->fn2 == mode) ? + BIT(cfg->bit2) : 0); + } + } +} + +/* Get slew rate of pin (high/low) */ +static int npcm7xx_get_slew_rate(struct npcm7xx_gpio *bank, + struct regmap *gcr_regmap, unsigned int pin) +{ + u32 val; + int gpio = (pin % bank->gc.ngpio); + unsigned long pinmask = BIT(gpio); + + if (pincfg[pin].flag & SLEW) + return ioread32(bank->base + NPCM7XX_GP_N_OSRC) + & pinmask; + /* LPC Slew rate in SRCNT register */ + if (pincfg[pin].flag & SLEWLPC) { + regmap_read(gcr_regmap, NPCM7XX_GCR_SRCNT, &val); + return !!(val & SRCNT_ESPI); + } + + return -EINVAL; +} + +/* Set slew rate of pin (high/low) */ +static int npcm7xx_set_slew_rate(struct npcm7xx_gpio *bank, + struct regmap *gcr_regmap, unsigned int pin, + int arg) +{ + int gpio = BIT(pin % bank->gc.ngpio); + + if (pincfg[pin].flag & SLEW) { + switch (arg) { + case 0: + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_OSRC, + gpio); + return 0; + case 1: + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_OSRC, + gpio); + return 0; + default: + return -EINVAL; + } + } + /* LPC Slew rate in SRCNT register */ + if (pincfg[pin].flag & SLEWLPC) { + switch (arg) { + case 0: + regmap_update_bits(gcr_regmap, NPCM7XX_GCR_SRCNT, + SRCNT_ESPI, 0); + return 0; + case 1: + regmap_update_bits(gcr_regmap, NPCM7XX_GCR_SRCNT, + SRCNT_ESPI, SRCNT_ESPI); + return 0; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +/* Get drive strength for a pin, if supported */ +static int npcm7xx_get_drive_strength(struct pinctrl_dev *pctldev, + unsigned int pin) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + struct npcm7xx_gpio *bank = + &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; + int gpio = (pin % bank->gc.ngpio); + unsigned long pinmask = BIT(gpio); + u32 ds = 0; + int flg, val; + + flg = pincfg[pin].flag; + if (flg & DRIVE_STRENGTH_MASK) { + /* Get standard reading */ + val = ioread32(bank->base + NPCM7XX_GP_N_ODSC) + & pinmask; + ds = val ? DSHI(flg) : DSLO(flg); + dev_dbg(bank->gc.parent, + "pin %d strength %d = %d\n", pin, val, ds); + return ds; + } + + return -EINVAL; +} + +/* Set drive strength for a pin, if supported */ +static int npcm7xx_set_drive_strength(struct npcm7xx_pinctrl *npcm, + unsigned int pin, int nval) +{ + int v; + struct npcm7xx_gpio *bank = + &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; + int gpio = BIT(pin % bank->gc.ngpio); + + v = (pincfg[pin].flag & DRIVE_STRENGTH_MASK); + if (!nval || !v) + return -ENOTSUPP; + if (DSLO(v) == nval) { + dev_dbg(bank->gc.parent, + "setting pin %d to low strength [%d]\n", pin, nval); + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_ODSC, gpio); + return 0; + } else if (DSHI(v) == nval) { + dev_dbg(bank->gc.parent, + "setting pin %d to high strength [%d]\n", pin, nval); + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_ODSC, gpio); + return 0; + } + + return -ENOTSUPP; +} + +/* pinctrl_ops */ +static void npcm7xx_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int offset) +{ + seq_printf(s, "pinctrl_ops.dbg: %d", offset); +} + +static int npcm7xx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npcm->dev, "group size: %d\n", ARRAY_SIZE(npcm7xx_groups)); + return ARRAY_SIZE(npcm7xx_groups); +} + +static const char *npcm7xx_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return npcm7xx_groups[selector].name; +} + +static int npcm7xx_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, + const unsigned int **pins, + unsigned int *npins) +{ + *npins = npcm7xx_groups[selector].npins; + *pins = npcm7xx_groups[selector].pins; + + return 0; +} + +static int npcm7xx_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + u32 *num_maps) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npcm->dev, "dt_node_to_map: %s\n", np_config->name); + return pinconf_generic_dt_node_to_map(pctldev, np_config, + map, num_maps, + PIN_MAP_TYPE_INVALID); +} + +static void npcm7xx_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, u32 num_maps) +{ + kfree(map); +} + +static struct pinctrl_ops npcm7xx_pinctrl_ops = { + .get_groups_count = npcm7xx_get_groups_count, + .get_group_name = npcm7xx_get_group_name, + .get_group_pins = npcm7xx_get_group_pins, + .pin_dbg_show = npcm7xx_pin_dbg_show, + .dt_node_to_map = npcm7xx_dt_node_to_map, + .dt_free_map = npcm7xx_dt_free_map, +}; + +/* pinmux_ops */ +static int npcm7xx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(npcm7xx_funcs); +} + +static const char *npcm7xx_get_function_name(struct pinctrl_dev *pctldev, + unsigned int function) +{ + return npcm7xx_funcs[function].name; +} + +static int npcm7xx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned int function, + const char * const **groups, + unsigned int * const ngroups) +{ + *ngroups = npcm7xx_funcs[function].ngroups; + *groups = npcm7xx_funcs[function].groups; + + return 0; +} + +static int npcm7xx_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, + unsigned int group) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npcm->dev, "set_mux: %d, %d[%s]\n", function, group, + npcm7xx_groups[group].name); + + npcm7xx_setfunc(npcm->gcr_regmap, npcm7xx_groups[group].pins, + npcm7xx_groups[group].npins, group); + + return 0; +} + +static int npcm7xx_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + + if (!range) { + dev_err(npcm->dev, "invalid range\n"); + return -EINVAL; + } + if (!range->gc) { + dev_err(npcm->dev, "invalid gpiochip\n"); + return -EINVAL; + } + + npcm7xx_setfunc(npcm->gcr_regmap, &offset, 1, fn_gpio); + + return 0; +} + +/* Release GPIO back to pinctrl mode */ +static void npcm7xx_gpio_request_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + int virq; + + virq = irq_find_mapping(npcm->domain, offset); + if (virq) + irq_dispose_mapping(virq); +} + +/* Set GPIO direction */ +static int npcm_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + struct npcm7xx_gpio *bank = + &npcm->gpio_bank[offset / NPCM7XX_GPIO_PER_BANK]; + int gpio = BIT(offset % bank->gc.ngpio); + + dev_dbg(bank->gc.parent, "GPIO Set Direction: %d = %d\n", offset, + input); + if (input) + iowrite32(gpio, bank->base + NPCM7XX_GP_N_OEC); + else + iowrite32(gpio, bank->base + NPCM7XX_GP_N_OES); + + return 0; +} + +static struct pinmux_ops npcm7xx_pinmux_ops = { + .get_functions_count = npcm7xx_get_functions_count, + .get_function_name = npcm7xx_get_function_name, + .get_function_groups = npcm7xx_get_function_groups, + .set_mux = npcm7xx_pinmux_set_mux, + .gpio_request_enable = npcm7xx_gpio_request_enable, + .gpio_disable_free = npcm7xx_gpio_request_free, + .gpio_set_direction = npcm_gpio_set_direction, +}; + +/* pinconf_ops */ +static int npcm7xx_config_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + enum pin_config_param param = pinconf_to_config_param(*config); + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + struct npcm7xx_gpio *bank = + &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; + int gpio = (pin % bank->gc.ngpio); + unsigned long pinmask = BIT(gpio); + u32 ie, oe, pu, pd; + int rc = 0; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + pu = ioread32(bank->base + NPCM7XX_GP_N_PU) & pinmask; + pd = ioread32(bank->base + NPCM7XX_GP_N_PD) & pinmask; + if (param == PIN_CONFIG_BIAS_DISABLE) + rc = (!pu && !pd); + else if (param == PIN_CONFIG_BIAS_PULL_UP) + rc = (pu && !pd); + else if (param == PIN_CONFIG_BIAS_PULL_DOWN) + rc = (!pu && pd); + break; + case PIN_CONFIG_OUTPUT: + case PIN_CONFIG_INPUT_ENABLE: + ie = ioread32(bank->base + NPCM7XX_GP_N_IEM) & pinmask; + oe = ioread32(bank->base + NPCM7XX_GP_N_OE) & pinmask; + if (param == PIN_CONFIG_INPUT_ENABLE) + rc = (ie && !oe); + else if (param == PIN_CONFIG_OUTPUT) + rc = (!ie && oe); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + rc = !(ioread32(bank->base + NPCM7XX_GP_N_OTYP) & pinmask); + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + rc = ioread32(bank->base + NPCM7XX_GP_N_OTYP) & pinmask; + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + rc = ioread32(bank->base + NPCM7XX_GP_N_DBNC) & pinmask; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + rc = npcm7xx_get_drive_strength(pctldev, pin); + if (rc) + *config = pinconf_to_config_packed(param, rc); + break; + case PIN_CONFIG_SLEW_RATE: + rc = npcm7xx_get_slew_rate(bank, npcm->gcr_regmap, pin); + if (rc >= 0) + *config = pinconf_to_config_packed(param, rc); + break; + default: + return -ENOTSUPP; + } + + if (!rc) + return -EINVAL; + + return 0; +} + +static int npcm7xx_config_set_one(struct npcm7xx_pinctrl *npcm, + unsigned int pin, unsigned long config) +{ + enum pin_config_param param = pinconf_to_config_param(config); + u16 arg = pinconf_to_config_argument(config); + struct npcm7xx_gpio *bank = + &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK]; + int gpio = BIT(pin % bank->gc.ngpio); + + dev_dbg(bank->gc.parent, "param=%d %d[GPIO]\n", param, pin); + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio); + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio); + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio); + break; + case PIN_CONFIG_BIAS_PULL_UP: + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio); + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio); + break; + case PIN_CONFIG_INPUT_ENABLE: + if (arg) { + iowrite32(gpio, bank->base + NPCM7XX_GP_N_OEC); + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_IEM, + gpio); + } else + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_IEM, + gpio); + break; + case PIN_CONFIG_OUTPUT: + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_IEM, gpio); + iowrite32(gpio, arg ? bank->base + NPCM7XX_GP_N_DOS : + bank->base + NPCM7XX_GP_N_DOC); + iowrite32(gpio, bank->base + NPCM7XX_GP_N_OES); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_OTYP, gpio); + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_OTYP, gpio); + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_DBNC, gpio); + break; + case PIN_CONFIG_SLEW_RATE: + return npcm7xx_set_slew_rate(bank, npcm->gcr_regmap, pin, arg); + case PIN_CONFIG_DRIVE_STRENGTH: + return npcm7xx_set_drive_strength(npcm, pin, arg); + default: + return -ENOTSUPP; + } + + return 0; +} + +/* Set multiple configuration settings for a pin */ +static int npcm7xx_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); + int rc; + + while (num_configs--) { + rc = npcm7xx_config_set_one(npcm, pin, *configs++); + if (rc) + return rc; + } + + return 0; +} + +static struct pinconf_ops npcm7xx_pinconf_ops = { + .is_generic = true, + .pin_config_get = npcm7xx_config_get, + .pin_config_set = npcm7xx_config_set, +}; + +/* pinctrl_desc */ +static struct pinctrl_desc npcm7xx_pinctrl_desc = { + .name = "npcm7xx-pinctrl", + .pins = npcm7xx_pins, + .npins = ARRAY_SIZE(npcm7xx_pins), + .pctlops = &npcm7xx_pinctrl_ops, + .pmxops = &npcm7xx_pinmux_ops, + .confops = &npcm7xx_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) +{ + int ret = -ENXIO; + struct resource res; + int id = 0, irq; + struct device_node *np; + struct of_phandle_args pinspec; + + for_each_available_child_of_node(pctrl->dev->of_node, np) + if (of_find_property(np, "gpio-controller", NULL)) { + ret = of_address_to_resource(np, 0, &res); + if (ret < 0) { + dev_err(pctrl->dev, + "Resource fail for GPIO bank %u\n", id); + return ret; + } + + pctrl->gpio_bank[id].base = + ioremap(res.start, resource_size(&res)); + + irq = irq_of_parse_and_map(np, 0); + if (irq < 0) { + dev_err(pctrl->dev, + "No IRQ for GPIO bank %u\n", id); + ret = irq; + return ret; + } + + ret = bgpio_init(&pctrl->gpio_bank[id].gc, + pctrl->dev, 4, + pctrl->gpio_bank[id].base + + NPCM7XX_GP_N_DIN, + pctrl->gpio_bank[id].base + + NPCM7XX_GP_N_DOUT, + NULL, + NULL, + pctrl->gpio_bank[id].base + + NPCM7XX_GP_N_IEM, + BGPIOF_READ_OUTPUT_REG_SET); + if (ret) { + dev_err(pctrl->dev, "bgpio_init() failed\n"); + return ret; + } + + ret = of_parse_phandle_with_fixed_args(np, + "gpio-ranges", 3, + 0, &pinspec); + if (ret < 0) { + dev_err(pctrl->dev, + "gpio-ranges fail for GPIO bank %u\n", + id); + return ret; + } + + pctrl->gpio_bank[id].irq = irq; + pctrl->gpio_bank[id].irq_chip = npcmgpio_irqchip; + pctrl->gpio_bank[id].gc.parent = pctrl->dev; + pctrl->gpio_bank[id].irqbase = + id * NPCM7XX_GPIO_PER_BANK; + pctrl->gpio_bank[id].pinctrl_id = pinspec.args[0]; + pctrl->gpio_bank[id].gc.base = pinspec.args[1]; + pctrl->gpio_bank[id].gc.ngpio = pinspec.args[2]; + pctrl->gpio_bank[id].gc.owner = THIS_MODULE; + pctrl->gpio_bank[id].gc.label = + devm_kasprintf(pctrl->dev, GFP_KERNEL, "%pOF", + np); + pctrl->gpio_bank[id].gc.dbg_show = npcmgpio_dbg_show; + pctrl->gpio_bank[id].direction_input = + pctrl->gpio_bank[id].gc.direction_input; + pctrl->gpio_bank[id].gc.direction_input = + npcmgpio_direction_input; + pctrl->gpio_bank[id].direction_output = + pctrl->gpio_bank[id].gc.direction_output; + pctrl->gpio_bank[id].gc.direction_output = + npcmgpio_direction_output; + pctrl->gpio_bank[id].request = + pctrl->gpio_bank[id].gc.request; + pctrl->gpio_bank[id].gc.request = npcmgpio_gpio_request; + pctrl->gpio_bank[id].gc.free = npcmgpio_gpio_free; + pctrl->gpio_bank[id].gc.of_node = np; + id++; + } + + pctrl->bank_num = id; + return ret; +} + +static int npcm7xx_gpio_register(struct npcm7xx_pinctrl *pctrl) +{ + int ret, id; + + for (id = 0 ; id < pctrl->bank_num ; id++) { + ret = devm_gpiochip_add_data(pctrl->dev, + &pctrl->gpio_bank[id].gc, + &pctrl->gpio_bank[id]); + if (ret) { + dev_err(pctrl->dev, "Failed to add GPIO chip %u\n", id); + goto err_register; + } + + ret = gpiochip_add_pin_range(&pctrl->gpio_bank[id].gc, + dev_name(pctrl->dev), + pctrl->gpio_bank[id].pinctrl_id, + pctrl->gpio_bank[id].gc.base, + pctrl->gpio_bank[id].gc.ngpio); + if (ret < 0) { + dev_err(pctrl->dev, "Failed to add GPIO bank %u\n", id); + gpiochip_remove(&pctrl->gpio_bank[id].gc); + goto err_register; + } + + ret = gpiochip_irqchip_add(&pctrl->gpio_bank[id].gc, + &pctrl->gpio_bank[id].irq_chip, + 0, handle_level_irq, + IRQ_TYPE_NONE); + if (ret < 0) { + dev_err(pctrl->dev, + "Failed to add IRQ chip %u\n", id); + gpiochip_remove(&pctrl->gpio_bank[id].gc); + goto err_register; + } + + gpiochip_set_chained_irqchip(&pctrl->gpio_bank[id].gc, + &pctrl->gpio_bank[id].irq_chip, + pctrl->gpio_bank[id].irq, + npcmgpio_irq_handler); + } + + return 0; + +err_register: + for (; id > 0; id--) + gpiochip_remove(&pctrl->gpio_bank[id - 1].gc); + + return ret; +} + +static int npcm7xx_pinctrl_probe(struct platform_device *pdev) +{ + struct npcm7xx_pinctrl *pctrl; + int ret; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, pctrl); + + pctrl->gcr_regmap = + syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr"); + if (IS_ERR(pctrl->gcr_regmap)) { + dev_err(pctrl->dev, "didn't find nuvoton,npcm750-gcr\n"); + return PTR_ERR(pctrl->gcr_regmap); + } + + ret = npcm7xx_gpio_of(pctrl); + if (ret < 0) { + dev_err(pctrl->dev, "Failed to gpio dt-binding %u\n", ret); + return ret; + } + + pctrl->pctldev = devm_pinctrl_register(&pdev->dev, + &npcm7xx_pinctrl_desc, pctrl); + if (IS_ERR(pctrl->pctldev)) { + dev_err(&pdev->dev, "Failed to register pinctrl device\n"); + return PTR_ERR(pctrl->pctldev); + } + + ret = npcm7xx_gpio_register(pctrl); + if (ret < 0) { + dev_err(pctrl->dev, "Failed to register gpio %u\n", ret); + return ret; + } + + pr_info("NPCM7xx Pinctrl driver probed\n"); + return 0; +} + +static const struct of_device_id npcm7xx_pinctrl_match[] = { + { .compatible = "nuvoton,npcm750-pinctrl" }, + { }, +}; +MODULE_DEVICE_TABLE(of, npcm7xx_pinctrl_match); + +static struct platform_driver npcm7xx_pinctrl_driver = { + .probe = npcm7xx_pinctrl_probe, + .driver = { + .name = "npcm7xx-pinctrl", + .of_match_table = npcm7xx_pinctrl_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init npcm7xx_pinctrl_register(void) +{ + return platform_driver_register(&npcm7xx_pinctrl_driver); +} +arch_initcall(npcm7xx_pinctrl_register); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("jordan_hargrave@dell.com"); +MODULE_AUTHOR("tomer.maimon@nuvoton.com"); +MODULE_DESCRIPTION("Nuvoton NPCM7XX Pinctrl and GPIO driver"); diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 1425c2874d40..67718b0f978d 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -24,7 +24,7 @@ #include <linux/errno.h> #include <linux/log2.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/mutex.h> diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c index 4e9fe7854e8a..13c193156363 100644 --- a/drivers/pinctrl/pinctrl-as3722.c +++ b/drivers/pinctrl/pinctrl-as3722.c @@ -21,7 +21,7 @@ */ #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mfd/as3722.h> diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index ef7ab208b951..5a850491a5cb 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -17,8 +17,6 @@ #include <dt-bindings/pinctrl/at91.h> #include <linux/clk.h> #include <linux/gpio/driver.h> -/* FIXME: needed for gpio_to_irq(), get rid of this */ -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/init.h> @@ -264,6 +262,13 @@ static struct irq_chip atmel_gpio_irq_chip = { .irq_set_wake = atmel_gpio_irq_set_wake, }; +static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip); + + return irq_find_mapping(atmel_pioctrl->irq_domain, offset); +} + static void atmel_gpio_irq_handler(struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); @@ -297,8 +302,9 @@ static void atmel_gpio_irq_handler(struct irq_desc *desc) break; for_each_set_bit(n, &isr, BITS_PER_LONG) - generic_handle_irq(gpio_to_irq(bank * - ATMEL_PIO_NPINS_PER_BANK + n)); + generic_handle_irq(atmel_gpio_to_irq( + atmel_pioctrl->gpio_chip, + bank * ATMEL_PIO_NPINS_PER_BANK + n)); } chained_irq_exit(chip, desc); @@ -360,13 +366,6 @@ static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val) BIT(pin->line)); } -static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip); - - return irq_find_mapping(atmel_pioctrl->irq_domain, offset); -} - static struct gpio_chip atmel_gpio_chip = { .direction_input = atmel_gpio_direction_input, .get = atmel_gpio_get, @@ -493,7 +492,6 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned num_pins, num_configs, reserve; unsigned long *configs; struct property *pins; - bool has_config; u32 pinfunc; int ret, i; @@ -509,9 +507,6 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, return ret; } - if (num_configs) - has_config = true; - num_pins = pins->length / sizeof(u32); if (!num_pins) { dev_err(pctldev->dev, "no pins found in node %pOF\n", np); @@ -524,7 +519,7 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, * map for each pin. */ reserve = 1; - if (has_config && num_pins >= 1) + if (num_configs) reserve++; reserve *= num_pins; ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, @@ -547,7 +542,7 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps, group, func); - if (has_config) { + if (num_configs) { ret = pinctrl_utils_add_map_configs(pctldev, map, reserved_maps, num_maps, group, configs, num_configs, diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 50f0ec42c637..3d49bbbcdbc7 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -16,7 +16,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> @@ -263,8 +263,8 @@ static int at91_dt_node_to_map(struct pinctrl_dev *pctldev, */ grp = at91_pinctrl_find_group_by_name(info, np->name); if (!grp) { - dev_err(info->dev, "unable to find group for node %s\n", - np->name); + dev_err(info->dev, "unable to find group for node %pOFn\n", + np); return -EINVAL; } @@ -1071,7 +1071,7 @@ static int at91_pinctrl_parse_groups(struct device_node *np, const __be32 *list; int i, j; - dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + dev_dbg(info->dev, "group(%d): %pOFn\n", index, np); /* Initialise group */ grp->name = np->name; @@ -1122,7 +1122,7 @@ static int at91_pinctrl_parse_functions(struct device_node *np, static u32 grp_index; u32 i = 0; - dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np); func = &info->functions[index]; @@ -1487,7 +1487,7 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type) return 0; case IRQ_TYPE_NONE: default: - pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq)); + pr_warn("AT91: No type for GPIO irq offset %d\n", d->irq); return -EINVAL; } @@ -1574,16 +1574,6 @@ void at91_pinctrl_gpio_resume(void) #define gpio_irq_set_wake NULL #endif /* CONFIG_PM */ -static struct irq_chip gpio_irqchip = { - .name = "GPIO", - .irq_ack = gpio_irq_ack, - .irq_disable = gpio_irq_mask, - .irq_mask = gpio_irq_mask, - .irq_unmask = gpio_irq_unmask, - /* .irq_set_type is set dynamically */ - .irq_set_wake = gpio_irq_set_wake, -}; - static void gpio_irq_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); @@ -1624,12 +1614,22 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, struct gpio_chip *gpiochip_prev = NULL; struct at91_gpio_chip *prev = NULL; struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); + struct irq_chip *gpio_irqchip; int ret, i; + gpio_irqchip = devm_kzalloc(&pdev->dev, sizeof(*gpio_irqchip), GFP_KERNEL); + if (!gpio_irqchip) + return -ENOMEM; + at91_gpio->pioc_hwirq = irqd_to_hwirq(d); - /* Setup proper .irq_set_type function */ - gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type; + gpio_irqchip->name = "GPIO"; + gpio_irqchip->irq_ack = gpio_irq_ack; + gpio_irqchip->irq_disable = gpio_irq_mask; + gpio_irqchip->irq_mask = gpio_irq_mask; + gpio_irqchip->irq_unmask = gpio_irq_unmask; + gpio_irqchip->irq_set_wake = gpio_irq_set_wake, + gpio_irqchip->irq_set_type = at91_gpio->ops->irq_type; /* Disable irqs of this PIO controller */ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); @@ -1640,7 +1640,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, * interrupt. */ ret = gpiochip_irqchip_add(&at91_gpio->chip, - &gpio_irqchip, + gpio_irqchip, 0, handle_edge_irq, IRQ_TYPE_NONE); @@ -1658,7 +1658,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, if (!gpiochip_prev) { /* Then register the chain on the parent IRQ */ gpiochip_set_chained_irqchip(&at91_gpio->chip, - &gpio_irqchip, + gpio_irqchip, at91_gpio->pioc_virq, gpio_irq_handler); return 0; diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 7939b178c6ae..63035181dfde 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -15,7 +15,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/slab.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/pinconf-generic.h> diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c index 5353b23f775c..b7533726340d 100644 --- a/drivers/pinctrl/pinctrl-digicolor.c +++ b/drivers/pinctrl/pinctrl-digicolor.c @@ -20,7 +20,6 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/gpio/driver.h> #include <linux/spinlock.h> #include <linux/pinctrl/machine.h> diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c index fb73dcbb5ef3..4d032e637f5c 100644 --- a/drivers/pinctrl/pinctrl-falcon.c +++ b/drivers/pinctrl/pinctrl-falcon.c @@ -10,7 +10,7 @@ * Copyright (C) 2012 John Crispin <john@phrozen.org> */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/export.h> diff --git a/drivers/pinctrl/pinctrl-gemini.c b/drivers/pinctrl/pinctrl-gemini.c index fa7d998e1d5a..f75bf6f16a2e 100644 --- a/drivers/pinctrl/pinctrl-gemini.c +++ b/drivers/pinctrl/pinctrl-gemini.c @@ -591,13 +591,16 @@ static const unsigned int tvc_3512_pins[] = { 319, /* TVC_DATA[1] */ 301, /* TVC_DATA[2] */ 283, /* TVC_DATA[3] */ - 265, /* TVC_CLK */ 320, /* TVC_DATA[4] */ 302, /* TVC_DATA[5] */ 284, /* TVC_DATA[6] */ 266, /* TVC_DATA[7] */ }; +static const unsigned int tvc_clk_3512_pins[] = { + 265, /* TVC_CLK */ +}; + /* NAND flash pins */ static const unsigned int nflash_3512_pins[] = { 199, 200, 201, 202, 216, 217, 218, 219, 220, 234, 235, 236, 237, 252, @@ -629,7 +632,7 @@ static const unsigned int pflash_3512_pins_extended[] = { /* Serial flash pins CE0, CE1, DI, DO, CK */ static const unsigned int sflash_3512_pins[] = { 230, 231, 232, 233, 211 }; -/* The GPIO0A (0) pin overlap with TVC and extended parallel flash */ +/* The GPIO0A (0) pin overlap with TVC CLK and extended parallel flash */ static const unsigned int gpio0a_3512_pins[] = { 265 }; /* The GPIO0B (1-4) pins overlap with TVC and ICE */ @@ -823,7 +826,13 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = { .num_pins = ARRAY_SIZE(tvc_3512_pins), /* Conflict with character LCD and ICE */ .mask = LCD_PADS_ENABLE, - .value = TVC_PADS_ENABLE | TVC_CLK_PAD_ENABLE, + .value = TVC_PADS_ENABLE, + }, + { + .name = "tvcclkgrp", + .pins = tvc_clk_3512_pins, + .num_pins = ARRAY_SIZE(tvc_clk_3512_pins), + .value = TVC_CLK_PAD_ENABLE, }, /* * The construction is done such that it is possible to use a serial @@ -860,8 +869,8 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = { .name = "gpio0agrp", .pins = gpio0a_3512_pins, .num_pins = ARRAY_SIZE(gpio0a_3512_pins), - /* Conflict with TVC */ - .mask = TVC_PADS_ENABLE, + /* Conflict with TVC CLK */ + .mask = TVC_CLK_PAD_ENABLE, }, { .name = "gpio0bgrp", @@ -1531,13 +1540,16 @@ static const unsigned int tvc_3516_pins[] = { 311, /* TVC_DATA[1] */ 394, /* TVC_DATA[2] */ 374, /* TVC_DATA[3] */ - 333, /* TVC_CLK */ 354, /* TVC_DATA[4] */ 395, /* TVC_DATA[5] */ 312, /* TVC_DATA[6] */ 334, /* TVC_DATA[7] */ }; +static const unsigned int tvc_clk_3516_pins[] = { + 333, /* TVC_CLK */ +}; + /* NAND flash pins */ static const unsigned int nflash_3516_pins[] = { 243, 260, 261, 224, 280, 262, 281, 264, 300, 263, 282, 301, 320, 283, @@ -1570,7 +1582,7 @@ static const unsigned int pflash_3516_pins_extended[] = { static const unsigned int sflash_3516_pins[] = { 296, 338, 295, 359, 339 }; /* The GPIO0A (0-4) pins overlap with TVC and extended parallel flash */ -static const unsigned int gpio0a_3516_pins[] = { 333, 354, 395, 312, 334 }; +static const unsigned int gpio0a_3516_pins[] = { 354, 395, 312, 334 }; /* The GPIO0B (5-7) pins overlap with ICE */ static const unsigned int gpio0b_3516_pins[] = { 375, 396, 376 }; @@ -1602,6 +1614,9 @@ static const unsigned int gpio0j_3516_pins[] = { 359, 339 }; /* The GPIO0K (30,31) pins overlap with NAND flash */ static const unsigned int gpio0k_3516_pins[] = { 275, 298 }; +/* The GPIO0L (0) pins overlap with TVC_CLK */ +static const unsigned int gpio0l_3516_pins[] = { 333 }; + /* The GPIO1A (0-4) pins that overlap with IDE and parallel flash */ static const unsigned int gpio1a_3516_pins[] = { 221, 200, 222, 201, 220 }; @@ -1761,7 +1776,13 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = { .num_pins = ARRAY_SIZE(tvc_3516_pins), /* Conflict with character LCD */ .mask = LCD_PADS_ENABLE, - .value = TVC_PADS_ENABLE | TVC_CLK_PAD_ENABLE, + .value = TVC_PADS_ENABLE, + }, + { + .name = "tvcclkgrp", + .pins = tvc_clk_3516_pins, + .num_pins = ARRAY_SIZE(tvc_clk_3516_pins), + .value = TVC_CLK_PAD_ENABLE, }, /* * The construction is done such that it is possible to use a serial @@ -1873,6 +1894,13 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = { .value = PFLASH_PADS_DISABLE | NAND_PADS_DISABLE, }, { + .name = "gpio0lgrp", + .pins = gpio0l_3516_pins, + .num_pins = ARRAY_SIZE(gpio0l_3516_pins), + /* Conflict with TVE CLK */ + .mask = TVC_CLK_PAD_ENABLE, + }, + { .name = "gpio1agrp", .pins = gpio1a_3516_pins, .num_pins = ARRAY_SIZE(gpio1a_3516_pins), @@ -2179,12 +2207,13 @@ static int gemini_pmx_set_mux(struct pinctrl_dev *pctldev, return -ENODEV; } - dev_info(pmx->dev, - "ACTIVATE function \"%s\" with group \"%s\"\n", - func->name, grp->name); + dev_dbg(pmx->dev, + "ACTIVATE function \"%s\" with group \"%s\"\n", + func->name, grp->name); regmap_read(pmx->map, GLOBAL_MISC_CTRL, &before); - regmap_update_bits(pmx->map, GLOBAL_MISC_CTRL, grp->mask, + regmap_update_bits(pmx->map, GLOBAL_MISC_CTRL, + grp->mask | grp->value, grp->value); regmap_read(pmx->map, GLOBAL_MISC_CTRL, &after); @@ -2211,10 +2240,10 @@ static int gemini_pmx_set_mux(struct pinctrl_dev *pctldev, "GLOBAL MISC CTRL before: %08x, after %08x, expected %08x\n", before, after, expected); } else { - dev_info(pmx->dev, - "padgroup %s %s\n", - gemini_padgroups[i], - enabled ? "enabled" : "disabled"); + dev_dbg(pmx->dev, + "padgroup %s %s\n", + gemini_padgroups[i], + enabled ? "enabled" : "disabled"); } } @@ -2233,10 +2262,10 @@ static int gemini_pmx_set_mux(struct pinctrl_dev *pctldev, "GLOBAL MISC CTRL before: %08x, after %08x, expected %08x\n", before, after, expected); } else { - dev_info(pmx->dev, - "padgroup %s %s\n", - gemini_padgroups[i], - enabled ? "enabled" : "disabled"); + dev_dbg(pmx->dev, + "padgroup %s %s\n", + gemini_padgroups[i], + enabled ? "enabled" : "disabled"); } } @@ -2463,9 +2492,9 @@ static int gemini_pinconf_group_set(struct pinctrl_dev *pctldev, regmap_update_bits(pmx->map, GLOBAL_IODRIVE, grp->driving_mask, val); - dev_info(pmx->dev, - "set group %s to %d mA drive strength mask %08x val %08x\n", - grp->name, arg, grp->driving_mask, val); + dev_dbg(pmx->dev, + "set group %s to %d mA drive strength mask %08x val %08x\n", + grp->name, arg, grp->driving_mask, val); break; default: dev_err(pmx->dev, "invalid config param %04x\n", param); @@ -2556,8 +2585,8 @@ static int gemini_pmx_probe(struct platform_device *pdev) /* Print initial state */ tmp = val; for_each_set_bit(i, &tmp, PADS_MAXBIT) { - dev_info(dev, "pad group %s %s\n", gemini_padgroups[i], - (val & BIT(i)) ? "enabled" : "disabled"); + dev_dbg(dev, "pad group %s %s\n", gemini_padgroups[i], + (val & BIT(i)) ? "enabled" : "disabled"); } /* Check if flash pin is set */ diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index 628817c40e3b..db6b48ea5f47 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -7,10 +7,11 @@ */ #include <linux/compiler.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> @@ -24,6 +25,9 @@ #include "pinconf.h" #include "pinmux.h" +#define GPIO_PIN 0x00 +#define GPIO_MSK 0x20 + #define JZ4740_GPIO_DATA 0x10 #define JZ4740_GPIO_PULL_DIS 0x30 #define JZ4740_GPIO_FUNC 0x40 @@ -33,7 +37,6 @@ #define JZ4740_GPIO_FLAG 0x80 #define JZ4770_GPIO_INT 0x10 -#define JZ4770_GPIO_MSK 0x20 #define JZ4770_GPIO_PAT1 0x30 #define JZ4770_GPIO_PAT0 0x40 #define JZ4770_GPIO_FLAG 0x50 @@ -46,6 +49,7 @@ enum jz_version { ID_JZ4740, + ID_JZ4725B, ID_JZ4770, ID_JZ4780, }; @@ -72,6 +76,13 @@ struct ingenic_pinctrl { const struct ingenic_chip_info *info; }; +struct ingenic_gpio_chip { + struct ingenic_pinctrl *jzpc; + struct gpio_chip gc; + struct irq_chip irq_chip; + unsigned int irq, reg_base; +}; + static const u32 jz4740_pull_ups[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, }; @@ -205,6 +216,99 @@ static const struct ingenic_chip_info jz4740_chip_info = { .pull_downs = jz4740_pull_downs, }; +static int jz4725b_mmc0_1bit_pins[] = { 0x48, 0x49, 0x5c, }; +static int jz4725b_mmc0_4bit_pins[] = { 0x5d, 0x5b, 0x56, }; +static int jz4725b_mmc1_1bit_pins[] = { 0x7a, 0x7b, 0x7c, }; +static int jz4725b_mmc1_4bit_pins[] = { 0x7d, 0x7e, 0x7f, }; +static int jz4725b_uart_data_pins[] = { 0x4c, 0x4d, }; +static int jz4725b_nand_cs1_pins[] = { 0x55, }; +static int jz4725b_nand_cs2_pins[] = { 0x56, }; +static int jz4725b_nand_cs3_pins[] = { 0x57, }; +static int jz4725b_nand_cs4_pins[] = { 0x58, }; +static int jz4725b_nand_cle_ale_pins[] = { 0x48, 0x49 }; +static int jz4725b_nand_fre_fwe_pins[] = { 0x5c, 0x5d }; +static int jz4725b_pwm_pwm0_pins[] = { 0x4a, }; +static int jz4725b_pwm_pwm1_pins[] = { 0x4b, }; +static int jz4725b_pwm_pwm2_pins[] = { 0x4c, }; +static int jz4725b_pwm_pwm3_pins[] = { 0x4d, }; +static int jz4725b_pwm_pwm4_pins[] = { 0x4e, }; +static int jz4725b_pwm_pwm5_pins[] = { 0x4f, }; + +static int jz4725b_mmc0_1bit_funcs[] = { 1, 1, 1, }; +static int jz4725b_mmc0_4bit_funcs[] = { 1, 0, 1, }; +static int jz4725b_mmc1_1bit_funcs[] = { 0, 0, 0, }; +static int jz4725b_mmc1_4bit_funcs[] = { 0, 0, 0, }; +static int jz4725b_uart_data_funcs[] = { 1, 1, }; +static int jz4725b_nand_cs1_funcs[] = { 0, }; +static int jz4725b_nand_cs2_funcs[] = { 0, }; +static int jz4725b_nand_cs3_funcs[] = { 0, }; +static int jz4725b_nand_cs4_funcs[] = { 0, }; +static int jz4725b_nand_cle_ale_funcs[] = { 0, 0, }; +static int jz4725b_nand_fre_fwe_funcs[] = { 0, 0, }; +static int jz4725b_pwm_pwm0_funcs[] = { 0, }; +static int jz4725b_pwm_pwm1_funcs[] = { 0, }; +static int jz4725b_pwm_pwm2_funcs[] = { 0, }; +static int jz4725b_pwm_pwm3_funcs[] = { 0, }; +static int jz4725b_pwm_pwm4_funcs[] = { 0, }; +static int jz4725b_pwm_pwm5_funcs[] = { 0, }; + +static const struct group_desc jz4725b_groups[] = { + INGENIC_PIN_GROUP("mmc0-1bit", jz4725b_mmc0_1bit), + INGENIC_PIN_GROUP("mmc0-4bit", jz4725b_mmc0_4bit), + INGENIC_PIN_GROUP("mmc1-1bit", jz4725b_mmc1_1bit), + INGENIC_PIN_GROUP("mmc1-4bit", jz4725b_mmc1_4bit), + INGENIC_PIN_GROUP("uart-data", jz4725b_uart_data), + INGENIC_PIN_GROUP("nand-cs1", jz4725b_nand_cs1), + INGENIC_PIN_GROUP("nand-cs2", jz4725b_nand_cs2), + INGENIC_PIN_GROUP("nand-cs3", jz4725b_nand_cs3), + INGENIC_PIN_GROUP("nand-cs4", jz4725b_nand_cs4), + INGENIC_PIN_GROUP("nand-cle-ale", jz4725b_nand_cle_ale), + INGENIC_PIN_GROUP("nand-fre-fwe", jz4725b_nand_fre_fwe), + INGENIC_PIN_GROUP("pwm0", jz4725b_pwm_pwm0), + INGENIC_PIN_GROUP("pwm1", jz4725b_pwm_pwm1), + INGENIC_PIN_GROUP("pwm2", jz4725b_pwm_pwm2), + INGENIC_PIN_GROUP("pwm3", jz4725b_pwm_pwm3), + INGENIC_PIN_GROUP("pwm4", jz4725b_pwm_pwm4), + INGENIC_PIN_GROUP("pwm5", jz4725b_pwm_pwm5), +}; + +static const char *jz4725b_mmc0_groups[] = { "mmc0-1bit", "mmc0-4bit", }; +static const char *jz4725b_mmc1_groups[] = { "mmc1-1bit", "mmc1-4bit", }; +static const char *jz4725b_uart_groups[] = { "uart-data", }; +static const char *jz4725b_nand_groups[] = { + "nand-cs1", "nand-cs2", "nand-cs3", "nand-cs4", + "nand-cle-ale", "nand-fre-fwe", +}; +static const char *jz4725b_pwm0_groups[] = { "pwm0", }; +static const char *jz4725b_pwm1_groups[] = { "pwm1", }; +static const char *jz4725b_pwm2_groups[] = { "pwm2", }; +static const char *jz4725b_pwm3_groups[] = { "pwm3", }; +static const char *jz4725b_pwm4_groups[] = { "pwm4", }; +static const char *jz4725b_pwm5_groups[] = { "pwm5", }; + +static const struct function_desc jz4725b_functions[] = { + { "mmc0", jz4725b_mmc0_groups, ARRAY_SIZE(jz4725b_mmc0_groups), }, + { "mmc1", jz4725b_mmc1_groups, ARRAY_SIZE(jz4725b_mmc1_groups), }, + { "uart", jz4725b_uart_groups, ARRAY_SIZE(jz4725b_uart_groups), }, + { "nand", jz4725b_nand_groups, ARRAY_SIZE(jz4725b_nand_groups), }, + { "pwm0", jz4725b_pwm0_groups, ARRAY_SIZE(jz4725b_pwm0_groups), }, + { "pwm1", jz4725b_pwm1_groups, ARRAY_SIZE(jz4725b_pwm1_groups), }, + { "pwm2", jz4725b_pwm2_groups, ARRAY_SIZE(jz4725b_pwm2_groups), }, + { "pwm3", jz4725b_pwm3_groups, ARRAY_SIZE(jz4725b_pwm3_groups), }, + { "pwm4", jz4725b_pwm4_groups, ARRAY_SIZE(jz4725b_pwm4_groups), }, + { "pwm5", jz4725b_pwm5_groups, ARRAY_SIZE(jz4725b_pwm5_groups), }, +}; + +static const struct ingenic_chip_info jz4725b_chip_info = { + .num_chips = 4, + .groups = jz4725b_groups, + .num_groups = ARRAY_SIZE(jz4725b_groups), + .functions = jz4725b_functions, + .num_functions = ARRAY_SIZE(jz4725b_functions), + .pull_ups = jz4740_pull_ups, + .pull_downs = jz4740_pull_downs, +}; + static const u32 jz4770_pull_ups[6] = { 0x3fffffff, 0xfff0030c, 0xffffffff, 0xffff4fff, 0xfffffb7c, 0xffa7f00f, }; @@ -438,6 +542,235 @@ static const struct ingenic_chip_info jz4770_chip_info = { .pull_downs = jz4770_pull_downs, }; +static u32 gpio_ingenic_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg) +{ + unsigned int val; + + regmap_read(jzgc->jzpc->map, jzgc->reg_base + reg, &val); + + return (u32) val; +} + +static void gpio_ingenic_set_bit(struct ingenic_gpio_chip *jzgc, + u8 reg, u8 offset, bool set) +{ + if (set) + reg = REG_SET(reg); + else + reg = REG_CLEAR(reg); + + regmap_write(jzgc->jzpc->map, jzgc->reg_base + reg, BIT(offset)); +} + +static inline bool ingenic_gpio_get_value(struct ingenic_gpio_chip *jzgc, + u8 offset) +{ + unsigned int val = gpio_ingenic_read_reg(jzgc, GPIO_PIN); + + return !!(val & BIT(offset)); +} + +static void ingenic_gpio_set_value(struct ingenic_gpio_chip *jzgc, + u8 offset, int value) +{ + if (jzgc->jzpc->version >= ID_JZ4770) + gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value); + else + gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value); +} + +static void irq_set_type(struct ingenic_gpio_chip *jzgc, + u8 offset, unsigned int type) +{ + u8 reg1, reg2; + + if (jzgc->jzpc->version >= ID_JZ4770) { + reg1 = JZ4770_GPIO_PAT1; + reg2 = JZ4770_GPIO_PAT0; + } else { + reg1 = JZ4740_GPIO_TRIG; + reg2 = JZ4740_GPIO_DIR; + } + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + gpio_ingenic_set_bit(jzgc, reg2, offset, true); + gpio_ingenic_set_bit(jzgc, reg1, offset, true); + break; + case IRQ_TYPE_EDGE_FALLING: + gpio_ingenic_set_bit(jzgc, reg2, offset, false); + gpio_ingenic_set_bit(jzgc, reg1, offset, true); + break; + case IRQ_TYPE_LEVEL_HIGH: + gpio_ingenic_set_bit(jzgc, reg2, offset, true); + gpio_ingenic_set_bit(jzgc, reg1, offset, false); + break; + case IRQ_TYPE_LEVEL_LOW: + default: + gpio_ingenic_set_bit(jzgc, reg2, offset, false); + gpio_ingenic_set_bit(jzgc, reg1, offset, false); + break; + } +} + +static void ingenic_gpio_irq_mask(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + + gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true); +} + +static void ingenic_gpio_irq_unmask(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + + gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false); +} + +static void ingenic_gpio_irq_enable(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + int irq = irqd->hwirq; + + if (jzgc->jzpc->version >= ID_JZ4770) + gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, true); + else + gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true); + + ingenic_gpio_irq_unmask(irqd); +} + +static void ingenic_gpio_irq_disable(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + int irq = irqd->hwirq; + + ingenic_gpio_irq_mask(irqd); + + if (jzgc->jzpc->version >= ID_JZ4770) + gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, false); + else + gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false); +} + +static void ingenic_gpio_irq_ack(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + int irq = irqd->hwirq; + bool high; + + if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) { + /* + * Switch to an interrupt for the opposite edge to the one that + * triggered the interrupt being ACKed. + */ + high = ingenic_gpio_get_value(jzgc, irq); + if (high) + irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING); + else + irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING); + } + + if (jzgc->jzpc->version >= ID_JZ4770) + gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false); + else + gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true); +} + +static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_EDGE_FALLING: + irq_set_handler_locked(irqd, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + case IRQ_TYPE_LEVEL_LOW: + irq_set_handler_locked(irqd, handle_level_irq); + break; + default: + irq_set_handler_locked(irqd, handle_bad_irq); + } + + if (type == IRQ_TYPE_EDGE_BOTH) { + /* + * The hardware does not support interrupts on both edges. The + * best we can do is to set up a single-edge interrupt and then + * switch to the opposing edge when ACKing the interrupt. + */ + bool high = ingenic_gpio_get_value(jzgc, irqd->hwirq); + + type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING; + } + + irq_set_type(jzgc, irqd->hwirq, type); + return 0; +} + +static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + + return irq_set_irq_wake(jzgc->irq, on); +} + +static void ingenic_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data); + unsigned long flag, i; + + chained_irq_enter(irq_chip, desc); + + if (jzgc->jzpc->version >= ID_JZ4770) + flag = gpio_ingenic_read_reg(jzgc, JZ4770_GPIO_FLAG); + else + flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG); + + for_each_set_bit(i, &flag, 32) + generic_handle_irq(irq_linear_revmap(gc->irq.domain, i)); + chained_irq_exit(irq_chip, desc); +} + +static void ingenic_gpio_set(struct gpio_chip *gc, + unsigned int offset, int value) +{ + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + + ingenic_gpio_set_value(jzgc, offset, value); +} + +static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + + return (int) ingenic_gpio_get_value(jzgc, offset); +} + +static int ingenic_gpio_direction_input(struct gpio_chip *gc, + unsigned int offset) +{ + return pinctrl_gpio_direction_input(gc->base + offset); +} + +static int ingenic_gpio_direction_output(struct gpio_chip *gc, + unsigned int offset, int value) +{ + ingenic_gpio_set(gc, offset, value); + return pinctrl_gpio_direction_output(gc->base + offset); +} + static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc, unsigned int pin, u8 reg, bool set) { @@ -460,6 +793,21 @@ static inline bool ingenic_get_pin_config(struct ingenic_pinctrl *jzpc, return val & BIT(idx); } +static int ingenic_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc); + struct ingenic_pinctrl *jzpc = jzgc->jzpc; + unsigned int pin = gc->base + offset; + + if (jzpc->version >= ID_JZ4770) + return ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PAT1); + + if (ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_SELECT)) + return true; + + return !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_DIR); +} + static const struct pinctrl_ops ingenic_pctlops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, @@ -479,7 +827,7 @@ static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc, if (jzpc->version >= ID_JZ4770) { ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false); - ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, false); + ingenic_config_pin(jzpc, pin, GPIO_MSK, false); ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, func & 0x2); ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT0, func & 0x1); } else { @@ -532,7 +880,7 @@ static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, if (jzpc->version >= ID_JZ4770) { ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false); - ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, true); + ingenic_config_pin(jzpc, pin, GPIO_MSK, true); ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, input); } else { ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false); @@ -712,12 +1060,95 @@ static const struct regmap_config ingenic_pinctrl_regmap_config = { static const struct of_device_id ingenic_pinctrl_of_match[] = { { .compatible = "ingenic,jz4740-pinctrl", .data = (void *) ID_JZ4740 }, + { .compatible = "ingenic,jz4725b-pinctrl", .data = (void *)ID_JZ4725B }, { .compatible = "ingenic,jz4770-pinctrl", .data = (void *) ID_JZ4770 }, { .compatible = "ingenic,jz4780-pinctrl", .data = (void *) ID_JZ4780 }, {}, }; -static int ingenic_pinctrl_probe(struct platform_device *pdev) +static const struct of_device_id ingenic_gpio_of_match[] __initconst = { + { .compatible = "ingenic,jz4740-gpio", }, + { .compatible = "ingenic,jz4770-gpio", }, + { .compatible = "ingenic,jz4780-gpio", }, + {}, +}; + +static int __init ingenic_gpio_probe(struct ingenic_pinctrl *jzpc, + struct device_node *node) +{ + struct ingenic_gpio_chip *jzgc; + struct device *dev = jzpc->dev; + unsigned int bank; + int err; + + err = of_property_read_u32(node, "reg", &bank); + if (err) { + dev_err(dev, "Cannot read \"reg\" property: %i\n", err); + return err; + } + + jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL); + if (!jzgc) + return -ENOMEM; + + jzgc->jzpc = jzpc; + jzgc->reg_base = bank * 0x100; + + jzgc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "GPIO%c", 'A' + bank); + if (!jzgc->gc.label) + return -ENOMEM; + + /* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY + * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN + * <linux/gpio/consumer.h> INSTEAD. + */ + jzgc->gc.base = bank * 32; + + jzgc->gc.ngpio = 32; + jzgc->gc.parent = dev; + jzgc->gc.of_node = node; + jzgc->gc.owner = THIS_MODULE; + + jzgc->gc.set = ingenic_gpio_set; + jzgc->gc.get = ingenic_gpio_get; + jzgc->gc.direction_input = ingenic_gpio_direction_input; + jzgc->gc.direction_output = ingenic_gpio_direction_output; + jzgc->gc.get_direction = ingenic_gpio_get_direction; + + if (of_property_read_bool(node, "gpio-ranges")) { + jzgc->gc.request = gpiochip_generic_request; + jzgc->gc.free = gpiochip_generic_free; + } + + err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc); + if (err) + return err; + + jzgc->irq = irq_of_parse_and_map(node, 0); + if (!jzgc->irq) + return -EINVAL; + + jzgc->irq_chip.name = jzgc->gc.label; + jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable; + jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable; + jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask; + jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask; + jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack; + jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type; + jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake; + jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND; + + err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0, + handle_level_irq, IRQ_TYPE_NONE); + if (err) + return err; + + gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip, + jzgc->irq, ingenic_gpio_irq_handler); + return 0; +} + +static int __init ingenic_pinctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ingenic_pinctrl *jzpc; @@ -727,6 +1158,7 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev) const struct of_device_id *of_id = of_match_device( ingenic_pinctrl_of_match, dev); const struct ingenic_chip_info *chip_info; + struct device_node *node; unsigned int i; int err; @@ -755,6 +1187,8 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev) if (jzpc->version >= ID_JZ4770) chip_info = &jz4770_chip_info; + else if (jzpc->version >= ID_JZ4725B) + chip_info = &jz4725b_chip_info; else chip_info = &jz4740_chip_info; jzpc->info = chip_info; @@ -815,11 +1249,11 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev) dev_set_drvdata(dev, jzpc->map); - if (dev->of_node) { - err = of_platform_populate(dev->of_node, NULL, NULL, dev); - if (err) { - dev_err(dev, "Failed to probe GPIO devices\n"); - return err; + for_each_child_of_node(dev->of_node, node) { + if (of_match_node(ingenic_gpio_of_match, node)) { + err = ingenic_gpio_probe(jzpc, node); + if (err) + return err; } } @@ -828,6 +1262,7 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev) static const struct platform_device_id ingenic_pinctrl_ids[] = { { "jz4740-pinctrl", ID_JZ4740 }, + { "jz4725b-pinctrl", ID_JZ4725B }, { "jz4770-pinctrl", ID_JZ4770 }, { "jz4780-pinctrl", ID_JZ4780 }, {}, @@ -837,14 +1272,13 @@ static struct platform_driver ingenic_pinctrl_driver = { .driver = { .name = "pinctrl-ingenic", .of_match_table = of_match_ptr(ingenic_pinctrl_of_match), - .suppress_bind_attrs = true, }, - .probe = ingenic_pinctrl_probe, .id_table = ingenic_pinctrl_ids, }; static int __init ingenic_pinctrl_drv_register(void) { - return platform_driver_register(&ingenic_pinctrl_driver); + return platform_driver_probe(&ingenic_pinctrl_driver, + ingenic_pinctrl_probe); } -postcore_initcall(ingenic_pinctrl_drv_register); +subsys_initcall(ingenic_pinctrl_drv_register); diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c index 81632af3a86a..22e80613e269 100644 --- a/drivers/pinctrl/pinctrl-lantiq.c +++ b/drivers/pinctrl/pinctrl-lantiq.c @@ -80,14 +80,14 @@ static void ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, int ret, i; if (!pins && !groups) { - dev_err(pctldev->dev, "%s defines neither pins nor groups\n", - np->name); + dev_err(pctldev->dev, "%pOFn defines neither pins nor groups\n", + np); return; } if (pins && groups) { - dev_err(pctldev->dev, "%s defines both pins and groups\n", - np->name); + dev_err(pctldev->dev, "%pOFn defines both pins and groups\n", + np); return; } diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c index 190f17e4bbda..a14bc5e5fc24 100644 --- a/drivers/pinctrl/pinctrl-lpc18xx.c +++ b/drivers/pinctrl/pinctrl-lpc18xx.c @@ -844,8 +844,11 @@ static int lpc18xx_pconf_get_pin(struct pinctrl_dev *pctldev, unsigned param, *arg = (reg & LPC18XX_SCU_PIN_EHD_MASK) >> LPC18XX_SCU_PIN_EHD_POS; switch (*arg) { case 3: *arg += 5; + /* fall through */ case 2: *arg += 5; + /* fall through */ case 1: *arg += 3; + /* fall through */ case 0: *arg += 4; } break; @@ -1060,8 +1063,11 @@ static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev, unsigned param, switch (param_val) { case 20: param_val -= 5; + /* fall through */ case 14: param_val -= 5; + /* fall through */ case 8: param_val -= 3; + /* fall through */ case 4: param_val -= 4; break; default: diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index cf73a403d22d..b03481ef99a1 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -4,7 +4,7 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/spi/spi.h> #include <linux/spi/mcp23s08.h> diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c index 302190d1558d..aa5f949ef219 100644 --- a/drivers/pinctrl/pinctrl-pistachio.c +++ b/drivers/pinctrl/pinctrl-pistachio.c @@ -9,7 +9,6 @@ * version 2, as published by the Free Software Foundation. */ -#include <linux/gpio.h> #include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/io.h> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index f4a61429e06e..95e4a06de019 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -27,7 +27,7 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/bitops.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/pinctrl/machine.h> @@ -501,8 +501,8 @@ static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev, */ grp = pinctrl_name_to_group(info, np->name); if (!grp) { - dev_err(info->dev, "unable to find group for node %s\n", - np->name); + dev_err(info->dev, "unable to find group for node %pOFn\n", + np); return -EINVAL; } @@ -2454,7 +2454,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, int i, j; int ret; - dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + dev_dbg(info->dev, "group(%d): %pOFn\n", index, np); /* Initialise group */ grp->name = np->name; @@ -2519,7 +2519,7 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np, static u32 grp_index; u32 i = 0; - dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np); func = &info->functions[index]; diff --git a/drivers/pinctrl/pinctrl-rza1.c b/drivers/pinctrl/pinctrl-rza1.c index f76edf664539..14eb576c04a2 100644 --- a/drivers/pinctrl/pinctrl-rza1.c +++ b/drivers/pinctrl/pinctrl-rza1.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Combined GPIO and pin controller support for Renesas RZ/A1 (r7s72100) SoC * * Copyright (C) 2017 Jacopo Mondi - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ /* @@ -930,8 +927,8 @@ static int rza1_parse_pinmux_node(struct rza1_pinctrl *rza1_pctl, &npin_configs); if (ret) { dev_err(rza1_pctl->dev, - "Unable to parse pin configuration options for %s\n", - np->name); + "Unable to parse pin configuration options for %pOFn\n", + np); return ret; } @@ -1226,8 +1223,8 @@ static int rza1_parse_gpiochip(struct rza1_pinctrl *rza1_pctl, *chip = rza1_gpiochip_template; chip->base = -1; - chip->label = devm_kasprintf(rza1_pctl->dev, GFP_KERNEL, "%s", - np->name); + chip->label = devm_kasprintf(rza1_pctl->dev, GFP_KERNEL, "%pOFn", + np); chip->ngpio = of_args.args[2]; chip->of_node = np; chip->parent = rza1_pctl->dev; @@ -1287,7 +1284,7 @@ static int rza1_gpio_register(struct rza1_pinctrl *rza1_pctl) ret = rza1_parse_gpiochip(rza1_pctl, child, &gpio_chips[i], &gpio_ranges[i]); if (ret) - goto gpiochip_remove; + return ret; ++i; } @@ -1295,12 +1292,6 @@ static int rza1_gpio_register(struct rza1_pinctrl *rza1_pctl) dev_info(rza1_pctl->dev, "Registered %u gpio controllers\n", i); return 0; - -gpiochip_remove: - for (; i > 0; i--) - devm_gpiochip_remove(rza1_pctl->dev, &gpio_chips[i - 1]); - - return ret; } /** diff --git a/drivers/pinctrl/pinctrl-rzn1.c b/drivers/pinctrl/pinctrl-rzn1.c new file mode 100644 index 000000000000..57886dcff53d --- /dev/null +++ b/drivers/pinctrl/pinctrl-rzn1.c @@ -0,0 +1,947 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2014-2018 Renesas Electronics Europe Limited + * + * Phil Edworthy <phil.edworthy@renesas.com> + * Based on a driver originally written by Michel Pollet at Renesas. + */ + +#include <dt-bindings/pinctrl/rzn1-pinctrl.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include "core.h" +#include "pinconf.h" +#include "pinctrl-utils.h" + +/* Field positions and masks in the pinmux registers */ +#define RZN1_L1_PIN_DRIVE_STRENGTH 10 +#define RZN1_L1_PIN_DRIVE_STRENGTH_4MA 0 +#define RZN1_L1_PIN_DRIVE_STRENGTH_6MA 1 +#define RZN1_L1_PIN_DRIVE_STRENGTH_8MA 2 +#define RZN1_L1_PIN_DRIVE_STRENGTH_12MA 3 +#define RZN1_L1_PIN_PULL 8 +#define RZN1_L1_PIN_PULL_NONE 0 +#define RZN1_L1_PIN_PULL_UP 1 +#define RZN1_L1_PIN_PULL_DOWN 3 +#define RZN1_L1_FUNCTION 0 +#define RZN1_L1_FUNC_MASK 0xf +#define RZN1_L1_FUNCTION_L2 0xf + +/* + * The hardware manual describes two levels of multiplexing, but it's more + * logical to think of the hardware as three levels, with level 3 consisting of + * the multiplexing for Ethernet MDIO signals. + * + * Level 1 functions go from 0 to 9, with level 1 function '15' (0xf) specifying + * that level 2 functions are used instead. Level 2 has a lot more options, + * going from 0 to 61. Level 3 allows selection of MDIO functions which can be + * floating, or one of seven internal peripherals. Unfortunately, there are two + * level 2 functions that can select MDIO, and two MDIO channels so we have four + * sets of level 3 functions. + * + * For this driver, we've compounded the numbers together, so: + * 0 to 9 is level 1 + * 10 to 71 is 10 + level 2 number + * 72 to 79 is 72 + MDIO0 source for level 2 MDIO function. + * 80 to 87 is 80 + MDIO0 source for level 2 MDIO_E1 function. + * 88 to 95 is 88 + MDIO1 source for level 2 MDIO function. + * 96 to 103 is 96 + MDIO1 source for level 2 MDIO_E1 function. + * Examples: + * Function 28 corresponds UART0 + * Function 73 corresponds to MDIO0 to GMAC0 + * + * There are 170 configurable pins (called PL_GPIO in the datasheet). + */ + +/* + * Structure detailing the HW registers on the RZ/N1 devices. + * Both the Level 1 mux registers and Level 2 mux registers have the same + * structure. The only difference is that Level 2 has additional MDIO registers + * at the end. + */ +struct rzn1_pinctrl_regs { + u32 conf[170]; + u32 pad0[86]; + u32 status_protect; /* 0x400 */ + /* MDIO mux registers, level2 only */ + u32 l2_mdio[2]; +}; + +/** + * struct rzn1_pmx_func - describes rzn1 pinmux functions + * @name: the name of this specific function + * @groups: corresponding pin groups + * @num_groups: the number of groups + */ +struct rzn1_pmx_func { + const char *name; + const char **groups; + unsigned int num_groups; +}; + +/** + * struct rzn1_pin_group - describes an rzn1 pin group + * @name: the name of this specific pin group + * @func: the name of the function selected by this group + * @npins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + * @pins: array of pins. Needed due to pinctrl_ops.get_group_pins() + * @pin_ids: array of pin_ids, i.e. the value used to select the mux + */ +struct rzn1_pin_group { + const char *name; + const char *func; + unsigned int npins; + unsigned int *pins; + u8 *pin_ids; +}; + +struct rzn1_pinctrl { + struct device *dev; + struct clk *clk; + struct pinctrl_dev *pctl; + struct rzn1_pinctrl_regs __iomem *lev1; + struct rzn1_pinctrl_regs __iomem *lev2; + u32 lev1_protect_phys; + u32 lev2_protect_phys; + u32 mdio_func[2]; + + struct rzn1_pin_group *groups; + unsigned int ngroups; + + struct rzn1_pmx_func *functions; + unsigned int nfunctions; +}; + +#define RZN1_PINS_PROP "pinmux" + +#define RZN1_PIN(pin) PINCTRL_PIN(pin, "pl_gpio"#pin) + +static const struct pinctrl_pin_desc rzn1_pins[] = { + RZN1_PIN(0), RZN1_PIN(1), RZN1_PIN(2), RZN1_PIN(3), RZN1_PIN(4), + RZN1_PIN(5), RZN1_PIN(6), RZN1_PIN(7), RZN1_PIN(8), RZN1_PIN(9), + RZN1_PIN(10), RZN1_PIN(11), RZN1_PIN(12), RZN1_PIN(13), RZN1_PIN(14), + RZN1_PIN(15), RZN1_PIN(16), RZN1_PIN(17), RZN1_PIN(18), RZN1_PIN(19), + RZN1_PIN(20), RZN1_PIN(21), RZN1_PIN(22), RZN1_PIN(23), RZN1_PIN(24), + RZN1_PIN(25), RZN1_PIN(26), RZN1_PIN(27), RZN1_PIN(28), RZN1_PIN(29), + RZN1_PIN(30), RZN1_PIN(31), RZN1_PIN(32), RZN1_PIN(33), RZN1_PIN(34), + RZN1_PIN(35), RZN1_PIN(36), RZN1_PIN(37), RZN1_PIN(38), RZN1_PIN(39), + RZN1_PIN(40), RZN1_PIN(41), RZN1_PIN(42), RZN1_PIN(43), RZN1_PIN(44), + RZN1_PIN(45), RZN1_PIN(46), RZN1_PIN(47), RZN1_PIN(48), RZN1_PIN(49), + RZN1_PIN(50), RZN1_PIN(51), RZN1_PIN(52), RZN1_PIN(53), RZN1_PIN(54), + RZN1_PIN(55), RZN1_PIN(56), RZN1_PIN(57), RZN1_PIN(58), RZN1_PIN(59), + RZN1_PIN(60), RZN1_PIN(61), RZN1_PIN(62), RZN1_PIN(63), RZN1_PIN(64), + RZN1_PIN(65), RZN1_PIN(66), RZN1_PIN(67), RZN1_PIN(68), RZN1_PIN(69), + RZN1_PIN(70), RZN1_PIN(71), RZN1_PIN(72), RZN1_PIN(73), RZN1_PIN(74), + RZN1_PIN(75), RZN1_PIN(76), RZN1_PIN(77), RZN1_PIN(78), RZN1_PIN(79), + RZN1_PIN(80), RZN1_PIN(81), RZN1_PIN(82), RZN1_PIN(83), RZN1_PIN(84), + RZN1_PIN(85), RZN1_PIN(86), RZN1_PIN(87), RZN1_PIN(88), RZN1_PIN(89), + RZN1_PIN(90), RZN1_PIN(91), RZN1_PIN(92), RZN1_PIN(93), RZN1_PIN(94), + RZN1_PIN(95), RZN1_PIN(96), RZN1_PIN(97), RZN1_PIN(98), RZN1_PIN(99), + RZN1_PIN(100), RZN1_PIN(101), RZN1_PIN(102), RZN1_PIN(103), + RZN1_PIN(104), RZN1_PIN(105), RZN1_PIN(106), RZN1_PIN(107), + RZN1_PIN(108), RZN1_PIN(109), RZN1_PIN(110), RZN1_PIN(111), + RZN1_PIN(112), RZN1_PIN(113), RZN1_PIN(114), RZN1_PIN(115), + RZN1_PIN(116), RZN1_PIN(117), RZN1_PIN(118), RZN1_PIN(119), + RZN1_PIN(120), RZN1_PIN(121), RZN1_PIN(122), RZN1_PIN(123), + RZN1_PIN(124), RZN1_PIN(125), RZN1_PIN(126), RZN1_PIN(127), + RZN1_PIN(128), RZN1_PIN(129), RZN1_PIN(130), RZN1_PIN(131), + RZN1_PIN(132), RZN1_PIN(133), RZN1_PIN(134), RZN1_PIN(135), + RZN1_PIN(136), RZN1_PIN(137), RZN1_PIN(138), RZN1_PIN(139), + RZN1_PIN(140), RZN1_PIN(141), RZN1_PIN(142), RZN1_PIN(143), + RZN1_PIN(144), RZN1_PIN(145), RZN1_PIN(146), RZN1_PIN(147), + RZN1_PIN(148), RZN1_PIN(149), RZN1_PIN(150), RZN1_PIN(151), + RZN1_PIN(152), RZN1_PIN(153), RZN1_PIN(154), RZN1_PIN(155), + RZN1_PIN(156), RZN1_PIN(157), RZN1_PIN(158), RZN1_PIN(159), + RZN1_PIN(160), RZN1_PIN(161), RZN1_PIN(162), RZN1_PIN(163), + RZN1_PIN(164), RZN1_PIN(165), RZN1_PIN(166), RZN1_PIN(167), + RZN1_PIN(168), RZN1_PIN(169), +}; + +enum { + LOCK_LEVEL1 = 0x1, + LOCK_LEVEL2 = 0x2, + LOCK_ALL = LOCK_LEVEL1 | LOCK_LEVEL2, +}; + +static void rzn1_hw_set_lock(struct rzn1_pinctrl *ipctl, u8 lock, u8 value) +{ + /* + * The pinmux configuration is locked by writing the physical address of + * the status_protect register to itself. It is unlocked by writing the + * address | 1. + */ + if (lock & LOCK_LEVEL1) { + u32 val = ipctl->lev1_protect_phys | !(value & LOCK_LEVEL1); + + writel(val, &ipctl->lev1->status_protect); + } + + if (lock & LOCK_LEVEL2) { + u32 val = ipctl->lev2_protect_phys | !(value & LOCK_LEVEL2); + + writel(val, &ipctl->lev2->status_protect); + } +} + +static void rzn1_pinctrl_mdio_select(struct rzn1_pinctrl *ipctl, int mdio, + u32 func) +{ + if (ipctl->mdio_func[mdio] >= 0 && ipctl->mdio_func[mdio] != func) + dev_warn(ipctl->dev, "conflicting setting for mdio%d!\n", mdio); + ipctl->mdio_func[mdio] = func; + + dev_dbg(ipctl->dev, "setting mdio%d to %u\n", mdio, func); + + writel(func, &ipctl->lev2->l2_mdio[mdio]); +} + +/* + * Using a composite pin description, set the hardware pinmux registers + * with the corresponding values. + * Make sure to unlock write protection and reset it afterward. + * + * NOTE: There is no protection for potential concurrency, it is assumed these + * calls are serialized already. + */ +static int rzn1_set_hw_pin_func(struct rzn1_pinctrl *ipctl, unsigned int pin, + u32 pin_config, u8 use_locks) +{ + u32 l1_cache; + u32 l2_cache; + u32 l1; + u32 l2; + + /* Level 3 MDIO multiplexing */ + if (pin_config >= RZN1_FUNC_MDIO0_HIGHZ && + pin_config <= RZN1_FUNC_MDIO1_E1_SWITCH) { + int mdio_channel; + u32 mdio_func; + + if (pin_config <= RZN1_FUNC_MDIO1_HIGHZ) + mdio_channel = 0; + else + mdio_channel = 1; + + /* Get MDIO func, and convert the func to the level 2 number */ + if (pin_config <= RZN1_FUNC_MDIO0_SWITCH) { + mdio_func = pin_config - RZN1_FUNC_MDIO0_HIGHZ; + pin_config = RZN1_FUNC_ETH_MDIO; + } else if (pin_config <= RZN1_FUNC_MDIO0_E1_SWITCH) { + mdio_func = pin_config - RZN1_FUNC_MDIO0_E1_HIGHZ; + pin_config = RZN1_FUNC_ETH_MDIO_E1; + } else if (pin_config <= RZN1_FUNC_MDIO1_SWITCH) { + mdio_func = pin_config - RZN1_FUNC_MDIO1_HIGHZ; + pin_config = RZN1_FUNC_ETH_MDIO; + } else { + mdio_func = pin_config - RZN1_FUNC_MDIO1_E1_HIGHZ; + pin_config = RZN1_FUNC_ETH_MDIO_E1; + } + rzn1_pinctrl_mdio_select(ipctl, mdio_channel, mdio_func); + } + + /* Note here, we do not allow anything past the MDIO Mux values */ + if (pin >= ARRAY_SIZE(ipctl->lev1->conf) || + pin_config >= RZN1_FUNC_MDIO0_HIGHZ) + return -EINVAL; + + l1 = readl(&ipctl->lev1->conf[pin]); + l1_cache = l1; + l2 = readl(&ipctl->lev2->conf[pin]); + l2_cache = l2; + + dev_dbg(ipctl->dev, "setting func for pin %u to %u\n", pin, pin_config); + + l1 &= ~(RZN1_L1_FUNC_MASK << RZN1_L1_FUNCTION); + + if (pin_config < RZN1_FUNC_L2_OFFSET) { + l1 |= (pin_config << RZN1_L1_FUNCTION); + } else { + l1 |= (RZN1_L1_FUNCTION_L2 << RZN1_L1_FUNCTION); + + l2 = pin_config - RZN1_FUNC_L2_OFFSET; + } + + /* If either configuration changes, we update both anyway */ + if (l1 != l1_cache || l2 != l2_cache) { + writel(l1, &ipctl->lev1->conf[pin]); + writel(l2, &ipctl->lev2->conf[pin]); + } + + return 0; +} + +static const struct rzn1_pin_group *rzn1_pinctrl_find_group_by_name( + const struct rzn1_pinctrl *ipctl, const char *name) +{ + unsigned int i; + + for (i = 0; i < ipctl->ngroups; i++) { + if (!strcmp(ipctl->groups[i].name, name)) + return &ipctl->groups[i]; + } + + return NULL; +} + +static int rzn1_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + return ipctl->ngroups; +} + +static const char *rzn1_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + return ipctl->groups[selector].name; +} + +static int rzn1_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, const unsigned int **pins, + unsigned int *npins) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= ipctl->ngroups) + return -EINVAL; + + *pins = ipctl->groups[selector].pins; + *npins = ipctl->groups[selector].npins; + + return 0; +} + +/* + * This function is called for each pinctl 'Function' node. + * Sub-nodes can be used to describe multiple 'Groups' for the 'Function' + * If there aren't any sub-nodes, the 'Group' is essentially the 'Function'. + * Each 'Group' uses pinmux = <...> to detail the pins and data used to select + * the functionality. Each 'Group' has optional pin configurations that apply + * to all pins in the 'Group'. + */ +static int rzn1_dt_node_to_map_one(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct rzn1_pin_group *grp; + unsigned long *configs = NULL; + unsigned int reserved_maps = *num_maps; + unsigned int num_configs = 0; + unsigned int reserve = 1; + int ret; + + dev_dbg(ipctl->dev, "processing node %pOF\n", np); + + grp = rzn1_pinctrl_find_group_by_name(ipctl, np->name); + if (!grp) { + dev_err(ipctl->dev, "unable to find group for node %pOF\n", np); + + return -EINVAL; + } + + /* Get the group's pin configuration */ + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); + if (ret < 0) { + dev_err(ipctl->dev, "%pOF: could not parse property\n", np); + + return ret; + } + + if (num_configs) + reserve++; + + /* Increase the number of maps to cover this group */ + ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, num_maps, + reserve); + if (ret < 0) + goto out; + + /* Associate the group with the function */ + ret = pinctrl_utils_add_map_mux(pctldev, map, &reserved_maps, num_maps, + grp->name, grp->func); + if (ret < 0) + goto out; + + if (num_configs) { + /* Associate the group's pin configuration with the group */ + ret = pinctrl_utils_add_map_configs(pctldev, map, + &reserved_maps, num_maps, grp->name, + configs, num_configs, + PIN_MAP_TYPE_CONFIGS_GROUP); + if (ret < 0) + goto out; + } + + dev_dbg(pctldev->dev, "maps: function %s group %s (%d pins)\n", + grp->func, grp->name, grp->npins); + +out: + kfree(configs); + + return ret; +} + +static int rzn1_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct device_node *child; + int ret; + + *map = NULL; + *num_maps = 0; + + ret = rzn1_dt_node_to_map_one(pctldev, np, map, num_maps); + if (ret < 0) + return ret; + + for_each_child_of_node(np, child) { + ret = rzn1_dt_node_to_map_one(pctldev, child, map, num_maps); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct pinctrl_ops rzn1_pctrl_ops = { + .get_groups_count = rzn1_get_groups_count, + .get_group_name = rzn1_get_group_name, + .get_group_pins = rzn1_get_group_pins, + .dt_node_to_map = rzn1_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; + +static int rzn1_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + return ipctl->nfunctions; +} + +static const char *rzn1_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + return ipctl->functions[selector].name; +} + +static int rzn1_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + *groups = ipctl->functions[selector].groups; + *num_groups = ipctl->functions[selector].num_groups; + + return 0; +} + +static int rzn1_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, + unsigned int group) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + struct rzn1_pin_group *grp = &ipctl->groups[group]; + unsigned int i, grp_pins = grp->npins; + + dev_dbg(ipctl->dev, "set mux %s(%d) group %s(%d)\n", + ipctl->functions[selector].name, selector, grp->name, group); + + rzn1_hw_set_lock(ipctl, LOCK_ALL, LOCK_ALL); + for (i = 0; i < grp_pins; i++) + rzn1_set_hw_pin_func(ipctl, grp->pins[i], grp->pin_ids[i], 0); + rzn1_hw_set_lock(ipctl, LOCK_ALL, 0); + + return 0; +} + +static const struct pinmux_ops rzn1_pmx_ops = { + .get_functions_count = rzn1_pmx_get_funcs_count, + .get_function_name = rzn1_pmx_get_func_name, + .get_function_groups = rzn1_pmx_get_groups, + .set_mux = rzn1_set_mux, +}; + +static int rzn1_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + const u32 reg_drive[4] = { 4, 6, 8, 12 }; + u32 pull, drive, l1mux; + u32 l1, l2, arg = 0; + + if (pin >= ARRAY_SIZE(ipctl->lev1->conf)) + return -EINVAL; + + l1 = readl(&ipctl->lev1->conf[pin]); + + l1mux = l1 & RZN1_L1_FUNC_MASK; + pull = (l1 >> RZN1_L1_PIN_PULL) & 0x3; + drive = (l1 >> RZN1_L1_PIN_DRIVE_STRENGTH) & 0x3; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + if (pull != RZN1_L1_PIN_PULL_UP) + return -EINVAL; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (pull != RZN1_L1_PIN_PULL_DOWN) + return -EINVAL; + break; + case PIN_CONFIG_BIAS_DISABLE: + if (pull != RZN1_L1_PIN_PULL_NONE) + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = reg_drive[drive]; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + l2 = readl(&ipctl->lev2->conf[pin]); + if (l1mux == RZN1_L1_FUNCTION_L2) { + if (l2 != 0) + return -EINVAL; + } else if (l1mux != RZN1_FUNC_HIGHZ) { + return -EINVAL; + } + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int rzn1_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param; + unsigned int i; + u32 l1, l1_cache; + u32 drv; + u32 arg; + + if (pin >= ARRAY_SIZE(ipctl->lev1->conf)) + return -EINVAL; + + l1 = readl(&ipctl->lev1->conf[pin]); + l1_cache = l1; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + dev_dbg(ipctl->dev, "set pin %d pull up\n", pin); + l1 &= ~(0x3 << RZN1_L1_PIN_PULL); + l1 |= (RZN1_L1_PIN_PULL_UP << RZN1_L1_PIN_PULL); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + dev_dbg(ipctl->dev, "set pin %d pull down\n", pin); + l1 &= ~(0x3 << RZN1_L1_PIN_PULL); + l1 |= (RZN1_L1_PIN_PULL_DOWN << RZN1_L1_PIN_PULL); + break; + case PIN_CONFIG_BIAS_DISABLE: + dev_dbg(ipctl->dev, "set pin %d bias off\n", pin); + l1 &= ~(0x3 << RZN1_L1_PIN_PULL); + l1 |= (RZN1_L1_PIN_PULL_NONE << RZN1_L1_PIN_PULL); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + dev_dbg(ipctl->dev, "set pin %d drv %umA\n", pin, arg); + switch (arg) { + case 4: + drv = RZN1_L1_PIN_DRIVE_STRENGTH_4MA; + break; + case 6: + drv = RZN1_L1_PIN_DRIVE_STRENGTH_6MA; + break; + case 8: + drv = RZN1_L1_PIN_DRIVE_STRENGTH_8MA; + break; + case 12: + drv = RZN1_L1_PIN_DRIVE_STRENGTH_12MA; + break; + default: + dev_err(ipctl->dev, + "Drive strength %umA not supported\n", + arg); + + return -EINVAL; + } + + l1 &= ~(0x3 << RZN1_L1_PIN_DRIVE_STRENGTH); + l1 |= (drv << RZN1_L1_PIN_DRIVE_STRENGTH); + break; + + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + dev_dbg(ipctl->dev, "set pin %d High-Z\n", pin); + l1 &= ~RZN1_L1_FUNC_MASK; + l1 |= RZN1_FUNC_HIGHZ; + break; + default: + return -ENOTSUPP; + } + } + + if (l1 != l1_cache) { + rzn1_hw_set_lock(ipctl, LOCK_LEVEL1, LOCK_LEVEL1); + writel(l1, &ipctl->lev1->conf[pin]); + rzn1_hw_set_lock(ipctl, LOCK_LEVEL1, 0); + } + + return 0; +} + +static int rzn1_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *config) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + struct rzn1_pin_group *grp = &ipctl->groups[selector]; + unsigned long old = 0; + unsigned int i; + + dev_dbg(ipctl->dev, "group get %s selector:%u\n", grp->name, selector); + + for (i = 0; i < grp->npins; i++) { + if (rzn1_pinconf_get(pctldev, grp->pins[i], config)) + return -ENOTSUPP; + + /* configs do not match between two pins */ + if (i && (old != *config)) + return -ENOTSUPP; + + old = *config; + } + + return 0; +} + +static int rzn1_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + struct rzn1_pin_group *grp = &ipctl->groups[selector]; + unsigned int i; + int ret; + + dev_dbg(ipctl->dev, "group set %s selector:%u configs:%p/%d\n", + grp->name, selector, configs, num_configs); + + for (i = 0; i < grp->npins; i++) { + unsigned int pin = grp->pins[i]; + + ret = rzn1_pinconf_set(pctldev, pin, configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops rzn1_pinconf_ops = { + .is_generic = true, + .pin_config_get = rzn1_pinconf_get, + .pin_config_set = rzn1_pinconf_set, + .pin_config_group_get = rzn1_pinconf_group_get, + .pin_config_group_set = rzn1_pinconf_group_set, + .pin_config_config_dbg_show = pinconf_generic_dump_config, +}; + +static struct pinctrl_desc rzn1_pinctrl_desc = { + .pctlops = &rzn1_pctrl_ops, + .pmxops = &rzn1_pmx_ops, + .confops = &rzn1_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int rzn1_pinctrl_parse_groups(struct device_node *np, + struct rzn1_pin_group *grp, + struct rzn1_pinctrl *ipctl) +{ + const __be32 *list; + unsigned int i; + int size; + + dev_dbg(ipctl->dev, "%s: %s\n", __func__, np->name); + + /* Initialise group */ + grp->name = np->name; + + /* + * The binding format is + * pinmux = <PIN_FUNC_ID CONFIG ...>, + * do sanity check and calculate pins number + */ + list = of_get_property(np, RZN1_PINS_PROP, &size); + if (!list) { + dev_err(ipctl->dev, + "no " RZN1_PINS_PROP " property in node %pOF\n", np); + + return -EINVAL; + } + + if (!size) { + dev_err(ipctl->dev, "Invalid " RZN1_PINS_PROP " in node %pOF\n", + np); + + return -EINVAL; + } + + grp->npins = size / sizeof(list[0]); + grp->pin_ids = devm_kmalloc_array(ipctl->dev, + grp->npins, sizeof(grp->pin_ids[0]), + GFP_KERNEL); + grp->pins = devm_kmalloc_array(ipctl->dev, + grp->npins, sizeof(grp->pins[0]), + GFP_KERNEL); + if (!grp->pin_ids || !grp->pins) + return -ENOMEM; + + for (i = 0; i < grp->npins; i++) { + u32 pin_id = be32_to_cpu(*list++); + + grp->pins[i] = pin_id & 0xff; + grp->pin_ids[i] = (pin_id >> 8) & 0x7f; + } + + return grp->npins; +} + +static int rzn1_pinctrl_count_function_groups(struct device_node *np) +{ + struct device_node *child; + int count = 0; + + if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0) + count++; + + for_each_child_of_node(np, child) { + if (of_property_count_u32_elems(child, RZN1_PINS_PROP) > 0) + count++; + } + + return count; +} + +static int rzn1_pinctrl_parse_functions(struct device_node *np, + struct rzn1_pinctrl *ipctl, + unsigned int index) +{ + struct rzn1_pmx_func *func; + struct rzn1_pin_group *grp; + struct device_node *child; + unsigned int i = 0; + int ret; + + func = &ipctl->functions[index]; + + /* Initialise function */ + func->name = np->name; + func->num_groups = rzn1_pinctrl_count_function_groups(np); + if (func->num_groups == 0) { + dev_err(ipctl->dev, "no groups defined in %pOF\n", np); + return -EINVAL; + } + dev_dbg(ipctl->dev, "function %s has %d groups\n", + np->name, func->num_groups); + + func->groups = devm_kmalloc_array(ipctl->dev, + func->num_groups, sizeof(char *), + GFP_KERNEL); + if (!func->groups) + return -ENOMEM; + + if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0) { + func->groups[i] = np->name; + grp = &ipctl->groups[ipctl->ngroups]; + grp->func = func->name; + ret = rzn1_pinctrl_parse_groups(np, grp, ipctl); + if (ret < 0) + return ret; + i++; + ipctl->ngroups++; + } + + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &ipctl->groups[ipctl->ngroups]; + grp->func = func->name; + ret = rzn1_pinctrl_parse_groups(child, grp, ipctl); + if (ret < 0) + return ret; + i++; + ipctl->ngroups++; + } + + dev_dbg(ipctl->dev, "function %s parsed %u/%u groups\n", + np->name, i, func->num_groups); + + return 0; +} + +static int rzn1_pinctrl_probe_dt(struct platform_device *pdev, + struct rzn1_pinctrl *ipctl) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + unsigned int maxgroups = 0; + unsigned int nfuncs = 0; + unsigned int i = 0; + int ret; + + nfuncs = of_get_child_count(np); + if (nfuncs <= 0) + return 0; + + ipctl->nfunctions = nfuncs; + ipctl->functions = devm_kmalloc_array(&pdev->dev, nfuncs, + sizeof(*ipctl->functions), + GFP_KERNEL); + if (!ipctl->functions) + return -ENOMEM; + + ipctl->ngroups = 0; + for_each_child_of_node(np, child) + maxgroups += rzn1_pinctrl_count_function_groups(child); + + ipctl->groups = devm_kmalloc_array(&pdev->dev, + maxgroups, + sizeof(*ipctl->groups), + GFP_KERNEL); + if (!ipctl->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + ret = rzn1_pinctrl_parse_functions(child, ipctl, i++); + if (ret < 0) + return ret; + } + + return 0; +} + +static int rzn1_pinctrl_probe(struct platform_device *pdev) +{ + struct rzn1_pinctrl *ipctl; + struct resource *res; + int ret; + + /* Create state holders etc for this driver */ + ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); + if (!ipctl) + return -ENOMEM; + + ipctl->mdio_func[0] = -1; + ipctl->mdio_func[1] = -1; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ipctl->lev1_protect_phys = (u32)res->start + 0x400; + ipctl->lev1 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ipctl->lev1)) + return PTR_ERR(ipctl->lev1); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ipctl->lev2_protect_phys = (u32)res->start + 0x400; + ipctl->lev2 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ipctl->lev2)) + return PTR_ERR(ipctl->lev2); + + ipctl->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ipctl->clk)) + return PTR_ERR(ipctl->clk); + ret = clk_prepare_enable(ipctl->clk); + if (ret) + return ret; + + ipctl->dev = &pdev->dev; + rzn1_pinctrl_desc.name = dev_name(&pdev->dev); + rzn1_pinctrl_desc.pins = rzn1_pins; + rzn1_pinctrl_desc.npins = ARRAY_SIZE(rzn1_pins); + + ret = rzn1_pinctrl_probe_dt(pdev, ipctl); + if (ret) { + dev_err(&pdev->dev, "fail to probe dt properties\n"); + goto err_clk; + } + + platform_set_drvdata(pdev, ipctl); + + ret = devm_pinctrl_register_and_init(&pdev->dev, &rzn1_pinctrl_desc, + ipctl, &ipctl->pctl); + if (ret) { + dev_err(&pdev->dev, "could not register rzn1 pinctrl driver\n"); + goto err_clk; + } + + ret = pinctrl_enable(ipctl->pctl); + if (ret) + goto err_clk; + + dev_info(&pdev->dev, "probed\n"); + + return 0; + +err_clk: + clk_disable_unprepare(ipctl->clk); + + return ret; +} + +static int rzn1_pinctrl_remove(struct platform_device *pdev) +{ + struct rzn1_pinctrl *ipctl = platform_get_drvdata(pdev); + + clk_disable_unprepare(ipctl->clk); + + return 0; +} + +static const struct of_device_id rzn1_pinctrl_match[] = { + { .compatible = "renesas,rzn1-pinctrl", }, + {} +}; +MODULE_DEVICE_TABLE(of, rzn1_pinctrl_match); + +static struct platform_driver rzn1_pinctrl_driver = { + .probe = rzn1_pinctrl_probe, + .remove = rzn1_pinctrl_remove, + .driver = { + .name = "rzn1-pinctrl", + .of_match_table = rzn1_pinctrl_match, + }, +}; + +static int __init _pinctrl_drv_register(void) +{ + return platform_driver_register(&rzn1_pinctrl_driver); +} +subsys_initcall(_pinctrl_drv_register); + +MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>"); +MODULE_DESCRIPTION("Renesas RZ/N1 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 7ec72ff2419a..1e0614daee9b 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1022,14 +1022,14 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, vals[found].reg = pcs->base + offset; vals[found].val = pinctrl_spec.args[1]; - dev_dbg(pcs->dev, "%s index: 0x%x value: 0x%x\n", - pinctrl_spec.np->name, offset, pinctrl_spec.args[1]); + dev_dbg(pcs->dev, "%pOFn index: 0x%x value: 0x%x\n", + pinctrl_spec.np, offset, pinctrl_spec.args[1]); pin = pcs_get_pin_by_offset(pcs, offset); if (pin < 0) { dev_err(pcs->dev, - "could not add functions for %s %ux\n", - np->name, offset); + "could not add functions for %pOFn %ux\n", + np, offset); break; } pins[found++] = pin; @@ -1135,8 +1135,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, val = pinctrl_spec.args[1]; mask = pinctrl_spec.args[2]; - dev_dbg(pcs->dev, "%s index: 0x%x value: 0x%x mask: 0x%x\n", - pinctrl_spec.np->name, offset, val, mask); + dev_dbg(pcs->dev, "%pOFn index: 0x%x value: 0x%x mask: 0x%x\n", + pinctrl_spec.np, offset, val, mask); /* Parse pins in each row from LSB */ while (mask) { @@ -1148,8 +1148,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, if ((mask & mask_pos) == 0) { dev_err(pcs->dev, - "Invalid mask for %s at 0x%x\n", - np->name, offset); + "Invalid mask for %pOFn at 0x%x\n", + np, offset); break; } @@ -1157,8 +1157,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, if (submask != mask_pos) { dev_warn(pcs->dev, - "Invalid submask 0x%x for %s at 0x%x\n", - submask, np->name, offset); + "Invalid submask 0x%x for %pOFn at 0x%x\n", + submask, np, offset); continue; } @@ -1169,8 +1169,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, pin = pcs_get_pin_by_offset(pcs, offset); if (pin < 0) { dev_err(pcs->dev, - "could not add functions for %s %ux\n", - np->name, offset); + "could not add functions for %pOFn %ux\n", + np, offset); break; } pins[found++] = pin + pin_num_from_lsb; @@ -1254,16 +1254,16 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map, num_maps, pgnames); if (ret < 0) { - dev_err(pcs->dev, "no pins entries for %s\n", - np_config->name); + dev_err(pcs->dev, "no pins entries for %pOFn\n", + np_config); goto free_pgnames; } } else { ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps, pgnames); if (ret < 0) { - dev_err(pcs->dev, "no pins entries for %s\n", - np_config->name); + dev_err(pcs->dev, "no pins entries for %pOFn\n", + np_config); goto free_pgnames; } } diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 0966bb0bf71f..e66af93f2cbf 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -817,8 +817,8 @@ static int st_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, grp = st_pctl_find_group_by_name(info, np->name); if (!grp) { - dev_err(info->dev, "unable to find group for node %s\n", - np->name); + dev_err(info->dev, "unable to find group for node %pOFn\n", + np); return -EINVAL; } @@ -1184,7 +1184,7 @@ static int st_pctl_dt_parse_groups(struct device_node *np, if (pp->length / sizeof(__be32) >= OF_GPIO_ARGS_MIN) { npins++; } else { - pr_warn("Invalid st,pins in %s node\n", np->name); + pr_warn("Invalid st,pins in %pOFn node\n", np); return -EINVAL; } } diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 195492033075..836e9f3eae4c 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -114,6 +114,14 @@ config PINCTRL_MSM8998 This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found in the Qualcomm MSM8998 platform. +config PINCTRL_QCS404 + tristate "Qualcomm QCS404 pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + TLMM block found in the Qualcomm QCS404 platform. + config PINCTRL_QDF2XXX tristate "Qualcomm Technologies QDF2xxx pin controller driver" depends on GPIOLIB && ACPI @@ -147,6 +155,15 @@ config PINCTRL_QCOM_SSBI_PMIC which are using SSBI for communication with SoC. Example PMIC's devices are pm8058 and pm8921. +config PINCTRL_SDM660 + tristate "Qualcomm Technologies Inc SDM660 pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm Technologies Inc TLMM block found on the Qualcomm + Technologies Inc SDM660 platform. + config PINCTRL_SDM845 tristate "Qualcomm Technologies Inc SDM845 pin controller driver" depends on GPIOLIB && OF diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 0c6f3ddc296d..344b4c6a6c6e 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -13,10 +13,12 @@ obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o obj-$(CONFIG_PINCTRL_MSM8994) += pinctrl-msm8994.o obj-$(CONFIG_PINCTRL_MSM8996) += pinctrl-msm8996.o obj-$(CONFIG_PINCTRL_MSM8998) += pinctrl-msm8998.o +obj-$(CONFIG_PINCTRL_QCS404) += pinctrl-qcs404.o obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o obj-$(CONFIG_PINCTRL_MDM9615) += pinctrl-mdm9615.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o +obj-$(CONFIG_PINCTRL_SDM660) += pinctrl-sdm660.o obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 5d72ffad32c2..7c7d083e2c0d 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -24,7 +24,7 @@ #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/reboot.h> @@ -37,6 +37,7 @@ #include "../pinctrl-utils.h" #define MAX_NR_GPIO 300 +#define MAX_NR_TILES 4 #define PS_HOLD_OFFSET 0x820 /** @@ -52,7 +53,7 @@ * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge * detection. * @soc; Reference to soc_data of platform specific data. - * @regs: Base address for the TLMM register map. + * @regs: Base addresses for the TLMM tiles. */ struct msm_pinctrl { struct device *dev; @@ -70,9 +71,27 @@ struct msm_pinctrl { DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); const struct msm_pinctrl_soc_data *soc; - void __iomem *regs; + void __iomem *regs[MAX_NR_TILES]; }; +#define MSM_ACCESSOR(name) \ +static u32 msm_readl_##name(struct msm_pinctrl *pctrl, \ + const struct msm_pingroup *g) \ +{ \ + return readl(pctrl->regs[g->tile] + g->name##_reg); \ +} \ +static void msm_writel_##name(u32 val, struct msm_pinctrl *pctrl, \ + const struct msm_pingroup *g) \ +{ \ + writel(val, pctrl->regs[g->tile] + g->name##_reg); \ +} + +MSM_ACCESSOR(ctl) +MSM_ACCESSOR(io) +MSM_ACCESSOR(intr_cfg) +MSM_ACCESSOR(intr_status) +MSM_ACCESSOR(intr_target) + static int msm_get_groups_count(struct pinctrl_dev *pctldev) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -166,21 +185,37 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev, raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->ctl_reg); + val = msm_readl_ctl(pctrl, g); val &= ~mask; val |= i << g->mux_bit; - writel(val, pctrl->regs + g->ctl_reg); + msm_writel_ctl(val, pctrl, g); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } +static int msm_pinmux_request_gpio(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct msm_pingroup *g = &pctrl->soc->groups[offset]; + + /* No funcs? Probably ACPI so can't do anything here */ + if (!g->nfuncs) + return 0; + + /* For now assume function 0 is GPIO because it always is */ + return msm_pinmux_set_mux(pctldev, g->funcs[0], offset); +} + static const struct pinmux_ops msm_pinmux_ops = { .request = msm_pinmux_request, .get_functions_count = msm_get_functions_count, .get_function_name = msm_get_function_name, .get_function_groups = msm_get_function_groups, + .gpio_request_enable = msm_pinmux_request_gpio, .set_mux = msm_pinmux_set_mux, }; @@ -244,7 +279,7 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev, if (ret < 0) return ret; - val = readl(pctrl->regs + g->ctl_reg); + val = msm_readl_ctl(pctrl, g); arg = (val >> bit) & mask; /* Convert register value to pinconf value */ @@ -283,7 +318,7 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev, if (!arg) return -EINVAL; - val = readl(pctrl->regs + g->io_reg); + val = msm_readl_io(pctrl, g); arg = !!(val & BIT(g->in_bit)); break; case PIN_CONFIG_INPUT_ENABLE: @@ -357,12 +392,12 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, case PIN_CONFIG_OUTPUT: /* set output value */ raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->io_reg); + val = msm_readl_io(pctrl, g); if (arg) val |= BIT(g->out_bit); else val &= ~BIT(g->out_bit); - writel(val, pctrl->regs + g->io_reg); + msm_writel_io(val, pctrl, g); raw_spin_unlock_irqrestore(&pctrl->lock, flags); /* enable output */ @@ -385,10 +420,10 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, } raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->ctl_reg); + val = msm_readl_ctl(pctrl, g); val &= ~(mask << bit); val |= arg << bit; - writel(val, pctrl->regs + g->ctl_reg); + msm_writel_ctl(val, pctrl, g); raw_spin_unlock_irqrestore(&pctrl->lock, flags); } @@ -412,9 +447,9 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->ctl_reg); + val = msm_readl_ctl(pctrl, g); val &= ~BIT(g->oe_bit); - writel(val, pctrl->regs + g->ctl_reg); + msm_writel_ctl(val, pctrl, g); raw_spin_unlock_irqrestore(&pctrl->lock, flags); @@ -432,16 +467,16 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->io_reg); + val = msm_readl_io(pctrl, g); if (value) val |= BIT(g->out_bit); else val &= ~BIT(g->out_bit); - writel(val, pctrl->regs + g->io_reg); + msm_writel_io(val, pctrl, g); - val = readl(pctrl->regs + g->ctl_reg); + val = msm_readl_ctl(pctrl, g); val |= BIT(g->oe_bit); - writel(val, pctrl->regs + g->ctl_reg); + msm_writel_ctl(val, pctrl, g); raw_spin_unlock_irqrestore(&pctrl->lock, flags); @@ -456,7 +491,7 @@ static int msm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) g = &pctrl->soc->groups[offset]; - val = readl(pctrl->regs + g->ctl_reg); + val = msm_readl_ctl(pctrl, g); /* 0 = output, 1 = input */ return val & BIT(g->oe_bit) ? 0 : 1; @@ -470,7 +505,7 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) g = &pctrl->soc->groups[offset]; - val = readl(pctrl->regs + g->io_reg); + val = msm_readl_io(pctrl, g); return !!(val & BIT(g->in_bit)); } @@ -485,12 +520,12 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->io_reg); + val = msm_readl_io(pctrl, g); if (value) val |= BIT(g->out_bit); else val &= ~BIT(g->out_bit); - writel(val, pctrl->regs + g->io_reg); + msm_writel_io(val, pctrl, g); raw_spin_unlock_irqrestore(&pctrl->lock, flags); } @@ -530,8 +565,8 @@ static void msm_gpio_dbg_show_one(struct seq_file *s, return; g = &pctrl->soc->groups[offset]; - ctl_reg = readl(pctrl->regs + g->ctl_reg); - io_reg = readl(pctrl->regs + g->io_reg); + ctl_reg = msm_readl_ctl(pctrl, g); + io_reg = msm_readl_io(pctrl, g); is_out = !!(ctl_reg & BIT(g->oe_bit)); func = (ctl_reg >> g->mux_bit) & 7; @@ -566,6 +601,42 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define msm_gpio_dbg_show NULL #endif +static int msm_gpio_init_valid_mask(struct gpio_chip *chip) +{ + struct msm_pinctrl *pctrl = gpiochip_get_data(chip); + int ret; + unsigned int len, i; + unsigned int max_gpios = pctrl->soc->ngpios; + u16 *tmp; + + /* The number of GPIOs in the ACPI tables */ + len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, + 0); + if (ret < 0) + return 0; + + if (ret > max_gpios) + return -EINVAL; + + tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len); + if (ret < 0) { + dev_err(pctrl->dev, "could not read list of GPIOs\n"); + goto out; + } + + bitmap_zero(chip->valid_mask, max_gpios); + for (i = 0; i < len; i++) + set_bit(tmp[i], chip->valid_mask); + +out: + kfree(tmp); + return ret; +} + static const struct gpio_chip msm_gpio_template = { .direction_input = msm_gpio_direction_input, .direction_output = msm_gpio_direction_output, @@ -575,6 +646,7 @@ static const struct gpio_chip msm_gpio_template = { .request = gpiochip_generic_request, .free = gpiochip_generic_free, .dbg_show = msm_gpio_dbg_show, + .init_valid_mask = msm_gpio_init_valid_mask, }; /* For dual-edge interrupts in software, since some hardware has no @@ -606,14 +678,14 @@ static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl, unsigned pol; do { - val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); + val = msm_readl_io(pctrl, g) & BIT(g->in_bit); - pol = readl(pctrl->regs + g->intr_cfg_reg); + pol = msm_readl_intr_cfg(pctrl, g); pol ^= BIT(g->intr_polarity_bit); - writel(pol, pctrl->regs + g->intr_cfg_reg); + msm_writel_intr_cfg(val, pctrl, g); - val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); - intstat = readl(pctrl->regs + g->intr_status_reg); + val2 = msm_readl_io(pctrl, g) & BIT(g->in_bit); + intstat = msm_readl_intr_status(pctrl, g); if (intstat || (val == val2)) return; } while (loop_limit-- > 0); @@ -633,7 +705,7 @@ static void msm_gpio_irq_mask(struct irq_data *d) raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->intr_cfg_reg); + val = msm_readl_intr_cfg(pctrl, g); /* * There are two bits that control interrupt forwarding to the CPU. The * RAW_STATUS_EN bit causes the level or edge sensed on the line to be @@ -658,7 +730,7 @@ static void msm_gpio_irq_mask(struct irq_data *d) val &= ~BIT(g->intr_raw_status_bit); val &= ~BIT(g->intr_enable_bit); - writel(val, pctrl->regs + g->intr_cfg_reg); + msm_writel_intr_cfg(val, pctrl, g); clear_bit(d->hwirq, pctrl->enabled_irqs); @@ -677,10 +749,10 @@ static void msm_gpio_irq_unmask(struct irq_data *d) raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->intr_cfg_reg); + val = msm_readl_intr_cfg(pctrl, g); val |= BIT(g->intr_raw_status_bit); val |= BIT(g->intr_enable_bit); - writel(val, pctrl->regs + g->intr_cfg_reg); + msm_writel_intr_cfg(val, pctrl, g); set_bit(d->hwirq, pctrl->enabled_irqs); @@ -699,12 +771,12 @@ static void msm_gpio_irq_ack(struct irq_data *d) raw_spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + g->intr_status_reg); + val = msm_readl_intr_status(pctrl, g); if (g->intr_ack_high) val |= BIT(g->intr_status_bit); else val &= ~BIT(g->intr_status_bit); - writel(val, pctrl->regs + g->intr_status_reg); + msm_writel_intr_status(val, pctrl, g); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) msm_gpio_update_dual_edge_pos(pctrl, g, d); @@ -733,17 +805,17 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) clear_bit(d->hwirq, pctrl->dual_edge_irqs); /* Route interrupts to application cpu */ - val = readl(pctrl->regs + g->intr_target_reg); + val = msm_readl_intr_target(pctrl, g); val &= ~(7 << g->intr_target_bit); val |= g->intr_target_kpss_val << g->intr_target_bit; - writel(val, pctrl->regs + g->intr_target_reg); + msm_writel_intr_target(val, pctrl, g); /* Update configuration for gpio. * RAW_STATUS_EN is left on for all gpio irqs. Due to the * internal circuitry of TLMM, toggling the RAW_STATUS * could cause the INTR_STATUS to be set for EDGE interrupts. */ - val = readl(pctrl->regs + g->intr_cfg_reg); + val = msm_readl_intr_cfg(pctrl, g); val |= BIT(g->intr_raw_status_bit); if (g->intr_detection_width == 2) { val &= ~(3 << g->intr_detection_bit); @@ -791,7 +863,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) } else { BUG(); } - writel(val, pctrl->regs + g->intr_cfg_reg); + msm_writel_intr_cfg(val, pctrl, g); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) msm_gpio_update_dual_edge_pos(pctrl, g, d); @@ -821,6 +893,41 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) return 0; } +static int msm_gpio_irq_reqres(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct msm_pinctrl *pctrl = gpiochip_get_data(gc); + int ret; + + if (!try_module_get(gc->owner)) + return -ENODEV; + + ret = msm_pinmux_request_gpio(pctrl->pctrl, NULL, d->hwirq); + if (ret) + goto out; + msm_gpio_direction_input(gc, d->hwirq); + + if (gpiochip_lock_as_irq(gc, d->hwirq)) { + dev_err(gc->parent, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + ret = -EINVAL; + goto out; + } + return 0; +out: + module_put(gc->owner); + return ret; +} + +static void msm_gpio_irq_relres(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_unlock_as_irq(gc, d->hwirq); + module_put(gc->owner); +} + static void msm_gpio_irq_handler(struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); @@ -840,7 +947,7 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) */ for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) { g = &pctrl->soc->groups[i]; - val = readl(pctrl->regs + g->intr_status_reg); + val = msm_readl_intr_status(pctrl, g); if (val & BIT(g->intr_status_bit)) { irq_pin = irq_find_mapping(gc->irq.domain, i); generic_handle_irq(irq_pin); @@ -855,41 +962,6 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int msm_gpio_init_valid_mask(struct gpio_chip *chip, - struct msm_pinctrl *pctrl) -{ - int ret; - unsigned int len, i; - unsigned int max_gpios = pctrl->soc->ngpios; - u16 *tmp; - - /* The number of GPIOs in the ACPI tables */ - len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0); - if (ret < 0) - return 0; - - if (ret > max_gpios) - return -EINVAL; - - tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len); - if (ret < 0) { - dev_err(pctrl->dev, "could not read list of GPIOs\n"); - goto out; - } - - bitmap_zero(chip->valid_mask, max_gpios); - for (i = 0; i < len; i++) - set_bit(tmp[i], chip->valid_mask); - -out: - kfree(tmp); - return ret; -} - static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) { return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0; @@ -919,6 +991,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type; pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake; + pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres; + pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres; ret = gpiochip_add_data(&pctrl->chip, pctrl); if (ret) { @@ -926,13 +1000,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) return ret; } - ret = msm_gpio_init_valid_mask(chip, pctrl); - if (ret) { - dev_err(pctrl->dev, "Failed to setup irq valid bits\n"); - gpiochip_remove(&pctrl->chip); - return ret; - } - /* * For DeviceTree-supported systems, the gpio core checks the * pinctrl's device node for the "gpio-ranges" property. @@ -975,7 +1042,7 @@ static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, { struct msm_pinctrl *pctrl = container_of(nb, struct msm_pinctrl, restart_nb); - writel(0, pctrl->regs + PS_HOLD_OFFSET); + writel(0, pctrl->regs[0] + PS_HOLD_OFFSET); mdelay(1000); return NOTIFY_DONE; } @@ -1011,6 +1078,7 @@ int msm_pinctrl_probe(struct platform_device *pdev, struct msm_pinctrl *pctrl; struct resource *res; int ret; + int i; pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) @@ -1022,10 +1090,20 @@ int msm_pinctrl_probe(struct platform_device *pdev, raw_spin_lock_init(&pctrl->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pctrl->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pctrl->regs)) - return PTR_ERR(pctrl->regs); + if (soc_data->tiles) { + for (i = 0; i < soc_data->ntiles; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + soc_data->tiles[i]); + pctrl->regs[i] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->regs[i])) + return PTR_ERR(pctrl->regs[i]); + } + } else { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->regs[0])) + return PTR_ERR(pctrl->regs[0]); + } msm_pinctrl_setup_pm_reset(pctrl); diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index 9b9feea540ff..29172fdf5882 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -76,6 +76,8 @@ struct msm_pingroup { u32 intr_status_reg; u32 intr_target_reg; + unsigned int tile:2; + unsigned mux_bit:5; unsigned pull_bit:5; @@ -117,6 +119,8 @@ struct msm_pinctrl_soc_data { unsigned ngroups; unsigned ngpios; bool pull_no_keeper; + const char *const *tiles; + unsigned int ntiles; }; int msm_pinctrl_probe(struct platform_device *pdev, diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c new file mode 100644 index 000000000000..7aae52a09ff0 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c @@ -0,0 +1,1697 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-msm.h" + +static const char * const qcs404_tiles[] = { + "north", + "south", + "east" +}; + +enum { + NORTH, + SOUTH, + EAST +}; + +#define FUNCTION(fname) \ + [msm_mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define PINGROUP(id, _tile, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9 \ + }, \ + .nfuncs = 10, \ + .ctl_reg = 0x1000 * id, \ + .io_reg = 0x1000 * id + 0x4, \ + .intr_cfg_reg = 0x1000 * id + 0x8, \ + .intr_status_reg = 0x1000 * id + 0xc, \ + .intr_target_reg = 0x1000 * id + 0x8, \ + .tile = _tile, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 4, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .tile = NORTH, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .tile = NORTH, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } +static const struct pinctrl_pin_desc qcs404_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "SDC1_RCLK"), + PINCTRL_PIN(121, "SDC1_CLK"), + PINCTRL_PIN(122, "SDC1_CMD"), + PINCTRL_PIN(123, "SDC1_DATA"), + PINCTRL_PIN(124, "SDC2_CLK"), + PINCTRL_PIN(125, "SDC2_CMD"), + PINCTRL_PIN(126, "SDC2_DATA"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); + +static const unsigned int sdc1_rclk_pins[] = { 120 }; +static const unsigned int sdc1_clk_pins[] = { 121 }; +static const unsigned int sdc1_cmd_pins[] = { 122 }; +static const unsigned int sdc1_data_pins[] = { 123 }; +static const unsigned int sdc2_clk_pins[] = { 124 }; +static const unsigned int sdc2_cmd_pins[] = { 125 }; +static const unsigned int sdc2_data_pins[] = { 126 }; + +enum qcs404_functions { + msm_mux_gpio, + msm_mux_hdmi_tx, + msm_mux_hdmi_ddc, + msm_mux_blsp_uart_tx_a2, + msm_mux_blsp_spi2, + msm_mux_m_voc, + msm_mux_qdss_cti_trig_in_a0, + msm_mux_blsp_uart_rx_a2, + msm_mux_qdss_tracectl_a, + msm_mux_blsp_uart2, + msm_mux_aud_cdc, + msm_mux_blsp_i2c_sda_a2, + msm_mux_qdss_tracedata_a, + msm_mux_blsp_i2c_scl_a2, + msm_mux_qdss_tracectl_b, + msm_mux_qdss_cti_trig_in_b0, + msm_mux_blsp_uart1, + msm_mux_blsp_spi_mosi_a1, + msm_mux_blsp_spi_miso_a1, + msm_mux_qdss_tracedata_b, + msm_mux_blsp_i2c1, + msm_mux_blsp_spi_cs_n_a1, + msm_mux_gcc_plltest, + msm_mux_blsp_spi_clk_a1, + msm_mux_rgb_data0, + msm_mux_blsp_uart5, + msm_mux_blsp_spi5, + msm_mux_adsp_ext, + msm_mux_rgb_data1, + msm_mux_prng_rosc, + msm_mux_rgb_data2, + msm_mux_blsp_i2c5, + msm_mux_gcc_gp1_clk_b, + msm_mux_rgb_data3, + msm_mux_gcc_gp2_clk_b, + msm_mux_blsp_spi0, + msm_mux_blsp_uart0, + msm_mux_gcc_gp3_clk_b, + msm_mux_blsp_i2c0, + msm_mux_qdss_traceclk_b, + msm_mux_pcie_clk, + msm_mux_nfc_irq, + msm_mux_blsp_spi4, + msm_mux_nfc_dwl, + msm_mux_audio_ts, + msm_mux_rgb_data4, + msm_mux_spi_lcd, + msm_mux_blsp_uart_tx_b2, + msm_mux_gcc_gp3_clk_a, + msm_mux_rgb_data5, + msm_mux_blsp_uart_rx_b2, + msm_mux_blsp_i2c_sda_b2, + msm_mux_blsp_i2c_scl_b2, + msm_mux_pwm_led11, + msm_mux_i2s_3_data0_a, + msm_mux_ebi2_lcd, + msm_mux_i2s_3_data1_a, + msm_mux_i2s_3_data2_a, + msm_mux_atest_char, + msm_mux_pwm_led3, + msm_mux_i2s_3_data3_a, + msm_mux_pwm_led4, + msm_mux_i2s_4, + msm_mux_ebi2_a, + msm_mux_dsd_clk_b, + msm_mux_pwm_led5, + msm_mux_pwm_led6, + msm_mux_pwm_led7, + msm_mux_pwm_led8, + msm_mux_pwm_led24, + msm_mux_spkr_dac0, + msm_mux_blsp_i2c4, + msm_mux_pwm_led9, + msm_mux_pwm_led10, + msm_mux_spdifrx_opt, + msm_mux_pwm_led12, + msm_mux_pwm_led13, + msm_mux_pwm_led14, + msm_mux_wlan1_adc1, + msm_mux_rgb_data_b0, + msm_mux_pwm_led15, + msm_mux_blsp_spi_mosi_b1, + msm_mux_wlan1_adc0, + msm_mux_rgb_data_b1, + msm_mux_pwm_led16, + msm_mux_blsp_spi_miso_b1, + msm_mux_qdss_cti_trig_out_b0, + msm_mux_wlan2_adc1, + msm_mux_rgb_data_b2, + msm_mux_pwm_led17, + msm_mux_blsp_spi_cs_n_b1, + msm_mux_wlan2_adc0, + msm_mux_rgb_data_b3, + msm_mux_pwm_led18, + msm_mux_blsp_spi_clk_b1, + msm_mux_rgb_data_b4, + msm_mux_pwm_led19, + msm_mux_ext_mclk1_b, + msm_mux_qdss_traceclk_a, + msm_mux_rgb_data_b5, + msm_mux_pwm_led20, + msm_mux_atest_char3, + msm_mux_i2s_3_sck_b, + msm_mux_ldo_update, + msm_mux_bimc_dte0, + msm_mux_rgb_hsync, + msm_mux_pwm_led21, + msm_mux_i2s_3_ws_b, + msm_mux_dbg_out, + msm_mux_rgb_vsync, + msm_mux_i2s_3_data0_b, + msm_mux_ldo_en, + msm_mux_hdmi_dtest, + msm_mux_rgb_de, + msm_mux_i2s_3_data1_b, + msm_mux_hdmi_lbk9, + msm_mux_rgb_clk, + msm_mux_atest_char1, + msm_mux_i2s_3_data2_b, + msm_mux_ebi_cdc, + msm_mux_hdmi_lbk8, + msm_mux_rgb_mdp, + msm_mux_atest_char0, + msm_mux_i2s_3_data3_b, + msm_mux_hdmi_lbk7, + msm_mux_rgb_data_b6, + msm_mux_rgb_data_b7, + msm_mux_hdmi_lbk6, + msm_mux_rgmii_int, + msm_mux_cri_trng1, + msm_mux_rgmii_wol, + msm_mux_cri_trng0, + msm_mux_gcc_tlmm, + msm_mux_rgmii_ck, + msm_mux_rgmii_tx, + msm_mux_hdmi_lbk5, + msm_mux_hdmi_pixel, + msm_mux_hdmi_rcv, + msm_mux_hdmi_lbk4, + msm_mux_rgmii_ctl, + msm_mux_ext_lpass, + msm_mux_rgmii_rx, + msm_mux_cri_trng, + msm_mux_hdmi_lbk3, + msm_mux_hdmi_lbk2, + msm_mux_qdss_cti_trig_out_b1, + msm_mux_rgmii_mdio, + msm_mux_hdmi_lbk1, + msm_mux_rgmii_mdc, + msm_mux_hdmi_lbk0, + msm_mux_ir_in, + msm_mux_wsa_en, + msm_mux_rgb_data6, + msm_mux_rgb_data7, + msm_mux_atest_char2, + msm_mux_ebi_ch0, + msm_mux_blsp_uart3, + msm_mux_blsp_spi3, + msm_mux_sd_write, + msm_mux_blsp_i2c3, + msm_mux_gcc_gp1_clk_a, + msm_mux_qdss_cti_trig_in_b1, + msm_mux_gcc_gp2_clk_a, + msm_mux_ext_mclk0, + msm_mux_mclk_in1, + msm_mux_i2s_1, + msm_mux_dsd_clk_a, + msm_mux_qdss_cti_trig_in_a1, + msm_mux_rgmi_dll1, + msm_mux_pwm_led22, + msm_mux_pwm_led23, + msm_mux_qdss_cti_trig_out_a0, + msm_mux_rgmi_dll2, + msm_mux_pwm_led1, + msm_mux_qdss_cti_trig_out_a1, + msm_mux_pwm_led2, + msm_mux_i2s_2, + msm_mux_pll_bist, + msm_mux_ext_mclk1_a, + msm_mux_mclk_in2, + msm_mux_bimc_dte1, + msm_mux_i2s_3_sck_a, + msm_mux_i2s_3_ws_a, + msm_mux__, +}; + +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", + "gpio21", "gpio21", "gpio22", "gpio22", "gpio23", "gpio23", "gpio24", + "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", + "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio36", "gpio36", + "gpio36", "gpio37", "gpio37", "gpio37", "gpio38", "gpio38", "gpio38", + "gpio39", "gpio39", "gpio40", "gpio40", "gpio41", "gpio41", "gpio41", + "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", + "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", + "gpio56", "gpio57", "gpio58", "gpio59", "gpio59", "gpio60", "gpio61", + "gpio62", "gpio63", "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", + "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", + "gpio76", "gpio77", "gpio77", "gpio78", "gpio78", "gpio78", "gpio79", + "gpio79", "gpio79", "gpio80", "gpio81", "gpio81", "gpio82", "gpio83", + "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", + "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", + "gpio98", "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", + "gpio104", "gpio105", "gpio106", "gpio107", "gpio108", "gpio108", + "gpio108", "gpio109", "gpio109", "gpio110", "gpio111", "gpio112", + "gpio113", "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", + "gpio119", +}; + +static const char * const hdmi_tx_groups[] = { + "gpio14", +}; + +static const char * const hdmi_ddc_groups[] = { + "gpio15", "gpio16", +}; + +static const char * const blsp_uart_tx_a2_groups[] = { + "gpio17", +}; + +static const char * const blsp_spi2_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", +}; + +static const char * const m_voc_groups[] = { + "gpio17", "gpio21", +}; + +static const char * const qdss_cti_trig_in_a0_groups[] = { + "gpio17", +}; + +static const char * const blsp_uart_rx_a2_groups[] = { + "gpio18", +}; + +static const char * const qdss_tracectl_a_groups[] = { + "gpio18", +}; + +static const char * const blsp_uart2_groups[] = { + "gpio19", "gpio20", +}; + +static const char * const aud_cdc_groups[] = { + "gpio19", "gpio20", +}; + +static const char * const blsp_i2c_sda_a2_groups[] = { + "gpio19", +}; + +static const char * const qdss_tracedata_a_groups[] = { + "gpio19", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio30", + "gpio31", "gpio32", "gpio36", "gpio38", "gpio39", "gpio42", "gpio43", + "gpio82", "gpio83", +}; + +static const char * const blsp_i2c_scl_a2_groups[] = { + "gpio20", +}; + +static const char * const qdss_tracectl_b_groups[] = { + "gpio20", +}; + +static const char * const qdss_cti_trig_in_b0_groups[] = { + "gpio21", +}; + +static const char * const blsp_uart1_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25", +}; + +static const char * const blsp_spi_mosi_a1_groups[] = { + "gpio22", +}; + +static const char * const blsp_spi_miso_a1_groups[] = { + "gpio23", +}; + +static const char * const qdss_tracedata_b_groups[] = { + "gpio23", "gpio35", "gpio40", "gpio41", "gpio44", "gpio45", "gpio46", + "gpio47", "gpio49", "gpio50", "gpio55", "gpio61", "gpio62", "gpio85", + "gpio89", "gpio93", +}; + +static const char * const blsp_i2c1_groups[] = { + "gpio24", "gpio25", +}; + +static const char * const blsp_spi_cs_n_a1_groups[] = { + "gpio24", +}; + +static const char * const gcc_plltest_groups[] = { + "gpio24", "gpio25", +}; + +static const char * const blsp_spi_clk_a1_groups[] = { + "gpio25", +}; + +static const char * const rgb_data0_groups[] = { + "gpio26", "gpio41", +}; + +static const char * const blsp_uart5_groups[] = { + "gpio26", "gpio27", "gpio28", "gpio29", +}; + +static const char * const blsp_spi5_groups[] = { + "gpio26", "gpio27", "gpio28", "gpio29", "gpio44", "gpio45", "gpio46", +}; + +static const char * const adsp_ext_groups[] = { + "gpio26", +}; + +static const char * const rgb_data1_groups[] = { + "gpio27", "gpio42", +}; + +static const char * const prng_rosc_groups[] = { + "gpio27", +}; + +static const char * const rgb_data2_groups[] = { + "gpio28", "gpio43", +}; + +static const char * const blsp_i2c5_groups[] = { + "gpio28", "gpio29", +}; + +static const char * const gcc_gp1_clk_b_groups[] = { + "gpio28", +}; + +static const char * const rgb_data3_groups[] = { + "gpio29", "gpio44", +}; + +static const char * const gcc_gp2_clk_b_groups[] = { + "gpio29", +}; + +static const char * const blsp_spi0_groups[] = { + "gpio30", "gpio31", "gpio32", "gpio33", +}; + +static const char * const blsp_uart0_groups[] = { + "gpio30", "gpio31", "gpio32", "gpio33", +}; + +static const char * const gcc_gp3_clk_b_groups[] = { + "gpio30", +}; + +static const char * const blsp_i2c0_groups[] = { + "gpio32", "gpio33", +}; + +static const char * const qdss_traceclk_b_groups[] = { + "gpio34", +}; + +static const char * const pcie_clk_groups[] = { + "gpio35", +}; + +static const char * const nfc_irq_groups[] = { + "gpio37", +}; + +static const char * const blsp_spi4_groups[] = { + "gpio37", "gpio38", "gpio117", "gpio118", +}; + +static const char * const nfc_dwl_groups[] = { + "gpio38", +}; + +static const char * const audio_ts_groups[] = { + "gpio38", +}; + +static const char * const rgb_data4_groups[] = { + "gpio39", "gpio45", +}; + +static const char * const spi_lcd_groups[] = { + "gpio39", "gpio40", +}; + +static const char * const blsp_uart_tx_b2_groups[] = { + "gpio39", +}; + +static const char * const gcc_gp3_clk_a_groups[] = { + "gpio39", +}; + +static const char * const rgb_data5_groups[] = { + "gpio40", "gpio46", +}; + +static const char * const blsp_uart_rx_b2_groups[] = { + "gpio40", +}; + +static const char * const blsp_i2c_sda_b2_groups[] = { + "gpio41", +}; + +static const char * const blsp_i2c_scl_b2_groups[] = { + "gpio42", +}; + +static const char * const pwm_led11_groups[] = { + "gpio43", +}; + +static const char * const i2s_3_data0_a_groups[] = { + "gpio106", +}; + +static const char * const ebi2_lcd_groups[] = { + "gpio106", "gpio107", "gpio108", "gpio109", +}; + +static const char * const i2s_3_data1_a_groups[] = { + "gpio107", +}; + +static const char * const i2s_3_data2_a_groups[] = { + "gpio108", +}; + +static const char * const atest_char_groups[] = { + "gpio108", +}; + +static const char * const pwm_led3_groups[] = { + "gpio108", +}; + +static const char * const i2s_3_data3_a_groups[] = { + "gpio109", +}; + +static const char * const pwm_led4_groups[] = { + "gpio109", +}; + +static const char * const i2s_4_groups[] = { + "gpio110", "gpio111", "gpio111", "gpio112", "gpio112", "gpio113", + "gpio113", "gpio114", "gpio114", "gpio115", "gpio115", "gpio116", +}; + +static const char * const ebi2_a_groups[] = { + "gpio110", +}; + +static const char * const dsd_clk_b_groups[] = { + "gpio110", +}; + +static const char * const pwm_led5_groups[] = { + "gpio110", +}; + +static const char * const pwm_led6_groups[] = { + "gpio111", +}; + +static const char * const pwm_led7_groups[] = { + "gpio112", +}; + +static const char * const pwm_led8_groups[] = { + "gpio113", +}; + +static const char * const pwm_led24_groups[] = { + "gpio114", +}; + +static const char * const spkr_dac0_groups[] = { + "gpio116", +}; + +static const char * const blsp_i2c4_groups[] = { + "gpio117", "gpio118", +}; + +static const char * const pwm_led9_groups[] = { + "gpio117", +}; + +static const char * const pwm_led10_groups[] = { + "gpio118", +}; + +static const char * const spdifrx_opt_groups[] = { + "gpio119", +}; + +static const char * const pwm_led12_groups[] = { + "gpio44", +}; + +static const char * const pwm_led13_groups[] = { + "gpio45", +}; + +static const char * const pwm_led14_groups[] = { + "gpio46", +}; + +static const char * const wlan1_adc1_groups[] = { + "gpio46", +}; + +static const char * const rgb_data_b0_groups[] = { + "gpio47", +}; + +static const char * const pwm_led15_groups[] = { + "gpio47", +}; + +static const char * const blsp_spi_mosi_b1_groups[] = { + "gpio47", +}; + +static const char * const wlan1_adc0_groups[] = { + "gpio47", +}; + +static const char * const rgb_data_b1_groups[] = { + "gpio48", +}; + +static const char * const pwm_led16_groups[] = { + "gpio48", +}; + +static const char * const blsp_spi_miso_b1_groups[] = { + "gpio48", +}; + +static const char * const qdss_cti_trig_out_b0_groups[] = { + "gpio48", +}; + +static const char * const wlan2_adc1_groups[] = { + "gpio48", +}; + +static const char * const rgb_data_b2_groups[] = { + "gpio49", +}; + +static const char * const pwm_led17_groups[] = { + "gpio49", +}; + +static const char * const blsp_spi_cs_n_b1_groups[] = { + "gpio49", +}; + +static const char * const wlan2_adc0_groups[] = { + "gpio49", +}; + +static const char * const rgb_data_b3_groups[] = { + "gpio50", +}; + +static const char * const pwm_led18_groups[] = { + "gpio50", +}; + +static const char * const blsp_spi_clk_b1_groups[] = { + "gpio50", +}; + +static const char * const rgb_data_b4_groups[] = { + "gpio51", +}; + +static const char * const pwm_led19_groups[] = { + "gpio51", +}; + +static const char * const ext_mclk1_b_groups[] = { + "gpio51", +}; + +static const char * const qdss_traceclk_a_groups[] = { + "gpio51", +}; + +static const char * const rgb_data_b5_groups[] = { + "gpio52", +}; + +static const char * const pwm_led20_groups[] = { + "gpio52", +}; + +static const char * const atest_char3_groups[] = { + "gpio52", +}; + +static const char * const i2s_3_sck_b_groups[] = { + "gpio52", +}; + +static const char * const ldo_update_groups[] = { + "gpio52", +}; + +static const char * const bimc_dte0_groups[] = { + "gpio52", "gpio54", +}; + +static const char * const rgb_hsync_groups[] = { + "gpio53", +}; + +static const char * const pwm_led21_groups[] = { + "gpio53", +}; + +static const char * const i2s_3_ws_b_groups[] = { + "gpio53", +}; + +static const char * const dbg_out_groups[] = { + "gpio53", +}; + +static const char * const rgb_vsync_groups[] = { + "gpio54", +}; + +static const char * const i2s_3_data0_b_groups[] = { + "gpio54", +}; + +static const char * const ldo_en_groups[] = { + "gpio54", +}; + +static const char * const hdmi_dtest_groups[] = { + "gpio54", +}; + +static const char * const rgb_de_groups[] = { + "gpio55", +}; + +static const char * const i2s_3_data1_b_groups[] = { + "gpio55", +}; + +static const char * const hdmi_lbk9_groups[] = { + "gpio55", +}; + +static const char * const rgb_clk_groups[] = { + "gpio56", +}; + +static const char * const atest_char1_groups[] = { + "gpio56", +}; + +static const char * const i2s_3_data2_b_groups[] = { + "gpio56", +}; + +static const char * const ebi_cdc_groups[] = { + "gpio56", "gpio58", "gpio106", "gpio107", "gpio108", "gpio111", +}; + +static const char * const hdmi_lbk8_groups[] = { + "gpio56", +}; + +static const char * const rgb_mdp_groups[] = { + "gpio57", +}; + +static const char * const atest_char0_groups[] = { + "gpio57", +}; + +static const char * const i2s_3_data3_b_groups[] = { + "gpio57", +}; + +static const char * const hdmi_lbk7_groups[] = { + "gpio57", +}; + +static const char * const rgb_data_b6_groups[] = { + "gpio58", +}; + +static const char * const rgb_data_b7_groups[] = { + "gpio59", +}; + +static const char * const hdmi_lbk6_groups[] = { + "gpio59", +}; + +static const char * const rgmii_int_groups[] = { + "gpio61", +}; + +static const char * const cri_trng1_groups[] = { + "gpio61", +}; + +static const char * const rgmii_wol_groups[] = { + "gpio62", +}; + +static const char * const cri_trng0_groups[] = { + "gpio62", +}; + +static const char * const gcc_tlmm_groups[] = { + "gpio62", +}; + +static const char * const rgmii_ck_groups[] = { + "gpio63", "gpio69", +}; + +static const char * const rgmii_tx_groups[] = { + "gpio64", "gpio65", "gpio66", "gpio67", +}; + +static const char * const hdmi_lbk5_groups[] = { + "gpio64", +}; + +static const char * const hdmi_pixel_groups[] = { + "gpio65", +}; + +static const char * const hdmi_rcv_groups[] = { + "gpio66", +}; + +static const char * const hdmi_lbk4_groups[] = { + "gpio67", +}; + +static const char * const rgmii_ctl_groups[] = { + "gpio68", "gpio74", +}; + +static const char * const ext_lpass_groups[] = { + "gpio69", +}; + +static const char * const rgmii_rx_groups[] = { + "gpio70", "gpio71", "gpio72", "gpio73", +}; + +static const char * const cri_trng_groups[] = { + "gpio70", +}; + +static const char * const hdmi_lbk3_groups[] = { + "gpio71", +}; + +static const char * const hdmi_lbk2_groups[] = { + "gpio72", +}; + +static const char * const qdss_cti_trig_out_b1_groups[] = { + "gpio73", +}; + +static const char * const rgmii_mdio_groups[] = { + "gpio75", +}; + +static const char * const hdmi_lbk1_groups[] = { + "gpio75", +}; + +static const char * const rgmii_mdc_groups[] = { + "gpio76", +}; + +static const char * const hdmi_lbk0_groups[] = { + "gpio76", +}; + +static const char * const ir_in_groups[] = { + "gpio77", +}; + +static const char * const wsa_en_groups[] = { + "gpio77", +}; + +static const char * const rgb_data6_groups[] = { + "gpio78", "gpio80", +}; + +static const char * const rgb_data7_groups[] = { + "gpio79", "gpio81", +}; + +static const char * const atest_char2_groups[] = { + "gpio80", +}; + +static const char * const ebi_ch0_groups[] = { + "gpio81", +}; + +static const char * const blsp_uart3_groups[] = { + "gpio82", "gpio83", "gpio84", "gpio85", +}; + +static const char * const blsp_spi3_groups[] = { + "gpio82", "gpio83", "gpio84", "gpio85", +}; + +static const char * const sd_write_groups[] = { + "gpio82", +}; + +static const char * const blsp_i2c3_groups[] = { + "gpio84", "gpio85", +}; + +static const char * const gcc_gp1_clk_a_groups[] = { + "gpio84", +}; + +static const char * const qdss_cti_trig_in_b1_groups[] = { + "gpio84", +}; + +static const char * const gcc_gp2_clk_a_groups[] = { + "gpio85", +}; + +static const char * const ext_mclk0_groups[] = { + "gpio86", +}; + +static const char * const mclk_in1_groups[] = { + "gpio86", +}; + +static const char * const i2s_1_groups[] = { + "gpio87", "gpio88", "gpio88", "gpio89", "gpio89", "gpio90", "gpio90", + "gpio91", "gpio91", "gpio92", "gpio92", "gpio93", "gpio93", "gpio94", + "gpio94", "gpio95", "gpio95", "gpio96", +}; + +static const char * const dsd_clk_a_groups[] = { + "gpio87", +}; + +static const char * const qdss_cti_trig_in_a1_groups[] = { + "gpio92", +}; + +static const char * const rgmi_dll1_groups[] = { + "gpio92", +}; + +static const char * const pwm_led22_groups[] = { + "gpio93", +}; + +static const char * const pwm_led23_groups[] = { + "gpio94", +}; + +static const char * const qdss_cti_trig_out_a0_groups[] = { + "gpio94", +}; + +static const char * const rgmi_dll2_groups[] = { + "gpio94", +}; + +static const char * const pwm_led1_groups[] = { + "gpio95", +}; + +static const char * const qdss_cti_trig_out_a1_groups[] = { + "gpio95", +}; + +static const char * const pwm_led2_groups[] = { + "gpio96", +}; + +static const char * const i2s_2_groups[] = { + "gpio97", "gpio98", "gpio99", "gpio100", "gpio101", "gpio102", +}; + +static const char * const pll_bist_groups[] = { + "gpio100", +}; + +static const char * const ext_mclk1_a_groups[] = { + "gpio103", +}; + +static const char * const mclk_in2_groups[] = { + "gpio103", +}; + +static const char * const bimc_dte1_groups[] = { + "gpio103", "gpio109", +}; + +static const char * const i2s_3_sck_a_groups[] = { + "gpio104", +}; + +static const char * const i2s_3_ws_a_groups[] = { + "gpio105", +}; + +static const struct msm_function qcs404_functions[] = { + FUNCTION(gpio), + FUNCTION(hdmi_tx), + FUNCTION(hdmi_ddc), + FUNCTION(blsp_uart_tx_a2), + FUNCTION(blsp_spi2), + FUNCTION(m_voc), + FUNCTION(qdss_cti_trig_in_a0), + FUNCTION(blsp_uart_rx_a2), + FUNCTION(qdss_tracectl_a), + FUNCTION(blsp_uart2), + FUNCTION(aud_cdc), + FUNCTION(blsp_i2c_sda_a2), + FUNCTION(qdss_tracedata_a), + FUNCTION(blsp_i2c_scl_a2), + FUNCTION(qdss_tracectl_b), + FUNCTION(qdss_cti_trig_in_b0), + FUNCTION(blsp_uart1), + FUNCTION(blsp_spi_mosi_a1), + FUNCTION(blsp_spi_miso_a1), + FUNCTION(qdss_tracedata_b), + FUNCTION(blsp_i2c1), + FUNCTION(blsp_spi_cs_n_a1), + FUNCTION(gcc_plltest), + FUNCTION(blsp_spi_clk_a1), + FUNCTION(rgb_data0), + FUNCTION(blsp_uart5), + FUNCTION(blsp_spi5), + FUNCTION(adsp_ext), + FUNCTION(rgb_data1), + FUNCTION(prng_rosc), + FUNCTION(rgb_data2), + FUNCTION(blsp_i2c5), + FUNCTION(gcc_gp1_clk_b), + FUNCTION(rgb_data3), + FUNCTION(gcc_gp2_clk_b), + FUNCTION(blsp_spi0), + FUNCTION(blsp_uart0), + FUNCTION(gcc_gp3_clk_b), + FUNCTION(blsp_i2c0), + FUNCTION(qdss_traceclk_b), + FUNCTION(pcie_clk), + FUNCTION(nfc_irq), + FUNCTION(blsp_spi4), + FUNCTION(nfc_dwl), + FUNCTION(audio_ts), + FUNCTION(rgb_data4), + FUNCTION(spi_lcd), + FUNCTION(blsp_uart_tx_b2), + FUNCTION(gcc_gp3_clk_a), + FUNCTION(rgb_data5), + FUNCTION(blsp_uart_rx_b2), + FUNCTION(blsp_i2c_sda_b2), + FUNCTION(blsp_i2c_scl_b2), + FUNCTION(pwm_led11), + FUNCTION(i2s_3_data0_a), + FUNCTION(ebi2_lcd), + FUNCTION(i2s_3_data1_a), + FUNCTION(i2s_3_data2_a), + FUNCTION(atest_char), + FUNCTION(pwm_led3), + FUNCTION(i2s_3_data3_a), + FUNCTION(pwm_led4), + FUNCTION(i2s_4), + FUNCTION(ebi2_a), + FUNCTION(dsd_clk_b), + FUNCTION(pwm_led5), + FUNCTION(pwm_led6), + FUNCTION(pwm_led7), + FUNCTION(pwm_led8), + FUNCTION(pwm_led24), + FUNCTION(spkr_dac0), + FUNCTION(blsp_i2c4), + FUNCTION(pwm_led9), + FUNCTION(pwm_led10), + FUNCTION(spdifrx_opt), + FUNCTION(pwm_led12), + FUNCTION(pwm_led13), + FUNCTION(pwm_led14), + FUNCTION(wlan1_adc1), + FUNCTION(rgb_data_b0), + FUNCTION(pwm_led15), + FUNCTION(blsp_spi_mosi_b1), + FUNCTION(wlan1_adc0), + FUNCTION(rgb_data_b1), + FUNCTION(pwm_led16), + FUNCTION(blsp_spi_miso_b1), + FUNCTION(qdss_cti_trig_out_b0), + FUNCTION(wlan2_adc1), + FUNCTION(rgb_data_b2), + FUNCTION(pwm_led17), + FUNCTION(blsp_spi_cs_n_b1), + FUNCTION(wlan2_adc0), + FUNCTION(rgb_data_b3), + FUNCTION(pwm_led18), + FUNCTION(blsp_spi_clk_b1), + FUNCTION(rgb_data_b4), + FUNCTION(pwm_led19), + FUNCTION(ext_mclk1_b), + FUNCTION(qdss_traceclk_a), + FUNCTION(rgb_data_b5), + FUNCTION(pwm_led20), + FUNCTION(atest_char3), + FUNCTION(i2s_3_sck_b), + FUNCTION(ldo_update), + FUNCTION(bimc_dte0), + FUNCTION(rgb_hsync), + FUNCTION(pwm_led21), + FUNCTION(i2s_3_ws_b), + FUNCTION(dbg_out), + FUNCTION(rgb_vsync), + FUNCTION(i2s_3_data0_b), + FUNCTION(ldo_en), + FUNCTION(hdmi_dtest), + FUNCTION(rgb_de), + FUNCTION(i2s_3_data1_b), + FUNCTION(hdmi_lbk9), + FUNCTION(rgb_clk), + FUNCTION(atest_char1), + FUNCTION(i2s_3_data2_b), + FUNCTION(ebi_cdc), + FUNCTION(hdmi_lbk8), + FUNCTION(rgb_mdp), + FUNCTION(atest_char0), + FUNCTION(i2s_3_data3_b), + FUNCTION(hdmi_lbk7), + FUNCTION(rgb_data_b6), + FUNCTION(rgb_data_b7), + FUNCTION(hdmi_lbk6), + FUNCTION(rgmii_int), + FUNCTION(cri_trng1), + FUNCTION(rgmii_wol), + FUNCTION(cri_trng0), + FUNCTION(gcc_tlmm), + FUNCTION(rgmii_ck), + FUNCTION(rgmii_tx), + FUNCTION(hdmi_lbk5), + FUNCTION(hdmi_pixel), + FUNCTION(hdmi_rcv), + FUNCTION(hdmi_lbk4), + FUNCTION(rgmii_ctl), + FUNCTION(ext_lpass), + FUNCTION(rgmii_rx), + FUNCTION(cri_trng), + FUNCTION(hdmi_lbk3), + FUNCTION(hdmi_lbk2), + FUNCTION(qdss_cti_trig_out_b1), + FUNCTION(rgmii_mdio), + FUNCTION(hdmi_lbk1), + FUNCTION(rgmii_mdc), + FUNCTION(hdmi_lbk0), + FUNCTION(ir_in), + FUNCTION(wsa_en), + FUNCTION(rgb_data6), + FUNCTION(rgb_data7), + FUNCTION(atest_char2), + FUNCTION(ebi_ch0), + FUNCTION(blsp_uart3), + FUNCTION(blsp_spi3), + FUNCTION(sd_write), + FUNCTION(blsp_i2c3), + FUNCTION(gcc_gp1_clk_a), + FUNCTION(qdss_cti_trig_in_b1), + FUNCTION(gcc_gp2_clk_a), + FUNCTION(ext_mclk0), + FUNCTION(mclk_in1), + FUNCTION(i2s_1), + FUNCTION(dsd_clk_a), + FUNCTION(qdss_cti_trig_in_a1), + FUNCTION(rgmi_dll1), + FUNCTION(pwm_led22), + FUNCTION(pwm_led23), + FUNCTION(qdss_cti_trig_out_a0), + FUNCTION(rgmi_dll2), + FUNCTION(pwm_led1), + FUNCTION(qdss_cti_trig_out_a1), + FUNCTION(pwm_led2), + FUNCTION(i2s_2), + FUNCTION(pll_bist), + FUNCTION(ext_mclk1_a), + FUNCTION(mclk_in2), + FUNCTION(bimc_dte1), + FUNCTION(i2s_3_sck_a), + FUNCTION(i2s_3_ws_a), +}; + +/* Every pin is maintained as a single group, and missing or non-existing pin + * would be maintained as dummy group to synchronize pin group index with + * pin descriptor registered with pinctrl core. + * Clients would not be able to request these dummy pin groups. + */ +static const struct msm_pingroup qcs404_groups[] = { + [0] = PINGROUP(0, SOUTH, _, _, _, _, _, _, _, _, _), + [1] = PINGROUP(1, SOUTH, _, _, _, _, _, _, _, _, _), + [2] = PINGROUP(2, SOUTH, _, _, _, _, _, _, _, _, _), + [3] = PINGROUP(3, SOUTH, _, _, _, _, _, _, _, _, _), + [4] = PINGROUP(4, SOUTH, _, _, _, _, _, _, _, _, _), + [5] = PINGROUP(5, SOUTH, _, _, _, _, _, _, _, _, _), + [6] = PINGROUP(6, SOUTH, _, _, _, _, _, _, _, _, _), + [7] = PINGROUP(7, SOUTH, _, _, _, _, _, _, _, _, _), + [8] = PINGROUP(8, SOUTH, _, _, _, _, _, _, _, _, _), + [9] = PINGROUP(9, SOUTH, _, _, _, _, _, _, _, _, _), + [10] = PINGROUP(10, SOUTH, _, _, _, _, _, _, _, _, _), + [11] = PINGROUP(11, SOUTH, _, _, _, _, _, _, _, _, _), + [12] = PINGROUP(12, SOUTH, _, _, _, _, _, _, _, _, _), + [13] = PINGROUP(13, SOUTH, _, _, _, _, _, _, _, _, _), + [14] = PINGROUP(14, SOUTH, hdmi_tx, _, _, _, _, _, _, _, _), + [15] = PINGROUP(15, SOUTH, hdmi_ddc, _, _, _, _, _, _, _, _), + [16] = PINGROUP(16, SOUTH, hdmi_ddc, _, _, _, _, _, _, _, _), + [17] = PINGROUP(17, NORTH, blsp_uart_tx_a2, blsp_spi2, m_voc, _, _, _, _, _, _), + [18] = PINGROUP(18, NORTH, blsp_uart_rx_a2, blsp_spi2, _, _, _, _, _, qdss_tracectl_a, _), + [19] = PINGROUP(19, NORTH, blsp_uart2, aud_cdc, blsp_i2c_sda_a2, blsp_spi2, _, qdss_tracedata_a, _, _, _), + [20] = PINGROUP(20, NORTH, blsp_uart2, aud_cdc, blsp_i2c_scl_a2, blsp_spi2, _, _, _, _, _), + [21] = PINGROUP(21, SOUTH, m_voc, _, _, _, _, _, _, _, qdss_cti_trig_in_b0), + [22] = PINGROUP(22, NORTH, blsp_uart1, blsp_spi_mosi_a1, _, _, _, _, _, _, _), + [23] = PINGROUP(23, NORTH, blsp_uart1, blsp_spi_miso_a1, _, _, _, _, _, qdss_tracedata_b, _), + [24] = PINGROUP(24, NORTH, blsp_uart1, blsp_i2c1, blsp_spi_cs_n_a1, gcc_plltest, _, _, _, _, _), + [25] = PINGROUP(25, NORTH, blsp_uart1, blsp_i2c1, blsp_spi_clk_a1, gcc_plltest, _, _, _, _, _), + [26] = PINGROUP(26, EAST, rgb_data0, blsp_uart5, blsp_spi5, adsp_ext, _, _, _, _, _), + [27] = PINGROUP(27, EAST, rgb_data1, blsp_uart5, blsp_spi5, prng_rosc, _, _, _, _, _), + [28] = PINGROUP(28, EAST, rgb_data2, blsp_uart5, blsp_i2c5, blsp_spi5, gcc_gp1_clk_b, _, _, _, _), + [29] = PINGROUP(29, EAST, rgb_data3, blsp_uart5, blsp_i2c5, blsp_spi5, gcc_gp2_clk_b, _, _, _, _), + [30] = PINGROUP(30, NORTH, blsp_spi0, blsp_uart0, gcc_gp3_clk_b, _, _, _, _, _, _), + [31] = PINGROUP(31, NORTH, blsp_spi0, blsp_uart0, _, _, _, _, _, _, _), + [32] = PINGROUP(32, NORTH, blsp_spi0, blsp_uart0, blsp_i2c0, _, _, _, _, _, _), + [33] = PINGROUP(33, NORTH, blsp_spi0, blsp_uart0, blsp_i2c0, _, _, _, _, _, _), + [34] = PINGROUP(34, SOUTH, _, qdss_traceclk_b, _, _, _, _, _, _, _), + [35] = PINGROUP(35, SOUTH, pcie_clk, _, qdss_tracedata_b, _, _, _, _, _, _), + [36] = PINGROUP(36, NORTH, _, _, _, _, _, _, qdss_tracedata_a, _, _), + [37] = PINGROUP(37, NORTH, nfc_irq, blsp_spi4, _, _, _, _, _, _, _), + [38] = PINGROUP(38, NORTH, nfc_dwl, blsp_spi4, audio_ts, _, _, _, _, _, _), + [39] = PINGROUP(39, EAST, rgb_data4, spi_lcd, blsp_uart_tx_b2, gcc_gp3_clk_a, qdss_tracedata_a, _, _, _, _), + [40] = PINGROUP(40, EAST, rgb_data5, spi_lcd, blsp_uart_rx_b2, _, qdss_tracedata_b, _, _, _, _), + [41] = PINGROUP(41, EAST, rgb_data0, blsp_i2c_sda_b2, _, qdss_tracedata_b, _, _, _, _, _), + [42] = PINGROUP(42, EAST, rgb_data1, blsp_i2c_scl_b2, _, _, _, _, _, qdss_tracedata_a, _), + [43] = PINGROUP(43, EAST, rgb_data2, pwm_led11, _, _, _, _, _, _, _), + [44] = PINGROUP(44, EAST, rgb_data3, pwm_led12, blsp_spi5, _, _, _, _, _, _), + [45] = PINGROUP(45, EAST, rgb_data4, pwm_led13, blsp_spi5, qdss_tracedata_b, _, _, _, _, _), + [46] = PINGROUP(46, EAST, rgb_data5, pwm_led14, blsp_spi5, qdss_tracedata_b, _, wlan1_adc1, _, _, _), + [47] = PINGROUP(47, EAST, rgb_data_b0, pwm_led15, blsp_spi_mosi_b1, qdss_tracedata_b, _, wlan1_adc0, _, _, _), + [48] = PINGROUP(48, EAST, rgb_data_b1, pwm_led16, blsp_spi_miso_b1, _, qdss_cti_trig_out_b0, _, wlan2_adc1, _, _), + [49] = PINGROUP(49, EAST, rgb_data_b2, pwm_led17, blsp_spi_cs_n_b1, _, qdss_tracedata_b, _, wlan2_adc0, _, _), + [50] = PINGROUP(50, EAST, rgb_data_b3, pwm_led18, blsp_spi_clk_b1, qdss_tracedata_b, _, _, _, _, _), + [51] = PINGROUP(51, EAST, rgb_data_b4, pwm_led19, ext_mclk1_b, qdss_traceclk_a, _, _, _, _, _), + [52] = PINGROUP(52, EAST, rgb_data_b5, pwm_led20, atest_char3, i2s_3_sck_b, ldo_update, bimc_dte0, _, _, _), + [53] = PINGROUP(53, EAST, rgb_hsync, pwm_led21, i2s_3_ws_b, dbg_out, _, _, _, _, _), + [54] = PINGROUP(54, EAST, rgb_vsync, i2s_3_data0_b, ldo_en, bimc_dte0, _, hdmi_dtest, _, _, _), + [55] = PINGROUP(55, EAST, rgb_de, i2s_3_data1_b, _, qdss_tracedata_b, _, hdmi_lbk9, _, _, _), + [56] = PINGROUP(56, EAST, rgb_clk, atest_char1, i2s_3_data2_b, ebi_cdc, _, hdmi_lbk8, _, _, _), + [57] = PINGROUP(57, EAST, rgb_mdp, atest_char0, i2s_3_data3_b, _, hdmi_lbk7, _, _, _, _), + [58] = PINGROUP(58, EAST, rgb_data_b6, _, ebi_cdc, _, _, _, _, _, _), + [59] = PINGROUP(59, EAST, rgb_data_b7, _, hdmi_lbk6, _, _, _, _, _, _), + [60] = PINGROUP(60, NORTH, _, _, _, _, _, _, _, _, _), + [61] = PINGROUP(61, NORTH, rgmii_int, cri_trng1, qdss_tracedata_b, _, _, _, _, _, _), + [62] = PINGROUP(62, NORTH, rgmii_wol, cri_trng0, qdss_tracedata_b, gcc_tlmm, _, _, _, _, _), + [63] = PINGROUP(63, NORTH, rgmii_ck, _, _, _, _, _, _, _, _), + [64] = PINGROUP(64, NORTH, rgmii_tx, _, hdmi_lbk5, _, _, _, _, _, _), + [65] = PINGROUP(65, NORTH, rgmii_tx, _, hdmi_pixel, _, _, _, _, _, _), + [66] = PINGROUP(66, NORTH, rgmii_tx, _, hdmi_rcv, _, _, _, _, _, _), + [67] = PINGROUP(67, NORTH, rgmii_tx, _, hdmi_lbk4, _, _, _, _, _, _), + [68] = PINGROUP(68, NORTH, rgmii_ctl, _, _, _, _, _, _, _, _), + [69] = PINGROUP(69, NORTH, rgmii_ck, ext_lpass, _, _, _, _, _, _, _), + [70] = PINGROUP(70, NORTH, rgmii_rx, cri_trng, _, _, _, _, _, _, _), + [71] = PINGROUP(71, NORTH, rgmii_rx, _, hdmi_lbk3, _, _, _, _, _, _), + [72] = PINGROUP(72, NORTH, rgmii_rx, _, hdmi_lbk2, _, _, _, _, _, _), + [73] = PINGROUP(73, NORTH, rgmii_rx, _, _, _, _, qdss_cti_trig_out_b1, _, _, _), + [74] = PINGROUP(74, NORTH, rgmii_ctl, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, NORTH, rgmii_mdio, _, hdmi_lbk1, _, _, _, _, _, _), + [76] = PINGROUP(76, NORTH, rgmii_mdc, _, _, _, _, _, hdmi_lbk0, _, _), + [77] = PINGROUP(77, NORTH, ir_in, wsa_en, _, _, _, _, _, _, _), + [78] = PINGROUP(78, EAST, rgb_data6, _, _, _, _, _, _, _, _), + [79] = PINGROUP(79, EAST, rgb_data7, _, _, _, _, _, _, _, _), + [80] = PINGROUP(80, EAST, rgb_data6, atest_char2, _, _, _, _, _, _, _), + [81] = PINGROUP(81, EAST, rgb_data7, ebi_ch0, _, _, _, _, _, _, _), + [82] = PINGROUP(82, NORTH, blsp_uart3, blsp_spi3, sd_write, _, _, _, _, _, qdss_tracedata_a), + [83] = PINGROUP(83, NORTH, blsp_uart3, blsp_spi3, _, _, _, _, qdss_tracedata_a, _, _), + [84] = PINGROUP(84, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp1_clk_a, qdss_cti_trig_in_b1, _, _, _, _), + [85] = PINGROUP(85, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp2_clk_a, qdss_tracedata_b, _, _, _, _), + [86] = PINGROUP(86, EAST, ext_mclk0, mclk_in1, _, _, _, _, _, _, _), + [87] = PINGROUP(87, EAST, i2s_1, dsd_clk_a, _, _, _, _, _, _, _), + [88] = PINGROUP(88, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _), + [89] = PINGROUP(89, EAST, i2s_1, i2s_1, _, _, _, _, _, _, qdss_tracedata_b), + [90] = PINGROUP(90, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _), + [91] = PINGROUP(91, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _), + [92] = PINGROUP(92, EAST, i2s_1, i2s_1, _, _, _, _, _, qdss_cti_trig_in_a1, _), + [93] = PINGROUP(93, EAST, i2s_1, pwm_led22, i2s_1, _, _, _, _, _, qdss_tracedata_b), + [94] = PINGROUP(94, EAST, i2s_1, pwm_led23, i2s_1, _, qdss_cti_trig_out_a0, _, rgmi_dll2, _, _), + [95] = PINGROUP(95, EAST, i2s_1, pwm_led1, i2s_1, _, qdss_cti_trig_out_a1, _, _, _, _), + [96] = PINGROUP(96, EAST, i2s_1, pwm_led2, _, _, _, _, _, _, _), + [97] = PINGROUP(97, EAST, i2s_2, _, _, _, _, _, _, _, _), + [98] = PINGROUP(98, EAST, i2s_2, _, _, _, _, _, _, _, _), + [99] = PINGROUP(99, EAST, i2s_2, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, EAST, i2s_2, pll_bist, _, _, _, _, _, _, _), + [101] = PINGROUP(101, EAST, i2s_2, _, _, _, _, _, _, _, _), + [102] = PINGROUP(102, EAST, i2s_2, _, _, _, _, _, _, _, _), + [103] = PINGROUP(103, EAST, ext_mclk1_a, mclk_in2, bimc_dte1, _, _, _, _, _, _), + [104] = PINGROUP(104, EAST, i2s_3_sck_a, _, _, _, _, _, _, _, _), + [105] = PINGROUP(105, EAST, i2s_3_ws_a, _, _, _, _, _, _, _, _), + [106] = PINGROUP(106, EAST, i2s_3_data0_a, ebi2_lcd, _, _, ebi_cdc, _, _, _, _), + [107] = PINGROUP(107, EAST, i2s_3_data1_a, ebi2_lcd, _, _, ebi_cdc, _, _, _, _), + [108] = PINGROUP(108, EAST, i2s_3_data2_a, ebi2_lcd, atest_char, pwm_led3, ebi_cdc, _, _, _, _), + [109] = PINGROUP(109, EAST, i2s_3_data3_a, ebi2_lcd, pwm_led4, bimc_dte1, _, _, _, _, _), + [110] = PINGROUP(110, EAST, i2s_4, ebi2_a, dsd_clk_b, pwm_led5, _, _, _, _, _), + [111] = PINGROUP(111, EAST, i2s_4, i2s_4, pwm_led6, ebi_cdc, _, _, _, _, _), + [112] = PINGROUP(112, EAST, i2s_4, i2s_4, pwm_led7, _, _, _, _, _, _), + [113] = PINGROUP(113, EAST, i2s_4, i2s_4, pwm_led8, _, _, _, _, _, _), + [114] = PINGROUP(114, EAST, i2s_4, i2s_4, pwm_led24, _, _, _, _, _, _), + [115] = PINGROUP(115, EAST, i2s_4, i2s_4, _, _, _, _, _, _, _), + [116] = PINGROUP(116, EAST, i2s_4, spkr_dac0, _, _, _, _, _, _, _), + [117] = PINGROUP(117, NORTH, blsp_i2c4, blsp_spi4, pwm_led9, _, _, _, _, _, _), + [118] = PINGROUP(118, NORTH, blsp_i2c4, blsp_spi4, pwm_led10, _, _, _, _, _, _), + [119] = PINGROUP(119, EAST, spdifrx_opt, _, _, _, _, _, _, _, _), + [120] = SDC_QDSD_PINGROUP(sdc1_rclk, 0xc2000, 15, 0), + [121] = SDC_QDSD_PINGROUP(sdc1_clk, 0xc2000, 13, 6), + [122] = SDC_QDSD_PINGROUP(sdc1_cmd, 0xc2000, 11, 3), + [123] = SDC_QDSD_PINGROUP(sdc1_data, 0xc2000, 9, 0), + [124] = SDC_QDSD_PINGROUP(sdc2_clk, 0xc3000, 14, 6), + [125] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xc3000, 11, 3), + [126] = SDC_QDSD_PINGROUP(sdc2_data, 0xc3000, 9, 0), +}; + +static const struct msm_pinctrl_soc_data qcs404_pinctrl = { + .pins = qcs404_pins, + .npins = ARRAY_SIZE(qcs404_pins), + .functions = qcs404_functions, + .nfunctions = ARRAY_SIZE(qcs404_functions), + .groups = qcs404_groups, + .ngroups = ARRAY_SIZE(qcs404_groups), + .ngpios = 120, + .tiles = qcs404_tiles, + .ntiles = ARRAY_SIZE(qcs404_tiles), +}; + +static int qcs404_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &qcs404_pinctrl); +} + +static const struct of_device_id qcs404_pinctrl_of_match[] = { + { .compatible = "qcom,qcs404-pinctrl", }, + { }, +}; + +static struct platform_driver qcs404_pinctrl_driver = { + .driver = { + .name = "qcs404-pinctrl", + .of_match_table = qcs404_pinctrl_of_match, + }, + .probe = qcs404_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init qcs404_pinctrl_init(void) +{ + return platform_driver_register(&qcs404_pinctrl_driver); +} +arch_initcall(qcs404_pinctrl_init); + +static void __exit qcs404_pinctrl_exit(void) +{ + platform_driver_unregister(&qcs404_pinctrl_driver); +} +module_exit(qcs404_pinctrl_exit); + +MODULE_DESCRIPTION("Qualcomm QCS404 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, qcs404_pinctrl_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c new file mode 100644 index 000000000000..6838b38555a1 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c @@ -0,0 +1,1455 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, Craig Tatlor. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-msm.h" + +static const char * const sdm660_tiles[] = { + "north", + "center", + "south" +}; + +enum { + NORTH, + CENTER, + SOUTH +}; + +#define REG_SIZE 0x1000 + +#define FUNCTION(fname) \ + [msm_mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + + +#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = (unsigned)ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9 \ + }, \ + .nfuncs = 10, \ + .ctl_reg = base + REG_SIZE * id, \ + .io_reg = base + 0x4 + REG_SIZE * id, \ + .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \ + .intr_status_reg = base + 0xc + REG_SIZE * id, \ + .intr_target_reg = base + 0x8 + REG_SIZE * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +static const struct pinctrl_pin_desc sdm660_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "SDC1_CLK"), + PINCTRL_PIN(115, "SDC1_CMD"), + PINCTRL_PIN(116, "SDC1_DATA"), + PINCTRL_PIN(117, "SDC2_CLK"), + PINCTRL_PIN(118, "SDC2_CMD"), + PINCTRL_PIN(119, "SDC2_DATA"), + PINCTRL_PIN(120, "SDC1_RCLK"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); + +static const unsigned int sdc1_clk_pins[] = { 114 }; +static const unsigned int sdc1_cmd_pins[] = { 115 }; +static const unsigned int sdc1_data_pins[] = { 116 }; +static const unsigned int sdc1_rclk_pins[] = { 120 }; +static const unsigned int sdc2_clk_pins[] = { 117 }; +static const unsigned int sdc2_cmd_pins[] = { 118 }; +static const unsigned int sdc2_data_pins[] = { 119 }; + +enum sdm660_functions { + msm_mux_adsp_ext, + msm_mux_agera_pll, + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_gpsadc0, + msm_mux_atest_gpsadc1, + msm_mux_atest_tsens, + msm_mux_atest_tsens2, + msm_mux_atest_usb1, + msm_mux_atest_usb10, + msm_mux_atest_usb11, + msm_mux_atest_usb12, + msm_mux_atest_usb13, + msm_mux_atest_usb2, + msm_mux_atest_usb20, + msm_mux_atest_usb21, + msm_mux_atest_usb22, + msm_mux_atest_usb23, + msm_mux_audio_ref, + msm_mux_bimc_dte0, + msm_mux_bimc_dte1, + msm_mux_blsp_i2c1, + msm_mux_blsp_i2c2, + msm_mux_blsp_i2c3, + msm_mux_blsp_i2c4, + msm_mux_blsp_i2c5, + msm_mux_blsp_i2c6, + msm_mux_blsp_i2c7, + msm_mux_blsp_i2c8_a, + msm_mux_blsp_i2c8_b, + msm_mux_blsp_spi1, + msm_mux_blsp_spi2, + msm_mux_blsp_spi3, + msm_mux_blsp_spi3_cs1, + msm_mux_blsp_spi3_cs2, + msm_mux_blsp_spi4, + msm_mux_blsp_spi5, + msm_mux_blsp_spi6, + msm_mux_blsp_spi7, + msm_mux_blsp_spi8_a, + msm_mux_blsp_spi8_b, + msm_mux_blsp_spi8_cs1, + msm_mux_blsp_spi8_cs2, + msm_mux_blsp_uart1, + msm_mux_blsp_uart2, + msm_mux_blsp_uart5, + msm_mux_blsp_uart6_a, + msm_mux_blsp_uart6_b, + msm_mux_blsp_uim1, + msm_mux_blsp_uim2, + msm_mux_blsp_uim5, + msm_mux_blsp_uim6, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c, + msm_mux_cri_trng, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_dbg_out, + msm_mux_ddr_bist, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_gpio, + msm_mux_gps_tx_a, + msm_mux_gps_tx_b, + msm_mux_gps_tx_c, + msm_mux_isense_dbg, + msm_mux_jitter_bist, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_m_voc, + msm_mux_mdp_vsync, + msm_mux_mdss_vsync0, + msm_mux_mdss_vsync1, + msm_mux_mdss_vsync2, + msm_mux_mdss_vsync3, + msm_mux_mss_lte, + msm_mux_nav_pps_a, + msm_mux_nav_pps_b, + msm_mux_nav_pps_c, + msm_mux_pa_indicator, + msm_mux_phase_flag0, + msm_mux_phase_flag1, + msm_mux_phase_flag2, + msm_mux_phase_flag3, + msm_mux_phase_flag4, + msm_mux_phase_flag5, + msm_mux_phase_flag6, + msm_mux_phase_flag7, + msm_mux_phase_flag8, + msm_mux_phase_flag9, + msm_mux_phase_flag10, + msm_mux_phase_flag11, + msm_mux_phase_flag12, + msm_mux_phase_flag13, + msm_mux_phase_flag14, + msm_mux_phase_flag15, + msm_mux_phase_flag16, + msm_mux_phase_flag17, + msm_mux_phase_flag18, + msm_mux_phase_flag19, + msm_mux_phase_flag20, + msm_mux_phase_flag21, + msm_mux_phase_flag22, + msm_mux_phase_flag23, + msm_mux_phase_flag24, + msm_mux_phase_flag25, + msm_mux_phase_flag26, + msm_mux_phase_flag27, + msm_mux_phase_flag28, + msm_mux_phase_flag29, + msm_mux_phase_flag30, + msm_mux_phase_flag31, + msm_mux_pll_bypassnl, + msm_mux_pll_reset, + msm_mux_pri_mi2s, + msm_mux_pri_mi2s_ws, + msm_mux_prng_rosc, + msm_mux_pwr_crypto, + msm_mux_pwr_modem, + msm_mux_pwr_nav, + msm_mux_qdss_cti0_a, + msm_mux_qdss_cti0_b, + msm_mux_qdss_cti1_a, + msm_mux_qdss_cti1_b, + msm_mux_qdss_gpio, + msm_mux_qdss_gpio0, + msm_mux_qdss_gpio1, + msm_mux_qdss_gpio10, + msm_mux_qdss_gpio11, + msm_mux_qdss_gpio12, + msm_mux_qdss_gpio13, + msm_mux_qdss_gpio14, + msm_mux_qdss_gpio15, + msm_mux_qdss_gpio2, + msm_mux_qdss_gpio3, + msm_mux_qdss_gpio4, + msm_mux_qdss_gpio5, + msm_mux_qdss_gpio6, + msm_mux_qdss_gpio7, + msm_mux_qdss_gpio8, + msm_mux_qdss_gpio9, + msm_mux_qlink_enable, + msm_mux_qlink_request, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qspi_data0, + msm_mux_qspi_data1, + msm_mux_qspi_data2, + msm_mux_qspi_data3, + msm_mux_qspi_resetn, + msm_mux_sec_mi2s, + msm_mux_sndwire_clk, + msm_mux_sndwire_data, + msm_mux_sp_cmu, + msm_mux_ssc_irq, + msm_mux_tgu_ch0, + msm_mux_tgu_ch1, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_uim1_clk, + msm_mux_uim1_data, + msm_mux_uim1_present, + msm_mux_uim1_reset, + msm_mux_uim2_clk, + msm_mux_uim2_data, + msm_mux_uim2_present, + msm_mux_uim2_reset, + msm_mux_uim_batt, + msm_mux_vfr_1, + msm_mux_vsense_clkout, + msm_mux_vsense_data0, + msm_mux_vsense_data1, + msm_mux_vsense_mode, + msm_mux_wlan1_adc0, + msm_mux_wlan1_adc1, + msm_mux_wlan2_adc0, + msm_mux_wlan2_adc1, + msm_mux__, +}; + +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", + "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", + "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", + "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", + "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", + "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio111", "gpio112", "gpio113", +}; + +static const char * const adsp_ext_groups[] = { + "gpio65", +}; +static const char * const agera_pll_groups[] = { + "gpio34", "gpio36", +}; +static const char * const atest_char0_groups[] = { + "gpio62", +}; +static const char * const atest_char1_groups[] = { + "gpio61", +}; +static const char * const atest_char2_groups[] = { + "gpio60", +}; +static const char * const atest_char3_groups[] = { + "gpio59", +}; +static const char * const atest_char_groups[] = { + "gpio58", +}; +static const char * const atest_gpsadc0_groups[] = { + "gpio1", +}; +static const char * const atest_gpsadc1_groups[] = { + "gpio0", +}; +static const char * const atest_tsens2_groups[] = { + "gpio3", +}; +static const char * const atest_tsens_groups[] = { + "gpio36", +}; +static const char * const atest_usb10_groups[] = { + "gpio11", +}; +static const char * const atest_usb11_groups[] = { + "gpio10", +}; +static const char * const atest_usb12_groups[] = { + "gpio9", +}; +static const char * const atest_usb13_groups[] = { + "gpio8", +}; +static const char * const atest_usb1_groups[] = { + "gpio3", +}; +static const char * const atest_usb20_groups[] = { + "gpio56", +}; +static const char * const atest_usb21_groups[] = { + "gpio36", +}; +static const char * const atest_usb22_groups[] = { + "gpio57", +}; +static const char * const atest_usb23_groups[] = { + "gpio37", +}; +static const char * const atest_usb2_groups[] = { + "gpio35", +}; +static const char * const audio_ref_groups[] = { + "gpio62", +}; +static const char * const bimc_dte0_groups[] = { + "gpio9", "gpio11", +}; +static const char * const bimc_dte1_groups[] = { + "gpio8", "gpio10", +}; +static const char * const blsp_i2c1_groups[] = { + "gpio2", "gpio3", +}; +static const char * const blsp_i2c2_groups[] = { + "gpio6", "gpio7", +}; +static const char * const blsp_i2c3_groups[] = { + "gpio10", "gpio11", +}; +static const char * const blsp_i2c4_groups[] = { + "gpio14", "gpio15", +}; +static const char * const blsp_i2c5_groups[] = { + "gpio18", "gpio19", +}; +static const char * const blsp_i2c6_groups[] = { + "gpio22", "gpio23", +}; +static const char * const blsp_i2c7_groups[] = { + "gpio26", "gpio27", +}; +static const char * const blsp_i2c8_a_groups[] = { + "gpio30", "gpio31", +}; +static const char * const blsp_i2c8_b_groups[] = { + "gpio44", "gpio52", +}; +static const char * const blsp_spi1_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio46", +}; +static const char * const blsp_spi2_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; +static const char * const blsp_spi3_cs1_groups[] = { + "gpio30", +}; +static const char * const blsp_spi3_cs2_groups[] = { + "gpio65", +}; +static const char * const blsp_spi3_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11", +}; +static const char * const blsp_spi4_groups[] = { + "gpio12", "gpio13", "gpio14", "gpio15", +}; +static const char * const blsp_spi5_groups[] = { + "gpio16", "gpio17", "gpio18", "gpio19", +}; +static const char * const blsp_spi6_groups[] = { + "gpio49", "gpio52", "gpio22", "gpio23", +}; +static const char * const blsp_spi7_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", +}; +static const char * const blsp_spi8_a_groups[] = { + "gpio28", "gpio29", "gpio30", "gpio31", +}; +static const char * const blsp_spi8_b_groups[] = { + "gpio40", "gpio41", "gpio44", "gpio52", +}; +static const char * const blsp_spi8_cs1_groups[] = { + "gpio64", +}; +static const char * const blsp_spi8_cs2_groups[] = { + "gpio76", +}; +static const char * const blsp_uart1_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; +static const char * const blsp_uart2_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; +static const char * const blsp_uart5_groups[] = { + "gpio16", "gpio17", "gpio18", "gpio19", +}; +static const char * const blsp_uart6_a_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", +}; +static const char * const blsp_uart6_b_groups[] = { + "gpio28", "gpio29", "gpio30", "gpio31", +}; +static const char * const blsp_uim1_groups[] = { + "gpio0", "gpio1", +}; +static const char * const blsp_uim2_groups[] = { + "gpio4", "gpio5", +}; +static const char * const blsp_uim5_groups[] = { + "gpio16", "gpio17", +}; +static const char * const blsp_uim6_groups[] = { + "gpio20", "gpio21", +}; +static const char * const cam_mclk_groups[] = { + "gpio32", "gpio33", "gpio34", "gpio35", +}; +static const char * const cci_async_groups[] = { + "gpio45", +}; +static const char * const cci_i2c_groups[] = { + "gpio36", "gpio37", "gpio38", "gpio39", +}; +static const char * const cri_trng0_groups[] = { + "gpio60", +}; +static const char * const cri_trng1_groups[] = { + "gpio61", +}; +static const char * const cri_trng_groups[] = { + "gpio62", +}; +static const char * const dbg_out_groups[] = { + "gpio11", +}; +static const char * const ddr_bist_groups[] = { + "gpio3", "gpio8", "gpio9", "gpio10", +}; +static const char * const gcc_gp1_groups[] = { + "gpio57", "gpio78", +}; +static const char * const gcc_gp2_groups[] = { + "gpio58", "gpio81", +}; +static const char * const gcc_gp3_groups[] = { + "gpio59", "gpio82", +}; +static const char * const gps_tx_a_groups[] = { + "gpio65", +}; +static const char * const gps_tx_b_groups[] = { + "gpio98", +}; +static const char * const gps_tx_c_groups[] = { + "gpio80", +}; +static const char * const isense_dbg_groups[] = { + "gpio68", +}; +static const char * const jitter_bist_groups[] = { + "gpio35", +}; +static const char * const ldo_en_groups[] = { + "gpio97", +}; +static const char * const ldo_update_groups[] = { + "gpio98", +}; +static const char * const m_voc_groups[] = { + "gpio28", +}; +static const char * const mdp_vsync_groups[] = { + "gpio59", "gpio74", +}; +static const char * const mdss_vsync0_groups[] = { + "gpio42", +}; +static const char * const mdss_vsync1_groups[] = { + "gpio42", +}; +static const char * const mdss_vsync2_groups[] = { + "gpio42", +}; +static const char * const mdss_vsync3_groups[] = { + "gpio42", +}; +static const char * const mss_lte_groups[] = { + "gpio81", "gpio82", +}; +static const char * const nav_pps_a_groups[] = { + "gpio65", +}; +static const char * const nav_pps_b_groups[] = { + "gpio98", +}; +static const char * const nav_pps_c_groups[] = { + "gpio80", +}; +static const char * const pa_indicator_groups[] = { + "gpio92", +}; +static const char * const phase_flag0_groups[] = { + "gpio68", +}; +static const char * const phase_flag1_groups[] = { + "gpio48", +}; +static const char * const phase_flag2_groups[] = { + "gpio49", +}; +static const char * const phase_flag3_groups[] = { + "gpio4", +}; +static const char * const phase_flag4_groups[] = { + "gpio57", +}; +static const char * const phase_flag5_groups[] = { + "gpio17", +}; +static const char * const phase_flag6_groups[] = { + "gpio53", +}; +static const char * const phase_flag7_groups[] = { + "gpio69", +}; +static const char * const phase_flag8_groups[] = { + "gpio70", +}; +static const char * const phase_flag9_groups[] = { + "gpio50", +}; +static const char * const phase_flag10_groups[] = { + "gpio56", +}; +static const char * const phase_flag11_groups[] = { + "gpio21", +}; +static const char * const phase_flag12_groups[] = { + "gpio22", +}; +static const char * const phase_flag13_groups[] = { + "gpio23", +}; +static const char * const phase_flag14_groups[] = { + "gpio5", +}; +static const char * const phase_flag15_groups[] = { + "gpio51", +}; +static const char * const phase_flag16_groups[] = { + "gpio52", +}; +static const char * const phase_flag17_groups[] = { + "gpio24", +}; +static const char * const phase_flag18_groups[] = { + "gpio25", +}; +static const char * const phase_flag19_groups[] = { + "gpio26", +}; +static const char * const phase_flag20_groups[] = { + "gpio27", +}; +static const char * const phase_flag21_groups[] = { + "gpio28", +}; +static const char * const phase_flag22_groups[] = { + "gpio29", +}; +static const char * const phase_flag23_groups[] = { + "gpio30", +}; +static const char * const phase_flag24_groups[] = { + "gpio31", +}; +static const char * const phase_flag25_groups[] = { + "gpio55", +}; +static const char * const phase_flag26_groups[] = { + "gpio12", +}; +static const char * const phase_flag27_groups[] = { + "gpio13", +}; +static const char * const phase_flag28_groups[] = { + "gpio14", +}; +static const char * const phase_flag29_groups[] = { + "gpio54", +}; +static const char * const phase_flag30_groups[] = { + "gpio47", +}; +static const char * const phase_flag31_groups[] = { + "gpio6", +}; +static const char * const pll_bypassnl_groups[] = { + "gpio36", +}; +static const char * const pll_reset_groups[] = { + "gpio37", +}; +static const char * const pri_mi2s_groups[] = { + "gpio12", "gpio14", "gpio15", "gpio61", +}; +static const char * const pri_mi2s_ws_groups[] = { + "gpio13", +}; +static const char * const prng_rosc_groups[] = { + "gpio102", +}; +static const char * const pwr_crypto_groups[] = { + "gpio33", +}; +static const char * const pwr_modem_groups[] = { + "gpio31", +}; +static const char * const pwr_nav_groups[] = { + "gpio32", +}; +static const char * const qdss_cti0_a_groups[] = { + "gpio49", "gpio50", +}; +static const char * const qdss_cti0_b_groups[] = { + "gpio13", "gpio21", +}; +static const char * const qdss_cti1_a_groups[] = { + "gpio53", "gpio55", +}; +static const char * const qdss_cti1_b_groups[] = { + "gpio12", "gpio66", +}; +static const char * const qdss_gpio0_groups[] = { + "gpio32", "gpio67", +}; +static const char * const qdss_gpio10_groups[] = { + "gpio43", "gpio77", +}; +static const char * const qdss_gpio11_groups[] = { + "gpio44", "gpio79", +}; +static const char * const qdss_gpio12_groups[] = { + "gpio45", "gpio80", +}; +static const char * const qdss_gpio13_groups[] = { + "gpio46", "gpio78", +}; +static const char * const qdss_gpio14_groups[] = { + "gpio47", "gpio72", +}; +static const char * const qdss_gpio15_groups[] = { + "gpio48", "gpio73", +}; +static const char * const qdss_gpio1_groups[] = { + "gpio33", "gpio63", +}; +static const char * const qdss_gpio2_groups[] = { + "gpio34", "gpio64", +}; +static const char * const qdss_gpio3_groups[] = { + "gpio35", "gpio56", +}; +static const char * const qdss_gpio4_groups[] = { + "gpio0", "gpio36", +}; +static const char * const qdss_gpio5_groups[] = { + "gpio1", "gpio37", +}; +static const char * const qdss_gpio6_groups[] = { + "gpio38", "gpio70", +}; +static const char * const qdss_gpio7_groups[] = { + "gpio39", "gpio71", +}; +static const char * const qdss_gpio8_groups[] = { + "gpio51", "gpio75", +}; +static const char * const qdss_gpio9_groups[] = { + "gpio42", "gpio76", +}; +static const char * const qdss_gpio_groups[] = { + "gpio31", "gpio52", "gpio68", "gpio69", +}; +static const char * const qlink_enable_groups[] = { + "gpio100", +}; +static const char * const qlink_request_groups[] = { + "gpio99", +}; +static const char * const qspi_clk_groups[] = { + "gpio47", +}; +static const char * const qspi_cs_groups[] = { + "gpio43", "gpio50", +}; +static const char * const qspi_data0_groups[] = { + "gpio33", +}; +static const char * const qspi_data1_groups[] = { + "gpio34", +}; +static const char * const qspi_data2_groups[] = { + "gpio35", +}; +static const char * const qspi_data3_groups[] = { + "gpio51", +}; +static const char * const qspi_resetn_groups[] = { + "gpio48", +}; +static const char * const sec_mi2s_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", "gpio62", +}; +static const char * const sndwire_clk_groups[] = { + "gpio24", +}; +static const char * const sndwire_data_groups[] = { + "gpio25", +}; +static const char * const sp_cmu_groups[] = { + "gpio64", +}; +static const char * const ssc_irq_groups[] = { + "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio74", + "gpio75", "gpio76", +}; +static const char * const tgu_ch0_groups[] = { + "gpio0", +}; +static const char * const tgu_ch1_groups[] = { + "gpio1", +}; +static const char * const tsense_pwm1_groups[] = { + "gpio71", +}; +static const char * const tsense_pwm2_groups[] = { + "gpio71", +}; +static const char * const uim1_clk_groups[] = { + "gpio88", +}; +static const char * const uim1_data_groups[] = { + "gpio87", +}; +static const char * const uim1_present_groups[] = { + "gpio90", +}; +static const char * const uim1_reset_groups[] = { + "gpio89", +}; +static const char * const uim2_clk_groups[] = { + "gpio84", +}; +static const char * const uim2_data_groups[] = { + "gpio83", +}; +static const char * const uim2_present_groups[] = { + "gpio86", +}; +static const char * const uim2_reset_groups[] = { + "gpio85", +}; +static const char * const uim_batt_groups[] = { + "gpio91", +}; +static const char * const vfr_1_groups[] = { + "gpio27", +}; +static const char * const vsense_clkout_groups[] = { + "gpio24", +}; +static const char * const vsense_data0_groups[] = { + "gpio21", +}; +static const char * const vsense_data1_groups[] = { + "gpio22", +}; +static const char * const vsense_mode_groups[] = { + "gpio23", +}; +static const char * const wlan1_adc0_groups[] = { + "gpio9", +}; +static const char * const wlan1_adc1_groups[] = { + "gpio8", +}; +static const char * const wlan2_adc0_groups[] = { + "gpio11", +}; +static const char * const wlan2_adc1_groups[] = { + "gpio10", +}; + +static const struct msm_function sdm660_functions[] = { + FUNCTION(adsp_ext), + FUNCTION(agera_pll), + FUNCTION(atest_char), + FUNCTION(atest_char0), + FUNCTION(atest_char1), + FUNCTION(atest_char2), + FUNCTION(atest_char3), + FUNCTION(atest_gpsadc0), + FUNCTION(atest_gpsadc1), + FUNCTION(atest_tsens), + FUNCTION(atest_tsens2), + FUNCTION(atest_usb1), + FUNCTION(atest_usb10), + FUNCTION(atest_usb11), + FUNCTION(atest_usb12), + FUNCTION(atest_usb13), + FUNCTION(atest_usb2), + FUNCTION(atest_usb20), + FUNCTION(atest_usb21), + FUNCTION(atest_usb22), + FUNCTION(atest_usb23), + FUNCTION(audio_ref), + FUNCTION(bimc_dte0), + FUNCTION(bimc_dte1), + FUNCTION(blsp_i2c1), + FUNCTION(blsp_i2c2), + FUNCTION(blsp_i2c3), + FUNCTION(blsp_i2c4), + FUNCTION(blsp_i2c5), + FUNCTION(blsp_i2c6), + FUNCTION(blsp_i2c7), + FUNCTION(blsp_i2c8_a), + FUNCTION(blsp_i2c8_b), + FUNCTION(blsp_spi1), + FUNCTION(blsp_spi2), + FUNCTION(blsp_spi3), + FUNCTION(blsp_spi3_cs1), + FUNCTION(blsp_spi3_cs2), + FUNCTION(blsp_spi4), + FUNCTION(blsp_spi5), + FUNCTION(blsp_spi6), + FUNCTION(blsp_spi7), + FUNCTION(blsp_spi8_a), + FUNCTION(blsp_spi8_b), + FUNCTION(blsp_spi8_cs1), + FUNCTION(blsp_spi8_cs2), + FUNCTION(blsp_uart1), + FUNCTION(blsp_uart2), + FUNCTION(blsp_uart5), + FUNCTION(blsp_uart6_a), + FUNCTION(blsp_uart6_b), + FUNCTION(blsp_uim1), + FUNCTION(blsp_uim2), + FUNCTION(blsp_uim5), + FUNCTION(blsp_uim6), + FUNCTION(cam_mclk), + FUNCTION(cci_async), + FUNCTION(cci_i2c), + FUNCTION(cri_trng), + FUNCTION(cri_trng0), + FUNCTION(cri_trng1), + FUNCTION(dbg_out), + FUNCTION(ddr_bist), + FUNCTION(gcc_gp1), + FUNCTION(gcc_gp2), + FUNCTION(gcc_gp3), + FUNCTION(gpio), + FUNCTION(gps_tx_a), + FUNCTION(gps_tx_b), + FUNCTION(gps_tx_c), + FUNCTION(isense_dbg), + FUNCTION(jitter_bist), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(m_voc), + FUNCTION(mdp_vsync), + FUNCTION(mdss_vsync0), + FUNCTION(mdss_vsync1), + FUNCTION(mdss_vsync2), + FUNCTION(mdss_vsync3), + FUNCTION(mss_lte), + FUNCTION(nav_pps_a), + FUNCTION(nav_pps_b), + FUNCTION(nav_pps_c), + FUNCTION(pa_indicator), + FUNCTION(phase_flag0), + FUNCTION(phase_flag1), + FUNCTION(phase_flag2), + FUNCTION(phase_flag3), + FUNCTION(phase_flag4), + FUNCTION(phase_flag5), + FUNCTION(phase_flag6), + FUNCTION(phase_flag7), + FUNCTION(phase_flag8), + FUNCTION(phase_flag9), + FUNCTION(phase_flag10), + FUNCTION(phase_flag11), + FUNCTION(phase_flag12), + FUNCTION(phase_flag13), + FUNCTION(phase_flag14), + FUNCTION(phase_flag15), + FUNCTION(phase_flag16), + FUNCTION(phase_flag17), + FUNCTION(phase_flag18), + FUNCTION(phase_flag19), + FUNCTION(phase_flag20), + FUNCTION(phase_flag21), + FUNCTION(phase_flag22), + FUNCTION(phase_flag23), + FUNCTION(phase_flag24), + FUNCTION(phase_flag25), + FUNCTION(phase_flag26), + FUNCTION(phase_flag27), + FUNCTION(phase_flag28), + FUNCTION(phase_flag29), + FUNCTION(phase_flag30), + FUNCTION(phase_flag31), + FUNCTION(pll_bypassnl), + FUNCTION(pll_reset), + FUNCTION(pri_mi2s), + FUNCTION(pri_mi2s_ws), + FUNCTION(prng_rosc), + FUNCTION(pwr_crypto), + FUNCTION(pwr_modem), + FUNCTION(pwr_nav), + FUNCTION(qdss_cti0_a), + FUNCTION(qdss_cti0_b), + FUNCTION(qdss_cti1_a), + FUNCTION(qdss_cti1_b), + FUNCTION(qdss_gpio), + FUNCTION(qdss_gpio0), + FUNCTION(qdss_gpio1), + FUNCTION(qdss_gpio10), + FUNCTION(qdss_gpio11), + FUNCTION(qdss_gpio12), + FUNCTION(qdss_gpio13), + FUNCTION(qdss_gpio14), + FUNCTION(qdss_gpio15), + FUNCTION(qdss_gpio2), + FUNCTION(qdss_gpio3), + FUNCTION(qdss_gpio4), + FUNCTION(qdss_gpio5), + FUNCTION(qdss_gpio6), + FUNCTION(qdss_gpio7), + FUNCTION(qdss_gpio8), + FUNCTION(qdss_gpio9), + FUNCTION(qlink_enable), + FUNCTION(qlink_request), + FUNCTION(qspi_clk), + FUNCTION(qspi_cs), + FUNCTION(qspi_data0), + FUNCTION(qspi_data1), + FUNCTION(qspi_data2), + FUNCTION(qspi_data3), + FUNCTION(qspi_resetn), + FUNCTION(sec_mi2s), + FUNCTION(sndwire_clk), + FUNCTION(sndwire_data), + FUNCTION(sp_cmu), + FUNCTION(ssc_irq), + FUNCTION(tgu_ch0), + FUNCTION(tgu_ch1), + FUNCTION(tsense_pwm1), + FUNCTION(tsense_pwm2), + FUNCTION(uim1_clk), + FUNCTION(uim1_data), + FUNCTION(uim1_present), + FUNCTION(uim1_reset), + FUNCTION(uim2_clk), + FUNCTION(uim2_data), + FUNCTION(uim2_present), + FUNCTION(uim2_reset), + FUNCTION(uim_batt), + FUNCTION(vfr_1), + FUNCTION(vsense_clkout), + FUNCTION(vsense_data0), + FUNCTION(vsense_data1), + FUNCTION(vsense_mode), + FUNCTION(wlan1_adc0), + FUNCTION(wlan1_adc1), + FUNCTION(wlan2_adc0), + FUNCTION(wlan2_adc1), +}; + +static const struct msm_pingroup sdm660_groups[] = { + PINGROUP(0, SOUTH, blsp_spi1, blsp_uart1, blsp_uim1, tgu_ch0, _, _, qdss_gpio4, atest_gpsadc1, _), + PINGROUP(1, SOUTH, blsp_spi1, blsp_uart1, blsp_uim1, tgu_ch1, _, _, qdss_gpio5, atest_gpsadc0, _), + PINGROUP(2, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, _, _, _, _, _, _), + PINGROUP(3, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, ddr_bist, _, _, atest_tsens2, atest_usb1, _), + PINGROUP(4, NORTH, blsp_spi2, blsp_uim2, blsp_uart2, phase_flag3, _, _, _, _, _), + PINGROUP(5, SOUTH, blsp_spi2, blsp_uim2, blsp_uart2, phase_flag14, _, _, _, _, _), + PINGROUP(6, SOUTH, blsp_spi2, blsp_i2c2, blsp_uart2, phase_flag31, _, _, _, _, _), + PINGROUP(7, SOUTH, blsp_spi2, blsp_i2c2, blsp_uart2, _, _, _, _, _, _), + PINGROUP(8, NORTH, blsp_spi3, ddr_bist, _, _, _, wlan1_adc1, atest_usb13, bimc_dte1, _), + PINGROUP(9, NORTH, blsp_spi3, ddr_bist, _, _, _, wlan1_adc0, atest_usb12, bimc_dte0, _), + PINGROUP(10, NORTH, blsp_spi3, blsp_i2c3, ddr_bist, _, _, wlan2_adc1, atest_usb11, bimc_dte1, _), + PINGROUP(11, NORTH, blsp_spi3, blsp_i2c3, _, dbg_out, wlan2_adc0, atest_usb10, bimc_dte0, _, _), + PINGROUP(12, NORTH, blsp_spi4, pri_mi2s, _, phase_flag26, qdss_cti1_b, _, _, _, _), + PINGROUP(13, NORTH, blsp_spi4, _, pri_mi2s_ws, _, _, phase_flag27, qdss_cti0_b, _, _), + PINGROUP(14, NORTH, blsp_spi4, blsp_i2c4, pri_mi2s, _, phase_flag28, _, _, _, _), + PINGROUP(15, NORTH, blsp_spi4, blsp_i2c4, pri_mi2s, _, _, _, _, _, _), + PINGROUP(16, CENTER, blsp_uart5, blsp_spi5, blsp_uim5, _, _, _, _, _, _), + PINGROUP(17, CENTER, blsp_uart5, blsp_spi5, blsp_uim5, _, phase_flag5, _, _, _, _), + PINGROUP(18, CENTER, blsp_uart5, blsp_spi5, blsp_i2c5, _, _, _, _, _, _), + PINGROUP(19, CENTER, blsp_uart5, blsp_spi5, blsp_i2c5, _, _, _, _, _, _), + PINGROUP(20, SOUTH, _, _, blsp_uim6, _, _, _, _, _, _), + PINGROUP(21, SOUTH, _, _, blsp_uim6, _, phase_flag11, qdss_cti0_b, vsense_data0, _, _), + PINGROUP(22, CENTER, blsp_spi6, _, blsp_i2c6, _, phase_flag12, vsense_data1, _, _, _), + PINGROUP(23, CENTER, blsp_spi6, _, blsp_i2c6, _, phase_flag13, vsense_mode, _, _, _), + PINGROUP(24, NORTH, blsp_spi7, blsp_uart6_a, sec_mi2s, sndwire_clk, _, _, phase_flag17, vsense_clkout, _), + PINGROUP(25, NORTH, blsp_spi7, blsp_uart6_a, sec_mi2s, sndwire_data, _, _, phase_flag18, _, _), + PINGROUP(26, NORTH, blsp_spi7, blsp_uart6_a, blsp_i2c7, sec_mi2s, _, phase_flag19, _, _, _), + PINGROUP(27, NORTH, blsp_spi7, blsp_uart6_a, blsp_i2c7, vfr_1, sec_mi2s, _, phase_flag20, _, _), + PINGROUP(28, CENTER, blsp_spi8_a, blsp_uart6_b, m_voc, _, phase_flag21, _, _, _, _), + PINGROUP(29, CENTER, blsp_spi8_a, blsp_uart6_b, _, _, phase_flag22, _, _, _, _), + PINGROUP(30, CENTER, blsp_spi8_a, blsp_uart6_b, blsp_i2c8_a, blsp_spi3_cs1, _, phase_flag23, _, _, _), + PINGROUP(31, CENTER, blsp_spi8_a, blsp_uart6_b, blsp_i2c8_a, pwr_modem, _, phase_flag24, qdss_gpio, _, _), + PINGROUP(32, SOUTH, cam_mclk, pwr_nav, _, _, qdss_gpio0, _, _, _, _), + PINGROUP(33, SOUTH, cam_mclk, qspi_data0, pwr_crypto, _, _, qdss_gpio1, _, _, _), + PINGROUP(34, SOUTH, cam_mclk, qspi_data1, agera_pll, _, _, qdss_gpio2, _, _, _), + PINGROUP(35, SOUTH, cam_mclk, qspi_data2, jitter_bist, _, _, qdss_gpio3, _, atest_usb2, _), + PINGROUP(36, SOUTH, cci_i2c, pll_bypassnl, agera_pll, _, _, qdss_gpio4, atest_tsens, atest_usb21, _), + PINGROUP(37, SOUTH, cci_i2c, pll_reset, _, _, qdss_gpio5, atest_usb23, _, _, _), + PINGROUP(38, SOUTH, cci_i2c, _, _, qdss_gpio6, _, _, _, _, _), + PINGROUP(39, SOUTH, cci_i2c, _, _, qdss_gpio7, _, _, _, _, _), + PINGROUP(40, SOUTH, _, _, blsp_spi8_b, _, _, _, _, _, _), + PINGROUP(41, SOUTH, _, _, blsp_spi8_b, _, _, _, _, _, _), + PINGROUP(42, SOUTH, mdss_vsync0, mdss_vsync1, mdss_vsync2, mdss_vsync3, _, _, qdss_gpio9, _, _), + PINGROUP(43, SOUTH, _, _, qspi_cs, _, _, qdss_gpio10, _, _, _), + PINGROUP(44, SOUTH, _, _, blsp_spi8_b, blsp_i2c8_b, _, _, qdss_gpio11, _, _), + PINGROUP(45, SOUTH, cci_async, _, _, qdss_gpio12, _, _, _, _, _), + PINGROUP(46, SOUTH, blsp_spi1, _, _, qdss_gpio13, _, _, _, _, _), + PINGROUP(47, SOUTH, qspi_clk, _, phase_flag30, qdss_gpio14, _, _, _, _, _), + PINGROUP(48, SOUTH, _, phase_flag1, qdss_gpio15, _, _, _, _, _, _), + PINGROUP(49, SOUTH, blsp_spi6, phase_flag2, qdss_cti0_a, _, _, _, _, _, _), + PINGROUP(50, SOUTH, qspi_cs, _, phase_flag9, qdss_cti0_a, _, _, _, _, _), + PINGROUP(51, SOUTH, qspi_data3, _, phase_flag15, qdss_gpio8, _, _, _, _, _), + PINGROUP(52, SOUTH, _, blsp_spi8_b, blsp_i2c8_b, blsp_spi6, phase_flag16, qdss_gpio, _, _, _), + PINGROUP(53, NORTH, _, phase_flag6, qdss_cti1_a, _, _, _, _, _, _), + PINGROUP(54, NORTH, _, _, phase_flag29, _, _, _, _, _, _), + PINGROUP(55, SOUTH, _, phase_flag25, qdss_cti1_a, _, _, _, _, _, _), + PINGROUP(56, SOUTH, _, phase_flag10, qdss_gpio3, _, atest_usb20, _, _, _, _), + PINGROUP(57, SOUTH, gcc_gp1, _, phase_flag4, atest_usb22, _, _, _, _, _), + PINGROUP(58, SOUTH, _, gcc_gp2, _, _, atest_char, _, _, _, _), + PINGROUP(59, NORTH, mdp_vsync, gcc_gp3, _, _, atest_char3, _, _, _, _), + PINGROUP(60, NORTH, cri_trng0, _, _, atest_char2, _, _, _, _, _), + PINGROUP(61, NORTH, pri_mi2s, cri_trng1, _, _, atest_char1, _, _, _, _), + PINGROUP(62, NORTH, sec_mi2s, audio_ref, _, cri_trng, _, _, atest_char0, _, _), + PINGROUP(63, NORTH, _, _, _, qdss_gpio1, _, _, _, _, _), + PINGROUP(64, SOUTH, blsp_spi8_cs1, sp_cmu, _, _, qdss_gpio2, _, _, _, _), + PINGROUP(65, SOUTH, _, nav_pps_a, nav_pps_a, gps_tx_a, blsp_spi3_cs2, adsp_ext, _, _, _), + PINGROUP(66, NORTH, _, _, qdss_cti1_b, _, _, _, _, _, _), + PINGROUP(67, NORTH, _, _, qdss_gpio0, _, _, _, _, _, _), + PINGROUP(68, NORTH, isense_dbg, _, phase_flag0, qdss_gpio, _, _, _, _, _), + PINGROUP(69, NORTH, _, phase_flag7, qdss_gpio, _, _, _, _, _, _), + PINGROUP(70, NORTH, _, phase_flag8, qdss_gpio6, _, _, _, _, _, _), + PINGROUP(71, NORTH, _, _, qdss_gpio7, tsense_pwm1, tsense_pwm2, _, _, _, _), + PINGROUP(72, NORTH, _, qdss_gpio14, _, _, _, _, _, _, _), + PINGROUP(73, NORTH, _, _, qdss_gpio15, _, _, _, _, _, _), + PINGROUP(74, NORTH, mdp_vsync, _, _, _, _, _, _, _, _), + PINGROUP(75, NORTH, _, _, qdss_gpio8, _, _, _, _, _, _), + PINGROUP(76, NORTH, blsp_spi8_cs2, _, _, _, qdss_gpio9, _, _, _, _), + PINGROUP(77, NORTH, _, _, qdss_gpio10, _, _, _, _, _, _), + PINGROUP(78, NORTH, gcc_gp1, _, qdss_gpio13, _, _, _, _, _, _), + PINGROUP(79, SOUTH, _, _, qdss_gpio11, _, _, _, _, _, _), + PINGROUP(80, SOUTH, nav_pps_b, nav_pps_b, gps_tx_c, _, _, qdss_gpio12, _, _, _), + PINGROUP(81, CENTER, mss_lte, gcc_gp2, _, _, _, _, _, _, _), + PINGROUP(82, CENTER, mss_lte, gcc_gp3, _, _, _, _, _, _, _), + PINGROUP(83, SOUTH, uim2_data, _, _, _, _, _, _, _, _), + PINGROUP(84, SOUTH, uim2_clk, _, _, _, _, _, _, _, _), + PINGROUP(85, SOUTH, uim2_reset, _, _, _, _, _, _, _, _), + PINGROUP(86, SOUTH, uim2_present, _, _, _, _, _, _, _, _), + PINGROUP(87, SOUTH, uim1_data, _, _, _, _, _, _, _, _), + PINGROUP(88, SOUTH, uim1_clk, _, _, _, _, _, _, _, _), + PINGROUP(89, SOUTH, uim1_reset, _, _, _, _, _, _, _, _), + PINGROUP(90, SOUTH, uim1_present, _, _, _, _, _, _, _, _), + PINGROUP(91, SOUTH, uim_batt, _, _, _, _, _, _, _, _), + PINGROUP(92, SOUTH, _, _, pa_indicator, _, _, _, _, _, _), + PINGROUP(93, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(94, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(95, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(96, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(97, SOUTH, _, ldo_en, _, _, _, _, _, _, _), + PINGROUP(98, SOUTH, _, nav_pps_c, nav_pps_c, gps_tx_b, ldo_update, _, _, _, _), + PINGROUP(99, SOUTH, qlink_request, _, _, _, _, _, _, _, _), + PINGROUP(100, SOUTH, qlink_enable, _, _, _, _, _, _, _, _), + PINGROUP(101, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(102, SOUTH, _, prng_rosc, _, _, _, _, _, _, _), + PINGROUP(103, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(104, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(105, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(106, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(107, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(108, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(109, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(110, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(111, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(112, SOUTH, _, _, _, _, _, _, _, _, _), + PINGROUP(113, SOUTH, _, _, _, _, _, _, _, _, _), + SDC_QDSD_PINGROUP(sdc1_clk, 0x99a000, 13, 6), + SDC_QDSD_PINGROUP(sdc1_cmd, 0x99a000, 11, 3), + SDC_QDSD_PINGROUP(sdc1_data, 0x99a000, 9, 0), + SDC_QDSD_PINGROUP(sdc2_clk, 0x99b000, 14, 6), + SDC_QDSD_PINGROUP(sdc2_cmd, 0x99b000, 11, 3), + SDC_QDSD_PINGROUP(sdc2_data, 0x99b000, 9, 0), + SDC_QDSD_PINGROUP(sdc1_rclk, 0x99a000, 15, 0), +}; + +static const struct msm_pinctrl_soc_data sdm660_pinctrl = { + .pins = sdm660_pins, + .npins = ARRAY_SIZE(sdm660_pins), + .functions = sdm660_functions, + .nfunctions = ARRAY_SIZE(sdm660_functions), + .groups = sdm660_groups, + .ngroups = ARRAY_SIZE(sdm660_groups), + .ngpios = 114, + .tiles = sdm660_tiles, + .ntiles = ARRAY_SIZE(sdm660_tiles), +}; + +static int sdm660_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &sdm660_pinctrl); +} + +static const struct of_device_id sdm660_pinctrl_of_match[] = { + { .compatible = "qcom,sdm660-pinctrl", }, + { .compatible = "qcom,sdm630-pinctrl", }, + { }, +}; + +static struct platform_driver sdm660_pinctrl_driver = { + .driver = { + .name = "sdm660-pinctrl", + .of_match_table = sdm660_pinctrl_of_match, + }, + .probe = sdm660_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init sdm660_pinctrl_init(void) +{ + return platform_driver_register(&sdm660_pinctrl_driver); +} +arch_initcall(sdm660_pinctrl_init); + +static void __exit sdm660_pinctrl_exit(void) +{ + platform_driver_unregister(&sdm660_pinctrl_driver); +} +module_exit(sdm660_pinctrl_exit); + +MODULE_DESCRIPTION("QTI sdm660 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, sdm660_pinctrl_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index cf82db78e69e..a29efbe08f48 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 6556dbeae65e..d6ddc47b57ec 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> @@ -319,6 +319,8 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, pad->function = function; ret = pmic_mpp_write_mode_ctl(state, pad); + if (ret < 0) + return ret; val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; @@ -343,13 +345,12 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, switch (param) { case PIN_CONFIG_BIAS_DISABLE: - arg = pad->pullup == PMIC_MPP_PULL_UP_OPEN; + if (pad->pullup != PMIC_MPP_PULL_UP_OPEN) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_UP: switch (pad->pullup) { - case PMIC_MPP_PULL_UP_OPEN: - arg = 0; - break; case PMIC_MPP_PULL_UP_0P6KOHM: arg = 600; break; @@ -364,13 +365,17 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, } break; case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: - arg = !pad->is_enabled; + if (pad->is_enabled) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_POWER_SOURCE: arg = pad->power_source; break; case PIN_CONFIG_INPUT_ENABLE: - arg = pad->input_enabled; + if (!pad->input_enabled) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_OUTPUT: arg = pad->out_value; @@ -382,7 +387,9 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, arg = pad->amux_input; break; case PMIC_MPP_CONF_PAIRED: - arg = pad->paired; + if (!pad->paired) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_DRIVE_STRENGTH: arg = pad->drive_strength; @@ -455,7 +462,7 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->dtest = arg; break; case PIN_CONFIG_DRIVE_STRENGTH: - arg = pad->drive_strength; + pad->drive_strength = arg; break; case PMIC_MPP_CONF_AMUX_ROUTE: if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4) @@ -502,6 +509,10 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_SINK_CTL, pad->drive_strength); + if (ret < 0) + return ret; + val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index f53e32a9d8fc..6b30bef829ab 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -20,7 +20,7 @@ #include <linux/pinctrl/pinconf-generic.h> #include <linux/slab.h> #include <linux/regmap.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/of_device.h> #include <linux/of_irq.h> @@ -260,22 +260,32 @@ static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, switch (param) { case PIN_CONFIG_BIAS_DISABLE: - arg = pin->bias == PM8XXX_GPIO_BIAS_NP; + if (pin->bias != PM8XXX_GPIO_BIAS_NP) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_DOWN: - arg = pin->bias == PM8XXX_GPIO_BIAS_PD; + if (pin->bias != PM8XXX_GPIO_BIAS_PD) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_UP: - arg = pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30; + if (pin->bias > PM8XXX_GPIO_BIAS_PU_1P5_30) + return -EINVAL; + arg = 1; break; case PM8XXX_QCOM_PULL_UP_STRENGTH: arg = pin->pull_up_strength; break; case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: - arg = pin->disable; + if (!pin->disable) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_INPUT_ENABLE: - arg = pin->mode == PM8XXX_GPIO_MODE_INPUT; + if (pin->mode != PM8XXX_GPIO_MODE_INPUT) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_OUTPUT: if (pin->mode & PM8XXX_GPIO_MODE_OUTPUT) @@ -290,10 +300,14 @@ static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, arg = pin->output_strength; break; case PIN_CONFIG_DRIVE_PUSH_PULL: - arg = !pin->open_drain; + if (pin->open_drain) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - arg = pin->open_drain; + if (!pin->open_drain) + return -EINVAL; + arg = 1; break; default: return -EINVAL; diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c index 1e513bd6d0a9..1a7dab150ef6 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c @@ -20,7 +20,7 @@ #include <linux/pinctrl/pinconf-generic.h> #include <linux/slab.h> #include <linux/regmap.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> #include <linux/of_device.h> #include <linux/of_irq.h> diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 698c7d8c9a08..ee6ee2338606 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -20,7 +20,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/irqdomain.h> #include <linux/of_device.h> #include <linux/spinlock.h> diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index e571bbd7139b..379f34a9a482 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -19,7 +19,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/machine.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> /** * enum pincfg_type - possible pin configuration types supported. diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig index 43d950c16528..e941ba60d4b7 100644 --- a/drivers/pinctrl/sh-pfc/Kconfig +++ b/drivers/pinctrl/sh-pfc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Renesas SH and SH Mobile PINCTRL drivers # @@ -39,6 +40,11 @@ config PINCTRL_PFC_R8A7743 depends on ARCH_R8A7743 select PINCTRL_SH_PFC +config PINCTRL_PFC_R8A7744 + def_bool y + depends on ARCH_R8A7744 + select PINCTRL_SH_PFC + config PINCTRL_PFC_R8A7745 def_bool y depends on ARCH_R8A7745 @@ -49,6 +55,16 @@ config PINCTRL_PFC_R8A77470 depends on ARCH_R8A77470 select PINCTRL_SH_PFC +config PINCTRL_PFC_R8A774A1 + def_bool y + depends on ARCH_R8A774A1 + select PINCTRL_SH_PFC + +config PINCTRL_PFC_R8A774C0 + def_bool y + depends on ARCH_R8A774C0 + select PINCTRL_SH_PFC + config PINCTRL_PFC_R8A7778 def_bool y depends on ARCH_R8A7778 diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile index d0b29c51c159..82ebb2a91ee0 100644 --- a/drivers/pinctrl/sh-pfc/Makefile +++ b/drivers/pinctrl/sh-pfc/Makefile @@ -5,8 +5,11 @@ obj-$(CONFIG_PINCTRL_PFC_EMEV2) += pfc-emev2.o obj-$(CONFIG_PINCTRL_PFC_R8A73A4) += pfc-r8a73a4.o obj-$(CONFIG_PINCTRL_PFC_R8A7740) += pfc-r8a7740.o obj-$(CONFIG_PINCTRL_PFC_R8A7743) += pfc-r8a7791.o +obj-$(CONFIG_PINCTRL_PFC_R8A7744) += pfc-r8a7791.o obj-$(CONFIG_PINCTRL_PFC_R8A7745) += pfc-r8a7794.o obj-$(CONFIG_PINCTRL_PFC_R8A77470) += pfc-r8a77470.o +obj-$(CONFIG_PINCTRL_PFC_R8A774A1) += pfc-r8a7796.o +obj-$(CONFIG_PINCTRL_PFC_R8A774C0) += pfc-r8a77990.o obj-$(CONFIG_PINCTRL_PFC_R8A7778) += pfc-r8a7778.o obj-$(CONFIG_PINCTRL_PFC_R8A7779) += pfc-r8a7779.o obj-$(CONFIG_PINCTRL_PFC_R8A7790) += pfc-r8a7790.o diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index c671c3c4aca6..a10f7050a74f 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Pin Control and GPIO driver for SuperH Pin Function Controller. * @@ -5,10 +6,6 @@ * * Copyright (C) 2008 Magnus Damm * Copyright (C) 2009 - 2012 Paul Mundt - * - * 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. */ #define DRV_NAME "sh-pfc" @@ -497,6 +494,12 @@ static const struct of_device_id sh_pfc_of_table[] = { .data = &r8a7743_pinmux_info, }, #endif +#ifdef CONFIG_PINCTRL_PFC_R8A7744 + { + .compatible = "renesas,pfc-r8a7744", + .data = &r8a7744_pinmux_info, + }, +#endif #ifdef CONFIG_PINCTRL_PFC_R8A7745 { .compatible = "renesas,pfc-r8a7745", @@ -509,6 +512,18 @@ static const struct of_device_id sh_pfc_of_table[] = { .data = &r8a77470_pinmux_info, }, #endif +#ifdef CONFIG_PINCTRL_PFC_R8A774A1 + { + .compatible = "renesas,pfc-r8a774a1", + .data = &r8a774a1_pinmux_info, + }, +#endif +#ifdef CONFIG_PINCTRL_PFC_R8A774C0 + { + .compatible = "renesas,pfc-r8a774c0", + .data = &r8a774c0_pinmux_info, + }, +#endif #ifdef CONFIG_PINCTRL_PFC_R8A7778 { .compatible = "renesas,pfc-r8a7778", diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h index 5af8ee26c03e..b5b1d163e98a 100644 --- a/drivers/pinctrl/sh-pfc/core.h +++ b/drivers/pinctrl/sh-pfc/core.h @@ -1,11 +1,8 @@ -/* +/* SPDX-License-Identifier: GPL-2.0 + * * SuperH Pin Function Controller support. * * Copyright (C) 2012 Renesas Solutions Corp. - * - * 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 __SH_PFC_CORE_H__ #define __SH_PFC_CORE_H__ diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c index 6ffdc6beb203..4f3a34ee1cd4 100644 --- a/drivers/pinctrl/sh-pfc/gpio.c +++ b/drivers/pinctrl/sh-pfc/gpio.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH Pin Function Controller GPIO driver. * * Copyright (C) 2008 Magnus Damm * Copyright (C) 2009 - 2012 Paul Mundt - * - * 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. */ #include <linux/device.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c index 1cbbe04d7df6..dc271c3243df 100644 --- a/drivers/pinctrl/sh-pfc/pfc-emev2.c +++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Pin Function Controller Support * * Copyright (C) 2015 Niklas Söderlund - * - * 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. */ #include <linux/init.h> #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c index ff5655dee67e..5acbacb3727f 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2012-2013 Renesas Solutions Corp. * Copyright (C) 2013 Magnus Damm * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/io.h> #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index 35f436bcb849..d4f81491996d 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * R8A7740 processor support * * Copyright (C) 2011 Renesas Solutions Corp. * Copyright (C) 2011 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/io.h> #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c index 9d3ed438ec7b..3d36e5f4ca7b 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c @@ -1093,6 +1093,233 @@ static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), }; +/* - AVB -------------------------------------------------------------------- */ +static const unsigned int avb_col_pins[] = { + RCAR_GP_PIN(5, 18), +}; +static const unsigned int avb_col_mux[] = { + AVB_COL_MARK, +}; +static const unsigned int avb_crs_pins[] = { + RCAR_GP_PIN(5, 17), +}; +static const unsigned int avb_crs_mux[] = { + AVB_CRS_MARK, +}; +static const unsigned int avb_link_pins[] = { + RCAR_GP_PIN(5, 14), +}; +static const unsigned int avb_link_mux[] = { + AVB_LINK_MARK, +}; +static const unsigned int avb_magic_pins[] = { + RCAR_GP_PIN(5, 15), +}; +static const unsigned int avb_magic_mux[] = { + AVB_MAGIC_MARK, +}; +static const unsigned int avb_phy_int_pins[] = { + RCAR_GP_PIN(5, 16), +}; +static const unsigned int avb_phy_int_mux[] = { + AVB_PHY_INT_MARK, +}; +static const unsigned int avb_mdio_pins[] = { + RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 13), +}; +static const unsigned int avb_mdio_mux[] = { + AVB_MDC_MARK, AVB_MDIO_MARK, +}; +static const unsigned int avb_mii_tx_rx_pins[] = { + RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), + RCAR_GP_PIN(3, 16), RCAR_GP_PIN(3, 27), RCAR_GP_PIN(3, 13), + + RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), + RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), RCAR_GP_PIN(3, 1), + RCAR_GP_PIN(3, 10), +}; +static const unsigned int avb_mii_tx_rx_mux[] = { + AVB_TX_CLK_MARK, AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK, + AVB_TXD3_MARK, AVB_TX_EN_MARK, + + AVB_RX_CLK_MARK, AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK, + AVB_RXD3_MARK, AVB_RX_DV_MARK, AVB_RX_ER_MARK, +}; +static const unsigned int avb_mii_tx_er_pins[] = { + RCAR_GP_PIN(5, 23), +}; +static const unsigned int avb_mii_tx_er_mux[] = { + AVB_TX_ER_MARK, +}; +static const unsigned int avb_gmii_tx_rx_pins[] = { + RCAR_GP_PIN(4, 1), RCAR_GP_PIN(3, 11), RCAR_GP_PIN(3, 12), + RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 16), + RCAR_GP_PIN(3, 27), RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 29), + RCAR_GP_PIN(4, 0), RCAR_GP_PIN(5, 22), RCAR_GP_PIN(3, 13), + RCAR_GP_PIN(5, 23), + + RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), + RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), RCAR_GP_PIN(3, 6), + RCAR_GP_PIN(3, 7), RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), + RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 10), +}; +static const unsigned int avb_gmii_tx_rx_mux[] = { + AVB_GTX_CLK_MARK, AVB_GTXREFCLK_MARK, AVB_TX_CLK_MARK, AVB_TXD0_MARK, + AVB_TXD1_MARK, AVB_TXD2_MARK, AVB_TXD3_MARK, AVB_TXD4_MARK, + AVB_TXD5_MARK, AVB_TXD6_MARK, AVB_TXD7_MARK, AVB_TX_EN_MARK, + AVB_TX_ER_MARK, + + AVB_RX_CLK_MARK, AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK, + AVB_RXD3_MARK, AVB_RXD4_MARK, AVB_RXD5_MARK, AVB_RXD6_MARK, + AVB_RXD7_MARK, AVB_RX_DV_MARK, AVB_RX_ER_MARK, +}; +static const unsigned int avb_avtp_match_a_pins[] = { + RCAR_GP_PIN(1, 15), +}; +static const unsigned int avb_avtp_match_a_mux[] = { + AVB_AVTP_MATCH_A_MARK, +}; +static const unsigned int avb_avtp_capture_a_pins[] = { + RCAR_GP_PIN(1, 14), +}; +static const unsigned int avb_avtp_capture_a_mux[] = { + AVB_AVTP_CAPTURE_A_MARK, +}; +static const unsigned int avb_avtp_match_b_pins[] = { + RCAR_GP_PIN(5, 20), +}; +static const unsigned int avb_avtp_match_b_mux[] = { + AVB_AVTP_MATCH_B_MARK, +}; +static const unsigned int avb_avtp_capture_b_pins[] = { + RCAR_GP_PIN(5, 19), +}; +static const unsigned int avb_avtp_capture_b_mux[] = { + AVB_AVTP_CAPTURE_B_MARK, +}; +/* - DU --------------------------------------------------------------------- */ +static const unsigned int du0_rgb666_pins[] = { + /* R[7:2], G[7:2], B[7:2] */ + RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 5), + RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 3), RCAR_GP_PIN(2, 2), + RCAR_GP_PIN(2, 15), RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13), + RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 10), + RCAR_GP_PIN(2, 23), RCAR_GP_PIN(2, 22), RCAR_GP_PIN(2, 21), + RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 19), RCAR_GP_PIN(2, 18), +}; +static const unsigned int du0_rgb666_mux[] = { + DU0_DR7_MARK, DU0_DR6_MARK, DU0_DR5_MARK, DU0_DR4_MARK, + DU0_DR3_MARK, DU0_DR2_MARK, + DU0_DG7_MARK, DU0_DG6_MARK, DU0_DG5_MARK, DU0_DG4_MARK, + DU0_DG3_MARK, DU0_DG2_MARK, + DU0_DB7_MARK, DU0_DB6_MARK, DU0_DB5_MARK, DU0_DB4_MARK, + DU0_DB3_MARK, DU0_DB2_MARK, +}; +static const unsigned int du0_rgb888_pins[] = { + /* R[7:0], G[7:0], B[7:0] */ + RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 5), + RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 3), RCAR_GP_PIN(2, 2), + RCAR_GP_PIN(2, 1), RCAR_GP_PIN(2, 0), + RCAR_GP_PIN(2, 15), RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13), + RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 10), + RCAR_GP_PIN(2, 9), RCAR_GP_PIN(2, 8), + RCAR_GP_PIN(2, 23), RCAR_GP_PIN(2, 22), RCAR_GP_PIN(2, 21), + RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 19), RCAR_GP_PIN(2, 18), + RCAR_GP_PIN(2, 17), RCAR_GP_PIN(2, 16), +}; +static const unsigned int du0_rgb888_mux[] = { + DU0_DR7_MARK, DU0_DR6_MARK, DU0_DR5_MARK, DU0_DR4_MARK, + DU0_DR3_MARK, DU0_DR2_MARK, DU0_DR1_MARK, DU0_DR0_MARK, + DU0_DG7_MARK, DU0_DG6_MARK, DU0_DG5_MARK, DU0_DG4_MARK, + DU0_DG3_MARK, DU0_DG2_MARK, DU0_DG1_MARK, DU0_DG0_MARK, + DU0_DB7_MARK, DU0_DB6_MARK, DU0_DB5_MARK, DU0_DB4_MARK, + DU0_DB3_MARK, DU0_DB2_MARK, DU0_DB1_MARK, DU0_DB0_MARK, +}; +static const unsigned int du0_clk0_out_pins[] = { + /* DOTCLKOUT0 */ + RCAR_GP_PIN(2, 25), +}; +static const unsigned int du0_clk0_out_mux[] = { + DU0_DOTCLKOUT0_MARK +}; +static const unsigned int du0_clk1_out_pins[] = { + /* DOTCLKOUT1 */ + RCAR_GP_PIN(2, 26), +}; +static const unsigned int du0_clk1_out_mux[] = { + DU0_DOTCLKOUT1_MARK +}; +static const unsigned int du0_clk_in_pins[] = { + /* CLKIN */ + RCAR_GP_PIN(2, 24), +}; +static const unsigned int du0_clk_in_mux[] = { + DU0_DOTCLKIN_MARK +}; +static const unsigned int du0_sync_pins[] = { + /* EXVSYNC/VSYNC, EXHSYNC/HSYNC */ + RCAR_GP_PIN(2, 28), RCAR_GP_PIN(2, 27), +}; +static const unsigned int du0_sync_mux[] = { + DU0_EXVSYNC_DU0_VSYNC_MARK, DU0_EXHSYNC_DU0_HSYNC_MARK +}; +static const unsigned int du0_oddf_pins[] = { + /* EXODDF/ODDF/DISP/CDE */ + RCAR_GP_PIN(2, 29), +}; +static const unsigned int du0_oddf_mux[] = { + DU0_EXODDF_DU0_ODDF_DISP_CDE_MARK, +}; +static const unsigned int du0_cde_pins[] = { + /* CDE */ + RCAR_GP_PIN(2, 31), +}; +static const unsigned int du0_cde_mux[] = { + DU0_CDE_MARK, +}; +static const unsigned int du0_disp_pins[] = { + /* DISP */ + RCAR_GP_PIN(2, 30), +}; +static const unsigned int du0_disp_mux[] = { + DU0_DISP_MARK +}; +/* - I2C4 ------------------------------------------------------------------- */ +static const unsigned int i2c4_a_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(4, 10), RCAR_GP_PIN(4, 11), +}; +static const unsigned int i2c4_a_mux[] = { + SCL4_A_MARK, SDA4_A_MARK, +}; +static const unsigned int i2c4_b_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(5, 30), RCAR_GP_PIN(5, 31), +}; +static const unsigned int i2c4_b_mux[] = { + SCL4_B_MARK, SDA4_B_MARK, +}; +static const unsigned int i2c4_c_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 5), +}; +static const unsigned int i2c4_c_mux[] = { + SCL4_C_MARK, SDA4_C_MARK, +}; +static const unsigned int i2c4_d_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 17), +}; +static const unsigned int i2c4_d_mux[] = { + SCL4_D_MARK, SDA4_D_MARK, +}; +static const unsigned int i2c4_e_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 6), +}; +static const unsigned int i2c4_e_mux[] = { + SCL4_E_MARK, SDA4_E_MARK, +}; /* - MMC -------------------------------------------------------------------- */ static const unsigned int mmc_data1_pins[] = { /* D0 */ @@ -1130,6 +1357,30 @@ static const unsigned int mmc_ctrl_pins[] = { static const unsigned int mmc_ctrl_mux[] = { MMC0_CLK_SDHI1_CLK_MARK, MMC0_CMD_SDHI1_CMD_MARK, }; +/* - QSPI ------------------------------------------------------------------- */ +static const unsigned int qspi0_ctrl_pins[] = { + /* SPCLK, SSL */ + RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 21), +}; +static const unsigned int qspi0_ctrl_mux[] = { + QSPI0_SPCLK_MARK, QSPI0_SSL_MARK, +}; +static const unsigned int qspi0_data2_pins[] = { + /* MOSI_IO0, MISO_IO1 */ + RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 18), +}; +static const unsigned int qspi0_data2_mux[] = { + QSPI0_MOSI_QSPI0_IO0_MARK, QSPI0_MISO_QSPI0_IO1_MARK, +}; +static const unsigned int qspi0_data4_pins[] = { + /* MOSI_IO0, MISO_IO1, IO2, IO3 */ + RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 18), RCAR_GP_PIN(1, 19), + RCAR_GP_PIN(1, 20), +}; +static const unsigned int qspi0_data4_mux[] = { + QSPI0_MOSI_QSPI0_IO0_MARK, QSPI0_MISO_QSPI0_IO1_MARK, + QSPI0_IO2_MARK, QSPI0_IO3_MARK, +}; /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_a_pins[] = { /* RX, TX */ @@ -1368,12 +1619,97 @@ static const unsigned int scif_clk_b_pins[] = { static const unsigned int scif_clk_b_mux[] = { SCIF_CLK_B_MARK, }; +/* - SDHI2 ------------------------------------------------------------------ */ +static const unsigned int sdhi2_data1_pins[] = { + /* D0 */ + RCAR_GP_PIN(4, 16), +}; +static const unsigned int sdhi2_data1_mux[] = { + SD2_DAT0_MARK, +}; +static const unsigned int sdhi2_data4_pins[] = { + /* D[0:3] */ + RCAR_GP_PIN(4, 16), RCAR_GP_PIN(4, 17), + RCAR_GP_PIN(4, 18), RCAR_GP_PIN(4, 19), +}; +static const unsigned int sdhi2_data4_mux[] = { + SD2_DAT0_MARK, SD2_DAT1_MARK, SD2_DAT2_MARK, SD2_DAT3_MARK, +}; +static const unsigned int sdhi2_ctrl_pins[] = { + /* CLK, CMD */ + RCAR_GP_PIN(4, 14), RCAR_GP_PIN(4, 15), +}; +static const unsigned int sdhi2_ctrl_mux[] = { + SD2_CLK_MARK, SD2_CMD_MARK, +}; +static const unsigned int sdhi2_cd_pins[] = { + /* CD */ + RCAR_GP_PIN(4, 20), +}; +static const unsigned int sdhi2_cd_mux[] = { + SD2_CD_MARK, +}; +static const unsigned int sdhi2_wp_pins[] = { + /* WP */ + RCAR_GP_PIN(4, 21), +}; +static const unsigned int sdhi2_wp_mux[] = { + SD2_WP_MARK, +}; +/* - USB0 ------------------------------------------------------------------- */ +static const unsigned int usb0_pins[] = { + RCAR_GP_PIN(0, 0), /* PWEN */ + RCAR_GP_PIN(0, 1), /* OVC */ +}; +static const unsigned int usb0_mux[] = { + USB0_PWEN_MARK, + USB0_OVC_MARK, +}; +/* - USB1 ------------------------------------------------------------------- */ +static const unsigned int usb1_pins[] = { + RCAR_GP_PIN(0, 2), /* PWEN */ + RCAR_GP_PIN(0, 3), /* OVC */ +}; +static const unsigned int usb1_mux[] = { + USB1_PWEN_MARK, + USB1_OVC_MARK, +}; static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(avb_col), + SH_PFC_PIN_GROUP(avb_crs), + SH_PFC_PIN_GROUP(avb_link), + SH_PFC_PIN_GROUP(avb_magic), + SH_PFC_PIN_GROUP(avb_phy_int), + SH_PFC_PIN_GROUP(avb_mdio), + SH_PFC_PIN_GROUP(avb_mii_tx_rx), + SH_PFC_PIN_GROUP(avb_mii_tx_er), + SH_PFC_PIN_GROUP(avb_gmii_tx_rx), + SH_PFC_PIN_GROUP(avb_avtp_match_a), + SH_PFC_PIN_GROUP(avb_avtp_capture_a), + SH_PFC_PIN_GROUP(avb_avtp_match_b), + SH_PFC_PIN_GROUP(avb_avtp_capture_b), + SH_PFC_PIN_GROUP(du0_rgb666), + SH_PFC_PIN_GROUP(du0_rgb888), + SH_PFC_PIN_GROUP(du0_clk0_out), + SH_PFC_PIN_GROUP(du0_clk1_out), + SH_PFC_PIN_GROUP(du0_clk_in), + SH_PFC_PIN_GROUP(du0_sync), + SH_PFC_PIN_GROUP(du0_oddf), + SH_PFC_PIN_GROUP(du0_cde), + SH_PFC_PIN_GROUP(du0_disp), + SH_PFC_PIN_GROUP(i2c4_a), + SH_PFC_PIN_GROUP(i2c4_b), + SH_PFC_PIN_GROUP(i2c4_c), + SH_PFC_PIN_GROUP(i2c4_d), + SH_PFC_PIN_GROUP(i2c4_e), SH_PFC_PIN_GROUP(mmc_data1), SH_PFC_PIN_GROUP(mmc_data4), SH_PFC_PIN_GROUP(mmc_data8), SH_PFC_PIN_GROUP(mmc_ctrl), + SH_PFC_PIN_GROUP(qspi0_ctrl), + SH_PFC_PIN_GROUP(qspi0_data2), + SH_PFC_PIN_GROUP(qspi0_data4), SH_PFC_PIN_GROUP(scif0_data_a), SH_PFC_PIN_GROUP(scif0_data_b), SH_PFC_PIN_GROUP(scif0_data_c), @@ -1407,6 +1743,49 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(scif5_data_f), SH_PFC_PIN_GROUP(scif_clk_a), SH_PFC_PIN_GROUP(scif_clk_b), + SH_PFC_PIN_GROUP(sdhi2_data1), + SH_PFC_PIN_GROUP(sdhi2_data4), + SH_PFC_PIN_GROUP(sdhi2_ctrl), + SH_PFC_PIN_GROUP(sdhi2_cd), + SH_PFC_PIN_GROUP(sdhi2_wp), + SH_PFC_PIN_GROUP(usb0), + SH_PFC_PIN_GROUP(usb1), +}; + +static const char * const avb_groups[] = { + "avb_col", + "avb_crs", + "avb_link", + "avb_magic", + "avb_phy_int", + "avb_mdio", + "avb_mii_tx_rx", + "avb_mii_tx_er", + "avb_gmii_tx_rx", + "avb_avtp_match_a", + "avb_avtp_capture_a", + "avb_avtp_match_b", + "avb_avtp_capture_b", +}; + +static const char * const du0_groups[] = { + "du0_rgb666", + "du0_rgb888", + "du0_clk0_out", + "du0_clk1_out", + "du0_clk_in", + "du0_sync", + "du0_oddf", + "du0_cde", + "du0_disp", +}; + +static const char * const i2c4_groups[] = { + "i2c4_a", + "i2c4_b", + "i2c4_c", + "i2c4_d", + "i2c4_e", }; static const char * const mmc_groups[] = { @@ -1416,6 +1795,12 @@ static const char * const mmc_groups[] = { "mmc_ctrl", }; +static const char * const qspi0_groups[] = { + "qspi0_ctrl", + "qspi0_data2", + "qspi0_data4", +}; + static const char * const scif0_groups[] = { "scif0_data_a", "scif0_data_b", @@ -1470,8 +1855,28 @@ static const char * const scif_clk_groups[] = { "scif_clk_b", }; +static const char * const sdhi2_groups[] = { + "sdhi2_data1", + "sdhi2_data4", + "sdhi2_ctrl", + "sdhi2_cd", + "sdhi2_wp", +}; + +static const char * const usb0_groups[] = { + "usb0", +}; + +static const char * const usb1_groups[] = { + "usb1", +}; + static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(avb), + SH_PFC_FUNCTION(du0), + SH_PFC_FUNCTION(i2c4), SH_PFC_FUNCTION(mmc), + SH_PFC_FUNCTION(qspi0), SH_PFC_FUNCTION(scif0), SH_PFC_FUNCTION(scif1), SH_PFC_FUNCTION(scif2), @@ -1479,6 +1884,9 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(scif4), SH_PFC_FUNCTION(scif5), SH_PFC_FUNCTION(scif_clk), + SH_PFC_FUNCTION(sdhi2), + SH_PFC_FUNCTION(usb0), + SH_PFC_FUNCTION(usb1), }; static const struct pinmux_cfg_reg pinmux_config_regs[] = { diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c index 00d61d175249..6bcdb4b5e69e 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * r8a7778 processor support - PFC hardware block * @@ -9,15 +10,6 @@ * based on * Copyright (C) 2011 Renesas Solutions Corp. * Copyright (C) 2011 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/io.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c index 5bef934f823d..64bace100316 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * r8a7779 processor support - PFC hardware block * * Copyright (C) 2011, 2013 Renesas Solutions Corp. * Copyright (C) 2011 Magnus Damm * Copyright (C) 2013 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c index f6332f247368..ab7a35392cd8 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * R8A7790 processor support * @@ -5,20 +6,6 @@ * Copyright (C) 2013 Magnus Damm * Copyright (C) 2012 Renesas Solutions Corp. * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/io.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 5811784d88cb..209f74a6e6ce 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * r8a7791/r8a7743 processor support - PFC hardware block. * * Copyright (C) 2013 Renesas Electronics Corporation * Copyright (C) 2014-2017 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/kernel.h> @@ -4458,7 +4455,7 @@ static const unsigned int vin2_clk_mux[] = { static const struct { struct sh_pfc_pin_group common[346]; - struct sh_pfc_pin_group r8a779x[9]; + struct sh_pfc_pin_group automotive[9]; } pinmux_groups = { .common = { SH_PFC_PIN_GROUP(audio_clk_a), @@ -4808,7 +4805,7 @@ static const struct { SH_PFC_PIN_GROUP(vin2_clkenb), SH_PFC_PIN_GROUP(vin2_clk), }, - .r8a779x = { + .automotive = { SH_PFC_PIN_GROUP(adi_common), SH_PFC_PIN_GROUP(adi_chsel0), SH_PFC_PIN_GROUP(adi_chsel1), @@ -5365,7 +5362,7 @@ static const char * const vin2_groups[] = { static const struct { struct sh_pfc_function common[58]; - struct sh_pfc_function r8a779x[2]; + struct sh_pfc_function automotive[2]; } pinmux_functions = { .common = { SH_PFC_FUNCTION(audio_clk), @@ -5427,7 +5424,7 @@ static const struct { SH_PFC_FUNCTION(vin1), SH_PFC_FUNCTION(vin2), }, - .r8a779x = { + .automotive = { SH_PFC_FUNCTION(adi), SH_PFC_FUNCTION(mlb), } @@ -6634,6 +6631,28 @@ const struct sh_pfc_soc_info r8a7743_pinmux_info = { }; #endif +#ifdef CONFIG_PINCTRL_PFC_R8A7744 +const struct sh_pfc_soc_info r8a7744_pinmux_info = { + .name = "r8a77440_pfc", + .ops = &r8a7791_pinmux_ops, + .unlock_reg = 0xe6060000, /* PMMR */ + + .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, + + .pins = pinmux_pins, + .nr_pins = ARRAY_SIZE(pinmux_pins), + .groups = pinmux_groups.common, + .nr_groups = ARRAY_SIZE(pinmux_groups.common), + .functions = pinmux_functions.common, + .nr_functions = ARRAY_SIZE(pinmux_functions.common), + + .cfg_regs = pinmux_config_regs, + + .pinmux_data = pinmux_data, + .pinmux_data_size = ARRAY_SIZE(pinmux_data), +}; +#endif + #ifdef CONFIG_PINCTRL_PFC_R8A7791 const struct sh_pfc_soc_info r8a7791_pinmux_info = { .name = "r8a77910_pfc", @@ -6646,10 +6665,10 @@ const struct sh_pfc_soc_info r8a7791_pinmux_info = { .nr_pins = ARRAY_SIZE(pinmux_pins), .groups = pinmux_groups.common, .nr_groups = ARRAY_SIZE(pinmux_groups.common) + - ARRAY_SIZE(pinmux_groups.r8a779x), + ARRAY_SIZE(pinmux_groups.automotive), .functions = pinmux_functions.common, .nr_functions = ARRAY_SIZE(pinmux_functions.common) + - ARRAY_SIZE(pinmux_functions.r8a779x), + ARRAY_SIZE(pinmux_functions.automotive), .cfg_regs = pinmux_config_regs, @@ -6670,10 +6689,10 @@ const struct sh_pfc_soc_info r8a7793_pinmux_info = { .nr_pins = ARRAY_SIZE(pinmux_pins), .groups = pinmux_groups.common, .nr_groups = ARRAY_SIZE(pinmux_groups.common) + - ARRAY_SIZE(pinmux_groups.r8a779x), + ARRAY_SIZE(pinmux_groups.automotive), .functions = pinmux_functions.common, .nr_functions = ARRAY_SIZE(pinmux_functions.common) + - ARRAY_SIZE(pinmux_functions.r8a779x), + ARRAY_SIZE(pinmux_functions.automotive), .cfg_regs = pinmux_config_regs, diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c index cc3597f66605..bf0681b38181 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * r8a7792 processor support - PFC hardware block. * * Copyright (C) 2013-2014 Renesas Electronics Corporation * Copyright (C) 2016 Cogent Embedded, Inc., <source@cogentembedded.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index 164002437594..6d1e5fdc03f8 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * r8a7794/r8a7745 processor support - PFC hardware block. * * Copyright (C) 2014-2015 Renesas Electronics Corporation * Copyright (C) 2015 Renesas Solutions Corp. * Copyright (C) 2015-2017 Cogent Embedded, Inc. <source@cogentembedded.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c index a6c5d50557e6..8c7de44615d1 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * R8A7795 ES1.x processor support - PFC hardware block. * * Copyright (C) 2015-2017 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index 4f55b1562ad4..0af737d11403 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * R8A7795 ES2.0+ processor support - PFC hardware block. * * Copyright (C) 2015-2017 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 3ea133cfb241..3a6d21d87107 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * R8A7796 processor support - PFC hardware block. * @@ -8,10 +9,6 @@ * R-Car Gen3 processor support - PFC hardware block. * * Copyright (C) 2015 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #include <linux/kernel.h> @@ -4126,347 +4123,354 @@ static const unsigned int vin5_clk_mux[] = { VI5_CLK_MARK, }; -static const struct sh_pfc_pin_group pinmux_groups[] = { - SH_PFC_PIN_GROUP(audio_clk_a_a), - SH_PFC_PIN_GROUP(audio_clk_a_b), - SH_PFC_PIN_GROUP(audio_clk_a_c), - SH_PFC_PIN_GROUP(audio_clk_b_a), - SH_PFC_PIN_GROUP(audio_clk_b_b), - SH_PFC_PIN_GROUP(audio_clk_c_a), - SH_PFC_PIN_GROUP(audio_clk_c_b), - SH_PFC_PIN_GROUP(audio_clkout_a), - SH_PFC_PIN_GROUP(audio_clkout_b), - SH_PFC_PIN_GROUP(audio_clkout_c), - SH_PFC_PIN_GROUP(audio_clkout_d), - SH_PFC_PIN_GROUP(audio_clkout1_a), - SH_PFC_PIN_GROUP(audio_clkout1_b), - SH_PFC_PIN_GROUP(audio_clkout2_a), - SH_PFC_PIN_GROUP(audio_clkout2_b), - SH_PFC_PIN_GROUP(audio_clkout3_a), - SH_PFC_PIN_GROUP(audio_clkout3_b), - SH_PFC_PIN_GROUP(avb_link), - SH_PFC_PIN_GROUP(avb_magic), - SH_PFC_PIN_GROUP(avb_phy_int), - SH_PFC_PIN_GROUP_ALIAS(avb_mdc, avb_mdio), /* Deprecated */ - SH_PFC_PIN_GROUP(avb_mdio), - SH_PFC_PIN_GROUP(avb_mii), - SH_PFC_PIN_GROUP(avb_avtp_pps), - SH_PFC_PIN_GROUP(avb_avtp_match_a), - SH_PFC_PIN_GROUP(avb_avtp_capture_a), - SH_PFC_PIN_GROUP(avb_avtp_match_b), - SH_PFC_PIN_GROUP(avb_avtp_capture_b), - SH_PFC_PIN_GROUP(can0_data_a), - SH_PFC_PIN_GROUP(can0_data_b), - SH_PFC_PIN_GROUP(can1_data), - SH_PFC_PIN_GROUP(can_clk), - SH_PFC_PIN_GROUP(canfd0_data_a), - SH_PFC_PIN_GROUP(canfd0_data_b), - SH_PFC_PIN_GROUP(canfd1_data), - SH_PFC_PIN_GROUP(drif0_ctrl_a), - SH_PFC_PIN_GROUP(drif0_data0_a), - SH_PFC_PIN_GROUP(drif0_data1_a), - SH_PFC_PIN_GROUP(drif0_ctrl_b), - SH_PFC_PIN_GROUP(drif0_data0_b), - SH_PFC_PIN_GROUP(drif0_data1_b), - SH_PFC_PIN_GROUP(drif0_ctrl_c), - SH_PFC_PIN_GROUP(drif0_data0_c), - SH_PFC_PIN_GROUP(drif0_data1_c), - SH_PFC_PIN_GROUP(drif1_ctrl_a), - SH_PFC_PIN_GROUP(drif1_data0_a), - SH_PFC_PIN_GROUP(drif1_data1_a), - SH_PFC_PIN_GROUP(drif1_ctrl_b), - SH_PFC_PIN_GROUP(drif1_data0_b), - SH_PFC_PIN_GROUP(drif1_data1_b), - SH_PFC_PIN_GROUP(drif1_ctrl_c), - SH_PFC_PIN_GROUP(drif1_data0_c), - SH_PFC_PIN_GROUP(drif1_data1_c), - SH_PFC_PIN_GROUP(drif2_ctrl_a), - SH_PFC_PIN_GROUP(drif2_data0_a), - SH_PFC_PIN_GROUP(drif2_data1_a), - SH_PFC_PIN_GROUP(drif2_ctrl_b), - SH_PFC_PIN_GROUP(drif2_data0_b), - SH_PFC_PIN_GROUP(drif2_data1_b), - SH_PFC_PIN_GROUP(drif3_ctrl_a), - SH_PFC_PIN_GROUP(drif3_data0_a), - SH_PFC_PIN_GROUP(drif3_data1_a), - SH_PFC_PIN_GROUP(drif3_ctrl_b), - SH_PFC_PIN_GROUP(drif3_data0_b), - SH_PFC_PIN_GROUP(drif3_data1_b), - SH_PFC_PIN_GROUP(du_rgb666), - SH_PFC_PIN_GROUP(du_rgb888), - SH_PFC_PIN_GROUP(du_clk_out_0), - SH_PFC_PIN_GROUP(du_clk_out_1), - SH_PFC_PIN_GROUP(du_sync), - SH_PFC_PIN_GROUP(du_oddf), - SH_PFC_PIN_GROUP(du_cde), - SH_PFC_PIN_GROUP(du_disp), - SH_PFC_PIN_GROUP(hdmi0_cec), - SH_PFC_PIN_GROUP(hscif0_data), - SH_PFC_PIN_GROUP(hscif0_clk), - SH_PFC_PIN_GROUP(hscif0_ctrl), - SH_PFC_PIN_GROUP(hscif1_data_a), - SH_PFC_PIN_GROUP(hscif1_clk_a), - SH_PFC_PIN_GROUP(hscif1_ctrl_a), - SH_PFC_PIN_GROUP(hscif1_data_b), - SH_PFC_PIN_GROUP(hscif1_clk_b), - SH_PFC_PIN_GROUP(hscif1_ctrl_b), - SH_PFC_PIN_GROUP(hscif2_data_a), - SH_PFC_PIN_GROUP(hscif2_clk_a), - SH_PFC_PIN_GROUP(hscif2_ctrl_a), - SH_PFC_PIN_GROUP(hscif2_data_b), - SH_PFC_PIN_GROUP(hscif2_clk_b), - SH_PFC_PIN_GROUP(hscif2_ctrl_b), - SH_PFC_PIN_GROUP(hscif2_data_c), - SH_PFC_PIN_GROUP(hscif2_clk_c), - SH_PFC_PIN_GROUP(hscif2_ctrl_c), - SH_PFC_PIN_GROUP(hscif3_data_a), - SH_PFC_PIN_GROUP(hscif3_clk), - SH_PFC_PIN_GROUP(hscif3_ctrl), - SH_PFC_PIN_GROUP(hscif3_data_b), - SH_PFC_PIN_GROUP(hscif3_data_c), - SH_PFC_PIN_GROUP(hscif3_data_d), - SH_PFC_PIN_GROUP(hscif4_data_a), - SH_PFC_PIN_GROUP(hscif4_clk), - SH_PFC_PIN_GROUP(hscif4_ctrl), - SH_PFC_PIN_GROUP(hscif4_data_b), - SH_PFC_PIN_GROUP(i2c1_a), - SH_PFC_PIN_GROUP(i2c1_b), - SH_PFC_PIN_GROUP(i2c2_a), - SH_PFC_PIN_GROUP(i2c2_b), - SH_PFC_PIN_GROUP(i2c6_a), - SH_PFC_PIN_GROUP(i2c6_b), - SH_PFC_PIN_GROUP(i2c6_c), - SH_PFC_PIN_GROUP(intc_ex_irq0), - SH_PFC_PIN_GROUP(intc_ex_irq1), - SH_PFC_PIN_GROUP(intc_ex_irq2), - SH_PFC_PIN_GROUP(intc_ex_irq3), - SH_PFC_PIN_GROUP(intc_ex_irq4), - SH_PFC_PIN_GROUP(intc_ex_irq5), - SH_PFC_PIN_GROUP(msiof0_clk), - SH_PFC_PIN_GROUP(msiof0_sync), - SH_PFC_PIN_GROUP(msiof0_ss1), - SH_PFC_PIN_GROUP(msiof0_ss2), - SH_PFC_PIN_GROUP(msiof0_txd), - SH_PFC_PIN_GROUP(msiof0_rxd), - SH_PFC_PIN_GROUP(msiof1_clk_a), - SH_PFC_PIN_GROUP(msiof1_sync_a), - SH_PFC_PIN_GROUP(msiof1_ss1_a), - SH_PFC_PIN_GROUP(msiof1_ss2_a), - SH_PFC_PIN_GROUP(msiof1_txd_a), - SH_PFC_PIN_GROUP(msiof1_rxd_a), - SH_PFC_PIN_GROUP(msiof1_clk_b), - SH_PFC_PIN_GROUP(msiof1_sync_b), - SH_PFC_PIN_GROUP(msiof1_ss1_b), - SH_PFC_PIN_GROUP(msiof1_ss2_b), - SH_PFC_PIN_GROUP(msiof1_txd_b), - SH_PFC_PIN_GROUP(msiof1_rxd_b), - SH_PFC_PIN_GROUP(msiof1_clk_c), - SH_PFC_PIN_GROUP(msiof1_sync_c), - SH_PFC_PIN_GROUP(msiof1_ss1_c), - SH_PFC_PIN_GROUP(msiof1_ss2_c), - SH_PFC_PIN_GROUP(msiof1_txd_c), - SH_PFC_PIN_GROUP(msiof1_rxd_c), - SH_PFC_PIN_GROUP(msiof1_clk_d), - SH_PFC_PIN_GROUP(msiof1_sync_d), - SH_PFC_PIN_GROUP(msiof1_ss1_d), - SH_PFC_PIN_GROUP(msiof1_ss2_d), - SH_PFC_PIN_GROUP(msiof1_txd_d), - SH_PFC_PIN_GROUP(msiof1_rxd_d), - SH_PFC_PIN_GROUP(msiof1_clk_e), - SH_PFC_PIN_GROUP(msiof1_sync_e), - SH_PFC_PIN_GROUP(msiof1_ss1_e), - SH_PFC_PIN_GROUP(msiof1_ss2_e), - SH_PFC_PIN_GROUP(msiof1_txd_e), - SH_PFC_PIN_GROUP(msiof1_rxd_e), - SH_PFC_PIN_GROUP(msiof1_clk_f), - SH_PFC_PIN_GROUP(msiof1_sync_f), - SH_PFC_PIN_GROUP(msiof1_ss1_f), - SH_PFC_PIN_GROUP(msiof1_ss2_f), - SH_PFC_PIN_GROUP(msiof1_txd_f), - SH_PFC_PIN_GROUP(msiof1_rxd_f), - SH_PFC_PIN_GROUP(msiof1_clk_g), - SH_PFC_PIN_GROUP(msiof1_sync_g), - SH_PFC_PIN_GROUP(msiof1_ss1_g), - SH_PFC_PIN_GROUP(msiof1_ss2_g), - SH_PFC_PIN_GROUP(msiof1_txd_g), - SH_PFC_PIN_GROUP(msiof1_rxd_g), - SH_PFC_PIN_GROUP(msiof2_clk_a), - SH_PFC_PIN_GROUP(msiof2_sync_a), - SH_PFC_PIN_GROUP(msiof2_ss1_a), - SH_PFC_PIN_GROUP(msiof2_ss2_a), - SH_PFC_PIN_GROUP(msiof2_txd_a), - SH_PFC_PIN_GROUP(msiof2_rxd_a), - SH_PFC_PIN_GROUP(msiof2_clk_b), - SH_PFC_PIN_GROUP(msiof2_sync_b), - SH_PFC_PIN_GROUP(msiof2_ss1_b), - SH_PFC_PIN_GROUP(msiof2_ss2_b), - SH_PFC_PIN_GROUP(msiof2_txd_b), - SH_PFC_PIN_GROUP(msiof2_rxd_b), - SH_PFC_PIN_GROUP(msiof2_clk_c), - SH_PFC_PIN_GROUP(msiof2_sync_c), - SH_PFC_PIN_GROUP(msiof2_ss1_c), - SH_PFC_PIN_GROUP(msiof2_ss2_c), - SH_PFC_PIN_GROUP(msiof2_txd_c), - SH_PFC_PIN_GROUP(msiof2_rxd_c), - SH_PFC_PIN_GROUP(msiof2_clk_d), - SH_PFC_PIN_GROUP(msiof2_sync_d), - SH_PFC_PIN_GROUP(msiof2_ss1_d), - SH_PFC_PIN_GROUP(msiof2_ss2_d), - SH_PFC_PIN_GROUP(msiof2_txd_d), - SH_PFC_PIN_GROUP(msiof2_rxd_d), - SH_PFC_PIN_GROUP(msiof3_clk_a), - SH_PFC_PIN_GROUP(msiof3_sync_a), - SH_PFC_PIN_GROUP(msiof3_ss1_a), - SH_PFC_PIN_GROUP(msiof3_ss2_a), - SH_PFC_PIN_GROUP(msiof3_txd_a), - SH_PFC_PIN_GROUP(msiof3_rxd_a), - SH_PFC_PIN_GROUP(msiof3_clk_b), - SH_PFC_PIN_GROUP(msiof3_sync_b), - SH_PFC_PIN_GROUP(msiof3_ss1_b), - SH_PFC_PIN_GROUP(msiof3_ss2_b), - SH_PFC_PIN_GROUP(msiof3_txd_b), - SH_PFC_PIN_GROUP(msiof3_rxd_b), - SH_PFC_PIN_GROUP(msiof3_clk_c), - SH_PFC_PIN_GROUP(msiof3_sync_c), - SH_PFC_PIN_GROUP(msiof3_txd_c), - SH_PFC_PIN_GROUP(msiof3_rxd_c), - SH_PFC_PIN_GROUP(msiof3_clk_d), - SH_PFC_PIN_GROUP(msiof3_sync_d), - SH_PFC_PIN_GROUP(msiof3_ss1_d), - SH_PFC_PIN_GROUP(msiof3_txd_d), - SH_PFC_PIN_GROUP(msiof3_rxd_d), - SH_PFC_PIN_GROUP(msiof3_clk_e), - SH_PFC_PIN_GROUP(msiof3_sync_e), - SH_PFC_PIN_GROUP(msiof3_ss1_e), - SH_PFC_PIN_GROUP(msiof3_ss2_e), - SH_PFC_PIN_GROUP(msiof3_txd_e), - SH_PFC_PIN_GROUP(msiof3_rxd_e), - SH_PFC_PIN_GROUP(pwm0), - SH_PFC_PIN_GROUP(pwm1_a), - SH_PFC_PIN_GROUP(pwm1_b), - SH_PFC_PIN_GROUP(pwm2_a), - SH_PFC_PIN_GROUP(pwm2_b), - SH_PFC_PIN_GROUP(pwm3_a), - SH_PFC_PIN_GROUP(pwm3_b), - SH_PFC_PIN_GROUP(pwm4_a), - SH_PFC_PIN_GROUP(pwm4_b), - SH_PFC_PIN_GROUP(pwm5_a), - SH_PFC_PIN_GROUP(pwm5_b), - SH_PFC_PIN_GROUP(pwm6_a), - SH_PFC_PIN_GROUP(pwm6_b), - SH_PFC_PIN_GROUP(scif0_data), - SH_PFC_PIN_GROUP(scif0_clk), - SH_PFC_PIN_GROUP(scif0_ctrl), - SH_PFC_PIN_GROUP(scif1_data_a), - SH_PFC_PIN_GROUP(scif1_clk), - SH_PFC_PIN_GROUP(scif1_ctrl), - SH_PFC_PIN_GROUP(scif1_data_b), - SH_PFC_PIN_GROUP(scif2_data_a), - SH_PFC_PIN_GROUP(scif2_clk), - SH_PFC_PIN_GROUP(scif2_data_b), - SH_PFC_PIN_GROUP(scif3_data_a), - SH_PFC_PIN_GROUP(scif3_clk), - SH_PFC_PIN_GROUP(scif3_ctrl), - SH_PFC_PIN_GROUP(scif3_data_b), - SH_PFC_PIN_GROUP(scif4_data_a), - SH_PFC_PIN_GROUP(scif4_clk_a), - SH_PFC_PIN_GROUP(scif4_ctrl_a), - SH_PFC_PIN_GROUP(scif4_data_b), - SH_PFC_PIN_GROUP(scif4_clk_b), - SH_PFC_PIN_GROUP(scif4_ctrl_b), - SH_PFC_PIN_GROUP(scif4_data_c), - SH_PFC_PIN_GROUP(scif4_clk_c), - SH_PFC_PIN_GROUP(scif4_ctrl_c), - SH_PFC_PIN_GROUP(scif5_data_a), - SH_PFC_PIN_GROUP(scif5_clk_a), - SH_PFC_PIN_GROUP(scif5_data_b), - SH_PFC_PIN_GROUP(scif5_clk_b), - SH_PFC_PIN_GROUP(scif_clk_a), - SH_PFC_PIN_GROUP(scif_clk_b), - SH_PFC_PIN_GROUP(sdhi0_data1), - SH_PFC_PIN_GROUP(sdhi0_data4), - SH_PFC_PIN_GROUP(sdhi0_ctrl), - SH_PFC_PIN_GROUP(sdhi0_cd), - SH_PFC_PIN_GROUP(sdhi0_wp), - SH_PFC_PIN_GROUP(sdhi1_data1), - SH_PFC_PIN_GROUP(sdhi1_data4), - SH_PFC_PIN_GROUP(sdhi1_ctrl), - SH_PFC_PIN_GROUP(sdhi1_cd), - SH_PFC_PIN_GROUP(sdhi1_wp), - SH_PFC_PIN_GROUP(sdhi2_data1), - SH_PFC_PIN_GROUP(sdhi2_data4), - SH_PFC_PIN_GROUP(sdhi2_data8), - SH_PFC_PIN_GROUP(sdhi2_ctrl), - SH_PFC_PIN_GROUP(sdhi2_cd_a), - SH_PFC_PIN_GROUP(sdhi2_wp_a), - SH_PFC_PIN_GROUP(sdhi2_cd_b), - SH_PFC_PIN_GROUP(sdhi2_wp_b), - SH_PFC_PIN_GROUP(sdhi2_ds), - SH_PFC_PIN_GROUP(sdhi3_data1), - SH_PFC_PIN_GROUP(sdhi3_data4), - SH_PFC_PIN_GROUP(sdhi3_data8), - SH_PFC_PIN_GROUP(sdhi3_ctrl), - SH_PFC_PIN_GROUP(sdhi3_cd), - SH_PFC_PIN_GROUP(sdhi3_wp), - SH_PFC_PIN_GROUP(sdhi3_ds), - SH_PFC_PIN_GROUP(ssi0_data), - SH_PFC_PIN_GROUP(ssi01239_ctrl), - SH_PFC_PIN_GROUP(ssi1_data_a), - SH_PFC_PIN_GROUP(ssi1_data_b), - SH_PFC_PIN_GROUP(ssi1_ctrl_a), - SH_PFC_PIN_GROUP(ssi1_ctrl_b), - SH_PFC_PIN_GROUP(ssi2_data_a), - SH_PFC_PIN_GROUP(ssi2_data_b), - SH_PFC_PIN_GROUP(ssi2_ctrl_a), - SH_PFC_PIN_GROUP(ssi2_ctrl_b), - SH_PFC_PIN_GROUP(ssi3_data), - SH_PFC_PIN_GROUP(ssi349_ctrl), - SH_PFC_PIN_GROUP(ssi4_data), - SH_PFC_PIN_GROUP(ssi4_ctrl), - SH_PFC_PIN_GROUP(ssi5_data), - SH_PFC_PIN_GROUP(ssi5_ctrl), - SH_PFC_PIN_GROUP(ssi6_data), - SH_PFC_PIN_GROUP(ssi6_ctrl), - SH_PFC_PIN_GROUP(ssi7_data), - SH_PFC_PIN_GROUP(ssi78_ctrl), - SH_PFC_PIN_GROUP(ssi8_data), - SH_PFC_PIN_GROUP(ssi9_data_a), - SH_PFC_PIN_GROUP(ssi9_data_b), - SH_PFC_PIN_GROUP(ssi9_ctrl_a), - SH_PFC_PIN_GROUP(ssi9_ctrl_b), - SH_PFC_PIN_GROUP(tmu_tclk1_a), - SH_PFC_PIN_GROUP(tmu_tclk1_b), - SH_PFC_PIN_GROUP(tmu_tclk2_a), - SH_PFC_PIN_GROUP(tmu_tclk2_b), - SH_PFC_PIN_GROUP(usb0), - SH_PFC_PIN_GROUP(usb1), - SH_PFC_PIN_GROUP(usb30), - VIN_DATA_PIN_GROUP(vin4_data_a, 8), - VIN_DATA_PIN_GROUP(vin4_data_a, 10), - VIN_DATA_PIN_GROUP(vin4_data_a, 12), - VIN_DATA_PIN_GROUP(vin4_data_a, 16), - SH_PFC_PIN_GROUP(vin4_data18_a), - VIN_DATA_PIN_GROUP(vin4_data_a, 20), - VIN_DATA_PIN_GROUP(vin4_data_a, 24), - VIN_DATA_PIN_GROUP(vin4_data_b, 8), - VIN_DATA_PIN_GROUP(vin4_data_b, 10), - VIN_DATA_PIN_GROUP(vin4_data_b, 12), - VIN_DATA_PIN_GROUP(vin4_data_b, 16), - SH_PFC_PIN_GROUP(vin4_data18_b), - VIN_DATA_PIN_GROUP(vin4_data_b, 20), - VIN_DATA_PIN_GROUP(vin4_data_b, 24), - SH_PFC_PIN_GROUP(vin4_sync), - SH_PFC_PIN_GROUP(vin4_field), - SH_PFC_PIN_GROUP(vin4_clkenb), - SH_PFC_PIN_GROUP(vin4_clk), - SH_PFC_PIN_GROUP(vin5_data8), - SH_PFC_PIN_GROUP(vin5_data10), - SH_PFC_PIN_GROUP(vin5_data12), - SH_PFC_PIN_GROUP(vin5_data16), - SH_PFC_PIN_GROUP(vin5_sync), - SH_PFC_PIN_GROUP(vin5_field), - SH_PFC_PIN_GROUP(vin5_clkenb), - SH_PFC_PIN_GROUP(vin5_clk), +static const struct { + struct sh_pfc_pin_group common[307]; + struct sh_pfc_pin_group automotive[33]; +} pinmux_groups = { + .common = { + SH_PFC_PIN_GROUP(audio_clk_a_a), + SH_PFC_PIN_GROUP(audio_clk_a_b), + SH_PFC_PIN_GROUP(audio_clk_a_c), + SH_PFC_PIN_GROUP(audio_clk_b_a), + SH_PFC_PIN_GROUP(audio_clk_b_b), + SH_PFC_PIN_GROUP(audio_clk_c_a), + SH_PFC_PIN_GROUP(audio_clk_c_b), + SH_PFC_PIN_GROUP(audio_clkout_a), + SH_PFC_PIN_GROUP(audio_clkout_b), + SH_PFC_PIN_GROUP(audio_clkout_c), + SH_PFC_PIN_GROUP(audio_clkout_d), + SH_PFC_PIN_GROUP(audio_clkout1_a), + SH_PFC_PIN_GROUP(audio_clkout1_b), + SH_PFC_PIN_GROUP(audio_clkout2_a), + SH_PFC_PIN_GROUP(audio_clkout2_b), + SH_PFC_PIN_GROUP(audio_clkout3_a), + SH_PFC_PIN_GROUP(audio_clkout3_b), + SH_PFC_PIN_GROUP(avb_link), + SH_PFC_PIN_GROUP(avb_magic), + SH_PFC_PIN_GROUP(avb_phy_int), + SH_PFC_PIN_GROUP_ALIAS(avb_mdc, avb_mdio), /* Deprecated */ + SH_PFC_PIN_GROUP(avb_mdio), + SH_PFC_PIN_GROUP(avb_mii), + SH_PFC_PIN_GROUP(avb_avtp_pps), + SH_PFC_PIN_GROUP(avb_avtp_match_a), + SH_PFC_PIN_GROUP(avb_avtp_capture_a), + SH_PFC_PIN_GROUP(avb_avtp_match_b), + SH_PFC_PIN_GROUP(avb_avtp_capture_b), + SH_PFC_PIN_GROUP(can0_data_a), + SH_PFC_PIN_GROUP(can0_data_b), + SH_PFC_PIN_GROUP(can1_data), + SH_PFC_PIN_GROUP(can_clk), + SH_PFC_PIN_GROUP(du_rgb666), + SH_PFC_PIN_GROUP(du_rgb888), + SH_PFC_PIN_GROUP(du_clk_out_0), + SH_PFC_PIN_GROUP(du_clk_out_1), + SH_PFC_PIN_GROUP(du_sync), + SH_PFC_PIN_GROUP(du_oddf), + SH_PFC_PIN_GROUP(du_cde), + SH_PFC_PIN_GROUP(du_disp), + SH_PFC_PIN_GROUP(hdmi0_cec), + SH_PFC_PIN_GROUP(hscif0_data), + SH_PFC_PIN_GROUP(hscif0_clk), + SH_PFC_PIN_GROUP(hscif0_ctrl), + SH_PFC_PIN_GROUP(hscif1_data_a), + SH_PFC_PIN_GROUP(hscif1_clk_a), + SH_PFC_PIN_GROUP(hscif1_ctrl_a), + SH_PFC_PIN_GROUP(hscif1_data_b), + SH_PFC_PIN_GROUP(hscif1_clk_b), + SH_PFC_PIN_GROUP(hscif1_ctrl_b), + SH_PFC_PIN_GROUP(hscif2_data_a), + SH_PFC_PIN_GROUP(hscif2_clk_a), + SH_PFC_PIN_GROUP(hscif2_ctrl_a), + SH_PFC_PIN_GROUP(hscif2_data_b), + SH_PFC_PIN_GROUP(hscif2_clk_b), + SH_PFC_PIN_GROUP(hscif2_ctrl_b), + SH_PFC_PIN_GROUP(hscif2_data_c), + SH_PFC_PIN_GROUP(hscif2_clk_c), + SH_PFC_PIN_GROUP(hscif2_ctrl_c), + SH_PFC_PIN_GROUP(hscif3_data_a), + SH_PFC_PIN_GROUP(hscif3_clk), + SH_PFC_PIN_GROUP(hscif3_ctrl), + SH_PFC_PIN_GROUP(hscif3_data_b), + SH_PFC_PIN_GROUP(hscif3_data_c), + SH_PFC_PIN_GROUP(hscif3_data_d), + SH_PFC_PIN_GROUP(hscif4_data_a), + SH_PFC_PIN_GROUP(hscif4_clk), + SH_PFC_PIN_GROUP(hscif4_ctrl), + SH_PFC_PIN_GROUP(hscif4_data_b), + SH_PFC_PIN_GROUP(i2c1_a), + SH_PFC_PIN_GROUP(i2c1_b), + SH_PFC_PIN_GROUP(i2c2_a), + SH_PFC_PIN_GROUP(i2c2_b), + SH_PFC_PIN_GROUP(i2c6_a), + SH_PFC_PIN_GROUP(i2c6_b), + SH_PFC_PIN_GROUP(i2c6_c), + SH_PFC_PIN_GROUP(intc_ex_irq0), + SH_PFC_PIN_GROUP(intc_ex_irq1), + SH_PFC_PIN_GROUP(intc_ex_irq2), + SH_PFC_PIN_GROUP(intc_ex_irq3), + SH_PFC_PIN_GROUP(intc_ex_irq4), + SH_PFC_PIN_GROUP(intc_ex_irq5), + SH_PFC_PIN_GROUP(msiof0_clk), + SH_PFC_PIN_GROUP(msiof0_sync), + SH_PFC_PIN_GROUP(msiof0_ss1), + SH_PFC_PIN_GROUP(msiof0_ss2), + SH_PFC_PIN_GROUP(msiof0_txd), + SH_PFC_PIN_GROUP(msiof0_rxd), + SH_PFC_PIN_GROUP(msiof1_clk_a), + SH_PFC_PIN_GROUP(msiof1_sync_a), + SH_PFC_PIN_GROUP(msiof1_ss1_a), + SH_PFC_PIN_GROUP(msiof1_ss2_a), + SH_PFC_PIN_GROUP(msiof1_txd_a), + SH_PFC_PIN_GROUP(msiof1_rxd_a), + SH_PFC_PIN_GROUP(msiof1_clk_b), + SH_PFC_PIN_GROUP(msiof1_sync_b), + SH_PFC_PIN_GROUP(msiof1_ss1_b), + SH_PFC_PIN_GROUP(msiof1_ss2_b), + SH_PFC_PIN_GROUP(msiof1_txd_b), + SH_PFC_PIN_GROUP(msiof1_rxd_b), + SH_PFC_PIN_GROUP(msiof1_clk_c), + SH_PFC_PIN_GROUP(msiof1_sync_c), + SH_PFC_PIN_GROUP(msiof1_ss1_c), + SH_PFC_PIN_GROUP(msiof1_ss2_c), + SH_PFC_PIN_GROUP(msiof1_txd_c), + SH_PFC_PIN_GROUP(msiof1_rxd_c), + SH_PFC_PIN_GROUP(msiof1_clk_d), + SH_PFC_PIN_GROUP(msiof1_sync_d), + SH_PFC_PIN_GROUP(msiof1_ss1_d), + SH_PFC_PIN_GROUP(msiof1_ss2_d), + SH_PFC_PIN_GROUP(msiof1_txd_d), + SH_PFC_PIN_GROUP(msiof1_rxd_d), + SH_PFC_PIN_GROUP(msiof1_clk_e), + SH_PFC_PIN_GROUP(msiof1_sync_e), + SH_PFC_PIN_GROUP(msiof1_ss1_e), + SH_PFC_PIN_GROUP(msiof1_ss2_e), + SH_PFC_PIN_GROUP(msiof1_txd_e), + SH_PFC_PIN_GROUP(msiof1_rxd_e), + SH_PFC_PIN_GROUP(msiof1_clk_f), + SH_PFC_PIN_GROUP(msiof1_sync_f), + SH_PFC_PIN_GROUP(msiof1_ss1_f), + SH_PFC_PIN_GROUP(msiof1_ss2_f), + SH_PFC_PIN_GROUP(msiof1_txd_f), + SH_PFC_PIN_GROUP(msiof1_rxd_f), + SH_PFC_PIN_GROUP(msiof1_clk_g), + SH_PFC_PIN_GROUP(msiof1_sync_g), + SH_PFC_PIN_GROUP(msiof1_ss1_g), + SH_PFC_PIN_GROUP(msiof1_ss2_g), + SH_PFC_PIN_GROUP(msiof1_txd_g), + SH_PFC_PIN_GROUP(msiof1_rxd_g), + SH_PFC_PIN_GROUP(msiof2_clk_a), + SH_PFC_PIN_GROUP(msiof2_sync_a), + SH_PFC_PIN_GROUP(msiof2_ss1_a), + SH_PFC_PIN_GROUP(msiof2_ss2_a), + SH_PFC_PIN_GROUP(msiof2_txd_a), + SH_PFC_PIN_GROUP(msiof2_rxd_a), + SH_PFC_PIN_GROUP(msiof2_clk_b), + SH_PFC_PIN_GROUP(msiof2_sync_b), + SH_PFC_PIN_GROUP(msiof2_ss1_b), + SH_PFC_PIN_GROUP(msiof2_ss2_b), + SH_PFC_PIN_GROUP(msiof2_txd_b), + SH_PFC_PIN_GROUP(msiof2_rxd_b), + SH_PFC_PIN_GROUP(msiof2_clk_c), + SH_PFC_PIN_GROUP(msiof2_sync_c), + SH_PFC_PIN_GROUP(msiof2_ss1_c), + SH_PFC_PIN_GROUP(msiof2_ss2_c), + SH_PFC_PIN_GROUP(msiof2_txd_c), + SH_PFC_PIN_GROUP(msiof2_rxd_c), + SH_PFC_PIN_GROUP(msiof2_clk_d), + SH_PFC_PIN_GROUP(msiof2_sync_d), + SH_PFC_PIN_GROUP(msiof2_ss1_d), + SH_PFC_PIN_GROUP(msiof2_ss2_d), + SH_PFC_PIN_GROUP(msiof2_txd_d), + SH_PFC_PIN_GROUP(msiof2_rxd_d), + SH_PFC_PIN_GROUP(msiof3_clk_a), + SH_PFC_PIN_GROUP(msiof3_sync_a), + SH_PFC_PIN_GROUP(msiof3_ss1_a), + SH_PFC_PIN_GROUP(msiof3_ss2_a), + SH_PFC_PIN_GROUP(msiof3_txd_a), + SH_PFC_PIN_GROUP(msiof3_rxd_a), + SH_PFC_PIN_GROUP(msiof3_clk_b), + SH_PFC_PIN_GROUP(msiof3_sync_b), + SH_PFC_PIN_GROUP(msiof3_ss1_b), + SH_PFC_PIN_GROUP(msiof3_ss2_b), + SH_PFC_PIN_GROUP(msiof3_txd_b), + SH_PFC_PIN_GROUP(msiof3_rxd_b), + SH_PFC_PIN_GROUP(msiof3_clk_c), + SH_PFC_PIN_GROUP(msiof3_sync_c), + SH_PFC_PIN_GROUP(msiof3_txd_c), + SH_PFC_PIN_GROUP(msiof3_rxd_c), + SH_PFC_PIN_GROUP(msiof3_clk_d), + SH_PFC_PIN_GROUP(msiof3_sync_d), + SH_PFC_PIN_GROUP(msiof3_ss1_d), + SH_PFC_PIN_GROUP(msiof3_txd_d), + SH_PFC_PIN_GROUP(msiof3_rxd_d), + SH_PFC_PIN_GROUP(msiof3_clk_e), + SH_PFC_PIN_GROUP(msiof3_sync_e), + SH_PFC_PIN_GROUP(msiof3_ss1_e), + SH_PFC_PIN_GROUP(msiof3_ss2_e), + SH_PFC_PIN_GROUP(msiof3_txd_e), + SH_PFC_PIN_GROUP(msiof3_rxd_e), + SH_PFC_PIN_GROUP(pwm0), + SH_PFC_PIN_GROUP(pwm1_a), + SH_PFC_PIN_GROUP(pwm1_b), + SH_PFC_PIN_GROUP(pwm2_a), + SH_PFC_PIN_GROUP(pwm2_b), + SH_PFC_PIN_GROUP(pwm3_a), + SH_PFC_PIN_GROUP(pwm3_b), + SH_PFC_PIN_GROUP(pwm4_a), + SH_PFC_PIN_GROUP(pwm4_b), + SH_PFC_PIN_GROUP(pwm5_a), + SH_PFC_PIN_GROUP(pwm5_b), + SH_PFC_PIN_GROUP(pwm6_a), + SH_PFC_PIN_GROUP(pwm6_b), + SH_PFC_PIN_GROUP(scif0_data), + SH_PFC_PIN_GROUP(scif0_clk), + SH_PFC_PIN_GROUP(scif0_ctrl), + SH_PFC_PIN_GROUP(scif1_data_a), + SH_PFC_PIN_GROUP(scif1_clk), + SH_PFC_PIN_GROUP(scif1_ctrl), + SH_PFC_PIN_GROUP(scif1_data_b), + SH_PFC_PIN_GROUP(scif2_data_a), + SH_PFC_PIN_GROUP(scif2_clk), + SH_PFC_PIN_GROUP(scif2_data_b), + SH_PFC_PIN_GROUP(scif3_data_a), + SH_PFC_PIN_GROUP(scif3_clk), + SH_PFC_PIN_GROUP(scif3_ctrl), + SH_PFC_PIN_GROUP(scif3_data_b), + SH_PFC_PIN_GROUP(scif4_data_a), + SH_PFC_PIN_GROUP(scif4_clk_a), + SH_PFC_PIN_GROUP(scif4_ctrl_a), + SH_PFC_PIN_GROUP(scif4_data_b), + SH_PFC_PIN_GROUP(scif4_clk_b), + SH_PFC_PIN_GROUP(scif4_ctrl_b), + SH_PFC_PIN_GROUP(scif4_data_c), + SH_PFC_PIN_GROUP(scif4_clk_c), + SH_PFC_PIN_GROUP(scif4_ctrl_c), + SH_PFC_PIN_GROUP(scif5_data_a), + SH_PFC_PIN_GROUP(scif5_clk_a), + SH_PFC_PIN_GROUP(scif5_data_b), + SH_PFC_PIN_GROUP(scif5_clk_b), + SH_PFC_PIN_GROUP(scif_clk_a), + SH_PFC_PIN_GROUP(scif_clk_b), + SH_PFC_PIN_GROUP(sdhi0_data1), + SH_PFC_PIN_GROUP(sdhi0_data4), + SH_PFC_PIN_GROUP(sdhi0_ctrl), + SH_PFC_PIN_GROUP(sdhi0_cd), + SH_PFC_PIN_GROUP(sdhi0_wp), + SH_PFC_PIN_GROUP(sdhi1_data1), + SH_PFC_PIN_GROUP(sdhi1_data4), + SH_PFC_PIN_GROUP(sdhi1_ctrl), + SH_PFC_PIN_GROUP(sdhi1_cd), + SH_PFC_PIN_GROUP(sdhi1_wp), + SH_PFC_PIN_GROUP(sdhi2_data1), + SH_PFC_PIN_GROUP(sdhi2_data4), + SH_PFC_PIN_GROUP(sdhi2_data8), + SH_PFC_PIN_GROUP(sdhi2_ctrl), + SH_PFC_PIN_GROUP(sdhi2_cd_a), + SH_PFC_PIN_GROUP(sdhi2_wp_a), + SH_PFC_PIN_GROUP(sdhi2_cd_b), + SH_PFC_PIN_GROUP(sdhi2_wp_b), + SH_PFC_PIN_GROUP(sdhi2_ds), + SH_PFC_PIN_GROUP(sdhi3_data1), + SH_PFC_PIN_GROUP(sdhi3_data4), + SH_PFC_PIN_GROUP(sdhi3_data8), + SH_PFC_PIN_GROUP(sdhi3_ctrl), + SH_PFC_PIN_GROUP(sdhi3_cd), + SH_PFC_PIN_GROUP(sdhi3_wp), + SH_PFC_PIN_GROUP(sdhi3_ds), + SH_PFC_PIN_GROUP(ssi0_data), + SH_PFC_PIN_GROUP(ssi01239_ctrl), + SH_PFC_PIN_GROUP(ssi1_data_a), + SH_PFC_PIN_GROUP(ssi1_data_b), + SH_PFC_PIN_GROUP(ssi1_ctrl_a), + SH_PFC_PIN_GROUP(ssi1_ctrl_b), + SH_PFC_PIN_GROUP(ssi2_data_a), + SH_PFC_PIN_GROUP(ssi2_data_b), + SH_PFC_PIN_GROUP(ssi2_ctrl_a), + SH_PFC_PIN_GROUP(ssi2_ctrl_b), + SH_PFC_PIN_GROUP(ssi3_data), + SH_PFC_PIN_GROUP(ssi349_ctrl), + SH_PFC_PIN_GROUP(ssi4_data), + SH_PFC_PIN_GROUP(ssi4_ctrl), + SH_PFC_PIN_GROUP(ssi5_data), + SH_PFC_PIN_GROUP(ssi5_ctrl), + SH_PFC_PIN_GROUP(ssi6_data), + SH_PFC_PIN_GROUP(ssi6_ctrl), + SH_PFC_PIN_GROUP(ssi7_data), + SH_PFC_PIN_GROUP(ssi78_ctrl), + SH_PFC_PIN_GROUP(ssi8_data), + SH_PFC_PIN_GROUP(ssi9_data_a), + SH_PFC_PIN_GROUP(ssi9_data_b), + SH_PFC_PIN_GROUP(ssi9_ctrl_a), + SH_PFC_PIN_GROUP(ssi9_ctrl_b), + SH_PFC_PIN_GROUP(tmu_tclk1_a), + SH_PFC_PIN_GROUP(tmu_tclk1_b), + SH_PFC_PIN_GROUP(tmu_tclk2_a), + SH_PFC_PIN_GROUP(tmu_tclk2_b), + SH_PFC_PIN_GROUP(usb0), + SH_PFC_PIN_GROUP(usb1), + SH_PFC_PIN_GROUP(usb30), + VIN_DATA_PIN_GROUP(vin4_data_a, 8), + VIN_DATA_PIN_GROUP(vin4_data_a, 10), + VIN_DATA_PIN_GROUP(vin4_data_a, 12), + VIN_DATA_PIN_GROUP(vin4_data_a, 16), + SH_PFC_PIN_GROUP(vin4_data18_a), + VIN_DATA_PIN_GROUP(vin4_data_a, 20), + VIN_DATA_PIN_GROUP(vin4_data_a, 24), + VIN_DATA_PIN_GROUP(vin4_data_b, 8), + VIN_DATA_PIN_GROUP(vin4_data_b, 10), + VIN_DATA_PIN_GROUP(vin4_data_b, 12), + VIN_DATA_PIN_GROUP(vin4_data_b, 16), + SH_PFC_PIN_GROUP(vin4_data18_b), + VIN_DATA_PIN_GROUP(vin4_data_b, 20), + VIN_DATA_PIN_GROUP(vin4_data_b, 24), + SH_PFC_PIN_GROUP(vin4_sync), + SH_PFC_PIN_GROUP(vin4_field), + SH_PFC_PIN_GROUP(vin4_clkenb), + SH_PFC_PIN_GROUP(vin4_clk), + SH_PFC_PIN_GROUP(vin5_data8), + SH_PFC_PIN_GROUP(vin5_data10), + SH_PFC_PIN_GROUP(vin5_data12), + SH_PFC_PIN_GROUP(vin5_data16), + SH_PFC_PIN_GROUP(vin5_sync), + SH_PFC_PIN_GROUP(vin5_field), + SH_PFC_PIN_GROUP(vin5_clkenb), + SH_PFC_PIN_GROUP(vin5_clk), + }, + .automotive = { + SH_PFC_PIN_GROUP(canfd0_data_a), + SH_PFC_PIN_GROUP(canfd0_data_b), + SH_PFC_PIN_GROUP(canfd1_data), + SH_PFC_PIN_GROUP(drif0_ctrl_a), + SH_PFC_PIN_GROUP(drif0_data0_a), + SH_PFC_PIN_GROUP(drif0_data1_a), + SH_PFC_PIN_GROUP(drif0_ctrl_b), + SH_PFC_PIN_GROUP(drif0_data0_b), + SH_PFC_PIN_GROUP(drif0_data1_b), + SH_PFC_PIN_GROUP(drif0_ctrl_c), + SH_PFC_PIN_GROUP(drif0_data0_c), + SH_PFC_PIN_GROUP(drif0_data1_c), + SH_PFC_PIN_GROUP(drif1_ctrl_a), + SH_PFC_PIN_GROUP(drif1_data0_a), + SH_PFC_PIN_GROUP(drif1_data1_a), + SH_PFC_PIN_GROUP(drif1_ctrl_b), + SH_PFC_PIN_GROUP(drif1_data0_b), + SH_PFC_PIN_GROUP(drif1_data1_b), + SH_PFC_PIN_GROUP(drif1_ctrl_c), + SH_PFC_PIN_GROUP(drif1_data0_c), + SH_PFC_PIN_GROUP(drif1_data1_c), + SH_PFC_PIN_GROUP(drif2_ctrl_a), + SH_PFC_PIN_GROUP(drif2_data0_a), + SH_PFC_PIN_GROUP(drif2_data1_a), + SH_PFC_PIN_GROUP(drif2_ctrl_b), + SH_PFC_PIN_GROUP(drif2_data0_b), + SH_PFC_PIN_GROUP(drif2_data1_b), + SH_PFC_PIN_GROUP(drif3_ctrl_a), + SH_PFC_PIN_GROUP(drif3_data0_a), + SH_PFC_PIN_GROUP(drif3_data1_a), + SH_PFC_PIN_GROUP(drif3_ctrl_b), + SH_PFC_PIN_GROUP(drif3_data0_b), + SH_PFC_PIN_GROUP(drif3_data1_b), + } }; static const char * const audio_clk_groups[] = { @@ -4962,58 +4966,65 @@ static const char * const vin5_groups[] = { "vin5_clk", }; -static const struct sh_pfc_function pinmux_functions[] = { - SH_PFC_FUNCTION(audio_clk), - SH_PFC_FUNCTION(avb), - SH_PFC_FUNCTION(can0), - SH_PFC_FUNCTION(can1), - SH_PFC_FUNCTION(can_clk), - SH_PFC_FUNCTION(canfd0), - SH_PFC_FUNCTION(canfd1), - SH_PFC_FUNCTION(drif0), - SH_PFC_FUNCTION(drif1), - SH_PFC_FUNCTION(drif2), - SH_PFC_FUNCTION(drif3), - SH_PFC_FUNCTION(du), - SH_PFC_FUNCTION(hdmi0), - SH_PFC_FUNCTION(hscif0), - SH_PFC_FUNCTION(hscif1), - SH_PFC_FUNCTION(hscif2), - SH_PFC_FUNCTION(hscif3), - SH_PFC_FUNCTION(hscif4), - SH_PFC_FUNCTION(i2c1), - SH_PFC_FUNCTION(i2c2), - SH_PFC_FUNCTION(i2c6), - SH_PFC_FUNCTION(intc_ex), - SH_PFC_FUNCTION(msiof0), - SH_PFC_FUNCTION(msiof1), - SH_PFC_FUNCTION(msiof2), - SH_PFC_FUNCTION(msiof3), - SH_PFC_FUNCTION(pwm0), - SH_PFC_FUNCTION(pwm1), - SH_PFC_FUNCTION(pwm2), - SH_PFC_FUNCTION(pwm3), - SH_PFC_FUNCTION(pwm4), - SH_PFC_FUNCTION(pwm5), - SH_PFC_FUNCTION(pwm6), - SH_PFC_FUNCTION(scif0), - SH_PFC_FUNCTION(scif1), - SH_PFC_FUNCTION(scif2), - SH_PFC_FUNCTION(scif3), - SH_PFC_FUNCTION(scif4), - SH_PFC_FUNCTION(scif5), - SH_PFC_FUNCTION(scif_clk), - SH_PFC_FUNCTION(sdhi0), - SH_PFC_FUNCTION(sdhi1), - SH_PFC_FUNCTION(sdhi2), - SH_PFC_FUNCTION(sdhi3), - SH_PFC_FUNCTION(ssi), - SH_PFC_FUNCTION(tmu), - SH_PFC_FUNCTION(usb0), - SH_PFC_FUNCTION(usb1), - SH_PFC_FUNCTION(usb30), - SH_PFC_FUNCTION(vin4), - SH_PFC_FUNCTION(vin5), +static const struct { + struct sh_pfc_function common[45]; + struct sh_pfc_function automotive[6]; +} pinmux_functions = { + .common = { + SH_PFC_FUNCTION(audio_clk), + SH_PFC_FUNCTION(avb), + SH_PFC_FUNCTION(can0), + SH_PFC_FUNCTION(can1), + SH_PFC_FUNCTION(can_clk), + SH_PFC_FUNCTION(du), + SH_PFC_FUNCTION(hdmi0), + SH_PFC_FUNCTION(hscif0), + SH_PFC_FUNCTION(hscif1), + SH_PFC_FUNCTION(hscif2), + SH_PFC_FUNCTION(hscif3), + SH_PFC_FUNCTION(hscif4), + SH_PFC_FUNCTION(i2c1), + SH_PFC_FUNCTION(i2c2), + SH_PFC_FUNCTION(i2c6), + SH_PFC_FUNCTION(intc_ex), + SH_PFC_FUNCTION(msiof0), + SH_PFC_FUNCTION(msiof1), + SH_PFC_FUNCTION(msiof2), + SH_PFC_FUNCTION(msiof3), + SH_PFC_FUNCTION(pwm0), + SH_PFC_FUNCTION(pwm1), + SH_PFC_FUNCTION(pwm2), + SH_PFC_FUNCTION(pwm3), + SH_PFC_FUNCTION(pwm4), + SH_PFC_FUNCTION(pwm5), + SH_PFC_FUNCTION(pwm6), + SH_PFC_FUNCTION(scif0), + SH_PFC_FUNCTION(scif1), + SH_PFC_FUNCTION(scif2), + SH_PFC_FUNCTION(scif3), + SH_PFC_FUNCTION(scif4), + SH_PFC_FUNCTION(scif5), + SH_PFC_FUNCTION(scif_clk), + SH_PFC_FUNCTION(sdhi0), + SH_PFC_FUNCTION(sdhi1), + SH_PFC_FUNCTION(sdhi2), + SH_PFC_FUNCTION(sdhi3), + SH_PFC_FUNCTION(ssi), + SH_PFC_FUNCTION(tmu), + SH_PFC_FUNCTION(usb0), + SH_PFC_FUNCTION(usb1), + SH_PFC_FUNCTION(usb30), + SH_PFC_FUNCTION(vin4), + SH_PFC_FUNCTION(vin5), + }, + .automotive = { + SH_PFC_FUNCTION(canfd0), + SH_PFC_FUNCTION(canfd1), + SH_PFC_FUNCTION(drif0), + SH_PFC_FUNCTION(drif1), + SH_PFC_FUNCTION(drif2), + SH_PFC_FUNCTION(drif3), + } }; static const struct pinmux_cfg_reg pinmux_config_regs[] = { @@ -6137,6 +6148,32 @@ static const struct sh_pfc_soc_operations r8a7796_pinmux_ops = { .set_bias = r8a7796_pinmux_set_bias, }; +#ifdef CONFIG_PINCTRL_PFC_R8A774A1 +const struct sh_pfc_soc_info r8a774a1_pinmux_info = { + .name = "r8a774a1_pfc", + .ops = &r8a7796_pinmux_ops, + .unlock_reg = 0xe6060000, /* PMMR */ + + .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, + + .pins = pinmux_pins, + .nr_pins = ARRAY_SIZE(pinmux_pins), + .groups = pinmux_groups.common, + .nr_groups = ARRAY_SIZE(pinmux_groups.common), + .functions = pinmux_functions.common, + .nr_functions = ARRAY_SIZE(pinmux_functions.common), + + .cfg_regs = pinmux_config_regs, + .drive_regs = pinmux_drive_regs, + .bias_regs = pinmux_bias_regs, + .ioctrl_regs = pinmux_ioctrl_regs, + + .pinmux_data = pinmux_data, + .pinmux_data_size = ARRAY_SIZE(pinmux_data), +}; +#endif + +#ifdef CONFIG_PINCTRL_PFC_R8A7796 const struct sh_pfc_soc_info r8a7796_pinmux_info = { .name = "r8a77960_pfc", .ops = &r8a7796_pinmux_ops, @@ -6146,10 +6183,12 @@ const struct sh_pfc_soc_info r8a7796_pinmux_info = { .pins = pinmux_pins, .nr_pins = ARRAY_SIZE(pinmux_pins), - .groups = pinmux_groups, - .nr_groups = ARRAY_SIZE(pinmux_groups), - .functions = pinmux_functions, - .nr_functions = ARRAY_SIZE(pinmux_functions), + .groups = pinmux_groups.common, + .nr_groups = ARRAY_SIZE(pinmux_groups.common) + + ARRAY_SIZE(pinmux_groups.automotive), + .functions = pinmux_functions.common, + .nr_functions = ARRAY_SIZE(pinmux_functions.common) + + ARRAY_SIZE(pinmux_functions.automotive), .cfg_regs = pinmux_config_regs, .drive_regs = pinmux_drive_regs, @@ -6159,3 +6198,4 @@ const struct sh_pfc_soc_info r8a7796_pinmux_info = { .pinmux_data = pinmux_data, .pinmux_data_size = ARRAY_SIZE(pinmux_data), }; +#endif diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c index cfd7de67e3e3..dfdd982984d4 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c @@ -1575,6 +1575,128 @@ static const struct sh_pfc_pin pinmux_pins[] = { SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS), }; +/* - AUDIO CLOCK ------------------------------------------------------------ */ +static const unsigned int audio_clk_a_a_pins[] = { + /* CLK A */ + RCAR_GP_PIN(6, 22), +}; +static const unsigned int audio_clk_a_a_mux[] = { + AUDIO_CLKA_A_MARK, +}; +static const unsigned int audio_clk_a_b_pins[] = { + /* CLK A */ + RCAR_GP_PIN(5, 4), +}; +static const unsigned int audio_clk_a_b_mux[] = { + AUDIO_CLKA_B_MARK, +}; +static const unsigned int audio_clk_a_c_pins[] = { + /* CLK A */ + RCAR_GP_PIN(5, 19), +}; +static const unsigned int audio_clk_a_c_mux[] = { + AUDIO_CLKA_C_MARK, +}; +static const unsigned int audio_clk_b_a_pins[] = { + /* CLK B */ + RCAR_GP_PIN(5, 12), +}; +static const unsigned int audio_clk_b_a_mux[] = { + AUDIO_CLKB_A_MARK, +}; +static const unsigned int audio_clk_b_b_pins[] = { + /* CLK B */ + RCAR_GP_PIN(6, 23), +}; +static const unsigned int audio_clk_b_b_mux[] = { + AUDIO_CLKB_B_MARK, +}; +static const unsigned int audio_clk_c_a_pins[] = { + /* CLK C */ + RCAR_GP_PIN(5, 21), +}; +static const unsigned int audio_clk_c_a_mux[] = { + AUDIO_CLKC_A_MARK, +}; +static const unsigned int audio_clk_c_b_pins[] = { + /* CLK C */ + RCAR_GP_PIN(5, 0), +}; +static const unsigned int audio_clk_c_b_mux[] = { + AUDIO_CLKC_B_MARK, +}; +static const unsigned int audio_clkout_a_pins[] = { + /* CLKOUT */ + RCAR_GP_PIN(5, 18), +}; +static const unsigned int audio_clkout_a_mux[] = { + AUDIO_CLKOUT_A_MARK, +}; +static const unsigned int audio_clkout_b_pins[] = { + /* CLKOUT */ + RCAR_GP_PIN(6, 28), +}; +static const unsigned int audio_clkout_b_mux[] = { + AUDIO_CLKOUT_B_MARK, +}; +static const unsigned int audio_clkout_c_pins[] = { + /* CLKOUT */ + RCAR_GP_PIN(5, 3), +}; +static const unsigned int audio_clkout_c_mux[] = { + AUDIO_CLKOUT_C_MARK, +}; +static const unsigned int audio_clkout_d_pins[] = { + /* CLKOUT */ + RCAR_GP_PIN(5, 21), +}; +static const unsigned int audio_clkout_d_mux[] = { + AUDIO_CLKOUT_D_MARK, +}; +static const unsigned int audio_clkout1_a_pins[] = { + /* CLKOUT1 */ + RCAR_GP_PIN(5, 15), +}; +static const unsigned int audio_clkout1_a_mux[] = { + AUDIO_CLKOUT1_A_MARK, +}; +static const unsigned int audio_clkout1_b_pins[] = { + /* CLKOUT1 */ + RCAR_GP_PIN(6, 29), +}; +static const unsigned int audio_clkout1_b_mux[] = { + AUDIO_CLKOUT1_B_MARK, +}; +static const unsigned int audio_clkout2_a_pins[] = { + /* CLKOUT2 */ + RCAR_GP_PIN(5, 16), +}; +static const unsigned int audio_clkout2_a_mux[] = { + AUDIO_CLKOUT2_A_MARK, +}; +static const unsigned int audio_clkout2_b_pins[] = { + /* CLKOUT2 */ + RCAR_GP_PIN(6, 30), +}; +static const unsigned int audio_clkout2_b_mux[] = { + AUDIO_CLKOUT2_B_MARK, +}; + +static const unsigned int audio_clkout3_a_pins[] = { + /* CLKOUT3 */ + RCAR_GP_PIN(5, 19), +}; +static const unsigned int audio_clkout3_a_mux[] = { + AUDIO_CLKOUT3_A_MARK, +}; +static const unsigned int audio_clkout3_b_pins[] = { + /* CLKOUT3 */ + RCAR_GP_PIN(6, 31), +}; +static const unsigned int audio_clkout3_b_mux[] = { + AUDIO_CLKOUT3_B_MARK, +}; + /* - EtherAVB --------------------------------------------------------------- */ static const unsigned int avb_link_pins[] = { /* AVB_LINK */ @@ -2907,6 +3029,25 @@ static const unsigned int pwm6_b_mux[] = { PWM6_B_MARK, }; +/* - SATA --------------------------------------------------------------------*/ +static const unsigned int sata0_devslp_a_pins[] = { + /* DEVSLP */ + RCAR_GP_PIN(6, 16), +}; + +static const unsigned int sata0_devslp_a_mux[] = { + SATA_DEVSLP_A_MARK, +}; + +static const unsigned int sata0_devslp_b_pins[] = { + /* DEVSLP */ + RCAR_GP_PIN(4, 6), +}; + +static const unsigned int sata0_devslp_b_mux[] = { + SATA_DEVSLP_B_MARK, +}; + /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_pins[] = { /* RX, TX */ @@ -3376,6 +3517,184 @@ static const unsigned int sdhi3_ds_mux[] = { SD3_DS_MARK, }; +/* - SSI -------------------------------------------------------------------- */ +static const unsigned int ssi0_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 2), +}; +static const unsigned int ssi0_data_mux[] = { + SSI_SDATA0_MARK, +}; +static const unsigned int ssi01239_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 1), +}; +static const unsigned int ssi01239_ctrl_mux[] = { + SSI_SCK01239_MARK, SSI_WS01239_MARK, +}; +static const unsigned int ssi1_data_a_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 3), +}; +static const unsigned int ssi1_data_a_mux[] = { + SSI_SDATA1_A_MARK, +}; +static const unsigned int ssi1_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(5, 12), +}; +static const unsigned int ssi1_data_b_mux[] = { + SSI_SDATA1_B_MARK, +}; +static const unsigned int ssi1_ctrl_a_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27), +}; +static const unsigned int ssi1_ctrl_a_mux[] = { + SSI_SCK1_A_MARK, SSI_WS1_A_MARK, +}; +static const unsigned int ssi1_ctrl_b_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 4), RCAR_GP_PIN(6, 21), +}; +static const unsigned int ssi1_ctrl_b_mux[] = { + SSI_SCK1_B_MARK, SSI_WS1_B_MARK, +}; +static const unsigned int ssi2_data_a_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 4), +}; +static const unsigned int ssi2_data_a_mux[] = { + SSI_SDATA2_A_MARK, +}; +static const unsigned int ssi2_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(5, 13), +}; +static const unsigned int ssi2_data_b_mux[] = { + SSI_SDATA2_B_MARK, +}; +static const unsigned int ssi2_ctrl_a_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 21), +}; +static const unsigned int ssi2_ctrl_a_mux[] = { + SSI_SCK2_A_MARK, SSI_WS2_A_MARK, +}; +static const unsigned int ssi2_ctrl_b_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29), +}; +static const unsigned int ssi2_ctrl_b_mux[] = { + SSI_SCK2_B_MARK, SSI_WS2_B_MARK, +}; +static const unsigned int ssi3_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 7), +}; +static const unsigned int ssi3_data_mux[] = { + SSI_SDATA3_MARK, +}; +static const unsigned int ssi349_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 5), RCAR_GP_PIN(6, 6), +}; +static const unsigned int ssi349_ctrl_mux[] = { + SSI_SCK349_MARK, SSI_WS349_MARK, +}; +static const unsigned int ssi4_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 10), +}; +static const unsigned int ssi4_data_mux[] = { + SSI_SDATA4_MARK, +}; +static const unsigned int ssi4_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9), +}; +static const unsigned int ssi4_ctrl_mux[] = { + SSI_SCK4_MARK, SSI_WS4_MARK, +}; +static const unsigned int ssi5_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 13), +}; +static const unsigned int ssi5_data_mux[] = { + SSI_SDATA5_MARK, +}; +static const unsigned int ssi5_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 11), RCAR_GP_PIN(6, 12), +}; +static const unsigned int ssi5_ctrl_mux[] = { + SSI_SCK5_MARK, SSI_WS5_MARK, +}; +static const unsigned int ssi6_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 16), +}; +static const unsigned int ssi6_data_mux[] = { + SSI_SDATA6_MARK, +}; +static const unsigned int ssi6_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 14), RCAR_GP_PIN(6, 15), +}; +static const unsigned int ssi6_ctrl_mux[] = { + SSI_SCK6_MARK, SSI_WS6_MARK, +}; +static const unsigned int ssi7_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 19), +}; +static const unsigned int ssi7_data_mux[] = { + SSI_SDATA7_MARK, +}; +static const unsigned int ssi78_ctrl_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18), +}; +static const unsigned int ssi78_ctrl_mux[] = { + SSI_SCK78_MARK, SSI_WS78_MARK, +}; +static const unsigned int ssi8_data_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 20), +}; +static const unsigned int ssi8_data_mux[] = { + SSI_SDATA8_MARK, +}; +static const unsigned int ssi9_data_a_pins[] = { + /* SDATA */ + RCAR_GP_PIN(6, 21), +}; +static const unsigned int ssi9_data_a_mux[] = { + SSI_SDATA9_A_MARK, +}; +static const unsigned int ssi9_data_b_pins[] = { + /* SDATA */ + RCAR_GP_PIN(5, 14), +}; +static const unsigned int ssi9_data_b_mux[] = { + SSI_SDATA9_B_MARK, +}; +static const unsigned int ssi9_ctrl_a_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16), +}; +static const unsigned int ssi9_ctrl_a_mux[] = { + SSI_SCK9_A_MARK, SSI_WS9_A_MARK, +}; +static const unsigned int ssi9_ctrl_b_pins[] = { + /* SCK, WS */ + RCAR_GP_PIN(6, 30), RCAR_GP_PIN(6, 31), +}; +static const unsigned int ssi9_ctrl_b_mux[] = { + SSI_SCK9_B_MARK, SSI_WS9_B_MARK, +}; + + /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { /* PWEN, OVC */ @@ -3407,6 +3726,23 @@ static const unsigned int usb30_mux[] = { }; static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(audio_clk_a_a), + SH_PFC_PIN_GROUP(audio_clk_a_b), + SH_PFC_PIN_GROUP(audio_clk_a_c), + SH_PFC_PIN_GROUP(audio_clk_b_a), + SH_PFC_PIN_GROUP(audio_clk_b_b), + SH_PFC_PIN_GROUP(audio_clk_c_a), + SH_PFC_PIN_GROUP(audio_clk_c_b), + SH_PFC_PIN_GROUP(audio_clkout_a), + SH_PFC_PIN_GROUP(audio_clkout_b), + SH_PFC_PIN_GROUP(audio_clkout_c), + SH_PFC_PIN_GROUP(audio_clkout_d), + SH_PFC_PIN_GROUP(audio_clkout1_a), + SH_PFC_PIN_GROUP(audio_clkout1_b), + SH_PFC_PIN_GROUP(audio_clkout2_a), + SH_PFC_PIN_GROUP(audio_clkout2_b), + SH_PFC_PIN_GROUP(audio_clkout3_a), + SH_PFC_PIN_GROUP(audio_clkout3_b), SH_PFC_PIN_GROUP(avb_link), SH_PFC_PIN_GROUP(avb_magic), SH_PFC_PIN_GROUP(avb_phy_int), @@ -3579,6 +3915,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(pwm5_b), SH_PFC_PIN_GROUP(pwm6_a), SH_PFC_PIN_GROUP(pwm6_b), + SH_PFC_PIN_GROUP(sata0_devslp_a), + SH_PFC_PIN_GROUP(sata0_devslp_b), SH_PFC_PIN_GROUP(scif0_data), SH_PFC_PIN_GROUP(scif0_clk), SH_PFC_PIN_GROUP(scif0_ctrl), @@ -3634,11 +3972,56 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(sdhi3_cd), SH_PFC_PIN_GROUP(sdhi3_wp), SH_PFC_PIN_GROUP(sdhi3_ds), + SH_PFC_PIN_GROUP(ssi0_data), + SH_PFC_PIN_GROUP(ssi01239_ctrl), + SH_PFC_PIN_GROUP(ssi1_data_a), + SH_PFC_PIN_GROUP(ssi1_data_b), + SH_PFC_PIN_GROUP(ssi1_ctrl_a), + SH_PFC_PIN_GROUP(ssi1_ctrl_b), + SH_PFC_PIN_GROUP(ssi2_data_a), + SH_PFC_PIN_GROUP(ssi2_data_b), + SH_PFC_PIN_GROUP(ssi2_ctrl_a), + SH_PFC_PIN_GROUP(ssi2_ctrl_b), + SH_PFC_PIN_GROUP(ssi3_data), + SH_PFC_PIN_GROUP(ssi349_ctrl), + SH_PFC_PIN_GROUP(ssi4_data), + SH_PFC_PIN_GROUP(ssi4_ctrl), + SH_PFC_PIN_GROUP(ssi5_data), + SH_PFC_PIN_GROUP(ssi5_ctrl), + SH_PFC_PIN_GROUP(ssi6_data), + SH_PFC_PIN_GROUP(ssi6_ctrl), + SH_PFC_PIN_GROUP(ssi7_data), + SH_PFC_PIN_GROUP(ssi78_ctrl), + SH_PFC_PIN_GROUP(ssi8_data), + SH_PFC_PIN_GROUP(ssi9_data_a), + SH_PFC_PIN_GROUP(ssi9_data_b), + SH_PFC_PIN_GROUP(ssi9_ctrl_a), + SH_PFC_PIN_GROUP(ssi9_ctrl_b), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), SH_PFC_PIN_GROUP(usb30), }; +static const char * const audio_clk_groups[] = { + "audio_clk_a_a", + "audio_clk_a_b", + "audio_clk_a_c", + "audio_clk_b_a", + "audio_clk_b_b", + "audio_clk_c_a", + "audio_clk_c_b", + "audio_clkout_a", + "audio_clkout_b", + "audio_clkout_c", + "audio_clkout_d", + "audio_clkout1_a", + "audio_clkout1_b", + "audio_clkout2_a", + "audio_clkout2_b", + "audio_clkout3_a", + "audio_clkout3_b", +}; + static const char * const avb_groups[] = { "avb_link", "avb_magic", @@ -3877,6 +4260,11 @@ static const char * const pwm6_groups[] = { "pwm6_b", }; +static const char * const sata0_groups[] = { + "sata0_devslp_a", + "sata0_devslp_b", +}; + static const char * const scif0_groups[] = { "scif0_data", "scif0_clk", @@ -3964,6 +4352,34 @@ static const char * const sdhi3_groups[] = { "sdhi3_ds", }; +static const char * const ssi_groups[] = { + "ssi0_data", + "ssi01239_ctrl", + "ssi1_data_a", + "ssi1_data_b", + "ssi1_ctrl_a", + "ssi1_ctrl_b", + "ssi2_data_a", + "ssi2_data_b", + "ssi2_ctrl_a", + "ssi2_ctrl_b", + "ssi3_data", + "ssi349_ctrl", + "ssi4_data", + "ssi4_ctrl", + "ssi5_data", + "ssi5_ctrl", + "ssi6_data", + "ssi6_ctrl", + "ssi7_data", + "ssi78_ctrl", + "ssi8_data", + "ssi9_data_a", + "ssi9_data_b", + "ssi9_ctrl_a", + "ssi9_ctrl_b", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -3977,6 +4393,7 @@ static const char * const usb30_groups[] = { }; static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(audio_clk), SH_PFC_FUNCTION(avb), SH_PFC_FUNCTION(du), SH_PFC_FUNCTION(hscif0), @@ -3999,6 +4416,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(pwm4), SH_PFC_FUNCTION(pwm5), SH_PFC_FUNCTION(pwm6), + SH_PFC_FUNCTION(sata0), SH_PFC_FUNCTION(scif0), SH_PFC_FUNCTION(scif1), SH_PFC_FUNCTION(scif2), @@ -4010,6 +4428,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi1), SH_PFC_FUNCTION(sdhi2), SH_PFC_FUNCTION(sdhi3), + SH_PFC_FUNCTION(ssi), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(usb30), diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c index eeb58b3bbc9a..44f9eefc86b5 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * R8A77970 processor support - PFC hardware block. * @@ -9,10 +10,6 @@ * R-Car Gen3 processor support - PFC hardware block. * * Copyright (C) 2015 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #include <linux/io.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c index b81c807ac54d..1fdafa48479c 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c @@ -1371,6 +1371,94 @@ static const unsigned int avb_avtp_capture_a_mux[] = { AVB_AVTP_CAPTURE_A_MARK, }; +/* - DU --------------------------------------------------------------------- */ +static const unsigned int du_rgb666_pins[] = { + /* R[7:2], G[7:2], B[7:2] */ + RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 5), + RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 0), + RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 10), + RCAR_GP_PIN(1, 4), RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 11), + RCAR_GP_PIN(0, 1), RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 16), + RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13), +}; +static const unsigned int du_rgb666_mux[] = { + DU_DR7_MARK, DU_DR6_MARK, DU_DR5_MARK, DU_DR4_MARK, + DU_DR3_MARK, DU_DR2_MARK, + DU_DG7_MARK, DU_DG6_MARK, DU_DG5_MARK, DU_DG4_MARK, + DU_DG3_MARK, DU_DG2_MARK, + DU_DB7_MARK, DU_DB6_MARK, DU_DB5_MARK, DU_DB4_MARK, + DU_DB3_MARK, DU_DB2_MARK, +}; +static const unsigned int du_rgb888_pins[] = { + /* R[7:0], G[7:0], B[7:0] */ + RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 5), + RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 0), + RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 21), + RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 10), + RCAR_GP_PIN(1, 4), RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 11), + RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 9), + RCAR_GP_PIN(0, 1), RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 16), + RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13), + RCAR_GP_PIN(1, 19), RCAR_GP_PIN(1, 18), +}; +static const unsigned int du_rgb888_mux[] = { + DU_DR7_MARK, DU_DR6_MARK, DU_DR5_MARK, DU_DR4_MARK, + DU_DR3_MARK, DU_DR2_MARK, DU_DR1_MARK, DU_DR0_MARK, + DU_DG7_MARK, DU_DG6_MARK, DU_DG5_MARK, DU_DG4_MARK, + DU_DG3_MARK, DU_DG2_MARK, DU_DG1_MARK, DU_DG0_MARK, + DU_DB7_MARK, DU_DB6_MARK, DU_DB5_MARK, DU_DB4_MARK, + DU_DB3_MARK, DU_DB2_MARK, DU_DB1_MARK, DU_DB0_MARK, +}; +static const unsigned int du_clk_in_0_pins[] = { + /* CLKIN0 */ + RCAR_GP_PIN(0, 16), +}; +static const unsigned int du_clk_in_0_mux[] = { + DU_DOTCLKIN0_MARK +}; +static const unsigned int du_clk_in_1_pins[] = { + /* CLKIN1 */ + RCAR_GP_PIN(1, 1), +}; +static const unsigned int du_clk_in_1_mux[] = { + DU_DOTCLKIN1_MARK +}; +static const unsigned int du_clk_out_0_pins[] = { + /* CLKOUT */ + RCAR_GP_PIN(1, 3), +}; +static const unsigned int du_clk_out_0_mux[] = { + DU_DOTCLKOUT0_MARK +}; +static const unsigned int du_sync_pins[] = { + /* VSYNC, HSYNC */ + RCAR_GP_PIN(1, 11), RCAR_GP_PIN(1, 8), +}; +static const unsigned int du_sync_mux[] = { + DU_VSYNC_MARK, DU_HSYNC_MARK +}; +static const unsigned int du_disp_cde_pins[] = { + /* DISP_CDE */ + RCAR_GP_PIN(1, 1), +}; +static const unsigned int du_disp_cde_mux[] = { + DU_DISP_CDE_MARK, +}; +static const unsigned int du_cde_pins[] = { + /* CDE */ + RCAR_GP_PIN(1, 0), +}; +static const unsigned int du_cde_mux[] = { + DU_CDE_MARK, +}; +static const unsigned int du_disp_pins[] = { + /* DISP */ + RCAR_GP_PIN(1, 2), +}; +static const unsigned int du_disp_mux[] = { + DU_DISP_MARK, +}; + /* - I2C -------------------------------------------------------------------- */ static const unsigned int i2c1_a_pins[] = { /* SCL, SDA */ @@ -1507,6 +1595,520 @@ static const unsigned int i2c7_b_mux[] = { SCL7_B_MARK, SDA7_B_MARK, }; +/* - INTC-EX ---------------------------------------------------------------- */ +static const unsigned int intc_ex_irq0_pins[] = { + /* IRQ0 */ + RCAR_GP_PIN(1, 0), +}; +static const unsigned int intc_ex_irq0_mux[] = { + IRQ0_MARK, +}; +static const unsigned int intc_ex_irq1_pins[] = { + /* IRQ1 */ + RCAR_GP_PIN(1, 1), +}; +static const unsigned int intc_ex_irq1_mux[] = { + IRQ1_MARK, +}; +static const unsigned int intc_ex_irq2_pins[] = { + /* IRQ2 */ + RCAR_GP_PIN(1, 2), +}; +static const unsigned int intc_ex_irq2_mux[] = { + IRQ2_MARK, +}; +static const unsigned int intc_ex_irq3_pins[] = { + /* IRQ3 */ + RCAR_GP_PIN(1, 9), +}; +static const unsigned int intc_ex_irq3_mux[] = { + IRQ3_MARK, +}; +static const unsigned int intc_ex_irq4_pins[] = { + /* IRQ4 */ + RCAR_GP_PIN(1, 10), +}; +static const unsigned int intc_ex_irq4_mux[] = { + IRQ4_MARK, +}; +static const unsigned int intc_ex_irq5_pins[] = { + /* IRQ5 */ + RCAR_GP_PIN(0, 7), +}; +static const unsigned int intc_ex_irq5_mux[] = { + IRQ5_MARK, +}; + +/* - MSIOF0 ----------------------------------------------------------------- */ +static const unsigned int msiof0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 10), +}; + +static const unsigned int msiof0_clk_mux[] = { + MSIOF0_SCK_MARK, +}; + +static const unsigned int msiof0_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(5, 13), +}; + +static const unsigned int msiof0_sync_mux[] = { + MSIOF0_SYNC_MARK, +}; + +static const unsigned int msiof0_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(5, 14), +}; + +static const unsigned int msiof0_ss1_mux[] = { + MSIOF0_SS1_MARK, +}; + +static const unsigned int msiof0_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(5, 15), +}; + +static const unsigned int msiof0_ss2_mux[] = { + MSIOF0_SS2_MARK, +}; + +static const unsigned int msiof0_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(5, 12), +}; + +static const unsigned int msiof0_txd_mux[] = { + MSIOF0_TXD_MARK, +}; + +static const unsigned int msiof0_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(5, 11), +}; + +static const unsigned int msiof0_rxd_mux[] = { + MSIOF0_RXD_MARK, +}; + +/* - MSIOF1 ----------------------------------------------------------------- */ +static const unsigned int msiof1_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 19), +}; + +static const unsigned int msiof1_clk_mux[] = { + MSIOF1_SCK_MARK, +}; + +static const unsigned int msiof1_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 16), +}; + +static const unsigned int msiof1_sync_mux[] = { + MSIOF1_SYNC_MARK, +}; + +static const unsigned int msiof1_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 14), +}; + +static const unsigned int msiof1_ss1_mux[] = { + MSIOF1_SS1_MARK, +}; + +static const unsigned int msiof1_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(1, 15), +}; + +static const unsigned int msiof1_ss2_mux[] = { + MSIOF1_SS2_MARK, +}; + +static const unsigned int msiof1_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 18), +}; + +static const unsigned int msiof1_txd_mux[] = { + MSIOF1_TXD_MARK, +}; + +static const unsigned int msiof1_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 17), +}; + +static const unsigned int msiof1_rxd_mux[] = { + MSIOF1_RXD_MARK, +}; + +/* - MSIOF2 ----------------------------------------------------------------- */ +static const unsigned int msiof2_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 8), +}; + +static const unsigned int msiof2_clk_a_mux[] = { + MSIOF2_SCK_A_MARK, +}; + +static const unsigned int msiof2_sync_a_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 9), +}; + +static const unsigned int msiof2_sync_a_mux[] = { + MSIOF2_SYNC_A_MARK, +}; + +static const unsigned int msiof2_ss1_a_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 15), +}; + +static const unsigned int msiof2_ss1_a_mux[] = { + MSIOF2_SS1_A_MARK, +}; + +static const unsigned int msiof2_ss2_a_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 14), +}; + +static const unsigned int msiof2_ss2_a_mux[] = { + MSIOF2_SS2_A_MARK, +}; + +static const unsigned int msiof2_txd_a_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 11), +}; + +static const unsigned int msiof2_txd_a_mux[] = { + MSIOF2_TXD_A_MARK, +}; + +static const unsigned int msiof2_rxd_a_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 10), +}; + +static const unsigned int msiof2_rxd_a_mux[] = { + MSIOF2_RXD_A_MARK, +}; + +static const unsigned int msiof2_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 13), +}; + +static const unsigned int msiof2_clk_b_mux[] = { + MSIOF2_SCK_B_MARK, +}; + +static const unsigned int msiof2_sync_b_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 10), +}; + +static const unsigned int msiof2_sync_b_mux[] = { + MSIOF2_SYNC_B_MARK, +}; + +static const unsigned int msiof2_ss1_b_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 16), +}; + +static const unsigned int msiof2_ss1_b_mux[] = { + MSIOF2_SS1_B_MARK, +}; + +static const unsigned int msiof2_ss2_b_pins[] = { + /* SS2 */ + RCAR_GP_PIN(1, 12), +}; + +static const unsigned int msiof2_ss2_b_mux[] = { + MSIOF2_SS2_B_MARK, +}; + +static const unsigned int msiof2_txd_b_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 15), +}; + +static const unsigned int msiof2_txd_b_mux[] = { + MSIOF2_TXD_B_MARK, +}; + +static const unsigned int msiof2_rxd_b_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 14), +}; + +static const unsigned int msiof2_rxd_b_mux[] = { + MSIOF2_RXD_B_MARK, +}; + +/* - MSIOF3 ----------------------------------------------------------------- */ +static const unsigned int msiof3_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 0), +}; + +static const unsigned int msiof3_clk_a_mux[] = { + MSIOF3_SCK_A_MARK, +}; + +static const unsigned int msiof3_sync_a_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 1), +}; + +static const unsigned int msiof3_sync_a_mux[] = { + MSIOF3_SYNC_A_MARK, +}; + +static const unsigned int msiof3_ss1_a_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 15), +}; + +static const unsigned int msiof3_ss1_a_mux[] = { + MSIOF3_SS1_A_MARK, +}; + +static const unsigned int msiof3_ss2_a_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 4), +}; + +static const unsigned int msiof3_ss2_a_mux[] = { + MSIOF3_SS2_A_MARK, +}; + +static const unsigned int msiof3_txd_a_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 3), +}; + +static const unsigned int msiof3_txd_a_mux[] = { + MSIOF3_TXD_A_MARK, +}; + +static const unsigned int msiof3_rxd_a_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 2), +}; + +static const unsigned int msiof3_rxd_a_mux[] = { + MSIOF3_RXD_A_MARK, +}; + +static const unsigned int msiof3_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 5), +}; + +static const unsigned int msiof3_clk_b_mux[] = { + MSIOF3_SCK_B_MARK, +}; + +static const unsigned int msiof3_sync_b_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 4), +}; + +static const unsigned int msiof3_sync_b_mux[] = { + MSIOF3_SYNC_B_MARK, +}; + +static const unsigned int msiof3_ss1_b_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 0), +}; + +static const unsigned int msiof3_ss1_b_mux[] = { + MSIOF3_SS1_B_MARK, +}; + +static const unsigned int msiof3_txd_b_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 7), +}; + +static const unsigned int msiof3_txd_b_mux[] = { + MSIOF3_TXD_B_MARK, +}; + +static const unsigned int msiof3_rxd_b_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 6), +}; + +static const unsigned int msiof3_rxd_b_mux[] = { + MSIOF3_RXD_B_MARK, +}; + +/* - PWM0 --------------------------------------------------------------------*/ +static const unsigned int pwm0_a_pins[] = { + /* PWM */ + RCAR_GP_PIN(2, 22), +}; + +static const unsigned int pwm0_a_mux[] = { + PWM0_A_MARK, +}; + +static const unsigned int pwm0_b_pins[] = { + /* PWM */ + RCAR_GP_PIN(6, 3), +}; + +static const unsigned int pwm0_b_mux[] = { + PWM0_B_MARK, +}; + +/* - PWM1 --------------------------------------------------------------------*/ +static const unsigned int pwm1_a_pins[] = { + /* PWM */ + RCAR_GP_PIN(2, 23), +}; + +static const unsigned int pwm1_a_mux[] = { + PWM1_A_MARK, +}; + +static const unsigned int pwm1_b_pins[] = { + /* PWM */ + RCAR_GP_PIN(6, 4), +}; + +static const unsigned int pwm1_b_mux[] = { + PWM1_B_MARK, +}; + +/* - PWM2 --------------------------------------------------------------------*/ +static const unsigned int pwm2_a_pins[] = { + /* PWM */ + RCAR_GP_PIN(1, 0), +}; + +static const unsigned int pwm2_a_mux[] = { + PWM2_A_MARK, +}; + +static const unsigned int pwm2_b_pins[] = { + /* PWM */ + RCAR_GP_PIN(1, 4), +}; + +static const unsigned int pwm2_b_mux[] = { + PWM2_B_MARK, +}; + +static const unsigned int pwm2_c_pins[] = { + /* PWM */ + RCAR_GP_PIN(6, 5), +}; + +static const unsigned int pwm2_c_mux[] = { + PWM2_C_MARK, +}; + +/* - PWM3 --------------------------------------------------------------------*/ +static const unsigned int pwm3_a_pins[] = { + /* PWM */ + RCAR_GP_PIN(1, 1), +}; + +static const unsigned int pwm3_a_mux[] = { + PWM3_A_MARK, +}; + +static const unsigned int pwm3_b_pins[] = { + /* PWM */ + RCAR_GP_PIN(1, 5), +}; + +static const unsigned int pwm3_b_mux[] = { + PWM3_B_MARK, +}; + +static const unsigned int pwm3_c_pins[] = { + /* PWM */ + RCAR_GP_PIN(6, 6), +}; + +static const unsigned int pwm3_c_mux[] = { + PWM3_C_MARK, +}; + +/* - PWM4 --------------------------------------------------------------------*/ +static const unsigned int pwm4_a_pins[] = { + /* PWM */ + RCAR_GP_PIN(1, 3), +}; + +static const unsigned int pwm4_a_mux[] = { + PWM4_A_MARK, +}; + +static const unsigned int pwm4_b_pins[] = { + /* PWM */ + RCAR_GP_PIN(6, 7), +}; + +static const unsigned int pwm4_b_mux[] = { + PWM4_B_MARK, +}; + +/* - PWM5 --------------------------------------------------------------------*/ +static const unsigned int pwm5_a_pins[] = { + /* PWM */ + RCAR_GP_PIN(2, 24), +}; + +static const unsigned int pwm5_a_mux[] = { + PWM5_A_MARK, +}; + +static const unsigned int pwm5_b_pins[] = { + /* PWM */ + RCAR_GP_PIN(6, 10), +}; + +static const unsigned int pwm5_b_mux[] = { + PWM5_B_MARK, +}; + +/* - PWM6 --------------------------------------------------------------------*/ +static const unsigned int pwm6_a_pins[] = { + /* PWM */ + RCAR_GP_PIN(2, 25), +}; + +static const unsigned int pwm6_a_mux[] = { + PWM6_A_MARK, +}; + +static const unsigned int pwm6_b_pins[] = { + /* PWM */ + RCAR_GP_PIN(6, 11), +}; + +static const unsigned int pwm6_b_mux[] = { + PWM6_B_MARK, +}; + /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_a_pins[] = { /* RX, TX */ @@ -1831,64 +2433,135 @@ static const unsigned int usb30_id_mux[] = { USB3HS0_ID_MARK, }; -static const struct sh_pfc_pin_group pinmux_groups[] = { - SH_PFC_PIN_GROUP(avb_link), - SH_PFC_PIN_GROUP(avb_magic), - SH_PFC_PIN_GROUP(avb_phy_int), - SH_PFC_PIN_GROUP(avb_mii), - SH_PFC_PIN_GROUP(avb_avtp_pps), - SH_PFC_PIN_GROUP(avb_avtp_match_a), - SH_PFC_PIN_GROUP(avb_avtp_capture_a), - SH_PFC_PIN_GROUP(i2c1_a), - SH_PFC_PIN_GROUP(i2c1_b), - SH_PFC_PIN_GROUP(i2c1_c), - SH_PFC_PIN_GROUP(i2c1_d), - SH_PFC_PIN_GROUP(i2c2_a), - SH_PFC_PIN_GROUP(i2c2_b), - SH_PFC_PIN_GROUP(i2c2_c), - SH_PFC_PIN_GROUP(i2c2_d), - SH_PFC_PIN_GROUP(i2c2_e), - SH_PFC_PIN_GROUP(i2c4), - SH_PFC_PIN_GROUP(i2c5), - SH_PFC_PIN_GROUP(i2c6_a), - SH_PFC_PIN_GROUP(i2c6_b), - SH_PFC_PIN_GROUP(i2c7_a), - SH_PFC_PIN_GROUP(i2c7_b), - SH_PFC_PIN_GROUP(scif0_data_a), - SH_PFC_PIN_GROUP(scif0_clk_a), - SH_PFC_PIN_GROUP(scif0_ctrl_a), - SH_PFC_PIN_GROUP(scif0_data_b), - SH_PFC_PIN_GROUP(scif0_clk_b), - SH_PFC_PIN_GROUP(scif1_data), - SH_PFC_PIN_GROUP(scif1_clk), - SH_PFC_PIN_GROUP(scif1_ctrl), - SH_PFC_PIN_GROUP(scif2_data_a), - SH_PFC_PIN_GROUP(scif2_clk_a), - SH_PFC_PIN_GROUP(scif2_data_b), - SH_PFC_PIN_GROUP(scif3_data_a), - SH_PFC_PIN_GROUP(scif3_clk_a), - SH_PFC_PIN_GROUP(scif3_ctrl_a), - SH_PFC_PIN_GROUP(scif3_data_b), - SH_PFC_PIN_GROUP(scif3_data_c), - SH_PFC_PIN_GROUP(scif3_clk_c), - SH_PFC_PIN_GROUP(scif4_data_a), - SH_PFC_PIN_GROUP(scif4_clk_a), - SH_PFC_PIN_GROUP(scif4_ctrl_a), - SH_PFC_PIN_GROUP(scif4_data_b), - SH_PFC_PIN_GROUP(scif4_clk_b), - SH_PFC_PIN_GROUP(scif4_data_c), - SH_PFC_PIN_GROUP(scif4_ctrl_c), - SH_PFC_PIN_GROUP(scif5_data_a), - SH_PFC_PIN_GROUP(scif5_clk_a), - SH_PFC_PIN_GROUP(scif5_data_b), - SH_PFC_PIN_GROUP(scif5_data_c), - SH_PFC_PIN_GROUP(scif_clk_a), - SH_PFC_PIN_GROUP(scif_clk_b), - SH_PFC_PIN_GROUP(usb0_a), - SH_PFC_PIN_GROUP(usb0_b), - SH_PFC_PIN_GROUP(usb0_id), - SH_PFC_PIN_GROUP(usb30), - SH_PFC_PIN_GROUP(usb30_id), +static const struct { + struct sh_pfc_pin_group common[123]; + struct sh_pfc_pin_group automotive[0]; +} pinmux_groups = { + .common = { + SH_PFC_PIN_GROUP(avb_link), + SH_PFC_PIN_GROUP(avb_magic), + SH_PFC_PIN_GROUP(avb_phy_int), + SH_PFC_PIN_GROUP(avb_mii), + SH_PFC_PIN_GROUP(avb_avtp_pps), + SH_PFC_PIN_GROUP(avb_avtp_match_a), + SH_PFC_PIN_GROUP(avb_avtp_capture_a), + SH_PFC_PIN_GROUP(du_rgb666), + SH_PFC_PIN_GROUP(du_rgb888), + SH_PFC_PIN_GROUP(du_clk_in_0), + SH_PFC_PIN_GROUP(du_clk_in_1), + SH_PFC_PIN_GROUP(du_clk_out_0), + SH_PFC_PIN_GROUP(du_sync), + SH_PFC_PIN_GROUP(du_disp_cde), + SH_PFC_PIN_GROUP(du_cde), + SH_PFC_PIN_GROUP(du_disp), + SH_PFC_PIN_GROUP(i2c1_a), + SH_PFC_PIN_GROUP(i2c1_b), + SH_PFC_PIN_GROUP(i2c1_c), + SH_PFC_PIN_GROUP(i2c1_d), + SH_PFC_PIN_GROUP(i2c2_a), + SH_PFC_PIN_GROUP(i2c2_b), + SH_PFC_PIN_GROUP(i2c2_c), + SH_PFC_PIN_GROUP(i2c2_d), + SH_PFC_PIN_GROUP(i2c2_e), + SH_PFC_PIN_GROUP(i2c4), + SH_PFC_PIN_GROUP(i2c5), + SH_PFC_PIN_GROUP(i2c6_a), + SH_PFC_PIN_GROUP(i2c6_b), + SH_PFC_PIN_GROUP(i2c7_a), + SH_PFC_PIN_GROUP(i2c7_b), + SH_PFC_PIN_GROUP(intc_ex_irq0), + SH_PFC_PIN_GROUP(intc_ex_irq1), + SH_PFC_PIN_GROUP(intc_ex_irq2), + SH_PFC_PIN_GROUP(intc_ex_irq3), + SH_PFC_PIN_GROUP(intc_ex_irq4), + SH_PFC_PIN_GROUP(intc_ex_irq5), + SH_PFC_PIN_GROUP(msiof0_clk), + SH_PFC_PIN_GROUP(msiof0_sync), + SH_PFC_PIN_GROUP(msiof0_ss1), + SH_PFC_PIN_GROUP(msiof0_ss2), + SH_PFC_PIN_GROUP(msiof0_txd), + SH_PFC_PIN_GROUP(msiof0_rxd), + SH_PFC_PIN_GROUP(msiof1_clk), + SH_PFC_PIN_GROUP(msiof1_sync), + SH_PFC_PIN_GROUP(msiof1_ss1), + SH_PFC_PIN_GROUP(msiof1_ss2), + SH_PFC_PIN_GROUP(msiof1_txd), + SH_PFC_PIN_GROUP(msiof1_rxd), + SH_PFC_PIN_GROUP(msiof2_clk_a), + SH_PFC_PIN_GROUP(msiof2_sync_a), + SH_PFC_PIN_GROUP(msiof2_ss1_a), + SH_PFC_PIN_GROUP(msiof2_ss2_a), + SH_PFC_PIN_GROUP(msiof2_txd_a), + SH_PFC_PIN_GROUP(msiof2_rxd_a), + SH_PFC_PIN_GROUP(msiof2_clk_b), + SH_PFC_PIN_GROUP(msiof2_sync_b), + SH_PFC_PIN_GROUP(msiof2_ss1_b), + SH_PFC_PIN_GROUP(msiof2_ss2_b), + SH_PFC_PIN_GROUP(msiof2_txd_b), + SH_PFC_PIN_GROUP(msiof2_rxd_b), + SH_PFC_PIN_GROUP(msiof3_clk_a), + SH_PFC_PIN_GROUP(msiof3_sync_a), + SH_PFC_PIN_GROUP(msiof3_ss1_a), + SH_PFC_PIN_GROUP(msiof3_ss2_a), + SH_PFC_PIN_GROUP(msiof3_txd_a), + SH_PFC_PIN_GROUP(msiof3_rxd_a), + SH_PFC_PIN_GROUP(msiof3_clk_b), + SH_PFC_PIN_GROUP(msiof3_sync_b), + SH_PFC_PIN_GROUP(msiof3_ss1_b), + SH_PFC_PIN_GROUP(msiof3_txd_b), + SH_PFC_PIN_GROUP(msiof3_rxd_b), + SH_PFC_PIN_GROUP(pwm0_a), + SH_PFC_PIN_GROUP(pwm0_b), + SH_PFC_PIN_GROUP(pwm1_a), + SH_PFC_PIN_GROUP(pwm1_b), + SH_PFC_PIN_GROUP(pwm2_a), + SH_PFC_PIN_GROUP(pwm2_b), + SH_PFC_PIN_GROUP(pwm2_c), + SH_PFC_PIN_GROUP(pwm3_a), + SH_PFC_PIN_GROUP(pwm3_b), + SH_PFC_PIN_GROUP(pwm3_c), + SH_PFC_PIN_GROUP(pwm4_a), + SH_PFC_PIN_GROUP(pwm4_b), + SH_PFC_PIN_GROUP(pwm5_a), + SH_PFC_PIN_GROUP(pwm5_b), + SH_PFC_PIN_GROUP(pwm6_a), + SH_PFC_PIN_GROUP(pwm6_b), + SH_PFC_PIN_GROUP(scif0_data_a), + SH_PFC_PIN_GROUP(scif0_clk_a), + SH_PFC_PIN_GROUP(scif0_ctrl_a), + SH_PFC_PIN_GROUP(scif0_data_b), + SH_PFC_PIN_GROUP(scif0_clk_b), + SH_PFC_PIN_GROUP(scif1_data), + SH_PFC_PIN_GROUP(scif1_clk), + SH_PFC_PIN_GROUP(scif1_ctrl), + SH_PFC_PIN_GROUP(scif2_data_a), + SH_PFC_PIN_GROUP(scif2_clk_a), + SH_PFC_PIN_GROUP(scif2_data_b), + SH_PFC_PIN_GROUP(scif3_data_a), + SH_PFC_PIN_GROUP(scif3_clk_a), + SH_PFC_PIN_GROUP(scif3_ctrl_a), + SH_PFC_PIN_GROUP(scif3_data_b), + SH_PFC_PIN_GROUP(scif3_data_c), + SH_PFC_PIN_GROUP(scif3_clk_c), + SH_PFC_PIN_GROUP(scif4_data_a), + SH_PFC_PIN_GROUP(scif4_clk_a), + SH_PFC_PIN_GROUP(scif4_ctrl_a), + SH_PFC_PIN_GROUP(scif4_data_b), + SH_PFC_PIN_GROUP(scif4_clk_b), + SH_PFC_PIN_GROUP(scif4_data_c), + SH_PFC_PIN_GROUP(scif4_ctrl_c), + SH_PFC_PIN_GROUP(scif5_data_a), + SH_PFC_PIN_GROUP(scif5_clk_a), + SH_PFC_PIN_GROUP(scif5_data_b), + SH_PFC_PIN_GROUP(scif5_data_c), + SH_PFC_PIN_GROUP(scif_clk_a), + SH_PFC_PIN_GROUP(scif_clk_b), + SH_PFC_PIN_GROUP(usb0_a), + SH_PFC_PIN_GROUP(usb0_b), + SH_PFC_PIN_GROUP(usb0_id), + SH_PFC_PIN_GROUP(usb30), + SH_PFC_PIN_GROUP(usb30_id), + } }; static const char * const avb_groups[] = { @@ -1901,6 +2574,18 @@ static const char * const avb_groups[] = { "avb_avtp_capture_a", }; +static const char * const du_groups[] = { + "du_rgb666", + "du_rgb888", + "du_clk_in_0", + "du_clk_in_1", + "du_clk_out_0", + "du_sync", + "du_disp_cde", + "du_cde", + "du_disp", +}; + static const char * const i2c1_groups[] = { "i2c1_a", "i2c1_b", @@ -1934,6 +2619,99 @@ static const char * const i2c7_groups[] = { "i2c7_b", }; +static const char * const intc_ex_groups[] = { + "intc_ex_irq0", + "intc_ex_irq1", + "intc_ex_irq2", + "intc_ex_irq3", + "intc_ex_irq4", + "intc_ex_irq5", +}; + +static const char * const msiof0_groups[] = { + "msiof0_clk", + "msiof0_sync", + "msiof0_ss1", + "msiof0_ss2", + "msiof0_txd", + "msiof0_rxd", +}; + +static const char * const msiof1_groups[] = { + "msiof1_clk", + "msiof1_sync", + "msiof1_ss1", + "msiof1_ss2", + "msiof1_txd", + "msiof1_rxd", +}; + +static const char * const msiof2_groups[] = { + "msiof2_clk_a", + "msiof2_sync_a", + "msiof2_ss1_a", + "msiof2_ss2_a", + "msiof2_txd_a", + "msiof2_rxd_a", + "msiof2_clk_b", + "msiof2_sync_b", + "msiof2_ss1_b", + "msiof2_ss2_b", + "msiof2_txd_b", + "msiof2_rxd_b", +}; + +static const char * const msiof3_groups[] = { + "msiof3_clk_a", + "msiof3_sync_a", + "msiof3_ss1_a", + "msiof3_ss2_a", + "msiof3_txd_a", + "msiof3_rxd_a", + "msiof3_clk_b", + "msiof3_sync_b", + "msiof3_ss1_b", + "msiof3_txd_b", + "msiof3_rxd_b", +}; + +static const char * const pwm0_groups[] = { + "pwm0_a", + "pwm0_b", +}; + +static const char * const pwm1_groups[] = { + "pwm1_a", + "pwm1_b", +}; + +static const char * const pwm2_groups[] = { + "pwm2_a", + "pwm2_b", + "pwm2_c", +}; + +static const char * const pwm3_groups[] = { + "pwm3_a", + "pwm3_b", + "pwm3_c", +}; + +static const char * const pwm4_groups[] = { + "pwm4_a", + "pwm4_b", +}; + +static const char * const pwm5_groups[] = { + "pwm5_a", + "pwm5_b", +}; + +static const char * const pwm6_groups[] = { + "pwm6_a", + "pwm6_b", +}; + static const char * const scif0_groups[] = { "scif0_data_a", "scif0_clk_a", @@ -1996,23 +2774,41 @@ static const char * const usb30_groups[] = { "usb30_id", }; -static const struct sh_pfc_function pinmux_functions[] = { - SH_PFC_FUNCTION(avb), - SH_PFC_FUNCTION(i2c1), - SH_PFC_FUNCTION(i2c2), - SH_PFC_FUNCTION(i2c4), - SH_PFC_FUNCTION(i2c5), - SH_PFC_FUNCTION(i2c6), - SH_PFC_FUNCTION(i2c7), - SH_PFC_FUNCTION(scif0), - SH_PFC_FUNCTION(scif1), - SH_PFC_FUNCTION(scif2), - SH_PFC_FUNCTION(scif3), - SH_PFC_FUNCTION(scif4), - SH_PFC_FUNCTION(scif5), - SH_PFC_FUNCTION(scif_clk), - SH_PFC_FUNCTION(usb0), - SH_PFC_FUNCTION(usb30), +static const struct { + struct sh_pfc_function common[29]; + struct sh_pfc_function automotive[0]; +} pinmux_functions = { + .common = { + SH_PFC_FUNCTION(avb), + SH_PFC_FUNCTION(du), + SH_PFC_FUNCTION(i2c1), + SH_PFC_FUNCTION(i2c2), + SH_PFC_FUNCTION(i2c4), + SH_PFC_FUNCTION(i2c5), + SH_PFC_FUNCTION(i2c6), + SH_PFC_FUNCTION(i2c7), + SH_PFC_FUNCTION(intc_ex), + SH_PFC_FUNCTION(msiof0), + SH_PFC_FUNCTION(msiof1), + SH_PFC_FUNCTION(msiof2), + SH_PFC_FUNCTION(msiof3), + SH_PFC_FUNCTION(pwm0), + SH_PFC_FUNCTION(pwm1), + SH_PFC_FUNCTION(pwm2), + SH_PFC_FUNCTION(pwm3), + SH_PFC_FUNCTION(pwm4), + SH_PFC_FUNCTION(pwm5), + SH_PFC_FUNCTION(pwm6), + SH_PFC_FUNCTION(scif0), + SH_PFC_FUNCTION(scif1), + SH_PFC_FUNCTION(scif2), + SH_PFC_FUNCTION(scif3), + SH_PFC_FUNCTION(scif4), + SH_PFC_FUNCTION(scif5), + SH_PFC_FUNCTION(scif_clk), + SH_PFC_FUNCTION(usb0), + SH_PFC_FUNCTION(usb30), + } }; static const struct pinmux_cfg_reg pinmux_config_regs[] = { @@ -2738,6 +3534,30 @@ static const struct sh_pfc_soc_operations r8a77990_pinmux_ops = { .set_bias = r8a77990_pinmux_set_bias, }; +#ifdef CONFIG_PINCTRL_PFC_R8A774C0 +const struct sh_pfc_soc_info r8a774c0_pinmux_info = { + .name = "r8a774c0_pfc", + .ops = &r8a77990_pinmux_ops, + .unlock_reg = 0xe6060000, /* PMMR */ + + .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, + + .pins = pinmux_pins, + .nr_pins = ARRAY_SIZE(pinmux_pins), + .groups = pinmux_groups.common, + .nr_groups = ARRAY_SIZE(pinmux_groups.common), + .functions = pinmux_functions.common, + .nr_functions = ARRAY_SIZE(pinmux_functions.common), + + .cfg_regs = pinmux_config_regs, + .bias_regs = pinmux_bias_regs, + + .pinmux_data = pinmux_data, + .pinmux_data_size = ARRAY_SIZE(pinmux_data), +}; +#endif + +#ifdef CONFIG_PINCTRL_PFC_R8A77990 const struct sh_pfc_soc_info r8a77990_pinmux_info = { .name = "r8a77990_pfc", .ops = &r8a77990_pinmux_ops, @@ -2747,10 +3567,12 @@ const struct sh_pfc_soc_info r8a77990_pinmux_info = { .pins = pinmux_pins, .nr_pins = ARRAY_SIZE(pinmux_pins), - .groups = pinmux_groups, - .nr_groups = ARRAY_SIZE(pinmux_groups), - .functions = pinmux_functions, - .nr_functions = ARRAY_SIZE(pinmux_functions), + .groups = pinmux_groups.common, + .nr_groups = ARRAY_SIZE(pinmux_groups.common) + + ARRAY_SIZE(pinmux_groups.automotive), + .functions = pinmux_functions.common, + .nr_functions = ARRAY_SIZE(pinmux_functions.common) + + ARRAY_SIZE(pinmux_functions.automotive), .cfg_regs = pinmux_config_regs, .bias_regs = pinmux_bias_regs, @@ -2758,3 +3580,4 @@ const struct sh_pfc_soc_info r8a77990_pinmux_info = { .pinmux_data = pinmux_data, .pinmux_data_size = ARRAY_SIZE(pinmux_data), }; +#endif diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c index adade5b7ffbc..9484eaa8522a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * R8A77995 processor support - PFC hardware block. * @@ -8,10 +9,6 @@ * R-Car Gen3 processor support - PFC hardware block. * * Copyright (C) 2015 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #include <linux/kernel.h> @@ -520,6 +517,10 @@ static const u16 pinmux_data[] = { PINMUX_SINGLE(QSPI0_SPCLK), PINMUX_SINGLE(SCL0), PINMUX_SINGLE(SDA0), + PINMUX_SINGLE(MSIOF0_RXD), + PINMUX_SINGLE(MSIOF0_TXD), + PINMUX_SINGLE(MSIOF0_SYNC), + PINMUX_SINGLE(MSIOF0_SCK), /* IPSR0 */ PINMUX_IPSR_MSEL(IP0_3_0, IRQ0_A, SEL_IRQ_0_0), @@ -1277,6 +1278,289 @@ static const unsigned int mmc_ctrl_mux[] = { MMC_CLK_MARK, MMC_CMD_MARK, }; +/* - MSIOF0 ----------------------------------------------------------------- */ +static const unsigned int msiof0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 12), +}; + +static const unsigned int msiof0_clk_mux[] = { + MSIOF0_SCK_MARK, +}; + +static const unsigned int msiof0_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(4, 13), +}; + +static const unsigned int msiof0_sync_mux[] = { + MSIOF0_SYNC_MARK, +}; + +static const unsigned int msiof0_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(4, 20), +}; + +static const unsigned int msiof0_ss1_mux[] = { + MSIOF0_SS1_MARK, +}; + +static const unsigned int msiof0_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(4, 21), +}; + +static const unsigned int msiof0_ss2_mux[] = { + MSIOF0_SS2_MARK, +}; + +static const unsigned int msiof0_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(4, 14), +}; + +static const unsigned int msiof0_txd_mux[] = { + MSIOF0_TXD_MARK, +}; + +static const unsigned int msiof0_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(4, 15), +}; + +static const unsigned int msiof0_rxd_mux[] = { + MSIOF0_RXD_MARK, +}; + +/* - MSIOF1 ----------------------------------------------------------------- */ +static const unsigned int msiof1_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 16), +}; + +static const unsigned int msiof1_clk_mux[] = { + MSIOF1_SCK_MARK, +}; + +static const unsigned int msiof1_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(4, 19), +}; + +static const unsigned int msiof1_sync_mux[] = { + MSIOF1_SYNC_MARK, +}; + +static const unsigned int msiof1_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(4, 25), +}; + +static const unsigned int msiof1_ss1_mux[] = { + MSIOF1_SS1_MARK, +}; + +static const unsigned int msiof1_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(4, 22), +}; + +static const unsigned int msiof1_ss2_mux[] = { + MSIOF1_SS2_MARK, +}; + +static const unsigned int msiof1_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(4, 17), +}; + +static const unsigned int msiof1_txd_mux[] = { + MSIOF1_TXD_MARK, +}; + +static const unsigned int msiof1_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(4, 18), +}; + +static const unsigned int msiof1_rxd_mux[] = { + MSIOF1_RXD_MARK, +}; + +/* - MSIOF2 ----------------------------------------------------------------- */ +static const unsigned int msiof2_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 3), +}; + +static const unsigned int msiof2_clk_mux[] = { + MSIOF2_SCK_MARK, +}; + +static const unsigned int msiof2_sync_a_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 6), +}; + +static const unsigned int msiof2_sync_a_mux[] = { + MSIOF2_SYNC_A_MARK, +}; + +static const unsigned int msiof2_sync_b_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 2), +}; + +static const unsigned int msiof2_sync_b_mux[] = { + MSIOF2_SYNC_B_MARK, +}; + +static const unsigned int msiof2_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 7), +}; + +static const unsigned int msiof2_ss1_mux[] = { + MSIOF2_SS1_MARK, +}; + +static const unsigned int msiof2_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 8), +}; + +static const unsigned int msiof2_ss2_mux[] = { + MSIOF2_SS2_MARK, +}; + +static const unsigned int msiof2_txd_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 4), +}; + +static const unsigned int msiof2_txd_mux[] = { + MSIOF2_TXD_MARK, +}; + +static const unsigned int msiof2_rxd_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 5), +}; + +static const unsigned int msiof2_rxd_mux[] = { + MSIOF2_RXD_MARK, +}; + +/* - MSIOF3 ----------------------------------------------------------------- */ +static const unsigned int msiof3_clk_a_pins[] = { + /* SCK */ + RCAR_GP_PIN(2, 24), +}; + +static const unsigned int msiof3_clk_a_mux[] = { + MSIOF3_SCK_A_MARK, +}; + +static const unsigned int msiof3_sync_a_pins[] = { + /* SYNC */ + RCAR_GP_PIN(2, 21), +}; + +static const unsigned int msiof3_sync_a_mux[] = { + MSIOF3_SYNC_A_MARK, +}; + +static const unsigned int msiof3_ss1_a_pins[] = { + /* SS1 */ + RCAR_GP_PIN(2, 14), +}; + +static const unsigned int msiof3_ss1_a_mux[] = { + MSIOF3_SS1_A_MARK, +}; + +static const unsigned int msiof3_ss2_a_pins[] = { + /* SS2 */ + RCAR_GP_PIN(2, 10), +}; + +static const unsigned int msiof3_ss2_a_mux[] = { + MSIOF3_SS2_A_MARK, +}; + +static const unsigned int msiof3_txd_a_pins[] = { + /* TXD */ + RCAR_GP_PIN(2, 22), +}; + +static const unsigned int msiof3_txd_a_mux[] = { + MSIOF3_TXD_A_MARK, +}; + +static const unsigned int msiof3_rxd_a_pins[] = { + /* RXD */ + RCAR_GP_PIN(2, 23), +}; + +static const unsigned int msiof3_rxd_a_mux[] = { + MSIOF3_RXD_A_MARK, +}; + +static const unsigned int msiof3_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 8), +}; + +static const unsigned int msiof3_clk_b_mux[] = { + MSIOF3_SCK_B_MARK, +}; + +static const unsigned int msiof3_sync_b_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 9), +}; + +static const unsigned int msiof3_sync_b_mux[] = { + MSIOF3_SYNC_B_MARK, +}; + +static const unsigned int msiof3_ss1_b_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 6), +}; + +static const unsigned int msiof3_ss1_b_mux[] = { + MSIOF3_SS1_B_MARK, +}; + +static const unsigned int msiof3_ss2_b_pins[] = { + /* SS2 */ + RCAR_GP_PIN(1, 7), +}; + +static const unsigned int msiof3_ss2_b_mux[] = { + MSIOF3_SS2_B_MARK, +}; + +static const unsigned int msiof3_txd_b_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 0), +}; + +static const unsigned int msiof3_txd_b_mux[] = { + MSIOF3_TXD_B_MARK, +}; + +static const unsigned int msiof3_rxd_b_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 1), +}; + +static const unsigned int msiof3_rxd_b_mux[] = { + MSIOF3_RXD_B_MARK, +}; + /* - PWM0 ------------------------------------------------------------------ */ static const unsigned int pwm0_a_pins[] = { /* PWM */ @@ -1752,6 +2036,37 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(mmc_data4), SH_PFC_PIN_GROUP(mmc_data8), SH_PFC_PIN_GROUP(mmc_ctrl), + SH_PFC_PIN_GROUP(msiof0_clk), + SH_PFC_PIN_GROUP(msiof0_sync), + SH_PFC_PIN_GROUP(msiof0_ss1), + SH_PFC_PIN_GROUP(msiof0_ss2), + SH_PFC_PIN_GROUP(msiof0_txd), + SH_PFC_PIN_GROUP(msiof0_rxd), + SH_PFC_PIN_GROUP(msiof1_clk), + SH_PFC_PIN_GROUP(msiof1_sync), + SH_PFC_PIN_GROUP(msiof1_ss1), + SH_PFC_PIN_GROUP(msiof1_ss2), + SH_PFC_PIN_GROUP(msiof1_txd), + SH_PFC_PIN_GROUP(msiof1_rxd), + SH_PFC_PIN_GROUP(msiof2_clk), + SH_PFC_PIN_GROUP(msiof2_sync_a), + SH_PFC_PIN_GROUP(msiof2_sync_b), + SH_PFC_PIN_GROUP(msiof2_ss1), + SH_PFC_PIN_GROUP(msiof2_ss2), + SH_PFC_PIN_GROUP(msiof2_txd), + SH_PFC_PIN_GROUP(msiof2_rxd), + SH_PFC_PIN_GROUP(msiof3_clk_a), + SH_PFC_PIN_GROUP(msiof3_sync_a), + SH_PFC_PIN_GROUP(msiof3_ss1_a), + SH_PFC_PIN_GROUP(msiof3_ss2_a), + SH_PFC_PIN_GROUP(msiof3_txd_a), + SH_PFC_PIN_GROUP(msiof3_rxd_a), + SH_PFC_PIN_GROUP(msiof3_clk_b), + SH_PFC_PIN_GROUP(msiof3_sync_b), + SH_PFC_PIN_GROUP(msiof3_ss1_b), + SH_PFC_PIN_GROUP(msiof3_ss2_b), + SH_PFC_PIN_GROUP(msiof3_txd_b), + SH_PFC_PIN_GROUP(msiof3_rxd_b), SH_PFC_PIN_GROUP(pwm0_a), SH_PFC_PIN_GROUP(pwm0_b), SH_PFC_PIN_GROUP(pwm0_c), @@ -1982,6 +2297,49 @@ static const char * const vin4_groups[] = { "vin4_clk", }; +static const char * const msiof0_groups[] = { + "msiof0_clk", + "msiof0_sync", + "msiof0_ss1", + "msiof0_ss2", + "msiof0_txd", + "msiof0_rxd", +}; + +static const char * const msiof1_groups[] = { + "msiof1_clk", + "msiof1_sync", + "msiof1_ss1", + "msiof1_ss2", + "msiof1_txd", + "msiof1_rxd", +}; + +static const char * const msiof2_groups[] = { + "msiof2_clk", + "msiof2_sync_a", + "msiof2_sync_b", + "msiof2_ss1", + "msiof2_ss2", + "msiof2_txd", + "msiof2_rxd", +}; + +static const char * const msiof3_groups[] = { + "msiof3_clk_a", + "msiof3_sync_a", + "msiof3_ss1_a", + "msiof3_ss2_a", + "msiof3_txd_a", + "msiof3_rxd_a", + "msiof3_clk_b", + "msiof3_sync_b", + "msiof3_ss1_b", + "msiof3_ss2_b", + "msiof3_txd_b", + "msiof3_rxd_b", +}; + static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(audio_clk), SH_PFC_FUNCTION(avb0), @@ -1996,6 +2354,10 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(i2c2), SH_PFC_FUNCTION(i2c3), SH_PFC_FUNCTION(mmc), + SH_PFC_FUNCTION(msiof0), + SH_PFC_FUNCTION(msiof1), + SH_PFC_FUNCTION(msiof2), + SH_PFC_FUNCTION(msiof3), SH_PFC_FUNCTION(pwm0), SH_PFC_FUNCTION(pwm1), SH_PFC_FUNCTION(pwm2), diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7203.c b/drivers/pinctrl/sh-pfc/pfc-sh7203.c index 61b27ec48876..9ee468a9bd0e 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7203.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7203.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7203 Pinmux * * Copyright (C) 2008 Magnus Damm - * - * 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. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7264.c b/drivers/pinctrl/sh-pfc/pfc-sh7264.c index 8070765311db..4f44ce0d7237 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7264.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7264.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7264 Pinmux * * Copyright (C) 2012 Renesas Electronics Europe Ltd - * - * 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. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7269.c b/drivers/pinctrl/sh-pfc/pfc-sh7269.c index a50d22bef1f4..5b48a0368e55 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7269.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7269.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7269 Pinmux * * Copyright (C) 2012 Renesas Electronics Europe Ltd * Copyright (C) 2012 Phil Edworthy - * - * 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. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index d25e6f674d0a..654029fc8d96 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * sh73a0 processor support - PFC hardware block * * Copyright (C) 2010 Renesas Solutions Corp. * Copyright (C) 2010 NISHIMOTO Hiroki - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/io.h> #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7720.c b/drivers/pinctrl/sh-pfc/pfc-sh7720.c index e07a82df42c8..65694bfaa08d 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7720.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7720.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7720 Pinmux * * Copyright (C) 2008 Magnus Damm - * - * 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. */ #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7723.c b/drivers/pinctrl/sh-pfc/pfc-sh7723.c index 8ea18df03492..86f9a88726b7 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7723.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7723.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7723 Pinmux * * Copyright (C) 2008 Magnus Damm - * - * 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. */ #include <linux/init.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7724.c b/drivers/pinctrl/sh-pfc/pfc-sh7724.c index 7f6c36c1a8fa..2cc4aa7df613 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7724.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7724.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7724 Pinmux * @@ -7,10 +8,6 @@ * * Based on SH7723 Pinmux * Copyright (C) 2008 Magnus Damm - * - * 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. */ #include <linux/init.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c index 6502e676d368..b0533c86053a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7734 processor support - PFC hardware block * * Copyright (C) 2012 Renesas Solutions Corp. * Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> - * - * 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. */ #include <linux/init.h> #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7757.c b/drivers/pinctrl/sh-pfc/pfc-sh7757.c index 6d8c31caefc1..b16090690ee3 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7757.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7757.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7757 (B0 step) Pinmux * @@ -7,10 +8,6 @@ * * Based on SH7723 Pinmux * Copyright (C) 2008 Magnus Damm - * - * 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. */ #include <linux/init.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7785.c b/drivers/pinctrl/sh-pfc/pfc-sh7785.c index 1934cbec3965..193179f7fdd9 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7785.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7785.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7785 Pinmux * * Copyright (C) 2008 Magnus Damm - * - * 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. */ #include <linux/init.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7786.c b/drivers/pinctrl/sh-pfc/pfc-sh7786.c index c98585d80de8..cc2657c4f85c 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7786.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7786.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH7786 Pinmux * @@ -7,10 +8,6 @@ * Based on SH7785 pinmux * * Copyright (C) 2008 Magnus Damm - * - * 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. */ #include <linux/init.h> diff --git a/drivers/pinctrl/sh-pfc/pfc-shx3.c b/drivers/pinctrl/sh-pfc/pfc-shx3.c index 3f60c900645e..905ae00cc6f1 100644 --- a/drivers/pinctrl/sh-pfc/pfc-shx3.c +++ b/drivers/pinctrl/sh-pfc/pfc-shx3.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH-X3 prototype CPU pinmux * * Copyright (C) 2010 Paul Mundt - * - * 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. */ #include <linux/init.h> #include <linux/kernel.h> diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 654dc20e171b..274d5ff87078 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH Pin Function Controller pinmux support. * * Copyright (C) 2012 Paul Mundt - * - * 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. */ #define DRV_NAME "sh-pfc" diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h index 3d0b31636d6d..458ae0a6b540 100644 --- a/drivers/pinctrl/sh-pfc/sh_pfc.h +++ b/drivers/pinctrl/sh-pfc/sh_pfc.h @@ -1,11 +1,8 @@ -/* +/* SPDX-License-Identifier: GPL-2.0 + * * SuperH Pin Function Controller Support * * Copyright (c) 2008 Magnus Damm - * - * 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 __SH_PFC_H @@ -273,8 +270,11 @@ extern const struct sh_pfc_soc_info emev2_pinmux_info; extern const struct sh_pfc_soc_info r8a73a4_pinmux_info; extern const struct sh_pfc_soc_info r8a7740_pinmux_info; extern const struct sh_pfc_soc_info r8a7743_pinmux_info; +extern const struct sh_pfc_soc_info r8a7744_pinmux_info; extern const struct sh_pfc_soc_info r8a7745_pinmux_info; extern const struct sh_pfc_soc_info r8a77470_pinmux_info; +extern const struct sh_pfc_soc_info r8a774a1_pinmux_info; +extern const struct sh_pfc_soc_info r8a774c0_pinmux_info; extern const struct sh_pfc_soc_info r8a7778_pinmux_info; extern const struct sh_pfc_soc_info r8a7779_pinmux_info; extern const struct sh_pfc_soc_info r8a7790_pinmux_info; diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index 3abb028f6158..4ba171827428 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -19,14 +19,13 @@ #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/of_irq.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/pinconf-generic.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> /* Definition of Pad&Mux Properties */ #define N 0 @@ -5540,14 +5539,10 @@ static int atlas7_pinmux_resume_noirq(struct device *dev) { struct atlas7_pmx *pmx = dev_get_drvdata(dev); struct atlas7_pad_status *status; - struct atlas7_pad_config *conf; int idx; - u32 bank; for (idx = 0; idx < pmx->pctl_desc.npins; idx++) { /* Get this Pad's descriptor from PINCTRL */ - conf = &pmx->pctl_data->confs[idx]; - bank = atlas7_pin_to_bank(idx); status = &pmx->sleep_data[idx]; /* Restore Function selector */ @@ -6058,8 +6053,8 @@ static int atlas7_gpio_probe(struct platform_device *pdev) ret = gpiochip_add_data(chip, a7gc); if (ret) { dev_err(&pdev->dev, - "%s: error in probe function with status %d\n", - np->name, ret); + "%pOF: error in probe function with status %d\n", + np, ret); goto failed; } diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 505845c66dd0..2e42d738b589 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -27,7 +27,7 @@ #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/bitops.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/of_gpio.h> #include "pinctrl-sirf.h" diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h index aa5cf7032231..db029b148c87 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.h +++ b/drivers/pinctrl/spear/pinctrl-spear.h @@ -12,7 +12,7 @@ #ifndef __PINMUX_SPEAR_H__ #define __PINMUX_SPEAR_H__ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/io.h> #include <linux/pinctrl/pinctrl.h> #include <linux/types.h> diff --git a/drivers/pinctrl/sprd/pinctrl-sprd.c b/drivers/pinctrl/sprd/pinctrl-sprd.c index 78c2f548b25f..4537b5453996 100644 --- a/drivers/pinctrl/sprd/pinctrl-sprd.c +++ b/drivers/pinctrl/sprd/pinctrl-sprd.c @@ -1059,6 +1059,12 @@ int sprd_pinctrl_core_probe(struct platform_device *pdev, return ret; } + ret = sprd_pinctrl_parse_dt(sprd_pctl); + if (ret) { + dev_err(&pdev->dev, "fail to parse dt properties\n"); + return ret; + } + pin_desc = devm_kcalloc(&pdev->dev, pinctrl_info->npins, sizeof(struct pinctrl_pin_desc), @@ -1083,13 +1089,6 @@ int sprd_pinctrl_core_probe(struct platform_device *pdev, return PTR_ERR(sprd_pctl->pctl); } - ret = sprd_pinctrl_parse_dt(sprd_pctl); - if (ret) { - dev_err(&pdev->dev, "fail to parse dt properties\n"); - pinctrl_unregister(sprd_pctl->pctl); - return ret; - } - return 0; } diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index a9bec6e6fdd1..0fbfcc9ea07c 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -416,8 +416,8 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, pins = of_find_property(node, "pinmux", NULL); if (!pins) { - dev_err(pctl->dev, "missing pins property in node %s .\n", - node->name); + dev_err(pctl->dev, "missing pins property in node %pOFn .\n", + node); return -EINVAL; } diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 4d9bf9b3e9f3..34e17376ef99 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -332,15 +332,15 @@ static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, function = sunxi_pctrl_parse_function_prop(node); if (!function) { - dev_err(pctl->dev, "missing function property in node %s\n", - node->name); + dev_err(pctl->dev, "missing function property in node %pOFn\n", + node); return -EINVAL; } pin_prop = sunxi_pctrl_find_pins_prop(node, &npins); if (!pin_prop) { - dev_err(pctl->dev, "missing pins property in node %s\n", - node->name); + dev_err(pctl->dev, "missing pins property in node %pOFn\n", + node); return -EINVAL; } @@ -1042,6 +1042,7 @@ static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl, static int sunxi_pinctrl_build_state(struct platform_device *pdev) { struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); + void *ptr; int i; /* @@ -1079,10 +1080,9 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) * We suppose that we won't have any more functions than pins, * we'll reallocate that later anyway */ - pctl->functions = devm_kcalloc(&pdev->dev, - pctl->ngroups, - sizeof(*pctl->functions), - GFP_KERNEL); + pctl->functions = kcalloc(pctl->ngroups, + sizeof(*pctl->functions), + GFP_KERNEL); if (!pctl->functions) return -ENOMEM; @@ -1109,13 +1109,15 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) } /* And now allocated and fill the array for real */ - pctl->functions = krealloc(pctl->functions, - pctl->nfunctions * sizeof(*pctl->functions), - GFP_KERNEL); - if (!pctl->functions) { + ptr = krealloc(pctl->functions, + pctl->nfunctions * sizeof(*pctl->functions), + GFP_KERNEL); + if (!ptr) { kfree(pctl->functions); + pctl->functions = NULL; return -ENOMEM; } + pctl->functions = ptr; for (i = 0; i < pctl->desc->npins; i++) { const struct sunxi_desc_pin *pin = pctl->desc->pins + i; @@ -1133,8 +1135,10 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) func_item = sunxi_pinctrl_find_function_by_name(pctl, func->name); - if (!func_item) + if (!func_item) { + kfree(pctl->functions); return -EINVAL; + } if (!func_item->groups) { func_item->groups = @@ -1142,8 +1146,10 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) func_item->ngroups, sizeof(*func_item->groups), GFP_KERNEL); - if (!func_item->groups) + if (!func_item->groups) { + kfree(pctl->functions); return -ENOMEM; + } } func_grp = func_item->groups; diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index 1aba75897d14..a5008c066bac 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -737,4 +737,3 @@ int tegra_pinctrl_probe(struct platform_device *pdev, return 0; } -EXPORT_SYMBOL_GPL(tegra_pinctrl_probe); diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c index 8782c348ebe9..a4bc506a01a3 100644 --- a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c +++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c @@ -452,8 +452,8 @@ static int ti_iodelay_node_iterator(struct pinctrl_dev *pctldev, pin = ti_iodelay_offset_to_pin(iod, cfg[pin_index].offset); if (pin < 0) { - dev_err(iod->dev, "could not add functions for %s %ux\n", - np->name, cfg[pin_index].offset); + dev_err(iod->dev, "could not add functions for %pOFn %ux\n", + np, cfg[pin_index].offset); return -ENODEV; } pins[pin_index] = pin; @@ -461,8 +461,8 @@ static int ti_iodelay_node_iterator(struct pinctrl_dev *pctldev, pd = &iod->pa[pin]; pd->drv_data = &cfg[pin_index]; - dev_dbg(iod->dev, "%s offset=%x a_delay = %d g_delay = %d\n", - np->name, cfg[pin_index].offset, cfg[pin_index].a_delay, + dev_dbg(iod->dev, "%pOFn offset=%x a_delay = %d g_delay = %d\n", + np, cfg[pin_index].offset, cfg[pin_index].a_delay, cfg[pin_index].g_delay); return 0; diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c index 60722898d5c7..4326f5c3683c 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c @@ -1048,9 +1048,8 @@ static const unsigned nand_cs1_pins[] = {131, 132}; static const int nand_cs1_muxvals[] = {1, 1}; static const unsigned sd_pins[] = {150, 151, 152, 153, 154, 155, 156, 157, 158}; static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const unsigned sd1_pins[] = {319, 320, 321, 322, 323, 324, 325, 326, - 327}; -static const int sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const unsigned int sd1_pins[] = {319, 320, 321, 322, 323, 324, 325, 326}; +static const int sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0}; static const unsigned spi0_pins[] = {199, 200, 201, 202}; static const int spi0_muxvals[] = {11, 11, 11, 11}; static const unsigned spi1_pins[] = {195, 196, 197, 198, 235, 238, 239}; diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h index 0a3d2ac27503..c63e3c8b97cd 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier.h +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h @@ -16,7 +16,7 @@ #ifndef __PINCTRL_UNIPHIER_H__ #define __PINCTRL_UNIPHIER_H__ -#include <linux/bitops.h> +#include <linux/bits.h> #include <linux/build_bug.h> #include <linux/kernel.h> #include <linux/types.h> diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c index c08318a5a91b..ccdf68e766b8 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wmt.c +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -494,10 +494,8 @@ static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset) u32 val; val = readl_relaxed(data->base + reg_dir); - if (val & BIT(bit)) - return GPIOF_DIR_OUT; - else - return GPIOF_DIR_IN; + /* Return 0 == output, 1 == input */ + return !(val & BIT(bit)); } static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset) diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.h b/drivers/pinctrl/vt8500/pinctrl-wmt.h index 885613396fe7..ade8be3b98b0 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wmt.h +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.h @@ -13,7 +13,7 @@ * more details. */ -#include <linux/gpio.h> +#include <linux/gpio/driver.h> /* VT8500 has no enable register in the extgpio bank. */ #define NO_REG 0xFFFF diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 39d4100c60a2..7166f1cf8a1d 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -24,6 +24,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -88,9 +89,9 @@ static const struct property_entry fusb302_props[] = { { } }; -static int cht_int33fe_probe(struct i2c_client *client) +static int cht_int33fe_probe(struct platform_device *pdev) { - struct device *dev = &client->dev; + struct device *dev = &pdev->dev; struct i2c_board_info board_info; struct cht_int33fe_data *data; struct i2c_client *max17047; @@ -206,7 +207,7 @@ static int cht_int33fe_probe(struct i2c_client *client) if (!data->pi3usb30532) goto out_unregister_fusb302; - i2c_set_clientdata(client, data); + platform_set_drvdata(pdev, data); return 0; @@ -224,9 +225,9 @@ out_unregister_max17047: return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ } -static int cht_int33fe_remove(struct i2c_client *i2c) +static int cht_int33fe_remove(struct platform_device *pdev) { - struct cht_int33fe_data *data = i2c_get_clientdata(i2c); + struct cht_int33fe_data *data = platform_get_drvdata(pdev); i2c_unregister_device(data->pi3usb30532); i2c_unregister_device(data->fusb302); @@ -240,29 +241,22 @@ static int cht_int33fe_remove(struct i2c_client *i2c) return 0; } -static const struct i2c_device_id cht_int33fe_i2c_id[] = { - { } -}; -MODULE_DEVICE_TABLE(i2c, cht_int33fe_i2c_id); - static const struct acpi_device_id cht_int33fe_acpi_ids[] = { { "INT33FE", }, { } }; MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids); -static struct i2c_driver cht_int33fe_driver = { +static struct platform_driver cht_int33fe_driver = { .driver = { .name = "Intel Cherry Trail ACPI INT33FE driver", .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), }, - .probe_new = cht_int33fe_probe, + .probe = cht_int33fe_probe, .remove = cht_int33fe_remove, - .id_table = cht_int33fe_i2c_id, - .disable_i2c_core_irq_mapping = true, }; -module_i2c_driver(cht_int33fe_driver); +module_platform_driver(cht_int33fe_driver); MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver"); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c index a473dc51b18d..e89ad4964dc1 100644 --- a/drivers/platform/x86/intel_int0002_vgpio.c +++ b/drivers/platform/x86/intel_int0002_vgpio.c @@ -60,7 +60,7 @@ static const struct x86_cpu_id int0002_cpu_ids[] = { /* * Limit ourselves to Cherry Trail for now, until testing shows we * need to handle the INT0002 device on Baytrail too. - * ICPU(INTEL_FAM6_ATOM_SILVERMONT1), * Valleyview, Bay Trail * + * ICPU(INTEL_FAM6_ATOM_SILVERMONT), * Valleyview, Bay Trail * */ ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */ {} diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index d79fbf924b13..5ad44204a9c3 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -125,8 +125,8 @@ static const struct mid_pb_ddata mrfld_ddata = { { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata } static const struct x86_cpu_id mid_pb_cpu_ids[] = { - ICPU(INTEL_FAM6_ATOM_PENWELL, mfld_ddata), - ICPU(INTEL_FAM6_ATOM_MERRIFIELD, mrfld_ddata), + ICPU(INTEL_FAM6_ATOM_SALTWELL_MID, mfld_ddata), + ICPU(INTEL_FAM6_ATOM_SILVERMONT_MID, mrfld_ddata), {} }; diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c index ffd0474b0531..cee08f236292 100644 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ b/drivers/platform/x86/intel_telemetry_debugfs.c @@ -320,7 +320,7 @@ static struct telemetry_debugfs_conf telem_apl_debugfs_conf = { static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = { TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_debugfs_conf), - TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, telem_apl_debugfs_conf), + TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS, telem_apl_debugfs_conf), {} }; diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c index 2f889d6c270e..fcc6bee51a42 100644 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ b/drivers/platform/x86/intel_telemetry_pltdrv.c @@ -192,7 +192,7 @@ static struct telemetry_plt_config telem_glk_config = { static const struct x86_cpu_id telemetry_cpu_ids[] = { TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_config), - TELEM_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, telem_glk_config), + TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS, telem_glk_config), {} }; diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index 295d8dcba48c..6cdb2c14eee4 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1133,47 +1133,40 @@ static const struct rapl_defaults rapl_defaults_cht = { .compute_time_window = rapl_compute_time_window_atom, }; -#define RAPL_CPU(_model, _ops) { \ - .vendor = X86_VENDOR_INTEL, \ - .family = 6, \ - .model = _model, \ - .driver_data = (kernel_ulong_t)&_ops, \ - } - static const struct x86_cpu_id rapl_ids[] __initconst = { - RAPL_CPU(INTEL_FAM6_SANDYBRIDGE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_SANDYBRIDGE_X, rapl_defaults_core), - - RAPL_CPU(INTEL_FAM6_IVYBRIDGE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_IVYBRIDGE_X, rapl_defaults_core), - - RAPL_CPU(INTEL_FAM6_HASWELL_CORE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_HASWELL_ULT, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_HASWELL_GT3E, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_HASWELL_X, rapl_defaults_hsw_server), - - RAPL_CPU(INTEL_FAM6_BROADWELL_CORE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_BROADWELL_GT3E, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_BROADWELL_XEON_D, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_BROADWELL_X, rapl_defaults_hsw_server), - - RAPL_CPU(INTEL_FAM6_SKYLAKE_DESKTOP, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_SKYLAKE_MOBILE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_SKYLAKE_X, rapl_defaults_hsw_server), - RAPL_CPU(INTEL_FAM6_KABYLAKE_MOBILE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_KABYLAKE_DESKTOP, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_CANNONLAKE_MOBILE, rapl_defaults_core), - - RAPL_CPU(INTEL_FAM6_ATOM_SILVERMONT1, rapl_defaults_byt), - RAPL_CPU(INTEL_FAM6_ATOM_AIRMONT, rapl_defaults_cht), - RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD, rapl_defaults_tng), - RAPL_CPU(INTEL_FAM6_ATOM_MOOREFIELD, rapl_defaults_ann), - RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_ATOM_DENVERTON, rapl_defaults_core), - - RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server), - RAPL_CPU(INTEL_FAM6_XEON_PHI_KNM, rapl_defaults_hsw_server), + INTEL_CPU_FAM6(SANDYBRIDGE, rapl_defaults_core), + INTEL_CPU_FAM6(SANDYBRIDGE_X, rapl_defaults_core), + + INTEL_CPU_FAM6(IVYBRIDGE, rapl_defaults_core), + INTEL_CPU_FAM6(IVYBRIDGE_X, rapl_defaults_core), + + INTEL_CPU_FAM6(HASWELL_CORE, rapl_defaults_core), + INTEL_CPU_FAM6(HASWELL_ULT, rapl_defaults_core), + INTEL_CPU_FAM6(HASWELL_GT3E, rapl_defaults_core), + INTEL_CPU_FAM6(HASWELL_X, rapl_defaults_hsw_server), + + INTEL_CPU_FAM6(BROADWELL_CORE, rapl_defaults_core), + INTEL_CPU_FAM6(BROADWELL_GT3E, rapl_defaults_core), + INTEL_CPU_FAM6(BROADWELL_XEON_D, rapl_defaults_core), + INTEL_CPU_FAM6(BROADWELL_X, rapl_defaults_hsw_server), + + INTEL_CPU_FAM6(SKYLAKE_DESKTOP, rapl_defaults_core), + INTEL_CPU_FAM6(SKYLAKE_MOBILE, rapl_defaults_core), + INTEL_CPU_FAM6(SKYLAKE_X, rapl_defaults_hsw_server), + INTEL_CPU_FAM6(KABYLAKE_MOBILE, rapl_defaults_core), + INTEL_CPU_FAM6(KABYLAKE_DESKTOP, rapl_defaults_core), + INTEL_CPU_FAM6(CANNONLAKE_MOBILE, rapl_defaults_core), + + INTEL_CPU_FAM6(ATOM_SILVERMONT, rapl_defaults_byt), + INTEL_CPU_FAM6(ATOM_AIRMONT, rapl_defaults_cht), + INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, rapl_defaults_tng), + INTEL_CPU_FAM6(ATOM_AIRMONT_MID, rapl_defaults_ann), + INTEL_CPU_FAM6(ATOM_GOLDMONT, rapl_defaults_core), + INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, rapl_defaults_core), + INTEL_CPU_FAM6(ATOM_GOLDMONT_X, rapl_defaults_core), + + INTEL_CPU_FAM6(XEON_PHI_KNL, rapl_defaults_hsw_server), + INTEL_CPU_FAM6(XEON_PHI_KNM, rapl_defaults_hsw_server), {} }; MODULE_DEVICE_TABLE(x86cpu, rapl_ids); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 329cdd33ed62..926cee0d0b5f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -189,7 +189,7 @@ config REGULATOR_BD718XX and LDO regulators. This driver can also be built as a module. If so, the module - will be called bd71837-regulator. + will be called bd718x7-regulator. config REGULATOR_BD9571MWV tristate "ROHM BD9571MWV Regulators" @@ -356,6 +356,13 @@ config REGULATOR_LM363X One boost output voltage is configurable and always on. Other LDOs are used for the display module. +config REGULATOR_LOCHNAGAR + tristate "Cirrus Logic Lochnagar regulator driver" + depends on MFD_LOCHNAGAR + help + This enables regulator support on the Cirrus Logic Lochnagar audio + development board. + config REGULATOR_LP3971 tristate "National Semiconductors LP3971 PMIC regulator driver" depends on I2C @@ -803,6 +810,18 @@ config REGULATOR_STM32_VREFBUF This driver can also be built as a module. If so, the module will be called stm32-vrefbuf. +config REGULATOR_STPMIC1 + tristate "STMicroelectronics STPMIC1 PMIC Regulators" + depends on MFD_STPMIC1 + help + This driver supports STMicroelectronics STPMIC1 PMIC voltage + regulators and switches. The STPMIC1 regulators supply power to + an application processor as well as to external system + peripherals such as DDR, Flash memories and system devices. + + To compile this driver as a module, choose M here: the + module will be called stpmic1_regulator. + config REGULATOR_TI_ABB tristate "TI Adaptive Body Bias on-chip LDO" depends on ARCH_OMAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 801d9a34a203..72488ef11b8a 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o -obj-$(CONFIG_REGULATOR_BD718XX) += bd71837-regulator.o +obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o @@ -46,6 +46,7 @@ obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o +obj-$(CONFIG_REGULATOR_LOCHNAGAR) += lochnagar-regulator.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o @@ -101,6 +102,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o +obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index e976d073f28d..9a72eae4926d 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -260,7 +260,7 @@ static int arizona_ldo1_common_init(struct platform_device *pdev, * so clean up would happen at the wrong time */ config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena", - GPIOD_OUT_LOW); + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); if (IS_ERR(config.ena_gpiod)) return PTR_ERR(config.ena_gpiod); diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 91b8ff8bac15..a3734039a86a 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -509,10 +509,10 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) /* * AXP803/AXP813 DCDC work frequency setting has the same * range and step as AXP22X, but at a different register. - * Fall through to the check below. * (See include/linux/mfd/axp20x.h) */ reg = AXP803_DCDC_FREQ_CTRL; + /* Fall through to the check below.*/ case AXP806_ID: /* * AXP806 also have DCDC work frequency setting register at a @@ -520,6 +520,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) */ if (axp20x->variant == AXP806_ID) reg = AXP806_DCDC_FREQ_CTRL; + /* Fall through */ case AXP221_ID: case AXP223_ID: case AXP809_ID: diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c deleted file mode 100644 index a1bd8aaf4d98..000000000000 --- a/drivers/regulator/bd71837-regulator.c +++ /dev/null @@ -1,645 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2018 ROHM Semiconductors -// bd71837-regulator.c ROHM BD71837MWV regulator driver - -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/gpio.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/mfd/rohm-bd718x7.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/machine.h> -#include <linux/regulator/of_regulator.h> -#include <linux/slab.h> - -struct bd71837_pmic { - struct regulator_desc descs[BD71837_REGULATOR_CNT]; - struct bd71837 *mfd; - struct platform_device *pdev; - struct regulator_dev *rdev[BD71837_REGULATOR_CNT]; -}; - -/* - * BUCK1/2/3/4 - * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting - * 00: 10.00mV/usec 10mV 1uS - * 01: 5.00mV/usec 10mV 2uS - * 10: 2.50mV/usec 10mV 4uS - * 11: 1.25mV/usec 10mV 8uS - */ -static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev, - int ramp_delay) -{ - struct bd71837_pmic *pmic = rdev_get_drvdata(rdev); - struct bd71837 *mfd = pmic->mfd; - int id = rdev->desc->id; - unsigned int ramp_value = BUCK_RAMPRATE_10P00MV; - - dev_dbg(&pmic->pdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1, - ramp_delay); - switch (ramp_delay) { - case 1 ... 1250: - ramp_value = BUCK_RAMPRATE_1P25MV; - break; - case 1251 ... 2500: - ramp_value = BUCK_RAMPRATE_2P50MV; - break; - case 2501 ... 5000: - ramp_value = BUCK_RAMPRATE_5P00MV; - break; - case 5001 ... 10000: - ramp_value = BUCK_RAMPRATE_10P00MV; - break; - default: - ramp_value = BUCK_RAMPRATE_10P00MV; - dev_err(&pmic->pdev->dev, - "%s: ramp_delay: %d not supported, setting 10000mV//us\n", - rdev->desc->name, ramp_delay); - } - - return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id, - BUCK_RAMPRATE_MASK, ramp_value << 6); -} - -/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed. - * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage - * is changed. Hence we return -EBUSY for these if voltage is changed - * when BUCK/LDO is enabled. - */ -static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev, - unsigned int sel) -{ - if (regulator_is_enabled_regmap(rdev)) - return -EBUSY; - - return regulator_set_voltage_sel_regmap(rdev, sel); -} - -static struct regulator_ops bd71837_ldo_regulator_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .list_voltage = regulator_list_voltage_linear_range, - .set_voltage_sel = bd71837_set_voltage_sel_restricted, - .get_voltage_sel = regulator_get_voltage_sel_regmap, -}; - -static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .list_voltage = regulator_list_voltage_table, - .set_voltage_sel = bd71837_set_voltage_sel_restricted, - .get_voltage_sel = regulator_get_voltage_sel_regmap, -}; - -static struct regulator_ops bd71837_buck_regulator_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .list_voltage = regulator_list_voltage_linear_range, - .set_voltage_sel = bd71837_set_voltage_sel_restricted, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, -}; - -static struct regulator_ops bd71837_buck_regulator_nolinear_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .list_voltage = regulator_list_voltage_table, - .set_voltage_sel = bd71837_set_voltage_sel_restricted, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, -}; - -static struct regulator_ops bd71837_buck1234_regulator_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .list_voltage = regulator_list_voltage_linear_range, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = bd71837_buck1234_set_ramp_delay, -}; - -/* - * BUCK1/2/3/4 - * 0.70 to 1.30V (10mV step) - */ -static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000), - REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0), -}; - -/* - * BUCK5 - * 0.9V to 1.35V () - */ -static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000), - REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000), - REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000), -}; - -/* - * BUCK6 - * 3.0V to 3.3V (step 100mV) - */ -static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000), -}; - -/* - * BUCK7 - * 000 = 1.605V - * 001 = 1.695V - * 010 = 1.755V - * 011 = 1.8V (Initial) - * 100 = 1.845V - * 101 = 1.905V - * 110 = 1.95V - * 111 = 1.995V - */ -static const unsigned int buck_7_volts[] = { - 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000 -}; - -/* - * BUCK8 - * 0.8V to 1.40V (step 10mV) - */ -static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000), - REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0), -}; - -/* - * LDO1 - * 3.0 to 3.3V (100mV step) - */ -static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000), -}; - -/* - * LDO2 - * 0.8 or 0.9V - */ -static const unsigned int ldo_2_volts[] = { - 900000, 800000 -}; - -/* - * LDO3 - * 1.8 to 3.3V (100mV step) - */ -static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), -}; - -/* - * LDO4 - * 0.9 to 1.8V (100mV step) - */ -static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000), - REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0), -}; - -/* - * LDO5 - * 1.8 to 3.3V (100mV step) - */ -static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), -}; - -/* - * LDO6 - * 0.9 to 1.8V (100mV step) - */ -static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000), - REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0), -}; - -/* - * LDO7 - * 1.8 to 3.3V (100mV step) - */ -static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = { - REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), -}; - -static const struct regulator_desc bd71837_regulators[] = { - { - .name = "buck1", - .of_match = of_match_ptr("BUCK1"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK1, - .ops = &bd71837_buck1234_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_BUCK1_VOLTAGE_NUM, - .linear_ranges = bd71837_buck1234_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), - .vsel_reg = BD71837_REG_BUCK1_VOLT_RUN, - .vsel_mask = BUCK1_RUN_MASK, - .enable_reg = BD71837_REG_BUCK1_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "buck2", - .of_match = of_match_ptr("BUCK2"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK2, - .ops = &bd71837_buck1234_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_BUCK2_VOLTAGE_NUM, - .linear_ranges = bd71837_buck1234_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), - .vsel_reg = BD71837_REG_BUCK2_VOLT_RUN, - .vsel_mask = BUCK2_RUN_MASK, - .enable_reg = BD71837_REG_BUCK2_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "buck3", - .of_match = of_match_ptr("BUCK3"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK3, - .ops = &bd71837_buck1234_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_BUCK3_VOLTAGE_NUM, - .linear_ranges = bd71837_buck1234_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), - .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN, - .vsel_mask = BUCK3_RUN_MASK, - .enable_reg = BD71837_REG_BUCK3_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "buck4", - .of_match = of_match_ptr("BUCK4"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK4, - .ops = &bd71837_buck1234_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_BUCK4_VOLTAGE_NUM, - .linear_ranges = bd71837_buck1234_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), - .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN, - .vsel_mask = BUCK4_RUN_MASK, - .enable_reg = BD71837_REG_BUCK4_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "buck5", - .of_match = of_match_ptr("BUCK5"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK5, - .ops = &bd71837_buck_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_BUCK5_VOLTAGE_NUM, - .linear_ranges = bd71837_buck5_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges), - .vsel_reg = BD71837_REG_BUCK5_VOLT, - .vsel_mask = BUCK5_MASK, - .enable_reg = BD71837_REG_BUCK5_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "buck6", - .of_match = of_match_ptr("BUCK6"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK6, - .ops = &bd71837_buck_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_BUCK6_VOLTAGE_NUM, - .linear_ranges = bd71837_buck6_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges), - .vsel_reg = BD71837_REG_BUCK6_VOLT, - .vsel_mask = BUCK6_MASK, - .enable_reg = BD71837_REG_BUCK6_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "buck7", - .of_match = of_match_ptr("BUCK7"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK7, - .ops = &bd71837_buck_regulator_nolinear_ops, - .type = REGULATOR_VOLTAGE, - .volt_table = &buck_7_volts[0], - .n_voltages = ARRAY_SIZE(buck_7_volts), - .vsel_reg = BD71837_REG_BUCK7_VOLT, - .vsel_mask = BUCK7_MASK, - .enable_reg = BD71837_REG_BUCK7_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "buck8", - .of_match = of_match_ptr("BUCK8"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_BUCK8, - .ops = &bd71837_buck_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_BUCK8_VOLTAGE_NUM, - .linear_ranges = bd71837_buck8_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges), - .vsel_reg = BD71837_REG_BUCK8_VOLT, - .vsel_mask = BUCK8_MASK, - .enable_reg = BD71837_REG_BUCK8_CTRL, - .enable_mask = BD71837_BUCK_EN, - .owner = THIS_MODULE, - }, - { - .name = "ldo1", - .of_match = of_match_ptr("LDO1"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_LDO1, - .ops = &bd71837_ldo_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_LDO1_VOLTAGE_NUM, - .linear_ranges = bd71837_ldo1_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges), - .vsel_reg = BD71837_REG_LDO1_VOLT, - .vsel_mask = LDO1_MASK, - .enable_reg = BD71837_REG_LDO1_VOLT, - .enable_mask = BD71837_LDO_EN, - .owner = THIS_MODULE, - }, - { - .name = "ldo2", - .of_match = of_match_ptr("LDO2"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_LDO2, - .ops = &bd71837_ldo_regulator_nolinear_ops, - .type = REGULATOR_VOLTAGE, - .volt_table = &ldo_2_volts[0], - .vsel_reg = BD71837_REG_LDO2_VOLT, - .vsel_mask = LDO2_MASK, - .n_voltages = ARRAY_SIZE(ldo_2_volts), - .n_voltages = BD71837_LDO2_VOLTAGE_NUM, - .enable_reg = BD71837_REG_LDO2_VOLT, - .enable_mask = BD71837_LDO_EN, - .owner = THIS_MODULE, - }, - { - .name = "ldo3", - .of_match = of_match_ptr("LDO3"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_LDO3, - .ops = &bd71837_ldo_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_LDO3_VOLTAGE_NUM, - .linear_ranges = bd71837_ldo3_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges), - .vsel_reg = BD71837_REG_LDO3_VOLT, - .vsel_mask = LDO3_MASK, - .enable_reg = BD71837_REG_LDO3_VOLT, - .enable_mask = BD71837_LDO_EN, - .owner = THIS_MODULE, - }, - { - .name = "ldo4", - .of_match = of_match_ptr("LDO4"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_LDO4, - .ops = &bd71837_ldo_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_LDO4_VOLTAGE_NUM, - .linear_ranges = bd71837_ldo4_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges), - .vsel_reg = BD71837_REG_LDO4_VOLT, - .vsel_mask = LDO4_MASK, - .enable_reg = BD71837_REG_LDO4_VOLT, - .enable_mask = BD71837_LDO_EN, - .owner = THIS_MODULE, - }, - { - .name = "ldo5", - .of_match = of_match_ptr("LDO5"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_LDO5, - .ops = &bd71837_ldo_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_LDO5_VOLTAGE_NUM, - .linear_ranges = bd71837_ldo5_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges), - /* LDO5 is supplied by buck6 */ - .supply_name = "buck6", - .vsel_reg = BD71837_REG_LDO5_VOLT, - .vsel_mask = LDO5_MASK, - .enable_reg = BD71837_REG_LDO5_VOLT, - .enable_mask = BD71837_LDO_EN, - .owner = THIS_MODULE, - }, - { - .name = "ldo6", - .of_match = of_match_ptr("LDO6"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_LDO6, - .ops = &bd71837_ldo_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_LDO6_VOLTAGE_NUM, - .linear_ranges = bd71837_ldo6_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges), - /* LDO6 is supplied by buck7 */ - .supply_name = "buck7", - .vsel_reg = BD71837_REG_LDO6_VOLT, - .vsel_mask = LDO6_MASK, - .enable_reg = BD71837_REG_LDO6_VOLT, - .enable_mask = BD71837_LDO_EN, - .owner = THIS_MODULE, - }, - { - .name = "ldo7", - .of_match = of_match_ptr("LDO7"), - .regulators_node = of_match_ptr("regulators"), - .id = BD71837_LDO7, - .ops = &bd71837_ldo_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD71837_LDO7_VOLTAGE_NUM, - .linear_ranges = bd71837_ldo7_voltage_ranges, - .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges), - .vsel_reg = BD71837_REG_LDO7_VOLT, - .vsel_mask = LDO7_MASK, - .enable_reg = BD71837_REG_LDO7_VOLT, - .enable_mask = BD71837_LDO_EN, - .owner = THIS_MODULE, - }, -}; - -struct reg_init { - unsigned int reg; - unsigned int mask; -}; - -static int bd71837_probe(struct platform_device *pdev) -{ - struct bd71837_pmic *pmic; - struct regulator_config config = { 0 }; - struct reg_init pmic_regulator_inits[] = { - { - .reg = BD71837_REG_BUCK1_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_BUCK2_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_BUCK3_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_BUCK4_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_BUCK5_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_BUCK6_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_BUCK7_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_BUCK8_CTRL, - .mask = BD71837_BUCK_SEL, - }, { - .reg = BD71837_REG_LDO1_VOLT, - .mask = BD71837_LDO_SEL, - }, { - .reg = BD71837_REG_LDO2_VOLT, - .mask = BD71837_LDO_SEL, - }, { - .reg = BD71837_REG_LDO3_VOLT, - .mask = BD71837_LDO_SEL, - }, { - .reg = BD71837_REG_LDO4_VOLT, - .mask = BD71837_LDO_SEL, - }, { - .reg = BD71837_REG_LDO5_VOLT, - .mask = BD71837_LDO_SEL, - }, { - .reg = BD71837_REG_LDO6_VOLT, - .mask = BD71837_LDO_SEL, - }, { - .reg = BD71837_REG_LDO7_VOLT, - .mask = BD71837_LDO_SEL, - } - }; - - int i, err; - - pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); - if (!pmic) - return -ENOMEM; - - memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs)); - - pmic->pdev = pdev; - pmic->mfd = dev_get_drvdata(pdev->dev.parent); - - if (!pmic->mfd) { - dev_err(&pdev->dev, "No MFD driver data\n"); - err = -EINVAL; - goto err; - } - platform_set_drvdata(pdev, pmic); - - /* Register LOCK release */ - err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK, - (REGLOCK_PWRSEQ | REGLOCK_VREG), 0); - if (err) { - dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err); - goto err; - } else { - dev_dbg(&pmic->pdev->dev, "Unlocked lock register 0x%x\n", - BD71837_REG_REGLOCK); - } - - /* - * There is a HW quirk in BD71837. The shutdown sequence timings for - * bucks/LDOs which are controlled via register interface are changed. - * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the - * beginning of shut-down sequence. As bucks 6 and 7 are parent - * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage - * monitoring to errorneously detect under voltage and force PMIC to - * emergency state instead of poweroff. In order to avoid this we - * disable voltage monitoring for LDO5 and LDO6 - */ - err = regmap_update_bits(pmic->mfd->regmap, BD718XX_REG_MVRFLTMASK2, - BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80, - BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80); - if (err) { - dev_err(&pmic->pdev->dev, - "Failed to disable voltage monitoring\n"); - goto err; - } - - for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) { - - struct regulator_desc *desc; - struct regulator_dev *rdev; - - desc = &pmic->descs[i]; - - config.dev = pdev->dev.parent; - config.driver_data = pmic; - config.regmap = pmic->mfd->regmap; - - rdev = devm_regulator_register(&pdev->dev, desc, &config); - if (IS_ERR(rdev)) { - dev_err(pmic->mfd->dev, - "failed to register %s regulator\n", - desc->name); - err = PTR_ERR(rdev); - goto err; - } - /* Regulator register gets the regulator constraints and - * applies them (set_machine_constraints). This should have - * turned the control register(s) to correct values and we - * can now switch the control from PMIC state machine to the - * register interface - */ - err = regmap_update_bits(pmic->mfd->regmap, - pmic_regulator_inits[i].reg, - pmic_regulator_inits[i].mask, - 0xFFFFFFFF); - if (err) { - dev_err(&pmic->pdev->dev, - "Failed to write BUCK/LDO SEL bit for (%s)\n", - desc->name); - goto err; - } - - pmic->rdev[i] = rdev; - } - -err: - return err; -} - -static struct platform_driver bd71837_regulator = { - .driver = { - .name = "bd71837-pmic", - }, - .probe = bd71837_probe, -}; - -module_platform_driver(bd71837_regulator); - -MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); -MODULE_DESCRIPTION("BD71837 voltage regulator driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c new file mode 100644 index 000000000000..3a47e0372e77 --- /dev/null +++ b/drivers/regulator/bd718x7-regulator.c @@ -0,0 +1,1119 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 ROHM Semiconductors +// bd71837-regulator.c ROHM BD71837MWV/BD71847MWV regulator driver + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/rohm-bd718x7.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +/* + * BUCK1/2/3/4 + * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting + * 00: 10.00mV/usec 10mV 1uS + * 01: 5.00mV/usec 10mV 2uS + * 10: 2.50mV/usec 10mV 4uS + * 11: 1.25mV/usec 10mV 8uS + */ +static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + int id = rdev->desc->id; + unsigned int ramp_value = BUCK_RAMPRATE_10P00MV; + + dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1, + ramp_delay); + switch (ramp_delay) { + case 1 ... 1250: + ramp_value = BUCK_RAMPRATE_1P25MV; + break; + case 1251 ... 2500: + ramp_value = BUCK_RAMPRATE_2P50MV; + break; + case 2501 ... 5000: + ramp_value = BUCK_RAMPRATE_5P00MV; + break; + case 5001 ... 10000: + ramp_value = BUCK_RAMPRATE_10P00MV; + break; + default: + ramp_value = BUCK_RAMPRATE_10P00MV; + dev_err(&rdev->dev, + "%s: ramp_delay: %d not supported, setting 10000mV//us\n", + rdev->desc->name, ramp_delay); + } + + return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id, + BUCK_RAMPRATE_MASK, ramp_value << 6); +} + +/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed. + * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage + * is changed. Hence we return -EBUSY for these if voltage is changed + * when BUCK/LDO is enabled. + */ +static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel) +{ + if (regulator_is_enabled_regmap(rdev)) + return -EBUSY; + + return regulator_set_voltage_sel_regmap(rdev, sel); +} + +static int bd718xx_set_voltage_sel_pickable_restricted( + struct regulator_dev *rdev, unsigned int sel) +{ + if (regulator_is_enabled_regmap(rdev)) + return -EBUSY; + + return regulator_set_voltage_sel_pickable_regmap(rdev, sel); +} + +static struct regulator_ops bd718xx_pickable_range_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, +}; + +static struct regulator_ops bd718xx_pickable_range_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops bd718xx_ldo_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = bd718xx_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = bd718xx_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static struct regulator_ops bd718xx_buck_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = bd718xx_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = bd718xx_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops bd718xx_dvs_buck_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = bd718xx_buck1234_set_ramp_delay, +}; + +/* + * BD71837 BUCK1/2/3/4 + * BD71847 BUCK1/2 + * 0.70 to 1.30V (10mV step) + */ +static const struct regulator_linear_range bd718xx_dvs_buck_volts[] = { + REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000), + REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0), +}; + +/* + * BD71837 BUCK5 + * 0.7V to 1.35V (range 0) + * and + * 0.675 to 1.325 (range 1) + */ +static const struct regulator_linear_range bd71837_buck5_volts[] = { + /* Ranges when VOLT_SEL bit is 0 */ + REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000), + REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000), + REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000), + /* Ranges when VOLT_SEL bit is 1 */ + REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000), + REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000), + REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000), +}; + +/* + * Range selector for first 3 linear ranges is 0x0 + * and 0x1 for last 3 ranges. + */ +static const unsigned int bd71837_buck5_volt_range_sel[] = { + 0x0, 0x0, 0x0, 0x80, 0x80, 0x80 +}; + +/* + * BD71847 BUCK3 + */ +static const struct regulator_linear_range bd71847_buck3_volts[] = { + /* Ranges when VOLT_SEL bits are 00 */ + REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000), + REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000), + REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000), + /* Ranges when VOLT_SEL bits are 01 */ + REGULATOR_LINEAR_RANGE(550000, 0x0, 0x7, 50000), + /* Ranges when VOLT_SEL bits are 11 */ + REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000), + REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000), + REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000), +}; + +static const unsigned int bd71847_buck3_volt_range_sel[] = { + 0x0, 0x0, 0x0, 0x40, 0x80, 0x80, 0x80 +}; + +static const struct regulator_linear_range bd71847_buck4_volts[] = { + REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000), + REGULATOR_LINEAR_RANGE(2600000, 0x00, 0x03, 100000), +}; + +static const unsigned int bd71847_buck4_volt_range_sel[] = { 0x0, 0x40 }; + +/* + * BUCK6 + * 3.0V to 3.3V (step 100mV) + */ +static const struct regulator_linear_range bd71837_buck6_volts[] = { + REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000), +}; + +/* + * BD71837 BUCK7 + * BD71847 BUCK5 + * 000 = 1.605V + * 001 = 1.695V + * 010 = 1.755V + * 011 = 1.8V (Initial) + * 100 = 1.845V + * 101 = 1.905V + * 110 = 1.95V + * 111 = 1.995V + */ +static const unsigned int bd718xx_3rd_nodvs_buck_volts[] = { + 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000 +}; + +/* + * BUCK8 + * 0.8V to 1.40V (step 10mV) + */ +static const struct regulator_linear_range bd718xx_4th_nodvs_buck_volts[] = { + REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000), +}; + +/* + * LDO1 + * 3.0 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd718xx_ldo1_volts[] = { + REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000), + REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000), +}; + +static const unsigned int bd718xx_ldo1_volt_range_sel[] = { 0x0, 0x20 }; + +/* + * LDO2 + * 0.8 or 0.9V + */ +static const unsigned int ldo_2_volts[] = { + 900000, 800000 +}; + +/* + * LDO3 + * 1.8 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd718xx_ldo3_volts[] = { + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), +}; + +/* + * LDO4 + * 0.9 to 1.8V (100mV step) + */ +static const struct regulator_linear_range bd718xx_ldo4_volts[] = { + REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000), +}; + +/* + * LDO5 for BD71837 + * 1.8 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo5_volts[] = { + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), +}; + +/* + * LDO5 for BD71837 + * 1.8 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd71847_ldo5_volts[] = { + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), + REGULATOR_LINEAR_RANGE(800000, 0x00, 0x0F, 100000), +}; + +static const unsigned int bd71847_ldo5_volt_range_sel[] = { 0x0, 0x20 }; + +/* + * LDO6 + * 0.9 to 1.8V (100mV step) + */ +static const struct regulator_linear_range bd718xx_ldo6_volts[] = { + REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000), +}; + +/* + * LDO7 + * 1.8 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo7_volts[] = { + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), +}; + +struct reg_init { + unsigned int reg; + unsigned int mask; + unsigned int val; +}; +struct bd718xx_regulator_data { + struct regulator_desc desc; + const struct reg_init init; + const struct reg_init *additional_inits; + int additional_init_amnt; +}; + +/* + * There is a HW quirk in BD71837. The shutdown sequence timings for + * bucks/LDOs which are controlled via register interface are changed. + * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the + * beginning of shut-down sequence. As bucks 6 and 7 are parent + * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage + * monitoring to errorneously detect under voltage and force PMIC to + * emergency state instead of poweroff. In order to avoid this we + * disable voltage monitoring for LDO5 and LDO6 + */ +static const struct reg_init bd71837_ldo5_inits[] = { + { + .reg = BD718XX_REG_MVRFLTMASK2, + .mask = BD718XX_LDO5_VRMON80, + .val = BD718XX_LDO5_VRMON80, + }, +}; + +static const struct reg_init bd71837_ldo6_inits[] = { + { + .reg = BD718XX_REG_MVRFLTMASK2, + .mask = BD718XX_LDO6_VRMON80, + .val = BD718XX_LDO6_VRMON80, + }, +}; + +static const struct bd718xx_regulator_data bd71847_regulators[] = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("BUCK1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK1, + .ops = &bd718xx_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_dvs_buck_volts, + .n_linear_ranges = + ARRAY_SIZE(bd718xx_dvs_buck_volts), + .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN, + .vsel_mask = DVS_BUCK_RUN_MASK, + .enable_reg = BD718XX_REG_BUCK1_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_BUCK1_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("BUCK2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK2, + .ops = &bd718xx_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_dvs_buck_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts), + .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN, + .vsel_mask = DVS_BUCK_RUN_MASK, + .enable_reg = BD718XX_REG_BUCK2_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_BUCK2_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck3", + .of_match = of_match_ptr("BUCK3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK3, + .ops = &bd718xx_pickable_range_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71847_BUCK3_VOLTAGE_NUM, + .linear_ranges = bd71847_buck3_volts, + .n_linear_ranges = + ARRAY_SIZE(bd71847_buck3_volts), + .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT, + .vsel_mask = BD718XX_1ST_NODVS_BUCK_MASK, + .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT, + .vsel_range_mask = BD71847_BUCK3_RANGE_MASK, + .linear_range_selectors = bd71847_buck3_volt_range_sel, + .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("BUCK4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK4, + .ops = &bd718xx_pickable_range_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71847_BUCK4_VOLTAGE_NUM, + .linear_ranges = bd71847_buck4_volts, + .n_linear_ranges = + ARRAY_SIZE(bd71847_buck4_volts), + .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL, + .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT, + .vsel_mask = BD71847_BUCK4_MASK, + .vsel_range_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT, + .vsel_range_mask = BD71847_BUCK4_RANGE_MASK, + .linear_range_selectors = bd71847_buck4_volt_range_sel, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck5", + .of_match = of_match_ptr("BUCK5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK5, + .ops = &bd718xx_buck_regulator_nolinear_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &bd718xx_3rd_nodvs_buck_volts[0], + .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts), + .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT, + .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK, + .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck6", + .of_match = of_match_ptr("BUCK6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK6, + .ops = &bd718xx_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_4th_nodvs_buck_volts, + .n_linear_ranges = + ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts), + .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT, + .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK, + .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "ldo1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO1, + .ops = &bd718xx_pickable_range_ldo_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO1_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo1_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts), + .vsel_reg = BD718XX_REG_LDO1_VOLT, + .vsel_mask = BD718XX_LDO1_MASK, + .vsel_range_reg = BD718XX_REG_LDO1_VOLT, + .vsel_range_mask = BD718XX_LDO1_RANGE_MASK, + .linear_range_selectors = bd718xx_ldo1_volt_range_sel, + .enable_reg = BD718XX_REG_LDO1_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO1_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo2", + .of_match = of_match_ptr("LDO2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO2, + .ops = &bd718xx_ldo_regulator_nolinear_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &ldo_2_volts[0], + .vsel_reg = BD718XX_REG_LDO2_VOLT, + .vsel_mask = BD718XX_LDO2_MASK, + .n_voltages = ARRAY_SIZE(ldo_2_volts), + .enable_reg = BD718XX_REG_LDO2_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO2_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo3", + .of_match = of_match_ptr("LDO3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO3, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO3_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo3_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts), + .vsel_reg = BD718XX_REG_LDO3_VOLT, + .vsel_mask = BD718XX_LDO3_MASK, + .enable_reg = BD718XX_REG_LDO3_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO3_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo4", + .of_match = of_match_ptr("LDO4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO4, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO4_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo4_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts), + .vsel_reg = BD718XX_REG_LDO4_VOLT, + .vsel_mask = BD718XX_LDO4_MASK, + .enable_reg = BD718XX_REG_LDO4_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO4_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo5", + .of_match = of_match_ptr("LDO5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO5, + .ops = &bd718xx_pickable_range_ldo_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71847_LDO5_VOLTAGE_NUM, + .linear_ranges = bd71847_ldo5_volts, + .n_linear_ranges = ARRAY_SIZE(bd71847_ldo5_volts), + .vsel_reg = BD718XX_REG_LDO5_VOLT, + .vsel_mask = BD71847_LDO5_MASK, + .vsel_range_reg = BD718XX_REG_LDO5_VOLT, + .vsel_range_mask = BD71847_LDO5_RANGE_MASK, + .linear_range_selectors = bd71847_ldo5_volt_range_sel, + .enable_reg = BD718XX_REG_LDO5_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO5_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo6", + .of_match = of_match_ptr("LDO6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO6, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO6_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo6_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts), + /* LDO6 is supplied by buck5 */ + .supply_name = "buck5", + .vsel_reg = BD718XX_REG_LDO6_VOLT, + .vsel_mask = BD718XX_LDO6_MASK, + .enable_reg = BD718XX_REG_LDO6_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO6_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, +}; + +static const struct bd718xx_regulator_data bd71837_regulators[] = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("BUCK1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK1, + .ops = &bd718xx_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_dvs_buck_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts), + .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN, + .vsel_mask = DVS_BUCK_RUN_MASK, + .enable_reg = BD718XX_REG_BUCK1_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_BUCK1_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("BUCK2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK2, + .ops = &bd718xx_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_dvs_buck_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts), + .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN, + .vsel_mask = DVS_BUCK_RUN_MASK, + .enable_reg = BD718XX_REG_BUCK2_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_BUCK2_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck3", + .of_match = of_match_ptr("BUCK3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK3, + .ops = &bd718xx_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_dvs_buck_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts), + .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN, + .vsel_mask = DVS_BUCK_RUN_MASK, + .enable_reg = BD71837_REG_BUCK3_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD71837_REG_BUCK3_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("BUCK4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK4, + .ops = &bd718xx_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_dvs_buck_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts), + .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN, + .vsel_mask = DVS_BUCK_RUN_MASK, + .enable_reg = BD71837_REG_BUCK4_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD71837_REG_BUCK4_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck5", + .of_match = of_match_ptr("BUCK5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK5, + .ops = &bd718xx_pickable_range_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK5_VOLTAGE_NUM, + .linear_ranges = bd71837_buck5_volts, + .n_linear_ranges = + ARRAY_SIZE(bd71837_buck5_volts), + .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT, + .vsel_mask = BD71837_BUCK5_MASK, + .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT, + .vsel_range_mask = BD71837_BUCK5_RANGE_MASK, + .linear_range_selectors = bd71837_buck5_volt_range_sel, + .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck6", + .of_match = of_match_ptr("BUCK6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK6, + .ops = &bd718xx_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK6_VOLTAGE_NUM, + .linear_ranges = bd71837_buck6_volts, + .n_linear_ranges = + ARRAY_SIZE(bd71837_buck6_volts), + .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT, + .vsel_mask = BD71837_BUCK6_MASK, + .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck7", + .of_match = of_match_ptr("BUCK7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK7, + .ops = &bd718xx_buck_regulator_nolinear_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &bd718xx_3rd_nodvs_buck_volts[0], + .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts), + .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT, + .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK, + .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "buck8", + .of_match = of_match_ptr("BUCK8"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_BUCK8, + .ops = &bd718xx_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM, + .linear_ranges = bd718xx_4th_nodvs_buck_volts, + .n_linear_ranges = + ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts), + .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT, + .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK, + .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL, + .enable_mask = BD718XX_BUCK_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL, + .mask = BD718XX_BUCK_SEL, + .val = BD718XX_BUCK_SEL, + }, + }, + { + .desc = { + .name = "ldo1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO1, + .ops = &bd718xx_pickable_range_ldo_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO1_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo1_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts), + .vsel_reg = BD718XX_REG_LDO1_VOLT, + .vsel_mask = BD718XX_LDO1_MASK, + .vsel_range_reg = BD718XX_REG_LDO1_VOLT, + .vsel_range_mask = BD718XX_LDO1_RANGE_MASK, + .linear_range_selectors = bd718xx_ldo1_volt_range_sel, + .enable_reg = BD718XX_REG_LDO1_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO1_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo2", + .of_match = of_match_ptr("LDO2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO2, + .ops = &bd718xx_ldo_regulator_nolinear_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &ldo_2_volts[0], + .vsel_reg = BD718XX_REG_LDO2_VOLT, + .vsel_mask = BD718XX_LDO2_MASK, + .n_voltages = ARRAY_SIZE(ldo_2_volts), + .enable_reg = BD718XX_REG_LDO2_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO2_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo3", + .of_match = of_match_ptr("LDO3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO3, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO3_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo3_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts), + .vsel_reg = BD718XX_REG_LDO3_VOLT, + .vsel_mask = BD718XX_LDO3_MASK, + .enable_reg = BD718XX_REG_LDO3_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO3_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo4", + .of_match = of_match_ptr("LDO4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO4, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO4_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo4_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts), + .vsel_reg = BD718XX_REG_LDO4_VOLT, + .vsel_mask = BD718XX_LDO4_MASK, + .enable_reg = BD718XX_REG_LDO4_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO4_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, + { + .desc = { + .name = "ldo5", + .of_match = of_match_ptr("LDO5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO5, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO5_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo5_volts, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_volts), + /* LDO5 is supplied by buck6 */ + .supply_name = "buck6", + .vsel_reg = BD718XX_REG_LDO5_VOLT, + .vsel_mask = BD71837_LDO5_MASK, + .enable_reg = BD718XX_REG_LDO5_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO5_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + .additional_inits = bd71837_ldo5_inits, + .additional_init_amnt = ARRAY_SIZE(bd71837_ldo5_inits), + }, + { + .desc = { + .name = "ldo6", + .of_match = of_match_ptr("LDO6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO6, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD718XX_LDO6_VOLTAGE_NUM, + .linear_ranges = bd718xx_ldo6_volts, + .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts), + /* LDO6 is supplied by buck7 */ + .supply_name = "buck7", + .vsel_reg = BD718XX_REG_LDO6_VOLT, + .vsel_mask = BD718XX_LDO6_MASK, + .enable_reg = BD718XX_REG_LDO6_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD718XX_REG_LDO6_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + .additional_inits = bd71837_ldo6_inits, + .additional_init_amnt = ARRAY_SIZE(bd71837_ldo6_inits), + }, + { + .desc = { + .name = "ldo7", + .of_match = of_match_ptr("LDO7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD718XX_LDO7, + .ops = &bd718xx_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO7_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo7_volts, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_volts), + .vsel_reg = BD71837_REG_LDO7_VOLT, + .vsel_mask = BD71837_LDO7_MASK, + .enable_reg = BD71837_REG_LDO7_VOLT, + .enable_mask = BD718XX_LDO_EN, + .owner = THIS_MODULE, + }, + .init = { + .reg = BD71837_REG_LDO7_VOLT, + .mask = BD718XX_LDO_SEL, + .val = BD718XX_LDO_SEL, + }, + }, +}; + +struct bd718xx_pmic_inits { + const struct bd718xx_regulator_data (*r_datas)[]; + unsigned int r_amount; +}; + +static int bd718xx_probe(struct platform_device *pdev) +{ + struct bd718xx *mfd; + struct regulator_config config = { 0 }; + struct bd718xx_pmic_inits pmic_regulators[] = { + [BD718XX_TYPE_BD71837] = { + .r_datas = &bd71837_regulators, + .r_amount = ARRAY_SIZE(bd71837_regulators), + }, + [BD718XX_TYPE_BD71847] = { + .r_datas = &bd71847_regulators, + .r_amount = ARRAY_SIZE(bd71847_regulators), + }, + }; + + int i, j, err; + + mfd = dev_get_drvdata(pdev->dev.parent); + if (!mfd) { + dev_err(&pdev->dev, "No MFD driver data\n"); + err = -EINVAL; + goto err; + } + + if (mfd->chip_type >= BD718XX_TYPE_AMOUNT || + !pmic_regulators[mfd->chip_type].r_datas) { + dev_err(&pdev->dev, "Unsupported chip type\n"); + err = -EINVAL; + goto err; + } + + /* Register LOCK release */ + err = regmap_update_bits(mfd->regmap, BD718XX_REG_REGLOCK, + (REGLOCK_PWRSEQ | REGLOCK_VREG), 0); + if (err) { + dev_err(&pdev->dev, "Failed to unlock PMIC (%d)\n", err); + goto err; + } else { + dev_dbg(&pdev->dev, "Unlocked lock register 0x%x\n", + BD718XX_REG_REGLOCK); + } + + for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) { + + const struct regulator_desc *desc; + struct regulator_dev *rdev; + const struct bd718xx_regulator_data *r; + + r = &(*pmic_regulators[mfd->chip_type].r_datas)[i]; + desc = &r->desc; + + config.dev = pdev->dev.parent; + config.regmap = mfd->regmap; + + rdev = devm_regulator_register(&pdev->dev, desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "failed to register %s regulator\n", + desc->name); + err = PTR_ERR(rdev); + goto err; + } + /* Regulator register gets the regulator constraints and + * applies them (set_machine_constraints). This should have + * turned the control register(s) to correct values and we + * can now switch the control from PMIC state machine to the + * register interface + */ + err = regmap_update_bits(mfd->regmap, r->init.reg, + r->init.mask, r->init.val); + if (err) { + dev_err(&pdev->dev, + "Failed to write BUCK/LDO SEL bit for (%s)\n", + desc->name); + goto err; + } + for (j = 0; j < r->additional_init_amnt; j++) { + err = regmap_update_bits(mfd->regmap, + r->additional_inits[j].reg, + r->additional_inits[j].mask, + r->additional_inits[j].val); + if (err) { + dev_err(&pdev->dev, + "Buck (%s) initialization failed\n", + desc->name); + goto err; + } + } + } + +err: + return err; +} + +static struct platform_driver bd718xx_regulator = { + .driver = { + .name = "bd718xx-pmic", + }, + .probe = bd718xx_probe, +}; + +module_platform_driver(bd718xx_regulator); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("BD71837/BD71847 voltage regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9577d8941846..2c66b528aede 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -426,19 +426,24 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(name); -static ssize_t regulator_print_opmode(char *buf, int mode) +static const char *regulator_opmode_to_str(int mode) { switch (mode) { case REGULATOR_MODE_FAST: - return sprintf(buf, "fast\n"); + return "fast"; case REGULATOR_MODE_NORMAL: - return sprintf(buf, "normal\n"); + return "normal"; case REGULATOR_MODE_IDLE: - return sprintf(buf, "idle\n"); + return "idle"; case REGULATOR_MODE_STANDBY: - return sprintf(buf, "standby\n"); + return "standby"; } - return sprintf(buf, "unknown\n"); + return "unknown"; +} + +static ssize_t regulator_print_opmode(char *buf, int mode) +{ + return sprintf(buf, "%s\n", regulator_opmode_to_str(mode)); } static ssize_t regulator_opmode_show(struct device *dev, @@ -2783,6 +2788,11 @@ static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV, if (desc->ops->list_voltage == regulator_list_voltage_linear_range) return regulator_map_voltage_linear_range(rdev, min_uV, max_uV); + if (desc->ops->list_voltage == + regulator_list_voltage_pickable_linear_range) + return regulator_map_voltage_pickable_linear_range(rdev, + min_uV, max_uV); + return regulator_map_voltage_iterate(rdev, min_uV, max_uV); } @@ -3470,21 +3480,23 @@ out: } EXPORT_SYMBOL_GPL(regulator_set_current_limit); +static int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev) +{ + /* sanity check */ + if (!rdev->desc->ops->get_current_limit) + return -EINVAL; + + return rdev->desc->ops->get_current_limit(rdev); +} + static int _regulator_get_current_limit(struct regulator_dev *rdev) { int ret; regulator_lock(rdev); - - /* sanity check */ - if (!rdev->desc->ops->get_current_limit) { - ret = -EINVAL; - goto out; - } - - ret = rdev->desc->ops->get_current_limit(rdev); -out: + ret = _regulator_get_current_limit_unlocked(rdev); regulator_unlock(rdev); + return ret; } @@ -3549,21 +3561,23 @@ out: } EXPORT_SYMBOL_GPL(regulator_set_mode); +static unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev) +{ + /* sanity check */ + if (!rdev->desc->ops->get_mode) + return -EINVAL; + + return rdev->desc->ops->get_mode(rdev); +} + static unsigned int _regulator_get_mode(struct regulator_dev *rdev) { int ret; regulator_lock(rdev); - - /* sanity check */ - if (!rdev->desc->ops->get_mode) { - ret = -EINVAL; - goto out; - } - - ret = rdev->desc->ops->get_mode(rdev); -out: + ret = _regulator_get_mode_unlocked(rdev); regulator_unlock(rdev); + return ret; } @@ -4455,41 +4469,33 @@ void regulator_unregister(struct regulator_dev *rdev) EXPORT_SYMBOL_GPL(regulator_unregister); #ifdef CONFIG_SUSPEND -static int _regulator_suspend(struct device *dev, void *data) -{ - struct regulator_dev *rdev = dev_to_rdev(dev); - suspend_state_t *state = data; - int ret; - - regulator_lock(rdev); - ret = suspend_set_state(rdev, *state); - regulator_unlock(rdev); - - return ret; -} - /** * regulator_suspend - prepare regulators for system wide suspend - * @state: system suspend state + * @dev: ``&struct device`` pointer that is passed to _regulator_suspend() * * Configure each regulator with it's suspend operating parameters for state. */ static int regulator_suspend(struct device *dev) { + struct regulator_dev *rdev = dev_to_rdev(dev); suspend_state_t state = pm_suspend_target_state; + int ret; + + regulator_lock(rdev); + ret = suspend_set_state(rdev, state); + regulator_unlock(rdev); - return class_for_each_device(®ulator_class, NULL, &state, - _regulator_suspend); + return ret; } -static int _regulator_resume(struct device *dev, void *data) +static int regulator_resume(struct device *dev) { - int ret = 0; + suspend_state_t state = pm_suspend_target_state; struct regulator_dev *rdev = dev_to_rdev(dev); - suspend_state_t *state = data; struct regulator_state *rstate; + int ret = 0; - rstate = regulator_get_suspend_state(rdev, *state); + rstate = regulator_get_suspend_state(rdev, state); if (rstate == NULL) return 0; @@ -4504,15 +4510,6 @@ static int _regulator_resume(struct device *dev, void *data) return ret; } - -static int regulator_resume(struct device *dev) -{ - suspend_state_t state = pm_suspend_target_state; - - return class_for_each_device(®ulator_class, NULL, &state, - _regulator_resume); -} - #else /* !CONFIG_SUSPEND */ #define regulator_suspend NULL @@ -4670,17 +4667,23 @@ static void regulator_summary_show_subtree(struct seq_file *s, struct regulation_constraints *c; struct regulator *consumer; struct summary_data summary_data; + unsigned int opmode; if (!rdev) return; - seq_printf(s, "%*s%-*s %3d %4d %6d ", + regulator_lock_nested(rdev, level); + + opmode = _regulator_get_mode_unlocked(rdev); + seq_printf(s, "%*s%-*s %3d %4d %6d %7s ", level * 3 + 1, "", 30 - level * 3, rdev_get_name(rdev), - rdev->use_count, rdev->open_count, rdev->bypass_count); + rdev->use_count, rdev->open_count, rdev->bypass_count, + regulator_opmode_to_str(opmode)); seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000); - seq_printf(s, "%5dmA ", _regulator_get_current_limit(rdev) / 1000); + seq_printf(s, "%5dmA ", + _regulator_get_current_limit_unlocked(rdev) / 1000); c = rdev->constraints; if (c) { @@ -4709,7 +4712,8 @@ static void regulator_summary_show_subtree(struct seq_file *s, switch (rdev->desc->type) { case REGULATOR_VOLTAGE: - seq_printf(s, "%37dmV %5dmV", + seq_printf(s, "%37dmA %5dmV %5dmV", + consumer->uA_load / 1000, consumer->voltage[PM_SUSPEND_ON].min_uV / 1000, consumer->voltage[PM_SUSPEND_ON].max_uV / 1000); break; @@ -4726,6 +4730,8 @@ static void regulator_summary_show_subtree(struct seq_file *s, class_for_each_device(®ulator_class, NULL, &summary_data, regulator_summary_show_children); + + regulator_unlock(rdev); } static int regulator_summary_show_roots(struct device *dev, void *data) @@ -4741,8 +4747,8 @@ static int regulator_summary_show_roots(struct device *dev, void *data) static int regulator_summary_show(struct seq_file *s, void *data) { - seq_puts(s, " regulator use open bypass voltage current min max\n"); - seq_puts(s, "-------------------------------------------------------------------------------\n"); + seq_puts(s, " regulator use open bypass opmode voltage current min max\n"); + seq_puts(s, "---------------------------------------------------------------------------------------\n"); class_for_each_device(®ulator_class, NULL, s, regulator_summary_show_roots); diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 9ececfef42d6..37e4025203e3 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -420,7 +420,7 @@ static int da9052_regulator_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.driver_data = regulator; config.regmap = da9052->regmap; - if (pdata && pdata->regulators) { + if (pdata) { config.init_data = pdata->regulators[cell->id]; } else { #ifdef CONFIG_OF diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index f40c3b8644ae..588c3d2445cf 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -612,7 +612,7 @@ static int da9055_regulator_probe(struct platform_device *pdev) config.driver_data = regulator; config.regmap = da9055->regmap; - if (pdata && pdata->regulators) { + if (pdata) { config.init_data = pdata->regulators[pdev->id]; } else { ret = da9055_regulator_dt_init(pdev, regulator, &config, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 6c122b3df5d0..8f68c7a05d27 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -294,11 +294,11 @@ static struct da9211_pdata *da9211_parse_regulators_dt( pdata->init_data[n] = da9211_matches[i].init_data; pdata->reg_node[n] = da9211_matches[i].of_node; pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev, - da9211_matches[i].of_node, - "enable", - 0, - GPIOD_OUT_HIGH, - "da9211-enable"); + da9211_matches[i].of_node, + "enable", + 0, + GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, + "da9211-enable"); n++; } diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c index 777fac6fb4cb..2c6098e6f4bc 100644 --- a/drivers/regulator/fixed-helper.c +++ b/drivers/regulator/fixed-helper.c @@ -43,7 +43,6 @@ struct platform_device *regulator_register_always_on(int id, const char *name, } data->cfg.microvolts = uv; - data->cfg.gpio = -EINVAL; data->cfg.enabled_at_boot = 1; data->cfg.init_data = &data->init_data; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 988a7472c2ab..ccc29038f19a 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -24,10 +24,9 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/fixed.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/machine.h> @@ -78,15 +77,16 @@ of_get_fixed_voltage_config(struct device *dev, if (init_data->constraints.boot_on) config->enabled_at_boot = true; - config->gpio = of_get_named_gpio(np, "gpio", 0); - if ((config->gpio < 0) && (config->gpio != -ENOENT)) - return ERR_PTR(config->gpio); - of_property_read_u32(np, "startup-delay-us", &config->startup_delay); - config->enable_high = of_property_read_bool(np, "enable-active-high"); - config->gpio_is_open_drain = of_property_read_bool(np, - "gpio-open-drain"); + /* + * FIXME: we pulled active low/high and open drain handling into + * gpiolib so it will be handled there. Delete this in the second + * step when we also remove the custom inversion handling for all + * legacy boardfiles. + */ + config->enable_high = 1; + config->gpio_is_open_drain = 0; if (of_find_property(np, "vin-supply", NULL)) config->input_supply = "vin"; @@ -102,6 +102,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; struct regulator_config cfg = { }; + enum gpiod_flags gflags; int ret; drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), @@ -150,25 +151,41 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.fixed_uV = config->microvolts; - if (gpio_is_valid(config->gpio)) { - cfg.ena_gpio = config->gpio; - if (pdev->dev.of_node) - cfg.ena_gpio_initialized = true; - } cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + gflags = GPIOD_OUT_HIGH; else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + gflags = GPIOD_OUT_LOW; } else { if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + gflags = GPIOD_OUT_LOW; else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + gflags = GPIOD_OUT_HIGH; } - if (config->gpio_is_open_drain) - cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; + if (config->gpio_is_open_drain) { + if (gflags == GPIOD_OUT_HIGH) + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + else + gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + } + + /* + * Some fixed regulators share the enable line between two + * regulators which makes it necessary to get a handle on the + * same descriptor for two different consumers. This will get + * the GPIO descriptor, but only the first call will initialize + * it so any flags such as inversion or open drain will only + * be set up by the first caller and assumed identical on the + * next caller. + * + * FIXME: find a better way to deal with this. + */ + gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE; + + cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags); + if (IS_ERR(cfg.ena_gpiod)) + return PTR_ERR(cfg.ena_gpiod); cfg.dev = &pdev->dev; cfg.init_data = config->init_data; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 2ae7c3ac5940..5686a1335bd3 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -103,6 +103,128 @@ int regulator_disable_regmap(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(regulator_disable_regmap); +static int regulator_range_selector_to_index(struct regulator_dev *rdev, + unsigned int rval) +{ + int i; + + if (!rdev->desc->linear_range_selectors) + return -EINVAL; + + rval &= rdev->desc->vsel_range_mask; + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + if (rdev->desc->linear_range_selectors[i] == rval) + return i; + } + return -EINVAL; +} + +/** + * regulator_get_voltage_sel_pickable_regmap - pickable range get_voltage_sel + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O and use pickable + * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask + * fields in their descriptor and then use this as their get_voltage_vsel + * operation, saving some code. + */ +int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) +{ + unsigned int r_val; + int range; + unsigned int val; + int ret, i; + unsigned int voltages_in_range = 0; + + if (!rdev->desc->linear_ranges) + return -EINVAL; + + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); + if (ret != 0) + return ret; + + ret = regmap_read(rdev->regmap, rdev->desc->vsel_range_reg, &r_val); + if (ret != 0) + return ret; + + val &= rdev->desc->vsel_mask; + val >>= ffs(rdev->desc->vsel_mask) - 1; + + range = regulator_range_selector_to_index(rdev, r_val); + if (range < 0) + return -EINVAL; + + for (i = 0; i < range; i++) + voltages_in_range += (rdev->desc->linear_ranges[i].max_sel - + rdev->desc->linear_ranges[i].min_sel) + 1; + + return val + voltages_in_range; +} +EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap); + +/** + * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel + * + * @rdev: regulator to operate on + * @sel: Selector to set + * + * Regulators that use regmap for their register I/O and use pickable + * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask + * fields in their descriptor and then use this as their set_voltage_vsel + * operation, saving some code. + */ +int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, + unsigned int sel) +{ + unsigned int range; + int ret, i; + unsigned int voltages_in_range = 0; + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + voltages_in_range = (rdev->desc->linear_ranges[i].max_sel - + rdev->desc->linear_ranges[i].min_sel) + 1; + if (sel < voltages_in_range) + break; + sel -= voltages_in_range; + } + + if (i == rdev->desc->n_linear_ranges) + return -EINVAL; + + sel <<= ffs(rdev->desc->vsel_mask) - 1; + sel += rdev->desc->linear_ranges[i].min_sel; + + range = rdev->desc->linear_range_selectors[i]; + + if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) { + ret = regmap_update_bits(rdev->regmap, + rdev->desc->vsel_reg, + rdev->desc->vsel_range_mask | + rdev->desc->vsel_mask, sel | range); + } else { + ret = regmap_update_bits(rdev->regmap, + rdev->desc->vsel_range_reg, + rdev->desc->vsel_range_mask, range); + if (ret) + return ret; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); + } + + if (ret) + return ret; + + if (rdev->desc->apply_bit) + ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg, + rdev->desc->apply_bit, + rdev->desc->apply_bit); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap); + /** * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users * @@ -321,20 +443,91 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev, ret += range->min_sel; - break; + /* + * Map back into a voltage to verify we're still in bounds. + * If we are not, then continue checking rest of the ranges. + */ + voltage = rdev->desc->ops->list_voltage(rdev, ret); + if (voltage >= min_uV && voltage <= max_uV) + break; } if (i == rdev->desc->n_linear_ranges) return -EINVAL; - /* Map back into a voltage to verify we're still in bounds */ - voltage = rdev->desc->ops->list_voltage(rdev, ret); - if (voltage < min_uV || voltage > max_uV) + return ret; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range); + +/** + * regulator_map_voltage_pickable_linear_range - map_voltage, pickable ranges + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers providing pickable linear_ranges in their descriptor can use + * this as their map_voltage() callback. + */ +int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + const struct regulator_linear_range *range; + int ret = -EINVAL; + int voltage, i; + unsigned int selector = 0; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + int linear_max_uV; + + range = &rdev->desc->linear_ranges[i]; + linear_max_uV = range->min_uV + + (range->max_sel - range->min_sel) * range->uV_step; + + if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) { + selector += (range->max_sel - range->min_sel + 1); + continue; + } + + if (min_uV <= range->min_uV) + min_uV = range->min_uV; + + /* range->uV_step == 0 means fixed voltage range */ + if (range->uV_step == 0) { + ret = 0; + } else { + ret = DIV_ROUND_UP(min_uV - range->min_uV, + range->uV_step); + if (ret < 0) + return ret; + } + + ret += selector; + + voltage = rdev->desc->ops->list_voltage(rdev, ret); + + /* + * Map back into a voltage to verify we're still in bounds. + * We may have overlapping voltage ranges. Hence we don't + * exit but retry until we have checked all ranges. + */ + if (voltage < min_uV || voltage > max_uV) + selector += (range->max_sel - range->min_sel + 1); + else + break; + } + + if (i == rdev->desc->n_linear_ranges) return -EINVAL; return ret; } -EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range); +EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range); /** * regulator_list_voltage_linear - List voltages with simple calculation @@ -361,6 +554,46 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev, EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); /** + * regulator_list_voltage_pickable_linear_range - pickable range list voltages + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * list_voltage() operation, intended to be used by drivers utilizing pickable + * ranges helpers. + */ +int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct regulator_linear_range *range; + int i; + unsigned int all_sels = 0; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + unsigned int sels_in_range; + + range = &rdev->desc->linear_ranges[i]; + + sels_in_range = range->max_sel - range->min_sel; + + if (all_sels + sels_in_range >= selector) { + selector -= all_sels; + return range->min_uV + (range->uV_step * selector); + } + + all_sels += (sels_in_range + 1); + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range); + +/** * regulator_list_voltage_linear_range - List voltages for linear ranges * * @rdev: Regulator device diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 257c1943e753..9c2607e912cf 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -84,6 +84,7 @@ static const struct regulator_desc isl9305_regulators[] = { .enable_mask = ISL9305_DCD1_EN, .supply_name = "VINDCD1", .ops = &isl9305_ops, + .owner = THIS_MODULE, }, [ISL9305_DCD2] = { .name = "DCD2", @@ -98,6 +99,7 @@ static const struct regulator_desc isl9305_regulators[] = { .enable_mask = ISL9305_DCD2_EN, .supply_name = "VINDCD2", .ops = &isl9305_ops, + .owner = THIS_MODULE, }, [ISL9305_LDO1] = { .name = "LDO1", @@ -112,6 +114,7 @@ static const struct regulator_desc isl9305_regulators[] = { .enable_mask = ISL9305_LDO1_EN, .supply_name = "VINLDO1", .ops = &isl9305_ops, + .owner = THIS_MODULE, }, [ISL9305_LDO2] = { .name = "LDO2", @@ -126,6 +129,7 @@ static const struct regulator_desc isl9305_regulators[] = { .enable_mask = ISL9305_LDO2_EN, .supply_name = "VINLDO2", .ops = &isl9305_ops, + .owner = THIS_MODULE, }, }; diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c index b615a413ca9f..bbedb08d257b 100644 --- a/drivers/regulator/lm363x-regulator.c +++ b/drivers/regulator/lm363x-regulator.c @@ -227,9 +227,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, */ switch (id) { case LM3632_LDO_POS: - return devm_gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW); + return devm_gpiod_get_index_optional(dev, "enable", 0, + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); case LM3632_LDO_NEG: - return devm_gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW); + return devm_gpiod_get_index_optional(dev, "enable", 1, + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); default: return NULL; } diff --git a/drivers/regulator/lochnagar-regulator.c b/drivers/regulator/lochnagar-regulator.c new file mode 100644 index 000000000000..2b5073b9ff86 --- /dev/null +++ b/drivers/regulator/lochnagar-regulator.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Lochnagar regulator driver +// +// Copyright (c) 2017-2018 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. +// +// Author: Charles Keepax <ckeepax@opensource.cirrus.com> + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> + +#include <linux/mfd/lochnagar.h> + +static const struct regulator_ops lochnagar_micvdd_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_linear_range lochnagar_micvdd_ranges[] = { + REGULATOR_LINEAR_RANGE(1000000, 0, 0xC, 50000), + REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000), +}; + +static int lochnagar_micbias_enable(struct regulator_dev *rdev) +{ + struct lochnagar *lochnagar = rdev_get_drvdata(rdev); + int ret; + + mutex_lock(&lochnagar->analogue_config_lock); + + ret = regulator_enable_regmap(rdev); + if (ret < 0) + goto err; + + ret = lochnagar_update_config(lochnagar); + +err: + mutex_unlock(&lochnagar->analogue_config_lock); + + return ret; +} + +static int lochnagar_micbias_disable(struct regulator_dev *rdev) +{ + struct lochnagar *lochnagar = rdev_get_drvdata(rdev); + int ret; + + mutex_lock(&lochnagar->analogue_config_lock); + + ret = regulator_disable_regmap(rdev); + if (ret < 0) + goto err; + + ret = lochnagar_update_config(lochnagar); + +err: + mutex_unlock(&lochnagar->analogue_config_lock); + + return ret; +} + +static const struct regulator_ops lochnagar_micbias_ops = { + .enable = lochnagar_micbias_enable, + .disable = lochnagar_micbias_disable, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_ops lochnagar_vddcore_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_linear_range lochnagar_vddcore_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500), +}; + +enum lochnagar_regulators { + LOCHNAGAR_MICVDD, + LOCHNAGAR_MIC1VDD, + LOCHNAGAR_MIC2VDD, + LOCHNAGAR_VDDCORE, +}; + +static int lochnagar_micbias_of_parse(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct lochnagar *lochnagar = config->driver_data; + int shift = (desc->id - LOCHNAGAR_MIC1VDD) * + LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT; + int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift; + unsigned int val; + int ret; + + ret = of_property_read_u32(np, "cirrus,micbias-input", &val); + if (ret >= 0) { + mutex_lock(&lochnagar->analogue_config_lock); + ret = regmap_update_bits(lochnagar->regmap, + LOCHNAGAR2_ANALOGUE_PATH_CTRL2, + mask, val << shift); + mutex_unlock(&lochnagar->analogue_config_lock); + if (ret < 0) { + dev_err(lochnagar->dev, + "Failed to update micbias source: %d\n", ret); + return ret; + } + } + + return 0; +} + +static const struct regulator_desc lochnagar_regulators[] = { + [LOCHNAGAR_MICVDD] = { + .name = "MICVDD", + .supply_name = "SYSVDD", + .type = REGULATOR_VOLTAGE, + .n_voltages = 32, + .ops = &lochnagar_micvdd_ops, + + .id = LOCHNAGAR_MICVDD, + .of_match = of_match_ptr("MICVDD"), + + .enable_reg = LOCHNAGAR2_MICVDD_CTRL1, + .enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK, + .vsel_reg = LOCHNAGAR2_MICVDD_CTRL2, + .vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK, + + .linear_ranges = lochnagar_micvdd_ranges, + .n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges), + + .enable_time = 3000, + .ramp_delay = 1000, + + .owner = THIS_MODULE, + }, + [LOCHNAGAR_MIC1VDD] = { + .name = "MIC1VDD", + .supply_name = "MICBIAS1", + .type = REGULATOR_VOLTAGE, + .ops = &lochnagar_micbias_ops, + + .id = LOCHNAGAR_MIC1VDD, + .of_match = of_match_ptr("MIC1VDD"), + .of_parse_cb = lochnagar_micbias_of_parse, + + .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2, + .enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK, + + .owner = THIS_MODULE, + }, + [LOCHNAGAR_MIC2VDD] = { + .name = "MIC2VDD", + .supply_name = "MICBIAS2", + .type = REGULATOR_VOLTAGE, + .ops = &lochnagar_micbias_ops, + + .id = LOCHNAGAR_MIC2VDD, + .of_match = of_match_ptr("MIC2VDD"), + .of_parse_cb = lochnagar_micbias_of_parse, + + .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2, + .enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK, + + .owner = THIS_MODULE, + }, + [LOCHNAGAR_VDDCORE] = { + .name = "VDDCORE", + .supply_name = "SYSVDD", + .type = REGULATOR_VOLTAGE, + .n_voltages = 57, + .ops = &lochnagar_vddcore_ops, + + .id = LOCHNAGAR_VDDCORE, + .of_match = of_match_ptr("VDDCORE"), + + .enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1, + .enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK, + .vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2, + .vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK, + + .linear_ranges = lochnagar_vddcore_ranges, + .n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges), + + .enable_time = 3000, + .ramp_delay = 1000, + + .owner = THIS_MODULE, + }, +}; + +static int lochnagar_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lochnagar *lochnagar = dev_get_drvdata(dev->parent); + struct regulator_config config = { }; + struct regulator_dev *rdev; + int ret, i; + + config.dev = lochnagar->dev; + config.regmap = lochnagar->regmap; + config.driver_data = lochnagar; + + for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) { + const struct regulator_desc *desc = &lochnagar_regulators[i]; + + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "Failed to register %s regulator: %d\n", + desc->name, ret); + return ret; + } + } + + return 0; +} + +static struct platform_driver lochnagar_regulator_driver = { + .driver = { + .name = "lochnagar-regulator", + }, + + .probe = lochnagar_regulator_probe, +}; +module_platform_driver(lochnagar_regulator_driver); + +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>"); +MODULE_DESCRIPTION("Regulator driver for Cirrus Logic Lochnagar Board"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:lochnagar-regulator"); diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index f2347474a106..553b4790050f 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -503,9 +503,10 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, /* FIXME: check default mode for GPIO here: high or low? */ ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev, - "enable", - enable_id, - GPIOD_OUT_HIGH); + "enable", + enable_id, + GPIOD_OUT_HIGH | + GPIOD_FLAGS_BIT_NONEXCLUSIVE); if (IS_ERR(ldo->ena_gpiod)) return PTR_ERR(ldo->ena_gpiod); diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 18d5b01ddcb2..63f724f260ef 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -404,7 +404,8 @@ static const struct regmap_config ltc3589_regmap_config = { .max_register = LTC3589_L2DTV2, .reg_defaults = ltc3589_reg_defaults, .num_reg_defaults = ARRAY_SIZE(ltc3589_reg_defaults), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .cache_type = REGCACHE_RBTREE, }; diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c index 9dec1609ff66..71fd0f2a4b76 100644 --- a/drivers/regulator/ltc3676.c +++ b/drivers/regulator/ltc3676.c @@ -321,7 +321,8 @@ static const struct regmap_config ltc3676_regmap_config = { .readable_reg = ltc3676_readable_reg, .volatile_reg = ltc3676_volatile_reg, .max_register = LTC3676_CLIRQ, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .cache_type = REGCACHE_RBTREE, }; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index f1e77ed5dfec..6c39fff73b8a 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -230,6 +230,7 @@ static int max8952_pmic_probe(struct i2c_client *client, gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_LOW; + gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE; gpiod = devm_gpiod_get_optional(&client->dev, "max8952,en", gflags); diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 7cd493ec6315..e7a58b509032 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -758,6 +758,7 @@ static int max8973_probe(struct i2c_client *client, gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_LOW; + gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE; gpiod = devm_gpiod_get_optional(&client->dev, "maxim,enable", gflags); diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index ad0c806b0737..3bf5ddfaaea8 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -929,8 +929,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, break; if (i == ARRAY_SIZE(regulators)) { - dev_warn(&pdev->dev, "don't know how to configure regulator %s\n", - reg_np->name); + dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n", + reg_np); continue; } diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index da4fb9824757..65eb1e0350cf 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -203,7 +203,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( if (!found) dev_warn(&pdev->dev, - "Unknown regulator: %s\n", child->name); + "Unknown regulator: %pOFn\n", child); } of_node_put(parent); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 210fc20f7de7..c4223b3e0dff 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -95,8 +95,8 @@ static void of_get_regulation_constraints(struct device_node *np, if (!ret) constraints->settling_time_up = pval; if (constraints->settling_time_up && constraints->settling_time) { - pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n", - np->name); + pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n", + np); constraints->settling_time_up = 0; } @@ -105,8 +105,8 @@ static void of_get_regulation_constraints(struct device_node *np, if (!ret) constraints->settling_time_down = pval; if (constraints->settling_time_down && constraints->settling_time) { - pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n", - np->name); + pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n", + np); constraints->settling_time_down = 0; } @@ -127,12 +127,12 @@ static void of_get_regulation_constraints(struct device_node *np, if (desc && desc->of_map_mode) { mode = desc->of_map_mode(pval); if (mode == REGULATOR_MODE_INVALID) - pr_err("%s: invalid mode %u\n", np->name, pval); + pr_err("%pOFn: invalid mode %u\n", np, pval); else constraints->initial_mode = mode; } else { - pr_warn("%s: mapping for mode %d not defined\n", - np->name, pval); + pr_warn("%pOFn: mapping for mode %d not defined\n", + np, pval); } } @@ -144,14 +144,14 @@ static void of_get_regulation_constraints(struct device_node *np, ret = of_property_read_u32_index(np, "regulator-allowed-modes", i, &pval); if (ret) { - pr_err("%s: couldn't read allowed modes index %d, ret=%d\n", - np->name, i, ret); + pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n", + np, i, ret); break; } mode = desc->of_map_mode(pval); if (mode == REGULATOR_MODE_INVALID) - pr_err("%s: invalid regulator-allowed-modes element %u\n", - np->name, pval); + pr_err("%pOFn: invalid regulator-allowed-modes element %u\n", + np, pval); else constraints->valid_modes_mask |= mode; } @@ -159,7 +159,7 @@ static void of_get_regulation_constraints(struct device_node *np, constraints->valid_ops_mask |= REGULATOR_CHANGE_MODE; } else { - pr_warn("%s: mode mapping not defined\n", np->name); + pr_warn("%pOFn: mode mapping not defined\n", np); } } @@ -197,13 +197,13 @@ static void of_get_regulation_constraints(struct device_node *np, if (desc && desc->of_map_mode) { mode = desc->of_map_mode(pval); if (mode == REGULATOR_MODE_INVALID) - pr_err("%s: invalid mode %u\n", - np->name, pval); + pr_err("%pOFn: invalid mode %u\n", + np, pval); else suspend_state->mode = mode; } else { - pr_warn("%s: mapping for mode %d not defined\n", - np->name, pval); + pr_warn("%pOFn: mapping for mode %d not defined\n", + np, pval); } } @@ -349,8 +349,8 @@ int of_regulator_match(struct device *dev, struct device_node *node, match->desc); if (!match->init_data) { dev_err(dev, - "failed to parse DT for regulator %s\n", - child->name); + "failed to parse DT for regulator %pOFn\n", + child); of_node_put(child); return -EINVAL; } @@ -399,16 +399,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev, init_data = of_get_regulator_init_data(dev, child, desc); if (!init_data) { dev_err(dev, - "failed to parse DT for regulator %s\n", - child->name); + "failed to parse DT for regulator %pOFn\n", + child); break; } if (desc->of_parse_cb) { if (desc->of_parse_cb(child, desc, config)) { dev_err(dev, - "driver callback failed to parse DT for regulator %s\n", - child->name); + "driver callback failed to parse DT for regulator %pOFn\n", + child); init_data = NULL; break; } diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 31c3a236120a..dd41a9bb3f5c 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -31,11 +31,17 @@ #define PFUZE100_COINVOL 0x1a #define PFUZE100_SW1ABVOL 0x20 +#define PFUZE100_SW1ABMODE 0x23 #define PFUZE100_SW1CVOL 0x2e +#define PFUZE100_SW1CMODE 0x31 #define PFUZE100_SW2VOL 0x35 +#define PFUZE100_SW2MODE 0x38 #define PFUZE100_SW3AVOL 0x3c +#define PFUZE100_SW3AMODE 0x3f #define PFUZE100_SW3BVOL 0x43 +#define PFUZE100_SW3BMODE 0x46 #define PFUZE100_SW4VOL 0x4a +#define PFUZE100_SW4MODE 0x4d #define PFUZE100_SWBSTCON1 0x66 #define PFUZE100_VREFDDRCON 0x6a #define PFUZE100_VSNVSVOL 0x6b @@ -46,6 +52,13 @@ #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 +#define PFUZE100_SWxMODE_MASK 0xf +#define PFUZE100_SWxMODE_APS_APS 0x8 +#define PFUZE100_SWxMODE_APS_OFF 0x4 + +#define PFUZE100_VGENxLPWR BIT(6) +#define PFUZE100_VGENxSTBY BIT(5) + enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, }; struct pfuze_regulator { @@ -559,6 +572,69 @@ static inline struct device_node *match_of_node(int index) } #endif +static struct pfuze_chip *syspm_pfuze_chip; + +static void pfuze_power_off_prepare(void) +{ + dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off"); + + /* Switch from default mode: APS/APS to APS/Off */ + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE, + PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE, + PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE, + PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE, + PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE, + PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE, + PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); + + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL, + PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, + PFUZE100_VGENxSTBY); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL, + PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, + PFUZE100_VGENxSTBY); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL, + PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, + PFUZE100_VGENxSTBY); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL, + PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, + PFUZE100_VGENxSTBY); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL, + PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, + PFUZE100_VGENxSTBY); + regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL, + PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, + PFUZE100_VGENxSTBY); +} + +static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip) +{ + if (pfuze_chip->chip_id != PFUZE100) { + dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n"); + return -ENODEV; + } + + if (pm_power_off_prepare) { + dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n"); + return -EBUSY; + } + + if (syspm_pfuze_chip) { + dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n"); + return -EBUSY; + } + + syspm_pfuze_chip = pfuze_chip; + pm_power_off_prepare = pfuze_power_off_prepare; + + return 0; +} + static int pfuze_identify(struct pfuze_chip *pfuze_chip) { unsigned int value; @@ -753,6 +829,20 @@ static int pfuze100_regulator_probe(struct i2c_client *client, } } + if (of_property_read_bool(client->dev.of_node, + "fsl,pmic-stby-poweroff")) + return pfuze_power_off_prepare_init(pfuze_chip); + + return 0; +} + +static int pfuze100_regulator_remove(struct i2c_client *client) +{ + if (syspm_pfuze_chip) { + syspm_pfuze_chip = NULL; + pm_power_off_prepare = NULL; + } + return 0; } @@ -763,6 +853,7 @@ static struct i2c_driver pfuze_driver = { .of_match_table = pfuze_dt_ids, }, .probe = pfuze100_regulator_probe, + .remove = pfuze100_regulator_remove, }; module_i2c_driver(pfuze_driver); diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 9f27daebd8c8..39ccf53fdeb3 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -414,7 +414,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, break; if (!rpmh_data->name) { - dev_err(dev, "Unknown regulator %s\n", node->name); + dev_err(dev, "Unknown regulator %pOFn\n", node); return -EINVAL; } @@ -423,8 +423,8 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, vreg->addr = cmd_db_read_addr(rpmh_resource_name); if (!vreg->addr) { - dev_err(dev, "%s: could not find RPMh address for resource %s\n", - node->name, rpmh_resource_name); + dev_err(dev, "%pOFn: could not find RPMh address for resource %s\n", + node, rpmh_resource_name); return -ENODEV; } @@ -469,13 +469,13 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, rdev = devm_regulator_register(dev, &vreg->rdesc, ®_config); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); - dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n", - node->name, ret); + dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n", + node, ret); return ret; } - dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n", - node->name, rpmh_resource_name, vreg->addr); + dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n", + node, rpmh_resource_name, vreg->addr); return 0; } @@ -504,6 +504,7 @@ static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode) break; default: mode = REGULATOR_MODE_INVALID; + break; } return mode; @@ -537,6 +538,7 @@ rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode) break; default: mode = REGULATOR_MODE_INVALID; + break; } return mode; @@ -566,6 +568,7 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode) break; default: mode = REGULATOR_MODE_INVALID; + break; } return mode; diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index fe2fb36803e0..f5bca77d67c1 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -420,6 +420,60 @@ static const struct regulator_desc pmi8998_bob = { .ops = &rpm_bob_ops, }; +static const struct regulator_desc pms405_hfsmps3 = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 216, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pms405_nldo300 = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 128, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pms405_nldo1200 = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 128, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pms405_pldo50 = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000), + }, + .n_linear_ranges = 1, + .n_voltages = 129, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pms405_pldo150 = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000), + }, + .n_linear_ranges = 1, + .n_voltages = 129, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pms405_pldo600 = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(1256000, 0, 98, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 99, + .ops = &rpm_smps_ldo_ops, +}; + struct rpm_regulator_data { const char *name; u32 type; @@ -661,6 +715,28 @@ static const struct rpm_regulator_data rpm_pmi8998_regulators[] = { {} }; +static const struct rpm_regulator_data rpm_pms405_regulators[] = { + { "s1", QCOM_SMD_RPM_SMPA, 1, &pms405_hfsmps3, "vdd_s1" }, + { "s2", QCOM_SMD_RPM_SMPA, 2, &pms405_hfsmps3, "vdd_s2" }, + { "s3", QCOM_SMD_RPM_SMPA, 3, &pms405_hfsmps3, "vdd_s3" }, + { "s4", QCOM_SMD_RPM_SMPA, 4, &pms405_hfsmps3, "vdd_s4" }, + { "s5", QCOM_SMD_RPM_SMPA, 5, &pms405_hfsmps3, "vdd_s5" }, + { "l1", QCOM_SMD_RPM_LDOA, 1, &pms405_nldo1200, "vdd_l1_l2" }, + { "l2", QCOM_SMD_RPM_LDOA, 2, &pms405_nldo1200, "vdd_l1_l2" }, + { "l3", QCOM_SMD_RPM_LDOA, 3, &pms405_nldo1200, "vdd_l3_l8" }, + { "l4", QCOM_SMD_RPM_LDOA, 4, &pms405_nldo300, "vdd_l4" }, + { "l5", QCOM_SMD_RPM_LDOA, 5, &pms405_pldo600, "vdd_l5_l6" }, + { "l6", QCOM_SMD_RPM_LDOA, 6, &pms405_pldo600, "vdd_l5_l6" }, + { "l7", QCOM_SMD_RPM_LDOA, 7, &pms405_pldo150, "vdd_l7" }, + { "l8", QCOM_SMD_RPM_LDOA, 8, &pms405_nldo1200, "vdd_l3_l8" }, + { "l9", QCOM_SMD_RPM_LDOA, 9, &pms405_nldo1200, "vdd_l9" }, + { "l10", QCOM_SMD_RPM_LDOA, 10, &pms405_pldo50, "vdd_l10_l11_l12_l13" }, + { "l11", QCOM_SMD_RPM_LDOA, 11, &pms405_pldo150, "vdd_l10_l11_l12_l13" }, + { "l12", QCOM_SMD_RPM_LDOA, 12, &pms405_pldo150, "vdd_l10_l11_l12_l13" }, + { "l13", QCOM_SMD_RPM_LDOA, 13, &pms405_pldo150, "vdd_l10_l11_l12_l13" }, + {} +}; + static const struct of_device_id rpm_of_match[] = { { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators }, { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators }, @@ -669,6 +745,7 @@ static const struct of_device_id rpm_of_match[] = { { .compatible = "qcom,rpm-pm8998-regulators", .data = &rpm_pm8998_regulators }, { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators }, { .compatible = "qcom,rpm-pmi8998-regulators", .data = &rpm_pmi8998_regulators }, + { .compatible = "qcom,rpm-pms405-regulators", .data = &rpm_pms405_regulators }, {} }; MODULE_DEVICE_TABLE(of, rpm_of_match); diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 667d16dc83ce..219b9afda0cb 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -447,15 +447,15 @@ static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767, } if (mode != S5M8767_ENCTRL_USE_GPIO) { dev_warn(s5m8767->dev, - "ext-control for %s: mismatched op_mode (%x), ignoring\n", - rdata->reg_node->name, mode); + "ext-control for %pOFn: mismatched op_mode (%x), ignoring\n", + rdata->reg_node, mode); return; } if (!rdata->ext_control_gpiod) { dev_warn(s5m8767->dev, - "ext-control for %s: GPIO not valid, ignoring\n", - rdata->reg_node->name); + "ext-control for %pOFn: GPIO not valid, ignoring\n", + rdata->reg_node); return; } @@ -566,17 +566,18 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, if (i == ARRAY_SIZE(regulators)) { dev_warn(iodev->dev, - "don't know how to configure regulator %s\n", - reg_np->name); + "don't know how to configure regulator %pOFn\n", + reg_np); continue; } - rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(&pdev->dev, - reg_np, - "s5m8767,pmic-ext-control-gpios", - 0, - GPIOD_OUT_HIGH, - "s5m8767"); + rdata->ext_control_gpiod = devm_gpiod_get_from_of_node( + &pdev->dev, + reg_np, + "s5m8767,pmic-ext-control-gpios", + 0, + GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, + "s5m8767"); if (IS_ERR(rdata->ext_control_gpiod)) return PTR_ERR(rdata->ext_control_gpiod); diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c new file mode 100644 index 000000000000..e15634edb8ce --- /dev/null +++ b/drivers/regulator/stpmic1_regulator.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics. + +#include <linux/interrupt.h> +#include <linux/mfd/stpmic1.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> + +/** + * stpmic1 regulator description + * @desc: regulator framework description + * @mask_reset_reg: mask reset register address + * @mask_reset_mask: mask rank and mask reset register mask + * @icc_reg: icc register address + * @icc_mask: icc register mask + */ +struct stpmic1_regulator_cfg { + struct regulator_desc desc; + u8 mask_reset_reg; + u8 mask_reset_mask; + u8 icc_reg; + u8 icc_mask; +}; + +/** + * stpmic1 regulator data: this structure is used as driver data + * @regul_id: regulator id + * @reg_node: DT node of regulator (unused on non-DT platforms) + * @cfg: stpmic specific regulator description + * @mask_reset: mask_reset bit value + * @irq_curlim: current limit interrupt number + * @regmap: point to parent regmap structure + */ +struct stpmic1_regulator { + unsigned int regul_id; + struct device_node *reg_node; + struct stpmic1_regulator_cfg *cfg; + u8 mask_reset; + int irq_curlim; + struct regmap *regmap; +}; + +static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); +static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); +static int stpmic1_set_icc(struct regulator_dev *rdev); +static int stpmic1_regulator_parse_dt(void *driver_data); +static unsigned int stpmic1_map_mode(unsigned int mode); + +enum { + STPMIC1_BUCK1 = 0, + STPMIC1_BUCK2 = 1, + STPMIC1_BUCK3 = 2, + STPMIC1_BUCK4 = 3, + STPMIC1_LDO1 = 4, + STPMIC1_LDO2 = 5, + STPMIC1_LDO3 = 6, + STPMIC1_LDO4 = 7, + STPMIC1_LDO5 = 8, + STPMIC1_LDO6 = 9, + STPMIC1_VREF_DDR = 10, + STPMIC1_BOOST = 11, + STPMIC1_VBUS_OTG = 12, + STPMIC1_SW_OUT = 13, +}; + +/* Enable time worst case is 5000mV/(2250uV/uS) */ +#define PMIC_ENABLE_TIME_US 2200 + +#define STPMIC1_BUCK_MODE_NORMAL 0 +#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK + +struct regulator_linear_range buck1_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000), + REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0), +}; + +struct regulator_linear_range buck2_ranges[] = { + REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0), + REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0), + REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0), + REGULATOR_LINEAR_RANGE(1150000, 22, 23, 0), + REGULATOR_LINEAR_RANGE(1200000, 24, 25, 0), + REGULATOR_LINEAR_RANGE(1250000, 26, 27, 0), + REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0), + REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0), + REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0), + REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0), + REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0), +}; + +struct regulator_linear_range buck3_ranges[] = { + REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0), + REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0), + REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0), + REGULATOR_LINEAR_RANGE(1300000, 28, 31, 0), + REGULATOR_LINEAR_RANGE(1400000, 32, 35, 0), + REGULATOR_LINEAR_RANGE(1500000, 36, 55, 100000), + REGULATOR_LINEAR_RANGE(3400000, 56, 63, 0), + +}; + +struct regulator_linear_range buck4_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000), + REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0), + REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0), + REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0), + REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0), + REGULATOR_LINEAR_RANGE(1500000, 36, 60, 100000), + REGULATOR_LINEAR_RANGE(3900000, 61, 63, 0), + +}; + +struct regulator_linear_range ldo1_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), + REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), + +}; + +struct regulator_linear_range ldo2_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), + REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), + +}; + +struct regulator_linear_range ldo3_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), + REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), + /* with index 31 LDO3 is in DDR mode */ + REGULATOR_LINEAR_RANGE(500000, 31, 31, 0), +}; + +struct regulator_linear_range ldo5_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000), + REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0), +}; + +struct regulator_linear_range ldo6_ranges[] = { + REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000), + REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), +}; + +static struct regulator_ops stpmic1_ldo_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_pull_down = regulator_set_pull_down_regmap, + .set_over_current_protection = stpmic1_set_icc, +}; + +static struct regulator_ops stpmic1_ldo3_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_iterate, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_pull_down = regulator_set_pull_down_regmap, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, + .set_over_current_protection = stpmic1_set_icc, +}; + +static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_pull_down = regulator_set_pull_down_regmap, + .set_over_current_protection = stpmic1_set_icc, +}; + +static struct regulator_ops stpmic1_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_pull_down = regulator_set_pull_down_regmap, + .set_mode = stpmic1_set_mode, + .get_mode = stpmic1_get_mode, + .set_over_current_protection = stpmic1_set_icc, +}; + +static struct regulator_ops stpmic1_vref_ddr_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_pull_down = regulator_set_pull_down_regmap, +}; + +static struct regulator_ops stpmic1_switch_regul_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_over_current_protection = stpmic1_set_icc, +}; + +#define REG_LDO(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 32, \ + .ops = &stpmic1_ldo_ops, \ + .linear_ranges = base ## _ranges, \ + .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = ids##_ACTIVE_CR, \ + .vsel_mask = LDO_VOLTAGE_MASK, \ + .enable_reg = ids##_ACTIVE_CR, \ + .enable_mask = LDO_ENABLE_MASK, \ + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .pull_down_reg = ids##_PULL_DOWN_REG, \ + .pull_down_mask = ids##_PULL_DOWN_MASK, \ + .supply_name = #base, \ +} + +#define REG_LDO3(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 32, \ + .ops = &stpmic1_ldo3_ops, \ + .linear_ranges = ldo3_ranges, \ + .n_linear_ranges = ARRAY_SIZE(ldo3_ranges), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = LDO3_ACTIVE_CR, \ + .vsel_mask = LDO_VOLTAGE_MASK, \ + .enable_reg = LDO3_ACTIVE_CR, \ + .enable_mask = LDO_ENABLE_MASK, \ + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .bypass_reg = LDO3_ACTIVE_CR, \ + .bypass_mask = LDO_BYPASS_MASK, \ + .bypass_val_on = LDO_BYPASS_MASK, \ + .bypass_val_off = 0, \ + .pull_down_reg = ids##_PULL_DOWN_REG, \ + .pull_down_mask = ids##_PULL_DOWN_MASK, \ + .supply_name = #base, \ +} + +#define REG_LDO4(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 1, \ + .ops = &stpmic1_ldo4_fixed_regul_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 3300000, \ + .fixed_uV = 3300000, \ + .enable_reg = LDO4_ACTIVE_CR, \ + .enable_mask = LDO_ENABLE_MASK, \ + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .pull_down_reg = ids##_PULL_DOWN_REG, \ + .pull_down_mask = ids##_PULL_DOWN_MASK, \ + .supply_name = #base, \ +} + +#define REG_BUCK(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .ops = &stpmic1_buck_ops, \ + .n_voltages = 64, \ + .linear_ranges = base ## _ranges, \ + .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = ids##_ACTIVE_CR, \ + .vsel_mask = BUCK_VOLTAGE_MASK, \ + .enable_reg = ids##_ACTIVE_CR, \ + .enable_mask = BUCK_ENABLE_MASK, \ + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .of_map_mode = stpmic1_map_mode, \ + .pull_down_reg = ids##_PULL_DOWN_REG, \ + .pull_down_mask = ids##_PULL_DOWN_MASK, \ + .supply_name = #base, \ +} + +#define REG_VREF_DDR(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 1, \ + .ops = &stpmic1_vref_ddr_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 500000, \ + .fixed_uV = 500000, \ + .enable_reg = VREF_DDR_ACTIVE_CR, \ + .enable_mask = BUCK_ENABLE_MASK, \ + .enable_val = 1, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .pull_down_reg = ids##_PULL_DOWN_REG, \ + .pull_down_mask = ids##_PULL_DOWN_MASK, \ + .supply_name = #base, \ +} + +#define REG_SWITCH(ids, base, reg, mask, val) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 1, \ + .ops = &stpmic1_switch_regul_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 0, \ + .fixed_uV = 5000000, \ + .enable_reg = (reg), \ + .enable_mask = (mask), \ + .enable_val = (val), \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .supply_name = #base, \ +} + +struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = { + [STPMIC1_BUCK1] = { + .desc = REG_BUCK(BUCK1, buck1), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(0), + .mask_reset_reg = BUCKS_MASK_RESET_CR, + .mask_reset_mask = BIT(0), + }, + [STPMIC1_BUCK2] = { + .desc = REG_BUCK(BUCK2, buck2), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(1), + .mask_reset_reg = BUCKS_MASK_RESET_CR, + .mask_reset_mask = BIT(1), + }, + [STPMIC1_BUCK3] = { + .desc = REG_BUCK(BUCK3, buck3), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(2), + .mask_reset_reg = BUCKS_MASK_RESET_CR, + .mask_reset_mask = BIT(2), + }, + [STPMIC1_BUCK4] = { + .desc = REG_BUCK(BUCK4, buck4), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(3), + .mask_reset_reg = BUCKS_MASK_RESET_CR, + .mask_reset_mask = BIT(3), + }, + [STPMIC1_LDO1] = { + .desc = REG_LDO(LDO1, ldo1), + .icc_reg = LDOS_ICCTO_CR, + .icc_mask = BIT(0), + .mask_reset_reg = LDOS_MASK_RESET_CR, + .mask_reset_mask = BIT(0), + }, + [STPMIC1_LDO2] = { + .desc = REG_LDO(LDO2, ldo2), + .icc_reg = LDOS_ICCTO_CR, + .icc_mask = BIT(1), + .mask_reset_reg = LDOS_MASK_RESET_CR, + .mask_reset_mask = BIT(1), + }, + [STPMIC1_LDO3] = { + .desc = REG_LDO3(LDO3, ldo3), + .icc_reg = LDOS_ICCTO_CR, + .icc_mask = BIT(2), + .mask_reset_reg = LDOS_MASK_RESET_CR, + .mask_reset_mask = BIT(2), + }, + [STPMIC1_LDO4] = { + .desc = REG_LDO4(LDO4, ldo4), + .icc_reg = LDOS_ICCTO_CR, + .icc_mask = BIT(3), + .mask_reset_reg = LDOS_MASK_RESET_CR, + .mask_reset_mask = BIT(3), + }, + [STPMIC1_LDO5] = { + .desc = REG_LDO(LDO5, ldo5), + .icc_reg = LDOS_ICCTO_CR, + .icc_mask = BIT(4), + .mask_reset_reg = LDOS_MASK_RESET_CR, + .mask_reset_mask = BIT(4), + }, + [STPMIC1_LDO6] = { + .desc = REG_LDO(LDO6, ldo6), + .icc_reg = LDOS_ICCTO_CR, + .icc_mask = BIT(5), + .mask_reset_reg = LDOS_MASK_RESET_CR, + .mask_reset_mask = BIT(5), + }, + [STPMIC1_VREF_DDR] = { + .desc = REG_VREF_DDR(VREF_DDR, vref_ddr), + .mask_reset_reg = LDOS_MASK_RESET_CR, + .mask_reset_mask = BIT(6), + }, + [STPMIC1_BOOST] = { + .desc = REG_SWITCH(BOOST, boost, BST_SW_CR, + BOOST_ENABLED, + BOOST_ENABLED), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(6), + }, + [STPMIC1_VBUS_OTG] = { + .desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR, + USBSW_OTG_SWITCH_ENABLED, + USBSW_OTG_SWITCH_ENABLED), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(4), + }, + [STPMIC1_SW_OUT] = { + .desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR, + SWIN_SWOUT_ENABLED, + SWIN_SWOUT_ENABLED), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(5), + }, +}; + +static unsigned int stpmic1_map_mode(unsigned int mode) +{ + switch (mode) { + case STPMIC1_BUCK_MODE_NORMAL: + return REGULATOR_MODE_NORMAL; + case STPMIC1_BUCK_MODE_LP: + return REGULATOR_MODE_STANDBY; + default: + return REGULATOR_MODE_INVALID; + } +} + +static unsigned int stpmic1_get_mode(struct regulator_dev *rdev) +{ + int value; + + regmap_read(rdev->regmap, rdev->desc->enable_reg, &value); + + if (value & STPMIC1_BUCK_MODE_LP) + return REGULATOR_MODE_STANDBY; + + return REGULATOR_MODE_NORMAL; +} + +static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + int value; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + value = STPMIC1_BUCK_MODE_NORMAL; + break; + case REGULATOR_MODE_STANDBY: + value = STPMIC1_BUCK_MODE_LP; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + STPMIC1_BUCK_MODE_LP, value); +} + +static int stpmic1_set_icc(struct regulator_dev *rdev) +{ + struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); + + /* enable switch off in case of over current */ + return regmap_update_bits(regul->regmap, regul->cfg->icc_reg, + regul->cfg->icc_mask, regul->cfg->icc_mask); +} + +static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) +{ + struct regulator_dev *rdev = (struct regulator_dev *)data; + + mutex_lock(&rdev->mutex); + + /* Send an overcurrent notification */ + regulator_notifier_call_chain(rdev, + REGULATOR_EVENT_OVER_CURRENT, + NULL); + + mutex_unlock(&rdev->mutex); + + return IRQ_HANDLED; +} + +static int stpmic1_regulator_init(struct platform_device *pdev, + struct regulator_dev *rdev) +{ + struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); + int ret = 0; + + /* set mask reset */ + if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) { + ret = regmap_update_bits(regul->regmap, + regul->cfg->mask_reset_reg, + regul->cfg->mask_reset_mask, + regul->cfg->mask_reset_mask); + if (ret) { + dev_err(&pdev->dev, "set mask reset failed\n"); + return ret; + } + } + + /* setup an irq handler for over-current detection */ + if (regul->irq_curlim > 0) { + ret = devm_request_threaded_irq(&pdev->dev, + regul->irq_curlim, NULL, + stpmic1_curlim_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + pdev->name, rdev); + if (ret) { + dev_err(&pdev->dev, "Request IRQ failed\n"); + return ret; + } + } + return 0; +} + +#define MATCH(_name, _id) \ + [STPMIC1_##_id] = { \ + .name = #_name, \ + .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \ + } + +static struct of_regulator_match stpmic1_regulators_matches[] = { + MATCH(buck1, BUCK1), + MATCH(buck2, BUCK2), + MATCH(buck3, BUCK3), + MATCH(buck4, BUCK4), + MATCH(ldo1, LDO1), + MATCH(ldo2, LDO2), + MATCH(ldo3, LDO3), + MATCH(ldo4, LDO4), + MATCH(ldo5, LDO5), + MATCH(ldo6, LDO6), + MATCH(vref_ddr, VREF_DDR), + MATCH(boost, BOOST), + MATCH(pwr_sw1, VBUS_OTG), + MATCH(pwr_sw2, SW_OUT), +}; + +static int stpmic1_regulator_parse_dt(void *driver_data) +{ + struct stpmic1_regulator *regul = + (struct stpmic1_regulator *)driver_data; + + if (!regul) + return -EINVAL; + + if (of_get_property(regul->reg_node, "st,mask-reset", NULL)) + regul->mask_reset = 1; + + regul->irq_curlim = of_irq_get(regul->reg_node, 0); + + return 0; +} + +static struct +regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id, + struct regulator_init_data *init_data, + struct stpmic1_regulator *regul) +{ + struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); + struct regulator_dev *rdev; + struct regulator_config config = {}; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.of_node = stpmic1_regulators_matches[id].of_node; + config.regmap = pmic_dev->regmap; + config.driver_data = regul; + + regul->regul_id = id; + regul->reg_node = config.of_node; + regul->cfg = &stpmic1_regulator_cfgs[id]; + regul->regmap = pmic_dev->regmap; + + rdev = devm_regulator_register(&pdev->dev, ®ul->cfg->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s regulator\n", + regul->cfg->desc.name); + } + + return rdev; +} + +static int stpmic1_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + struct stpmic1_regulator *regul; + struct regulator_init_data *init_data; + struct device_node *np; + int i, ret; + + np = pdev->dev.of_node; + + ret = of_regulator_match(&pdev->dev, np, + stpmic1_regulators_matches, + ARRAY_SIZE(stpmic1_regulators_matches)); + if (ret < 0) { + dev_err(&pdev->dev, + "Error in PMIC regulator device tree node"); + return ret; + } + + regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) * + sizeof(struct stpmic1_regulator), + GFP_KERNEL); + if (!regul) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { + /* Parse DT & find regulators to register */ + init_data = stpmic1_regulators_matches[i].init_data; + if (init_data) + init_data->regulator_init = &stpmic1_regulator_parse_dt; + + rdev = stpmic1_regulator_register(pdev, i, init_data, regul); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + ret = stpmic1_regulator_init(pdev, rdev); + if (ret) { + dev_err(&pdev->dev, + "failed to initialize regulator %d\n", ret); + return ret; + } + + regul++; + } + + dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); + + return 0; +} + +static const struct of_device_id of_pmic_regulator_match[] = { + { .compatible = "st,stpmic1-regulators" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, of_pmic_regulator_match); + +static struct platform_driver stpmic1_regulator_driver = { + .driver = { + .name = "stpmic1-regulator", + .of_match_table = of_match_ptr(of_pmic_regulator_match), + }, + .probe = stpmic1_regulator_probe, +}; + +module_platform_driver(stpmic1_regulator_driver); + +MODULE_DESCRIPTION("STPMIC1 PMIC voltage regulator driver"); +MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index edaef9e4dc74..db714d5edafc 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -374,6 +374,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_LOW; + gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE; rpdata->gpiod = devm_gpiod_get_from_of_node(&pdev->dev, tps65090_matches[idx].of_node, diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a23e7d394a0a..5e9ebdb0594c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3309,10 +3309,8 @@ dasd_exit(void) dasd_proc_exit(); #endif dasd_eer_exit(); - if (dasd_page_cache != NULL) { - kmem_cache_destroy(dasd_page_cache); - dasd_page_cache = NULL; - } + kmem_cache_destroy(dasd_page_cache); + dasd_page_cache = NULL; dasd_gendisk_exit(); dasd_devmap_exit(); if (dasd_debug_area != NULL) { diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 7036a6c6f86f..5542d9eadfe0 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -76,7 +76,7 @@ int dasd_gendisk_alloc(struct dasd_block *block) gdp->queue = block->request_queue; block->gdp = gdp; set_capacity(block->gdp, 0); - device_add_disk(&base->cdev->dev, block->gdp); + device_add_disk(&base->cdev->dev, block->gdp, NULL); return 0; } diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 23e526cda5c1..4e8aedd50cb0 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -685,7 +685,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char } get_device(&dev_info->dev); - device_add_disk(&dev_info->dev, dev_info->gd); + device_add_disk(&dev_info->dev, dev_info->gd, NULL); switch (dev_info->segment_type) { case SEG_TYPE_SR: diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 98f66b7b6794..e01889394c84 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -500,7 +500,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) /* 512 byte sectors */ set_capacity(bdev->gendisk, scmdev->size >> 9); - device_add_disk(&scmdev->dev, bdev->gendisk); + device_add_disk(&scmdev->dev, bdev->gendisk, NULL); return 0; out_queue: diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index c6ab34f94b1b..3072b89785dd 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -11,6 +11,7 @@ endif GCOV_PROFILE_sclp_early_core.o := n KCOV_INSTRUMENT_sclp_early_core.o := n UBSAN_SANITIZE_sclp_early_core.o := n +KASAN_SANITIZE_sclp_early_core.o := n CFLAGS_sclp_early_core.o += -D__NO_FORTIFY diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 4f1a69c9d81d..fdc0c0b7a6f5 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -58,22 +58,31 @@ struct mon_private { static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn) { - struct appldata_product_id id; + struct appldata_parameter_list *parm_list; + struct appldata_product_id *id; int rc; - memcpy(id.prod_nr, "LNXAPPL", 7); - id.prod_fn = myhdr->applid; - id.record_nr = myhdr->record_num; - id.version_nr = myhdr->version; - id.release_nr = myhdr->release; - id.mod_lvl = myhdr->mod_level; - rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen); + id = kmalloc(sizeof(*id), GFP_KERNEL); + parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL); + rc = -ENOMEM; + if (!id || !parm_list) + goto out; + memcpy(id->prod_nr, "LNXAPPL", 7); + id->prod_fn = myhdr->applid; + id->record_nr = myhdr->record_num; + id->version_nr = myhdr->version; + id->release_nr = myhdr->release; + id->mod_lvl = myhdr->mod_level; + rc = appldata_asm(parm_list, id, fcn, + (void *) buffer, myhdr->datalen); if (rc <= 0) - return rc; + goto out; pr_err("Writing monitor data failed with rc=%i\n", rc); - if (rc == 5) - return -EPERM; - return -EINVAL; + rc = (rc == 5) ? -EPERM : -EINVAL; +out: + kfree(id); + kfree(parm_list); + return rc; } static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 1fe4918088e7..b3fcc24b1182 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -63,6 +63,9 @@ typedef unsigned int sclp_cmdw_t; #define SCLP_CMDW_READ_CPU_INFO 0x00010001 +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_STORAGE_INFO 0x00040001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 #define SCLP_CMDW_READ_EVENT_DATA 0x00770005 #define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005 #define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005 @@ -156,6 +159,54 @@ struct read_cpu_info_sccb { u8 reserved[4096 - 16]; } __attribute__((packed, aligned(PAGE_SIZE))); +struct read_info_sccb { + struct sccb_header header; /* 0-7 */ + u16 rnmax; /* 8-9 */ + u8 rnsize; /* 10 */ + u8 _pad_11[16 - 11]; /* 11-15 */ + u16 ncpurl; /* 16-17 */ + u16 cpuoff; /* 18-19 */ + u8 _pad_20[24 - 20]; /* 20-23 */ + u8 loadparm[8]; /* 24-31 */ + u8 _pad_32[42 - 32]; /* 32-41 */ + u8 fac42; /* 42 */ + u8 fac43; /* 43 */ + u8 _pad_44[48 - 44]; /* 44-47 */ + u64 facilities; /* 48-55 */ + u8 _pad_56[66 - 56]; /* 56-65 */ + u8 fac66; /* 66 */ + u8 _pad_67[76 - 67]; /* 67-83 */ + u32 ibc; /* 76-79 */ + u8 _pad80[84 - 80]; /* 80-83 */ + u8 fac84; /* 84 */ + u8 fac85; /* 85 */ + u8 _pad_86[91 - 86]; /* 86-90 */ + u8 fac91; /* 91 */ + u8 _pad_92[98 - 92]; /* 92-97 */ + u8 fac98; /* 98 */ + u8 hamaxpow; /* 99 */ + u32 rnsize2; /* 100-103 */ + u64 rnmax2; /* 104-111 */ + u32 hsa_size; /* 112-115 */ + u8 fac116; /* 116 */ + u8 fac117; /* 117 */ + u8 fac118; /* 118 */ + u8 fac119; /* 119 */ + u16 hcpua; /* 120-121 */ + u8 _pad_122[124 - 122]; /* 122-123 */ + u32 hmfai; /* 124-127 */ + u8 _pad_128[4096 - 128]; /* 128-4095 */ +} __packed __aligned(PAGE_SIZE); + +struct read_storage_sccb { + struct sccb_header header; + u16 max_id; + u16 assigned; + u16 standby; + u16 :16; + u32 entries[0]; +} __packed; + static inline void sclp_fill_core_info(struct sclp_core_info *info, struct read_cpu_info_sccb *sccb) { @@ -275,6 +326,7 @@ unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb); int sclp_early_set_event_mask(struct init_sccb *sccb, sccb_mask_t receive_mask, sccb_mask_t send_mask); +int sclp_early_get_info(struct read_info_sccb *info); /* useful inlines */ diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index d7686a68c093..37d42de06079 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -460,15 +460,6 @@ static int sclp_mem_freeze(struct device *dev) return -EPERM; } -struct read_storage_sccb { - struct sccb_header header; - u16 max_id; - u16 assigned; - u16 standby; - u16 :16; - u32 entries[0]; -} __packed; - static const struct dev_pm_ops sclp_mem_pm_ops = { .freeze = sclp_mem_freeze, }; @@ -498,7 +489,7 @@ static int __init sclp_detect_standby_memory(void) for (id = 0; id <= sclp_max_storage_id; id++) { memset(sccb, 0, PAGE_SIZE); sccb->header.length = PAGE_SIZE; - rc = sclp_sync_request(0x00040001 | id << 8, sccb); + rc = sclp_sync_request(SCLP_CMDW_READ_STORAGE_INFO | id << 8, sccb); if (rc) goto out; switch (sccb->header.response_code) { diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 9a74abb9224d..e792cee3b51c 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -15,80 +15,17 @@ #include "sclp_sdias.h" #include "sclp.h" -#define SCLP_CMDW_READ_SCP_INFO 0x00020001 -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 - -struct read_info_sccb { - struct sccb_header header; /* 0-7 */ - u16 rnmax; /* 8-9 */ - u8 rnsize; /* 10 */ - u8 _pad_11[16 - 11]; /* 11-15 */ - u16 ncpurl; /* 16-17 */ - u16 cpuoff; /* 18-19 */ - u8 _pad_20[24 - 20]; /* 20-23 */ - u8 loadparm[8]; /* 24-31 */ - u8 _pad_32[42 - 32]; /* 32-41 */ - u8 fac42; /* 42 */ - u8 fac43; /* 43 */ - u8 _pad_44[48 - 44]; /* 44-47 */ - u64 facilities; /* 48-55 */ - u8 _pad_56[66 - 56]; /* 56-65 */ - u8 fac66; /* 66 */ - u8 _pad_67[76 - 67]; /* 67-83 */ - u32 ibc; /* 76-79 */ - u8 _pad80[84 - 80]; /* 80-83 */ - u8 fac84; /* 84 */ - u8 fac85; /* 85 */ - u8 _pad_86[91 - 86]; /* 86-90 */ - u8 fac91; /* 91 */ - u8 _pad_92[98 - 92]; /* 92-97 */ - u8 fac98; /* 98 */ - u8 hamaxpow; /* 99 */ - u32 rnsize2; /* 100-103 */ - u64 rnmax2; /* 104-111 */ - u8 _pad_112[116 - 112]; /* 112-115 */ - u8 fac116; /* 116 */ - u8 fac117; /* 117 */ - u8 fac118; /* 118 */ - u8 fac119; /* 119 */ - u16 hcpua; /* 120-121 */ - u8 _pad_122[124 - 122]; /* 122-123 */ - u32 hmfai; /* 124-127 */ - u8 _pad_128[4096 - 128]; /* 128-4095 */ -} __packed __aligned(PAGE_SIZE); - static struct sclp_ipl_info sclp_ipl_info; struct sclp_info sclp; EXPORT_SYMBOL(sclp); -static int __init sclp_early_read_info(struct read_info_sccb *sccb) -{ - int i; - sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, - SCLP_CMDW_READ_SCP_INFO}; - - for (i = 0; i < ARRAY_SIZE(commands); i++) { - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - sccb->header.function_code = 0x80; - sccb->header.control_mask[2] = 0x80; - if (sclp_early_cmd(commands[i], sccb)) - break; - if (sccb->header.response_code == 0x10) - return 0; - if (sccb->header.response_code != 0x1f0) - break; - } - return -EIO; -} - static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) { struct sclp_core_entry *cpue; u16 boot_cpu_address, cpu; - if (sclp_early_read_info(sccb)) + if (sclp_early_get_info(sccb)) return; sclp.facilities = sccb->facilities; @@ -147,6 +84,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) sclp_ipl_info.has_dump = 1; memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN); + if (sccb->hsa_size) + sclp.hsa_size = (sccb->hsa_size - 1) * PAGE_SIZE; sclp.mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0; sclp.mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0; sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0; @@ -189,61 +128,6 @@ int __init sclp_early_get_core_info(struct sclp_core_info *info) return 0; } -static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb) -{ - memset(sccb, 0, sizeof(*sccb)); - sccb->hdr.length = sizeof(*sccb); - sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf); - sccb->evbuf.hdr.type = EVTYP_SDIAS; - sccb->evbuf.event_qual = SDIAS_EQ_SIZE; - sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP; - sccb->evbuf.event_id = 4712; - sccb->evbuf.dbs = 1; - if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) - return -EIO; - if (sccb->hdr.response_code != 0x20) - return -EIO; - if (sccb->evbuf.blk_cnt == 0) - return 0; - return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; -} - -static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb) -{ - memset(sccb, 0, PAGE_SIZE); - sccb->hdr.length = PAGE_SIZE; - if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb)) - return -EIO; - if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220)) - return -EIO; - if (sccb->evbuf.blk_cnt == 0) - return 0; - return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; -} - -static void __init sclp_early_hsa_size_detect(void *sccb) -{ - unsigned long flags; - long size = -EIO; - - raw_local_irq_save(flags); - if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK)) - goto out; - size = sclp_early_hsa_size_init(sccb); - /* First check for synchronous response (LPAR) */ - if (size) - goto out_mask; - if (!(S390_lowcore.ext_params & 1)) - sclp_early_wait_irq(); - size = sclp_early_hsa_copy_wait(sccb); -out_mask: - sclp_early_set_event_mask(sccb, 0, 0); -out: - raw_local_irq_restore(flags); - if (size > 0) - sclp.hsa_size = size; -} - static void __init sclp_early_console_detect(struct init_sccb *sccb) { if (sccb->header.response_code != 0x20) @@ -262,7 +146,6 @@ void __init sclp_early_detect(void) sclp_early_facilities_detect(sccb); sclp_early_init_core_info(sccb); - sclp_early_hsa_size_detect(sccb); /* * Turn off SCLP event notifications. Also save remote masks in the diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 2f61f5579aa5..387c114ded3f 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -9,9 +9,13 @@ #include <asm/lowcore.h> #include <asm/ebcdic.h> #include <asm/irq.h> +#include <asm/sections.h> +#include <asm/mem_detect.h> #include "sclp.h" #include "sclp_rw.h" +static struct read_info_sccb __bootdata(sclp_info_sccb); +static int __bootdata(sclp_info_sccb_valid); char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); int sclp_init_state __section(.data) = sclp_init_state_uninitialized; /* @@ -234,3 +238,115 @@ void sclp_early_printk_force(const char *str) { __sclp_early_printk(str, strlen(str), 1); } + +int __init sclp_early_read_info(void) +{ + int i; + struct read_info_sccb *sccb = &sclp_info_sccb; + sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, + SCLP_CMDW_READ_SCP_INFO}; + + for (i = 0; i < ARRAY_SIZE(commands); i++) { + memset(sccb, 0, sizeof(*sccb)); + sccb->header.length = sizeof(*sccb); + sccb->header.function_code = 0x80; + sccb->header.control_mask[2] = 0x80; + if (sclp_early_cmd(commands[i], sccb)) + break; + if (sccb->header.response_code == 0x10) { + sclp_info_sccb_valid = 1; + return 0; + } + if (sccb->header.response_code != 0x1f0) + break; + } + return -EIO; +} + +int __init sclp_early_get_info(struct read_info_sccb *info) +{ + if (!sclp_info_sccb_valid) + return -EIO; + + *info = sclp_info_sccb; + return 0; +} + +int __init sclp_early_get_memsize(unsigned long *mem) +{ + unsigned long rnmax; + unsigned long rnsize; + struct read_info_sccb *sccb = &sclp_info_sccb; + + if (!sclp_info_sccb_valid) + return -EIO; + + rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; + rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; + rnsize <<= 20; + *mem = rnsize * rnmax; + return 0; +} + +int __init sclp_early_get_hsa_size(unsigned long *hsa_size) +{ + if (!sclp_info_sccb_valid) + return -EIO; + + *hsa_size = 0; + if (sclp_info_sccb.hsa_size) + *hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE; + return 0; +} + +#define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL + +void __weak __init add_mem_detect_block(u64 start, u64 end) {} +int __init sclp_early_read_storage_info(void) +{ + struct read_storage_sccb *sccb = (struct read_storage_sccb *)&sclp_early_sccb; + int rc, id, max_id = 0; + unsigned long rn, rzm; + sclp_cmdw_t command; + u16 sn; + + if (!sclp_info_sccb_valid) + return -EIO; + + if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY)) + return -EOPNOTSUPP; + + rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2; + rzm <<= 20; + + for (id = 0; id <= max_id; id++) { + memset(sclp_early_sccb, 0, sizeof(sclp_early_sccb)); + sccb->header.length = sizeof(sclp_early_sccb); + command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8); + rc = sclp_early_cmd(command, sccb); + if (rc) + goto fail; + + max_id = sccb->max_id; + switch (sccb->header.response_code) { + case 0x0010: + for (sn = 0; sn < sccb->assigned; sn++) { + if (!sccb->entries[sn]) + continue; + rn = sccb->entries[sn] >> 16; + add_mem_detect_block((rn - 1) * rzm, rn * rzm); + } + break; + case 0x0310: + case 0x0410: + break; + default: + goto fail; + } + } + + return 0; +fail: + mem_detect.count = 0; + return -EIO; +} diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c index e7c84a4e5eb5..995e9196852e 100644 --- a/drivers/s390/char/sclp_pci.c +++ b/drivers/s390/char/sclp_pci.c @@ -24,6 +24,7 @@ #define SCLP_ATYPE_PCI 2 +#define SCLP_ERRNOTIFY_AQ_RESET 0 #define SCLP_ERRNOTIFY_AQ_REPAIR 1 #define SCLP_ERRNOTIFY_AQ_INFO_LOG 2 @@ -111,9 +112,14 @@ static int sclp_pci_check_report(struct zpci_report_error_header *report) if (report->version != 1) return -EINVAL; - if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR && - report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG) + switch (report->action) { + case SCLP_ERRNOTIFY_AQ_RESET: + case SCLP_ERRNOTIFY_AQ_REPAIR: + case SCLP_ERRNOTIFY_AQ_INFO_LOG: + break; + default: return -EINVAL; + } if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb))) return -EINVAL; diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index cdcde18e7220..4554cdf4d6bd 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -971,7 +971,7 @@ tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb) snprintf(exception, BUFSIZE, "Data degraded"); break; case 0x03: - snprintf(exception, BUFSIZE, "Data degraded in partion %i", + snprintf(exception, BUFSIZE, "Data degraded in partition %i", sense->fmt.f70.mp); break; case 0x04: diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 069b9ef08206..58333cb4503f 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -153,7 +153,7 @@ static struct vmlogrdr_priv_t sys_ser[] = { } }; -#define MAXMINOR (sizeof(sys_ser)/sizeof(struct vmlogrdr_priv_t)) +#define MAXMINOR ARRAY_SIZE(sys_ser) static char FENCE[] = {"EOR"}; static int vmlogrdr_major = 0; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 93b2862bd3fa..4ebf6d4fc66c 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -608,6 +608,36 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) } EXPORT_SYMBOL(ccwgroup_driver_unregister); +static int __ccwgroupdev_check_busid(struct device *dev, void *id) +{ + char *bus_id = id; + + return (strcmp(bus_id, dev_name(dev)) == 0); +} + +/** + * get_ccwgroupdev_by_busid() - obtain device from a bus id + * @gdrv: driver the device is owned by + * @bus_id: bus id of the device to be searched + * + * This function searches all devices owned by @gdrv for a device with a bus + * id matching @bus_id. + * Returns: + * If a match is found, its reference count of the found device is increased + * and it is returned; else %NULL is returned. + */ +struct ccwgroup_device *get_ccwgroupdev_by_busid(struct ccwgroup_driver *gdrv, + char *bus_id) +{ + struct device *dev; + + dev = driver_find_device(&gdrv->driver, NULL, bus_id, + __ccwgroupdev_check_busid); + + return dev ? to_ccwgroupdev(dev) : NULL; +} +EXPORT_SYMBOL_GPL(get_ccwgroupdev_by_busid); + /** * ccwgroup_probe_ccwdev() - probe function for slave devices * @cdev: ccw device to be probed diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 9c7d9da42ba0..9537e656e927 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -595,19 +595,11 @@ static inline int qdio_inbound_q_done(struct qdio_q *q) return 0; } -static inline int contains_aobs(struct qdio_q *q) -{ - return !q->is_input_q && q->u.out.use_cq; -} - static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count) { unsigned char state = 0; int j, b = start; - if (!contains_aobs(q)) - return; - for (j = 0; j < count; ++j) { get_buf_state(q, b, &state, 0); if (state == SLSB_P_OUTPUT_PENDING) { @@ -618,8 +610,6 @@ static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count) q->u.out.sbal_state[b].flags |= QDIO_OUTBUF_STATE_FLAG_PENDING; q->u.out.aobs[b] = NULL; - } else if (state == SLSB_P_OUTPUT_EMPTY) { - q->u.out.sbal_state[b].aob = NULL; } b = next_buf(b); } @@ -638,7 +628,6 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q, q->aobs[bufnr] = aob; } if (q->aobs[bufnr]) { - q->sbal_state[bufnr].aob = q->aobs[bufnr]; q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user; phys_aob = virt_to_phys(q->aobs[bufnr]); WARN_ON_ONCE(phys_aob & 0xFF); @@ -666,10 +655,10 @@ static void qdio_kick_handler(struct qdio_q *q) qperf_inc(q, outbound_handler); DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", start, count); + if (q->u.out.use_cq) + qdio_handle_aobs(q, start, count); } - qdio_handle_aobs(q, start, count); - q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, q->irq_ptr->int_parm); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 78f1be41b05e..e324d890a4f6 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -27,7 +27,6 @@ struct qaob *qdio_allocate_aob(void) { return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC); } -EXPORT_SYMBOL_GPL(qdio_allocate_aob); void qdio_release_aob(struct qaob *aob) { diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index b59af548ed1c..fd5e215c66b7 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -10,7 +10,7 @@ zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o obj-$(CONFIG_ZCRYPT) += zcrypt.o # adapter drivers depend on ap.o and zcrypt.o -obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o +obj-$(CONFIG_ZCRYPT) += zcrypt_cex2c.o zcrypt_cex2a.o zcrypt_cex4.o # pkey kernel module pkey-objs := pkey_api.o diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index f039266b275d..048665e4f13d 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -65,12 +65,11 @@ static struct device *ap_root_device; DEFINE_SPINLOCK(ap_list_lock); LIST_HEAD(ap_card_list); -/* Default permissions (card and domain masking) */ -static struct ap_perms { - DECLARE_BITMAP(apm, AP_DEVICES); - DECLARE_BITMAP(aqm, AP_DOMAINS); -} ap_perms; -static DEFINE_MUTEX(ap_perms_mutex); +/* Default permissions (ioctl, card and domain masking) */ +struct ap_perms ap_perms; +EXPORT_SYMBOL(ap_perms); +DEFINE_MUTEX(ap_perms_mutex); +EXPORT_SYMBOL(ap_perms_mutex); static struct ap_config_info *ap_configuration; static bool initialised; @@ -944,21 +943,9 @@ static int modify_bitmap(const char *str, unsigned long *bitmap, int bits) return 0; } -/* - * process_mask_arg() - parse a bitmap string and clear/set the - * bits in the bitmap accordingly. The string may be given as - * absolute value, a hex string like 0x1F2E3D4C5B6A" simple over- - * writing the current content of the bitmap. Or as relative string - * like "+1-16,-32,-0x40,+128" where only single bits or ranges of - * bits are cleared or set. Distinction is done based on the very - * first character which may be '+' or '-' for the relative string - * and othewise assume to be an absolute value string. If parsing fails - * a negative errno value is returned. All arguments and bitmaps are - * big endian order. - */ -static int process_mask_arg(const char *str, - unsigned long *bitmap, int bits, - struct mutex *lock) +int ap_parse_mask_str(const char *str, + unsigned long *bitmap, int bits, + struct mutex *lock) { unsigned long *newmap, size; int rc; @@ -989,6 +976,7 @@ static int process_mask_arg(const char *str, kfree(newmap); return rc; } +EXPORT_SYMBOL(ap_parse_mask_str); /* * AP bus attributes. @@ -1049,6 +1037,21 @@ static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) static BUS_ATTR_RO(ap_usage_domain_mask); +static ssize_t ap_adapter_mask_show(struct bus_type *bus, char *buf) +{ + if (!ap_configuration) /* QCI not supported */ + return snprintf(buf, PAGE_SIZE, "not supported\n"); + + return snprintf(buf, PAGE_SIZE, + "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_configuration->apm[0], ap_configuration->apm[1], + ap_configuration->apm[2], ap_configuration->apm[3], + ap_configuration->apm[4], ap_configuration->apm[5], + ap_configuration->apm[6], ap_configuration->apm[7]); +} + +static BUS_ATTR_RO(ap_adapter_mask); + static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", @@ -1161,7 +1164,7 @@ static ssize_t apmask_store(struct bus_type *bus, const char *buf, { int rc; - rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex); + rc = ap_parse_mask_str(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex); if (rc) return rc; @@ -1192,7 +1195,7 @@ static ssize_t aqmask_store(struct bus_type *bus, const char *buf, { int rc; - rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex); + rc = ap_parse_mask_str(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex); if (rc) return rc; @@ -1207,6 +1210,7 @@ static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_ap_control_domain_mask, &bus_attr_ap_usage_domain_mask, + &bus_attr_ap_adapter_mask, &bus_attr_config_time, &bus_attr_poll_thread, &bus_attr_ap_interrupts, @@ -1218,11 +1222,10 @@ static struct bus_attribute *const ap_bus_attrs[] = { }; /** - * ap_select_domain(): Select an AP domain. - * - * Pick one of the 16 AP domains. + * ap_select_domain(): Select an AP domain if possible and we haven't + * already done so before. */ -static int ap_select_domain(void) +static void ap_select_domain(void) { int count, max_count, best_domain; struct ap_queue_status status; @@ -1237,7 +1240,7 @@ static int ap_select_domain(void) if (ap_domain_index >= 0) { /* Domain has already been selected. */ spin_unlock_bh(&ap_domain_lock); - return 0; + return; } best_domain = -1; max_count = 0; @@ -1264,11 +1267,8 @@ static int ap_select_domain(void) if (best_domain >= 0) { ap_domain_index = best_domain; AP_DBF(DBF_DEBUG, "new ap_domain_index=%d\n", ap_domain_index); - spin_unlock_bh(&ap_domain_lock); - return 0; } spin_unlock_bh(&ap_domain_lock); - return -ENODEV; } /* @@ -1346,8 +1346,7 @@ static void ap_scan_bus(struct work_struct *unused) AP_DBF(DBF_DEBUG, "%s running\n", __func__); ap_query_configuration(ap_configuration); - if (ap_select_domain() != 0) - goto out; + ap_select_domain(); for (id = 0; id < AP_DEVICES; id++) { /* check if device is registered */ @@ -1467,12 +1466,11 @@ static void ap_scan_bus(struct work_struct *unused) } } /* end device loop */ - if (defdomdevs < 1) + if (ap_domain_index >= 0 && defdomdevs < 1) AP_DBF(DBF_INFO, "no queue device with default domain %d available\n", ap_domain_index); -out: mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); } @@ -1496,21 +1494,22 @@ static int __init ap_debug_init(void) static void __init ap_perms_init(void) { /* all resources useable if no kernel parameter string given */ + memset(&ap_perms.ioctlm, 0xFF, sizeof(ap_perms.ioctlm)); memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm)); memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm)); /* apm kernel parameter string */ if (apm_str) { memset(&ap_perms.apm, 0, sizeof(ap_perms.apm)); - process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES, - &ap_perms_mutex); + ap_parse_mask_str(apm_str, ap_perms.apm, AP_DEVICES, + &ap_perms_mutex); } /* aqm kernel parameter string */ if (aqm_str) { memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm)); - process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS, - &ap_perms_mutex); + ap_parse_mask_str(aqm_str, ap_perms.aqm, AP_DOMAINS, + &ap_perms_mutex); } } @@ -1533,7 +1532,7 @@ static int __init ap_module_init(void) return -ENODEV; } - /* set up the AP permissions (ap and aq masks) */ + /* set up the AP permissions (ioctls, ap and aq masks) */ ap_perms_init(); /* Get AP configuration data if available */ diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 5246cd8c16a6..3eed1b36c876 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -20,6 +20,7 @@ #define AP_DEVICES 256 /* Number of AP devices. */ #define AP_DOMAINS 256 /* Number of AP domains. */ +#define AP_IOCTLS 256 /* Number of ioctls. */ #define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */ #define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */ #define AP_POLL_TIME 1 /* Time in ticks between receive polls. */ @@ -257,6 +258,14 @@ void ap_queue_resume(struct ap_device *ap_dev); struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type, int comp_device_type, unsigned int functions); +struct ap_perms { + unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)]; + unsigned long apm[BITS_TO_LONGS(AP_DEVICES)]; + unsigned long aqm[BITS_TO_LONGS(AP_DOMAINS)]; +}; +extern struct ap_perms ap_perms; +extern struct mutex ap_perms_mutex; + /* * check APQN for owned/reserved by ap bus and default driver(s). * Checks if this APQN is or will be in use by the ap bus @@ -280,4 +289,20 @@ int ap_owned_by_def_drv(int card, int queue); int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, unsigned long *aqm); +/* + * ap_parse_mask_str() - helper function to parse a bitmap string + * and clear/set the bits in the bitmap accordingly. The string may be + * given as absolute value, a hex string like 0x1F2E3D4C5B6A" simple + * overwriting the current content of the bitmap. Or as relative string + * like "+1-16,-32,-0x40,+128" where only single bits or ranges of + * bits are cleared or set. Distinction is done based on the very + * first character which may be '+' or '-' for the relative string + * and othewise assume to be an absolute value string. If parsing fails + * a negative errno value is returned. All arguments and bitmaps are + * big endian order. + */ +int ap_parse_mask_str(const char *str, + unsigned long *bitmap, int bits, + struct mutex *lock); + #endif /* _AP_BUS_H_ */ diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 1b4001e0285f..2f92bbed4bf6 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -16,9 +16,12 @@ #include <linux/slab.h> #include <linux/kallsyms.h> #include <linux/debugfs.h> +#include <linux/random.h> +#include <linux/cpufeature.h> #include <asm/zcrypt.h> #include <asm/cpacf.h> #include <asm/pkey.h> +#include <crypto/aes.h> #include "zcrypt_api.h" @@ -32,6 +35,9 @@ MODULE_DESCRIPTION("s390 protected key interface"); /* Size of vardata block used for some of the cca requests/replies */ #define VARDATASIZE 4096 +/* mask of available pckmo subfunctions, fetched once at module init */ +static cpacf_mask_t pckmo_functions; + /* * debug feature data and functions */ @@ -55,6 +61,24 @@ static void __exit pkey_debug_exit(void) debug_unregister(debug_info); } +/* Key token types */ +#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */ +#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */ + +/* For TOKTYPE_NON_CCA: */ +#define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */ + +/* For TOKTYPE_CCA_INTERNAL: */ +#define TOKVER_CCA_AES 0x04 /* CCA AES key token */ + +/* header part of a key token */ +struct keytoken_header { + u8 type; /* one of the TOKTYPE values */ + u8 res0[3]; + u8 version; /* one of the TOKVER values */ + u8 res1[3]; +} __packed; + /* inside view of a secure key token (only type 0x01 version 0x04) */ struct secaeskeytoken { u8 type; /* 0x01 for internal key token */ @@ -71,6 +95,17 @@ struct secaeskeytoken { u8 tvv[4]; /* token validation value */ } __packed; +/* inside view of a protected key token (only type 0x00 version 0x01) */ +struct protaeskeytoken { + u8 type; /* 0x00 for PAES specific key tokens */ + u8 res0[3]; + u8 version; /* should be 0x01 for protected AES key token */ + u8 res1[3]; + u32 keytype; /* key type, one of the PKEY_KEYTYPE values */ + u32 len; /* bytes actually stored in protkey[] */ + u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */ +} __packed; + /* * Simple check if the token is a valid CCA secure AES key * token. If keybitsize is given, the bitsize of the key is @@ -80,16 +115,16 @@ static int check_secaeskeytoken(const u8 *token, int keybitsize) { struct secaeskeytoken *t = (struct secaeskeytoken *) token; - if (t->type != 0x01) { + if (t->type != TOKTYPE_CCA_INTERNAL) { DEBUG_ERR( - "%s secure token check failed, type mismatch 0x%02x != 0x01\n", - __func__, (int) t->type); + "%s secure token check failed, type mismatch 0x%02x != 0x%02x\n", + __func__, (int) t->type, TOKTYPE_CCA_INTERNAL); return -EINVAL; } - if (t->version != 0x04) { + if (t->version != TOKVER_CCA_AES) { DEBUG_ERR( - "%s secure token check failed, version mismatch 0x%02x != 0x04\n", - __func__, (int) t->version); + "%s secure token check failed, version mismatch 0x%02x != 0x%02x\n", + __func__, (int) t->version, TOKVER_CCA_AES); return -EINVAL; } if (keybitsize > 0 && t->bitsize != keybitsize) { @@ -647,6 +682,16 @@ int pkey_clr2protkey(u32 keytype, return -EINVAL; } + /* + * Check if the needed pckmo subfunction is available. + * These subfunctions can be enabled/disabled by customers + * in the LPAR profile or may even change on the fly. + */ + if (!cpacf_test_func(&pckmo_functions, fc)) { + DEBUG_ERR("%s pckmo functions not available\n", __func__); + return -EOPNOTSUPP; + } + /* prepare param block */ memset(paramblock, 0, sizeof(paramblock)); memcpy(paramblock, clrkey->clrkey, keysize); @@ -1052,6 +1097,166 @@ out: EXPORT_SYMBOL(pkey_verifykey); /* + * Generate a random protected key + */ +int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey) +{ + struct pkey_clrkey clrkey; + int keysize; + int rc; + + switch (keytype) { + case PKEY_KEYTYPE_AES_128: + keysize = 16; + break; + case PKEY_KEYTYPE_AES_192: + keysize = 24; + break; + case PKEY_KEYTYPE_AES_256: + keysize = 32; + break; + default: + DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__, + keytype); + return -EINVAL; + } + + /* generate a dummy random clear key */ + get_random_bytes(clrkey.clrkey, keysize); + + /* convert it to a dummy protected key */ + rc = pkey_clr2protkey(keytype, &clrkey, protkey); + if (rc) + return rc; + + /* replace the key part of the protected key with random bytes */ + get_random_bytes(protkey->protkey, keysize); + + return 0; +} +EXPORT_SYMBOL(pkey_genprotkey); + +/* + * Verify if a protected key is still valid + */ +int pkey_verifyprotkey(const struct pkey_protkey *protkey) +{ + unsigned long fc; + struct { + u8 iv[AES_BLOCK_SIZE]; + u8 key[MAXPROTKEYSIZE]; + } param; + u8 null_msg[AES_BLOCK_SIZE]; + u8 dest_buf[AES_BLOCK_SIZE]; + unsigned int k; + + switch (protkey->type) { + case PKEY_KEYTYPE_AES_128: + fc = CPACF_KMC_PAES_128; + break; + case PKEY_KEYTYPE_AES_192: + fc = CPACF_KMC_PAES_192; + break; + case PKEY_KEYTYPE_AES_256: + fc = CPACF_KMC_PAES_256; + break; + default: + DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__, + protkey->type); + return -EINVAL; + } + + memset(null_msg, 0, sizeof(null_msg)); + + memset(param.iv, 0, sizeof(param.iv)); + memcpy(param.key, protkey->protkey, sizeof(param.key)); + + k = cpacf_kmc(fc | CPACF_ENCRYPT, ¶m, null_msg, dest_buf, + sizeof(null_msg)); + if (k != sizeof(null_msg)) { + DEBUG_ERR("%s protected key is not valid\n", __func__); + return -EKEYREJECTED; + } + + return 0; +} +EXPORT_SYMBOL(pkey_verifyprotkey); + +/* + * Transform a non-CCA key token into a protected key + */ +static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen, + struct pkey_protkey *protkey) +{ + struct keytoken_header *hdr = (struct keytoken_header *)key; + struct protaeskeytoken *t; + + switch (hdr->version) { + case TOKVER_PROTECTED_KEY: + if (keylen != sizeof(struct protaeskeytoken)) + return -EINVAL; + + t = (struct protaeskeytoken *)key; + protkey->len = t->len; + protkey->type = t->keytype; + memcpy(protkey->protkey, t->protkey, + sizeof(protkey->protkey)); + + return pkey_verifyprotkey(protkey); + default: + DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n", + __func__, hdr->version); + return -EINVAL; + } +} + +/* + * Transform a CCA internal key token into a protected key + */ +static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen, + struct pkey_protkey *protkey) +{ + struct keytoken_header *hdr = (struct keytoken_header *)key; + + switch (hdr->version) { + case TOKVER_CCA_AES: + if (keylen != sizeof(struct secaeskeytoken)) + return -EINVAL; + + return pkey_skey2pkey((struct pkey_seckey *)key, + protkey); + default: + DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n", + __func__, hdr->version); + return -EINVAL; + } +} + +/* + * Transform a key blob (of any type) into a protected key + */ +int pkey_keyblob2pkey(const __u8 *key, __u32 keylen, + struct pkey_protkey *protkey) +{ + struct keytoken_header *hdr = (struct keytoken_header *)key; + + if (keylen < sizeof(struct keytoken_header)) + return -EINVAL; + + switch (hdr->type) { + case TOKTYPE_NON_CCA: + return pkey_nonccatok2pkey(key, keylen, protkey); + case TOKTYPE_CCA_INTERNAL: + return pkey_ccainttok2pkey(key, keylen, protkey); + default: + DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__, + hdr->type); + return -EINVAL; + } +} +EXPORT_SYMBOL(pkey_keyblob2pkey); + +/* * File io functions */ @@ -1167,6 +1372,58 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; break; } + case PKEY_GENPROTK: { + struct pkey_genprotk __user *ugp = (void __user *) arg; + struct pkey_genprotk kgp; + + if (copy_from_user(&kgp, ugp, sizeof(kgp))) + return -EFAULT; + rc = pkey_genprotkey(kgp.keytype, &kgp.protkey); + DEBUG_DBG("%s pkey_genprotkey()=%d\n", __func__, rc); + if (rc) + break; + if (copy_to_user(ugp, &kgp, sizeof(kgp))) + return -EFAULT; + break; + } + case PKEY_VERIFYPROTK: { + struct pkey_verifyprotk __user *uvp = (void __user *) arg; + struct pkey_verifyprotk kvp; + + if (copy_from_user(&kvp, uvp, sizeof(kvp))) + return -EFAULT; + rc = pkey_verifyprotkey(&kvp.protkey); + DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc); + break; + } + case PKEY_KBLOB2PROTK: { + struct pkey_kblob2pkey __user *utp = (void __user *) arg; + struct pkey_kblob2pkey ktp; + __u8 __user *ukey; + __u8 *kkey; + + if (copy_from_user(&ktp, utp, sizeof(ktp))) + return -EFAULT; + if (ktp.keylen < MINKEYBLOBSIZE || + ktp.keylen > MAXKEYBLOBSIZE) + return -EINVAL; + ukey = ktp.key; + kkey = kmalloc(ktp.keylen, GFP_KERNEL); + if (kkey == NULL) + return -ENOMEM; + if (copy_from_user(kkey, ukey, ktp.keylen)) { + kfree(kkey); + return -EFAULT; + } + rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); + DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + kfree(kkey); + if (rc) + break; + if (copy_to_user(utp, &ktp, sizeof(ktp))) + return -EFAULT; + break; + } default: /* unknown/unsupported ioctl cmd */ return -ENOTTY; @@ -1178,6 +1435,236 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, /* * Sysfs and file io operations */ + +/* + * Sysfs attribute read function for all protected key binary attributes. + * The implementation can not deal with partial reads, because a new random + * protected key blob is generated with each read. In case of partial reads + * (i.e. off != 0 or count < key blob size) -EINVAL is returned. + */ +static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf, + loff_t off, size_t count) +{ + struct protaeskeytoken protkeytoken; + struct pkey_protkey protkey; + int rc; + + if (off != 0 || count < sizeof(protkeytoken)) + return -EINVAL; + if (is_xts) + if (count < 2 * sizeof(protkeytoken)) + return -EINVAL; + + memset(&protkeytoken, 0, sizeof(protkeytoken)); + protkeytoken.type = TOKTYPE_NON_CCA; + protkeytoken.version = TOKVER_PROTECTED_KEY; + protkeytoken.keytype = keytype; + + rc = pkey_genprotkey(protkeytoken.keytype, &protkey); + if (rc) + return rc; + + protkeytoken.len = protkey.len; + memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len); + + memcpy(buf, &protkeytoken, sizeof(protkeytoken)); + + if (is_xts) { + rc = pkey_genprotkey(protkeytoken.keytype, &protkey); + if (rc) + return rc; + + protkeytoken.len = protkey.len; + memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len); + + memcpy(buf + sizeof(protkeytoken), &protkeytoken, + sizeof(protkeytoken)); + + return 2 * sizeof(protkeytoken); + } + + return sizeof(protkeytoken); +} + +static ssize_t protkey_aes_128_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf, + off, count); +} + +static ssize_t protkey_aes_192_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf, + off, count); +} + +static ssize_t protkey_aes_256_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf, + off, count); +} + +static ssize_t protkey_aes_128_xts_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf, + off, count); +} + +static ssize_t protkey_aes_256_xts_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf, + off, count); +} + +static BIN_ATTR_RO(protkey_aes_128, sizeof(struct protaeskeytoken)); +static BIN_ATTR_RO(protkey_aes_192, sizeof(struct protaeskeytoken)); +static BIN_ATTR_RO(protkey_aes_256, sizeof(struct protaeskeytoken)); +static BIN_ATTR_RO(protkey_aes_128_xts, 2 * sizeof(struct protaeskeytoken)); +static BIN_ATTR_RO(protkey_aes_256_xts, 2 * sizeof(struct protaeskeytoken)); + +static struct bin_attribute *protkey_attrs[] = { + &bin_attr_protkey_aes_128, + &bin_attr_protkey_aes_192, + &bin_attr_protkey_aes_256, + &bin_attr_protkey_aes_128_xts, + &bin_attr_protkey_aes_256_xts, + NULL +}; + +static struct attribute_group protkey_attr_group = { + .name = "protkey", + .bin_attrs = protkey_attrs, +}; + +/* + * Sysfs attribute read function for all secure key ccadata binary attributes. + * The implementation can not deal with partial reads, because a new random + * protected key blob is generated with each read. In case of partial reads + * (i.e. off != 0 or count < key blob size) -EINVAL is returned. + */ +static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf, + loff_t off, size_t count) +{ + int rc; + + if (off != 0 || count < sizeof(struct secaeskeytoken)) + return -EINVAL; + if (is_xts) + if (count < 2 * sizeof(struct secaeskeytoken)) + return -EINVAL; + + rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf); + if (rc) + return rc; + + if (is_xts) { + buf += sizeof(struct pkey_seckey); + rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf); + if (rc) + return rc; + + return 2 * sizeof(struct secaeskeytoken); + } + + return sizeof(struct secaeskeytoken); +} + +static ssize_t ccadata_aes_128_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf, + off, count); +} + +static ssize_t ccadata_aes_192_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf, + off, count); +} + +static ssize_t ccadata_aes_256_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf, + off, count); +} + +static ssize_t ccadata_aes_128_xts_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf, + off, count); +} + +static ssize_t ccadata_aes_256_xts_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, + size_t count) +{ + return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf, + off, count); +} + +static BIN_ATTR_RO(ccadata_aes_128, sizeof(struct secaeskeytoken)); +static BIN_ATTR_RO(ccadata_aes_192, sizeof(struct secaeskeytoken)); +static BIN_ATTR_RO(ccadata_aes_256, sizeof(struct secaeskeytoken)); +static BIN_ATTR_RO(ccadata_aes_128_xts, 2 * sizeof(struct secaeskeytoken)); +static BIN_ATTR_RO(ccadata_aes_256_xts, 2 * sizeof(struct secaeskeytoken)); + +static struct bin_attribute *ccadata_attrs[] = { + &bin_attr_ccadata_aes_128, + &bin_attr_ccadata_aes_192, + &bin_attr_ccadata_aes_256, + &bin_attr_ccadata_aes_128_xts, + &bin_attr_ccadata_aes_256_xts, + NULL +}; + +static struct attribute_group ccadata_attr_group = { + .name = "ccadata", + .bin_attrs = ccadata_attrs, +}; + +static const struct attribute_group *pkey_attr_groups[] = { + &protkey_attr_group, + &ccadata_attr_group, + NULL, +}; + static const struct file_operations pkey_fops = { .owner = THIS_MODULE, .open = nonseekable_open, @@ -1190,6 +1677,7 @@ static struct miscdevice pkey_dev = { .minor = MISC_DYNAMIC_MINOR, .mode = 0666, .fops = &pkey_fops, + .groups = pkey_attr_groups, }; /* @@ -1197,14 +1685,23 @@ static struct miscdevice pkey_dev = { */ static int __init pkey_init(void) { - cpacf_mask_t pckmo_functions; + cpacf_mask_t kmc_functions; - /* check for pckmo instructions available */ + /* + * The pckmo instruction should be available - even if we don't + * actually invoke it. This instruction comes with MSA 3 which + * is also the minimum level for the kmc instructions which + * are able to work with protected keys. + */ if (!cpacf_query(CPACF_PCKMO, &pckmo_functions)) return -EOPNOTSUPP; - if (!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_128_KEY) || - !cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_192_KEY) || - !cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_256_KEY)) + + /* check for kmc instructions available */ + if (!cpacf_query(CPACF_KMC, &kmc_functions)) + return -EOPNOTSUPP; + if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) || + !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) || + !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) return -EOPNOTSUPP; pkey_debug_init(); @@ -1222,5 +1719,5 @@ static void __exit pkey_exit(void) pkey_debug_exit(); } -module_init(pkey_init); +module_cpu_feature_match(MSA, pkey_init); module_exit(pkey_exit); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index e6854127b434..eb93c2d27d0a 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * zcrypt 2.1.0 - * - * Copyright IBM Corp. 2001, 2012 + * Copyright IBM Corp. 2001, 2018 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) * Cornelia Huck <cornelia.huck@de.ibm.com> @@ -11,6 +9,7 @@ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> * Ralph Wuerthner <rwuerthn@de.ibm.com> * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> + * Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com> */ #include <linux/module.h> @@ -24,6 +23,8 @@ #include <linux/uaccess.h> #include <linux/hw_random.h> #include <linux/debugfs.h> +#include <linux/cdev.h> +#include <linux/ctype.h> #include <asm/debug.h> #define CREATE_TRACE_POINTS @@ -108,6 +109,375 @@ struct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant) } EXPORT_SYMBOL(zcrypt_msgtype); +/* + * Multi device nodes extension functions. + */ + +#ifdef CONFIG_ZCRYPT_MULTIDEVNODES + +struct zcdn_device; + +static struct class *zcrypt_class; +static dev_t zcrypt_devt; +static struct cdev zcrypt_cdev; + +struct zcdn_device { + struct device device; + struct ap_perms perms; +}; + +#define to_zcdn_dev(x) container_of((x), struct zcdn_device, device) + +#define ZCDN_MAX_NAME 32 + +static int zcdn_create(const char *name); +static int zcdn_destroy(const char *name); + +/* helper function, matches the name for find_zcdndev_by_name() */ +static int __match_zcdn_name(struct device *dev, const void *data) +{ + return strcmp(dev_name(dev), (const char *)data) == 0; +} + +/* helper function, matches the devt value for find_zcdndev_by_devt() */ +static int __match_zcdn_devt(struct device *dev, const void *data) +{ + return dev->devt == *((dev_t *) data); +} + +/* + * Find zcdn device by name. + * Returns reference to the zcdn device which needs to be released + * with put_device() after use. + */ +static inline struct zcdn_device *find_zcdndev_by_name(const char *name) +{ + struct device *dev = + class_find_device(zcrypt_class, NULL, + (void *) name, + __match_zcdn_name); + + return dev ? to_zcdn_dev(dev) : NULL; +} + +/* + * Find zcdn device by devt value. + * Returns reference to the zcdn device which needs to be released + * with put_device() after use. + */ +static inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt) +{ + struct device *dev = + class_find_device(zcrypt_class, NULL, + (void *) &devt, + __match_zcdn_devt); + + return dev ? to_zcdn_dev(dev) : NULL; +} + +static ssize_t ioctlmask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i, rc; + struct zcdn_device *zcdndev = to_zcdn_dev(dev); + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + + buf[0] = '0'; + buf[1] = 'x'; + for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++) + snprintf(buf + 2 + 2 * i * sizeof(long), + PAGE_SIZE - 2 - 2 * i * sizeof(long), + "%016lx", zcdndev->perms.ioctlm[i]); + buf[2 + 2 * i * sizeof(long)] = '\n'; + buf[2 + 2 * i * sizeof(long) + 1] = '\0'; + rc = 2 + 2 * i * sizeof(long) + 1; + + mutex_unlock(&ap_perms_mutex); + + return rc; +} + +static ssize_t ioctlmask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + struct zcdn_device *zcdndev = to_zcdn_dev(dev); + + rc = ap_parse_mask_str(buf, zcdndev->perms.ioctlm, + AP_IOCTLS, &ap_perms_mutex); + if (rc) + return rc; + + return count; +} + +static DEVICE_ATTR_RW(ioctlmask); + +static ssize_t apmask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i, rc; + struct zcdn_device *zcdndev = to_zcdn_dev(dev); + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + + buf[0] = '0'; + buf[1] = 'x'; + for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++) + snprintf(buf + 2 + 2 * i * sizeof(long), + PAGE_SIZE - 2 - 2 * i * sizeof(long), + "%016lx", zcdndev->perms.apm[i]); + buf[2 + 2 * i * sizeof(long)] = '\n'; + buf[2 + 2 * i * sizeof(long) + 1] = '\0'; + rc = 2 + 2 * i * sizeof(long) + 1; + + mutex_unlock(&ap_perms_mutex); + + return rc; +} + +static ssize_t apmask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + struct zcdn_device *zcdndev = to_zcdn_dev(dev); + + rc = ap_parse_mask_str(buf, zcdndev->perms.apm, + AP_DEVICES, &ap_perms_mutex); + if (rc) + return rc; + + return count; +} + +static DEVICE_ATTR_RW(apmask); + +static ssize_t aqmask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i, rc; + struct zcdn_device *zcdndev = to_zcdn_dev(dev); + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + + buf[0] = '0'; + buf[1] = 'x'; + for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++) + snprintf(buf + 2 + 2 * i * sizeof(long), + PAGE_SIZE - 2 - 2 * i * sizeof(long), + "%016lx", zcdndev->perms.aqm[i]); + buf[2 + 2 * i * sizeof(long)] = '\n'; + buf[2 + 2 * i * sizeof(long) + 1] = '\0'; + rc = 2 + 2 * i * sizeof(long) + 1; + + mutex_unlock(&ap_perms_mutex); + + return rc; +} + +static ssize_t aqmask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + struct zcdn_device *zcdndev = to_zcdn_dev(dev); + + rc = ap_parse_mask_str(buf, zcdndev->perms.aqm, + AP_DOMAINS, &ap_perms_mutex); + if (rc) + return rc; + + return count; +} + +static DEVICE_ATTR_RW(aqmask); + +static struct attribute *zcdn_dev_attrs[] = { + &dev_attr_ioctlmask.attr, + &dev_attr_apmask.attr, + &dev_attr_aqmask.attr, + NULL +}; + +static struct attribute_group zcdn_dev_attr_group = { + .attrs = zcdn_dev_attrs +}; + +static const struct attribute_group *zcdn_dev_attr_groups[] = { + &zcdn_dev_attr_group, + NULL +}; + +static ssize_t zcdn_create_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + int rc; + char name[ZCDN_MAX_NAME]; + + strncpy(name, skip_spaces(buf), sizeof(name)); + name[sizeof(name) - 1] = '\0'; + + rc = zcdn_create(strim(name)); + + return rc ? rc : count; +} + +static const struct class_attribute class_attr_zcdn_create = + __ATTR(create, 0600, NULL, zcdn_create_store); + +static ssize_t zcdn_destroy_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + int rc; + char name[ZCDN_MAX_NAME]; + + strncpy(name, skip_spaces(buf), sizeof(name)); + name[sizeof(name) - 1] = '\0'; + + rc = zcdn_destroy(strim(name)); + + return rc ? rc : count; +} + +static const struct class_attribute class_attr_zcdn_destroy = + __ATTR(destroy, 0600, NULL, zcdn_destroy_store); + +static void zcdn_device_release(struct device *dev) +{ + struct zcdn_device *zcdndev = to_zcdn_dev(dev); + + ZCRYPT_DBF(DBF_INFO, "releasing zcdn device %d:%d\n", + MAJOR(dev->devt), MINOR(dev->devt)); + + kfree(zcdndev); +} + +static int zcdn_create(const char *name) +{ + dev_t devt; + int i, rc = 0; + char nodename[ZCDN_MAX_NAME]; + struct zcdn_device *zcdndev; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + + /* check if device node with this name already exists */ + if (name[0]) { + zcdndev = find_zcdndev_by_name(name); + if (zcdndev) { + put_device(&zcdndev->device); + rc = -EEXIST; + goto unlockout; + } + } + + /* find an unused minor number */ + for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) { + devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i); + zcdndev = find_zcdndev_by_devt(devt); + if (zcdndev) + put_device(&zcdndev->device); + else + break; + } + if (i == ZCRYPT_MAX_MINOR_NODES) { + rc = -ENOSPC; + goto unlockout; + } + + /* alloc and prepare a new zcdn device */ + zcdndev = kzalloc(sizeof(*zcdndev), GFP_KERNEL); + if (!zcdndev) { + rc = -ENOMEM; + goto unlockout; + } + zcdndev->device.release = zcdn_device_release; + zcdndev->device.class = zcrypt_class; + zcdndev->device.devt = devt; + zcdndev->device.groups = zcdn_dev_attr_groups; + if (name[0]) + strncpy(nodename, name, sizeof(nodename)); + else + snprintf(nodename, sizeof(nodename), + ZCRYPT_NAME "_%d", (int) MINOR(devt)); + nodename[sizeof(nodename)-1] = '\0'; + if (dev_set_name(&zcdndev->device, nodename)) { + rc = -EINVAL; + goto unlockout; + } + rc = device_register(&zcdndev->device); + if (rc) { + put_device(&zcdndev->device); + goto unlockout; + } + + ZCRYPT_DBF(DBF_INFO, "created zcdn device %d:%d\n", + MAJOR(devt), MINOR(devt)); + +unlockout: + mutex_unlock(&ap_perms_mutex); + return rc; +} + +static int zcdn_destroy(const char *name) +{ + int rc = 0; + struct zcdn_device *zcdndev; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + + /* try to find this zcdn device */ + zcdndev = find_zcdndev_by_name(name); + if (!zcdndev) { + rc = -ENOENT; + goto unlockout; + } + + /* + * The zcdn device is not hard destroyed. It is subject to + * reference counting and thus just needs to be unregistered. + */ + put_device(&zcdndev->device); + device_unregister(&zcdndev->device); + +unlockout: + mutex_unlock(&ap_perms_mutex); + return rc; +} + +static void zcdn_destroy_all(void) +{ + int i; + dev_t devt; + struct zcdn_device *zcdndev; + + mutex_lock(&ap_perms_mutex); + for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) { + devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i); + zcdndev = find_zcdndev_by_devt(devt); + if (zcdndev) { + put_device(&zcdndev->device); + device_unregister(&zcdndev->device); + } + } + mutex_unlock(&ap_perms_mutex); +} + +#endif + /** * zcrypt_read (): Not supported beyond zcrypt 1.3.1. * @@ -137,6 +507,23 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf, */ static int zcrypt_open(struct inode *inode, struct file *filp) { + struct ap_perms *perms = &ap_perms; + +#ifdef CONFIG_ZCRYPT_MULTIDEVNODES + if (filp->f_inode->i_cdev == &zcrypt_cdev) { + struct zcdn_device *zcdndev; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev); + /* find returns a reference, no get_device() needed */ + mutex_unlock(&ap_perms_mutex); + if (zcdndev) + perms = &zcdndev->perms; + } +#endif + filp->private_data = (void *) perms; + atomic_inc(&zcrypt_open_count); return nonseekable_open(inode, filp); } @@ -148,10 +535,55 @@ static int zcrypt_open(struct inode *inode, struct file *filp) */ static int zcrypt_release(struct inode *inode, struct file *filp) { +#ifdef CONFIG_ZCRYPT_MULTIDEVNODES + if (filp->f_inode->i_cdev == &zcrypt_cdev) { + struct zcdn_device *zcdndev; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev); + mutex_unlock(&ap_perms_mutex); + if (zcdndev) { + /* 2 puts here: one for find, one for open */ + put_device(&zcdndev->device); + put_device(&zcdndev->device); + } + } +#endif + atomic_dec(&zcrypt_open_count); return 0; } +static inline int zcrypt_check_ioctl(struct ap_perms *perms, + unsigned int cmd) +{ + int rc = -EPERM; + int ioctlnr = (cmd & _IOC_NRMASK) >> _IOC_NRSHIFT; + + if (ioctlnr > 0 && ioctlnr < AP_IOCTLS) { + if (test_bit_inv(ioctlnr, perms->ioctlm)) + rc = 0; + } + + if (rc) + ZCRYPT_DBF(DBF_WARN, + "ioctl check failed: ioctlnr=0x%04x rc=%d\n", + ioctlnr, rc); + + return rc; +} + +static inline bool zcrypt_check_card(struct ap_perms *perms, int card) +{ + return test_bit_inv(card, perms->apm) ? true : false; +} + +static inline bool zcrypt_check_queue(struct ap_perms *perms, int queue) +{ + return test_bit_inv(queue, perms->aqm) ? true : false; +} + static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc, struct zcrypt_queue *zq, unsigned int weight) @@ -213,7 +645,8 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, /* * zcrypt ioctls. */ -static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) +static long zcrypt_rsa_modexpo(struct ap_perms *perms, + struct ica_rsa_modexpo *mex) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; @@ -250,6 +683,9 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) if (zc->min_mod_size > mex->inputdatalength || zc->max_mod_size < mex->inputdatalength) continue; + /* check if device node has admission for this card */ + if (!zcrypt_check_card(perms, zc->card->id)) + continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) @@ -258,6 +694,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) /* check if device is online and eligible */ if (!zq->online || !zq->ops->rsa_modexpo) continue; + /* check if device node has admission for this queue */ + if (!zcrypt_check_queue(perms, + AP_QID_QUEUE(zq->queue->qid))) + continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) continue; @@ -287,7 +727,8 @@ out: return rc; } -static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) +static long zcrypt_rsa_crt(struct ap_perms *perms, + struct ica_rsa_modexpo_crt *crt) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; @@ -324,6 +765,9 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) if (zc->min_mod_size > crt->inputdatalength || zc->max_mod_size < crt->inputdatalength) continue; + /* check if device node has admission for this card */ + if (!zcrypt_check_card(perms, zc->card->id)) + continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) @@ -332,6 +776,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) /* check if device is online and eligible */ if (!zq->online || !zq->ops->rsa_modexpo_crt) continue; + /* check if device node has admission for this queue */ + if (!zcrypt_check_queue(perms, + AP_QID_QUEUE(zq->queue->qid))) + continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) continue; @@ -361,7 +809,8 @@ out: return rc; } -long zcrypt_send_cprb(struct ica_xcRB *xcRB) +static long _zcrypt_send_cprb(struct ap_perms *perms, + struct ica_xcRB *xcRB) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; @@ -373,6 +822,7 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); + xcRB->status = 0; ap_init_message(&ap_msg); rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); if (rc) @@ -389,6 +839,9 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) if (xcRB->user_defined != AUTOSELECT && xcRB->user_defined != zc->card->id) continue; + /* check if device node has admission for this card */ + if (!zcrypt_check_card(perms, zc->card->id)) + continue; /* get weight index of the card device */ weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) @@ -400,6 +853,10 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) ((*domain != (unsigned short) AUTOSELECT) && (*domain != AP_QID_QUEUE(zq->queue->qid)))) continue; + /* check if device node has admission for this queue */ + if (!zcrypt_check_queue(perms, + AP_QID_QUEUE(zq->queue->qid))) + continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) continue; @@ -433,6 +890,11 @@ out: AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } + +long zcrypt_send_cprb(struct ica_xcRB *xcRB) +{ + return _zcrypt_send_cprb(&ap_perms, xcRB); +} EXPORT_SYMBOL(zcrypt_send_cprb); static bool is_desired_ep11_card(unsigned int dev_id, @@ -459,7 +921,8 @@ static bool is_desired_ep11_queue(unsigned int dev_qid, return false; } -static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) +static long zcrypt_send_ep11_cprb(struct ap_perms *perms, + struct ep11_urb *xcrb) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; @@ -510,6 +973,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) if (targets && !is_desired_ep11_card(zc->card->id, target_num, targets)) continue; + /* check if device node has admission for this card */ + if (!zcrypt_check_card(perms, zc->card->id)) + continue; /* get weight index of the card device */ weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) @@ -522,6 +988,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) continue; + /* check if device node has admission for this queue */ + if (!zcrypt_check_queue(perms, + AP_QID_QUEUE(zq->queue->qid))) + continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) continue; @@ -788,7 +1258,13 @@ static int zcrypt_requestq_count(void) static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - int rc = 0; + int rc; + struct ap_perms *perms = + (struct ap_perms *) filp->private_data; + + rc = zcrypt_check_ioctl(perms, cmd); + if (rc) + return rc; switch (cmd) { case ICARSAMODEXPO: { @@ -798,12 +1274,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&mex, umex, sizeof(mex))) return -EFAULT; do { - rc = zcrypt_rsa_modexpo(&mex); + rc = zcrypt_rsa_modexpo(perms, &mex); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_modexpo(&mex); + rc = zcrypt_rsa_modexpo(perms, &mex); } while (rc == -EAGAIN); if (rc) { ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc); @@ -818,12 +1294,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&crt, ucrt, sizeof(crt))) return -EFAULT; do { - rc = zcrypt_rsa_crt(&crt); + rc = zcrypt_rsa_crt(perms, &crt); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_crt(&crt); + rc = zcrypt_rsa_crt(perms, &crt); } while (rc == -EAGAIN); if (rc) { ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc); @@ -838,15 +1314,16 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) return -EFAULT; do { - rc = zcrypt_send_cprb(&xcRB); + rc = _zcrypt_send_cprb(perms, &xcRB); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_send_cprb(&xcRB); + rc = _zcrypt_send_cprb(perms, &xcRB); } while (rc == -EAGAIN); if (rc) - ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d\n", rc); + ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n", + rc, xcRB.status); if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) return -EFAULT; return rc; @@ -858,12 +1335,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) return -EFAULT; do { - rc = zcrypt_send_ep11_cprb(&xcrb); + rc = zcrypt_send_ep11_cprb(perms, &xcrb); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_send_ep11_cprb(&xcrb); + rc = zcrypt_send_ep11_cprb(perms, &xcrb); } while (rc == -EAGAIN); if (rc) ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc); @@ -989,8 +1466,8 @@ struct compat_ica_rsa_modexpo { compat_uptr_t n_modulus; }; -static long trans_modexpo32(struct file *filp, unsigned int cmd, - unsigned long arg) +static long trans_modexpo32(struct ap_perms *perms, struct file *filp, + unsigned int cmd, unsigned long arg) { struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg); struct compat_ica_rsa_modexpo mex32; @@ -1006,12 +1483,12 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd, mex64.b_key = compat_ptr(mex32.b_key); mex64.n_modulus = compat_ptr(mex32.n_modulus); do { - rc = zcrypt_rsa_modexpo(&mex64); + rc = zcrypt_rsa_modexpo(perms, &mex64); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_modexpo(&mex64); + rc = zcrypt_rsa_modexpo(perms, &mex64); } while (rc == -EAGAIN); if (rc) return rc; @@ -1031,8 +1508,8 @@ struct compat_ica_rsa_modexpo_crt { compat_uptr_t u_mult_inv; }; -static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, - unsigned long arg) +static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp, + unsigned int cmd, unsigned long arg) { struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg); struct compat_ica_rsa_modexpo_crt crt32; @@ -1051,12 +1528,12 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, crt64.nq_prime = compat_ptr(crt32.nq_prime); crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv); do { - rc = zcrypt_rsa_crt(&crt64); + rc = zcrypt_rsa_crt(perms, &crt64); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_crt(&crt64); + rc = zcrypt_rsa_crt(perms, &crt64); } while (rc == -EAGAIN); if (rc) return rc; @@ -1084,8 +1561,8 @@ struct compat_ica_xcRB { unsigned int status; } __packed; -static long trans_xcRB32(struct file *filp, unsigned int cmd, - unsigned long arg) +static long trans_xcRB32(struct ap_perms *perms, struct file *filp, + unsigned int cmd, unsigned long arg) { struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg); struct compat_ica_xcRB xcRB32; @@ -1115,12 +1592,12 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, xcRB64.priority_window = xcRB32.priority_window; xcRB64.status = xcRB32.status; do { - rc = zcrypt_send_cprb(&xcRB64); + rc = _zcrypt_send_cprb(perms, &xcRB64); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_send_cprb(&xcRB64); + rc = _zcrypt_send_cprb(perms, &xcRB64); } while (rc == -EAGAIN); xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; xcRB32.reply_data_length = xcRB64.reply_data_length; @@ -1133,12 +1610,20 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + int rc; + struct ap_perms *perms = + (struct ap_perms *) filp->private_data; + + rc = zcrypt_check_ioctl(perms, cmd); + if (rc) + return rc; + if (cmd == ICARSAMODEXPO) - return trans_modexpo32(filp, cmd, arg); + return trans_modexpo32(perms, filp, cmd, arg); if (cmd == ICARSACRT) - return trans_modexpo_crt32(filp, cmd, arg); + return trans_modexpo_crt32(perms, filp, cmd, arg); if (cmd == ZSECSENDCPRB) - return trans_xcRB32(filp, cmd, arg); + return trans_xcRB32(perms, filp, cmd, arg); return zcrypt_unlocked_ioctl(filp, cmd, arg); } #endif @@ -1256,6 +1741,67 @@ void zcrypt_debug_exit(void) debug_unregister(zcrypt_dbf_info); } +#ifdef CONFIG_ZCRYPT_MULTIDEVNODES + +static int __init zcdn_init(void) +{ + int rc; + + /* create a new class 'zcrypt' */ + zcrypt_class = class_create(THIS_MODULE, ZCRYPT_NAME); + if (IS_ERR(zcrypt_class)) { + rc = PTR_ERR(zcrypt_class); + goto out_class_create_failed; + } + zcrypt_class->dev_release = zcdn_device_release; + + /* alloc device minor range */ + rc = alloc_chrdev_region(&zcrypt_devt, + 0, ZCRYPT_MAX_MINOR_NODES, + ZCRYPT_NAME); + if (rc) + goto out_alloc_chrdev_failed; + + cdev_init(&zcrypt_cdev, &zcrypt_fops); + zcrypt_cdev.owner = THIS_MODULE; + rc = cdev_add(&zcrypt_cdev, zcrypt_devt, ZCRYPT_MAX_MINOR_NODES); + if (rc) + goto out_cdev_add_failed; + + /* need some class specific sysfs attributes */ + rc = class_create_file(zcrypt_class, &class_attr_zcdn_create); + if (rc) + goto out_class_create_file_1_failed; + rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy); + if (rc) + goto out_class_create_file_2_failed; + + return 0; + +out_class_create_file_2_failed: + class_remove_file(zcrypt_class, &class_attr_zcdn_create); +out_class_create_file_1_failed: + cdev_del(&zcrypt_cdev); +out_cdev_add_failed: + unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES); +out_alloc_chrdev_failed: + class_destroy(zcrypt_class); +out_class_create_failed: + return rc; +} + +static void zcdn_exit(void) +{ + class_remove_file(zcrypt_class, &class_attr_zcdn_create); + class_remove_file(zcrypt_class, &class_attr_zcdn_destroy); + zcdn_destroy_all(); + cdev_del(&zcrypt_cdev); + unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES); + class_destroy(zcrypt_class); +} + +#endif + /** * zcrypt_api_init(): Module initialization. * @@ -1269,15 +1815,27 @@ int __init zcrypt_api_init(void) if (rc) goto out; +#ifdef CONFIG_ZCRYPT_MULTIDEVNODES + rc = zcdn_init(); + if (rc) + goto out; +#endif + /* Register the request sprayer. */ rc = misc_register(&zcrypt_misc_device); if (rc < 0) - goto out; + goto out_misc_register_failed; zcrypt_msgtype6_init(); zcrypt_msgtype50_init(); + return 0; +out_misc_register_failed: +#ifdef CONFIG_ZCRYPT_MULTIDEVNODES + zcdn_exit(); +#endif + zcrypt_debug_exit(); out: return rc; } @@ -1289,6 +1847,9 @@ out: */ void __exit zcrypt_api_exit(void) { +#ifdef CONFIG_ZCRYPT_MULTIDEVNODES + zcdn_exit(); +#endif misc_deregister(&zcrypt_misc_device); zcrypt_msgtype6_exit(); zcrypt_msgtype50_exit(); diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index a848625c1a5a..af67a768a3fc 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * zcrypt 2.1.0 - * - * Copyright IBM Corp. 2001, 2012 + * Copyright IBM Corp. 2001, 2018 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) * Cornelia Huck <cornelia.huck@de.ibm.com> @@ -22,17 +20,8 @@ #include "ap_bus.h" /** - * device type for an actual device is either PCICA, PCICC, PCIXCC_MCL2, - * PCIXCC_MCL3, CEX2C, or CEX2A - * - * NOTE: PCIXCC_MCL3 refers to a PCIXCC with May 2004 version of Licensed - * Internal Code (LIC) (EC J12220 level 29). - * PCIXCC_MCL2 refers to any LIC before this level. + * Supported device types */ -#define ZCRYPT_PCICA 1 -#define ZCRYPT_PCICC 2 -#define ZCRYPT_PCIXCC_MCL2 3 -#define ZCRYPT_PCIXCC_MCL3 4 #define ZCRYPT_CEX2C 5 #define ZCRYPT_CEX2A 6 #define ZCRYPT_CEX3C 7 diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index 40cd4c1c2de8..d4f35a183c15 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2012 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h index e5b5c02c9d67..f09bb850763b 100644 --- a/drivers/s390/crypto/zcrypt_cca_key.h +++ b/drivers/s390/crypto/zcrypt_cca_key.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2006 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index f4ae5fa30ec9..146f54f5cbb8 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2012 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) @@ -43,8 +41,8 @@ #define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME MODULE_AUTHOR("IBM Corporation"); -MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \ - "Copyright IBM Corp. 2001, 2012"); +MODULE_DESCRIPTION("CEX2A/CEX3A Cryptographic Coprocessor device driver, " \ + "Copyright IBM Corp. 2001, 2018"); MODULE_LICENSE("GPL"); static struct ap_device_id zcrypt_cex2a_card_ids[] = { diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h index 66d58bc87c66..7842214d9d09 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.h +++ b/drivers/s390/crypto/zcrypt_cex2a.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2006 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) @@ -14,7 +12,7 @@ #define _ZCRYPT_CEX2A_H_ /** - * The type 50 message family is associated with a CEX2A card. + * The type 50 message family is associated with CEXxA cards. * * The four members of the family are described below. * @@ -111,7 +109,7 @@ struct type50_crb3_msg { } __packed; /** - * The type 80 response family is associated with a CEX2A card. + * The type 80 response family is associated with a CEXxA cards. * * Note that all unsigned char arrays are right-justified and left-padded * with zeroes. diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_cex2c.c index 94d9f7224aea..546f67676734 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_cex2c.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * zcrypt 2.1.0 - * - * Copyright IBM Corp. 2001, 2012 + * Copyright IBM Corp. 2001, 2018 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) * @@ -25,39 +23,22 @@ #include "zcrypt_api.h" #include "zcrypt_error.h" #include "zcrypt_msgtype6.h" -#include "zcrypt_pcixcc.h" +#include "zcrypt_cex2c.h" #include "zcrypt_cca_key.h" -#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */ -#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ -#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */ -#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE +#define CEX2C_MIN_MOD_SIZE 16 /* 128 bits */ +#define CEX2C_MAX_MOD_SIZE 256 /* 2048 bits */ +#define CEX3C_MIN_MOD_SIZE 16 /* 128 bits */ #define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */ - -#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */ -#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ - -#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024) - -#define PCIXCC_CLEANUP_TIME (15*HZ) - -#define CEIL4(x) ((((x)+3)/4)*4) - -struct response_type { - struct completion work; - int type; -}; -#define PCIXCC_RESPONSE_TYPE_ICA 0 -#define PCIXCC_RESPONSE_TYPE_XCRB 1 +#define CEX2C_MAX_XCRB_MESSAGE_SIZE (12*1024) +#define CEX2C_CLEANUP_TIME (15*HZ) MODULE_AUTHOR("IBM Corporation"); -MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \ - "Copyright IBM Corp. 2001, 2012"); +MODULE_DESCRIPTION("CEX2C/CEX3C Cryptographic Coprocessor device driver, " \ + "Copyright IBM Corp. 2001, 2018"); MODULE_LICENSE("GPL"); -static struct ap_device_id zcrypt_pcixcc_card_ids[] = { - { .dev_type = AP_DEVICE_TYPE_PCIXCC, - .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, +static struct ap_device_id zcrypt_cex2c_card_ids[] = { { .dev_type = AP_DEVICE_TYPE_CEX2C, .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, { .dev_type = AP_DEVICE_TYPE_CEX3C, @@ -65,11 +46,9 @@ static struct ap_device_id zcrypt_pcixcc_card_ids[] = { { /* end of list */ }, }; -MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids); +MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_card_ids); -static struct ap_device_id zcrypt_pcixcc_queue_ids[] = { - { .dev_type = AP_DEVICE_TYPE_PCIXCC, - .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, +static struct ap_device_id zcrypt_cex2c_queue_ids[] = { { .dev_type = AP_DEVICE_TYPE_CEX2C, .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, { .dev_type = AP_DEVICE_TYPE_CEX3C, @@ -77,16 +56,16 @@ static struct ap_device_id zcrypt_pcixcc_queue_ids[] = { { /* end of list */ }, }; -MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids); +MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_queue_ids); /** - * Large random number detection function. Its sends a message to a pcixcc + * Large random number detection function. Its sends a message to a CEX2C/CEX3C * card to find out if large random numbers are supported. * @ap_dev: pointer to the AP device. * * Returns 1 if large random numbers are supported, 0 if not and < 0 on error. */ -static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq) +static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) { struct ap_message ap_msg; unsigned long long psmid; @@ -147,13 +126,11 @@ out_free: } /** - * Probe function for PCIXCC/CEX2C card devices. It always accepts the - * AP device since the bus_match already checked the hardware type. The - * PCIXCC cards come in two flavours: micro code level 2 and micro code - * level 3. This is checked by sending a test message to the device. + * Probe function for CEX2C/CEX3C card devices. It always accepts the + * AP device since the bus_match already checked the hardware type. * @ap_dev: pointer to the AP card device. */ -static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev) +static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev) { /* * Normalized speed ratings per crypto adapter @@ -179,9 +156,9 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev) zc->type_string = "CEX2C"; memcpy(zc->speed_rating, CEX2C_SPEED_IDX, sizeof(CEX2C_SPEED_IDX)); - zc->min_mod_size = PCIXCC_MIN_MOD_SIZE; - zc->max_mod_size = PCIXCC_MAX_MOD_SIZE; - zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; + zc->min_mod_size = CEX2C_MIN_MOD_SIZE; + zc->max_mod_size = CEX2C_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX2C_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3C: zc->user_space_type = ZCRYPT_CEX3C; @@ -208,10 +185,10 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev) } /** - * This is called to remove the PCIXCC/CEX2C card driver information + * This is called to remove the CEX2C/CEX3C card driver information * if an AP card device is removed. */ -static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev) +static void zcrypt_cex2c_card_remove(struct ap_device *ap_dev) { struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; @@ -219,33 +196,31 @@ static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev) zcrypt_card_unregister(zc); } -static struct ap_driver zcrypt_pcixcc_card_driver = { - .probe = zcrypt_pcixcc_card_probe, - .remove = zcrypt_pcixcc_card_remove, - .ids = zcrypt_pcixcc_card_ids, +static struct ap_driver zcrypt_cex2c_card_driver = { + .probe = zcrypt_cex2c_card_probe, + .remove = zcrypt_cex2c_card_remove, + .ids = zcrypt_cex2c_card_ids, .flags = AP_DRIVER_FLAG_DEFAULT, }; /** - * Probe function for PCIXCC/CEX2C queue devices. It always accepts the - * AP device since the bus_match already checked the hardware type. The - * PCIXCC cards come in two flavours: micro code level 2 and micro code - * level 3. This is checked by sending a test message to the device. + * Probe function for CEX2C/CEX3C queue devices. It always accepts the + * AP device since the bus_match already checked the hardware type. * @ap_dev: pointer to the AP card device. */ -static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev) +static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev) { struct ap_queue *aq = to_ap_queue(&ap_dev->device); struct zcrypt_queue *zq; int rc; - zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); + zq = zcrypt_queue_alloc(CEX2C_MAX_XCRB_MESSAGE_SIZE); if (!zq) return -ENOMEM; zq->queue = aq; zq->online = 1; atomic_set(&zq->load, 0); - rc = zcrypt_pcixcc_rng_supported(aq); + rc = zcrypt_cex2c_rng_supported(aq); if (rc < 0) { zcrypt_queue_free(zq); return rc; @@ -257,7 +232,7 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev) zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, MSGTYPE06_VARIANT_NORNG); ap_queue_init_reply(aq, &zq->reply); - aq->request_timeout = PCIXCC_CLEANUP_TIME, + aq->request_timeout = CEX2C_CLEANUP_TIME; aq->private = zq; rc = zcrypt_queue_register(zq); if (rc) { @@ -268,10 +243,10 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev) } /** - * This is called to remove the PCIXCC/CEX2C queue driver information + * This is called to remove the CEX2C/CEX3C queue driver information * if an AP queue device is removed. */ -static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev) +static void zcrypt_cex2c_queue_remove(struct ap_device *ap_dev) { struct ap_queue *aq = to_ap_queue(&ap_dev->device); struct zcrypt_queue *zq = aq->private; @@ -281,37 +256,37 @@ static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev) zcrypt_queue_unregister(zq); } -static struct ap_driver zcrypt_pcixcc_queue_driver = { - .probe = zcrypt_pcixcc_queue_probe, - .remove = zcrypt_pcixcc_queue_remove, +static struct ap_driver zcrypt_cex2c_queue_driver = { + .probe = zcrypt_cex2c_queue_probe, + .remove = zcrypt_cex2c_queue_remove, .suspend = ap_queue_suspend, .resume = ap_queue_resume, - .ids = zcrypt_pcixcc_queue_ids, + .ids = zcrypt_cex2c_queue_ids, .flags = AP_DRIVER_FLAG_DEFAULT, }; -int __init zcrypt_pcixcc_init(void) +int __init zcrypt_cex2c_init(void) { int rc; - rc = ap_driver_register(&zcrypt_pcixcc_card_driver, - THIS_MODULE, "pcixcccard"); + rc = ap_driver_register(&zcrypt_cex2c_card_driver, + THIS_MODULE, "cex2card"); if (rc) return rc; - rc = ap_driver_register(&zcrypt_pcixcc_queue_driver, - THIS_MODULE, "pcixccqueue"); + rc = ap_driver_register(&zcrypt_cex2c_queue_driver, + THIS_MODULE, "cex2cqueue"); if (rc) - ap_driver_unregister(&zcrypt_pcixcc_card_driver); + ap_driver_unregister(&zcrypt_cex2c_card_driver); return rc; } -void zcrypt_pcixcc_exit(void) +void zcrypt_cex2c_exit(void) { - ap_driver_unregister(&zcrypt_pcixcc_queue_driver); - ap_driver_unregister(&zcrypt_pcixcc_card_driver); + ap_driver_unregister(&zcrypt_cex2c_queue_driver); + ap_driver_unregister(&zcrypt_cex2c_card_driver); } -module_init(zcrypt_pcixcc_init); -module_exit(zcrypt_pcixcc_exit); +module_init(zcrypt_cex2c_init); +module_exit(zcrypt_cex2c_exit); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_cex2c.h index cf73a0f91e9c..6ec405c2bec2 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_cex2c.h @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * zcrypt 2.1.0 - * - * Copyright IBM Corp. 2001, 2012 + * Copyright IBM Corp. 2001, 2018 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) * @@ -11,10 +9,10 @@ * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> */ -#ifndef _ZCRYPT_PCIXCC_H_ -#define _ZCRYPT_PCIXCC_H_ +#ifndef _ZCRYPT_CEX2C_H_ +#define _ZCRYPT_CEX2C_H_ -int zcrypt_pcixcc_init(void); -void zcrypt_pcixcc_exit(void); +int zcrypt_cex2c_init(void); +void zcrypt_cex2c_exit(void); -#endif /* _ZCRYPT_PCIXCC_H_ */ +#endif /* _ZCRYPT_CEX2C_H_ */ diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 35d58dbbc4da..f9d4c6c7521d 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -37,8 +37,8 @@ #define CEX4_CLEANUP_TIME (900*HZ) MODULE_AUTHOR("IBM Corporation"); -MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \ - "Copyright IBM Corp. 2012"); +MODULE_DESCRIPTION("CEX4/CEX5/CEX6 Cryptographic Card device driver, " \ + "Copyright IBM Corp. 2018"); MODULE_LICENSE("GPL"); static struct ap_device_id zcrypt_cex4_card_ids[] = { @@ -66,8 +66,9 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = { MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids); /** - * Probe function for CEX4 card device. It always accepts the AP device - * since the bus_match already checked the hardware type. + * Probe function for CEX4/CEX5/CEX6 card device. It always + * accepts the AP device since the bus_match already checked + * the hardware type. * @ap_dev: pointer to the AP device. */ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) @@ -199,7 +200,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) } /** - * This is called to remove the CEX4 card driver information + * This is called to remove the CEX4/CEX5/CEX6 card driver information * if an AP card device is removed. */ static void zcrypt_cex4_card_remove(struct ap_device *ap_dev) @@ -218,8 +219,9 @@ static struct ap_driver zcrypt_cex4_card_driver = { }; /** - * Probe function for CEX4 queue device. It always accepts the AP device - * since the bus_match already checked the hardware type. + * Probe function for CEX4/CEX5/CEX6 queue device. It always + * accepts the AP device since the bus_match already checked + * the hardware type. * @ap_dev: pointer to the AP device. */ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) @@ -265,8 +267,8 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) } /** - * This is called to remove the CEX4 queue driver information - * if an AP queue device is removed. + * This is called to remove the CEX4/CEX5/CEX6 queue driver + * information if an AP queue device is removed. */ static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) { diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 6f7ebc1dbe10..240b27f3f5f6 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2006 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) @@ -16,6 +14,7 @@ #include <linux/atomic.h> #include "zcrypt_debug.h" #include "zcrypt_api.h" +#include "zcrypt_msgtype6.h" /** * Reply Messages @@ -114,6 +113,27 @@ static inline int convert_error(struct zcrypt_queue *zq, card, queue, ehdr->reply_code); return -EAGAIN; case REP82_ERROR_TRANSPORT_FAIL: + /* Card or infrastructure failure, disable card */ + atomic_set(&zcrypt_rescan_req, 1); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + card, queue); + /* For type 86 response show the apfs value (failure reason) */ + if (ehdr->type == TYPE86_RSP_CODE) { + struct { + struct type86_hdr hdr; + struct type86_fmt2_ext fmt2; + } __packed * head = reply->message; + unsigned int apfs = *((u32 *)head->fmt2.apfs); + + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x apfs=0x%x => online=0 rc=EAGAIN\n", + card, queue, apfs, ehdr->reply_code); + } else + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n", + card, queue, ehdr->reply_code); + return -EAGAIN; case REP82_ERROR_MACHINE_FAILURE: // REP88_ERROR_MODULE_FAILURE // '10' CEX2A /* If a card fails disable it and repeat the request. */ diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index f159662c907b..fc4295b3d801 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2012 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) @@ -27,13 +25,13 @@ #include "zcrypt_error.h" #include "zcrypt_msgtype50.h" -/* 4096 bits */ +/* >= CEX3A: 4096 bits */ #define CEX3A_MAX_MOD_SIZE 512 -/* max outputdatalength + type80_hdr */ +/* CEX2A: max outputdatalength + type80_hdr */ #define CEX2A_MAX_RESPONSE_SIZE 0x110 -/* 512 bit modulus, (max outputdatalength) + type80_hdr */ +/* >= CEX3A: 512 bit modulus, (max outputdatalength) + type80_hdr */ #define CEX3A_MAX_RESPONSE_SIZE 0x210 MODULE_AUTHOR("IBM Corporation"); @@ -42,7 +40,7 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \ MODULE_LICENSE("GPL"); /** - * The type 50 message family is associated with a CEX2A card. + * The type 50 message family is associated with a CEXxA cards. * * The four members of the family are described below. * @@ -139,7 +137,7 @@ struct type50_crb3_msg { } __packed; /** - * The type 80 response family is associated with a CEX2A card. + * The type 80 response family is associated with a CEXxA cards. * * Note that all unsigned char arrays are right-justified and left-padded * with zeroes. @@ -273,7 +271,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, /* * CEX2A and CEX3A w/o FW update can handle requests up to * 256 byte modulus (2k keys). - * CEX3A with FW update and CEX4A cards are able to handle + * CEX3A with FW update and newer CEXxA cards are able to handle * 512 byte modulus (4k keys). */ if (mod_len <= 128) { /* up to 1024 bit key size */ @@ -356,7 +354,7 @@ static int convert_type80(struct zcrypt_queue *zq, unsigned char *data; if (t80h->len < sizeof(*t80h) + outputdatalength) { - /* The result is too short, the CEX2A card may not do that.. */ + /* The result is too short, the CEXxA card may not do that.. */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), @@ -447,10 +445,10 @@ out: static atomic_t zcrypt_step = ATOMIC_INIT(0); /** - * The request distributor calls this function if it picked the CEX2A + * The request distributor calls this function if it picked the CEXxA * device to handle a modexpo request. * @zq: pointer to zcrypt_queue structure that identifies the - * CEX2A device to the request distributor + * CEXxA device to the request distributor * @mex: pointer to the modexpo request buffer */ static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq, @@ -493,10 +491,10 @@ out_free: } /** - * The request distributor calls this function if it picked the CEX2A + * The request distributor calls this function if it picked the CEXxA * device to handle a modexpo_crt request. * @zq: pointer to zcrypt_queue structure that identifies the - * CEX2A device to the request distributor + * CEXxA device to the request distributor * @crt: pointer to the modexpoc_crt request buffer */ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq, diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h index 8530f652ea4f..66bec4f45c56 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.h +++ b/drivers/s390/crypto/zcrypt_msgtype50.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2012 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 2101776a8148..0cbcc238ef98 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2012 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) @@ -29,8 +27,7 @@ #include "zcrypt_msgtype6.h" #include "zcrypt_cca_key.h" -#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ -#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ +#define CEXXC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ #define CEIL4(x) ((((x)+3)/4)*4) @@ -38,9 +35,9 @@ struct response_type { struct completion work; int type; }; -#define PCIXCC_RESPONSE_TYPE_ICA 0 -#define PCIXCC_RESPONSE_TYPE_XCRB 1 -#define PCIXCC_RESPONSE_TYPE_EP11 2 +#define CEXXC_RESPONSE_TYPE_ICA 0 +#define CEXXC_RESPONSE_TYPE_XCRB 1 +#define CEXXC_RESPONSE_TYPE_EP11 2 MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ @@ -111,7 +108,7 @@ struct function_and_rules_block { } __packed; /** - * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C + * The following is used to initialize the CPRBX passed to the CEXxC/CEXxP * card in a type6 message. The 3 fields that must be filled in at execution * time are req_parml, rpl_parml and usage_domain. * Everything about this interface is ascii/big-endian, since the @@ -294,7 +291,7 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq, /* message header, cprbx and f&r */ msg->hdr = static_type6_hdrX; msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); - msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); + msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); msg->cprbx = static_cprbx; msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); @@ -364,7 +361,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq, /* message header, cprbx and f&r */ msg->hdr = static_type6_hdrX; msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); - msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); + msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); msg->cprbx = static_cprbx; msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); @@ -658,16 +655,6 @@ static int convert_type86_ica(struct zcrypt_queue *zq, (int) service_rc, (int) service_rs); return -EINVAL; } - if (service_rc == 8 && service_rs == 783) { - zq->zcard->min_mod_size = - PCIXCC_MIN_MOD_SIZE_OLD; - ZCRYPT_DBF(DBF_DEBUG, - "device=%02x.%04x rc/rs=%d/%d => rc=EAGAIN\n", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - (int) service_rc, (int) service_rs); - return -EAGAIN; - } zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), @@ -697,7 +684,7 @@ static int convert_type86_ica(struct zcrypt_queue *zq, if (pad_len > 0) { if (pad_len < 10) return -EINVAL; - /* 'restore' padding left in the PCICC/PCIXCC card. */ + /* 'restore' padding left in the CEXXC card. */ if (copy_to_user(outputdata, static_pad, pad_len - 1)) return -EFAULT; if (put_user(0, outputdata + pad_len - 1)) @@ -955,13 +942,13 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, if (t86r->hdr.type == TYPE86_RSP_CODE && t86r->cprbx.cprb_ver_id == 0x02) { switch (resp_type->type) { - case PCIXCC_RESPONSE_TYPE_ICA: + case CEXXC_RESPONSE_TYPE_ICA: length = sizeof(struct type86x_reply) + t86r->length - 2; - length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length); + length = min(CEXXC_MAX_ICA_RESPONSE_SIZE, length); memcpy(msg->message, reply->message, length); break; - case PCIXCC_RESPONSE_TYPE_XCRB: + case CEXXC_RESPONSE_TYPE_XCRB: length = t86r->fmt2.offset2 + t86r->fmt2.count2; length = min(MSGTYPE06_MAX_MSG_SIZE, length); memcpy(msg->message, reply->message, length); @@ -1004,7 +991,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, if (t86r->hdr.type == TYPE86_RSP_CODE && t86r->cprbx.cprb_ver_id == 0x04) { switch (resp_type->type) { - case PCIXCC_RESPONSE_TYPE_EP11: + case CEXXC_RESPONSE_TYPE_EP11: length = t86r->fmt2.offset1 + t86r->fmt2.count1; length = min(MSGTYPE06_MAX_MSG_SIZE, length); memcpy(msg->message, reply->message, length); @@ -1022,10 +1009,10 @@ out: static atomic_t zcrypt_step = ATOMIC_INIT(0); /** - * The request distributor calls this function if it picked the PCIXCC/CEX2C + * The request distributor calls this function if it picked the CEXxC * device to handle a modexpo request. * @zq: pointer to zcrypt_queue structure that identifies the - * PCIXCC/CEX2C device to the request distributor + * CEXxC device to the request distributor * @mex: pointer to the modexpo request buffer */ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, @@ -1033,7 +1020,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, { struct ap_message ap_msg; struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_ICA, + .type = CEXXC_RESPONSE_TYPE_ICA, }; int rc; @@ -1066,10 +1053,10 @@ out_free: } /** - * The request distributor calls this function if it picked the PCIXCC/CEX2C + * The request distributor calls this function if it picked the CEXxC * device to handle a modexpo_crt request. * @zq: pointer to zcrypt_queue structure that identifies the - * PCIXCC/CEX2C device to the request distributor + * CEXxC device to the request distributor * @crt: pointer to the modexpoc_crt request buffer */ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, @@ -1077,7 +1064,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, { struct ap_message ap_msg; struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_ICA, + .type = CEXXC_RESPONSE_TYPE_ICA, }; int rc; @@ -1122,7 +1109,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, unsigned int *func_code, unsigned short **dom) { struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, + .type = CEXXC_RESPONSE_TYPE_XCRB, }; ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); @@ -1131,18 +1118,17 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, ap_msg->receive = zcrypt_msgtype6_receive; ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); - ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); if (!ap_msg->private) return -ENOMEM; - memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); return XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom); } /** - * The request distributor calls this function if it picked the PCIXCC/CEX2C + * The request distributor calls this function if it picked the CEXxC * device to handle a send_cprb request. * @zq: pointer to zcrypt_queue structure that identifies the - * PCIXCC/CEX2C device to the request distributor + * CEXxC device to the request distributor * @xcRB: pointer to the send_cprb request buffer */ static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq, @@ -1178,7 +1164,7 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, unsigned int *func_code) { struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_EP11, + .type = CEXXC_RESPONSE_TYPE_EP11, }; ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); @@ -1187,10 +1173,9 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, ap_msg->receive = zcrypt_msgtype6_receive_ep11; ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); - ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); if (!ap_msg->private) return -ENOMEM; - memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); return xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code); } @@ -1273,7 +1258,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, unsigned int *domain) { struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, + .type = CEXXC_RESPONSE_TYPE_XCRB, }; ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); @@ -1282,10 +1267,9 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, ap_msg->receive = zcrypt_msgtype6_receive; ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); - ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); if (!ap_msg->private) return -ENOMEM; - memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain); @@ -1294,10 +1278,10 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, } /** - * The request distributor calls this function if it picked the PCIXCC/CEX2C + * The request distributor calls this function if it picked the CEXxC * device to generate random data. * @zq: pointer to zcrypt_queue structure that identifies the - * PCIXCC/CEX2C device to the request distributor + * CEXxC device to the request distributor * @buffer: pointer to a memory page to return random data */ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, @@ -1332,7 +1316,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, } /** - * The crypto operations for a PCIXCC/CEX2C card. + * The crypto operations for a CEXxC card. */ static struct zcrypt_ops zcrypt_msgtype6_norng_ops = { .owner = THIS_MODULE, diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index e4c2f37d7ad9..41a0df5f070f 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2012 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) @@ -24,7 +22,7 @@ #define MSGTYPE06_MAX_MSG_SIZE (12*1024) /** - * The type 6 message family is associated with PCICC or PCIXCC cards. + * The type 6 message family is associated with CEXxC/CEXxP cards. * * It contains a message header followed by a CPRB, both of which * are described below. @@ -43,13 +41,8 @@ struct type6_hdr { unsigned int offset2; /* 0x00000000 */ unsigned int offset3; /* 0x00000000 */ unsigned int offset4; /* 0x00000000 */ - unsigned char agent_id[16]; /* PCICC: */ - /* 0x0100 */ - /* 0x4343412d4150504c202020 */ - /* 0x010101 */ - /* PCIXCC: */ - /* 0x4341000000000000 */ - /* 0x0000000000000000 */ + unsigned char agent_id[16]; /* 0x4341000000000000 */ + /* 0x0000000000000000 */ unsigned char rqid[2]; /* rqid. internal to 603 */ unsigned char reserved5[2]; /* 0x0000 */ unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */ @@ -65,7 +58,7 @@ struct type6_hdr { } __packed; /** - * The type 86 message family is associated with PCICC and PCIXCC cards. + * The type 86 message family is associated with CEXxC/CEXxP cards. * * It contains a message header followed by a CPRB. The CPRB is * the same as the request CPRB, which is described above. diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index 8df82c6ef66e..522c4bc69a08 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * zcrypt 2.1.0 - * * Copyright IBM Corp. 2001, 2012 * Author(s): Robert Burroughs * Eric Rossman (edrossma@us.ibm.com) diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 7d1609fa233c..df82a349e969 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -220,16 +220,4 @@ static struct pcmcia_driver aha152x_cs_driver = { .id_table = aha152x_ids, .resume = aha152x_resume, }; - -static int __init init_aha152x_cs(void) -{ - return pcmcia_register_driver(&aha152x_cs_driver); -} - -static void __exit exit_aha152x_cs(void) -{ - pcmcia_unregister_driver(&aha152x_cs_driver); -} - -module_init(init_aha152x_cs); -module_exit(exit_aha152x_cs); +module_pcmcia_driver(aha152x_cs_driver); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 5fb6eefc6541..f3230494a8c9 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1742,19 +1742,6 @@ static struct pcmcia_driver nsp_driver = { .suspend = nsp_cs_suspend, .resume = nsp_cs_resume, }; - -static int __init nsp_cs_init(void) -{ - return pcmcia_register_driver(&nsp_driver); -} - -static void __exit nsp_cs_exit(void) -{ - pcmcia_unregister_driver(&nsp_driver); -} - - -module_init(nsp_cs_init) -module_exit(nsp_cs_exit) +module_pcmcia_driver(nsp_driver); /* end */ diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index afd64f0adc4b..ea5122f3396d 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -326,10 +326,6 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht); /* Interrupt handler */ //static irqreturn_t nspintr(int irq, void *dev_id); -/* Module entry point*/ -static int __init nsp_cs_init(void); -static void __exit nsp_cs_exit(void); - /* Debug */ #ifdef NSP_DEBUG static void show_command (struct scsi_cmnd *SCpnt); diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 0556054764dc..173351a8554b 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -254,8 +254,12 @@ static void qlogic_release(struct pcmcia_device *link) static int qlogic_resume(struct pcmcia_device *link) { scsi_info_t *info = link->priv; + int ret; + + ret = pcmcia_enable_device(link); + if (ret) + return ret; - pcmcia_enable_device(link); if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { @@ -300,18 +304,7 @@ static struct pcmcia_driver qlogic_cs_driver = { .resume = qlogic_resume, }; -static int __init init_qlogic_cs(void) -{ - return pcmcia_register_driver(&qlogic_cs_driver); -} - -static void __exit exit_qlogic_cs(void) -{ - pcmcia_unregister_driver(&qlogic_cs_driver); -} - MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers"); MODULE_LICENSE("GPL"); -module_init(init_qlogic_cs); -module_exit(exit_qlogic_cs); +module_pcmcia_driver(qlogic_cs_driver); diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 20011c8afbb5..a3b63bea0e50 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -880,18 +880,4 @@ static struct pcmcia_driver sym53c500_cs_driver = { .id_table = sym53c500_ids, .resume = sym53c500_resume, }; - -static int __init -init_sym53c500_cs(void) -{ - return pcmcia_register_driver(&sym53c500_cs_driver); -} - -static void __exit -exit_sym53c500_cs(void) -{ - pcmcia_unregister_driver(&sym53c500_cs_driver); -} - -module_init(init_sym53c500_cs); -module_exit(exit_sym53c500_cs); +module_pcmcia_driver(sym53c500_cs_driver); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index eb97d2dd3651..62348412ed1b 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -3046,11 +3046,14 @@ scsi_device_quiesce(struct scsi_device *sdev) */ WARN_ON_ONCE(sdev->quiesced_by && sdev->quiesced_by != current); - blk_set_preempt_only(q); + if (sdev->quiesced_by == current) + return 0; + + blk_set_pm_only(q); blk_mq_freeze_queue(q); /* - * Ensure that the effect of blk_set_preempt_only() will be visible + * Ensure that the effect of blk_set_pm_only() will be visible * for percpu_ref_tryget() callers that occur after the queue * unfreeze even if the queue was already frozen before this function * was called. See also https://lwn.net/Articles/573497/. @@ -3063,7 +3066,7 @@ scsi_device_quiesce(struct scsi_device *sdev) if (err == 0) sdev->quiesced_by = current; else - blk_clear_preempt_only(q); + blk_clear_pm_only(q); mutex_unlock(&sdev->state_mutex); return err; @@ -3088,7 +3091,7 @@ void scsi_device_resume(struct scsi_device *sdev) mutex_lock(&sdev->state_mutex); WARN_ON_ONCE(!sdev->quiesced_by); sdev->quiesced_by = NULL; - blk_clear_preempt_only(sdev->request_queue); + blk_clear_pm_only(sdev->request_queue); if (sdev->sdev_state == SDEV_QUIESCE) scsi_device_set_state(sdev, SDEV_RUNNING); mutex_unlock(&sdev->state_mutex); diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index b44c1bb687a2..a2b4179bfdf7 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -8,6 +8,7 @@ #include <linux/pm_runtime.h> #include <linux/export.h> #include <linux/async.h> +#include <linux/blk-pm.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 4a57ffecc7e6..b762d0fd773c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -45,6 +45,7 @@ #include <linux/init.h> #include <linux/blkdev.h> #include <linux/blkpg.h> +#include <linux/blk-pm.h> #include <linux/delay.h> #include <linux/mutex.h> #include <linux/string_helpers.h> @@ -3275,7 +3276,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) } blk_pm_runtime_init(sdp->request_queue, dev); - device_add_disk(dev, gd); + device_add_disk(dev, gd, NULL); if (sdkp->capacity) sd_dif_config_host(sdkp); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index d0389b20574d..54dd70ae9731 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -43,6 +43,7 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/blkdev.h> +#include <linux/blk-pm.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/pm_runtime.h> @@ -758,7 +759,7 @@ static int sr_probe(struct device *dev) dev_set_drvdata(dev, cd); disk->flags |= GENHD_FL_REMOVABLE; - device_add_disk(&sdev->sdev_gendev, disk); + device_add_disk(&sdev->sdev_gendev, disk, NULL); sdev_printk(KERN_DEBUG, sdev, "Attached scsi CD-ROM %s\n", cd->cdi.name); diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index feed3db21c10..ee89ffb6dde8 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on); */ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) { - unsigned long freq = 0; + long freq = 0; int i; if (se->clk_perf_tbl) { @@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { freq = clk_round_rate(se->clk, freq + 1); - if (!freq || freq == se->clk_perf_tbl[i - 1]) + if (freq <= 0 || freq == se->clk_perf_tbl[i - 1]) break; se->clk_perf_tbl[i] = freq; } @@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get); * @se: Pointer to the concerned serial engine. * @req_freq: Requested clock frequency. * @index: Index of the resultant frequency in the table. - * @res_freq: Resultant frequency which matches or is closer to the - * requested frequency. + * @res_freq: Resultant frequency of the source clock. * @exact: Flag to indicate exact multiple requirement of the requested * frequency. * - * This function is called by the protocol drivers to determine the matching - * or exact multiple of the requested frequency, as provided by the serial - * engine clock in order to meet the performance requirements. If there is - * no matching or exact multiple of the requested frequency found, then it - * selects the closest floor frequency, if exact flag is not set. + * This function is called by the protocol drivers to determine the best match + * of the requested frequency as provided by the serial engine clock in order + * to meet the performance requirements. + * + * If we return success: + * - if @exact is true then @res_freq / <an_integer> == @req_freq + * - if @exact is false then @res_freq / <an_integer> <= @req_freq * * Return: 0 on success, standard Linux error codes on failure. */ @@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, unsigned long *tbl; int num_clk_levels; int i; + unsigned long best_delta; + unsigned long new_delta; + unsigned int divider; num_clk_levels = geni_se_clk_tbl_get(se, &tbl); if (num_clk_levels < 0) @@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, if (num_clk_levels == 0) return -EINVAL; - *res_freq = 0; + best_delta = ULONG_MAX; for (i = 0; i < num_clk_levels; i++) { - if (!(tbl[i] % req_freq)) { + divider = DIV_ROUND_UP(tbl[i], req_freq); + new_delta = req_freq - tbl[i] / divider; + if (new_delta < best_delta) { + /* We have a new best! */ *index = i; *res_freq = tbl[i]; - return 0; - } - if (!(*res_freq) || ((tbl[i] > *res_freq) && - (tbl[i] < req_freq))) { - *index = i; - *res_freq = tbl[i]; + /* If the new best is exact then we're done */ + if (new_delta == 0) + return 0; + + /* Record how close we got */ + best_delta = new_delta; } } diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 671d078349cc..f756450a8914 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -129,7 +129,7 @@ config SPI_BCM63XX config SPI_BCM63XX_HSSPI tristate "Broadcom BCM63XX HS SPI controller driver" - depends on BCM63XX || COMPILE_TEST + depends on BCM63XX || ARCH_BCM_63XX || COMPILE_TEST help This enables support for the High Speed SPI controller present on newer Broadcom BCM63XX SoCs. @@ -520,6 +520,12 @@ config SPI_RSPI help SPI driver for Renesas RSPI and QSPI blocks. +config SPI_QCOM_QSPI + tristate "QTI QSPI controller" + depends on ARCH_QCOM + help + QSPI(Quad SPI) driver for Qualcomm QSPI controller. + config SPI_QUP tristate "Qualcomm SPI controller with QUP interface" depends on ARCH_QCOM || (ARM && COMPILE_TEST) @@ -533,6 +539,18 @@ config SPI_QUP This driver can also be built as a module. If so, the module will be called spi_qup. +config SPI_QCOM_GENI + tristate "Qualcomm GENI based SPI controller" + depends on QCOM_GENI_SE + help + This driver supports GENI serial engine based SPI controller in + master mode on the Qualcomm Technologies Inc.'s SoCs. If you say + yes to this option, support will be included for the built-in SPI + interface on the Qualcomm Technologies Inc.'s SoCs. + + 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 @@ -596,6 +614,22 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_SLAVE_MT27XX + tristate "MediaTek SPI slave device" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on SPI_SLAVE + help + This selects the MediaTek(R) SPI slave device driver. + If you want to use MediaTek(R) SPI slave interface, + say Y or M here.If you are not sure, say N. + SPI slave drivers for Mediatek MT27XX series ARM SoCs. + +config SPI_SPRD + tristate "Spreadtrum SPI controller" + depends on ARCH_SPRD || COMPILE_TEST + help + SPI driver for Spreadtrum SoCs. + config SPI_SPRD_ADI tristate "Spreadtrum ADI controller" depends on ARCH_SPRD || COMPILE_TEST @@ -613,6 +647,15 @@ config SPI_STM32 is not available, the driver automatically falls back to PIO mode. +config SPI_STM32_QSPI + tristate "STMicroelectronics STM32 QUAD SPI controller" + depends on ARCH_STM32 || COMPILE_TEST + depends on OF + help + This enables support for the Quad SPI controller in master mode. + This driver does not support generic SPI. The implementation only + supports spi-mem interface. + config SPI_ST_SSC4 tristate "STMicroelectronics SPI SSC-based driver" depends on ARCH_STI || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a90d55970036..df04dfbe7d70 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -74,6 +74,8 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o +obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o +obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o @@ -88,8 +90,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o +obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o +obj-$(CONFIG_SPI_SPRD) += spi-sprd.o obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o obj-$(CONFIG_SPI_STM32) += spi-stm32.o +obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 3f890d162934..74fddcd3282b 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1767,10 +1767,8 @@ static int atmel_spi_suspend(struct device *dev) /* Stop the queue running */ ret = spi_master_suspend(master); - if (ret) { - dev_warn(dev, "cannot suspend master\n"); + if (ret) return ret; - } if (!pm_runtime_suspended(dev)) atmel_spi_runtime_suspend(dev); @@ -1799,11 +1797,7 @@ static int atmel_spi_resume(struct device *dev) } /* Start the queue running */ - ret = spi_master_resume(master); - if (ret) - dev_err(dev, "problem starting queue (%d)\n", ret); - - return ret; + return spi_master_resume(master); } #endif diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 8612525fa4e3..584bcb018a62 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -89,7 +89,7 @@ #define BSPI_BPP_MODE_SELECT_MASK BIT(8) #define BSPI_BPP_ADDR_SELECT_MASK BIT(16) -#define BSPI_READ_LENGTH 512 +#define BSPI_READ_LENGTH 256 /* MSPI register offsets */ #define MSPI_SPCR0_LSB 0x000 @@ -355,7 +355,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int bpc = 0, bpp = 0; u8 command = op->cmd.opcode; int width = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE; - int addrlen = op->addr.nbytes * 8; + int addrlen = op->addr.nbytes; int flex_mode = 1; dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n", diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index c23849f7aa7b..9a06ffdb73b8 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -101,6 +101,7 @@ struct bcm63xx_hsspi { struct platform_device *pdev; struct clk *clk; + struct clk *pll_clk; void __iomem *regs; u8 __iomem *fifo; @@ -332,7 +333,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) struct resource *res_mem; void __iomem *regs; struct device *dev = &pdev->dev; - struct clk *clk; + struct clk *clk, *pll_clk = NULL; int irq, ret; u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS; @@ -358,7 +359,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) rate = clk_get_rate(clk); if (!rate) { - struct clk *pll_clk = devm_clk_get(dev, "pll"); + pll_clk = devm_clk_get(dev, "pll"); if (IS_ERR(pll_clk)) { ret = PTR_ERR(pll_clk); @@ -373,19 +374,20 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) clk_disable_unprepare(pll_clk); if (!rate) { ret = -EINVAL; - goto out_disable_clk; + goto out_disable_pll_clk; } } master = spi_alloc_master(&pdev->dev, sizeof(*bs)); if (!master) { ret = -ENOMEM; - goto out_disable_clk; + goto out_disable_pll_clk; } bs = spi_master_get_devdata(master); bs->pdev = pdev; bs->clk = clk; + bs->pll_clk = pll_clk; bs->regs = regs; bs->speed_hz = rate; bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0)); @@ -440,6 +442,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) out_put_master: spi_master_put(master); +out_disable_pll_clk: + clk_disable_unprepare(pll_clk); out_disable_clk: clk_disable_unprepare(clk); return ret; @@ -453,6 +457,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev) /* reset the hardware and block queue progress */ __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG); + clk_disable_unprepare(bs->pll_clk); clk_disable_unprepare(bs->clk); return 0; @@ -465,6 +470,7 @@ static int bcm63xx_hsspi_suspend(struct device *dev) struct bcm63xx_hsspi *bs = spi_master_get_devdata(master); spi_master_suspend(master); + clk_disable_unprepare(bs->pll_clk); clk_disable_unprepare(bs->clk); return 0; @@ -480,6 +486,12 @@ static int bcm63xx_hsspi_resume(struct device *dev) if (ret) return ret; + if (bs->pll_clk) { + ret = clk_prepare_enable(bs->pll_clk); + if (ret) + return ret; + } + spi_master_resume(master); return 0; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index a02099c90c5c..56adec83f8fc 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -208,13 +208,11 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits) static void davinci_spi_chipselect(struct spi_device *spi, int value) { struct davinci_spi *dspi; - struct davinci_spi_platform_data *pdata; struct davinci_spi_config *spicfg = spi->controller_data; u8 chip_sel = spi->chip_select; u16 spidat1 = CS_DEFAULT; dspi = spi_master_get_devdata(spi->master); - pdata = &dspi->pdata; /* program delay transfers if tx_delay is non zero */ if (spicfg && spicfg->wdelay) @@ -232,7 +230,8 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) !(spi->mode & SPI_CS_HIGH)); } else { if (value == BITBANG_CS_ACTIVE) { - spidat1 |= SPIDAT1_CSHOLD_MASK; + if (!(spi->mode & SPI_CS_WORD)) + spidat1 |= SPIDAT1_CSHOLD_MASK; spidat1 &= ~(0x1 << chip_sel); } } @@ -421,26 +420,17 @@ static int davinci_spi_setup(struct spi_device *spi) { int retval = 0; struct davinci_spi *dspi; - struct davinci_spi_platform_data *pdata; struct spi_master *master = spi->master; struct device_node *np = spi->dev.of_node; bool internal_cs = true; dspi = spi_master_get_devdata(spi->master); - pdata = &dspi->pdata; if (!(spi->mode & SPI_NO_CS)) { if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) { retval = gpio_direction_output( spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); internal_cs = false; - } else if (pdata->chip_sel && - spi->chip_select < pdata->num_chipselect && - pdata->chip_sel[spi->chip_select] != SPI_INTERN_CS) { - spi->cs_gpio = pdata->chip_sel[spi->chip_select]; - retval = gpio_direction_output( - spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - internal_cs = false; } if (retval) { @@ -449,8 +439,9 @@ static int davinci_spi_setup(struct spi_device *spi) return retval; } - if (internal_cs) + if (internal_cs) { set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); + } } if (spi->mode & SPI_READY) @@ -985,7 +976,7 @@ static int davinci_spi_probe(struct platform_device *pdev) dspi->prescaler_limit = pdata->prescaler_limit; dspi->version = pdata->version; - dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; + dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_WORD; if (dspi->version == SPI_VERSION_2) dspi->bitbang.flags |= SPI_READY; diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index e80f60ed6fdf..3ffb6a40fe0c 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -34,8 +34,9 @@ struct dw_spi_mmio { }; #define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24 -#define OCELOT_IF_SI_OWNER_MASK GENMASK(5, 4) #define OCELOT_IF_SI_OWNER_OFFSET 4 +#define JAGUAR2_IF_SI_OWNER_OFFSET 6 +#define MSCC_IF_SI_OWNER_MASK GENMASK(1, 0) #define MSCC_IF_SI_OWNER_SISL 0 #define MSCC_IF_SI_OWNER_SIBM 1 #define MSCC_IF_SI_OWNER_SIMC 2 @@ -76,7 +77,8 @@ static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable) } static int dw_spi_mscc_init(struct platform_device *pdev, - struct dw_spi_mmio *dwsmmio) + struct dw_spi_mmio *dwsmmio, + const char *cpu_syscon, u32 if_si_owner_offset) { struct dw_spi_mscc *dwsmscc; struct resource *res; @@ -92,7 +94,7 @@ static int dw_spi_mscc_init(struct platform_device *pdev, return PTR_ERR(dwsmscc->spi_mst); } - dwsmscc->syscon = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon"); + dwsmscc->syscon = syscon_regmap_lookup_by_compatible(cpu_syscon); if (IS_ERR(dwsmscc->syscon)) return PTR_ERR(dwsmscc->syscon); @@ -101,8 +103,8 @@ static int dw_spi_mscc_init(struct platform_device *pdev, /* Select the owner of the SI interface */ regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL, - OCELOT_IF_SI_OWNER_MASK, - MSCC_IF_SI_OWNER_SIMC << OCELOT_IF_SI_OWNER_OFFSET); + MSCC_IF_SI_OWNER_MASK << if_si_owner_offset, + MSCC_IF_SI_OWNER_SIMC << if_si_owner_offset); dwsmmio->dws.set_cs = dw_spi_mscc_set_cs; dwsmmio->priv = dwsmscc; @@ -110,6 +112,28 @@ static int dw_spi_mscc_init(struct platform_device *pdev, return 0; } +static int dw_spi_mscc_ocelot_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) +{ + return dw_spi_mscc_init(pdev, dwsmmio, "mscc,ocelot-cpu-syscon", + OCELOT_IF_SI_OWNER_OFFSET); +} + +static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) +{ + return dw_spi_mscc_init(pdev, dwsmmio, "mscc,jaguar2-cpu-syscon", + JAGUAR2_IF_SI_OWNER_OFFSET); +} + +static int dw_spi_alpine_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) +{ + dwsmmio->dws.cs_override = 1; + + return 0; +} + static int dw_spi_mmio_probe(struct platform_device *pdev) { int (*init_func)(struct platform_device *pdev, @@ -212,7 +236,9 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) static const struct of_device_id dw_spi_mmio_of_match[] = { { .compatible = "snps,dw-apb-ssi", }, - { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_init}, + { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init}, + { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init}, + { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init}, { /* end of table */} }; MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index ac2eb89ef7a5..b705f2bdb8b9 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -144,6 +144,8 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) if (!enable) dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select)); + else if (dws->cs_override) + dw_writel(dws, DW_SPI_SER, 0); } EXPORT_SYMBOL_GPL(dw_spi_set_cs); @@ -308,15 +310,10 @@ static int dw_spi_transfer_one(struct spi_controller *master, dws->current_freq = transfer->speed_hz; spi_set_clk(dws, chip->clk_div); } - if (transfer->bits_per_word == 8) { - dws->n_bytes = 1; - dws->dma_width = 1; - } else if (transfer->bits_per_word == 16) { - dws->n_bytes = 2; - dws->dma_width = 2; - } else { - return -EINVAL; - } + + dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); + dws->dma_width = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); + /* Default SPI mode is SCPOL = 0, SCPH = 0 */ cr0 = (transfer->bits_per_word - 1) | (chip->type << SPI_FRF_OFFSET) @@ -468,6 +465,10 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws) dws->fifo_len = (fifo == 1) ? 0 : fifo; dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len); } + + /* enable HW fixup for explicit CS deselect for Amazon's alpine chip */ + if (dws->cs_override) + dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF); } int dw_spi_add_host(struct device *dev, struct dw_spi *dws) @@ -496,7 +497,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) } master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; - master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; master->setup = dw_spi_setup; @@ -572,13 +573,8 @@ EXPORT_SYMBOL_GPL(dw_spi_suspend_host); int dw_spi_resume_host(struct dw_spi *dws) { - int ret; - spi_hw_init(&dws->master->dev, dws); - ret = spi_controller_resume(dws->master); - if (ret) - dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); - return ret; + return spi_controller_resume(dws->master); } EXPORT_SYMBOL_GPL(dw_spi_resume_host); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 0168b08364d5..c9c15881e982 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -32,6 +32,7 @@ #define DW_SPI_IDR 0x58 #define DW_SPI_VERSION 0x5c #define DW_SPI_DR 0x60 +#define DW_SPI_CS_OVERRIDE 0xf4 /* Bit fields in CTRLR0 */ #define SPI_DFS_OFFSET 0 @@ -109,6 +110,7 @@ struct dw_spi { u32 fifo_len; /* depth of the FIFO buffer */ u32 max_freq; /* max bus freq supported */ + int cs_override; u32 reg_io_width; /* DR I/O width in bytes */ u16 bus_num; u16 num_cs; /* supported slave numbers */ diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index f1526757aaf6..79fc3940245a 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -246,6 +246,19 @@ static int ep93xx_spi_read_write(struct spi_master *master) return -EINPROGRESS; } +static enum dma_transfer_direction +ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir) +{ + switch (dir) { + case DMA_TO_DEVICE: + return DMA_MEM_TO_DEV; + case DMA_FROM_DEVICE: + return DMA_DEV_TO_MEM; + default: + return DMA_TRANS_NONE; + } +} + /** * ep93xx_spi_dma_prepare() - prepares a DMA transfer * @master: SPI master @@ -257,7 +270,7 @@ static int ep93xx_spi_read_write(struct spi_master *master) */ static struct dma_async_tx_descriptor * ep93xx_spi_dma_prepare(struct spi_master *master, - enum dma_transfer_direction dir) + enum dma_data_direction dir) { struct ep93xx_spi *espi = spi_master_get_devdata(master); struct spi_transfer *xfer = master->cur_msg->state; @@ -277,9 +290,9 @@ ep93xx_spi_dma_prepare(struct spi_master *master, buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; memset(&conf, 0, sizeof(conf)); - conf.direction = dir; + conf.direction = ep93xx_dma_data_to_trans_dir(dir); - if (dir == DMA_DEV_TO_MEM) { + if (dir == DMA_FROM_DEVICE) { chan = espi->dma_rx; buf = xfer->rx_buf; sgt = &espi->rx_sgt; @@ -343,7 +356,8 @@ ep93xx_spi_dma_prepare(struct spi_master *master, if (!nents) return ERR_PTR(-ENOMEM); - txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir, DMA_CTRL_ACK); + txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, conf.direction, + DMA_CTRL_ACK); if (!txd) { dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir); return ERR_PTR(-ENOMEM); @@ -360,13 +374,13 @@ ep93xx_spi_dma_prepare(struct spi_master *master, * unmapped. */ static void ep93xx_spi_dma_finish(struct spi_master *master, - enum dma_transfer_direction dir) + enum dma_data_direction dir) { struct ep93xx_spi *espi = spi_master_get_devdata(master); struct dma_chan *chan; struct sg_table *sgt; - if (dir == DMA_DEV_TO_MEM) { + if (dir == DMA_FROM_DEVICE) { chan = espi->dma_rx; sgt = &espi->rx_sgt; } else { @@ -381,8 +395,8 @@ static void ep93xx_spi_dma_callback(void *callback_param) { struct spi_master *master = callback_param; - ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV); - ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); + ep93xx_spi_dma_finish(master, DMA_TO_DEVICE); + ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE); spi_finalize_current_transfer(master); } @@ -392,15 +406,15 @@ static int ep93xx_spi_dma_transfer(struct spi_master *master) struct ep93xx_spi *espi = spi_master_get_devdata(master); struct dma_async_tx_descriptor *rxd, *txd; - rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM); + rxd = ep93xx_spi_dma_prepare(master, DMA_FROM_DEVICE); if (IS_ERR(rxd)) { dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); return PTR_ERR(rxd); } - txd = ep93xx_spi_dma_prepare(master, DMA_MEM_TO_DEV); + txd = ep93xx_spi_dma_prepare(master, DMA_TO_DEVICE); if (IS_ERR(txd)) { - ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); + ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE); dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); return PTR_ERR(txd); } diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 1e8ff6256079..cf2118dc91f4 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -798,10 +798,8 @@ static int of_fsl_espi_suspend(struct device *dev) int ret; ret = spi_master_suspend(master); - if (ret) { - dev_warn(dev, "cannot suspend master\n"); + if (ret) return ret; - } return pm_runtime_force_suspend(dev); } diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index e6d5cc6ab108..51670976faa3 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -276,7 +276,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi) fsl_lpspi_set_watermark(fsl_lpspi); - temp = CFGR1_PCSCFG | CFGR1_MASTER | CFGR1_NOSTALL; + temp = CFGR1_PCSCFG | CFGR1_MASTER; if (fsl_lpspi->config.mode & SPI_CS_HIGH) temp |= CFGR1_PCSPOL; writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1); diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c new file mode 100644 index 000000000000..6432ecc4e2ca --- /dev/null +++ b/drivers/spi/spi-geni-qcom.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/log2.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/qcom-geni-se.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> + +/* SPI SE specific registers and respective register fields */ +#define SE_SPI_CPHA 0x224 +#define CPHA BIT(0) + +#define SE_SPI_LOOPBACK 0x22c +#define LOOPBACK_ENABLE 0x1 +#define NORMAL_MODE 0x0 +#define LOOPBACK_MSK GENMASK(1, 0) + +#define SE_SPI_CPOL 0x230 +#define CPOL BIT(2) + +#define SE_SPI_DEMUX_OUTPUT_INV 0x24c +#define CS_DEMUX_OUTPUT_INV_MSK GENMASK(3, 0) + +#define SE_SPI_DEMUX_SEL 0x250 +#define CS_DEMUX_OUTPUT_SEL GENMASK(3, 0) + +#define SE_SPI_TRANS_CFG 0x25c +#define CS_TOGGLE BIT(0) + +#define SE_SPI_WORD_LEN 0x268 +#define WORD_LEN_MSK GENMASK(9, 0) +#define MIN_WORD_LEN 4 + +#define SE_SPI_TX_TRANS_LEN 0x26c +#define SE_SPI_RX_TRANS_LEN 0x270 +#define TRANS_LEN_MSK GENMASK(23, 0) + +#define SE_SPI_PRE_POST_CMD_DLY 0x274 + +#define SE_SPI_DELAY_COUNTERS 0x278 +#define SPI_INTER_WORDS_DELAY_MSK GENMASK(9, 0) +#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10) +#define SPI_CS_CLK_DELAY_SHFT 10 + +/* M_CMD OP codes for SPI */ +#define SPI_TX_ONLY 1 +#define SPI_RX_ONLY 2 +#define SPI_FULL_DUPLEX 3 +#define SPI_TX_RX 7 +#define SPI_CS_ASSERT 8 +#define SPI_CS_DEASSERT 9 +#define SPI_SCK_ONLY 10 +/* M_CMD params for SPI */ +#define SPI_PRE_CMD_DELAY BIT(0) +#define TIMESTAMP_BEFORE BIT(1) +#define FRAGMENTATION BIT(2) +#define TIMESTAMP_AFTER BIT(3) +#define POST_CMD_DELAY BIT(4) + +/* SPI M_COMMAND OPCODE */ +enum spi_mcmd_code { + CMD_NONE, + CMD_XFER, + CMD_CS, + CMD_CANCEL, +}; + + +struct spi_geni_master { + struct geni_se se; + struct device *dev; + u32 tx_fifo_depth; + u32 fifo_width_bits; + u32 tx_wm; + unsigned long cur_speed_hz; + unsigned int cur_bits_per_word; + unsigned int tx_rem_bytes; + unsigned int rx_rem_bytes; + const struct spi_transfer *cur_xfer; + struct completion xfer_done; + unsigned int oversampling; + spinlock_t lock; + unsigned int cur_mcmd; + int irq; +}; + +static void handle_fifo_timeout(struct spi_master *spi, + struct spi_message *msg); + +static int get_spi_clk_cfg(unsigned int speed_hz, + struct spi_geni_master *mas, + unsigned int *clk_idx, + unsigned int *clk_div) +{ + unsigned long sclk_freq; + unsigned int actual_hz; + struct geni_se *se = &mas->se; + int ret; + + ret = geni_se_clk_freq_match(&mas->se, + speed_hz * mas->oversampling, + clk_idx, &sclk_freq, false); + if (ret) { + dev_err(mas->dev, "Failed(%d) to find src clk for %dHz\n", + ret, speed_hz); + return ret; + } + + *clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz); + actual_hz = sclk_freq / (mas->oversampling * *clk_div); + + dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz, + actual_hz, sclk_freq, *clk_idx, *clk_div); + ret = clk_set_rate(se->clk, sclk_freq); + if (ret) + dev_err(mas->dev, "clk_set_rate failed %d\n", ret); + return ret; +} + +static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) +{ + struct spi_geni_master *mas = spi_master_get_devdata(slv->master); + struct spi_master *spi = dev_get_drvdata(mas->dev); + struct geni_se *se = &mas->se; + unsigned long timeout; + + reinit_completion(&mas->xfer_done); + pm_runtime_get_sync(mas->dev); + if (!(slv->mode & SPI_CS_HIGH)) + set_flag = !set_flag; + + mas->cur_mcmd = CMD_CS; + if (set_flag) + geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); + else + geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); + + timeout = wait_for_completion_timeout(&mas->xfer_done, HZ); + if (!timeout) + handle_fifo_timeout(spi, NULL); + + pm_runtime_put(mas->dev); +} + +static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, + unsigned int bits_per_word) +{ + unsigned int pack_words; + bool msb_first = (mode & SPI_LSB_FIRST) ? false : true; + struct geni_se *se = &mas->se; + u32 word_len; + + word_len = readl(se->base + SE_SPI_WORD_LEN); + + /* + * If bits_per_word isn't a byte aligned value, set the packing to be + * 1 SPI word per FIFO word. + */ + if (!(mas->fifo_width_bits % bits_per_word)) + pack_words = mas->fifo_width_bits / bits_per_word; + else + pack_words = 1; + word_len &= ~WORD_LEN_MSK; + word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK); + geni_se_config_packing(&mas->se, bits_per_word, pack_words, msb_first, + true, true); + writel(word_len, se->base + SE_SPI_WORD_LEN); +} + +static int setup_fifo_params(struct spi_device *spi_slv, + struct spi_master *spi) +{ + struct spi_geni_master *mas = spi_master_get_devdata(spi); + struct geni_se *se = &mas->se; + u32 loopback_cfg, cpol, cpha, demux_output_inv; + u32 demux_sel, clk_sel, m_clk_cfg, idx, div; + int ret; + + loopback_cfg = readl(se->base + SE_SPI_LOOPBACK); + cpol = readl(se->base + SE_SPI_CPOL); + cpha = readl(se->base + SE_SPI_CPHA); + demux_output_inv = 0; + loopback_cfg &= ~LOOPBACK_MSK; + cpol &= ~CPOL; + cpha &= ~CPHA; + + if (spi_slv->mode & SPI_LOOP) + loopback_cfg |= LOOPBACK_ENABLE; + + if (spi_slv->mode & SPI_CPOL) + cpol |= CPOL; + + if (spi_slv->mode & SPI_CPHA) + cpha |= CPHA; + + if (spi_slv->mode & SPI_CS_HIGH) + demux_output_inv = BIT(spi_slv->chip_select); + + demux_sel = spi_slv->chip_select; + mas->cur_speed_hz = spi_slv->max_speed_hz; + mas->cur_bits_per_word = spi_slv->bits_per_word; + + ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div); + if (ret) { + dev_err(mas->dev, "Err setting clks ret(%d) for %ld\n", + ret, mas->cur_speed_hz); + return ret; + } + + clk_sel = idx & CLK_SEL_MSK; + m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; + spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word); + writel(loopback_cfg, se->base + SE_SPI_LOOPBACK); + writel(demux_sel, se->base + SE_SPI_DEMUX_SEL); + writel(cpha, se->base + SE_SPI_CPHA); + writel(cpol, se->base + SE_SPI_CPOL); + writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV); + writel(clk_sel, se->base + SE_GENI_CLK_SEL); + writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); + return 0; +} + +static int spi_geni_prepare_message(struct spi_master *spi, + struct spi_message *spi_msg) +{ + int ret; + struct spi_geni_master *mas = spi_master_get_devdata(spi); + struct geni_se *se = &mas->se; + + geni_se_select_mode(se, GENI_SE_FIFO); + reinit_completion(&mas->xfer_done); + ret = setup_fifo_params(spi_msg->spi, spi); + if (ret) + dev_err(mas->dev, "Couldn't select mode %d\n", ret); + return ret; +} + +static int spi_geni_init(struct spi_geni_master *mas) +{ + struct geni_se *se = &mas->se; + unsigned int proto, major, minor, ver; + + pm_runtime_get_sync(mas->dev); + + proto = geni_se_read_proto(se); + if (proto != GENI_SE_SPI) { + dev_err(mas->dev, "Invalid proto %d\n", proto); + pm_runtime_put(mas->dev); + return -ENXIO; + } + mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se); + + /* Width of Tx and Rx FIFO is same */ + mas->fifo_width_bits = geni_se_get_tx_fifo_width(se); + + /* + * Hardware programming guide suggests to configure + * RX FIFO RFR level to fifo_depth-2. + */ + geni_se_init(se, 0x0, mas->tx_fifo_depth - 2); + /* Transmit an entire FIFO worth of data per IRQ */ + mas->tx_wm = 1; + ver = geni_se_get_qup_hw_version(se); + major = GENI_SE_VERSION_MAJOR(ver); + minor = GENI_SE_VERSION_MINOR(ver); + + if (major == 1 && minor == 0) + mas->oversampling = 2; + else + mas->oversampling = 1; + + pm_runtime_put(mas->dev); + return 0; +} + +static void setup_fifo_xfer(struct spi_transfer *xfer, + struct spi_geni_master *mas, + u16 mode, struct spi_master *spi) +{ + u32 m_cmd = 0; + u32 spi_tx_cfg, len; + struct geni_se *se = &mas->se; + + spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); + if (xfer->bits_per_word != mas->cur_bits_per_word) { + spi_setup_word_len(mas, mode, xfer->bits_per_word); + mas->cur_bits_per_word = xfer->bits_per_word; + } + + /* Speed and bits per word can be overridden per transfer */ + if (xfer->speed_hz != mas->cur_speed_hz) { + int ret; + u32 clk_sel, m_clk_cfg; + unsigned int idx, div; + + ret = get_spi_clk_cfg(xfer->speed_hz, mas, &idx, &div); + if (ret) { + dev_err(mas->dev, "Err setting clks:%d\n", ret); + return; + } + /* + * SPI core clock gets configured with the requested frequency + * or the frequency closer to the requested frequency. + * For that reason requested frequency is stored in the + * cur_speed_hz and referred in the consecutive transfer instead + * of calling clk_get_rate() API. + */ + mas->cur_speed_hz = xfer->speed_hz; + clk_sel = idx & CLK_SEL_MSK; + m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; + writel(clk_sel, se->base + SE_GENI_CLK_SEL); + writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); + } + + mas->tx_rem_bytes = 0; + mas->rx_rem_bytes = 0; + if (xfer->tx_buf && xfer->rx_buf) + m_cmd = SPI_FULL_DUPLEX; + else if (xfer->tx_buf) + m_cmd = SPI_TX_ONLY; + else if (xfer->rx_buf) + m_cmd = SPI_RX_ONLY; + + spi_tx_cfg &= ~CS_TOGGLE; + + if (!(mas->cur_bits_per_word % MIN_WORD_LEN)) + len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word; + else + len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1); + len &= TRANS_LEN_MSK; + + mas->cur_xfer = xfer; + if (m_cmd & SPI_TX_ONLY) { + mas->tx_rem_bytes = xfer->len; + writel(len, se->base + SE_SPI_TX_TRANS_LEN); + } + + if (m_cmd & SPI_RX_ONLY) { + writel(len, se->base + SE_SPI_RX_TRANS_LEN); + mas->rx_rem_bytes = xfer->len; + } + writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); + mas->cur_mcmd = CMD_XFER; + geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); + + /* + * TX_WATERMARK_REG should be set after SPI configuration and + * setting up GENI SE engine, as driver starts data transfer + * for the watermark interrupt. + */ + if (m_cmd & SPI_TX_ONLY) + writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); +} + +static void handle_fifo_timeout(struct spi_master *spi, + struct spi_message *msg) +{ + struct spi_geni_master *mas = spi_master_get_devdata(spi); + unsigned long time_left, flags; + struct geni_se *se = &mas->se; + + spin_lock_irqsave(&mas->lock, flags); + reinit_completion(&mas->xfer_done); + mas->cur_mcmd = CMD_CANCEL; + geni_se_cancel_m_cmd(se); + writel(0, se->base + SE_GENI_TX_WATERMARK_REG); + spin_unlock_irqrestore(&mas->lock, flags); + time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + if (time_left) + return; + + spin_lock_irqsave(&mas->lock, flags); + reinit_completion(&mas->xfer_done); + geni_se_abort_m_cmd(se); + spin_unlock_irqrestore(&mas->lock, flags); + time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + if (!time_left) + dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); +} + +static int spi_geni_transfer_one(struct spi_master *spi, + struct spi_device *slv, + struct spi_transfer *xfer) +{ + struct spi_geni_master *mas = spi_master_get_devdata(spi); + + /* Terminate and return success for 0 byte length transfer */ + if (!xfer->len) + return 0; + + setup_fifo_xfer(xfer, mas, slv->mode, spi); + return 1; +} + +static unsigned int geni_byte_per_fifo_word(struct spi_geni_master *mas) +{ + /* + * Calculate how many bytes we'll put in each FIFO word. If the + * transfer words don't pack cleanly into a FIFO word we'll just put + * one transfer word in each FIFO word. If they do pack we'll pack 'em. + */ + if (mas->fifo_width_bits % mas->cur_bits_per_word) + return roundup_pow_of_two(DIV_ROUND_UP(mas->cur_bits_per_word, + BITS_PER_BYTE)); + + return mas->fifo_width_bits / BITS_PER_BYTE; +} + +static void geni_spi_handle_tx(struct spi_geni_master *mas) +{ + struct geni_se *se = &mas->se; + unsigned int max_bytes; + const u8 *tx_buf; + unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); + unsigned int i = 0; + + max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word; + if (mas->tx_rem_bytes < max_bytes) + max_bytes = mas->tx_rem_bytes; + + tx_buf = mas->cur_xfer->tx_buf + mas->cur_xfer->len - mas->tx_rem_bytes; + while (i < max_bytes) { + unsigned int j; + unsigned int bytes_to_write; + u32 fifo_word = 0; + u8 *fifo_byte = (u8 *)&fifo_word; + + bytes_to_write = min(bytes_per_fifo_word, max_bytes - i); + for (j = 0; j < bytes_to_write; j++) + fifo_byte[j] = tx_buf[i++]; + iowrite32_rep(se->base + SE_GENI_TX_FIFOn, &fifo_word, 1); + } + mas->tx_rem_bytes -= max_bytes; + if (!mas->tx_rem_bytes) + writel(0, se->base + SE_GENI_TX_WATERMARK_REG); +} + +static void geni_spi_handle_rx(struct spi_geni_master *mas) +{ + struct geni_se *se = &mas->se; + u32 rx_fifo_status; + unsigned int rx_bytes; + unsigned int rx_last_byte_valid; + u8 *rx_buf; + unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); + unsigned int i = 0; + + rx_fifo_status = readl(se->base + SE_GENI_RX_FIFO_STATUS); + rx_bytes = (rx_fifo_status & RX_FIFO_WC_MSK) * bytes_per_fifo_word; + if (rx_fifo_status & RX_LAST) { + rx_last_byte_valid = rx_fifo_status & RX_LAST_BYTE_VALID_MSK; + rx_last_byte_valid >>= RX_LAST_BYTE_VALID_SHFT; + if (rx_last_byte_valid && rx_last_byte_valid < 4) + rx_bytes -= bytes_per_fifo_word - rx_last_byte_valid; + } + if (mas->rx_rem_bytes < rx_bytes) + rx_bytes = mas->rx_rem_bytes; + + rx_buf = mas->cur_xfer->rx_buf + mas->cur_xfer->len - mas->rx_rem_bytes; + while (i < rx_bytes) { + u32 fifo_word = 0; + u8 *fifo_byte = (u8 *)&fifo_word; + unsigned int bytes_to_read; + unsigned int j; + + bytes_to_read = min(bytes_per_fifo_word, rx_bytes - i); + ioread32_rep(se->base + SE_GENI_RX_FIFOn, &fifo_word, 1); + for (j = 0; j < bytes_to_read; j++) + rx_buf[i++] = fifo_byte[j]; + } + mas->rx_rem_bytes -= rx_bytes; +} + +static irqreturn_t geni_spi_isr(int irq, void *data) +{ + struct spi_master *spi = data; + struct spi_geni_master *mas = spi_master_get_devdata(spi); + struct geni_se *se = &mas->se; + u32 m_irq; + unsigned long flags; + irqreturn_t ret = IRQ_HANDLED; + + if (mas->cur_mcmd == CMD_NONE) + return IRQ_NONE; + + spin_lock_irqsave(&mas->lock, flags); + m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); + + if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) + geni_spi_handle_rx(mas); + + if (m_irq & M_TX_FIFO_WATERMARK_EN) + geni_spi_handle_tx(mas); + + if (m_irq & M_CMD_DONE_EN) { + if (mas->cur_mcmd == CMD_XFER) + spi_finalize_current_transfer(spi); + else if (mas->cur_mcmd == CMD_CS) + complete(&mas->xfer_done); + mas->cur_mcmd = CMD_NONE; + /* + * If this happens, then a CMD_DONE came before all the Tx + * buffer bytes were sent out. This is unusual, log this + * condition and disable the WM interrupt to prevent the + * system from stalling due an interrupt storm. + * If this happens when all Rx bytes haven't been received, log + * the condition. + * The only known time this can happen is if bits_per_word != 8 + * and some registers that expect xfer lengths in num spi_words + * weren't written correctly. + */ + if (mas->tx_rem_bytes) { + writel(0, se->base + SE_GENI_TX_WATERMARK_REG); + dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", + mas->tx_rem_bytes, mas->cur_bits_per_word); + } + if (mas->rx_rem_bytes) + dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", + mas->rx_rem_bytes, mas->cur_bits_per_word); + } + + if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) { + mas->cur_mcmd = CMD_NONE; + complete(&mas->xfer_done); + } + + writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); + spin_unlock_irqrestore(&mas->lock, flags); + return ret; +} + +static int spi_geni_probe(struct platform_device *pdev) +{ + int ret; + struct spi_master *spi; + struct spi_geni_master *mas; + struct resource *res; + struct geni_se *se; + + spi = spi_alloc_master(&pdev->dev, sizeof(*mas)); + if (!spi) + return -ENOMEM; + + platform_set_drvdata(pdev, spi); + mas = spi_master_get_devdata(spi); + mas->dev = &pdev->dev; + mas->se.dev = &pdev->dev; + mas->se.wrapper = dev_get_drvdata(pdev->dev.parent); + se = &mas->se; + + spi->bus_num = -1; + spi->dev.of_node = pdev->dev.of_node; + mas->se.clk = devm_clk_get(&pdev->dev, "se"); + if (IS_ERR(mas->se.clk)) { + ret = PTR_ERR(mas->se.clk); + dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); + goto spi_geni_probe_err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + se->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(se->base)) { + ret = PTR_ERR(se->base); + goto spi_geni_probe_err; + } + + spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; + spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + spi->num_chipselect = 4; + spi->max_speed_hz = 50000000; + spi->prepare_message = spi_geni_prepare_message; + spi->transfer_one = spi_geni_transfer_one; + spi->auto_runtime_pm = true; + spi->handle_err = handle_fifo_timeout; + spi->set_cs = spi_geni_set_cs; + + init_completion(&mas->xfer_done); + spin_lock_init(&mas->lock); + pm_runtime_enable(&pdev->dev); + + ret = spi_geni_init(mas); + if (ret) + goto spi_geni_probe_runtime_disable; + + mas->irq = platform_get_irq(pdev, 0); + if (mas->irq < 0) { + ret = mas->irq; + dev_err(&pdev->dev, "Err getting IRQ %d\n", ret); + goto spi_geni_probe_runtime_disable; + } + + ret = request_irq(mas->irq, geni_spi_isr, + IRQF_TRIGGER_HIGH, "spi_geni", spi); + if (ret) + goto spi_geni_probe_runtime_disable; + + ret = spi_register_master(spi); + if (ret) + goto spi_geni_probe_free_irq; + + return 0; +spi_geni_probe_free_irq: + free_irq(mas->irq, spi); +spi_geni_probe_runtime_disable: + pm_runtime_disable(&pdev->dev); +spi_geni_probe_err: + spi_master_put(spi); + return ret; +} + +static int spi_geni_remove(struct platform_device *pdev) +{ + struct spi_master *spi = platform_get_drvdata(pdev); + struct spi_geni_master *mas = spi_master_get_devdata(spi); + + /* Unregister _before_ disabling pm_runtime() so we stop transfers */ + spi_unregister_master(spi); + + free_irq(mas->irq, spi); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int __maybe_unused spi_geni_runtime_suspend(struct device *dev) +{ + struct spi_master *spi = dev_get_drvdata(dev); + struct spi_geni_master *mas = spi_master_get_devdata(spi); + + return geni_se_resources_off(&mas->se); +} + +static int __maybe_unused spi_geni_runtime_resume(struct device *dev) +{ + struct spi_master *spi = dev_get_drvdata(dev); + struct spi_geni_master *mas = spi_master_get_devdata(spi); + + return geni_se_resources_on(&mas->se); +} + +static int __maybe_unused spi_geni_suspend(struct device *dev) +{ + struct spi_master *spi = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(spi); + if (ret) + return ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + spi_master_resume(spi); + + return ret; +} + +static int __maybe_unused spi_geni_resume(struct device *dev) +{ + struct spi_master *spi = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + ret = spi_master_resume(spi); + if (ret) + pm_runtime_force_suspend(dev); + + return ret; +} + +static const struct dev_pm_ops spi_geni_pm_ops = { + SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend, + spi_geni_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(spi_geni_suspend, spi_geni_resume) +}; + +static const struct of_device_id spi_geni_dt_match[] = { + { .compatible = "qcom,geni-spi" }, + {} +}; +MODULE_DEVICE_TABLE(of, spi_geni_dt_match); + +static struct platform_driver spi_geni_driver = { + .probe = spi_geni_probe, + .remove = spi_geni_remove, + .driver = { + .name = "geni_spi", + .pm = &spi_geni_pm_ops, + .of_match_table = spi_geni_dt_match, + }, +}; +module_platform_driver(spi_geni_driver); + +MODULE_DESCRIPTION("SPI driver for GENI based QUP cores"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 421bfc7dda67..45973ee3ae11 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -295,9 +295,11 @@ static int spi_gpio_request(struct device *dev, spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN); if (IS_ERR(spi_gpio->miso)) return PTR_ERR(spi_gpio->miso); - if (!spi_gpio->miso) - /* HW configuration without MISO pin */ - *mflags |= SPI_MASTER_NO_RX; + /* + * No setting SPI_MASTER_NO_RX here - if there is only a MOSI + * pin connected the host can still do RX by changing the + * direction of the line. + */ spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); if (IS_ERR(spi_gpio->sck)) @@ -423,7 +425,7 @@ static int spi_gpio_probe(struct platform_device *pdev) spi_gpio->bitbang.chipselect = spi_gpio_chipselect; spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction; - if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) { + if ((master_flags & SPI_MASTER_NO_TX) == 0) { spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0; spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1; spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; @@ -447,10 +449,8 @@ static int spi_gpio_probe(struct platform_device *pdev) static int spi_gpio_remove(struct platform_device *pdev) { struct spi_gpio *spi_gpio; - struct spi_gpio_platform_data *pdata; spi_gpio = platform_get_drvdata(pdev); - pdata = dev_get_platdata(&pdev->dev); /* stop() unregisters child devices too */ spi_bitbang_stop(&spi_gpio->bitbang); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 08dd3a31a3e5..dd1ce12aa386 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -63,6 +63,7 @@ struct spi_imx_devtype_data { void (*trigger)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *); + void (*setup_wml)(struct spi_imx_data *); void (*disable)(struct spi_imx_data *); bool has_dmamode; bool has_slavemode; @@ -216,7 +217,6 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - unsigned int bytes_per_word, i; if (!master->dma_rx) return false; @@ -224,14 +224,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, if (spi_imx->slave_mode) return false; - bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); - - for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) { - if (!(transfer->len % (i * bytes_per_word))) - break; - } + if (transfer->len < spi_imx->devtype_data->fifo_size) + return false; - spi_imx->wml = i; spi_imx->dynamic_burst = 0; return true; @@ -583,18 +578,21 @@ static int mx51_ecspi_config(struct spi_device *spi) else /* SCLK is _very_ slow */ usleep_range(delay, delay + 10); + return 0; +} + +static void mx51_setup_wml(struct spi_imx_data *spi_imx) +{ /* * Configure the DMA register: setup the watermark * and enable DMA request. */ - writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml) | + writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) | MX51_ECSPI_DMA_TX_WML(spi_imx->wml) | MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) | MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN | MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA); - - return 0; } static int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx) @@ -931,6 +929,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .trigger = mx51_ecspi_trigger, .rx_available = mx51_ecspi_rx_available, .reset = mx51_ecspi_reset, + .setup_wml = mx51_setup_wml, .fifo_size = 64, .has_dmamode = true, .dynamic_burst = true, @@ -1138,7 +1137,6 @@ static int spi_imx_setupxfer(struct spi_device *spi, struct spi_transfer *t) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); - int ret; if (!t) return 0; @@ -1179,12 +1177,6 @@ static int spi_imx_setupxfer(struct spi_device *spi, else spi_imx->usedma = 0; - if (spi_imx->usedma) { - ret = spi_imx_dma_configure(spi->master); - if (ret) - return ret; - } - if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) { spi_imx->rx = mx53_ecspi_rx_slave; spi_imx->tx = mx53_ecspi_tx_slave; @@ -1289,6 +1281,31 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, unsigned long timeout; struct spi_master *master = spi_imx->bitbang.master; struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; + struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents); + unsigned int bytes_per_word, i; + int ret; + + /* Get the right burst length from the last sg to ensure no tail data */ + bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); + for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) { + if (!(sg_dma_len(last_sg) % (i * bytes_per_word))) + break; + } + /* Use 1 as wml in case no available burst length got */ + if (i == 0) + i = 1; + + spi_imx->wml = i; + + ret = spi_imx_dma_configure(master); + if (ret) + return ret; + + if (!spi_imx->devtype_data->setup_wml) { + dev_err(spi_imx->dev, "No setup_wml()?\n"); + return -EINVAL; + } + spi_imx->devtype_data->setup_wml(spi_imx); /* * The TX DMA setup starts the transfer, so make sure RX is configured diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index e43842c7a31a..62a7b80801d2 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -12,6 +12,8 @@ #include "internals.h" +#define SPI_MEM_MAX_BUSWIDTH 4 + /** * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a * memory operation @@ -149,6 +151,44 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem, } EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); +static bool spi_mem_buswidth_is_valid(u8 buswidth) +{ + if (hweight8(buswidth) > 1 || buswidth > SPI_MEM_MAX_BUSWIDTH) + return false; + + return true; +} + +static int spi_mem_check_op(const struct spi_mem_op *op) +{ + if (!op->cmd.buswidth) + return -EINVAL; + + if ((op->addr.nbytes && !op->addr.buswidth) || + (op->dummy.nbytes && !op->dummy.buswidth) || + (op->data.nbytes && !op->data.buswidth)) + return -EINVAL; + + if (!spi_mem_buswidth_is_valid(op->cmd.buswidth) || + !spi_mem_buswidth_is_valid(op->addr.buswidth) || + !spi_mem_buswidth_is_valid(op->dummy.buswidth) || + !spi_mem_buswidth_is_valid(op->data.buswidth)) + return -EINVAL; + + return 0; +} + +static bool spi_mem_internal_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct spi_controller *ctlr = mem->spi->controller; + + if (ctlr->mem_ops && ctlr->mem_ops->supports_op) + return ctlr->mem_ops->supports_op(mem, op); + + return spi_mem_default_supports_op(mem, op); +} + /** * spi_mem_supports_op() - Check if a memory device and the controller it is * connected to support a specific memory operation @@ -166,12 +206,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); */ bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { - struct spi_controller *ctlr = mem->spi->controller; - - if (ctlr->mem_ops && ctlr->mem_ops->supports_op) - return ctlr->mem_ops->supports_op(mem, op); + if (spi_mem_check_op(op)) + return false; - return spi_mem_default_supports_op(mem, op); + return spi_mem_internal_supports_op(mem, op); } EXPORT_SYMBOL_GPL(spi_mem_supports_op); @@ -196,7 +234,11 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) u8 *tmpbuf; int ret; - if (!spi_mem_supports_op(mem, op)) + ret = spi_mem_check_op(op); + if (ret) + return ret; + + if (!spi_mem_internal_supports_op(mem, op)) return -ENOTSUPP; if (ctlr->mem_ops) { @@ -346,10 +388,25 @@ EXPORT_SYMBOL_GPL(spi_mem_get_name); int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { struct spi_controller *ctlr = mem->spi->controller; + size_t len; + + len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size) return ctlr->mem_ops->adjust_op_size(mem, op); + if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) { + if (len > spi_max_transfer_size(mem->spi)) + return -EINVAL; + + op->data.nbytes = min3((size_t)op->data.nbytes, + spi_max_transfer_size(mem->spi), + spi_max_message_size(mem->spi) - + len); + if (!op->data.nbytes) + return -EINVAL; + } + return 0; } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 86bf45667a04..3dc31627c655 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -98,6 +98,7 @@ struct mtk_spi { struct clk *parent_clk, *sel_clk, *spi_clk; struct spi_transfer *cur_transfer; u32 xfer_len; + u32 num_xfered; struct scatterlist *tx_sgl, *rx_sgl; u32 tx_sgl_len, rx_sgl_len; const struct mtk_spi_compatible *dev_comp; @@ -385,6 +386,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, mdata->cur_transfer = xfer; mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len); + mdata->num_xfered = 0; mtk_spi_prepare_transfer(master, xfer); mtk_spi_setup_packet(master); @@ -415,6 +417,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master, mdata->tx_sgl_len = 0; mdata->rx_sgl_len = 0; mdata->cur_transfer = xfer; + mdata->num_xfered = 0; mtk_spi_prepare_transfer(master, xfer); @@ -482,7 +485,7 @@ static int mtk_spi_setup(struct spi_device *spi) static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) { - u32 cmd, reg_val, cnt, remainder; + u32 cmd, reg_val, cnt, remainder, len; struct spi_master *master = dev_id; struct mtk_spi *mdata = spi_master_get_devdata(master); struct spi_transfer *trans = mdata->cur_transfer; @@ -497,36 +500,38 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) if (trans->rx_buf) { cnt = mdata->xfer_len / 4; ioread32_rep(mdata->base + SPI_RX_DATA_REG, - trans->rx_buf, cnt); + trans->rx_buf + mdata->num_xfered, cnt); remainder = mdata->xfer_len % 4; if (remainder > 0) { reg_val = readl(mdata->base + SPI_RX_DATA_REG); - memcpy(trans->rx_buf + (cnt * 4), - ®_val, remainder); + memcpy(trans->rx_buf + + mdata->num_xfered + + (cnt * 4), + ®_val, + remainder); } } - trans->len -= mdata->xfer_len; - if (!trans->len) { + mdata->num_xfered += mdata->xfer_len; + if (mdata->num_xfered == trans->len) { spi_finalize_current_transfer(master); return IRQ_HANDLED; } - if (trans->tx_buf) - trans->tx_buf += mdata->xfer_len; - if (trans->rx_buf) - trans->rx_buf += mdata->xfer_len; - - mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, trans->len); + len = trans->len - mdata->num_xfered; + mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len); mtk_spi_setup_packet(master); - cnt = trans->len / 4; - iowrite32_rep(mdata->base + SPI_TX_DATA_REG, trans->tx_buf, cnt); + cnt = len / 4; + iowrite32_rep(mdata->base + SPI_TX_DATA_REG, + trans->tx_buf + mdata->num_xfered, cnt); - remainder = trans->len % 4; + remainder = len % 4; if (remainder > 0) { reg_val = 0; - memcpy(®_val, trans->tx_buf + (cnt * 4), remainder); + memcpy(®_val, + trans->tx_buf + (cnt * 4) + mdata->num_xfered, + remainder); writel(reg_val, mdata->base + SPI_TX_DATA_REG); } diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 508c61c669e7..f024c3fc3679 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -33,6 +33,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/gcd.h> +#include <linux/iopoll.h> #include <linux/spi/spi.h> #include <linux/gpio.h> @@ -126,6 +127,7 @@ struct omap2_mcspi_regs { }; struct omap2_mcspi { + struct completion txdone; struct spi_master *master; /* Virtual base address of the controller */ void __iomem *base; @@ -135,6 +137,7 @@ struct omap2_mcspi { struct device *dev; struct omap2_mcspi_regs ctx; int fifo_depth; + bool slave_aborted; unsigned int pin_dir:1; }; @@ -274,19 +277,23 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) } } -static void omap2_mcspi_set_master_mode(struct spi_master *master) +static void omap2_mcspi_set_mode(struct spi_master *master) { struct omap2_mcspi *mcspi = spi_master_get_devdata(master); struct omap2_mcspi_regs *ctx = &mcspi->ctx; u32 l; /* - * Setup when switching from (reset default) slave mode - * to single-channel master mode + * Choose master or slave mode */ l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); - l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS); - l |= OMAP2_MCSPI_MODULCTRL_SINGLE; + l &= ~(OMAP2_MCSPI_MODULCTRL_STEST); + if (spi_controller_is_slave(master)) { + l |= (OMAP2_MCSPI_MODULCTRL_MS); + } else { + l &= ~(OMAP2_MCSPI_MODULCTRL_MS); + l |= OMAP2_MCSPI_MODULCTRL_SINGLE; + } mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); ctx->modulctrl = l; @@ -299,7 +306,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi *mcspi; unsigned int wcnt; - int max_fifo_depth, fifo_depth, bytes_per_word; + int max_fifo_depth, bytes_per_word; u32 chconf, xferlevel; mcspi = spi_master_get_devdata(master); @@ -315,10 +322,6 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, else max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; - fifo_depth = gcd(t->len, max_fifo_depth); - if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0) - goto disable_fifo; - wcnt = t->len / bytes_per_word; if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) goto disable_fifo; @@ -326,16 +329,17 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, xferlevel = wcnt << 16; if (t->rx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFER; - xferlevel |= (fifo_depth - 1) << 8; + xferlevel |= (bytes_per_word - 1) << 8; } + if (t->tx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFET; - xferlevel |= fifo_depth - 1; + xferlevel |= bytes_per_word - 1; } mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel); mcspi_write_chconf0(spi, chconf); - mcspi->fifo_depth = fifo_depth; + mcspi->fifo_depth = max_fifo_depth; return; } @@ -353,18 +357,22 @@ disable_fifo: static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) { - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(1000); - while (!(readl_relaxed(reg) & bit)) { - if (time_after(jiffies, timeout)) { - if (!(readl_relaxed(reg) & bit)) - return -ETIMEDOUT; - else - return 0; - } - cpu_relax(); + u32 val; + + return readl_poll_timeout(reg, val, val & bit, 1, MSEC_PER_SEC); +} + +static int mcspi_wait_for_completion(struct omap2_mcspi *mcspi, + struct completion *x) +{ + if (spi_controller_is_slave(mcspi->master)) { + if (wait_for_completion_interruptible(x) || + mcspi->slave_aborted) + return -EINTR; + } else { + wait_for_completion(x); } + return 0; } @@ -517,7 +525,12 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, dma_async_issue_pending(mcspi_dma->dma_rx); omap2_mcspi_set_dma_req(spi, 1, 1); - wait_for_completion(&mcspi_dma->dma_rx_completion); + ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion); + if (ret || mcspi->slave_aborted) { + dmaengine_terminate_sync(mcspi_dma->dma_rx); + omap2_mcspi_set_dma_req(spi, 1, 0); + return 0; + } for (x = 0; x < nb_sizes; x++) kfree(sg_out[x]); @@ -585,7 +598,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) struct dma_slave_config cfg; enum dma_slave_buswidth width; unsigned es; - u32 burst; void __iomem *chstat_reg; void __iomem *irqstat_reg; int wait_res; @@ -605,34 +617,49 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) } count = xfer->len; - burst = 1; - - if (mcspi->fifo_depth > 0) { - if (count > mcspi->fifo_depth) - burst = mcspi->fifo_depth / es; - else - burst = count / es; - } memset(&cfg, 0, sizeof(cfg)); cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.src_addr_width = width; cfg.dst_addr_width = width; - cfg.src_maxburst = burst; - cfg.dst_maxburst = burst; + cfg.src_maxburst = es; + cfg.dst_maxburst = es; rx = xfer->rx_buf; tx = xfer->tx_buf; - if (tx != NULL) + mcspi->slave_aborted = false; + reinit_completion(&mcspi_dma->dma_tx_completion); + reinit_completion(&mcspi_dma->dma_rx_completion); + reinit_completion(&mcspi->txdone); + if (tx) { + /* Enable EOW IRQ to know end of tx in slave mode */ + if (spi_controller_is_slave(spi->master)) + mcspi_write_reg(spi->master, + OMAP2_MCSPI_IRQENABLE, + OMAP2_MCSPI_IRQSTATUS_EOW); omap2_mcspi_tx_dma(spi, xfer, cfg); + } if (rx != NULL) count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); if (tx != NULL) { - wait_for_completion(&mcspi_dma->dma_tx_completion); + int ret; + + ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion); + if (ret || mcspi->slave_aborted) { + dmaengine_terminate_sync(mcspi_dma->dma_tx); + omap2_mcspi_set_dma_req(spi, 0, 0); + return 0; + } + + if (spi_controller_is_slave(mcspi->master)) { + ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone); + if (ret || mcspi->slave_aborted) + return 0; + } if (mcspi->fifo_depth > 0) { irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; @@ -1089,6 +1116,36 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) gpio_free(spi->cs_gpio); } +static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data) +{ + struct omap2_mcspi *mcspi = data; + u32 irqstat; + + irqstat = mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS); + if (!irqstat) + return IRQ_NONE; + + /* Disable IRQ and wakeup slave xfer task */ + mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0); + if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW) + complete(&mcspi->txdone); + + return IRQ_HANDLED; +} + +static int omap2_mcspi_slave_abort(struct spi_master *master) +{ + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels; + + mcspi->slave_aborted = true; + complete(&mcspi_dma->dma_rx_completion); + complete(&mcspi_dma->dma_tx_completion); + complete(&mcspi->txdone); + + return 0; +} + static int omap2_mcspi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *t) @@ -1255,10 +1312,20 @@ static bool omap2_mcspi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { + struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); + struct omap2_mcspi_dma *mcspi_dma = + &mcspi->dma_channels[spi->chip_select]; + + if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) + return false; + + if (spi_controller_is_slave(master)) + return true; + return (xfer->len >= DMA_MIN_BYTES); } -static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) +static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi) { struct spi_master *master = mcspi->master; struct omap2_mcspi_regs *ctx = &mcspi->ctx; @@ -1275,7 +1342,7 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) OMAP2_MCSPI_WAKEUPENABLE_WKEN); ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; - omap2_mcspi_set_master_mode(master); + omap2_mcspi_set_mode(master); pm_runtime_mark_last_busy(mcspi->dev); pm_runtime_put_autosuspend(mcspi->dev); return 0; @@ -1350,11 +1417,12 @@ static int omap2_mcspi_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; - master = spi_alloc_master(&pdev->dev, sizeof *mcspi); - if (master == NULL) { - dev_dbg(&pdev->dev, "master allocation failed\n"); + if (of_property_read_bool(node, "spi-slave")) + master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi)); + else + master = spi_alloc_master(&pdev->dev, sizeof(*mcspi)); + if (!master) return -ENOMEM; - } /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; @@ -1366,6 +1434,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->transfer_one = omap2_mcspi_transfer_one; master->set_cs = omap2_mcspi_set_cs; master->cleanup = omap2_mcspi_cleanup; + master->slave_abort = omap2_mcspi_slave_abort; master->dev.of_node = node; master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; @@ -1417,15 +1486,31 @@ static int omap2_mcspi_probe(struct platform_device *pdev) sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i); } + status = platform_get_irq(pdev, 0); + if (status == -EPROBE_DEFER) + goto free_master; + if (status < 0) { + dev_err(&pdev->dev, "no irq resource found\n"); + goto free_master; + } + init_completion(&mcspi->txdone); + status = devm_request_irq(&pdev->dev, status, + omap2_mcspi_irq_handler, 0, pdev->name, + mcspi); + if (status) { + dev_err(&pdev->dev, "Cannot request IRQ"); + goto free_master; + } + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_enable(&pdev->dev); - status = omap2_mcspi_master_setup(mcspi); + status = omap2_mcspi_controller_setup(mcspi); if (status < 0) goto disable_pm; - status = devm_spi_register_master(&pdev->dev, master); + status = devm_spi_register_controller(&pdev->dev, master); if (status < 0) goto disable_pm; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 47ef6b1a2e76..7f280567093e 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -431,6 +431,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) int word_len; struct orion_spi *orion_spi; int cs = spi->chip_select; + void __iomem *vaddr; word_len = spi->bits_per_word; count = xfer->len; @@ -441,8 +442,9 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) * Use SPI direct write mode if base address is available. Otherwise * fall back to PIO mode for this transfer. */ - if ((orion_spi->child[cs].direct_access.vaddr) && (xfer->tx_buf) && - (word_len == 8)) { + vaddr = orion_spi->child[cs].direct_access.vaddr; + + if (vaddr && xfer->tx_buf && word_len == 8) { unsigned int cnt = count / 4; unsigned int rem = count % 4; @@ -450,13 +452,11 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) * Send the TX-data to the SPI device via the direct * mapped address window */ - iowrite32_rep(orion_spi->child[cs].direct_access.vaddr, - xfer->tx_buf, cnt); + iowrite32_rep(vaddr, xfer->tx_buf, cnt); if (rem) { u32 *buf = (u32 *)xfer->tx_buf; - iowrite8_rep(orion_spi->child[cs].direct_access.vaddr, - &buf[cnt], rem); + iowrite8_rep(vaddr, &buf[cnt], rem); } return count; @@ -683,6 +683,7 @@ static int orion_spi_probe(struct platform_device *pdev) } for_each_available_child_of_node(pdev->dev.of_node, np) { + struct orion_direct_acc *dir_acc; u32 cs; int cs_gpio; @@ -750,14 +751,13 @@ static int orion_spi_probe(struct platform_device *pdev) * This needs to get extended for the direct SPI-NOR / SPI-NAND * support, once this gets implemented. */ - spi->child[cs].direct_access.vaddr = devm_ioremap(&pdev->dev, - r->start, - PAGE_SIZE); - if (!spi->child[cs].direct_access.vaddr) { + dir_acc = &spi->child[cs].direct_access; + dir_acc->vaddr = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); + if (!dir_acc->vaddr) { status = -ENOMEM; goto out_rel_axi_clk; } - spi->child[cs].direct_access.size = PAGE_SIZE; + dir_acc->size = PAGE_SIZE; dev_info(&pdev->dev, "CS%d configured for direct access\n", cs); } diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index bd1c6b53283f..d7e4e18ec3df 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -468,7 +468,7 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi) /* allocate coherent DMAable memory for hardware buffer descriptors. */ sqi->bd = dma_zalloc_coherent(&sqi->master->dev, sizeof(*bd) * PESQI_BD_COUNT, - &sqi->bd_dma, GFP_DMA32); + &sqi->bd_dma, GFP_KERNEL); if (!sqi->bd) { dev_err(&sqi->master->dev, "failed allocating dma buffer\n"); return -ENOMEM; @@ -656,7 +656,7 @@ static int pic32_sqi_probe(struct platform_device *pdev) master->max_speed_hz = clk_get_rate(sqi->base_clk); master->dma_alignment = 32; master->max_dma_len = PESQI_BD_BUF_LEN_MAX; - master->dev.of_node = of_node_get(pdev->dev.of_node); + master->dev.of_node = pdev->dev.of_node; master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD; master->flags = SPI_MASTER_HALF_DUPLEX; diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index f8a45af1fa9f..131849adc570 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -320,7 +320,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s, desc_rx = dmaengine_prep_slave_sg(master->dma_rx, xfer->rx_sg.sgl, xfer->rx_sg.nents, - DMA_FROM_DEVICE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) { ret = -EINVAL; @@ -330,7 +330,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s, desc_tx = dmaengine_prep_slave_sg(master->dma_tx, xfer->tx_sg.sgl, xfer->tx_sg.nents, - DMA_TO_DEVICE, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { ret = -EINVAL; @@ -774,7 +774,7 @@ static int pic32_spi_probe(struct platform_device *pdev) if (ret) goto err_master; - master->dev.of_node = of_node_get(pdev->dev.of_node); + master->dev.of_node = pdev->dev.of_node; master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH; master->num_chipselect = 1; /* single chip-select */ master->max_speed_hz = clk_get_rate(pic32s->clk); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 1af8c96b940e..6120e6abcd96 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1490,10 +1490,8 @@ static void do_polling_transfer(struct pl022 *pl022) struct spi_message *message = NULL; struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; - struct chip_data *chip; unsigned long time, timeout; - chip = pl022->cur_chip; message = pl022->cur_msg; while (message->state != STATE_DONE) { @@ -2325,10 +2323,8 @@ static int pl022_suspend(struct device *dev) int ret; ret = spi_master_suspend(pl022->master); - if (ret) { - dev_warn(dev, "cannot suspend master\n"); + if (ret) return ret; - } ret = pm_runtime_force_suspend(dev); if (ret) { @@ -2353,9 +2349,7 @@ static int pl022_resume(struct device *dev) /* Start the queue running */ ret = spi_master_resume(pl022->master); - if (ret) - dev_err(dev, "problem starting queue (%d)\n", ret); - else + if (!ret) dev_dbg(dev, "resumed\n"); return ret; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 14f4ea59caff..612cc49db28f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -33,6 +33,7 @@ #include <linux/clk.h> #include <linux/pm_runtime.h> #include <linux/acpi.h> +#include <linux/of_device.h> #include "spi-pxa2xx.h" @@ -665,9 +666,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) bytes_left = drv_data->rx_end - drv_data->rx; switch (drv_data->n_bytes) { case 4: - bytes_left >>= 1; + bytes_left >>= 2; + break; case 2: bytes_left >>= 1; + break; } rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data); @@ -1333,9 +1336,6 @@ static void cleanup(struct spi_device *spi) kfree(chip); } -#ifdef CONFIG_PCI -#ifdef CONFIG_ACPI - static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { { "INT33C0", LPSS_LPT_SSP }, { "INT33C1", LPSS_LPT_SSP }, @@ -1347,23 +1347,6 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); -static int pxa2xx_spi_get_port_id(struct acpi_device *adev) -{ - unsigned int devid; - int port_id = -1; - - if (adev && adev->pnp.unique_id && - !kstrtouint(adev->pnp.unique_id, 0, &devid)) - port_id = devid; - return port_id; -} -#else /* !CONFIG_ACPI */ -static int pxa2xx_spi_get_port_id(struct acpi_device *adev) -{ - return -1; -} -#endif - /* * PCI IDs of compound devices that integrate both host controller and private * integrated DMA engine. Please note these are not used in module @@ -1410,6 +1393,37 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { }, }; +static const struct of_device_id pxa2xx_spi_of_match[] = { + { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP }, + {}, +}; +MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match); + +#ifdef CONFIG_ACPI + +static int pxa2xx_spi_get_port_id(struct acpi_device *adev) +{ + unsigned int devid; + int port_id = -1; + + if (adev && adev->pnp.unique_id && + !kstrtouint(adev->pnp.unique_id, 0, &devid)) + port_id = devid; + return port_id; +} + +#else /* !CONFIG_ACPI */ + +static int pxa2xx_spi_get_port_id(struct acpi_device *adev) +{ + return -1; +} + +#endif /* CONFIG_ACPI */ + + +#ifdef CONFIG_PCI + static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) { struct device *dev = param; @@ -1420,6 +1434,8 @@ static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) return true; } +#endif /* CONFIG_PCI */ + static struct pxa2xx_spi_master * pxa2xx_spi_init_pdata(struct platform_device *pdev) { @@ -1429,11 +1445,15 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) struct resource *res; const struct acpi_device_id *adev_id = NULL; const struct pci_device_id *pcidev_id = NULL; - int type; + const struct of_device_id *of_id = NULL; + enum pxa_ssp_type type; adev = ACPI_COMPANION(&pdev->dev); - if (dev_is_pci(pdev->dev.parent)) + if (pdev->dev.of_node) + of_id = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + else if (dev_is_pci(pdev->dev.parent)) pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, to_pci_dev(pdev->dev.parent)); else if (adev) @@ -1443,9 +1463,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) return NULL; if (adev_id) - type = (int)adev_id->driver_data; + type = (enum pxa_ssp_type)adev_id->driver_data; else if (pcidev_id) - type = (int)pcidev_id->driver_data; + type = (enum pxa_ssp_type)pcidev_id->driver_data; + else if (of_id) + type = (enum pxa_ssp_type)of_id->data; else return NULL; @@ -1464,11 +1486,13 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) if (IS_ERR(ssp->mmio_base)) return NULL; +#ifdef CONFIG_PCI if (pcidev_id) { pdata->tx_param = pdev->dev.parent; pdata->rx_param = pdev->dev.parent; pdata->dma_filter = pxa2xx_spi_idma_filter; } +#endif ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->irq = platform_get_irq(pdev, 0); @@ -1482,14 +1506,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) return pdata; } -#else /* !CONFIG_PCI */ -static inline struct pxa2xx_spi_master * -pxa2xx_spi_init_pdata(struct platform_device *pdev) -{ - return NULL; -} -#endif - static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master, unsigned int cs) { @@ -1764,14 +1780,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) return 0; } -static void pxa2xx_spi_shutdown(struct platform_device *pdev) -{ - int status = 0; - - if ((status = pxa2xx_spi_remove(pdev)) != 0) - dev_err(&pdev->dev, "shutdown failed with %d\n", status); -} - #ifdef CONFIG_PM_SLEEP static int pxa2xx_spi_suspend(struct device *dev) { @@ -1808,13 +1816,7 @@ static int pxa2xx_spi_resume(struct device *dev) lpss_ssp_setup(drv_data); /* Start the queue running */ - status = spi_controller_resume(drv_data->master); - if (status != 0) { - dev_err(dev, "problem starting queue (%d)\n", status); - return status; - } - - return 0; + return spi_controller_resume(drv_data->master); } #endif @@ -1848,10 +1850,10 @@ static struct platform_driver driver = { .name = "pxa2xx-spi", .pm = &pxa2xx_spi_pm_ops, .acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match), + .of_match_table = of_match_ptr(pxa2xx_spi_of_match), }, .probe = pxa2xx_spi_probe, .remove = pxa2xx_spi_remove, - .shutdown = pxa2xx_spi_shutdown, }; static int __init pxa2xx_spi_init(void) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c new file mode 100644 index 000000000000..b8163b40bb92 --- /dev/null +++ b/drivers/spi/spi-qcom-qspi.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> + + +#define QSPI_NUM_CS 2 +#define QSPI_BYTES_PER_WORD 4 + +#define MSTR_CONFIG 0x0000 +#define FULL_CYCLE_MODE BIT(3) +#define FB_CLK_EN BIT(4) +#define PIN_HOLDN BIT(6) +#define PIN_WPN BIT(7) +#define DMA_ENABLE BIT(8) +#define BIG_ENDIAN_MODE BIT(9) +#define SPI_MODE_MSK 0xc00 +#define SPI_MODE_SHFT 10 +#define CHIP_SELECT_NUM BIT(12) +#define SBL_EN BIT(13) +#define LPA_BASE_MSK 0x3c000 +#define LPA_BASE_SHFT 14 +#define TX_DATA_DELAY_MSK 0xc0000 +#define TX_DATA_DELAY_SHFT 18 +#define TX_CLK_DELAY_MSK 0x300000 +#define TX_CLK_DELAY_SHFT 20 +#define TX_CS_N_DELAY_MSK 0xc00000 +#define TX_CS_N_DELAY_SHFT 22 +#define TX_DATA_OE_DELAY_MSK 0x3000000 +#define TX_DATA_OE_DELAY_SHFT 24 + +#define AHB_MASTER_CFG 0x0004 +#define HMEM_TYPE_START_MID_TRANS_MSK 0x7 +#define HMEM_TYPE_START_MID_TRANS_SHFT 0 +#define HMEM_TYPE_LAST_TRANS_MSK 0x38 +#define HMEM_TYPE_LAST_TRANS_SHFT 3 +#define USE_HMEMTYPE_LAST_ON_DESC_OR_CHAIN_MSK 0xc0 +#define USE_HMEMTYPE_LAST_ON_DESC_OR_CHAIN_SHFT 6 +#define HMEMTYPE_READ_TRANS_MSK 0x700 +#define HMEMTYPE_READ_TRANS_SHFT 8 +#define HSHARED BIT(11) +#define HINNERSHARED BIT(12) + +#define MSTR_INT_EN 0x000C +#define MSTR_INT_STATUS 0x0010 +#define RESP_FIFO_UNDERRUN BIT(0) +#define RESP_FIFO_NOT_EMPTY BIT(1) +#define RESP_FIFO_RDY BIT(2) +#define HRESP_FROM_NOC_ERR BIT(3) +#define WR_FIFO_EMPTY BIT(9) +#define WR_FIFO_FULL BIT(10) +#define WR_FIFO_OVERRUN BIT(11) +#define TRANSACTION_DONE BIT(16) +#define QSPI_ERR_IRQS (RESP_FIFO_UNDERRUN | HRESP_FROM_NOC_ERR | \ + WR_FIFO_OVERRUN) +#define QSPI_ALL_IRQS (QSPI_ERR_IRQS | RESP_FIFO_RDY | \ + WR_FIFO_EMPTY | WR_FIFO_FULL | \ + TRANSACTION_DONE) + +#define PIO_XFER_CTRL 0x0014 +#define REQUEST_COUNT_MSK 0xffff + +#define PIO_XFER_CFG 0x0018 +#define TRANSFER_DIRECTION BIT(0) +#define MULTI_IO_MODE_MSK 0xe +#define MULTI_IO_MODE_SHFT 1 +#define TRANSFER_FRAGMENT BIT(8) +#define SDR_1BIT 1 +#define SDR_2BIT 2 +#define SDR_4BIT 3 +#define DDR_1BIT 5 +#define DDR_2BIT 6 +#define DDR_4BIT 7 +#define DMA_DESC_SINGLE_SPI 1 +#define DMA_DESC_DUAL_SPI 2 +#define DMA_DESC_QUAD_SPI 3 + +#define PIO_XFER_STATUS 0x001c +#define WR_FIFO_BYTES_MSK 0xffff0000 +#define WR_FIFO_BYTES_SHFT 16 + +#define PIO_DATAOUT_1B 0x0020 +#define PIO_DATAOUT_4B 0x0024 + +#define RD_FIFO_STATUS 0x002c +#define FIFO_EMPTY BIT(11) +#define WR_CNTS_MSK 0x7f0 +#define WR_CNTS_SHFT 4 +#define RDY_64BYTE BIT(3) +#define RDY_32BYTE BIT(2) +#define RDY_16BYTE BIT(1) +#define FIFO_RDY BIT(0) + +#define RD_FIFO_CFG 0x0028 +#define CONTINUOUS_MODE BIT(0) + +#define RD_FIFO_RESET 0x0030 +#define RESET_FIFO BIT(0) + +#define CUR_MEM_ADDR 0x0048 +#define HW_VERSION 0x004c +#define RD_FIFO 0x0050 +#define SAMPLING_CLK_CFG 0x0090 +#define SAMPLING_CLK_STATUS 0x0094 + + +enum qspi_dir { + QSPI_READ, + QSPI_WRITE, +}; + +struct qspi_xfer { + union { + const void *tx_buf; + void *rx_buf; + }; + unsigned int rem_bytes; + unsigned int buswidth; + enum qspi_dir dir; + bool is_last; +}; + +enum qspi_clocks { + QSPI_CLK_CORE, + QSPI_CLK_IFACE, + QSPI_NUM_CLKS +}; + +struct qcom_qspi { + void __iomem *base; + struct device *dev; + struct clk_bulk_data clks[QSPI_NUM_CLKS]; + struct qspi_xfer xfer; + /* Lock to protect data accessed by IRQs */ + spinlock_t lock; +}; + +static u32 qspi_buswidth_to_iomode(struct qcom_qspi *ctrl, + unsigned int buswidth) +{ + switch (buswidth) { + case 1: + return SDR_1BIT << MULTI_IO_MODE_SHFT; + case 2: + return SDR_2BIT << MULTI_IO_MODE_SHFT; + case 4: + return SDR_4BIT << MULTI_IO_MODE_SHFT; + default: + dev_warn_once(ctrl->dev, + "Unexpected bus width: %u\n", buswidth); + return SDR_1BIT << MULTI_IO_MODE_SHFT; + } +} + +static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl) +{ + u32 pio_xfer_cfg; + const struct qspi_xfer *xfer; + + xfer = &ctrl->xfer; + pio_xfer_cfg = readl(ctrl->base + PIO_XFER_CFG); + pio_xfer_cfg &= ~TRANSFER_DIRECTION; + pio_xfer_cfg |= xfer->dir; + if (xfer->is_last) + pio_xfer_cfg &= ~TRANSFER_FRAGMENT; + else + pio_xfer_cfg |= TRANSFER_FRAGMENT; + pio_xfer_cfg &= ~MULTI_IO_MODE_MSK; + pio_xfer_cfg |= qspi_buswidth_to_iomode(ctrl, xfer->buswidth); + + writel(pio_xfer_cfg, ctrl->base + PIO_XFER_CFG); +} + +static void qcom_qspi_pio_xfer_ctrl(struct qcom_qspi *ctrl) +{ + u32 pio_xfer_ctrl; + + pio_xfer_ctrl = readl(ctrl->base + PIO_XFER_CTRL); + pio_xfer_ctrl &= ~REQUEST_COUNT_MSK; + pio_xfer_ctrl |= ctrl->xfer.rem_bytes; + writel(pio_xfer_ctrl, ctrl->base + PIO_XFER_CTRL); +} + +static void qcom_qspi_pio_xfer(struct qcom_qspi *ctrl) +{ + u32 ints; + + qcom_qspi_pio_xfer_cfg(ctrl); + + /* Ack any previous interrupts that might be hanging around */ + writel(QSPI_ALL_IRQS, ctrl->base + MSTR_INT_STATUS); + + /* Setup new interrupts */ + if (ctrl->xfer.dir == QSPI_WRITE) + ints = QSPI_ERR_IRQS | WR_FIFO_EMPTY; + else + ints = QSPI_ERR_IRQS | RESP_FIFO_RDY; + writel(ints, ctrl->base + MSTR_INT_EN); + + /* Kick off the transfer */ + qcom_qspi_pio_xfer_ctrl(ctrl); +} + +static void qcom_qspi_handle_err(struct spi_master *master, + struct spi_message *msg) +{ + struct qcom_qspi *ctrl = spi_master_get_devdata(master); + unsigned long flags; + + spin_lock_irqsave(&ctrl->lock, flags); + writel(0, ctrl->base + MSTR_INT_EN); + ctrl->xfer.rem_bytes = 0; + spin_unlock_irqrestore(&ctrl->lock, flags); +} + +static int qcom_qspi_transfer_one(struct spi_master *master, + struct spi_device *slv, + struct spi_transfer *xfer) +{ + struct qcom_qspi *ctrl = spi_master_get_devdata(master); + int ret; + unsigned long speed_hz; + unsigned long flags; + + speed_hz = slv->max_speed_hz; + if (xfer->speed_hz) + speed_hz = xfer->speed_hz; + + /* In regular operation (SBL_EN=1) core must be 4x transfer clock */ + ret = clk_set_rate(ctrl->clks[QSPI_CLK_CORE].clk, speed_hz * 4); + if (ret) { + dev_err(ctrl->dev, "Failed to set core clk %d\n", ret); + return ret; + } + + spin_lock_irqsave(&ctrl->lock, flags); + + /* We are half duplex, so either rx or tx will be set */ + if (xfer->rx_buf) { + ctrl->xfer.dir = QSPI_READ; + ctrl->xfer.buswidth = xfer->rx_nbits; + ctrl->xfer.rx_buf = xfer->rx_buf; + } else { + ctrl->xfer.dir = QSPI_WRITE; + ctrl->xfer.buswidth = xfer->tx_nbits; + ctrl->xfer.tx_buf = xfer->tx_buf; + } + ctrl->xfer.is_last = list_is_last(&xfer->transfer_list, + &master->cur_msg->transfers); + ctrl->xfer.rem_bytes = xfer->len; + qcom_qspi_pio_xfer(ctrl); + + spin_unlock_irqrestore(&ctrl->lock, flags); + + /* We'll call spi_finalize_current_transfer() when done */ + return 1; +} + +static int qcom_qspi_prepare_message(struct spi_master *master, + struct spi_message *message) +{ + u32 mstr_cfg; + struct qcom_qspi *ctrl; + int tx_data_oe_delay = 1; + int tx_data_delay = 1; + unsigned long flags; + + ctrl = spi_master_get_devdata(master); + spin_lock_irqsave(&ctrl->lock, flags); + + mstr_cfg = readl(ctrl->base + MSTR_CONFIG); + mstr_cfg &= ~CHIP_SELECT_NUM; + if (message->spi->chip_select) + mstr_cfg |= CHIP_SELECT_NUM; + + mstr_cfg |= FB_CLK_EN | PIN_WPN | PIN_HOLDN | SBL_EN | FULL_CYCLE_MODE; + mstr_cfg &= ~(SPI_MODE_MSK | TX_DATA_OE_DELAY_MSK | TX_DATA_DELAY_MSK); + mstr_cfg |= message->spi->mode << SPI_MODE_SHFT; + mstr_cfg |= tx_data_oe_delay << TX_DATA_OE_DELAY_SHFT; + mstr_cfg |= tx_data_delay << TX_DATA_DELAY_SHFT; + mstr_cfg &= ~DMA_ENABLE; + + writel(mstr_cfg, ctrl->base + MSTR_CONFIG); + spin_unlock_irqrestore(&ctrl->lock, flags); + + return 0; +} + +static irqreturn_t pio_read(struct qcom_qspi *ctrl) +{ + u32 rd_fifo_status; + u32 rd_fifo; + unsigned int wr_cnts; + unsigned int bytes_to_read; + unsigned int words_to_read; + u32 *word_buf; + u8 *byte_buf; + int i; + + rd_fifo_status = readl(ctrl->base + RD_FIFO_STATUS); + + if (!(rd_fifo_status & FIFO_RDY)) { + dev_dbg(ctrl->dev, "Spurious IRQ %#x\n", rd_fifo_status); + return IRQ_NONE; + } + + wr_cnts = (rd_fifo_status & WR_CNTS_MSK) >> WR_CNTS_SHFT; + wr_cnts = min(wr_cnts, ctrl->xfer.rem_bytes); + + words_to_read = wr_cnts / QSPI_BYTES_PER_WORD; + bytes_to_read = wr_cnts % QSPI_BYTES_PER_WORD; + + if (words_to_read) { + word_buf = ctrl->xfer.rx_buf; + ctrl->xfer.rem_bytes -= words_to_read * QSPI_BYTES_PER_WORD; + ioread32_rep(ctrl->base + RD_FIFO, word_buf, words_to_read); + ctrl->xfer.rx_buf = word_buf + words_to_read; + } + + if (bytes_to_read) { + byte_buf = ctrl->xfer.rx_buf; + rd_fifo = readl(ctrl->base + RD_FIFO); + ctrl->xfer.rem_bytes -= bytes_to_read; + for (i = 0; i < bytes_to_read; i++) + *byte_buf++ = rd_fifo >> (i * BITS_PER_BYTE); + ctrl->xfer.rx_buf = byte_buf; + } + + return IRQ_HANDLED; +} + +static irqreturn_t pio_write(struct qcom_qspi *ctrl) +{ + const void *xfer_buf = ctrl->xfer.tx_buf; + const int *word_buf; + const char *byte_buf; + unsigned int wr_fifo_bytes; + unsigned int wr_fifo_words; + unsigned int wr_size; + unsigned int rem_words; + + wr_fifo_bytes = readl(ctrl->base + PIO_XFER_STATUS); + wr_fifo_bytes >>= WR_FIFO_BYTES_SHFT; + + if (ctrl->xfer.rem_bytes < QSPI_BYTES_PER_WORD) { + /* Process the last 1-3 bytes */ + wr_size = min(wr_fifo_bytes, ctrl->xfer.rem_bytes); + ctrl->xfer.rem_bytes -= wr_size; + + byte_buf = xfer_buf; + while (wr_size--) + writel(*byte_buf++, + ctrl->base + PIO_DATAOUT_1B); + ctrl->xfer.tx_buf = byte_buf; + } else { + /* + * Process all the whole words; to keep things simple we'll + * just wait for the next interrupt to handle the last 1-3 + * bytes if we don't have an even number of words. + */ + rem_words = ctrl->xfer.rem_bytes / QSPI_BYTES_PER_WORD; + wr_fifo_words = wr_fifo_bytes / QSPI_BYTES_PER_WORD; + + wr_size = min(rem_words, wr_fifo_words); + ctrl->xfer.rem_bytes -= wr_size * QSPI_BYTES_PER_WORD; + + word_buf = xfer_buf; + iowrite32_rep(ctrl->base + PIO_DATAOUT_4B, word_buf, wr_size); + ctrl->xfer.tx_buf = word_buf + wr_size; + + } + + return IRQ_HANDLED; +} + +static irqreturn_t qcom_qspi_irq(int irq, void *dev_id) +{ + u32 int_status; + struct qcom_qspi *ctrl = dev_id; + irqreturn_t ret = IRQ_NONE; + unsigned long flags; + + spin_lock_irqsave(&ctrl->lock, flags); + + int_status = readl(ctrl->base + MSTR_INT_STATUS); + writel(int_status, ctrl->base + MSTR_INT_STATUS); + + if (ctrl->xfer.dir == QSPI_WRITE) { + if (int_status & WR_FIFO_EMPTY) + ret = pio_write(ctrl); + } else { + if (int_status & RESP_FIFO_RDY) + ret = pio_read(ctrl); + } + + if (int_status & QSPI_ERR_IRQS) { + if (int_status & RESP_FIFO_UNDERRUN) + dev_err(ctrl->dev, "IRQ error: FIFO underrun\n"); + if (int_status & WR_FIFO_OVERRUN) + dev_err(ctrl->dev, "IRQ error: FIFO overrun\n"); + if (int_status & HRESP_FROM_NOC_ERR) + dev_err(ctrl->dev, "IRQ error: NOC response error\n"); + ret = IRQ_HANDLED; + } + + if (!ctrl->xfer.rem_bytes) { + writel(0, ctrl->base + MSTR_INT_EN); + spi_finalize_current_transfer(dev_get_drvdata(ctrl->dev)); + } + + spin_unlock_irqrestore(&ctrl->lock, flags); + return ret; +} + +static int qcom_qspi_probe(struct platform_device *pdev) +{ + int ret; + struct device *dev; + struct resource *res; + struct spi_master *master; + struct qcom_qspi *ctrl; + + dev = &pdev->dev; + + master = spi_alloc_master(dev, sizeof(*ctrl)); + if (!master) + return -ENOMEM; + + platform_set_drvdata(pdev, master); + + ctrl = spi_master_get_devdata(master); + + spin_lock_init(&ctrl->lock); + ctrl->dev = dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ctrl->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ctrl->base)) { + ret = PTR_ERR(ctrl->base); + goto exit_probe_master_put; + } + + ctrl->clks[QSPI_CLK_CORE].id = "core"; + ctrl->clks[QSPI_CLK_IFACE].id = "iface"; + ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks); + if (ret) + goto exit_probe_master_put; + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "Failed to get irq %d\n", ret); + goto exit_probe_master_put; + } + ret = devm_request_irq(dev, ret, qcom_qspi_irq, + IRQF_TRIGGER_HIGH, dev_name(dev), ctrl); + if (ret) { + dev_err(dev, "Failed to request irq %d\n", ret); + goto exit_probe_master_put; + } + + master->max_speed_hz = 300000000; + master->num_chipselect = QSPI_NUM_CS; + master->bus_num = -1; + master->dev.of_node = pdev->dev.of_node; + master->mode_bits = SPI_MODE_0 | + SPI_TX_DUAL | SPI_RX_DUAL | + SPI_TX_QUAD | SPI_RX_QUAD; + master->flags = SPI_MASTER_HALF_DUPLEX; + master->prepare_message = qcom_qspi_prepare_message; + master->transfer_one = qcom_qspi_transfer_one; + master->handle_err = qcom_qspi_handle_err; + master->auto_runtime_pm = true; + + pm_runtime_enable(dev); + + ret = spi_register_master(master); + if (!ret) + return 0; + + pm_runtime_disable(dev); + +exit_probe_master_put: + spi_master_put(master); + + return ret; +} + +static int qcom_qspi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + + /* Unregister _before_ disabling pm_runtime() so we stop transfers */ + spi_unregister_master(master); + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct qcom_qspi *ctrl = spi_master_get_devdata(master); + + clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks); + + return 0; +} + +static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct qcom_qspi *ctrl = spi_master_get_devdata(master); + + return clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks); +} + +static int __maybe_unused qcom_qspi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + spi_master_resume(master); + + return ret; +} + +static int __maybe_unused qcom_qspi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + ret = spi_master_resume(master); + if (ret) + pm_runtime_force_suspend(dev); + + return ret; +} + +static const struct dev_pm_ops qcom_qspi_dev_pm_ops = { + SET_RUNTIME_PM_OPS(qcom_qspi_runtime_suspend, + qcom_qspi_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(qcom_qspi_suspend, qcom_qspi_resume) +}; + +static const struct of_device_id qcom_qspi_dt_match[] = { + { .compatible = "qcom,qspi-v1", }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_qspi_dt_match); + +static struct platform_driver qcom_qspi_driver = { + .driver = { + .name = "qcom_qspi", + .pm = &qcom_qspi_dev_pm_ops, + .of_match_table = qcom_qspi_dt_match, + }, + .probe = qcom_qspi_probe, + .remove = qcom_qspi_remove, +}; +module_platform_driver(qcom_qspi_driver); + +MODULE_DESCRIPTION("SPI driver for QSPI cores"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c index 3641d0e20135..fbbf9a188247 100644 --- a/drivers/spi/spi-rb4xx.c +++ b/drivers/spi/spi-rb4xx.c @@ -159,7 +159,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev) master->bus_num = 0; master->num_chipselect = 3; master->mode_bits = SPI_TX_DUAL; - master->bits_per_word_mask = BIT(7); + master->bits_per_word_mask = SPI_BPW_MASK(8); master->flags = SPI_MASTER_MUST_TX; master->transfer_one = rb4xx_transfer_one; master->set_cs = rb4xx_set_cs; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index fdcf3076681b..51ef632bca52 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -164,7 +164,6 @@ enum rockchip_ssi_type { struct rockchip_spi_dma_data { struct dma_chan *ch; - enum dma_transfer_direction direction; dma_addr_t addr; }; @@ -202,12 +201,11 @@ struct rockchip_spi { bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; - u32 use_dma; + bool use_dma; struct sg_table tx_sg; struct sg_table rx_sg; struct rockchip_spi_dma_data dma_rx; struct rockchip_spi_dma_data dma_tx; - struct dma_slave_caps dma_caps; }; static inline void spi_enable_chip(struct rockchip_spi *rs, int enable) @@ -381,6 +379,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs) { int remain = 0; + spi_enable_chip(rs, 1); + do { if (rs->tx) { remain = rs->tx_end - rs->tx; @@ -445,6 +445,9 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) struct dma_slave_config rxconf, txconf; struct dma_async_tx_descriptor *rxdesc, *txdesc; + memset(&rxconf, 0, sizeof(rxconf)); + memset(&txconf, 0, sizeof(txconf)); + spin_lock_irqsave(&rs->lock, flags); rs->state &= ~RXBUSY; rs->state &= ~TXBUSY; @@ -452,19 +455,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) rxdesc = NULL; if (rs->rx) { - rxconf.direction = rs->dma_rx.direction; + rxconf.direction = DMA_DEV_TO_MEM; rxconf.src_addr = rs->dma_rx.addr; rxconf.src_addr_width = rs->n_bytes; - if (rs->dma_caps.max_burst > 4) - rxconf.src_maxburst = 4; - else - rxconf.src_maxburst = 1; + rxconf.src_maxburst = 1; dmaengine_slave_config(rs->dma_rx.ch, &rxconf); rxdesc = dmaengine_prep_slave_sg( rs->dma_rx.ch, rs->rx_sg.sgl, rs->rx_sg.nents, - rs->dma_rx.direction, DMA_PREP_INTERRUPT); + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!rxdesc) return -EINVAL; @@ -474,19 +474,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) txdesc = NULL; if (rs->tx) { - txconf.direction = rs->dma_tx.direction; + txconf.direction = DMA_MEM_TO_DEV; txconf.dst_addr = rs->dma_tx.addr; txconf.dst_addr_width = rs->n_bytes; - if (rs->dma_caps.max_burst > 4) - txconf.dst_maxburst = 4; - else - txconf.dst_maxburst = 1; + txconf.dst_maxburst = rs->fifo_len / 2; dmaengine_slave_config(rs->dma_tx.ch, &txconf); txdesc = dmaengine_prep_slave_sg( rs->dma_tx.ch, rs->tx_sg.sgl, rs->tx_sg.nents, - rs->dma_tx.direction, DMA_PREP_INTERRUPT); + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!txdesc) { if (rxdesc) dmaengine_terminate_sync(rs->dma_rx.ch); @@ -506,6 +503,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) dma_async_issue_pending(rs->dma_rx.ch); } + spi_enable_chip(rs, 1); + if (txdesc) { spin_lock_irqsave(&rs->lock, flags); rs->state |= TXBUSY; @@ -514,7 +513,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) dma_async_issue_pending(rs->dma_tx.ch); } - return 0; + /* 1 means the transfer is in progress */ + return 1; } static void rockchip_spi_config(struct rockchip_spi *rs) @@ -578,7 +578,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs) writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); - writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMATDLR); + writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR); writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); @@ -597,7 +597,6 @@ static int rockchip_spi_transfer_one( struct spi_device *spi, struct spi_transfer *xfer) { - int ret = 0; struct rockchip_spi *rs = spi_master_get_devdata(master); WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && @@ -635,30 +634,16 @@ static int rockchip_spi_transfer_one( /* we need prepare dma before spi was enabled */ if (master->can_dma && master->can_dma(master, spi, xfer)) - rs->use_dma = 1; + rs->use_dma = true; else - rs->use_dma = 0; + rs->use_dma = false; rockchip_spi_config(rs); - if (rs->use_dma) { - if (rs->tmode == CR0_XFM_RO) { - /* rx: dma must be prepared first */ - ret = rockchip_spi_prepare_dma(rs); - spi_enable_chip(rs, 1); - } else { - /* tx or tr: spi must be enabled first */ - spi_enable_chip(rs, 1); - ret = rockchip_spi_prepare_dma(rs); - } - /* successful DMA prepare means the transfer is in progress */ - ret = ret ? ret : 1; - } else { - spi_enable_chip(rs, 1); - ret = rockchip_spi_pio_transfer(rs); - } + if (rs->use_dma) + return rockchip_spi_prepare_dma(rs); - return ret; + return rockchip_spi_pio_transfer(rs); } static bool rockchip_spi_can_dma(struct spi_master *master, @@ -780,11 +765,8 @@ static int rockchip_spi_probe(struct platform_device *pdev) } if (rs->dma_tx.ch && rs->dma_rx.ch) { - dma_get_slave_caps(rs->dma_rx.ch, &(rs->dma_caps)); rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR); rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR); - rs->dma_tx.direction = DMA_MEM_TO_DEV; - rs->dma_rx.direction = DMA_DEV_TO_MEM; master->can_dma = rockchip_spi_can_dma; master->dma_tx = rs->dma_tx.ch; diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index b37de1d991d6..55f8e55327b3 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH RSPI driver * @@ -6,15 +7,6 @@ * * Based on spi-sh.c: * Copyright (C) 2011 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 20e800e70442..dc0926e43665 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH HSPI bus driver * @@ -7,15 +8,6 @@ * Based on pxa2xx_spi.c: * Copyright (C) 2011 Renesas Solutions Corp. * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/clk.h> @@ -316,6 +308,6 @@ static struct platform_driver hspi_driver = { module_platform_driver(hspi_driver); MODULE_DESCRIPTION("SuperH HSPI bus driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); MODULE_ALIAS("platform:sh-hspi"); diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 101cd6aae2ea..adf384323934 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH MSIOF SPI Master Interface * * Copyright (c) 2009 Magnus Damm * Copyright (C) 2014 Renesas Electronics Corporation * Copyright (C) 2014-2017 Glider bvba - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bitmap.h> @@ -1343,8 +1339,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) i = platform_get_irq(pdev, 0); if (i < 0) { - dev_err(&pdev->dev, "cannot get platform IRQ\n"); - ret = -ENOENT; + dev_err(&pdev->dev, "cannot get IRQ\n"); + ret = i; goto err1; } diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 50e0ea9acf8b..f1ee58208216 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH SPI bus driver * @@ -5,15 +6,6 @@ * * Based on pxa2xx_spi.c: * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> @@ -522,6 +514,6 @@ static struct platform_driver spi_sh_driver = { module_platform_driver(spi_sh_driver); MODULE_DESCRIPTION("SH SPI bus driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yoshihiro Shimoda"); MODULE_ALIAS("platform:sh_spi"); diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c new file mode 100644 index 000000000000..d1075433f6a6 --- /dev/null +++ b/drivers/spi/spi-slave-mt27xx.c @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 MediaTek Inc. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> + +#define SPIS_IRQ_EN_REG 0x0 +#define SPIS_IRQ_CLR_REG 0x4 +#define SPIS_IRQ_ST_REG 0x8 +#define SPIS_IRQ_MASK_REG 0xc +#define SPIS_CFG_REG 0x10 +#define SPIS_RX_DATA_REG 0x14 +#define SPIS_TX_DATA_REG 0x18 +#define SPIS_RX_DST_REG 0x1c +#define SPIS_TX_SRC_REG 0x20 +#define SPIS_DMA_CFG_REG 0x30 +#define SPIS_SOFT_RST_REG 0x40 + +/* SPIS_IRQ_EN_REG */ +#define DMA_DONE_EN BIT(7) +#define DATA_DONE_EN BIT(2) +#define RSTA_DONE_EN BIT(1) +#define CMD_INVALID_EN BIT(0) + +/* SPIS_IRQ_ST_REG */ +#define DMA_DONE_ST BIT(7) +#define DATA_DONE_ST BIT(2) +#define RSTA_DONE_ST BIT(1) +#define CMD_INVALID_ST BIT(0) + +/* SPIS_IRQ_MASK_REG */ +#define DMA_DONE_MASK BIT(7) +#define DATA_DONE_MASK BIT(2) +#define RSTA_DONE_MASK BIT(1) +#define CMD_INVALID_MASK BIT(0) + +/* SPIS_CFG_REG */ +#define SPIS_TX_ENDIAN BIT(7) +#define SPIS_RX_ENDIAN BIT(6) +#define SPIS_TXMSBF BIT(5) +#define SPIS_RXMSBF BIT(4) +#define SPIS_CPHA BIT(3) +#define SPIS_CPOL BIT(2) +#define SPIS_TX_EN BIT(1) +#define SPIS_RX_EN BIT(0) + +/* SPIS_DMA_CFG_REG */ +#define TX_DMA_TRIG_EN BIT(31) +#define TX_DMA_EN BIT(30) +#define RX_DMA_EN BIT(29) +#define TX_DMA_LEN 0xfffff + +/* SPIS_SOFT_RST_REG */ +#define SPIS_DMA_ADDR_EN BIT(1) +#define SPIS_SOFT_RST BIT(0) + +#define MTK_SPI_SLAVE_MAX_FIFO_SIZE 512U + +struct mtk_spi_slave { + struct device *dev; + void __iomem *base; + struct clk *spi_clk; + struct completion xfer_done; + struct spi_transfer *cur_transfer; + bool slave_aborted; +}; + +static const struct of_device_id mtk_spi_slave_of_match[] = { + { .compatible = "mediatek,mt2712-spi-slave", }, + {} +}; +MODULE_DEVICE_TABLE(of, mtk_spi_slave_of_match); + +static void mtk_spi_slave_disable_dma(struct mtk_spi_slave *mdata) +{ + u32 reg_val; + + reg_val = readl(mdata->base + SPIS_DMA_CFG_REG); + reg_val &= ~RX_DMA_EN; + reg_val &= ~TX_DMA_EN; + writel(reg_val, mdata->base + SPIS_DMA_CFG_REG); +} + +static void mtk_spi_slave_disable_xfer(struct mtk_spi_slave *mdata) +{ + u32 reg_val; + + reg_val = readl(mdata->base + SPIS_CFG_REG); + reg_val &= ~SPIS_TX_EN; + reg_val &= ~SPIS_RX_EN; + writel(reg_val, mdata->base + SPIS_CFG_REG); +} + +static int mtk_spi_slave_wait_for_completion(struct mtk_spi_slave *mdata) +{ + if (wait_for_completion_interruptible(&mdata->xfer_done) || + mdata->slave_aborted) { + dev_err(mdata->dev, "interrupted\n"); + return -EINTR; + } + + return 0; +} + +static int mtk_spi_slave_prepare_message(struct spi_controller *ctlr, + struct spi_message *msg) +{ + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + struct spi_device *spi = msg->spi; + bool cpha, cpol; + u32 reg_val; + + cpha = spi->mode & SPI_CPHA ? 1 : 0; + cpol = spi->mode & SPI_CPOL ? 1 : 0; + + reg_val = readl(mdata->base + SPIS_CFG_REG); + if (cpha) + reg_val |= SPIS_CPHA; + else + reg_val &= ~SPIS_CPHA; + if (cpol) + reg_val |= SPIS_CPOL; + else + reg_val &= ~SPIS_CPOL; + + if (spi->mode & SPI_LSB_FIRST) + reg_val &= ~(SPIS_TXMSBF | SPIS_RXMSBF); + else + reg_val |= SPIS_TXMSBF | SPIS_RXMSBF; + + reg_val &= ~SPIS_TX_ENDIAN; + reg_val &= ~SPIS_RX_ENDIAN; + writel(reg_val, mdata->base + SPIS_CFG_REG); + + return 0; +} + +static int mtk_spi_slave_fifo_transfer(struct spi_controller *ctlr, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + int reg_val, cnt, remainder, ret; + + writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + + reg_val = readl(mdata->base + SPIS_CFG_REG); + if (xfer->rx_buf) + reg_val |= SPIS_RX_EN; + if (xfer->tx_buf) + reg_val |= SPIS_TX_EN; + writel(reg_val, mdata->base + SPIS_CFG_REG); + + cnt = xfer->len / 4; + if (xfer->tx_buf) + iowrite32_rep(mdata->base + SPIS_TX_DATA_REG, + xfer->tx_buf, cnt); + + remainder = xfer->len % 4; + if (xfer->tx_buf && remainder > 0) { + reg_val = 0; + memcpy(®_val, xfer->tx_buf + cnt * 4, remainder); + writel(reg_val, mdata->base + SPIS_TX_DATA_REG); + } + + ret = mtk_spi_slave_wait_for_completion(mdata); + if (ret) { + mtk_spi_slave_disable_xfer(mdata); + writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + } + + return ret; +} + +static int mtk_spi_slave_dma_transfer(struct spi_controller *ctlr, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + struct device *dev = mdata->dev; + int reg_val, ret; + + writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + + if (xfer->tx_buf) { + /* tx_buf is a const void* where we need a void * for + * the dma mapping + */ + void *nonconst_tx = (void *)xfer->tx_buf; + + xfer->tx_dma = dma_map_single(dev, nonconst_tx, + xfer->len, DMA_TO_DEVICE); + if (dma_mapping_error(dev, xfer->tx_dma)) { + ret = -ENOMEM; + goto disable_transfer; + } + } + + if (xfer->rx_buf) { + xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, + xfer->len, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, xfer->rx_dma)) { + ret = -ENOMEM; + goto unmap_txdma; + } + } + + writel(xfer->tx_dma, mdata->base + SPIS_TX_SRC_REG); + writel(xfer->rx_dma, mdata->base + SPIS_RX_DST_REG); + + writel(SPIS_DMA_ADDR_EN, mdata->base + SPIS_SOFT_RST_REG); + + /* enable config reg tx rx_enable */ + reg_val = readl(mdata->base + SPIS_CFG_REG); + if (xfer->tx_buf) + reg_val |= SPIS_TX_EN; + if (xfer->rx_buf) + reg_val |= SPIS_RX_EN; + writel(reg_val, mdata->base + SPIS_CFG_REG); + + /* config dma */ + reg_val = 0; + reg_val |= (xfer->len - 1) & TX_DMA_LEN; + writel(reg_val, mdata->base + SPIS_DMA_CFG_REG); + + reg_val = readl(mdata->base + SPIS_DMA_CFG_REG); + if (xfer->tx_buf) + reg_val |= TX_DMA_EN; + if (xfer->rx_buf) + reg_val |= RX_DMA_EN; + reg_val |= TX_DMA_TRIG_EN; + writel(reg_val, mdata->base + SPIS_DMA_CFG_REG); + + ret = mtk_spi_slave_wait_for_completion(mdata); + if (ret) + goto unmap_rxdma; + + return 0; + +unmap_rxdma: + if (xfer->rx_buf) + dma_unmap_single(dev, xfer->rx_dma, + xfer->len, DMA_FROM_DEVICE); + +unmap_txdma: + if (xfer->tx_buf) + dma_unmap_single(dev, xfer->tx_dma, + xfer->len, DMA_TO_DEVICE); + +disable_transfer: + mtk_spi_slave_disable_dma(mdata); + mtk_spi_slave_disable_xfer(mdata); + writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + + return ret; +} + +static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + + reinit_completion(&mdata->xfer_done); + mdata->slave_aborted = false; + mdata->cur_transfer = xfer; + + if (xfer->len > MTK_SPI_SLAVE_MAX_FIFO_SIZE) + return mtk_spi_slave_dma_transfer(ctlr, spi, xfer); + else + return mtk_spi_slave_fifo_transfer(ctlr, spi, xfer); +} + +static int mtk_spi_slave_setup(struct spi_device *spi) +{ + struct mtk_spi_slave *mdata = spi_controller_get_devdata(spi->master); + u32 reg_val; + + reg_val = DMA_DONE_EN | DATA_DONE_EN | + RSTA_DONE_EN | CMD_INVALID_EN; + writel(reg_val, mdata->base + SPIS_IRQ_EN_REG); + + reg_val = DMA_DONE_MASK | DATA_DONE_MASK | + RSTA_DONE_MASK | CMD_INVALID_MASK; + writel(reg_val, mdata->base + SPIS_IRQ_MASK_REG); + + mtk_spi_slave_disable_dma(mdata); + mtk_spi_slave_disable_xfer(mdata); + + return 0; +} + +static int mtk_slave_abort(struct spi_controller *ctlr) +{ + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + + mdata->slave_aborted = true; + complete(&mdata->xfer_done); + + return 0; +} + +static irqreturn_t mtk_spi_slave_interrupt(int irq, void *dev_id) +{ + struct spi_controller *ctlr = dev_id; + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + struct spi_transfer *trans = mdata->cur_transfer; + u32 int_status, reg_val, cnt, remainder; + + int_status = readl(mdata->base + SPIS_IRQ_ST_REG); + writel(int_status, mdata->base + SPIS_IRQ_CLR_REG); + + if (!trans) + return IRQ_NONE; + + if ((int_status & DMA_DONE_ST) && + ((int_status & DATA_DONE_ST) || + (int_status & RSTA_DONE_ST))) { + writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + + if (trans->tx_buf) + dma_unmap_single(mdata->dev, trans->tx_dma, + trans->len, DMA_TO_DEVICE); + if (trans->rx_buf) + dma_unmap_single(mdata->dev, trans->rx_dma, + trans->len, DMA_FROM_DEVICE); + + mtk_spi_slave_disable_dma(mdata); + mtk_spi_slave_disable_xfer(mdata); + } + + if ((!(int_status & DMA_DONE_ST)) && + ((int_status & DATA_DONE_ST) || + (int_status & RSTA_DONE_ST))) { + cnt = trans->len / 4; + if (trans->rx_buf) + ioread32_rep(mdata->base + SPIS_RX_DATA_REG, + trans->rx_buf, cnt); + remainder = trans->len % 4; + if (trans->rx_buf && remainder > 0) { + reg_val = readl(mdata->base + SPIS_RX_DATA_REG); + memcpy(trans->rx_buf + (cnt * 4), + ®_val, remainder); + } + + mtk_spi_slave_disable_xfer(mdata); + } + + if (int_status & CMD_INVALID_ST) { + dev_warn(&ctlr->dev, "cmd invalid\n"); + return IRQ_NONE; + } + + mdata->cur_transfer = NULL; + complete(&mdata->xfer_done); + + return IRQ_HANDLED; +} + +static int mtk_spi_slave_probe(struct platform_device *pdev) +{ + struct spi_controller *ctlr; + struct mtk_spi_slave *mdata; + struct resource *res; + int irq, ret; + + ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata)); + if (!ctlr) { + dev_err(&pdev->dev, "failed to alloc spi slave\n"); + return -ENOMEM; + } + + ctlr->auto_runtime_pm = true; + ctlr->dev.of_node = pdev->dev.of_node; + ctlr->mode_bits = SPI_CPOL | SPI_CPHA; + ctlr->mode_bits |= SPI_LSB_FIRST; + + ctlr->prepare_message = mtk_spi_slave_prepare_message; + ctlr->transfer_one = mtk_spi_slave_transfer_one; + ctlr->setup = mtk_spi_slave_setup; + ctlr->slave_abort = mtk_slave_abort; + + mdata = spi_controller_get_devdata(ctlr); + + platform_set_drvdata(pdev, ctlr); + + init_completion(&mdata->xfer_done); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + dev_err(&pdev->dev, "failed to determine base address\n"); + goto err_put_ctlr; + } + + mdata->dev = &pdev->dev; + + mdata->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mdata->base)) { + ret = PTR_ERR(mdata->base); + goto err_put_ctlr; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq (%d)\n", irq); + ret = irq; + goto err_put_ctlr; + } + + ret = devm_request_irq(&pdev->dev, irq, mtk_spi_slave_interrupt, + IRQF_TRIGGER_NONE, dev_name(&pdev->dev), ctlr); + if (ret) { + dev_err(&pdev->dev, "failed to register irq (%d)\n", ret); + goto err_put_ctlr; + } + + mdata->spi_clk = devm_clk_get(&pdev->dev, "spi"); + if (IS_ERR(mdata->spi_clk)) { + ret = PTR_ERR(mdata->spi_clk); + dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret); + goto err_put_ctlr; + } + + ret = clk_prepare_enable(mdata->spi_clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret); + goto err_put_ctlr; + } + + pm_runtime_enable(&pdev->dev); + + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret) { + dev_err(&pdev->dev, + "failed to register slave controller(%d)\n", ret); + clk_disable_unprepare(mdata->spi_clk); + goto err_disable_runtime_pm; + } + + clk_disable_unprepare(mdata->spi_clk); + + return 0; + +err_disable_runtime_pm: + pm_runtime_disable(&pdev->dev); +err_put_ctlr: + spi_controller_put(ctlr); + + return ret; +} + +static int mtk_spi_slave_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mtk_spi_slave_suspend(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + int ret; + + ret = spi_controller_suspend(ctlr); + if (ret) + return ret; + + if (!pm_runtime_suspended(dev)) + clk_disable_unprepare(mdata->spi_clk); + + return ret; +} + +static int mtk_spi_slave_resume(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + int ret; + + if (!pm_runtime_suspended(dev)) { + ret = clk_prepare_enable(mdata->spi_clk); + if (ret < 0) { + dev_err(dev, "failed to enable spi_clk (%d)\n", ret); + return ret; + } + } + + ret = spi_controller_resume(ctlr); + if (ret < 0) + clk_disable_unprepare(mdata->spi_clk); + + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int mtk_spi_slave_runtime_suspend(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + + clk_disable_unprepare(mdata->spi_clk); + + return 0; +} + +static int mtk_spi_slave_runtime_resume(struct device *dev) +{ + struct spi_controller *ctlr = dev_get_drvdata(dev); + struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + int ret; + + ret = clk_prepare_enable(mdata->spi_clk); + if (ret < 0) { + dev_err(dev, "failed to enable spi_clk (%d)\n", ret); + return ret; + } + + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops mtk_spi_slave_pm = { + SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_slave_suspend, mtk_spi_slave_resume) + SET_RUNTIME_PM_OPS(mtk_spi_slave_runtime_suspend, + mtk_spi_slave_runtime_resume, NULL) +}; + +static struct platform_driver mtk_spi_slave_driver = { + .driver = { + .name = "mtk-spi-slave", + .pm = &mtk_spi_slave_pm, + .of_match_table = mtk_spi_slave_of_match, + }, + .probe = mtk_spi_slave_probe, + .remove = mtk_spi_slave_remove, +}; + +module_platform_driver(mtk_spi_slave_driver); + +MODULE_DESCRIPTION("MTK SPI Slave Controller driver"); +MODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mtk-spi-slave"); diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c index c0257e937995..169f3d595f60 100644 --- a/drivers/spi/spi-slave-system-control.c +++ b/drivers/spi/spi-slave-system-control.c @@ -60,6 +60,7 @@ static void spi_slave_system_control_complete(void *arg) case CMD_REBOOT: dev_info(&priv->spi->dev, "Rebooting system...\n"); kernel_restart(NULL); + break; case CMD_POWEROFF: dev_info(&priv->spi->dev, "Powering off system...\n"); diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c new file mode 100644 index 000000000000..8daa24eec624 --- /dev/null +++ b/drivers/spi/spi-sprd.c @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Spreadtrum Communications Inc. + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> + +#define SPRD_SPI_TXD 0x0 +#define SPRD_SPI_CLKD 0x4 +#define SPRD_SPI_CTL0 0x8 +#define SPRD_SPI_CTL1 0xc +#define SPRD_SPI_CTL2 0x10 +#define SPRD_SPI_CTL3 0x14 +#define SPRD_SPI_CTL4 0x18 +#define SPRD_SPI_CTL5 0x1c +#define SPRD_SPI_INT_EN 0x20 +#define SPRD_SPI_INT_CLR 0x24 +#define SPRD_SPI_INT_RAW_STS 0x28 +#define SPRD_SPI_INT_MASK_STS 0x2c +#define SPRD_SPI_STS1 0x30 +#define SPRD_SPI_STS2 0x34 +#define SPRD_SPI_DSP_WAIT 0x38 +#define SPRD_SPI_STS3 0x3c +#define SPRD_SPI_CTL6 0x40 +#define SPRD_SPI_STS4 0x44 +#define SPRD_SPI_FIFO_RST 0x48 +#define SPRD_SPI_CTL7 0x4c +#define SPRD_SPI_STS5 0x50 +#define SPRD_SPI_CTL8 0x54 +#define SPRD_SPI_CTL9 0x58 +#define SPRD_SPI_CTL10 0x5c +#define SPRD_SPI_CTL11 0x60 +#define SPRD_SPI_CTL12 0x64 +#define SPRD_SPI_STS6 0x68 +#define SPRD_SPI_STS7 0x6c +#define SPRD_SPI_STS8 0x70 +#define SPRD_SPI_STS9 0x74 + +/* Bits & mask definition for register CTL0 */ +#define SPRD_SPI_SCK_REV BIT(13) +#define SPRD_SPI_NG_TX BIT(1) +#define SPRD_SPI_NG_RX BIT(0) +#define SPRD_SPI_CHNL_LEN_MASK GENMASK(4, 0) +#define SPRD_SPI_CSN_MASK GENMASK(11, 8) +#define SPRD_SPI_CS0_VALID BIT(8) + +/* Bits & mask definition for register SPI_INT_EN */ +#define SPRD_SPI_TX_END_INT_EN BIT(8) +#define SPRD_SPI_RX_END_INT_EN BIT(9) + +/* Bits & mask definition for register SPI_INT_RAW_STS */ +#define SPRD_SPI_TX_END_RAW BIT(8) +#define SPRD_SPI_RX_END_RAW BIT(9) + +/* Bits & mask definition for register SPI_INT_CLR */ +#define SPRD_SPI_TX_END_CLR BIT(8) +#define SPRD_SPI_RX_END_CLR BIT(9) + +/* Bits & mask definition for register INT_MASK_STS */ +#define SPRD_SPI_MASK_RX_END BIT(9) +#define SPRD_SPI_MASK_TX_END BIT(8) + +/* Bits & mask definition for register STS2 */ +#define SPRD_SPI_TX_BUSY BIT(8) + +/* Bits & mask definition for register CTL1 */ +#define SPRD_SPI_RX_MODE BIT(12) +#define SPRD_SPI_TX_MODE BIT(13) +#define SPRD_SPI_RTX_MD_MASK GENMASK(13, 12) + +/* Bits & mask definition for register CTL2 */ +#define SPRD_SPI_DMA_EN BIT(6) + +/* Bits & mask definition for register CTL4 */ +#define SPRD_SPI_START_RX BIT(9) +#define SPRD_SPI_ONLY_RECV_MASK GENMASK(8, 0) + +/* Bits & mask definition for register SPI_INT_CLR */ +#define SPRD_SPI_RX_END_INT_CLR BIT(9) +#define SPRD_SPI_TX_END_INT_CLR BIT(8) + +/* Bits & mask definition for register SPI_INT_RAW */ +#define SPRD_SPI_RX_END_IRQ BIT(9) +#define SPRD_SPI_TX_END_IRQ BIT(8) + +/* Bits & mask definition for register CTL12 */ +#define SPRD_SPI_SW_RX_REQ BIT(0) +#define SPRD_SPI_SW_TX_REQ BIT(1) + +/* Bits & mask definition for register CTL7 */ +#define SPRD_SPI_DATA_LINE2_EN BIT(15) +#define SPRD_SPI_MODE_MASK GENMASK(5, 3) +#define SPRD_SPI_MODE_OFFSET 3 +#define SPRD_SPI_3WIRE_MODE 4 +#define SPRD_SPI_4WIRE_MODE 0 + +/* Bits & mask definition for register CTL8 */ +#define SPRD_SPI_TX_MAX_LEN_MASK GENMASK(19, 0) +#define SPRD_SPI_TX_LEN_H_MASK GENMASK(3, 0) +#define SPRD_SPI_TX_LEN_H_OFFSET 16 + +/* Bits & mask definition for register CTL9 */ +#define SPRD_SPI_TX_LEN_L_MASK GENMASK(15, 0) + +/* Bits & mask definition for register CTL10 */ +#define SPRD_SPI_RX_MAX_LEN_MASK GENMASK(19, 0) +#define SPRD_SPI_RX_LEN_H_MASK GENMASK(3, 0) +#define SPRD_SPI_RX_LEN_H_OFFSET 16 + +/* Bits & mask definition for register CTL11 */ +#define SPRD_SPI_RX_LEN_L_MASK GENMASK(15, 0) + +/* Default & maximum word delay cycles */ +#define SPRD_SPI_MIN_DELAY_CYCLE 14 +#define SPRD_SPI_MAX_DELAY_CYCLE 130 + +#define SPRD_SPI_FIFO_SIZE 32 +#define SPRD_SPI_CHIP_CS_NUM 0x4 +#define SPRD_SPI_CHNL_LEN 2 +#define SPRD_SPI_DEFAULT_SOURCE 26000000 +#define SPRD_SPI_MAX_SPEED_HZ 48000000 +#define SPRD_SPI_AUTOSUSPEND_DELAY 100 + +struct sprd_spi { + void __iomem *base; + struct device *dev; + struct clk *clk; + u32 src_clk; + u32 hw_mode; + u32 trans_len; + u32 trans_mode; + u32 word_delay; + u32 hw_speed_hz; + u32 len; + int status; + const void *tx_buf; + void *rx_buf; + int (*read_bufs)(struct sprd_spi *ss, u32 len); + int (*write_bufs)(struct sprd_spi *ss, u32 len); +}; + +static u32 sprd_spi_transfer_max_timeout(struct sprd_spi *ss, + struct spi_transfer *t) +{ + /* + * The time spent on transmission of the full FIFO data is the maximum + * SPI transmission time. + */ + u32 size = t->bits_per_word * SPRD_SPI_FIFO_SIZE; + u32 bit_time_us = DIV_ROUND_UP(USEC_PER_SEC, ss->hw_speed_hz); + u32 total_time_us = size * bit_time_us; + /* + * There is an interval between data and the data in our SPI hardware, + * so the total transmission time need add the interval time. + */ + u32 interval_cycle = SPRD_SPI_FIFO_SIZE * ss->word_delay; + u32 interval_time_us = DIV_ROUND_UP(interval_cycle * USEC_PER_SEC, + ss->src_clk); + + return total_time_us + interval_time_us; +} + +static int sprd_spi_wait_for_tx_end(struct sprd_spi *ss, struct spi_transfer *t) +{ + u32 val, us; + int ret; + + us = sprd_spi_transfer_max_timeout(ss, t); + ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val, + val & SPRD_SPI_TX_END_IRQ, 0, us); + if (ret) { + dev_err(ss->dev, "SPI error, spi send timeout!\n"); + return ret; + } + + ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_STS2, val, + !(val & SPRD_SPI_TX_BUSY), 0, us); + if (ret) { + dev_err(ss->dev, "SPI error, spi busy timeout!\n"); + return ret; + } + + writel_relaxed(SPRD_SPI_TX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR); + + return 0; +} + +static int sprd_spi_wait_for_rx_end(struct sprd_spi *ss, struct spi_transfer *t) +{ + u32 val, us; + int ret; + + us = sprd_spi_transfer_max_timeout(ss, t); + ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val, + val & SPRD_SPI_RX_END_IRQ, 0, us); + if (ret) { + dev_err(ss->dev, "SPI error, spi rx timeout!\n"); + return ret; + } + + writel_relaxed(SPRD_SPI_RX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR); + + return 0; +} + +static void sprd_spi_tx_req(struct sprd_spi *ss) +{ + writel_relaxed(SPRD_SPI_SW_TX_REQ, ss->base + SPRD_SPI_CTL12); +} + +static void sprd_spi_rx_req(struct sprd_spi *ss) +{ + writel_relaxed(SPRD_SPI_SW_RX_REQ, ss->base + SPRD_SPI_CTL12); +} + +static void sprd_spi_enter_idle(struct sprd_spi *ss) +{ + u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL1); + + val &= ~SPRD_SPI_RTX_MD_MASK; + writel_relaxed(val, ss->base + SPRD_SPI_CTL1); +} + +static void sprd_spi_set_transfer_bits(struct sprd_spi *ss, u32 bits) +{ + u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL0); + + /* Set the valid bits for every transaction */ + val &= ~(SPRD_SPI_CHNL_LEN_MASK << SPRD_SPI_CHNL_LEN); + val |= bits << SPRD_SPI_CHNL_LEN; + writel_relaxed(val, ss->base + SPRD_SPI_CTL0); +} + +static void sprd_spi_set_tx_length(struct sprd_spi *ss, u32 length) +{ + u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL8); + + length &= SPRD_SPI_TX_MAX_LEN_MASK; + val &= ~SPRD_SPI_TX_LEN_H_MASK; + val |= length >> SPRD_SPI_TX_LEN_H_OFFSET; + writel_relaxed(val, ss->base + SPRD_SPI_CTL8); + + val = length & SPRD_SPI_TX_LEN_L_MASK; + writel_relaxed(val, ss->base + SPRD_SPI_CTL9); +} + +static void sprd_spi_set_rx_length(struct sprd_spi *ss, u32 length) +{ + u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL10); + + length &= SPRD_SPI_RX_MAX_LEN_MASK; + val &= ~SPRD_SPI_RX_LEN_H_MASK; + val |= length >> SPRD_SPI_RX_LEN_H_OFFSET; + writel_relaxed(val, ss->base + SPRD_SPI_CTL10); + + val = length & SPRD_SPI_RX_LEN_L_MASK; + writel_relaxed(val, ss->base + SPRD_SPI_CTL11); +} + +static void sprd_spi_chipselect(struct spi_device *sdev, bool cs) +{ + struct spi_controller *sctlr = sdev->controller; + struct sprd_spi *ss = spi_controller_get_devdata(sctlr); + u32 val; + + val = readl_relaxed(ss->base + SPRD_SPI_CTL0); + /* The SPI controller will pull down CS pin if cs is 0 */ + if (!cs) { + val &= ~SPRD_SPI_CS0_VALID; + writel_relaxed(val, ss->base + SPRD_SPI_CTL0); + } else { + val |= SPRD_SPI_CSN_MASK; + writel_relaxed(val, ss->base + SPRD_SPI_CTL0); + } +} + +static int sprd_spi_write_only_receive(struct sprd_spi *ss, u32 len) +{ + u32 val; + + /* Clear the start receive bit and reset receive data number */ + val = readl_relaxed(ss->base + SPRD_SPI_CTL4); + val &= ~(SPRD_SPI_START_RX | SPRD_SPI_ONLY_RECV_MASK); + writel_relaxed(val, ss->base + SPRD_SPI_CTL4); + + /* Set the receive data length */ + val = readl_relaxed(ss->base + SPRD_SPI_CTL4); + val |= len & SPRD_SPI_ONLY_RECV_MASK; + writel_relaxed(val, ss->base + SPRD_SPI_CTL4); + + /* Trigger to receive data */ + val = readl_relaxed(ss->base + SPRD_SPI_CTL4); + val |= SPRD_SPI_START_RX; + writel_relaxed(val, ss->base + SPRD_SPI_CTL4); + + return len; +} + +static int sprd_spi_write_bufs_u8(struct sprd_spi *ss, u32 len) +{ + u8 *tx_p = (u8 *)ss->tx_buf; + int i; + + for (i = 0; i < len; i++) + writeb_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); + + ss->tx_buf += i; + return i; +} + +static int sprd_spi_write_bufs_u16(struct sprd_spi *ss, u32 len) +{ + u16 *tx_p = (u16 *)ss->tx_buf; + int i; + + for (i = 0; i < len; i++) + writew_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); + + ss->tx_buf += i << 1; + return i << 1; +} + +static int sprd_spi_write_bufs_u32(struct sprd_spi *ss, u32 len) +{ + u32 *tx_p = (u32 *)ss->tx_buf; + int i; + + for (i = 0; i < len; i++) + writel_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); + + ss->tx_buf += i << 2; + return i << 2; +} + +static int sprd_spi_read_bufs_u8(struct sprd_spi *ss, u32 len) +{ + u8 *rx_p = (u8 *)ss->rx_buf; + int i; + + for (i = 0; i < len; i++) + rx_p[i] = readb_relaxed(ss->base + SPRD_SPI_TXD); + + ss->rx_buf += i; + return i; +} + +static int sprd_spi_read_bufs_u16(struct sprd_spi *ss, u32 len) +{ + u16 *rx_p = (u16 *)ss->rx_buf; + int i; + + for (i = 0; i < len; i++) + rx_p[i] = readw_relaxed(ss->base + SPRD_SPI_TXD); + + ss->rx_buf += i << 1; + return i << 1; +} + +static int sprd_spi_read_bufs_u32(struct sprd_spi *ss, u32 len) +{ + u32 *rx_p = (u32 *)ss->rx_buf; + int i; + + for (i = 0; i < len; i++) + rx_p[i] = readl_relaxed(ss->base + SPRD_SPI_TXD); + + ss->rx_buf += i << 2; + return i << 2; +} + +static int sprd_spi_txrx_bufs(struct spi_device *sdev, struct spi_transfer *t) +{ + struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); + u32 trans_len = ss->trans_len, len; + int ret, write_size = 0; + + while (trans_len) { + len = trans_len > SPRD_SPI_FIFO_SIZE ? SPRD_SPI_FIFO_SIZE : + trans_len; + if (ss->trans_mode & SPRD_SPI_TX_MODE) { + sprd_spi_set_tx_length(ss, len); + write_size += ss->write_bufs(ss, len); + + /* + * For our 3 wires mode or dual TX line mode, we need + * to request the controller to transfer. + */ + if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) + sprd_spi_tx_req(ss); + + ret = sprd_spi_wait_for_tx_end(ss, t); + } else { + sprd_spi_set_rx_length(ss, len); + + /* + * For our 3 wires mode or dual TX line mode, we need + * to request the controller to read. + */ + if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) + sprd_spi_rx_req(ss); + else + write_size += ss->write_bufs(ss, len); + + ret = sprd_spi_wait_for_rx_end(ss, t); + } + + if (ret) + goto complete; + + if (ss->trans_mode & SPRD_SPI_RX_MODE) + ss->read_bufs(ss, len); + + trans_len -= len; + } + + ret = write_size; + +complete: + sprd_spi_enter_idle(ss); + + return ret; +} + +static void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz) +{ + /* + * From SPI datasheet, the prescale calculation formula: + * prescale = SPI source clock / (2 * SPI_freq) - 1; + */ + u32 clk_div = DIV_ROUND_UP(ss->src_clk, speed_hz << 1) - 1; + + /* Save the real hardware speed */ + ss->hw_speed_hz = (ss->src_clk >> 1) / (clk_div + 1); + writel_relaxed(clk_div, ss->base + SPRD_SPI_CLKD); +} + +static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t) +{ + u16 word_delay, interval; + u32 val; + + val = readl_relaxed(ss->base + SPRD_SPI_CTL7); + val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX); + /* Set default chip selection, clock phase and clock polarity */ + val |= ss->hw_mode & SPI_CPHA ? SPRD_SPI_NG_RX : SPRD_SPI_NG_TX; + val |= ss->hw_mode & SPI_CPOL ? SPRD_SPI_SCK_REV : 0; + writel_relaxed(val, ss->base + SPRD_SPI_CTL0); + + /* + * Set the intervals of two SPI frames, and the inteval calculation + * formula as below per datasheet: + * interval time (source clock cycles) = interval * 4 + 10. + */ + word_delay = clamp_t(u16, t->word_delay, SPRD_SPI_MIN_DELAY_CYCLE, + SPRD_SPI_MAX_DELAY_CYCLE); + interval = DIV_ROUND_UP(word_delay - 10, 4); + ss->word_delay = interval * 4 + 10; + writel_relaxed(interval, ss->base + SPRD_SPI_CTL5); + + /* Reset SPI fifo */ + writel_relaxed(1, ss->base + SPRD_SPI_FIFO_RST); + writel_relaxed(0, ss->base + SPRD_SPI_FIFO_RST); + + /* Set SPI work mode */ + val = readl_relaxed(ss->base + SPRD_SPI_CTL7); + val &= ~SPRD_SPI_MODE_MASK; + + if (ss->hw_mode & SPI_3WIRE) + val |= SPRD_SPI_3WIRE_MODE << SPRD_SPI_MODE_OFFSET; + else + val |= SPRD_SPI_4WIRE_MODE << SPRD_SPI_MODE_OFFSET; + + if (ss->hw_mode & SPI_TX_DUAL) + val |= SPRD_SPI_DATA_LINE2_EN; + else + val &= ~SPRD_SPI_DATA_LINE2_EN; + + writel_relaxed(val, ss->base + SPRD_SPI_CTL7); +} + +static int sprd_spi_setup_transfer(struct spi_device *sdev, + struct spi_transfer *t) +{ + struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); + u8 bits_per_word = t->bits_per_word; + u32 val, mode = 0; + + ss->len = t->len; + ss->tx_buf = t->tx_buf; + ss->rx_buf = t->rx_buf; + + ss->hw_mode = sdev->mode; + sprd_spi_init_hw(ss, t); + + /* Set tansfer speed and valid bits */ + sprd_spi_set_speed(ss, t->speed_hz); + sprd_spi_set_transfer_bits(ss, bits_per_word); + + if (bits_per_word > 16) + bits_per_word = round_up(bits_per_word, 16); + else + bits_per_word = round_up(bits_per_word, 8); + + switch (bits_per_word) { + case 8: + ss->trans_len = t->len; + ss->read_bufs = sprd_spi_read_bufs_u8; + ss->write_bufs = sprd_spi_write_bufs_u8; + break; + case 16: + ss->trans_len = t->len >> 1; + ss->read_bufs = sprd_spi_read_bufs_u16; + ss->write_bufs = sprd_spi_write_bufs_u16; + break; + case 32: + ss->trans_len = t->len >> 2; + ss->read_bufs = sprd_spi_read_bufs_u32; + ss->write_bufs = sprd_spi_write_bufs_u32; + break; + default: + return -EINVAL; + } + + /* Set transfer read or write mode */ + val = readl_relaxed(ss->base + SPRD_SPI_CTL1); + val &= ~SPRD_SPI_RTX_MD_MASK; + if (t->tx_buf) + mode |= SPRD_SPI_TX_MODE; + if (t->rx_buf) + mode |= SPRD_SPI_RX_MODE; + + writel_relaxed(val | mode, ss->base + SPRD_SPI_CTL1); + + ss->trans_mode = mode; + + /* + * If in only receive mode, we need to trigger the SPI controller to + * receive data automatically. + */ + if (ss->trans_mode == SPRD_SPI_RX_MODE) + ss->write_bufs = sprd_spi_write_only_receive; + + return 0; +} + +static int sprd_spi_transfer_one(struct spi_controller *sctlr, + struct spi_device *sdev, + struct spi_transfer *t) +{ + int ret; + + ret = sprd_spi_setup_transfer(sdev, t); + if (ret) + goto setup_err; + + ret = sprd_spi_txrx_bufs(sdev, t); + if (ret == t->len) + ret = 0; + else if (ret >= 0) + ret = -EREMOTEIO; + +setup_err: + spi_finalize_current_transfer(sctlr); + + return ret; +} + +static int sprd_spi_clk_init(struct platform_device *pdev, struct sprd_spi *ss) +{ + struct clk *clk_spi, *clk_parent; + + clk_spi = devm_clk_get(&pdev->dev, "spi"); + if (IS_ERR(clk_spi)) { + dev_warn(&pdev->dev, "can't get the spi clock\n"); + clk_spi = NULL; + } + + clk_parent = devm_clk_get(&pdev->dev, "source"); + if (IS_ERR(clk_parent)) { + dev_warn(&pdev->dev, "can't get the source clock\n"); + clk_parent = NULL; + } + + ss->clk = devm_clk_get(&pdev->dev, "enable"); + if (IS_ERR(ss->clk)) { + dev_err(&pdev->dev, "can't get the enable clock\n"); + return PTR_ERR(ss->clk); + } + + if (!clk_set_parent(clk_spi, clk_parent)) + ss->src_clk = clk_get_rate(clk_spi); + else + ss->src_clk = SPRD_SPI_DEFAULT_SOURCE; + + return 0; +} + +static int sprd_spi_probe(struct platform_device *pdev) +{ + struct spi_controller *sctlr; + struct resource *res; + struct sprd_spi *ss; + int ret; + + pdev->id = of_alias_get_id(pdev->dev.of_node, "spi"); + sctlr = spi_alloc_master(&pdev->dev, sizeof(*ss)); + if (!sctlr) + return -ENOMEM; + + ss = spi_controller_get_devdata(sctlr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ss->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ss->base)) { + ret = PTR_ERR(ss->base); + goto free_controller; + } + + ss->dev = &pdev->dev; + sctlr->dev.of_node = pdev->dev.of_node; + sctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE | SPI_TX_DUAL; + sctlr->bus_num = pdev->id; + sctlr->set_cs = sprd_spi_chipselect; + sctlr->transfer_one = sprd_spi_transfer_one; + sctlr->auto_runtime_pm = true; + sctlr->max_speed_hz = min_t(u32, ss->src_clk >> 1, + SPRD_SPI_MAX_SPEED_HZ); + + platform_set_drvdata(pdev, sctlr); + ret = sprd_spi_clk_init(pdev, ss); + if (ret) + goto free_controller; + + ret = clk_prepare_enable(ss->clk); + if (ret) + goto free_controller; + + ret = pm_runtime_set_active(&pdev->dev); + if (ret < 0) + goto disable_clk; + + pm_runtime_set_autosuspend_delay(&pdev->dev, + SPRD_SPI_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to resume SPI controller\n"); + goto err_rpm_put; + } + + ret = devm_spi_register_controller(&pdev->dev, sctlr); + if (ret) + goto err_rpm_put; + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + return 0; + +err_rpm_put: + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); +disable_clk: + clk_disable_unprepare(ss->clk); +free_controller: + spi_controller_put(sctlr); + + return ret; +} + +static int sprd_spi_remove(struct platform_device *pdev) +{ + struct spi_controller *sctlr = platform_get_drvdata(pdev); + struct sprd_spi *ss = spi_controller_get_devdata(sctlr); + int ret; + + ret = pm_runtime_get_sync(ss->dev); + if (ret < 0) { + dev_err(ss->dev, "failed to resume SPI controller\n"); + return ret; + } + + clk_disable_unprepare(ss->clk); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int __maybe_unused sprd_spi_runtime_suspend(struct device *dev) +{ + struct spi_controller *sctlr = dev_get_drvdata(dev); + struct sprd_spi *ss = spi_controller_get_devdata(sctlr); + + clk_disable_unprepare(ss->clk); + + return 0; +} + +static int __maybe_unused sprd_spi_runtime_resume(struct device *dev) +{ + struct spi_controller *sctlr = dev_get_drvdata(dev); + struct sprd_spi *ss = spi_controller_get_devdata(sctlr); + int ret; + + ret = clk_prepare_enable(ss->clk); + if (ret) + return ret; + + return 0; +} + +static const struct dev_pm_ops sprd_spi_pm_ops = { + SET_RUNTIME_PM_OPS(sprd_spi_runtime_suspend, + sprd_spi_runtime_resume, NULL) +}; + +static const struct of_device_id sprd_spi_of_match[] = { + { .compatible = "sprd,sc9860-spi", }, + { /* sentinel */ } +}; + +static struct platform_driver sprd_spi_driver = { + .driver = { + .name = "sprd-spi", + .of_match_table = sprd_spi_of_match, + .pm = &sprd_spi_pm_ops, + }, + .probe = sprd_spi_probe, + .remove = sprd_spi_remove, +}; + +module_platform_driver(sprd_spi_driver); + +MODULE_DESCRIPTION("Spreadtrum SPI Controller driver"); +MODULE_AUTHOR("Lanqing Liu <lanqing.liu@spreadtrum.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c new file mode 100644 index 000000000000..3b2a9a6b990d --- /dev/null +++ b/drivers/spi/spi-stm32-qspi.c @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics. + */ +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/sizes.h> +#include <linux/spi/spi-mem.h> + +#define QSPI_CR 0x00 +#define CR_EN BIT(0) +#define CR_ABORT BIT(1) +#define CR_DMAEN BIT(2) +#define CR_TCEN BIT(3) +#define CR_SSHIFT BIT(4) +#define CR_DFM BIT(6) +#define CR_FSEL BIT(7) +#define CR_FTHRES_MASK GENMASK(12, 8) +#define CR_TEIE BIT(16) +#define CR_TCIE BIT(17) +#define CR_FTIE BIT(18) +#define CR_SMIE BIT(19) +#define CR_TOIE BIT(20) +#define CR_PRESC_MASK GENMASK(31, 24) + +#define QSPI_DCR 0x04 +#define DCR_FSIZE_MASK GENMASK(20, 16) + +#define QSPI_SR 0x08 +#define SR_TEF BIT(0) +#define SR_TCF BIT(1) +#define SR_FTF BIT(2) +#define SR_SMF BIT(3) +#define SR_TOF BIT(4) +#define SR_BUSY BIT(5) +#define SR_FLEVEL_MASK GENMASK(13, 8) + +#define QSPI_FCR 0x0c +#define FCR_CTEF BIT(0) +#define FCR_CTCF BIT(1) + +#define QSPI_DLR 0x10 + +#define QSPI_CCR 0x14 +#define CCR_INST_MASK GENMASK(7, 0) +#define CCR_IMODE_MASK GENMASK(9, 8) +#define CCR_ADMODE_MASK GENMASK(11, 10) +#define CCR_ADSIZE_MASK GENMASK(13, 12) +#define CCR_DCYC_MASK GENMASK(22, 18) +#define CCR_DMODE_MASK GENMASK(25, 24) +#define CCR_FMODE_MASK GENMASK(27, 26) +#define CCR_FMODE_INDW (0U << 26) +#define CCR_FMODE_INDR (1U << 26) +#define CCR_FMODE_APM (2U << 26) +#define CCR_FMODE_MM (3U << 26) +#define CCR_BUSWIDTH_0 0x0 +#define CCR_BUSWIDTH_1 0x1 +#define CCR_BUSWIDTH_2 0x2 +#define CCR_BUSWIDTH_4 0x3 + +#define QSPI_AR 0x18 +#define QSPI_ABR 0x1c +#define QSPI_DR 0x20 +#define QSPI_PSMKR 0x24 +#define QSPI_PSMAR 0x28 +#define QSPI_PIR 0x2c +#define QSPI_LPTR 0x30 +#define LPTR_DFT_TIMEOUT 0x10 + +#define STM32_QSPI_MAX_MMAP_SZ SZ_256M +#define STM32_QSPI_MAX_NORCHIP 2 + +#define STM32_FIFO_TIMEOUT_US 30000 +#define STM32_BUSY_TIMEOUT_US 100000 +#define STM32_ABT_TIMEOUT_US 100000 + +struct stm32_qspi_flash { + struct stm32_qspi *qspi; + u32 cs; + u32 presc; +}; + +struct stm32_qspi { + struct device *dev; + void __iomem *io_base; + void __iomem *mm_base; + resource_size_t mm_size; + struct clk *clk; + u32 clk_rate; + struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP]; + struct completion data_completion; + u32 fmode; + + /* + * to protect device configuration, could be different between + * 2 flash access (bk1, bk2) + */ + struct mutex lock; +}; + +static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) +{ + struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; + u32 cr, sr; + + sr = readl_relaxed(qspi->io_base + QSPI_SR); + + if (sr & (SR_TEF | SR_TCF)) { + /* disable irq */ + cr = readl_relaxed(qspi->io_base + QSPI_CR); + cr &= ~CR_TCIE & ~CR_TEIE; + writel_relaxed(cr, qspi->io_base + QSPI_CR); + complete(&qspi->data_completion); + } + + return IRQ_HANDLED; +} + +static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr) +{ + *val = readb_relaxed(addr); +} + +static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr) +{ + writeb_relaxed(*val, addr); +} + +static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + void (*tx_fifo)(u8 *val, void __iomem *addr); + u32 len = op->data.nbytes, sr; + u8 *buf; + int ret; + + if (op->data.dir == SPI_MEM_DATA_IN) { + tx_fifo = stm32_qspi_read_fifo; + buf = op->data.buf.in; + + } else { + tx_fifo = stm32_qspi_write_fifo; + buf = (u8 *)op->data.buf.out; + } + + while (len--) { + ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, + sr, (sr & SR_FTF), 1, + STM32_FIFO_TIMEOUT_US); + if (ret) { + dev_err(qspi->dev, "fifo timeout (len:%d stat:%#x)\n", + len, sr); + return ret; + } + tx_fifo(buf++, qspi->io_base + QSPI_DR); + } + + return 0; +} + +static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + memcpy_fromio(op->data.buf.in, qspi->mm_base + op->addr.val, + op->data.nbytes); + return 0; +} + +static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) +{ + if (!op->data.nbytes) + return 0; + + if (qspi->fmode == CCR_FMODE_MM) + return stm32_qspi_tx_mm(qspi, op); + + return stm32_qspi_tx_poll(qspi, op); +} + +static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) +{ + u32 sr; + + return readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr, + !(sr & SR_BUSY), 1, + STM32_BUSY_TIMEOUT_US); +} + +static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + u32 cr, sr; + int err = 0; + + if (!op->data.nbytes) + return stm32_qspi_wait_nobusy(qspi); + + if (readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) + goto out; + + reinit_completion(&qspi->data_completion); + cr = readl_relaxed(qspi->io_base + QSPI_CR); + writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); + + if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, + msecs_to_jiffies(1000))) { + err = -ETIMEDOUT; + } else { + sr = readl_relaxed(qspi->io_base + QSPI_SR); + if (sr & SR_TEF) + err = -EIO; + } + +out: + /* clear flags */ + writel_relaxed(FCR_CTCF | FCR_CTEF, qspi->io_base + QSPI_FCR); + + return err; +} + +static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth) +{ + if (buswidth == 4) + return CCR_BUSWIDTH_4; + + return buswidth; +} + +static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); + struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; + u32 ccr, cr, addr_max; + int timeout, err = 0; + + dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", + op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, + op->dummy.buswidth, op->data.buswidth, + op->addr.val, op->data.nbytes); + + err = stm32_qspi_wait_nobusy(qspi); + if (err) + goto abort; + + addr_max = op->addr.val + op->data.nbytes + 1; + + if (op->data.dir == SPI_MEM_DATA_IN) { + if (addr_max < qspi->mm_size && + op->addr.buswidth) + qspi->fmode = CCR_FMODE_MM; + else + qspi->fmode = CCR_FMODE_INDR; + } else { + qspi->fmode = CCR_FMODE_INDW; + } + + cr = readl_relaxed(qspi->io_base + QSPI_CR); + cr &= ~CR_PRESC_MASK & ~CR_FSEL; + cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); + cr |= FIELD_PREP(CR_FSEL, flash->cs); + writel_relaxed(cr, qspi->io_base + QSPI_CR); + + if (op->data.nbytes) + writel_relaxed(op->data.nbytes - 1, + qspi->io_base + QSPI_DLR); + else + qspi->fmode = CCR_FMODE_INDW; + + ccr = qspi->fmode; + ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); + ccr |= FIELD_PREP(CCR_IMODE_MASK, + stm32_qspi_get_mode(qspi, op->cmd.buswidth)); + + if (op->addr.nbytes) { + ccr |= FIELD_PREP(CCR_ADMODE_MASK, + stm32_qspi_get_mode(qspi, op->addr.buswidth)); + ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1); + } + + if (op->dummy.buswidth && op->dummy.nbytes) + ccr |= FIELD_PREP(CCR_DCYC_MASK, + op->dummy.nbytes * 8 / op->dummy.buswidth); + + if (op->data.nbytes) { + ccr |= FIELD_PREP(CCR_DMODE_MASK, + stm32_qspi_get_mode(qspi, op->data.buswidth)); + } + + writel_relaxed(ccr, qspi->io_base + QSPI_CCR); + + if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM) + writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); + + err = stm32_qspi_tx(qspi, op); + + /* + * Abort in: + * -error case + * -read memory map: prefetching must be stopped if we read the last + * byte of device (device size - fifo size). like device size is not + * knows, the prefetching is always stop. + */ + if (err || qspi->fmode == CCR_FMODE_MM) + goto abort; + + /* wait end of tx in indirect mode */ + err = stm32_qspi_wait_cmd(qspi, op); + if (err) + goto abort; + + return 0; + +abort: + cr = readl_relaxed(qspi->io_base + QSPI_CR) | CR_ABORT; + writel_relaxed(cr, qspi->io_base + QSPI_CR); + + /* wait clear of abort bit by hw */ + timeout = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_CR, + cr, !(cr & CR_ABORT), 1, + STM32_ABT_TIMEOUT_US); + + writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR); + + if (err || timeout) + dev_err(qspi->dev, "%s err:%d abort timeout:%d\n", + __func__, err, timeout); + + return err; +} + +static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); + int ret; + + mutex_lock(&qspi->lock); + ret = stm32_qspi_send(mem, op); + mutex_unlock(&qspi->lock); + + return ret; +} + +static int stm32_qspi_setup(struct spi_device *spi) +{ + struct spi_controller *ctrl = spi->master; + struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); + struct stm32_qspi_flash *flash; + u32 cr, presc; + + if (ctrl->busy) + return -EBUSY; + + if (!spi->max_speed_hz) + return -EINVAL; + + presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; + + flash = &qspi->flash[spi->chip_select]; + flash->qspi = qspi; + flash->cs = spi->chip_select; + flash->presc = presc; + + mutex_lock(&qspi->lock); + writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QSPI_LPTR); + cr = FIELD_PREP(CR_FTHRES_MASK, 3) | CR_TCEN | CR_SSHIFT | CR_EN; + writel_relaxed(cr, qspi->io_base + QSPI_CR); + + /* set dcr fsize to max address */ + writel_relaxed(DCR_FSIZE_MASK, qspi->io_base + QSPI_DCR); + mutex_unlock(&qspi->lock); + + return 0; +} + +/* + * no special host constraint, so use default spi_mem_default_supports_op + * to check supported mode. + */ +static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { + .exec_op = stm32_qspi_exec_op, +}; + +static void stm32_qspi_release(struct stm32_qspi *qspi) +{ + /* disable qspi */ + writel_relaxed(0, qspi->io_base + QSPI_CR); + mutex_destroy(&qspi->lock); + clk_disable_unprepare(qspi->clk); +} + +static int stm32_qspi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_controller *ctrl; + struct reset_control *rstc; + struct stm32_qspi *qspi; + struct resource *res; + int ret, irq; + + ctrl = spi_alloc_master(dev, sizeof(*qspi)); + if (!ctrl) + return -ENOMEM; + + qspi = spi_controller_get_devdata(ctrl); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); + qspi->io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qspi->io_base)) + return PTR_ERR(qspi->io_base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); + qspi->mm_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qspi->mm_base)) + return PTR_ERR(qspi->mm_base); + + qspi->mm_size = resource_size(res); + if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, + dev_name(dev), qspi); + if (ret) { + dev_err(dev, "failed to request irq\n"); + return ret; + } + + init_completion(&qspi->data_completion); + + qspi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(qspi->clk)) + return PTR_ERR(qspi->clk); + + qspi->clk_rate = clk_get_rate(qspi->clk); + if (!qspi->clk_rate) + return -EINVAL; + + ret = clk_prepare_enable(qspi->clk); + if (ret) { + dev_err(dev, "can not enable the clock\n"); + return ret; + } + + rstc = devm_reset_control_get_exclusive(dev, NULL); + if (!IS_ERR(rstc)) { + reset_control_assert(rstc); + udelay(2); + reset_control_deassert(rstc); + } + + qspi->dev = dev; + platform_set_drvdata(pdev, qspi); + mutex_init(&qspi->lock); + + ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD + | SPI_TX_DUAL | SPI_TX_QUAD; + ctrl->setup = stm32_qspi_setup; + ctrl->bus_num = -1; + ctrl->mem_ops = &stm32_qspi_mem_ops; + ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; + ctrl->dev.of_node = dev->of_node; + + ret = devm_spi_register_master(dev, ctrl); + if (ret) + goto err_spi_register; + + return 0; + +err_spi_register: + stm32_qspi_release(qspi); + + return ret; +} + +static int stm32_qspi_remove(struct platform_device *pdev) +{ + struct stm32_qspi *qspi = platform_get_drvdata(pdev); + + stm32_qspi_release(qspi); + return 0; +} + +static const struct of_device_id stm32_qspi_match[] = { + {.compatible = "st,stm32f469-qspi"}, + {} +}; +MODULE_DEVICE_TABLE(of, stm32_qspi_match); + +static struct platform_driver stm32_qspi_driver = { + .probe = stm32_qspi_probe, + .remove = stm32_qspi_remove, + .driver = { + .name = "stm32-qspi", + .of_match_table = stm32_qspi_match, + }, +}; +module_platform_driver(stm32_qspi_driver); + +MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9da0bc5a036c..6ca59406b0b7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * SPI init/core code * * Copyright (C) 2005 David Brownell * Copyright (C) 2008 Secret Lab Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -60,6 +51,7 @@ static void spidev_release(struct device *dev) spi->controller->cleanup(spi); spi_controller_put(spi->controller); + kfree(spi->driver_override); kfree(spi); } @@ -77,6 +69,51 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf) } static DEVICE_ATTR_RO(modalias); +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *a, + const char *buf, size_t count) +{ + struct spi_device *spi = to_spi_device(dev); + const char *end = memchr(buf, '\n', count); + const size_t len = end ? end - buf : count; + const char *driver_override, *old; + + /* We need to keep extra room for a newline when displaying value */ + if (len >= (PAGE_SIZE - 1)) + return -EINVAL; + + driver_override = kstrndup(buf, len, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + device_lock(dev); + old = spi->driver_override; + if (len) { + spi->driver_override = driver_override; + } else { + /* Emptry string, disable driver override */ + spi->driver_override = NULL; + kfree(driver_override); + } + device_unlock(dev); + kfree(old); + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *a, char *buf) +{ + const struct spi_device *spi = to_spi_device(dev); + ssize_t len; + + device_lock(dev); + len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : ""); + device_unlock(dev); + return len; +} +static DEVICE_ATTR_RW(driver_override); + #define SPI_STATISTICS_ATTRS(field, file) \ static ssize_t spi_controller_##field##_show(struct device *dev, \ struct device_attribute *attr, \ @@ -158,6 +195,7 @@ SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu"); static struct attribute *spi_dev_attrs[] = { &dev_attr_modalias.attr, + &dev_attr_driver_override.attr, NULL, }; @@ -305,6 +343,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) const struct spi_device *spi = to_spi_device(dev); const struct spi_driver *sdrv = to_spi_driver(drv); + /* Check override first, and if set, only use the named driver */ + if (spi->driver_override) + return strcmp(spi->driver_override, drv->name) == 0; + /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) return 1; @@ -733,7 +775,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable) enable = !enable; if (gpio_is_valid(spi->cs_gpio)) { - gpio_set_value(spi->cs_gpio, !enable); + /* Honour the SPI_NO_CS flag */ + if (!(spi->mode & SPI_NO_CS)) + gpio_set_value(spi->cs_gpio, !enable); /* Some SPI masters need both GPIO CS & slave_select */ if ((spi->controller->flags & SPI_MASTER_GPIO_SS) && spi->controller->set_cs) @@ -2783,8 +2827,10 @@ int spi_setup(struct spi_device *spi) return -EINVAL; /* help drivers fail *cleanly* when they need options * that aren't supported with their current controller + * SPI_CS_WORD has a fallback software implementation, + * so it is ignored here. */ - bad_bits = spi->mode & ~spi->controller->mode_bits; + bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD); ugly_bits = bad_bits & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD); if (ugly_bits) { @@ -2838,6 +2884,35 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) if (list_empty(&message->transfers)) return -EINVAL; + /* If an SPI controller does not support toggling the CS line on each + * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO + * for the CS line, we can emulate the CS-per-word hardware function by + * splitting transfers into one-word transfers and ensuring that + * cs_change is set for each transfer. + */ + if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) || + gpio_is_valid(spi->cs_gpio))) { + size_t maxsize; + int ret; + + maxsize = (spi->bits_per_word + 7) / 8; + + /* spi_split_transfers_maxsize() requires message->spi */ + message->spi = spi; + + ret = spi_split_transfers_maxsize(ctlr, message, maxsize, + GFP_KERNEL); + if (ret) + return ret; + + list_for_each_entry(xfer, &message->transfers, transfer_list) { + /* don't change cs_change on the last entry in the list */ + if (list_is_last(&xfer->transfer_list, &message->transfers)) + break; + xfer->cs_change = 1; + } + } + /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where * either MOSI or MISO is missing. They can also be caused by @@ -3323,20 +3398,23 @@ EXPORT_SYMBOL_GPL(spi_write_then_read); /*-------------------------------------------------------------------------*/ -#if IS_ENABLED(CONFIG_OF_DYNAMIC) +#if IS_ENABLED(CONFIG_OF) static int __spi_of_device_match(struct device *dev, void *data) { return dev->of_node == data; } /* must call put_device() when done with returned spi_device device */ -static struct spi_device *of_find_spi_device_by_node(struct device_node *node) +struct spi_device *of_find_spi_device_by_node(struct device_node *node) { struct device *dev = bus_find_device(&spi_bus_type, NULL, node, __spi_of_device_match); return dev ? to_spi_device(dev) : NULL; } +EXPORT_SYMBOL_GPL(of_find_spi_device_by_node); +#endif /* IS_ENABLED(CONFIG_OF) */ +#if IS_ENABLED(CONFIG_OF_DYNAMIC) static int __spi_of_controller_match(struct device *dev, const void *data) { return dev->of_node == data; diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index cda10719d1d1..b0c76e2626ce 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -669,6 +669,7 @@ static const struct of_device_id spidev_dt_ids[] = { { .compatible = "lineartechnology,ltc2488" }, { .compatible = "ge,achc" }, { .compatible = "semtech,sx1301" }, + { .compatible = "lwn,bk4" }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); @@ -724,11 +725,9 @@ static int spidev_probe(struct spi_device *spi) * compatible string, it is a Linux implementation thing * rather than a description of the hardware. */ - if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { - dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n"); - WARN_ON(spi->dev.of_node && - !of_match_device(spidev_dt_ids, &spi->dev)); - } + WARN(spi->dev.of_node && + of_device_is_compatible(spi->dev.of_node, "spidev"), + "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node); spidev_probe_acpi(spi); diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 25b9fcd5e3a4..b7810b1aad07 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -202,7 +202,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7606_state *st = iio_priv(indio_dev); - int values[3]; + DECLARE_BITMAP(values, 3); int ret, i; switch (mask) { @@ -227,12 +227,10 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - values[0] = (ret >> 0) & 1; - values[1] = (ret >> 1) & 1; - values[2] = (ret >> 2) & 1; + values[0] = ret; mutex_lock(&st->lock); - gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + gpiod_set_array_value(3, st->gpio_os->desc, st->gpio_os->info, values); st->oversampling = val; mutex_unlock(&st->lock); diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c index 448478451c4c..def8a1f57d1c 100644 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -630,8 +630,7 @@ static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id) } #ifdef CONFIG_MTD_SPINAND_ONDIEECC -static int spinand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, +static int spinand_write_page_hwecc(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { @@ -643,21 +642,22 @@ static int spinand_write_page_hwecc(struct mtd_info *mtd, return nand_prog_page_op(chip, page, 0, p, eccsize * eccsteps); } -static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - u8 *buf, int oob_required, int page) +static int spinand_read_page_hwecc(struct nand_chip *chip, u8 *buf, + int oob_required, int page) { int retval; u8 status; u8 *p = buf; int eccsize = chip->ecc.size; int eccsteps = chip->ecc.steps; + struct mtd_info *mtd = nand_to_mtd(chip); struct spinand_info *info = nand_get_controller_data(chip); enable_read_hw_ecc = 1; nand_read_page_op(chip, page, 0, p, eccsize * eccsteps); if (oob_required) - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); while (1) { retval = spinand_read_status(info->spi, &status); @@ -681,13 +681,13 @@ static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } #endif -static void spinand_select_chip(struct mtd_info *mtd, int dev) +static void spinand_select_chip(struct nand_chip *chip, int dev) { } -static u8 spinand_read_byte(struct mtd_info *mtd) +static u8 spinand_read_byte(struct nand_chip *chip) { - struct spinand_state *state = mtd_to_state(mtd); + struct spinand_state *state = mtd_to_state(nand_to_mtd(chip)); u8 data; data = state->buf[state->buf_ptr]; @@ -695,8 +695,9 @@ static u8 spinand_read_byte(struct mtd_info *mtd) return data; } -static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip) +static int spinand_wait(struct nand_chip *chip) { + struct mtd_info *mtd = nand_to_mtd(chip); struct spinand_info *info = nand_get_controller_data(chip); unsigned long timeo = jiffies; @@ -724,17 +725,17 @@ static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip) return 0; } -static void spinand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void spinand_write_buf(struct nand_chip *chip, const u8 *buf, int len) { - struct spinand_state *state = mtd_to_state(mtd); + struct spinand_state *state = mtd_to_state(nand_to_mtd(chip)); memcpy(state->buf + state->buf_ptr, buf, len); state->buf_ptr += len; } -static void spinand_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void spinand_read_buf(struct nand_chip *chip, u8 *buf, int len) { - struct spinand_state *state = mtd_to_state(mtd); + struct spinand_state *state = mtd_to_state(nand_to_mtd(chip)); memcpy(buf, state->buf + state->buf_ptr, len); state->buf_ptr += len; @@ -759,10 +760,10 @@ static void spinand_reset(struct spi_device *spi_nand) dev_err(&spi_nand->dev, "wait timedout!\n"); } -static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command, +static void spinand_cmdfunc(struct nand_chip *chip, unsigned int command, int column, int page) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct spinand_info *info = nand_get_controller_data(chip); struct spinand_state *state = info->priv; @@ -914,15 +915,15 @@ static int spinand_probe(struct spi_device *spi_nand) nand_set_flash_node(chip, spi_nand->dev.of_node); nand_set_controller_data(chip, info); - chip->read_buf = spinand_read_buf; - chip->write_buf = spinand_write_buf; - chip->read_byte = spinand_read_byte; - chip->cmdfunc = spinand_cmdfunc; - chip->waitfunc = spinand_wait; + chip->legacy.read_buf = spinand_read_buf; + chip->legacy.write_buf = spinand_write_buf; + chip->legacy.read_byte = spinand_read_byte; + chip->legacy.cmdfunc = spinand_cmdfunc; + chip->legacy.waitfunc = spinand_wait; chip->options |= NAND_CACHEPRG; chip->select_chip = spinand_select_chip; - chip->set_features = nand_get_set_features_notsupp; - chip->get_features = nand_get_set_features_notsupp; + chip->legacy.set_features = nand_get_set_features_notsupp; + chip->legacy.get_features = nand_get_set_features_notsupp; mtd = nand_to_mtd(chip); @@ -934,7 +935,7 @@ static int spinand_probe(struct spi_device *spi_nand) mtd_set_ooblayout(mtd, &spinand_oob_64_ops); #endif - if (nand_scan(mtd, 1)) + if (nand_scan(chip, 1)) return -ENXIO; return mtd_device_register(mtd, NULL, 0); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index cb0461a10808..f459118bc11b 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -636,9 +636,9 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) /* * The unmap_zeroes_data set means that the underlying device supports - * REQ_DISCARD and has the discard_zeroes_data bit set. This satisfies - * the SBC requirements for LBPRZ, meaning that a subsequent read - * will return zeroes after an UNMAP or WRITE SAME (16) to an LBA + * REQ_OP_DISCARD and has the discard_zeroes_data bit set. This + * satisfies the SBC requirements for LBPRZ, meaning that a subsequent + * read will return zeroes after an UNMAP or WRITE SAME (16) to an LBA * See sbc4r36 6.6.4. */ if (((dev->dev_attrib.emulate_tpu != 0) || diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index 1e47511a6bd5..d748527d7a38 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c @@ -45,7 +45,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) } static const struct x86_cpu_id soc_thermal_ids[] = { - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1, 0, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, 0, BYT_SOC_DTS_APIC_IRQ}, {} }; diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 1c06325beaca..39ed56214cd3 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -40,7 +40,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) { enum mctrl_gpio_idx i; struct gpio_desc *desc_array[UART_GPIO_MAX]; - int value_array[UART_GPIO_MAX]; + DECLARE_BITMAP(values, UART_GPIO_MAX); unsigned int count = 0; if (gpios == NULL) @@ -49,10 +49,11 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) for (i = 0; i < UART_GPIO_MAX; i++) if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { desc_array[count] = gpios->gpio[i]; - value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); + __assign_bit(count, values, + mctrl & mctrl_gpios_desc[i].mctrl); count++; } - gpiod_set_array_value(count, desc_array, value_array); + gpiod_set_array_value(count, desc_array, NULL, values); } EXPORT_SYMBOL_GPL(mctrl_gpio_set); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index bc03b0a690b4..9ede35cecb12 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -310,17 +310,17 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) if (difference & ACM_CTRL_DSR) acm->iocount.dsr++; - if (difference & ACM_CTRL_BRK) - acm->iocount.brk++; - if (difference & ACM_CTRL_RI) - acm->iocount.rng++; if (difference & ACM_CTRL_DCD) acm->iocount.dcd++; - if (difference & ACM_CTRL_FRAMING) + if (newctrl & ACM_CTRL_BRK) + acm->iocount.brk++; + if (newctrl & ACM_CTRL_RI) + acm->iocount.rng++; + if (newctrl & ACM_CTRL_FRAMING) acm->iocount.frame++; - if (difference & ACM_CTRL_PARITY) + if (newctrl & ACM_CTRL_PARITY) acm->iocount.parity++; - if (difference & ACM_CTRL_OVERRUN) + if (newctrl & ACM_CTRL_OVERRUN) acm->iocount.overrun++; spin_unlock_irqrestore(&acm->read_lock, flags); @@ -355,7 +355,6 @@ static void acm_ctrl_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - acm->nb_index = 0; dev_dbg(&acm->control->dev, "%s - urb shutting down with status: %d\n", __func__, status); @@ -1642,6 +1641,7 @@ static int acm_pre_reset(struct usb_interface *intf) struct acm *acm = usb_get_intfdata(intf); clear_bit(EVENT_RX_STALL, &acm->flags); + acm->nb_index = 0; /* pending control transfers are lost */ return 0; } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 244417d0dfd1..ffccd40ea67d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1474,8 +1474,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb u = 0; switch (uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: - if (is_in) - allow_short = true; if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; /* min 8 byte setup packet */ @@ -1505,6 +1503,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb is_in = 0; uurb->endpoint &= ~USB_DIR_IN; } + if (is_in) + allow_short = true; snoop(&ps->dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index ca8a4b53c59f..1074cb82ec17 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -221,6 +221,8 @@ #include <linux/usb/gadget.h> #include <linux/usb/composite.h> +#include <linux/nospec.h> + #include "configfs.h" @@ -3152,6 +3154,7 @@ static struct config_group *fsg_lun_make(struct config_group *group, fsg_opts = to_fsg_opts(&group->cg_item); if (num >= FSG_MAX_LUNS) return ERR_PTR(-ERANGE); + num = array_index_nospec(num, FSG_MAX_LUNS); mutex_lock(&fsg_opts->lock); if (fsg_opts->refcnt || fsg_opts->common->luns[num]) { diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 722860eb5a91..51dd8e00c4f8 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -179,10 +179,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { + pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) xhci->quirks |= XHCI_SSIC_PORT_UNUSED; + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; - } if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c b/drivers/usb/roles/intel-xhci-usb-role-switch.c index 1fb3dd0f1dfa..277de96181f9 100644 --- a/drivers/usb/roles/intel-xhci-usb-role-switch.c +++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c @@ -161,6 +161,8 @@ static int intel_xhci_usb_remove(struct platform_device *pdev) { struct intel_xhci_usb_data *data = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); + usb_role_switch_unregister(data->role_sw); return 0; } diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index d11f3f8dad40..1e592ec94ba4 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -318,8 +318,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, struct vhci_hcd *vhci_hcd; struct vhci *vhci; int retval = 0; - int rhport; + int rhport = -1; unsigned long flags; + bool invalid_rhport = false; u32 prev_port_status[VHCI_HC_PORTS]; @@ -334,9 +335,19 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, wIndex); - if (wIndex > VHCI_HC_PORTS) - pr_err("invalid port number %d\n", wIndex); - rhport = wIndex - 1; + /* + * wIndex can be 0 for some request types (typeReq). rhport is + * in valid range when wIndex >= 1 and < VHCI_HC_PORTS. + * + * Reference port_status[] only with valid rhport when + * invalid_rhport is false. + */ + if (wIndex < 1 || wIndex > VHCI_HC_PORTS) { + invalid_rhport = true; + if (wIndex > VHCI_HC_PORTS) + pr_err("invalid port number %d\n", wIndex); + } else + rhport = wIndex - 1; vhci_hcd = hcd_to_vhci_hcd(hcd); vhci = vhci_hcd->vhci; @@ -345,8 +356,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* store old status and compare now and old later */ if (usbip_dbg_flag_vhci_rh) { - memcpy(prev_port_status, vhci_hcd->port_status, - sizeof(prev_port_status)); + if (!invalid_rhport) + memcpy(prev_port_status, vhci_hcd->port_status, + sizeof(prev_port_status)); } switch (typeReq) { @@ -354,8 +366,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, usbip_dbg_vhci_rh(" ClearHubFeature\n"); break; case ClearPortFeature: - if (rhport < 0) + if (invalid_rhport) { + pr_err("invalid port number %d\n", wIndex); goto error; + } switch (wValue) { case USB_PORT_FEAT_SUSPEND: if (hcd->speed == HCD_USB3) { @@ -415,9 +429,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case GetPortStatus: usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); - if (wIndex < 1) { + if (invalid_rhport) { pr_err("invalid port number %d\n", wIndex); retval = -EPIPE; + goto error; } /* we do not care about resume. */ @@ -513,16 +528,20 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; } - if (rhport < 0) + if (invalid_rhport) { + pr_err("invalid port number %d\n", wIndex); goto error; + } vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND; break; case USB_PORT_FEAT_POWER: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_POWER\n"); - if (rhport < 0) + if (invalid_rhport) { + pr_err("invalid port number %d\n", wIndex); goto error; + } if (hcd->speed == HCD_USB3) vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER; else @@ -531,8 +550,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_BH_PORT_RESET: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n"); - if (rhport < 0) + if (invalid_rhport) { + pr_err("invalid port number %d\n", wIndex); goto error; + } /* Applicable only for USB3.0 hub */ if (hcd->speed != HCD_USB3) { pr_err("USB_PORT_FEAT_BH_PORT_RESET req not " @@ -543,8 +564,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_RESET: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_RESET\n"); - if (rhport < 0) + if (invalid_rhport) { + pr_err("invalid port number %d\n", wIndex); goto error; + } /* if it's already enabled, disable */ if (hcd->speed == HCD_USB3) { vhci_hcd->port_status[rhport] = 0; @@ -565,8 +588,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: usbip_dbg_vhci_rh(" SetPortFeature: default %d\n", wValue); - if (rhport < 0) + if (invalid_rhport) { + pr_err("invalid port number %d\n", wIndex); goto error; + } if (hcd->speed == HCD_USB3) { if ((vhci_hcd->port_status[rhport] & USB_SS_PORT_STAT_POWER) != 0) { @@ -608,7 +633,7 @@ error: if (usbip_dbg_flag_vhci_rh) { pr_debug("port %d\n", rhport); /* Only dump valid port status */ - if (rhport >= 0) { + if (!invalid_rhport) { dump_port_status_diff(prev_port_status[rhport], vhci_hcd->port_status[rhport], hcd->speed == HCD_USB3); @@ -618,8 +643,10 @@ error: spin_unlock_irqrestore(&vhci->lock, flags); - if ((vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0) + if (!invalid_rhport && + (vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0) { usb_hcd_poll_rh_status(hcd); + } return retval; } diff --git a/drivers/xen/biomerge.c b/drivers/xen/biomerge.c index 55ed80c3a17c..f3fbb700f569 100644 --- a/drivers/xen/biomerge.c +++ b/drivers/xen/biomerge.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/bio.h> -#include <linux/io.h> #include <linux/export.h> +#include <xen/xen.h> #include <xen/page.h> bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, @@ -20,4 +20,3 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, return false; #endif } -EXPORT_SYMBOL(xen_biovec_phys_mergeable); diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index a6f9ba85dc4b..f5c1af4ce9ab 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -303,6 +303,9 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, */ flags &= ~(__GFP_DMA | __GFP_HIGHMEM); + /* Convert the size to actually allocated. */ + size = 1UL << (order + XEN_PAGE_SHIFT); + /* On ARM this function returns an ioremap'ped virtual address for * which virt_to_phys doesn't return the corresponding physical * address. In fact on ARM virt_to_phys only works for kernel direct @@ -351,6 +354,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, * physical address */ phys = xen_bus_to_phys(dev_addr); + /* Convert the size to actually allocated. */ + size = 1UL << (order + XEN_PAGE_SHIFT); + if (((dev_addr + size - 1 <= dma_mask)) || range_straddles_page_boundary(phys, size)) xen_destroy_contiguous_region(phys, order); @@ -662,7 +668,7 @@ xen_swiotlb_dma_mmap(struct device *dev, struct vm_area_struct *vma, return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); #endif - return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); + return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs); } /* @@ -689,7 +695,7 @@ xen_swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt, handle, size, attrs); } #endif - return dma_common_get_sgtable(dev, sgt, cpu_addr, handle, size); + return dma_common_get_sgtable(dev, sgt, cpu_addr, handle, size, attrs); } static int xen_swiotlb_mapping_error(struct device *dev, dma_addr_t dma_addr) diff --git a/drivers/xen/time.c b/drivers/xen/time.c index 3e741cd1409c..0968859c29d0 100644 --- a/drivers/xen/time.c +++ b/drivers/xen/time.c @@ -175,7 +175,7 @@ void __init xen_time_setup_guest(void) xen_runstate_remote = !HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_runstate_update_flag); - pv_time_ops.steal_clock = xen_steal_clock; + pv_ops.time.steal_clock = xen_steal_clock; static_key_slow_inc(¶virt_steal_enabled); if (xen_runstate_remote) diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c index 23d1808fe027..e25ab76b9c99 100644 --- a/drivers/xen/xen-acpi-pad.c +++ b/drivers/xen/xen-acpi-pad.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/acpi.h> +#include <xen/xen.h> #include <xen/interface/version.h> #include <xen/xen-ops.h> #include <asm/xen/hypercall.h> |
