diff options
Diffstat (limited to 'drivers')
306 files changed, 12326 insertions, 7007 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 398451839178..d696f165a50e 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -508,10 +508,10 @@ struct hid_uid { const char *uid; }; -static int match_hid_uid(struct device *dev, void *data) +static int match_hid_uid(struct device *dev, const void *data) { struct acpi_device *adev = ACPI_COMPANION(dev); - struct hid_uid *id = data; + const struct hid_uid *id = data; if (!adev) return 0; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 7def63ab00c0..e3974a8f8fd4 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -725,17 +725,15 @@ bool acpi_dev_found(const char *hid) EXPORT_SYMBOL(acpi_dev_found); struct acpi_dev_match_info { - const char *dev_name; - struct acpi_device *adev; struct acpi_device_id hid[2]; const char *uid; s64 hrv; }; -static int acpi_dev_match_cb(struct device *dev, void *data) +static int acpi_dev_match_cb(struct device *dev, const void *data) { struct acpi_device *adev = to_acpi_device(dev); - struct acpi_dev_match_info *match = data; + const struct acpi_dev_match_info *match = data; unsigned long long hrv; acpi_status status; @@ -746,9 +744,6 @@ static int acpi_dev_match_cb(struct device *dev, void *data) strcmp(adev->pnp.unique_id, match->uid))) return 0; - match->dev_name = acpi_dev_name(adev); - match->adev = adev; - if (match->hrv == -1) return 1; @@ -818,7 +813,7 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv) match.hrv = hrv; dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); - return dev ? match.adev : NULL; + return dev ? to_acpi_device(dev) : NULL; } EXPORT_SYMBOL(acpi_dev_get_first_match_dev); diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index 3eaa459ae057..aa64eece77a6 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -134,10 +134,10 @@ static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset) } #ifdef CONFIG_TEGRA_IOMMU_SMMU -static int tegra_ahb_match_by_smmu(struct device *dev, void *data) +static int tegra_ahb_match_by_smmu(struct device *dev, const void *data) { struct tegra_ahb *ahb = dev_get_drvdata(dev); - struct device_node *dn = data; + const struct device_node *dn = data; return (ahb->dev->of_node == dn) ? 1 : 0; } diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 9b09e31ae82f..63c1e76739f1 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -137,7 +137,6 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) sizeof(*raw_capacity), GFP_KERNEL); if (!raw_capacity) { - pr_err("cpu_capacity: failed to allocate memory for raw capacities\n"); cap_parsing_failed = true; return false; } @@ -217,10 +216,8 @@ static int __init register_cpufreq_notifier(void) if (!acpi_disabled || !raw_capacity) return -EINVAL; - if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) { - pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n"); + if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) return -ENOMEM; - } cpumask_copy(cpus_to_visit, cpu_possible_mask); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0a58e969f8b7..df3cac739813 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -323,8 +323,8 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev); * return to the caller and not iterate over any more devices. */ struct device *bus_find_device(struct bus_type *bus, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)) + struct device *start, const void *data, + int (*match)(struct device *dev, const void *data)) { struct klist_iter i; struct device *dev; @@ -342,7 +342,7 @@ struct device *bus_find_device(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_find_device); -static int match_name(struct device *dev, void *data) +static int match_name(struct device *dev, const void *data) { const char *name = data; diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 8827c60f51e2..8d553c92cd32 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -660,7 +660,8 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu) static int __init cacheinfo_sysfs_init(void) { - return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "base/cacheinfo:online", + return cpuhp_setup_state(CPUHP_AP_BASE_CACHEINFO_ONLINE, + "base/cacheinfo:online", cacheinfo_cpu_online, cacheinfo_cpu_pre_down); } device_initcall(cacheinfo_sysfs_init); diff --git a/drivers/base/core.c b/drivers/base/core.c index b4c64528f13c..da84a73f2ba6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3356,3 +3356,9 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) dev->of_node_reused = true; } EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); + +int device_match_of_node(struct device *dev, const void *np) +{ + return dev->of_node == np; +} +EXPORT_SYMBOL_GPL(device_match_of_node); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 0df9b4461766..994a90747420 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -235,6 +235,19 @@ static int __init deferred_probe_timeout_setup(char *str) } __setup("deferred_probe_timeout=", deferred_probe_timeout_setup); +static int __driver_deferred_probe_check_state(struct device *dev) +{ + if (!initcalls_done) + return -EPROBE_DEFER; + + if (!deferred_probe_timeout) { + dev_WARN(dev, "deferred probe timeout, ignoring dependency"); + return -ETIMEDOUT; + } + + return 0; +} + /** * driver_deferred_probe_check_state() - Check deferred probe state * @dev: device to check @@ -248,14 +261,40 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup); */ int driver_deferred_probe_check_state(struct device *dev) { - if (initcalls_done) { - if (!deferred_probe_timeout) { - dev_WARN(dev, "deferred probe timeout, ignoring dependency"); - return -ETIMEDOUT; - } - dev_warn(dev, "ignoring dependency for device, assuming no driver"); - return -ENODEV; - } + int ret; + + ret = __driver_deferred_probe_check_state(dev); + if (ret < 0) + return ret; + + dev_warn(dev, "ignoring dependency for device, assuming no driver"); + + return -ENODEV; +} + +/** + * driver_deferred_probe_check_state_continue() - check deferred probe state + * @dev: device to check + * + * Returns -ETIMEDOUT if deferred probe debug timeout has expired, or + * -EPROBE_DEFER otherwise. + * + * Drivers or subsystems can opt-in to calling this function instead of + * directly returning -EPROBE_DEFER. + * + * This is similar to driver_deferred_probe_check_state(), but it allows the + * subsystem to keep deferring probe after built-in drivers have had a chance + * to probe. One scenario where that is useful is if built-in drivers rely on + * resources that are provided by modular drivers. + */ +int driver_deferred_probe_check_state_continue(struct device *dev) +{ + int ret; + + ret = __driver_deferred_probe_check_state(dev); + if (ret < 0) + return ret; + return -EPROBE_DEFER; } diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index f7035fc12b92..09f28479b243 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -133,7 +133,7 @@ static struct bus_type *generic_match_buses[] = { NULL, }; -static int device_fwnode_match(struct device *dev, void *fwnode) +static int device_fwnode_match(struct device *dev, const void *fwnode) { return dev_fwnode(dev) == fwnode; } diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 857c8f1b876e..4e5ca632f35e 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -73,8 +73,8 @@ EXPORT_SYMBOL_GPL(driver_for_each_device); * return to the caller and not iterate over any more devices. */ struct device *driver_find_device(struct device_driver *drv, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)) + struct device *start, const void *data, + int (*match)(struct device *dev, const void *data)) { struct klist_iter i; struct device *dev; diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig index 38f2da6f5c2b..3f9e274e2ed3 100644 --- a/drivers/base/firmware_loader/Kconfig +++ b/drivers/base/firmware_loader/Kconfig @@ -26,6 +26,9 @@ config FW_LOADER if FW_LOADER +config FW_LOADER_PAGED_BUF + bool + config EXTRA_FIRMWARE string "Build named firmware blobs into the kernel binary" help @@ -67,6 +70,7 @@ config EXTRA_FIRMWARE_DIR config FW_LOADER_USER_HELPER bool "Enable the firmware sysfs fallback mechanism" + select FW_LOADER_PAGED_BUF help This option enables a sysfs loading facility to enable firmware loading to the kernel through userspace as a fallback mechanism @@ -151,5 +155,19 @@ config FW_LOADER_USER_HELPER_FALLBACK If you are unsure about this, say N here. +config FW_LOADER_COMPRESS + bool "Enable compressed firmware support" + select FW_LOADER_PAGED_BUF + select XZ_DEC + help + This option enables the support for loading compressed firmware + files. The caller of firmware API receives the decompressed file + content. The compressed file is loaded as a fallback, only after + loading the raw file failed at first. + + Currently only XZ-compressed files are supported, and they have to + be compressed with either none or crc32 integrity check type (pass + "-C crc32" option to xz command). + endif # FW_LOADER endmenu diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index f962488546b6..62ee90b4db56 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -219,20 +219,6 @@ static ssize_t firmware_loading_show(struct device *dev, return sprintf(buf, "%d\n", loading); } -/* one pages buffer should be mapped/unmapped only once */ -static int map_fw_priv_pages(struct fw_priv *fw_priv) -{ - if (!fw_priv->is_paged_buf) - return 0; - - vunmap(fw_priv->data); - fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, - PAGE_KERNEL_RO); - if (!fw_priv->data) - return -ENOMEM; - return 0; -} - /** * firmware_loading_store() - set value in the 'loading' control file * @dev: device pointer @@ -254,7 +240,6 @@ static ssize_t firmware_loading_store(struct device *dev, struct fw_priv *fw_priv; ssize_t written = count; int loading = simple_strtol(buf, NULL, 10); - int i; mutex_lock(&fw_lock); fw_priv = fw_sysfs->fw_priv; @@ -265,12 +250,7 @@ static ssize_t firmware_loading_store(struct device *dev, case 1: /* discarding any previous partial load */ if (!fw_sysfs_done(fw_priv)) { - for (i = 0; i < fw_priv->nr_pages; i++) - __free_page(fw_priv->pages[i]); - vfree(fw_priv->pages); - fw_priv->pages = NULL; - fw_priv->page_array_size = 0; - fw_priv->nr_pages = 0; + fw_free_paged_buf(fw_priv); fw_state_start(fw_priv); } break; @@ -284,7 +264,7 @@ static ssize_t firmware_loading_store(struct device *dev, * see the mapped 'buf->data' once the loading * is completed. * */ - rc = map_fw_priv_pages(fw_priv); + rc = fw_map_paged_buf(fw_priv); if (rc) dev_err(dev, "%s: map pages failed\n", __func__); @@ -389,40 +369,13 @@ out: static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) { - struct fw_priv *fw_priv= fw_sysfs->fw_priv; - int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT; - - /* If the array of pages is too small, grow it... */ - if (fw_priv->page_array_size < pages_needed) { - int new_array_size = max(pages_needed, - fw_priv->page_array_size * 2); - struct page **new_pages; + int err; - new_pages = vmalloc(array_size(new_array_size, sizeof(void *))); - if (!new_pages) { - fw_load_abort(fw_sysfs); - return -ENOMEM; - } - memcpy(new_pages, fw_priv->pages, - fw_priv->page_array_size * sizeof(void *)); - memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * - (new_array_size - fw_priv->page_array_size)); - vfree(fw_priv->pages); - fw_priv->pages = new_pages; - fw_priv->page_array_size = new_array_size; - } - - while (fw_priv->nr_pages < pages_needed) { - fw_priv->pages[fw_priv->nr_pages] = - alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - - if (!fw_priv->pages[fw_priv->nr_pages]) { - fw_load_abort(fw_sysfs); - return -ENOMEM; - } - fw_priv->nr_pages++; - } - return 0; + err = fw_grow_paged_buf(fw_sysfs->fw_priv, + PAGE_ALIGN(min_size) >> PAGE_SHIFT); + if (err) + fw_load_abort(fw_sysfs); + return err; } /** @@ -659,7 +612,7 @@ static bool fw_run_sysfs_fallback(enum fw_opt opt_flags) /* Also permit LSMs and IMA to fail firmware sysfs fallback */ ret = security_kernel_load_data(LOADING_FIRMWARE); if (ret < 0) - return ret; + return false; return fw_force_sysfs_fallback(opt_flags); } diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index 4c1395f8e7ed..7048a41973ed 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -64,12 +64,14 @@ struct fw_priv { void *data; size_t size; size_t allocated_size; -#ifdef CONFIG_FW_LOADER_USER_HELPER +#ifdef CONFIG_FW_LOADER_PAGED_BUF bool is_paged_buf; - bool need_uevent; struct page **pages; int nr_pages; int page_array_size; +#endif +#ifdef CONFIG_FW_LOADER_USER_HELPER + bool need_uevent; struct list_head pending_list; #endif const char *fw_name; @@ -133,4 +135,14 @@ static inline void fw_state_done(struct fw_priv *fw_priv) int assign_fw(struct firmware *fw, struct device *device, enum fw_opt opt_flags); +#ifdef CONFIG_FW_LOADER_PAGED_BUF +void fw_free_paged_buf(struct fw_priv *fw_priv); +int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed); +int fw_map_paged_buf(struct fw_priv *fw_priv); +#else +static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {} +int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; } +int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; } +#endif + #endif /* __FIRMWARE_LOADER_H */ diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 7eaaf5ee5ba6..bf44c79beae9 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -33,6 +33,7 @@ #include <linux/syscore_ops.h> #include <linux/reboot.h> #include <linux/security.h> +#include <linux/xz.h> #include <generated/utsrelease.h> @@ -251,15 +252,7 @@ static void __free_fw_priv(struct kref *ref) list_del(&fw_priv->list); spin_unlock(&fwc->lock); -#ifdef CONFIG_FW_LOADER_USER_HELPER - if (fw_priv->is_paged_buf) { - int i; - vunmap(fw_priv->data); - for (i = 0; i < fw_priv->nr_pages; i++) - __free_page(fw_priv->pages[i]); - vfree(fw_priv->pages); - } else -#endif + fw_free_paged_buf(fw_priv); /* free leftover pages */ if (!fw_priv->allocated_size) vfree(fw_priv->data); kfree_const(fw_priv->fw_name); @@ -274,6 +267,174 @@ static void free_fw_priv(struct fw_priv *fw_priv) spin_unlock(&fwc->lock); } +#ifdef CONFIG_FW_LOADER_PAGED_BUF +void fw_free_paged_buf(struct fw_priv *fw_priv) +{ + int i; + + if (!fw_priv->pages) + return; + + for (i = 0; i < fw_priv->nr_pages; i++) + __free_page(fw_priv->pages[i]); + kvfree(fw_priv->pages); + fw_priv->pages = NULL; + fw_priv->page_array_size = 0; + fw_priv->nr_pages = 0; +} + +int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) +{ + /* If the array of pages is too small, grow it */ + if (fw_priv->page_array_size < pages_needed) { + int new_array_size = max(pages_needed, + fw_priv->page_array_size * 2); + struct page **new_pages; + + new_pages = kvmalloc_array(new_array_size, sizeof(void *), + GFP_KERNEL); + if (!new_pages) + return -ENOMEM; + memcpy(new_pages, fw_priv->pages, + fw_priv->page_array_size * sizeof(void *)); + memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * + (new_array_size - fw_priv->page_array_size)); + kvfree(fw_priv->pages); + fw_priv->pages = new_pages; + fw_priv->page_array_size = new_array_size; + } + + while (fw_priv->nr_pages < pages_needed) { + fw_priv->pages[fw_priv->nr_pages] = + alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + + if (!fw_priv->pages[fw_priv->nr_pages]) + return -ENOMEM; + fw_priv->nr_pages++; + } + + return 0; +} + +int fw_map_paged_buf(struct fw_priv *fw_priv) +{ + /* one pages buffer should be mapped/unmapped only once */ + if (!fw_priv->pages) + return 0; + + vunmap(fw_priv->data); + fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, + PAGE_KERNEL_RO); + if (!fw_priv->data) + return -ENOMEM; + + /* page table is no longer needed after mapping, let's free */ + kvfree(fw_priv->pages); + fw_priv->pages = NULL; + + return 0; +} +#endif + +/* + * XZ-compressed firmware support + */ +#ifdef CONFIG_FW_LOADER_COMPRESS +/* show an error and return the standard error code */ +static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret) +{ + if (xz_ret != XZ_STREAM_END) { + dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret); + return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL; + } + return 0; +} + +/* single-shot decompression onto the pre-allocated buffer */ +static int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv, + size_t in_size, const void *in_buffer) +{ + struct xz_dec *xz_dec; + struct xz_buf xz_buf; + enum xz_ret xz_ret; + + xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1); + if (!xz_dec) + return -ENOMEM; + + xz_buf.in_size = in_size; + xz_buf.in = in_buffer; + xz_buf.in_pos = 0; + xz_buf.out_size = fw_priv->allocated_size; + xz_buf.out = fw_priv->data; + xz_buf.out_pos = 0; + + xz_ret = xz_dec_run(xz_dec, &xz_buf); + xz_dec_end(xz_dec); + + fw_priv->size = xz_buf.out_pos; + return fw_decompress_xz_error(dev, xz_ret); +} + +/* decompression on paged buffer and map it */ +static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv, + size_t in_size, const void *in_buffer) +{ + struct xz_dec *xz_dec; + struct xz_buf xz_buf; + enum xz_ret xz_ret; + struct page *page; + int err = 0; + + xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1); + if (!xz_dec) + return -ENOMEM; + + xz_buf.in_size = in_size; + xz_buf.in = in_buffer; + xz_buf.in_pos = 0; + + fw_priv->is_paged_buf = true; + fw_priv->size = 0; + do { + if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) { + err = -ENOMEM; + goto out; + } + + /* decompress onto the new allocated page */ + page = fw_priv->pages[fw_priv->nr_pages - 1]; + xz_buf.out = kmap(page); + xz_buf.out_pos = 0; + xz_buf.out_size = PAGE_SIZE; + xz_ret = xz_dec_run(xz_dec, &xz_buf); + kunmap(page); + fw_priv->size += xz_buf.out_pos; + /* partial decompression means either end or error */ + if (xz_buf.out_pos != PAGE_SIZE) + break; + } while (xz_ret == XZ_OK); + + err = fw_decompress_xz_error(dev, xz_ret); + if (!err) + err = fw_map_paged_buf(fw_priv); + + out: + xz_dec_end(xz_dec); + return err; +} + +static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv, + size_t in_size, const void *in_buffer) +{ + /* if the buffer is pre-allocated, we can perform in single-shot mode */ + if (fw_priv->data) + return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer); + else + return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer); +} +#endif /* CONFIG_FW_LOADER_COMPRESS */ + /* direct firmware loading support */ static char fw_path_para[256]; static const char * const fw_path[] = { @@ -293,7 +454,12 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); static int -fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) +fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, + const char *suffix, + int (*decompress)(struct device *dev, + struct fw_priv *fw_priv, + size_t in_size, + const void *in_buffer)) { loff_t size; int i, len; @@ -301,9 +467,11 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) char *path; enum kernel_read_file_id id = READING_FIRMWARE; size_t msize = INT_MAX; + void *buffer = NULL; /* Already populated data member means we're loading into a buffer */ - if (fw_priv->data) { + if (!decompress && fw_priv->data) { + buffer = fw_priv->data; id = READING_FIRMWARE_PREALLOC_BUFFER; msize = fw_priv->allocated_size; } @@ -317,15 +485,15 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) if (!fw_path[i][0]) continue; - len = snprintf(path, PATH_MAX, "%s/%s", - fw_path[i], fw_priv->fw_name); + len = snprintf(path, PATH_MAX, "%s/%s%s", + fw_path[i], fw_priv->fw_name, suffix); if (len >= PATH_MAX) { rc = -ENAMETOOLONG; break; } fw_priv->size = 0; - rc = kernel_read_file_from_path(path, &fw_priv->data, &size, + rc = kernel_read_file_from_path(path, &buffer, &size, msize, id); if (rc) { if (rc != -ENOENT) @@ -336,8 +504,24 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) path); continue; } - dev_dbg(device, "direct-loading %s\n", fw_priv->fw_name); - fw_priv->size = size; + if (decompress) { + dev_dbg(device, "f/w decompressing %s\n", + fw_priv->fw_name); + rc = decompress(device, fw_priv, size, buffer); + /* discard the superfluous original content */ + vfree(buffer); + buffer = NULL; + if (rc) { + fw_free_paged_buf(fw_priv); + continue; + } + } else { + dev_dbg(device, "direct-loading %s\n", + fw_priv->fw_name); + if (!fw_priv->data) + fw_priv->data = buffer; + fw_priv->size = size; + } fw_state_done(fw_priv); break; } @@ -584,7 +768,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name, if (ret <= 0) /* error or already assigned */ goto out; - ret = fw_get_filesystem_firmware(device, fw->priv); + ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); +#ifdef CONFIG_FW_LOADER_COMPRESS + if (ret == -ENOENT) + ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", + fw_decompress_xz); +#endif + if (ret) { if (!(opt_flags & FW_OPT_NO_WARN)) dev_warn(device, diff --git a/drivers/base/node.c b/drivers/base/node.c index 8598fcbd2a17..aa878fbcf705 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -66,6 +66,7 @@ static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); * @dev: Device for this memory access class * @list_node: List element in the node's access list * @access: The access class rank + * @hmem_attrs: Heterogeneous memory performance attributes */ struct node_access_nodes { struct device dev; @@ -673,8 +674,8 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid) /** * register_memory_node_under_compute_node - link memory node to its compute * node for a given access class. - * @mem_node: Memory node number - * @cpu_node: Cpu node number + * @mem_nid: Memory node number + * @cpu_nid: Cpu node number * @access: Access class to register * * Description: diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 4d1729853d1a..713903290385 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -5,7 +5,7 @@ * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * - * Please see Documentation/driver-model/platform.txt for more + * Please see Documentation/driver-model/platform.rst for more * information. */ diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index caac5d24baa4..4bad0614109b 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -132,3 +132,12 @@ config ASPEED_BT_IPMI_BMC Provides a driver for the BT (Block Transfer) IPMI interface found on Aspeed SOCs (AST2400 and AST2500). The driver implements the BMC side of the BT interface. + +config IPMB_DEVICE_INTERFACE + tristate 'IPMB Interface handler' + depends on I2C + depends on I2C_SLAVE + help + Provides a driver for a device (Satellite MC) to + receive requests and send responses back to the BMC via + the IPMB interface. This module requires I2C support. diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 3f06b2062475..0822adc2ec41 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o +obj-$(CONFIG_IPMB_DEVICE_INTERFACE) += ipmb_dev_int.o diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c new file mode 100644 index 000000000000..57204335c5f5 --- /dev/null +++ b/drivers/char/ipmi/ipmb_dev_int.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * IPMB driver to receive a request and send a response + * + * Copyright (C) 2019 Mellanox Techologies, Ltd. + * + * This was inspired by Brendan Higgins' ipmi-bmc-bt-i2c driver. + */ + +#include <linux/acpi.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/poll.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/wait.h> + +#define MAX_MSG_LEN 128 +#define IPMB_REQUEST_LEN_MIN 7 +#define NETFN_RSP_BIT_MASK 0x4 +#define REQUEST_QUEUE_MAX_LEN 256 + +#define IPMB_MSG_LEN_IDX 0 +#define RQ_SA_8BIT_IDX 1 +#define NETFN_LUN_IDX 2 + +#define GET_7BIT_ADDR(addr_8bit) (addr_8bit >> 1) +#define GET_8BIT_ADDR(addr_7bit) ((addr_7bit << 1) & 0xff) + +#define IPMB_MSG_PAYLOAD_LEN_MAX (MAX_MSG_LEN - IPMB_REQUEST_LEN_MIN - 1) + +#define SMBUS_MSG_HEADER_LENGTH 2 +#define SMBUS_MSG_IDX_OFFSET (SMBUS_MSG_HEADER_LENGTH + 1) + +struct ipmb_msg { + u8 len; + u8 rs_sa; + u8 netfn_rs_lun; + u8 checksum1; + u8 rq_sa; + u8 rq_seq_rq_lun; + u8 cmd; + u8 payload[IPMB_MSG_PAYLOAD_LEN_MAX]; + /* checksum2 is included in payload */ +} __packed; + +struct ipmb_request_elem { + struct list_head list; + struct ipmb_msg request; +}; + +struct ipmb_dev { + struct i2c_client *client; + struct miscdevice miscdev; + struct ipmb_msg request; + struct list_head request_queue; + atomic_t request_queue_len; + size_t msg_idx; + spinlock_t lock; + wait_queue_head_t wait_queue; + struct mutex file_mutex; +}; + +static inline struct ipmb_dev *to_ipmb_dev(struct file *file) +{ + return container_of(file->private_data, struct ipmb_dev, miscdev); +} + +static ssize_t ipmb_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + struct ipmb_dev *ipmb_dev = to_ipmb_dev(file); + struct ipmb_request_elem *queue_elem; + struct ipmb_msg msg; + ssize_t ret; + + memset(&msg, 0, sizeof(msg)); + + spin_lock_irq(&ipmb_dev->lock); + + while (list_empty(&ipmb_dev->request_queue)) { + spin_unlock_irq(&ipmb_dev->lock); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(ipmb_dev->wait_queue, + !list_empty(&ipmb_dev->request_queue)); + if (ret) + return ret; + + spin_lock_irq(&ipmb_dev->lock); + } + + queue_elem = list_first_entry(&ipmb_dev->request_queue, + struct ipmb_request_elem, list); + memcpy(&msg, &queue_elem->request, sizeof(msg)); + list_del(&queue_elem->list); + kfree(queue_elem); + atomic_dec(&ipmb_dev->request_queue_len); + + spin_unlock_irq(&ipmb_dev->lock); + + count = min_t(size_t, count, msg.len + 1); + if (copy_to_user(buf, &msg, count)) + ret = -EFAULT; + + return ret < 0 ? ret : count; +} + +static ssize_t ipmb_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct ipmb_dev *ipmb_dev = to_ipmb_dev(file); + u8 rq_sa, netf_rq_lun, msg_len; + union i2c_smbus_data data; + u8 msg[MAX_MSG_LEN]; + ssize_t ret; + + if (count > sizeof(msg)) + return -EINVAL; + + if (copy_from_user(&msg, buf, count)) + return -EFAULT; + + if (count < msg[0]) + return -EINVAL; + + rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]); + netf_rq_lun = msg[NETFN_LUN_IDX]; + + if (!(netf_rq_lun & NETFN_RSP_BIT_MASK)) + return -EINVAL; + + /* + * subtract rq_sa and netf_rq_lun from the length of the msg passed to + * i2c_smbus_xfer + */ + msg_len = msg[IPMB_MSG_LEN_IDX] - SMBUS_MSG_HEADER_LENGTH; + if (msg_len > I2C_SMBUS_BLOCK_MAX) + msg_len = I2C_SMBUS_BLOCK_MAX; + + data.block[0] = msg_len; + memcpy(&data.block[1], msg + SMBUS_MSG_IDX_OFFSET, msg_len); + ret = i2c_smbus_xfer(ipmb_dev->client->adapter, rq_sa, + ipmb_dev->client->flags, + I2C_SMBUS_WRITE, netf_rq_lun, + I2C_SMBUS_BLOCK_DATA, &data); + + return ret ? : count; +} + +static unsigned int ipmb_poll(struct file *file, poll_table *wait) +{ + struct ipmb_dev *ipmb_dev = to_ipmb_dev(file); + unsigned int mask = POLLOUT; + + mutex_lock(&ipmb_dev->file_mutex); + poll_wait(file, &ipmb_dev->wait_queue, wait); + + if (atomic_read(&ipmb_dev->request_queue_len)) + mask |= POLLIN; + mutex_unlock(&ipmb_dev->file_mutex); + + return mask; +} + +static const struct file_operations ipmb_fops = { + .owner = THIS_MODULE, + .read = ipmb_read, + .write = ipmb_write, + .poll = ipmb_poll, +}; + +/* Called with ipmb_dev->lock held. */ +static void ipmb_handle_request(struct ipmb_dev *ipmb_dev) +{ + struct ipmb_request_elem *queue_elem; + + if (atomic_read(&ipmb_dev->request_queue_len) >= + REQUEST_QUEUE_MAX_LEN) + return; + + queue_elem = kmalloc(sizeof(*queue_elem), GFP_ATOMIC); + if (!queue_elem) + return; + + memcpy(&queue_elem->request, &ipmb_dev->request, + sizeof(struct ipmb_msg)); + list_add(&queue_elem->list, &ipmb_dev->request_queue); + atomic_inc(&ipmb_dev->request_queue_len); + wake_up_all(&ipmb_dev->wait_queue); +} + +static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa) +{ + /* The 8 lsb of the sum is 0 when the checksum is valid */ + return (rs_sa + ipmb_dev->request.netfn_rs_lun + + ipmb_dev->request.checksum1); +} + +static bool is_ipmb_request(struct ipmb_dev *ipmb_dev, u8 rs_sa) +{ + if (ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) { + if (ipmb_verify_checksum1(ipmb_dev, rs_sa)) + return false; + + /* + * Check whether this is an IPMB request or + * response. + * The 6 MSB of netfn_rs_lun are dedicated to the netfn + * while the remaining bits are dedicated to the lun. + * If the LSB of the netfn is cleared, it is associated + * with an IPMB request. + * If the LSB of the netfn is set, it is associated with + * an IPMB response. + */ + if (!(ipmb_dev->request.netfn_rs_lun & NETFN_RSP_BIT_MASK)) + return true; + } + return false; +} + +/* + * The IPMB protocol only supports I2C Writes so there is no need + * to support I2C_SLAVE_READ* events. + * This i2c callback function only monitors IPMB request messages + * and adds them in a queue, so that they can be handled by + * receive_ipmb_request. + */ +static int ipmb_slave_cb(struct i2c_client *client, + enum i2c_slave_event event, u8 *val) +{ + struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client); + u8 *buf = (u8 *)&ipmb_dev->request; + unsigned long flags; + + spin_lock_irqsave(&ipmb_dev->lock, flags); + switch (event) { + case I2C_SLAVE_WRITE_REQUESTED: + memset(&ipmb_dev->request, 0, sizeof(ipmb_dev->request)); + ipmb_dev->msg_idx = 0; + + /* + * At index 0, ipmb_msg stores the length of msg, + * skip it for now. + * The len will be populated once the whole + * buf is populated. + * + * The I2C bus driver's responsibility is to pass the + * data bytes to the backend driver; it does not + * forward the i2c slave address. + * Since the first byte in the IPMB message is the + * address of the responder, it is the responsibility + * of the IPMB driver to format the message properly. + * So this driver prepends the address of the responder + * to the received i2c data before the request message + * is handled in userland. + */ + buf[++ipmb_dev->msg_idx] = GET_8BIT_ADDR(client->addr); + break; + + case I2C_SLAVE_WRITE_RECEIVED: + if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg)) + break; + + buf[++ipmb_dev->msg_idx] = *val; + break; + + case I2C_SLAVE_STOP: + ipmb_dev->request.len = ipmb_dev->msg_idx; + + if (is_ipmb_request(ipmb_dev, GET_8BIT_ADDR(client->addr))) + ipmb_handle_request(ipmb_dev); + break; + + default: + break; + } + spin_unlock_irqrestore(&ipmb_dev->lock, flags); + + return 0; +} + +static int ipmb_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ipmb_dev *ipmb_dev; + int ret; + + ipmb_dev = devm_kzalloc(&client->dev, sizeof(*ipmb_dev), + GFP_KERNEL); + if (!ipmb_dev) + return -ENOMEM; + + spin_lock_init(&ipmb_dev->lock); + init_waitqueue_head(&ipmb_dev->wait_queue); + atomic_set(&ipmb_dev->request_queue_len, 0); + INIT_LIST_HEAD(&ipmb_dev->request_queue); + + mutex_init(&ipmb_dev->file_mutex); + + ipmb_dev->miscdev.minor = MISC_DYNAMIC_MINOR; + + ipmb_dev->miscdev.name = devm_kasprintf(&client->dev, GFP_KERNEL, + "%s%d", "ipmb-", + client->adapter->nr); + ipmb_dev->miscdev.fops = &ipmb_fops; + ipmb_dev->miscdev.parent = &client->dev; + ret = misc_register(&ipmb_dev->miscdev); + if (ret) + return ret; + + ipmb_dev->client = client; + i2c_set_clientdata(client, ipmb_dev); + ret = i2c_slave_register(client, ipmb_slave_cb); + if (ret) { + misc_deregister(&ipmb_dev->miscdev); + return ret; + } + + return 0; +} + +static int ipmb_remove(struct i2c_client *client) +{ + struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client); + + i2c_slave_unregister(client); + misc_deregister(&ipmb_dev->miscdev); + + return 0; +} + +static const struct i2c_device_id ipmb_id[] = { + { "ipmb-dev", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, ipmb_id); + +static const struct acpi_device_id acpi_ipmb_id[] = { + { "IPMB0001", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id); + +static struct i2c_driver ipmb_driver = { + .driver = { + .name = "ipmb-dev", + .acpi_match_table = ACPI_PTR(acpi_ipmb_id), + }, + .probe = ipmb_probe, + .remove = ipmb_remove, + .id_table = ipmb_id, +}; +module_i2c_driver(ipmb_driver); + +MODULE_AUTHOR("Mellanox Technologies"); +MODULE_DESCRIPTION("IPMB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 1dc10740fc0f..6707659cffd6 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2819,9 +2819,9 @@ static const struct device_type bmc_device_type = { .groups = bmc_dev_attr_groups, }; -static int __find_bmc_guid(struct device *dev, void *data) +static int __find_bmc_guid(struct device *dev, const void *data) { - guid_t *guid = data; + const guid_t *guid = data; struct bmc_device *bmc; int rv; @@ -2857,9 +2857,9 @@ struct prod_dev_id { unsigned char device_id; }; -static int __find_bmc_prod_dev_id(struct device *dev, void *data) +static int __find_bmc_prod_dev_id(struct device *dev, const void *data) { - struct prod_dev_id *cid = data; + const struct prod_dev_id *cid = data; struct bmc_device *bmc; int rv; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index f124a2d2bb9f..da5b6723329a 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -71,7 +71,7 @@ enum si_intf_state { static const char * const si_to_str[] = { "invalid", "kcs", "smic", "bt" }; -static int initialized; +static bool initialized; /* * Indexes into stats[] in smi_info below. @@ -2124,7 +2124,7 @@ static int __init init_ipmi_si(void) } skip_fallback_noirq: - initialized = 1; + initialized = true; mutex_unlock(&smi_infos_lock); if (type) diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index f2a91c4d8cab..22f6c9b20e9a 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -19,6 +19,7 @@ #include "ipmi_si.h" #include "ipmi_dmi.h" +static bool platform_registered; static bool si_tryplatform = true; #ifdef CONFIG_ACPI static bool si_tryacpi = true; @@ -426,7 +427,7 @@ static int ipmi_remove(struct platform_device *pdev) return ipmi_si_remove_by_dev(&pdev->dev); } -static int pdev_match_name(struct device *dev, void *data) +static int pdev_match_name(struct device *dev, const void *data) { struct platform_device *pdev = to_platform_device(dev); const char *name = data; @@ -443,6 +444,7 @@ void ipmi_remove_platform_device_by_name(char *name) struct platform_device *pdev = to_platform_device(dev); platform_device_unregister(pdev); + put_device(dev); } } @@ -469,9 +471,12 @@ void ipmi_si_platform_init(void) int rv = platform_driver_register(&ipmi_platform_driver); if (rv) pr_err("Unable to register driver: %d\n", rv); + else + platform_registered = true; } void ipmi_si_platform_shutdown(void) { - platform_driver_unregister(&ipmi_platform_driver); + if (platform_registered) + platform_driver_unregister(&ipmi_platform_driver); } diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index cf8156d6bc07..305fa5054274 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -303,6 +303,7 @@ struct ssif_info { ((unsigned int) atomic_read(&(ssif)->stats[SSIF_STAT_ ## stat])) static bool initialized; +static bool platform_registered; static void return_hosed_msg(struct ssif_info *ssif_info, struct ipmi_smi_msg *msg); @@ -2088,6 +2089,8 @@ static int init_ipmi_ssif(void) rv = platform_driver_register(&ipmi_driver); if (rv) pr_err("Unable to register driver: %d\n", rv); + else + platform_registered = true; } ssif_i2c_driver.address_list = ssif_address_list(); @@ -2111,7 +2114,7 @@ static void cleanup_ipmi_ssif(void) kfree(ssif_i2c_driver.address_list); - if (ssif_trydmi) + if (ssif_trydmi && platform_registered) platform_driver_unregister(&ipmi_driver); free_ssif_clients(); diff --git a/drivers/clk/renesas/r8a77470-cpg-mssr.c b/drivers/clk/renesas/r8a77470-cpg-mssr.c index ab0fb10b6bf0..d81ae65f0d18 100644 --- a/drivers/clk/renesas/r8a77470-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77470-cpg-mssr.c @@ -175,7 +175,7 @@ static const unsigned int r8a77470_crit_mod_clks[] __initconst = { *--------------------------------------------------- * 0 0 20 x80 x78 x50 * 0 1 26 x60 x60 x56 - * 1 0 Prohibitted setting + * 1 0 Prohibited setting * 1 1 30 x52 x52 x50 * * *1 : Table 7.4 indicates VCO output (PLL0 = VCO) diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index 22cc7f68ef6e..20a9cb7cb6d3 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -24,6 +24,7 @@ #include <linux/of_device.h> #include <linux/of_dma.h> #include <linux/list.h> +#include <linux/dma/mxs-dma.h> #include <asm/irq.h> @@ -77,6 +78,7 @@ #define BM_CCW_COMMAND (3 << 0) #define CCW_CHAIN (1 << 2) #define CCW_IRQ (1 << 3) +#define CCW_WAIT4RDY (1 << 5) #define CCW_DEC_SEM (1 << 6) #define CCW_WAIT4END (1 << 7) #define CCW_HALT_ON_TERM (1 << 8) @@ -477,16 +479,16 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan) * ...... * ->device_prep_slave_sg(0); * ...... - * ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + * ->device_prep_slave_sg(DMA_CTRL_ACK); * ...... * [3] If there are more than two DMA commands in the DMA chain, the code * should be: * ...... * ->device_prep_slave_sg(0); // First * ...... - * ->device_prep_slave_sg(DMA_PREP_INTERRUPT [| DMA_CTRL_ACK]); + * ->device_prep_slave_sg(DMA_CTRL_ACK]); * ...... - * ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK); // Last + * ->device_prep_slave_sg(DMA_CTRL_ACK); // Last * ...... */ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( @@ -500,13 +502,12 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( struct scatterlist *sg; u32 i, j; u32 *pio; - bool append = flags & DMA_PREP_INTERRUPT; - int idx = append ? mxs_chan->desc_count : 0; + int idx = 0; - if (mxs_chan->status == DMA_IN_PROGRESS && !append) - return NULL; + if (mxs_chan->status == DMA_IN_PROGRESS) + idx = mxs_chan->desc_count; - if (sg_len + (append ? idx : 0) > NUM_CCW) { + if (sg_len + idx > NUM_CCW) { dev_err(mxs_dma->dma_device.dev, "maximum number of sg exceeded: %d > %d\n", sg_len, NUM_CCW); @@ -520,7 +521,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( * If the sg is prepared with append flag set, the sg * will be appended to the last prepared sg. */ - if (append) { + if (idx) { BUG_ON(idx < 1); ccw = &mxs_chan->ccw[idx - 1]; ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx; @@ -541,12 +542,14 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( ccw->bits = 0; ccw->bits |= CCW_IRQ; ccw->bits |= CCW_DEC_SEM; - if (flags & DMA_CTRL_ACK) + if (flags & MXS_DMA_CTRL_WAIT4END) ccw->bits |= CCW_WAIT4END; ccw->bits |= CCW_HALT_ON_TERM; ccw->bits |= CCW_TERM_FLUSH; ccw->bits |= BF_CCW(sg_len, PIO_NUM); ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND); + if (flags & MXS_DMA_CTRL_WAIT4RDY) + ccw->bits |= CCW_WAIT4RDY; } else { for_each_sg(sgl, sg, sg_len, i) { if (sg_dma_len(sg) > MAX_XFER_BYTES) { @@ -573,7 +576,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( ccw->bits &= ~CCW_CHAIN; ccw->bits |= CCW_IRQ; ccw->bits |= CCW_DEC_SEM; - if (flags & DMA_CTRL_ACK) + if (flags & MXS_DMA_CTRL_WAIT4END) ccw->bits |= CCW_WAIT4END; } } diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 937a930ce87d..44fd4f9404a9 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * System Control and Management Interface (SCMI) Message Protocol * driver common header file containing some definitions, structures diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c index 85ec99f97841..20123384271c 100644 --- a/drivers/firmware/efi/dev-path-parser.c +++ b/drivers/firmware/efi/dev-path-parser.c @@ -17,9 +17,9 @@ struct acpi_hid_uid { char uid[11]; /* UINT_MAX + null byte */ }; -static int __init match_acpi_dev(struct device *dev, void *data) +static int __init match_acpi_dev(struct device *dev, const void *data) { - struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data; + struct acpi_hid_uid hid_uid = *(const struct acpi_hid_uid *)data; struct acpi_device *adev = to_acpi_device(dev); if (acpi_match_device_ids(adev, hid_uid.hid)) diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 4983827151bf..adbeeefaca92 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BSD-3-Clause +/* SPDX-License-Identifier: BSD-3-Clause */ /* * Texas Instruments System Control Interface (TISCI) Protocol * diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c index 75f64abf9c81..e405309baadc 100644 --- a/drivers/fpga/of-fpga-region.c +++ b/drivers/fpga/of-fpga-region.c @@ -22,11 +22,6 @@ static const struct of_device_id fpga_region_of_match[] = { }; MODULE_DEVICE_TABLE(of, fpga_region_of_match); -static int fpga_region_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * of_fpga_region_find - find FPGA region * @np: device node of FPGA Region @@ -37,7 +32,7 @@ static int fpga_region_of_node_match(struct device *dev, const void *data) */ static struct fpga_region *of_fpga_region_find(struct device_node *np) { - return fpga_region_class_find(NULL, np, fpga_region_of_node_match); + return fpga_region_class_find(NULL, np, device_match_of_node); } /** diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c index 6314225dbed0..3611a0571667 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/gpio-cs5535.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(mask, "GPIO channel mask."); /* * FIXME: convert this singleton driver to use the state container - * design pattern, see Documentation/driver-model/design-patterns.txt + * design pattern, see Documentation/driver-model/design-patterns.rst */ static struct cs5535_gpio_chip { struct gpio_chip chip; diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 80b75501f5c6..ad19df0686c9 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -93,7 +93,7 @@ static struct bus_type mipi_dsi_bus_type = { .pm = &mipi_dsi_device_pm_ops, }; -static int of_device_match(struct device *dev, void *data) +static int of_device_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/gpu/drm/i915/.gitignore b/drivers/gpu/drm/i915/.gitignore deleted file mode 100644 index cff45d81f42f..000000000000 --- a/drivers/gpu/drm/i915/.gitignore +++ /dev/null @@ -1 +0,0 @@ -header_test_*.c diff --git a/drivers/gpu/drm/i915/Makefile.header-test b/drivers/gpu/drm/i915/Makefile.header-test index c1c391816fa7..639b596a06a9 100644 --- a/drivers/gpu/drm/i915/Makefile.header-test +++ b/drivers/gpu/drm/i915/Makefile.header-test @@ -2,7 +2,7 @@ # Copyright © 2019 Intel Corporation # Test the headers are compilable as standalone units -header_test := \ +header-test-$(CONFIG_DRM_I915_WERROR) := \ i915_active_types.h \ i915_gem_context_types.h \ i915_priolist_types.h \ @@ -35,13 +35,3 @@ header_test := \ intel_sprite.h \ intel_tv.h \ intel_workarounds_types.h - -quiet_cmd_header_test = HDRTEST $@ - cmd_header_test = echo "\#include \"$(<F)\"" > $@ - -header_test_%.c: %.h - $(call cmd,header_test) - -i915-$(CONFIG_DRM_I915_WERROR) += $(foreach h,$(header_test),$(patsubst %.h,header_test_%.o,$(h))) - -clean-files += $(foreach h,$(header_test),$(patsubst %.h,header_test_%.c,$(h))) diff --git a/drivers/gpu/drm/i915/i915_mm.c b/drivers/gpu/drm/i915/i915_mm.c index e4935dd1fd37..c23bb29e6d3e 100644 --- a/drivers/gpu/drm/i915/i915_mm.c +++ b/drivers/gpu/drm/i915/i915_mm.c @@ -35,8 +35,7 @@ struct remap_pfn { pgprot_t prot; }; -static int remap_pfn(pte_t *pte, pgtable_t token, - unsigned long addr, void *data) +static int remap_pfn(pte_t *pte, unsigned long addr, void *data) { struct remap_pfn *r = data; diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 826b3f047c0c..cf25f183c4a7 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -2372,10 +2372,10 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc) return 0; } -static int tegra_dc_match_by_pipe(struct device *dev, void *data) +static int tegra_dc_match_by_pipe(struct device *dev, const void *data) { struct tegra_dc *dc = dev_get_drvdata(dev); - unsigned int pipe = (unsigned long)data; + unsigned int pipe = (unsigned long)(void *)data; return dc->pipe == pipe; } diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 1549c7a2f04c..185a577c46f6 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -16,6 +16,7 @@ #include <linux/export.h> #include <linux/slab.h> #include <linux/mutex.h> +#include <linux/input/elan-i2c-ids.h> #include "hid-ids.h" @@ -916,6 +917,8 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { bool hid_ignore(struct hid_device *hdev) { + int i; + if (hdev->quirks & HID_QUIRK_NO_IGNORE) return false; if (hdev->quirks & HID_QUIRK_IGNORE) @@ -980,18 +983,15 @@ bool hid_ignore(struct hid_device *hdev) break; case USB_VENDOR_ID_ELAN: /* - * Many Elan devices have a product id of 0x0401 and are handled - * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev - * is not (and cannot be) handled by that driver -> - * Ignore all 0x0401 devs except for the ELAN0800 dev. + * Blacklist of everything that gets handled by the elan_i2c + * input driver. This avoids disabling valid touchpads and + * other ELAN devices. */ - if (hdev->product == 0x0401 && - strncmp(hdev->name, "ELAN0800", 8) != 0) - return true; - /* Same with product id 0x0400 */ - if (hdev->product == 0x0400 && - strncmp(hdev->name, "QTEC0001", 8) != 0) - return true; + if ((hdev->product == 0x0401 || hdev->product == 0x0400)) + for (i = 0; strlen(elan_acpi_id[i].id); ++i) + if (!strncmp(hdev->name, elan_acpi_id[i].id, + strlen(elan_acpi_id[i].id))) + return true; break; } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 72d5a7cde7ea..894da5abdc55 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -2163,6 +2163,7 @@ static void __exit vmbus_exit(void) MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Microsoft Hyper-V VMBus Driver"); subsys_initcall(hv_acpi_init); module_exit(vmbus_exit); diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 58bfd6319f65..2463aa7ab4f6 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -525,23 +525,12 @@ static const struct file_operations debug_func_knob_fops = { static int debug_func_init(void) { - struct dentry *file; int ret; /* Create debugfs node */ debug_debugfs_dir = debugfs_create_dir("coresight_cpu_debug", NULL); - if (!debug_debugfs_dir) { - pr_err("%s: unable to create debugfs directory\n", __func__); - return -ENOMEM; - } - - file = debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL, - &debug_func_knob_fops); - if (!file) { - pr_err("%s: unable to create enable knob file\n", __func__); - ret = -ENOMEM; - goto err; - } + debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL, + &debug_func_knob_fops); /* Register function to be called for panic */ ret = atomic_notifier_chain_register(&panic_notifier_list, diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index cf580ffbc27c..dad7d96c5943 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -37,7 +37,7 @@ static int coresight_alloc_conns(struct device *dev, return 0; } -int coresight_device_fwnode_match(struct device *dev, void *fwnode) +int coresight_device_fwnode_match(struct device *dev, const void *fwnode) { return dev_fwnode(dev) == fwnode; } diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 8b07fe55395a..7d401790dd7e 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -202,6 +202,6 @@ static inline void *coresight_get_uci_data(const struct amba_id *id) void coresight_release_platform_data(struct coresight_platform_data *pdata); -int coresight_device_fwnode_match(struct device *dev, void *fwnode); +int coresight_device_fwnode_match(struct device *dev, const void *fwnode); #endif diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 86d1fc2c1bd4..55db77f6410b 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -498,9 +498,9 @@ struct coresight_device *coresight_get_sink(struct list_head *path) return csdev; } -static int coresight_enabled_sink(struct device *dev, void *data) +static int coresight_enabled_sink(struct device *dev, const void *data) { - bool *reset = data; + const bool *reset = data; struct coresight_device *csdev = to_coresight_device(dev); if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || @@ -544,7 +544,7 @@ struct coresight_device *coresight_get_enabled_sink(bool deactivate) return dev ? to_coresight_device(dev) : NULL; } -static int coresight_sink_by_id(struct device *dev, void *data) +static int coresight_sink_by_id(struct device *dev, const void *data) { struct coresight_device *csdev = to_coresight_device(dev); unsigned long hash; diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 033dce563c99..55922896d862 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -789,10 +789,9 @@ static int intel_th_populate(struct intel_th *th) return 0; } -static int match_devt(struct device *dev, void *data) +static int match_devt(struct device *dev, const void *data) { - dev_t devt = (dev_t)(unsigned long)data; - + dev_t devt = (dev_t)(unsigned long)(void *)data; return dev->devt == devt; } diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index 455e1f36a2a3..c7fe3b44a860 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -457,7 +457,7 @@ static struct pci_driver amd_mp2_pci_driver = { }; module_pci_driver(amd_mp2_pci_driver); -static int amd_mp2_device_match(struct device *dev, void *data) +static int amd_mp2_device_match(struct device *dev, const void *data) { return 1; } diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 1969bfdfe6a4..428a82c3a35f 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -320,7 +320,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev) } EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); -static int i2c_acpi_find_match_adapter(struct device *dev, void *data) +static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) { struct i2c_adapter *adapter = i2c_verify_adapter(dev); @@ -330,7 +330,7 @@ static int i2c_acpi_find_match_adapter(struct device *dev, void *data) return ACPI_HANDLE(dev) == (acpi_handle)data; } -static int i2c_acpi_find_match_device(struct device *dev, void *data) +static int i2c_acpi_find_match_device(struct device *dev, const void *data) { return ACPI_COMPANION(dev) == data; } diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 406e5f695a7e..2eb59a260ad4 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -112,12 +112,12 @@ void of_i2c_register_devices(struct i2c_adapter *adap) of_node_put(bus); } -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } -static int of_dev_or_parent_node_match(struct device *dev, void *data) +static int of_dev_or_parent_node_match(struct device *dev, const void *data) { if (dev->of_node == data) return 1; diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 2fb2314548e9..5a8351c9a426 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -90,7 +90,7 @@ static const struct iio_chan_spec #ifdef CONFIG_OF -static int iio_dev_node_match(struct device *dev, void *data) +static int iio_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data && dev->type == &iio_device_type; } diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 829b0c6944d8..61758201d9b2 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -127,7 +127,7 @@ __malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size, res = (void *)pbundle->internal_buffer + pbundle->internal_used; pbundle->internal_used = ALIGN(new_used, sizeof(*pbundle->internal_buffer)); - if (flags & __GFP_ZERO) + if (want_init_on_alloc(flags)) memset(res, 0, size); return res; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index e068a02122f5..3afd3e9330e7 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -4498,7 +4498,7 @@ static const struct acpi_device_id hns_roce_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match); -static int hns_roce_node_match(struct device *dev, void *fwnode) +static int hns_roce_node_match(struct device *dev, const void *fwnode) { return dev->fwnode == fwnode; } diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index ac21c050fdb0..a2b5fbba2d3b 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -808,6 +808,7 @@ static bool joydev_dev_is_blacklisted(struct input_dev *dev) static bool joydev_dev_is_absolute_mouse(struct input_dev *dev) { DECLARE_BITMAP(jd_scratch, KEY_CNT); + bool ev_match = false; BUILD_BUG_ON(ABS_CNT > KEY_CNT || EV_CNT > KEY_CNT); @@ -826,17 +827,36 @@ static bool joydev_dev_is_absolute_mouse(struct input_dev *dev) * considered to be an absolute mouse if the following is * true: * - * 1) Event types are exactly EV_ABS, EV_KEY and EV_SYN. + * 1) Event types are exactly + * EV_ABS, EV_KEY and EV_SYN + * or + * EV_ABS, EV_KEY, EV_SYN and EV_MSC + * or + * EV_ABS, EV_KEY, EV_SYN, EV_MSC and EV_REL. * 2) Absolute events are exactly ABS_X and ABS_Y. * 3) Keys are exactly BTN_LEFT, BTN_RIGHT and BTN_MIDDLE. * 4) Device is not on "Amiga" bus. */ bitmap_zero(jd_scratch, EV_CNT); + /* VMware VMMouse, HP ILO2 */ __set_bit(EV_ABS, jd_scratch); __set_bit(EV_KEY, jd_scratch); __set_bit(EV_SYN, jd_scratch); - if (!bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + /* HP ILO2, AMI BMC firmware */ + __set_bit(EV_MSC, jd_scratch); + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + /* VMware Virtual USB Mouse, QEMU USB Tablet, ATEN BMC firmware */ + __set_bit(EV_REL, jd_scratch); + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + if (!ev_match) return false; bitmap_zero(jd_scratch, ABS_CNT); diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig index 62dcc5b71641..f002fb88f2e7 100644 --- a/drivers/input/joystick/iforce/Kconfig +++ b/drivers/input/joystick/iforce/Kconfig @@ -14,15 +14,15 @@ config JOYSTICK_IFORCE module will be called iforce. config JOYSTICK_IFORCE_USB - bool "I-Force USB joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB + tristate "I-Force USB joysticks and wheels" + depends on JOYSTICK_IFORCE && USB help Say Y here if you have an I-Force joystick or steering wheel connected to your USB port. config JOYSTICK_IFORCE_232 - bool "I-Force Serial joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO + tristate "I-Force Serial joysticks and wheels" + depends on JOYSTICK_IFORCE && SERIO help Say Y here if you have an I-Force joystick or steering wheel connected to your serial (COM) port. diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile index fa79a49d7ca1..dbbe7c04010d 100644 --- a/drivers/input/joystick/iforce/Makefile +++ b/drivers/input/joystick/iforce/Makefile @@ -5,8 +5,7 @@ # By Johann Deneux <johann.deneux@gmail.com> # -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o - +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o iforce-y := iforce-ff.o iforce-main.o iforce-packets.o -iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o -iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o +obj-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o +obj-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 2ed7da7d1f3e..4cadebd8b9c4 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c @@ -372,12 +372,12 @@ int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, stru } switch (effect->u.periodic.waveform) { - case FF_SQUARE: wave_code = 0x20; break; - case FF_TRIANGLE: wave_code = 0x21; break; - case FF_SINE: wave_code = 0x22; break; - case FF_SAW_UP: wave_code = 0x23; break; - case FF_SAW_DOWN: wave_code = 0x24; break; - default: wave_code = 0x20; break; + case FF_SQUARE: wave_code = 0x20; break; + case FF_TRIANGLE: wave_code = 0x21; break; + case FF_SINE: wave_code = 0x22; break; + case FF_SAW_UP: wave_code = 0x23; break; + case FF_SAW_DOWN: wave_code = 0x24; break; + default: wave_code = 0x20; break; } if (!old || need_core(old, effect)) { @@ -476,9 +476,9 @@ int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, str int core_err = 0; switch (effect->type) { - case FF_SPRING: type = 0x40; break; - case FF_DAMPER: type = 0x41; break; - default: return -1; + case FF_SPRING: type = 0x40; break; + case FF_DAMPER: type = 0x41; break; + default: return -1; } if (!old || need_condition_modifier(iforce, old, effect)) { diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 55f5b7bb4cac..9a5f90da06ec 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -9,10 +9,11 @@ /* */ +#include <asm/unaligned.h> #include "iforce.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>"); -MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); +MODULE_DESCRIPTION("Core I-Force joysticks and wheels driver"); MODULE_LICENSE("GPL"); static signed short btn_joystick[] = @@ -55,6 +56,7 @@ static struct iforce_device iforce_device[] = { { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? { 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, + { 0x06a3, 0xff04, "Saitek R440 Force Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback", btn_joystick, abs_joystick_rudder, ff_iforce }, { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? @@ -120,22 +122,21 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, * Upload the effect */ switch (effect->type) { + case FF_PERIODIC: + ret = iforce_upload_periodic(iforce, effect, old); + break; - case FF_PERIODIC: - ret = iforce_upload_periodic(iforce, effect, old); - break; - - case FF_CONSTANT: - ret = iforce_upload_constant(iforce, effect, old); - break; + case FF_CONSTANT: + ret = iforce_upload_constant(iforce, effect, old); + break; - case FF_SPRING: - case FF_DAMPER: - ret = iforce_upload_condition(iforce, effect, old); - break; + case FF_SPRING: + case FF_DAMPER: + ret = iforce_upload_condition(iforce, effect, old); + break; - default: - return -EINVAL; + default: + return -EINVAL; } if (ret == 0) { @@ -173,15 +174,7 @@ static int iforce_open(struct input_dev *dev) { struct iforce *iforce = input_get_drvdata(dev); - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - iforce->irq->dev = iforce->usbdev; - if (usb_submit_urb(iforce->irq, GFP_KERNEL)) - return -EIO; - break; -#endif - } + iforce->xport_ops->start_io(iforce); if (test_bit(EV_FF, dev->evbit)) { /* Enable force feedback */ @@ -214,27 +207,17 @@ static void iforce_close(struct input_dev *dev) !test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)); } - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - usb_kill_urb(iforce->irq); - usb_kill_urb(iforce->out); - usb_kill_urb(iforce->ctrl); - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - //TODO: Wait for the last packets to be sent - break; -#endif - } + iforce->xport_ops->stop_io(iforce); } -int iforce_init_device(struct iforce *iforce) +int iforce_init_device(struct device *parent, u16 bustype, + struct iforce *iforce) { struct input_dev *input_dev; struct ff_device *ff; - unsigned char c[] = "CEOV"; + u8 c[] = "CEOV"; + u8 buf[IFORCE_MAX_LENGTH]; + size_t len; int i, error; int ff_effects = 0; @@ -252,20 +235,8 @@ int iforce_init_device(struct iforce *iforce) * Input device fields. */ - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - input_dev->id.bustype = BUS_USB; - input_dev->dev.parent = &iforce->usbdev->dev; - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - input_dev->id.bustype = BUS_RS232; - input_dev->dev.parent = &iforce->serio->dev; - break; -#endif - } + input_dev->id.bustype = bustype; + input_dev->dev.parent = parent; input_set_drvdata(input_dev, iforce); @@ -290,7 +261,7 @@ int iforce_init_device(struct iforce *iforce) */ for (i = 0; i < 20; i++) - if (!iforce_get_id_packet(iforce, "O")) + if (!iforce_get_id_packet(iforce, 'O', buf, &len)) break; if (i == 20) { /* 5 seconds */ @@ -304,23 +275,23 @@ int iforce_init_device(struct iforce *iforce) * Get device info. */ - if (!iforce_get_id_packet(iforce, "M")) - input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3) + input_dev->id.vendor = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n"); - if (!iforce_get_id_packet(iforce, "P")) - input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3) + input_dev->id.product = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n"); - if (!iforce_get_id_packet(iforce, "B")) - iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3) + iforce->device_memory.end = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n"); - if (!iforce_get_id_packet(iforce, "N")) - ff_effects = iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2) + ff_effects = buf[1]; else dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n"); @@ -336,8 +307,9 @@ int iforce_init_device(struct iforce *iforce) */ for (i = 0; c[i]; i++) - if (!iforce_get_id_packet(iforce, c + i)) - iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata); + if (!iforce_get_id_packet(iforce, c[i], buf, &len)) + iforce_dump_packet(iforce, "info", + (FF_CMD_QUERY & 0xff00) | len, buf); /* * Disable spring, enable force feedback. @@ -371,34 +343,29 @@ int iforce_init_device(struct iforce *iforce) signed short t = iforce->type->abs[i]; switch (t) { + case ABS_X: + case ABS_Y: + case ABS_WHEEL: + input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); + set_bit(t, input_dev->ffbit); + break; - case ABS_X: - case ABS_Y: - case ABS_WHEEL: - - input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); - set_bit(t, input_dev->ffbit); - break; - - case ABS_THROTTLE: - case ABS_GAS: - case ABS_BRAKE: - - input_set_abs_params(input_dev, t, 0, 255, 0, 0); - break; - - case ABS_RUDDER: - - input_set_abs_params(input_dev, t, -128, 127, 0, 0); - break; + case ABS_THROTTLE: + case ABS_GAS: + case ABS_BRAKE: + input_set_abs_params(input_dev, t, 0, 255, 0, 0); + break; - case ABS_HAT0X: - case ABS_HAT0Y: - case ABS_HAT1X: - case ABS_HAT1Y: + case ABS_RUDDER: + input_set_abs_params(input_dev, t, -128, 127, 0, 0); + break; - input_set_abs_params(input_dev, t, -1, 1, 0, 0); - break; + case ABS_HAT0X: + case ABS_HAT0Y: + case ABS_HAT1X: + case ABS_HAT1Y: + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + break; } } @@ -431,35 +398,4 @@ int iforce_init_device(struct iforce *iforce) fail: input_free_device(input_dev); return error; } - -static int __init iforce_init(void) -{ - int err = 0; - -#ifdef CONFIG_JOYSTICK_IFORCE_USB - err = usb_register(&iforce_usb_driver); - if (err) - return err; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - err = serio_register_driver(&iforce_serio_drv); -#ifdef CONFIG_JOYSTICK_IFORCE_USB - if (err) - usb_deregister(&iforce_usb_driver); -#endif -#endif - return err; -} - -static void __exit iforce_exit(void) -{ -#ifdef CONFIG_JOYSTICK_IFORCE_USB - usb_deregister(&iforce_usb_driver); -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_unregister_driver(&iforce_serio_drv); -#endif -} - -module_init(iforce_init); -module_exit(iforce_exit); +EXPORT_SYMBOL(iforce_init_device); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 42cd9730e4cc..b313e38b2c3a 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -9,6 +9,7 @@ /* */ +#include <asm/unaligned.h> #include "iforce.h" static struct { @@ -79,27 +80,12 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) /* * If necessary, start the transmission */ - switch (iforce->bus) { + if (empty) + iforce->xport_ops->xmit(iforce); -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - if (empty) - iforce_serial_xmit(iforce); - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - - if (iforce->usbdev && empty && - !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { - - iforce_usb_xmit(iforce); - } - break; -#endif - } return 0; } +EXPORT_SYMBOL(iforce_send_packet); /* Start or stop an effect */ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) @@ -133,157 +119,96 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) return -1; } -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data) { struct input_dev *dev = iforce->dev; int i; - static int being_used = 0; - if (being_used) - dev_warn(&iforce->dev->dev, - "re-entrant call to iforce_process %d\n", being_used); - being_used++; - -#ifdef CONFIG_JOYSTICK_IFORCE_232 - if (HI(iforce->expect_packet) == HI(cmd)) { - iforce->expect_packet = 0; - iforce->ecmd = cmd; - memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); - } -#endif - wake_up(&iforce->wait); + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - if (!iforce->type) { - being_used--; - return; - } - - switch (HI(cmd)) { - - case 0x01: /* joystick position data */ - case 0x03: /* wheel position data */ - if (HI(cmd) == 1) { - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) - input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); - } else { - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_GAS, 255 - data[2]); - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); - } + for (i = 0; iforce->type->btn[i] >= 0; i++) + input_report_key(dev, iforce->type->btn[i], + data[(i >> 3) + 5] & (1 << (i & 7))); - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - - for (i = 0; iforce->type->btn[i] >= 0; i++) - input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); - - /* If there are untouched bits left, interpret them as the second hat */ - if (i <= 8) { - int btns = data[6]; - if (test_bit(ABS_HAT1X, dev->absbit)) { - if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1); - else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1); - else input_report_abs(dev, ABS_HAT1X, 0); - } - if (test_bit(ABS_HAT1Y, dev->absbit)) { - if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1); - else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1); - else input_report_abs(dev, ABS_HAT1Y, 0); - } - } + /* If there are untouched bits left, interpret them as the second hat */ + if (i <= 8) { + u8 btns = data[6]; - input_sync(dev); - - break; - - case 0x02: /* status report */ - input_report_key(dev, BTN_DEAD, data[0] & 0x02); - input_sync(dev); + if (test_bit(ABS_HAT1X, dev->absbit)) { + if (btns & BIT(3)) + input_report_abs(dev, ABS_HAT1X, -1); + else if (btns & BIT(1)) + input_report_abs(dev, ABS_HAT1X, 1); + else + input_report_abs(dev, ABS_HAT1X, 0); + } - /* Check if an effect was just started or stopped */ - i = data[1] & 0x7f; - if (data[1] & 0x80) { - if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { - /* Report play event */ - input_report_ff_status(dev, i, FF_STATUS_PLAYING); - } - } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { - /* Report stop event */ - input_report_ff_status(dev, i, FF_STATUS_STOPPED); - } - if (LO(cmd) > 3) { - int j; - for (j = 3; j < LO(cmd); j += 2) - mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); - } - break; + if (test_bit(ABS_HAT1Y, dev->absbit)) { + if (btns & BIT(0)) + input_report_abs(dev, ABS_HAT1Y, -1); + else if (btns & BIT(2)) + input_report_abs(dev, ABS_HAT1Y, 1); + else + input_report_abs(dev, ABS_HAT1Y, 0); + } } - being_used--; } -int iforce_get_id_packet(struct iforce *iforce, char *packet) +void iforce_process_packet(struct iforce *iforce, + u8 packet_id, u8 *data, size_t len) { - switch (iforce->bus) { + struct input_dev *dev = iforce->dev; + int i, j; - case IFORCE_USB: { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - int status; + switch (packet_id) { - iforce->cr.bRequest = packet[0]; - iforce->ctrl->dev = iforce->usbdev; + case 0x01: /* joystick position data */ + input_report_abs(dev, ABS_X, + (__s16) get_unaligned_le16(data)); + input_report_abs(dev, ABS_Y, + (__s16) get_unaligned_le16(data + 2)); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - status = usb_submit_urb(iforce->ctrl, GFP_KERNEL); - if (status) { - dev_err(&iforce->intf->dev, - "usb_submit_urb failed %d\n", status); - return -1; - } + if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); - wait_event_interruptible_timeout(iforce->wait, - iforce->ctrl->status != -EINPROGRESS, HZ); + iforce_report_hats_buttons(iforce, data); - if (iforce->ctrl->status) { - dev_dbg(&iforce->intf->dev, - "iforce->ctrl->status = %d\n", - iforce->ctrl->status); - usb_unlink_urb(iforce->ctrl); - return -1; - } -#else - printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n"); -#endif - } + input_sync(dev); break; - case IFORCE_232: + case 0x03: /* wheel position data */ + input_report_abs(dev, ABS_WHEEL, + (__s16) get_unaligned_le16(data)); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); -#ifdef CONFIG_JOYSTICK_IFORCE_232 - iforce->expect_packet = FF_CMD_QUERY; - iforce_send_packet(iforce, FF_CMD_QUERY, packet); + iforce_report_hats_buttons(iforce, data); - wait_event_interruptible_timeout(iforce->wait, - !iforce->expect_packet, HZ); + input_sync(dev); + break; + + case 0x02: /* status report */ + input_report_key(dev, BTN_DEAD, data[0] & 0x02); + input_sync(dev); - if (iforce->expect_packet) { - iforce->expect_packet = 0; - return -1; + /* Check if an effect was just started or stopped */ + i = data[1] & 0x7f; + if (data[1] & 0x80) { + if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report play event */ + input_report_ff_status(dev, i, FF_STATUS_PLAYING); + } + } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report stop event */ + input_report_ff_status(dev, i, FF_STATUS_STOPPED); } -#else - dev_err(&iforce->dev->dev, - "iforce_get_id_packet: iforce->bus = SERIO!\n"); -#endif - break; - default: - dev_err(&iforce->dev->dev, - "iforce_get_id_packet: iforce->bus = %d\n", - iforce->bus); + for (j = 3; j < len; j += 2) + mark_core_as_ready(iforce, get_unaligned_le16(data + j)); + break; } - - return -(iforce->edata[0] != packet[0]); } - +EXPORT_SYMBOL(iforce_process_packet); diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 65a4fe26324f..bbe31e0b759f 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -9,10 +9,26 @@ /* */ +#include <linux/serio.h> #include "iforce.h" -void iforce_serial_xmit(struct iforce *iforce) +struct iforce_serio { + struct iforce iforce; + + struct serio *serio; + int idx, pkt, len, id; + u8 csum; + u8 expect_packet; + u8 cmd_response[IFORCE_MAX_LENGTH]; + u8 cmd_response_len; + u8 data_in[IFORCE_MAX_LENGTH]; +}; + +static void iforce_serio_xmit(struct iforce *iforce) { + struct iforce_serio *iforce_serio = container_of(iforce, + struct iforce_serio, + iforce); unsigned char cs; int i; unsigned long flags; @@ -33,19 +49,20 @@ again: cs = 0x2b; - serio_write(iforce->serio, 0x2b); + serio_write(iforce_serio->serio, 0x2b); - serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { - serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + serio_write(iforce_serio->serio, + iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); } - serio_write(iforce->serio, cs); + serio_write(iforce_serio->serio, cs); if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) goto again; @@ -55,54 +72,118 @@ again: spin_unlock_irqrestore(&iforce->xmit_lock, flags); } +static int iforce_serio_get_id(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) +{ + struct iforce_serio *iforce_serio = container_of(iforce, + struct iforce_serio, + iforce); + + iforce_serio->expect_packet = HI(FF_CMD_QUERY); + iforce_serio->cmd_response_len = 0; + + iforce_send_packet(iforce, FF_CMD_QUERY, &id); + + wait_event_interruptible_timeout(iforce->wait, + !iforce_serio->expect_packet, HZ); + + if (iforce_serio->expect_packet) { + iforce_serio->expect_packet = 0; + return -ETIMEDOUT; + } + + if (iforce_serio->cmd_response[0] != id) + return -EIO; + + memcpy(response_data, iforce_serio->cmd_response, + iforce_serio->cmd_response_len); + *response_len = iforce_serio->cmd_response_len; + + return 0; +} + +static int iforce_serio_start_io(struct iforce *iforce) +{ + /* No special handling required */ + return 0; +} + +static void iforce_serio_stop_io(struct iforce *iforce) +{ + //TODO: Wait for the last packets to be sent +} + +static const struct iforce_xport_ops iforce_serio_xport_ops = { + .xmit = iforce_serio_xmit, + .get_id = iforce_serio_get_id, + .start_io = iforce_serio_start_io, + .stop_io = iforce_serio_stop_io, +}; + static void iforce_serio_write_wakeup(struct serio *serio) { struct iforce *iforce = serio_get_drvdata(serio); - iforce_serial_xmit(iforce); + iforce_serio_xmit(iforce); } static irqreturn_t iforce_serio_irq(struct serio *serio, - unsigned char data, unsigned int flags) + unsigned char data, unsigned int flags) { - struct iforce *iforce = serio_get_drvdata(serio); + struct iforce_serio *iforce_serio = serio_get_drvdata(serio); + struct iforce *iforce = &iforce_serio->iforce; - if (!iforce->pkt) { + if (!iforce_serio->pkt) { if (data == 0x2b) - iforce->pkt = 1; + iforce_serio->pkt = 1; goto out; } - if (!iforce->id) { + if (!iforce_serio->id) { if (data > 3 && data != 0xff) - iforce->pkt = 0; + iforce_serio->pkt = 0; else - iforce->id = data; + iforce_serio->id = data; goto out; } - if (!iforce->len) { + if (!iforce_serio->len) { if (data > IFORCE_MAX_LENGTH) { - iforce->pkt = 0; - iforce->id = 0; + iforce_serio->pkt = 0; + iforce_serio->id = 0; } else { - iforce->len = data; + iforce_serio->len = data; } goto out; } - if (iforce->idx < iforce->len) { - iforce->csum += iforce->data[iforce->idx++] = data; + if (iforce_serio->idx < iforce_serio->len) { + iforce_serio->data_in[iforce_serio->idx++] = data; + iforce_serio->csum += data; goto out; } - if (iforce->idx == iforce->len) { - iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); - iforce->pkt = 0; - iforce->id = 0; - iforce->len = 0; - iforce->idx = 0; - iforce->csum = 0; + if (iforce_serio->idx == iforce_serio->len) { + /* Handle command completion */ + if (iforce_serio->expect_packet == iforce_serio->id) { + iforce_serio->expect_packet = 0; + memcpy(iforce_serio->cmd_response, + iforce_serio->data_in, IFORCE_MAX_LENGTH); + iforce_serio->cmd_response_len = iforce_serio->len; + + /* Signal that command is done */ + wake_up(&iforce->wait); + } else if (likely(iforce->type)) { + iforce_process_packet(iforce, iforce_serio->id, + iforce_serio->data_in, + iforce_serio->len); + } + + iforce_serio->pkt = 0; + iforce_serio->id = 0; + iforce_serio->len = 0; + iforce_serio->idx = 0; + iforce_serio->csum = 0; } out: return IRQ_HANDLED; @@ -110,23 +191,23 @@ out: static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { - struct iforce *iforce; + struct iforce_serio *iforce_serio; int err; - iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL); - if (!iforce) + iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL); + if (!iforce_serio) return -ENOMEM; - iforce->bus = IFORCE_232; - iforce->serio = serio; + iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops; - serio_set_drvdata(serio, iforce); + iforce_serio->serio = serio; + serio_set_drvdata(serio, iforce_serio); err = serio_open(serio, drv); if (err) goto fail1; - err = iforce_init_device(iforce); + err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce); if (err) goto fail2; @@ -134,18 +215,18 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) fail2: serio_close(serio); fail1: serio_set_drvdata(serio, NULL); - kfree(iforce); + kfree(iforce_serio); return err; } static void iforce_serio_disconnect(struct serio *serio) { - struct iforce *iforce = serio_get_drvdata(serio); + struct iforce_serio *iforce_serio = serio_get_drvdata(serio); - input_unregister_device(iforce->dev); + input_unregister_device(iforce_serio->iforce.dev); serio_close(serio); serio_set_drvdata(serio, NULL); - kfree(iforce); + kfree(iforce_serio); } static const struct serio_device_id iforce_serio_ids[] = { @@ -171,3 +252,9 @@ struct serio_driver iforce_serio_drv = { .connect = iforce_serio_connect, .disconnect = iforce_serio_disconnect, }; + +module_serio_driver(iforce_serio_drv); + +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>"); +MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index f1569ae8381b..ade376bfb79f 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -9,10 +9,24 @@ /* */ +#include <linux/usb.h> #include "iforce.h" -void iforce_usb_xmit(struct iforce *iforce) +struct iforce_usb { + struct iforce iforce; + + struct usb_device *usbdev; + struct usb_interface *intf; + struct urb *irq, *out; + + u8 data_in[IFORCE_MAX_LENGTH] ____cacheline_aligned; + u8 data_out[IFORCE_MAX_LENGTH] ____cacheline_aligned; +}; + +static void __iforce_usb_xmit(struct iforce *iforce) { + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); int n, c; unsigned long flags; @@ -24,31 +38,32 @@ void iforce_usb_xmit(struct iforce *iforce) return; } - ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; + ((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); n = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); - iforce->out->transfer_buffer_length = n + 1; - iforce->out->dev = iforce->usbdev; + iforce_usb->out->transfer_buffer_length = n + 1; + iforce_usb->out->dev = iforce_usb->usbdev; /* Copy rest of data then */ c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); if (n < c) c=n; - memcpy(iforce->out->transfer_buffer + 1, + memcpy(iforce_usb->out->transfer_buffer + 1, &iforce->xmit.buf[iforce->xmit.tail], c); if (n != c) { - memcpy(iforce->out->transfer_buffer + 1 + c, + memcpy(iforce_usb->out->transfer_buffer + 1 + c, &iforce->xmit.buf[0], n-c); } XMIT_INC(iforce->xmit.tail, n); - if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) { + if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) { clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); - dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n); + dev_warn(&iforce_usb->intf->dev, + "usb_submit_urb failed %d\n", n); } /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. @@ -57,10 +72,77 @@ void iforce_usb_xmit(struct iforce *iforce) spin_unlock_irqrestore(&iforce->xmit_lock, flags); } +static void iforce_usb_xmit(struct iforce *iforce) +{ + if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) + __iforce_usb_xmit(iforce); +} + +static int iforce_usb_get_id(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) +{ + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + u8 *buf; + int status; + + buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + status = usb_control_msg(iforce_usb->usbdev, + usb_rcvctrlpipe(iforce_usb->usbdev, 0), + id, + USB_TYPE_VENDOR | USB_DIR_IN | + USB_RECIP_INTERFACE, + 0, 0, buf, IFORCE_MAX_LENGTH, HZ); + if (status < 0) { + dev_err(&iforce_usb->intf->dev, + "usb_submit_urb failed: %d\n", status); + } else if (buf[0] != id) { + status = -EIO; + } else { + memcpy(response_data, buf, status); + *response_len = status; + status = 0; + } + + kfree(buf); + return status; +} + +static int iforce_usb_start_io(struct iforce *iforce) +{ + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + + if (usb_submit_urb(iforce_usb->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void iforce_usb_stop_io(struct iforce *iforce) +{ + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + + usb_kill_urb(iforce_usb->irq); + usb_kill_urb(iforce_usb->out); +} + +static const struct iforce_xport_ops iforce_usb_xport_ops = { + .xmit = iforce_usb_xmit, + .get_id = iforce_usb_get_id, + .start_io = iforce_usb_start_io, + .stop_io = iforce_usb_stop_io, +}; + static void iforce_usb_irq(struct urb *urb) { - struct iforce *iforce = urb->context; - struct device *dev = &iforce->intf->dev; + struct iforce_usb *iforce_usb = urb->context; + struct iforce *iforce = &iforce_usb->iforce; + struct device *dev = &iforce_usb->intf->dev; int status; switch (urb->status) { @@ -80,11 +162,11 @@ static void iforce_usb_irq(struct urb *urb) goto exit; } - iforce_process_packet(iforce, - (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); + iforce_process_packet(iforce, iforce_usb->data_in[0], + iforce_usb->data_in + 1, urb->actual_length - 1); exit: - status = usb_submit_urb (urb, GFP_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, status); @@ -92,35 +174,28 @@ exit: static void iforce_usb_out(struct urb *urb) { - struct iforce *iforce = urb->context; + struct iforce_usb *iforce_usb = urb->context; + struct iforce *iforce = &iforce_usb->iforce; if (urb->status) { clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); - dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n", + dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n", urb->status); return; } - iforce_usb_xmit(iforce); + __iforce_usb_xmit(iforce); wake_up(&iforce->wait); } -static void iforce_usb_ctrl(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - iforce->ecmd = 0xff00 | urb->actual_length; - wake_up(&iforce->wait); -} - static int iforce_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *epirq, *epout; - struct iforce *iforce; + struct iforce_usb *iforce_usb; int err = -ENOMEM; interface = intf->cur_altsetting; @@ -131,48 +206,45 @@ static int iforce_usb_probe(struct usb_interface *intf, epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; - if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) - goto fail; - - if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb = kzalloc(sizeof(*iforce_usb), GFP_KERNEL); + if (!iforce_usb) goto fail; - if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!iforce_usb->irq) goto fail; - if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL); + if (!iforce_usb->out) goto fail; - iforce->bus = IFORCE_USB; - iforce->usbdev = dev; - iforce->intf = intf; - - iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; - iforce->cr.wIndex = 0; - iforce->cr.wLength = cpu_to_le16(16); + iforce_usb->iforce.xport_ops = &iforce_usb_xport_ops; - usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), - iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); + iforce_usb->usbdev = dev; + iforce_usb->intf = intf; - usb_fill_int_urb(iforce->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress), - iforce + 1, 32, iforce_usb_out, iforce, epout->bInterval); + usb_fill_int_urb(iforce_usb->irq, dev, + usb_rcvintpipe(dev, epirq->bEndpointAddress), + iforce_usb->data_in, sizeof(iforce_usb->data_in), + iforce_usb_irq, iforce_usb, epirq->bInterval); - usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), - (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); + usb_fill_int_urb(iforce_usb->out, dev, + usb_sndintpipe(dev, epout->bEndpointAddress), + iforce_usb->data_out, sizeof(iforce_usb->data_out), + iforce_usb_out, iforce_usb, epout->bInterval); - err = iforce_init_device(iforce); + err = iforce_init_device(&intf->dev, BUS_USB, &iforce_usb->iforce); if (err) goto fail; - usb_set_intfdata(intf, iforce); + usb_set_intfdata(intf, iforce_usb); return 0; fail: - if (iforce) { - usb_free_urb(iforce->irq); - usb_free_urb(iforce->out); - usb_free_urb(iforce->ctrl); - kfree(iforce); + if (iforce_usb) { + usb_free_urb(iforce_usb->irq); + usb_free_urb(iforce_usb->out); + kfree(iforce_usb); } return err; @@ -180,17 +252,16 @@ fail: static void iforce_usb_disconnect(struct usb_interface *intf) { - struct iforce *iforce = usb_get_intfdata(intf); + struct iforce_usb *iforce_usb = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); - input_unregister_device(iforce->dev); + input_unregister_device(iforce_usb->iforce.dev); - usb_free_urb(iforce->irq); - usb_free_urb(iforce->out); - usb_free_urb(iforce->ctrl); + usb_free_urb(iforce_usb->irq); + usb_free_urb(iforce_usb->out); - kfree(iforce); + kfree(iforce_usb); } static const struct usb_device_id iforce_usb_ids[] = { @@ -202,6 +273,7 @@ static const struct usb_device_id iforce_usb_ids[] = { { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ { USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */ { USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */ + { USB_DEVICE(0x06a3, 0xff04) }, /* Saitek R440 Force Wheel */ { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0003) }, /* Guillemot Jet Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ @@ -217,3 +289,9 @@ struct usb_driver iforce_usb_driver = { .disconnect = iforce_usb_disconnect, .id_table = iforce_usb_ids, }; + +module_usb_driver(iforce_usb_driver); + +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>"); +MODULE_DESCRIPTION("USB I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index f1681706f526..9cfa460466aa 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -14,8 +14,6 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <linux/usb.h> -#include <linux/serio.h> #include <linux/circ_buf.h> #include <linux/mutex.h> @@ -28,10 +26,6 @@ #define IFORCE_MAX_LENGTH 16 -/* iforce::bus */ -#define IFORCE_232 1 -#define IFORCE_USB 2 - #define IFORCE_EFFECTS_MAX 32 /* Each force feedback effect is made of one core effect, which can be @@ -81,27 +75,21 @@ struct iforce_device { signed short *ff; }; +struct iforce; + +struct iforce_xport_ops { + void (*xmit)(struct iforce *iforce); + int (*get_id)(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len); + int (*start_io)(struct iforce *iforce); + void (*stop_io)(struct iforce *iforce); +}; + struct iforce { struct input_dev *dev; /* Input device interface */ struct iforce_device *type; - int bus; - - unsigned char data[IFORCE_MAX_LENGTH]; - unsigned char edata[IFORCE_MAX_LENGTH]; - u16 ecmd; - u16 expect_packet; - -#ifdef CONFIG_JOYSTICK_IFORCE_232 - struct serio *serio; /* RS232 transfer */ - int idx, pkt, len, id; - unsigned char csum; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_USB - struct usb_device *usbdev; /* USB transfer */ - struct usb_interface *intf; - struct urb *irq, *out, *ctrl; - struct usb_ctrlrequest cr; -#endif + const struct iforce_xport_ops *xport_ops; + spinlock_t xmit_lock; /* Buffer used for asynchronous sending of bytes to the device */ struct circ_buf xmit; @@ -127,23 +115,24 @@ struct iforce { /* Encode a time value */ #define TIME_SCALE(a) (a) +static inline int iforce_get_id_packet(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) +{ + return iforce->xport_ops->get_id(iforce, id, + response_data, response_len); +} /* Public functions */ -/* iforce-serio.c */ -void iforce_serial_xmit(struct iforce *iforce); - -/* iforce-usb.c */ -void iforce_usb_xmit(struct iforce *iforce); - /* iforce-main.c */ -int iforce_init_device(struct iforce *iforce); +int iforce_init_device(struct device *parent, u16 bustype, + struct iforce *iforce); /* iforce-packets.c */ int iforce_control_playback(struct iforce*, u16 id, unsigned int); -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); +void iforce_process_packet(struct iforce *iforce, + u8 packet_id, u8 *data, size_t len); int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data); -int iforce_get_id_packet(struct iforce *iforce, char *packet); /* iforce-ff.c */ int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index a23c23979a2e..03f4d152f6b7 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -771,7 +771,6 @@ static int gpio_keys_probe(struct platform_device *pdev) struct fwnode_handle *child = NULL; struct gpio_keys_drvdata *ddata; struct input_dev *input; - size_t size; int i, error; int wakeup = 0; @@ -781,9 +780,8 @@ static int gpio_keys_probe(struct platform_device *pdev) return PTR_ERR(pdata); } - size = sizeof(struct gpio_keys_drvdata) + - pdata->nbuttons * sizeof(struct gpio_button_data); - ddata = devm_kzalloc(dev, size, GFP_KERNEL); + ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons), + GFP_KERNEL); if (!ddata) { dev_err(dev, "failed to allocate state\n"); return -ENOMEM; diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 1eafe6b848ba..465eecfa6b3f 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -165,6 +165,8 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev) pdata->rep = device_property_present(dev, "autorepeat"); device_property_read_u32(dev, "poll-interval", &pdata->poll_interval); + device_property_read_string(dev, "label", &pdata->name); + device_for_each_child_node(dev, child) { if (fwnode_property_read_u32(child, "linux,code", &button->code)) { @@ -232,7 +234,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) struct gpio_keys_polled_dev *bdev; struct input_polled_dev *poll_dev; struct input_dev *input; - size_t size; int error; int i; @@ -247,9 +248,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) return -EINVAL; } - size = sizeof(struct gpio_keys_polled_dev) + - pdata->nbuttons * sizeof(struct gpio_keys_button_data); - bdev = devm_kzalloc(dev, size, GFP_KERNEL); + bdev = devm_kzalloc(dev, struct_size(bdev, data, pdata->nbuttons), + GFP_KERNEL); if (!bdev) { dev_err(dev, "no memory for private data\n"); return -ENOMEM; @@ -269,7 +269,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) input = poll_dev->input; - input->name = pdev->name; + input->name = pdata->name ?: pdev->name; input->phys = DRV_NAME"/input0"; input->id.bustype = BUS_HOST; diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index ae9c51cc85f9..97500a2de2d5 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -422,7 +422,6 @@ static int imx_keypad_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev); struct imx_keypad *keypad; struct input_dev *input_dev; - struct resource *res; int irq, error, i, row, col; if (!keymap_data && !pdev->dev.of_node) { @@ -455,8 +454,7 @@ static int imx_keypad_probe(struct platform_device *pdev) timer_setup(&keypad->check_matrix_timer, imx_keypad_check_for_events, 0); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); + keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(keypad->mmio_base)) return PTR_ERR(keypad->mmio_base); diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 6da607d3b811..3bbd7e652533 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -266,7 +266,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, struct tca8418_keypad *keypad_data; struct input_dev *input; u32 rows = 0, cols = 0; - int error, row_shift, max_keys; + int error, row_shift; u8 reg; /* Check i2c driver capabilities */ @@ -291,7 +291,6 @@ static int tca8418_keypad_probe(struct i2c_client *client, } row_shift = get_count_order(cols); - max_keys = rows << row_shift; /* Allocate memory for keypad_data and input device */ keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL); diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index 9d39679372c5..fd355cf59397 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -13,7 +13,6 @@ #include <linux/regmap.h> #include <linux/of.h> #include <linux/mfd/da9063/core.h> -#include <linux/mfd/da9063/pdata.h> #include <linux/mfd/da9063/registers.h> #include <linux/mfd/da9062/core.h> #include <linux/mfd/da9062/registers.h> @@ -192,8 +191,6 @@ static void da9063_cancel_poll(void *data) static int da9063_onkey_probe(struct platform_device *pdev) { - struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); - struct da9063_pdata *pdata = dev_get_platdata(da9063->dev); struct da9063_onkey *onkey; const struct of_device_id *match; int irq; @@ -220,12 +217,8 @@ static int da9063_onkey_probe(struct platform_device *pdev) return -ENXIO; } - if (pdata) - onkey->key_power = pdata->key_power; - else - onkey->key_power = - !of_property_read_bool(pdev->dev.of_node, - "dlg,disable-key-power"); + onkey->key_power = !of_property_read_bool(pdev->dev.of_node, + "dlg,disable-key-power"); onkey->input = devm_input_allocate_device(&pdev->dev); if (!onkey->input) { diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c index fbf6caab7217..4d875f2ac13d 100644 --- a/drivers/input/misc/max77650-onkey.c +++ b/drivers/input/misc/max77650-onkey.c @@ -119,3 +119,4 @@ module_platform_driver(max77650_onkey_driver); MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver"); MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-onkey"); diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 420efaab3860..d9b103a81a79 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -34,6 +34,7 @@ #include <linux/completion.h> #include <linux/of.h> #include <linux/property.h> +#include <linux/input/elan-i2c-ids.h> #include <linux/regulator/consumer.h> #include <asm/unaligned.h> @@ -96,6 +97,7 @@ struct elan_tp_data { u8 max_baseline; bool baseline_ready; u8 clickpad; + bool middle_button; }; static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, @@ -363,27 +365,62 @@ static unsigned int elan_convert_resolution(u8 val) static int elan_query_device_parameters(struct elan_tp_data *data) { + struct i2c_client *client = data->client; unsigned int x_traces, y_traces; + u32 x_mm, y_mm; u8 hw_x_res, hw_y_res; int error; - error = data->ops->get_max(data->client, &data->max_x, &data->max_y); - if (error) - return error; - - error = data->ops->get_num_traces(data->client, &x_traces, &y_traces); - if (error) - return error; + if (device_property_read_u32(&client->dev, + "touchscreen-size-x", &data->max_x) || + device_property_read_u32(&client->dev, + "touchscreen-size-y", &data->max_y)) { + error = data->ops->get_max(data->client, + &data->max_x, + &data->max_y); + if (error) + return error; + } else { + /* size is the maximum + 1 */ + --data->max_x; + --data->max_y; + } + if (device_property_read_u32(&client->dev, + "elan,x_traces", + &x_traces) || + device_property_read_u32(&client->dev, + "elan,y_traces", + &y_traces)) { + error = data->ops->get_num_traces(data->client, + &x_traces, &y_traces); + if (error) + return error; + } data->width_x = data->max_x / x_traces; data->width_y = data->max_y / y_traces; - error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res); - if (error) - return error; + if (device_property_read_u32(&client->dev, + "touchscreen-x-mm", &x_mm) || + device_property_read_u32(&client->dev, + "touchscreen-y-mm", &y_mm)) { + error = data->ops->get_resolution(data->client, + &hw_x_res, &hw_y_res); + if (error) + return error; + + data->x_res = elan_convert_resolution(hw_x_res); + data->y_res = elan_convert_resolution(hw_y_res); + } else { + data->x_res = (data->max_x + 1) / x_mm; + data->y_res = (data->max_y + 1) / y_mm; + } + + if (device_property_read_bool(&client->dev, "elan,clickpad")) + data->clickpad = 1; - data->x_res = elan_convert_resolution(hw_x_res); - data->y_res = elan_convert_resolution(hw_y_res); + if (device_property_read_bool(&client->dev, "elan,middle-button")) + data->middle_button = true; return 0; } @@ -923,8 +960,9 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) finger_data += ETP_FINGER_DATA_LEN; } - input_report_key(input, BTN_LEFT, tp_info & 0x01); - input_report_key(input, BTN_RIGHT, tp_info & 0x02); + input_report_key(input, BTN_LEFT, tp_info & BIT(0)); + input_report_key(input, BTN_MIDDLE, tp_info & BIT(2)); + input_report_key(input, BTN_RIGHT, tp_info & BIT(1)); input_report_abs(input, ABS_DISTANCE, hover_event != 0); input_mt_report_pointer_emulation(input, true); input_sync(input); @@ -1058,10 +1096,13 @@ static int elan_setup_input_device(struct elan_tp_data *data) __set_bit(EV_ABS, input->evbit); __set_bit(INPUT_PROP_POINTER, input->propbit); - if (data->clickpad) + if (data->clickpad) { __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); - else + } else { __set_bit(BTN_RIGHT, input->keybit); + if (data->middle_button) + __set_bit(BTN_MIDDLE, input->keybit); + } __set_bit(BTN_LEFT, input->keybit); /* Set up ST parameters */ @@ -1332,55 +1373,6 @@ static const struct i2c_device_id elan_id[] = { MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI -static const struct acpi_device_id elan_acpi_id[] = { - { "ELAN0000", 0 }, - { "ELAN0100", 0 }, - { "ELAN0600", 0 }, - { "ELAN0601", 0 }, - { "ELAN0602", 0 }, - { "ELAN0603", 0 }, - { "ELAN0604", 0 }, - { "ELAN0605", 0 }, - { "ELAN0606", 0 }, - { "ELAN0607", 0 }, - { "ELAN0608", 0 }, - { "ELAN0609", 0 }, - { "ELAN060B", 0 }, - { "ELAN060C", 0 }, - { "ELAN060F", 0 }, - { "ELAN0610", 0 }, - { "ELAN0611", 0 }, - { "ELAN0612", 0 }, - { "ELAN0615", 0 }, - { "ELAN0616", 0 }, - { "ELAN0617", 0 }, - { "ELAN0618", 0 }, - { "ELAN0619", 0 }, - { "ELAN061A", 0 }, - { "ELAN061B", 0 }, - { "ELAN061C", 0 }, - { "ELAN061D", 0 }, - { "ELAN061E", 0 }, - { "ELAN061F", 0 }, - { "ELAN0620", 0 }, - { "ELAN0621", 0 }, - { "ELAN0622", 0 }, - { "ELAN0623", 0 }, - { "ELAN0624", 0 }, - { "ELAN0625", 0 }, - { "ELAN0626", 0 }, - { "ELAN0627", 0 }, - { "ELAN0628", 0 }, - { "ELAN0629", 0 }, - { "ELAN062A", 0 }, - { "ELAN062B", 0 }, - { "ELAN062C", 0 }, - { "ELAN062D", 0 }, - { "ELAN0631", 0 }, - { "ELAN0632", 0 }, - { "ELAN1000", 0 }, - { } -}; MODULE_DEVICE_TABLE(acpi, elan_acpi_id); #endif diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index a4345052abd2..2d8434b7b623 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -227,6 +227,52 @@ static void elantech_packet_dump(struct psmouse *psmouse) } /* + * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in + * fw_version for this is based on the following fw_version & caps table: + * + * Laptop-model: fw_version: caps: buttons: + * Acer S3 0x461f00 10, 13, 0e clickpad + * Acer S7-392 0x581f01 50, 17, 0d clickpad + * Acer V5-131 0x461f02 01, 16, 0c clickpad + * Acer V5-551 0x461f00 ? clickpad + * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons + * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons + * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons + * Asus TP500LN 0x381f17 10, 14, 0e clickpad + * Asus X750JN 0x381f17 10, 14, 0e clickpad + * Asus UX31 0x361f00 20, 15, 0e clickpad + * Asus UX32VD 0x361f02 00, 15, 0e clickpad + * Avatar AVIU-145A2 0x361f00 ? clickpad + * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**) + * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**) + * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons + * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) + * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons + * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) + * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) + * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons + * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad + * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad + * Samsung NP900X3E-A02 0x575f03 ? clickpad + * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad + * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons + * Samsung RF710 0x450f00 ? 2 hw buttons + * System76 Pangolin 0x250f01 ? 2 hw buttons + * (*) + 3 trackpoint buttons + * (**) + 0 trackpoint buttons + * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps + */ +static inline int elantech_is_buttonpad(struct elantech_device_info *info) +{ + return info->fw_version & 0x001000; +} + +/* * Interpret complete data packets and report absolute mode input events for * hardware version 1. (4 byte packets) */ @@ -523,7 +569,7 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); /* For clickpads map both buttons to BTN_LEFT */ - if (etd->info.fw_version & 0x001000) + if (elantech_is_buttonpad(&etd->info)) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -541,7 +587,7 @@ static void elantech_input_sync_v4(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; /* For clickpads map both buttons to BTN_LEFT */ - if (etd->info.fw_version & 0x001000) + if (elantech_is_buttonpad(&etd->info)) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -991,88 +1037,6 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) return rc; } -static int elantech_set_range(struct psmouse *psmouse, - unsigned int *x_min, unsigned int *y_min, - unsigned int *x_max, unsigned int *y_max, - unsigned int *width) -{ - struct elantech_data *etd = psmouse->private; - struct elantech_device_info *info = &etd->info; - unsigned char param[3]; - unsigned char traces; - - switch (info->hw_version) { - case 1: - *x_min = ETP_XMIN_V1; - *y_min = ETP_YMIN_V1; - *x_max = ETP_XMAX_V1; - *y_max = ETP_YMAX_V1; - break; - - case 2: - if (info->fw_version == 0x020800 || - info->fw_version == 0x020b00 || - info->fw_version == 0x020030) { - *x_min = ETP_XMIN_V2; - *y_min = ETP_YMIN_V2; - *x_max = ETP_XMAX_V2; - *y_max = ETP_YMAX_V2; - } else { - int i; - int fixed_dpi; - - i = (info->fw_version > 0x020800 && - info->fw_version < 0x020900) ? 1 : 2; - - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - fixed_dpi = param[1] & 0x10; - - if (((info->fw_version >> 16) == 0x14) && fixed_dpi) { - if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) - return -1; - - *x_max = (info->capabilities[1] - i) * param[1] / 2; - *y_max = (info->capabilities[2] - i) * param[2] / 2; - } else if (info->fw_version == 0x040216) { - *x_max = 819; - *y_max = 405; - } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) { - *x_max = 900; - *y_max = 500; - } else { - *x_max = (info->capabilities[1] - i) * 64; - *y_max = (info->capabilities[2] - i) * 64; - } - } - break; - - case 3: - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - *x_max = (0x0f & param[0]) << 8 | param[1]; - *y_max = (0xf0 & param[0]) << 4 | param[2]; - break; - - case 4: - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - *x_max = (0x0f & param[0]) << 8 | param[1]; - *y_max = (0xf0 & param[0]) << 4 | param[2]; - traces = info->capabilities[1]; - if ((traces < 2) || (traces > *x_max)) - return -1; - - *width = *x_max / (traces - 1); - break; - } - - return 0; -} - /* * (value from firmware) * 10 + 790 = dpi * we also have to convert dpi to dots/mm (*10/254 to avoid floating point) @@ -1099,53 +1063,12 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, return 0; } -/* - * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in - * fw_version for this is based on the following fw_version & caps table: - * - * Laptop-model: fw_version: caps: buttons: - * Acer S3 0x461f00 10, 13, 0e clickpad - * Acer S7-392 0x581f01 50, 17, 0d clickpad - * Acer V5-131 0x461f02 01, 16, 0c clickpad - * Acer V5-551 0x461f00 ? clickpad - * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons - * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons - * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons - * Asus TP500LN 0x381f17 10, 14, 0e clickpad - * Asus X750JN 0x381f17 10, 14, 0e clickpad - * Asus UX31 0x361f00 20, 15, 0e clickpad - * Asus UX32VD 0x361f02 00, 15, 0e clickpad - * Avatar AVIU-145A2 0x361f00 ? clickpad - * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**) - * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**) - * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons - * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons - * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons - * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) - * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons - * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) - * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) - * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons - * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad - * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad - * Samsung NP900X3E-A02 0x575f03 ? clickpad - * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad - * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons - * Samsung RF710 0x450f00 ? 2 hw buttons - * System76 Pangolin 0x250f01 ? 2 hw buttons - * (*) + 3 trackpoint buttons - * (**) + 0 trackpoint buttons - * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps - */ static void elantech_set_buttonpad_prop(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; - if (etd->info.fw_version & 0x001000) { + if (elantech_is_buttonpad(&etd->info)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); __clear_bit(BTN_RIGHT, dev->keybit); } @@ -1181,16 +1104,6 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { { } }; -static const char * const middle_button_pnp_ids[] = { - "LEN2131", /* ThinkPad P52 w/ NFC */ - "LEN2132", /* ThinkPad P52 */ - "LEN2133", /* ThinkPad P72 w/ NFC */ - "LEN2134", /* ThinkPad P72 */ - "LEN0407", - "LEN0408", - NULL -}; - /* * Set the appropriate event bits for the input subsystem */ @@ -1199,10 +1112,9 @@ static int elantech_set_input_params(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; struct elantech_device_info *info = &etd->info; - unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; - - if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) - return -1; + unsigned int x_min = info->x_min, y_min = info->y_min, + x_max = info->x_max, y_max = info->y_max, + width = info->width; __set_bit(INPUT_PROP_POINTER, dev->propbit); __set_bit(EV_KEY, dev->evbit); @@ -1210,8 +1122,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) __clear_bit(EV_REL, dev->evbit); __set_bit(BTN_LEFT, dev->keybit); - if (dmi_check_system(elantech_dmi_has_middle_button) || - psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids)) + if (info->has_middle_button) __set_bit(BTN_MIDDLE, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); @@ -1686,6 +1597,7 @@ static int elantech_query_info(struct psmouse *psmouse, struct elantech_device_info *info) { unsigned char param[3]; + unsigned char traces; memset(info, 0, sizeof(*info)); @@ -1754,6 +1666,90 @@ static int elantech_query_info(struct psmouse *psmouse, } } + /* query range information */ + switch (info->hw_version) { + case 1: + info->x_min = ETP_XMIN_V1; + info->y_min = ETP_YMIN_V1; + info->x_max = ETP_XMAX_V1; + info->y_max = ETP_YMAX_V1; + break; + + case 2: + if (info->fw_version == 0x020800 || + info->fw_version == 0x020b00 || + info->fw_version == 0x020030) { + info->x_min = ETP_XMIN_V2; + info->y_min = ETP_YMIN_V2; + info->x_max = ETP_XMAX_V2; + info->y_max = ETP_YMAX_V2; + } else { + int i; + int fixed_dpi; + + i = (info->fw_version > 0x020800 && + info->fw_version < 0x020900) ? 1 : 2; + + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + fixed_dpi = param[1] & 0x10; + + if (((info->fw_version >> 16) == 0x14) && fixed_dpi) { + if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) + return -EINVAL; + + info->x_max = (info->capabilities[1] - i) * param[1] / 2; + info->y_max = (info->capabilities[2] - i) * param[2] / 2; + } else if (info->fw_version == 0x040216) { + info->x_max = 819; + info->y_max = 405; + } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) { + info->x_max = 900; + info->y_max = 500; + } else { + info->x_max = (info->capabilities[1] - i) * 64; + info->y_max = (info->capabilities[2] - i) * 64; + } + } + break; + + case 3: + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + info->x_max = (0x0f & param[0]) << 8 | param[1]; + info->y_max = (0xf0 & param[0]) << 4 | param[2]; + break; + + case 4: + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + info->x_max = (0x0f & param[0]) << 8 | param[1]; + info->y_max = (0xf0 & param[0]) << 4 | param[2]; + traces = info->capabilities[1]; + if ((traces < 2) || (traces > info->x_max)) + return -EINVAL; + + info->width = info->x_max / (traces - 1); + + /* column number of traces */ + info->x_traces = traces; + + /* row number of traces */ + traces = info->capabilities[2]; + if ((traces >= 2) && (traces <= info->y_max)) + info->y_traces = traces; + + break; + } + + /* check for the middle button: DMI matching or new v4 firmwares */ + info->has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) || + (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) && + !elantech_is_buttonpad(info)); + return 0; } @@ -1780,10 +1776,6 @@ static const char * const i2c_blacklist_pnp_ids[] = { * These are known to not be working properly as bits are missing * in elan_i2c. */ - "LEN2131", /* ThinkPad P52 w/ NFC */ - "LEN2132", /* ThinkPad P52 */ - "LEN2133", /* ThinkPad P72 w/ NFC */ - "LEN2134", /* ThinkPad P72 */ NULL }; @@ -1791,17 +1783,45 @@ static int elantech_create_smbus(struct psmouse *psmouse, struct elantech_device_info *info, bool leave_breadcrumbs) { - const struct property_entry i2c_properties[] = { - PROPERTY_ENTRY_BOOL("elan,trackpoint"), - { }, - }; + struct property_entry i2c_props[11] = {}; struct i2c_board_info smbus_board = { I2C_BOARD_INFO("elan_i2c", 0x15), .flags = I2C_CLIENT_HOST_NOTIFY, }; + unsigned int idx = 0; + + smbus_board.properties = i2c_props; + + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-x", + info->x_max + 1); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-y", + info->y_max + 1); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-x", + info->x_min); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-y", + info->y_min); + if (info->x_res) + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-x-mm", + (info->x_max + 1) / info->x_res); + if (info->y_res) + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-y-mm", + (info->y_max + 1) / info->y_res); if (info->has_trackpoint) - smbus_board.properties = i2c_properties; + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,trackpoint"); + + if (info->has_middle_button) + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,middle-button"); + + if (info->x_traces) + i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,x_traces", + info->x_traces); + if (info->y_traces) + i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,y_traces", + info->y_traces); + + if (elantech_is_buttonpad(info)) + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,clickpad"); return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false, leave_breadcrumbs); diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 12ba5af93145..46343998522b 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -141,8 +141,15 @@ struct elantech_device_info { unsigned char debug; unsigned char hw_version; unsigned int fw_version; + unsigned int x_min; + unsigned int y_min; + unsigned int x_max; + unsigned int y_max; unsigned int x_res; unsigned int y_res; + unsigned int x_traces; + unsigned int y_traces; + unsigned int width; unsigned int bus; bool paritycheck; bool jumpy_cursor; @@ -150,6 +157,7 @@ struct elantech_device_info { bool crc_enabled; bool set_hw_resolution; bool has_trackpoint; + bool has_middle_button; int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param); }; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index b8ec301025b7..1080c0c49815 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -173,6 +173,7 @@ static const char * const smbus_pnp_ids[] = { "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */ "LEN0073", /* X1 Carbon G5 (Elantech) */ "LEN0092", /* X1 Carbon 6 */ + "LEN0093", /* T480 */ "LEN0096", /* X280 */ "LEN0097", /* X280 -> ALPS trackpoint */ "LEN200f", /* T450s */ diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index bb14369e34a7..d20a5d6780d1 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -70,7 +70,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) int pitch_y = 0; int rx_receivers = 0; int tx_receivers = 0; - int sensor_flags = 0; item = rmi_get_register_desc_item(&f12->control_reg_desc, 8); if (!item) { @@ -126,10 +125,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) offset += 2; } - if (rmi_register_desc_has_subpacket(item, 4)) { - sensor_flags = buf[offset]; + /* Skip over sensor flags */ + if (rmi_register_desc_has_subpacket(item, 4)) offset += 1; - } sensor->x_mm = (pitch_x * rx_receivers) >> 12; sensor->y_mm = (pitch_y * tx_receivers) >> 12; diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 19378f200c63..4a5f482cf1af 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -256,16 +256,6 @@ enum v4l_dbg_inputs { MXT_V4L_INPUT_MAX, }; -static const struct v4l2_file_operations mxt_video_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .unlocked_ioctl = video_ioctl2, - .read = vb2_fop_read, - .mmap = vb2_fop_mmap, - .poll = vb2_fop_poll, -}; - enum mxt_suspend_mode { MXT_SUSPEND_DEEP_SLEEP = 0, MXT_SUSPEND_T9_CTRL = 1, @@ -1521,7 +1511,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) } else if (config_crc == data->config_crc) { dev_dbg(dev, "Config CRC 0x%06X: OK\n", data->config_crc); - return 0; + ret = 0; + goto release_raw; } else { dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", data->config_crc, config_crc); @@ -2218,6 +2209,16 @@ recheck: } #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 +static const struct v4l2_file_operations mxt_video_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x, unsigned int y) { diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index c639ebce914c..3cc4341bbdff 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -27,6 +27,7 @@ #include <linux/gpio/consumer.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> +#include <asm/unaligned.h> #define WORK_REGISTER_THRESHOLD 0x00 #define WORK_REGISTER_REPORT_RATE 0x08 @@ -228,7 +229,6 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) for (i = 0; i < tsdata->max_support_points; i++) { u8 *buf = &rdbuf[i * tplen + offset]; - bool down; type = buf[0] >> 6; /* ignore Reserved events */ @@ -239,23 +239,19 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN) continue; - x = ((buf[0] << 8) | buf[1]) & 0x0fff; - y = ((buf[2] << 8) | buf[3]) & 0x0fff; + x = get_unaligned_be16(buf) & 0x0fff; + y = get_unaligned_be16(buf + 2) & 0x0fff; /* The FT5x26 send the y coordinate first */ if (tsdata->version == EV_FT) swap(x, y); id = (buf[2] >> 4) & 0x0f; - down = type != TOUCH_EVENT_UP; input_mt_slot(tsdata->input, id); - input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); - - if (!down) - continue; - - touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y, - true); + if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, + type != TOUCH_EVENT_UP)) + touchscreen_report_pos(tsdata->input, &tsdata->prop, + x, y, true); } input_mt_report_pointer_emulation(tsdata->input, true); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index c6b85ba7f991..2e1404cd09ec 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -28,6 +28,7 @@ struct eeti_ts { struct input_dev *input; struct gpio_desc *attn_gpio; struct touchscreen_properties props; + struct mutex mutex; bool running; }; @@ -62,42 +63,80 @@ static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) input_sync(eeti->input); } +static int eeti_ts_read(struct eeti_ts *eeti) +{ + int len, error; + char buf[6]; + + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); + if (len != sizeof(buf)) { + error = len < 0 ? len : -EIO; + dev_err(&eeti->client->dev, + "failed to read touchscreen data: %d\n", + error); + return error; + } + + /* Motion packet */ + if (buf[0] & 0x80) + eeti_ts_report_event(eeti, buf); + + return 0; +} + static irqreturn_t eeti_ts_isr(int irq, void *dev_id) { struct eeti_ts *eeti = dev_id; - int len; int error; - char buf[6]; + + mutex_lock(&eeti->mutex); do { - len = i2c_master_recv(eeti->client, buf, sizeof(buf)); - if (len != sizeof(buf)) { - error = len < 0 ? len : -EIO; - dev_err(&eeti->client->dev, - "failed to read touchscreen data: %d\n", - error); + /* + * If we have attention GPIO, trust it. Otherwise we'll read + * once and exit. We assume that in this case we are using + * level triggered interrupt and it will get raised again + * if/when there is more data. + */ + if (eeti->attn_gpio && + !gpiod_get_value_cansleep(eeti->attn_gpio)) { break; } - if (buf[0] & 0x80) { - /* Motion packet */ - eeti_ts_report_event(eeti, buf); - } - } while (eeti->running && - eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)); + error = eeti_ts_read(eeti); + if (error) + break; + + } while (eeti->running && eeti->attn_gpio); + mutex_unlock(&eeti->mutex); return IRQ_HANDLED; } static void eeti_ts_start(struct eeti_ts *eeti) { + mutex_lock(&eeti->mutex); + eeti->running = true; - wmb(); enable_irq(eeti->client->irq); + + /* + * Kick the controller in case we are using edge interrupt and + * we missed our edge while interrupt was disabled. We expect + * the attention GPIO to be wired in this case. + */ + if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)) + eeti_ts_read(eeti); + + mutex_unlock(&eeti->mutex); } static void eeti_ts_stop(struct eeti_ts *eeti) { + /* + * Not locking here, just setting a flag and expect that the + * interrupt thread will notice the flag eventually. + */ eeti->running = false; wmb(); disable_irq(eeti->client->irq); @@ -140,6 +179,8 @@ static int eeti_ts_probe(struct i2c_client *client, return -ENOMEM; } + mutex_init(&eeti->mutex); + input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device.\n"); diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index c10fc594f94d..e04eecd65bbb 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -364,8 +364,6 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct imx6ul_tsc *tsc; struct input_dev *input_dev; - struct resource *tsc_mem; - struct resource *adc_mem; int err; int tsc_irq; int adc_irq; @@ -403,16 +401,14 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) return err; } - tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem); + tsc->tsc_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(tsc->tsc_regs)) { err = PTR_ERR(tsc->tsc_regs); dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err); return err; } - adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem); + tsc->adc_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(tsc->adc_regs)) { err = PTR_ERR(tsc->adc_regs); dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err); diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 4f6fe8cc8efa..5875bb1099a8 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1056,8 +1056,6 @@ static int iqs5xx_probe(struct i2c_client *client, if (!iqs5xx) return -ENOMEM; - dev_set_drvdata(&client->dev, iqs5xx); - i2c_set_clientdata(client, iqs5xx); iqs5xx->client = client; diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 2d96cf0023dd..a9a9fabd3968 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2034,7 +2034,7 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) static struct platform_driver arm_smmu_driver; -static int arm_smmu_match_node(struct device *dev, void *data) +static int arm_smmu_match_node(struct device *dev, const void *data) { return dev->fwnode == data; } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 653b6b3dcafb..64977c131ee6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1426,7 +1426,7 @@ static bool arm_smmu_capable(enum iommu_cap cap) } } -static int arm_smmu_match_node(struct device *dev, void *data) +static int arm_smmu_match_node(struct device *dev, const void *data) { return dev->fwnode == data; } diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index f802255219d3..a7f9c3edbcb2 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -951,8 +951,8 @@ static void __iommu_dma_free(struct device *dev, size_t size, void *cpu_addr) if (pages) __iommu_dma_free_pages(pages, count); - if (page && !dma_release_from_contiguous(dev, page, count)) - __free_pages(page, get_order(alloc_size)); + if (page) + dma_free_contiguous(dev, page, alloc_size); } static void iommu_dma_free(struct device *dev, size_t size, void *cpu_addr, @@ -970,12 +970,7 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size, struct page *page = NULL; void *cpu_addr; - if (gfpflags_allow_blocking(gfp)) - page = dma_alloc_from_contiguous(dev, alloc_size >> PAGE_SHIFT, - get_order(alloc_size), - gfp & __GFP_NOWARN); - if (!page) - page = alloc_pages(gfp, get_order(alloc_size)); + page = dma_alloc_contiguous(dev, alloc_size, gfp); if (!page) return NULL; @@ -997,8 +992,7 @@ static void *iommu_dma_alloc_pages(struct device *dev, size_t size, memset(cpu_addr, 0, alloc_size); return cpu_addr; out_free_pages: - if (!dma_release_from_contiguous(dev, page, alloc_size >> PAGE_SHIFT)) - __free_pages(page, get_order(alloc_size)); + dma_free_contiguous(dev, page, alloc_size); return NULL; } diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 01e298f620f3..276065c888bc 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -132,7 +132,7 @@ static void smu_start_cmd(void) /* Flush command and data to RAM */ faddr = (unsigned long)smu->cmd_buf; fend = faddr + smu->cmd_buf->length + 2; - flush_inval_dcache_range(faddr, fend); + flush_dcache_range(faddr, fend); /* We also disable NAP mode for the duration of the command @@ -194,7 +194,7 @@ static irqreturn_t smu_db_intr(int irq, void *arg) * reply length (it's only 2 cache lines anyway) */ faddr = (unsigned long)smu->cmd_buf; - flush_inval_dcache_range(faddr, faddr + 256); + flush_dcache_range(faddr, faddr + 256); /* Now check ack */ ack = (~cmd->cmd) & 0xff; diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index a64116586b4c..43b336316fde 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c @@ -296,8 +296,6 @@ struct flexrm_mbox { struct dma_pool *bd_pool; struct dma_pool *cmpl_pool; struct dentry *root; - struct dentry *config; - struct dentry *stats; struct mbox_controller controller; }; @@ -1603,7 +1601,6 @@ static int flexrm_mbox_probe(struct platform_device *pdev) 1 << RING_CMPL_ALIGN_ORDER, 0); if (!mbox->cmpl_pool) { ret = -ENOMEM; - goto fail_destroy_bd_pool; } /* Allocate platform MSIs for each ring */ @@ -1624,28 +1621,15 @@ static int flexrm_mbox_probe(struct platform_device *pdev) /* Create debugfs root entry */ mbox->root = debugfs_create_dir(dev_name(mbox->dev), NULL); - if (IS_ERR_OR_NULL(mbox->root)) { - ret = PTR_ERR_OR_ZERO(mbox->root); - goto fail_free_msis; - } /* Create debugfs config entry */ - mbox->config = debugfs_create_devm_seqfile(mbox->dev, - "config", mbox->root, - flexrm_debugfs_conf_show); - if (IS_ERR_OR_NULL(mbox->config)) { - ret = PTR_ERR_OR_ZERO(mbox->config); - goto fail_free_debugfs_root; - } + debugfs_create_devm_seqfile(mbox->dev, "config", mbox->root, + flexrm_debugfs_conf_show); /* Create debugfs stats entry */ - mbox->stats = debugfs_create_devm_seqfile(mbox->dev, - "stats", mbox->root, - flexrm_debugfs_stats_show); - if (IS_ERR_OR_NULL(mbox->stats)) { - ret = PTR_ERR_OR_ZERO(mbox->stats); - goto fail_free_debugfs_root; - } + debugfs_create_devm_seqfile(mbox->dev, "stats", mbox->root, + flexrm_debugfs_stats_show); + skip_debugfs: /* Initialize mailbox controller */ @@ -1676,11 +1660,9 @@ skip_debugfs: fail_free_debugfs_root: debugfs_remove_recursive(mbox->root); -fail_free_msis: platform_msi_domain_free_irqs(dev); fail_destroy_cmpl_pool: dma_pool_destroy(mbox->cmpl_pool); -fail_destroy_bd_pool: dma_pool_destroy(mbox->bd_pool); fail: return ret; diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 8513c42f7091..fcb3b18a0678 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -395,8 +395,6 @@ struct pdc_state { */ struct scatterlist *src_sg[PDC_RING_ENTRIES]; - struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ - /* counters */ u32 pdc_requests; /* number of request messages submitted */ u32 pdc_replies; /* number of reply messages received */ @@ -501,9 +499,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs) debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); /* S_IRUSR == 0400 */ - pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400, - debugfs_dir, pdcs, - &pdc_debugfs_stats); + debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs, + &pdc_debugfs_stats); } static void pdc_free_debugfs(void) @@ -1603,7 +1600,6 @@ static int pdc_probe(struct platform_device *pdev) if (err) goto cleanup_buf_pool; - pdcs->debugfs_stats = NULL; pdc_setup_debugfs(pdcs); dev_dbg(dev, "pdc_probe() successful"); diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 2a48ea3f1b30..b6b5acc92ca2 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1599,9 +1599,7 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) unsigned long freed; c = container_of(shrink, struct dm_bufio_client, shrinker); - if (sc->gfp_mask & __GFP_FS) - dm_bufio_lock(c); - else if (!dm_bufio_trylock(c)) + if (!dm_bufio_trylock(c)) return SHRINK_STOP; freed = __scan(c, sc->nr_to_scan, sc->gfp_mask); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 1b16d34bb785..d5216bcc4649 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -120,6 +120,10 @@ struct iv_tcw_private { u8 *whitening; }; +struct iv_eboiv_private { + struct crypto_cipher *tfm; +}; + /* * Crypt: maps a linear range of a block device * and encrypts / decrypts at the same time. @@ -159,6 +163,7 @@ struct crypt_config { struct iv_benbi_private benbi; struct iv_lmk_private lmk; struct iv_tcw_private tcw; + struct iv_eboiv_private eboiv; } iv_gen_private; u64 iv_offset; unsigned int iv_size; @@ -291,8 +296,9 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc) * Note that this encryption scheme is vulnerable to watermarking attacks * and should be used for old compatible containers access only. * - * plumb: unimplemented, see: - * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454 + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode) + * The IV is encrypted little-endian byte-offset (with the same key + * and cipher as the volume). */ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, @@ -841,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv, return 0; } +static void crypt_iv_eboiv_dtr(struct crypt_config *cc) +{ + struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv; + + crypto_free_cipher(eboiv->tfm); + eboiv->tfm = NULL; +} + +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti, + const char *opts) +{ + struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv; + struct crypto_cipher *tfm; + + tfm = crypto_alloc_cipher(cc->cipher, 0, 0); + if (IS_ERR(tfm)) { + ti->error = "Error allocating crypto tfm for EBOIV"; + return PTR_ERR(tfm); + } + + if (crypto_cipher_blocksize(tfm) != cc->iv_size) { + ti->error = "Block size of EBOIV cipher does " + "not match IV size of block cipher"; + crypto_free_cipher(tfm); + return -EINVAL; + } + + eboiv->tfm = tfm; + return 0; +} + +static int crypt_iv_eboiv_init(struct crypt_config *cc) +{ + struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv; + int err; + + err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size); + if (err) + return err; + + return 0; +} + +static int crypt_iv_eboiv_wipe(struct crypt_config *cc) +{ + /* Called after cc->key is set to random key in crypt_wipe() */ + return crypt_iv_eboiv_init(cc); +} + +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq) +{ + struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv; + + memset(iv, 0, cc->iv_size); + *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size); + crypto_cipher_encrypt_one(eboiv->tfm, iv, iv); + + return 0; +} + static const struct crypt_iv_operations crypt_iv_plain_ops = { .generator = crypt_iv_plain_gen }; @@ -893,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = { .generator = crypt_iv_random_gen }; +static struct crypt_iv_operations crypt_iv_eboiv_ops = { + .ctr = crypt_iv_eboiv_ctr, + .dtr = crypt_iv_eboiv_dtr, + .init = crypt_iv_eboiv_init, + .wipe = crypt_iv_eboiv_wipe, + .generator = crypt_iv_eboiv_gen +}; + /* * Integrity extensions */ @@ -2158,6 +2233,14 @@ static int crypt_wipe_key(struct crypt_config *cc) clear_bit(DM_CRYPT_KEY_VALID, &cc->flags); get_random_bytes(&cc->key, cc->key_size); + + /* Wipe IV private keys */ + if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) { + r = cc->iv_gen_ops->wipe(cc); + if (r) + return r; + } + kzfree(cc->key_string); cc->key_string = NULL; r = crypt_setkey(cc); @@ -2288,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode) cc->iv_gen_ops = &crypt_iv_benbi_ops; else if (strcmp(ivmode, "null") == 0) cc->iv_gen_ops = &crypt_iv_null_ops; + else if (strcmp(ivmode, "eboiv") == 0) + cc->iv_gen_ops = &crypt_iv_eboiv_ops; else if (strcmp(ivmode, "lmk") == 0) { cc->iv_gen_ops = &crypt_iv_lmk_ops; /* @@ -2699,7 +2784,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) return -EINVAL; } - cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); + cc = kzalloc(struct_size(cc, key, key_size), GFP_KERNEL); if (!cc) { ti->error = "Cannot allocate encryption context"; return -ENOMEM; @@ -3050,14 +3135,8 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv, memset(cc->key, 0, cc->key_size * sizeof(u8)); return ret; } - if (argc == 2 && !strcasecmp(argv[1], "wipe")) { - if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) { - ret = cc->iv_gen_ops->wipe(cc); - if (ret) - return ret; - } + if (argc == 2 && !strcasecmp(argv[1], "wipe")) return crypt_wipe_key(cc); - } } error: @@ -3094,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits) static struct target_type crypt_target = { .name = "crypt", - .version = {1, 18, 1}, + .version = {1, 19, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 44e76cda087a..b1b0de402dfc 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -476,6 +476,9 @@ static int sync_rw_sb(struct dm_integrity_c *ic, int op, int op_flags) io_loc.sector = ic->start; io_loc.count = SB_SECTORS; + if (op == REQ_OP_WRITE) + sb_set_version(ic); + return dm_io(&io_req, 1, &io_loc, NULL); } @@ -2317,7 +2320,6 @@ static void recalc_write_super(struct dm_integrity_c *ic) if (dm_integrity_failed(ic)) return; - sb_set_version(ic); r = sync_rw_sb(ic, REQ_OP_WRITE, 0); if (unlikely(r)) dm_integrity_io_error(ic, "writing superblock", r); @@ -3358,7 +3360,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error) goto bad; } - crypt_iv = kmalloc(ivsize, GFP_KERNEL); + crypt_iv = kzalloc(ivsize, GFP_KERNEL); if (!crypt_iv) { *error = "Could not allocate iv"; r = -ENOMEM; @@ -3387,7 +3389,6 @@ static int create_journal(struct dm_integrity_c *ic, char **error) sg_set_buf(&sg[i], va, PAGE_SIZE); } sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids); - memset(crypt_iv, 0x00, ivsize); skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv); diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index e549392e0ea5..99721c76225d 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -40,7 +40,7 @@ * * Would result in the log looking like this: * - * c,a,flush,fuad,b,<other writes>,<next flush> + * c,a,b,flush,fuad,<other writes>,<next flush> * * This is meant to help expose problems where file systems do not properly wait * on data being written before invoking a FLUSH. FUA bypasses cache so once it @@ -699,7 +699,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio) if (discard_bio) alloc_size = sizeof(struct pending_block); else - alloc_size = sizeof(struct pending_block) + sizeof(struct bio_vec) * bio_segments(bio); + alloc_size = struct_size(block, vecs, bio_segments(bio)); block = kzalloc(alloc_size, GFP_NOIO); if (!block) { diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 5f7063f05ae0..c9e44ac1f9a6 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -115,7 +115,7 @@ static void end_clone_bio(struct bio *clone) /* * Update the original request. - * Do not use blk_end_request() here, because it may complete + * Do not use blk_mq_end_request() here, because it may complete * the original request before the clone, and break the ordering. */ if (is_last) diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 3107f2b1988b..63916e1dc569 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1,6 +1,4 @@ /* - * dm-snapshot.c - * * Copyright (C) 2001-2002 Sistina Software (UK) Limited. * * This file is released under the GPL. @@ -134,7 +132,10 @@ struct dm_snapshot { * - I/O error while merging * => stop merging; set merge_failed; process I/O normally. */ - int merge_failed; + bool merge_failed:1; + + bool discard_zeroes_cow:1; + bool discard_passdown_origin:1; /* * Incoming bios that overlap with chunks being merged must wait @@ -1173,12 +1174,64 @@ static void stop_merge(struct dm_snapshot *s) clear_bit(SHUTDOWN_MERGE, &s->state_bits); } +static int parse_snapshot_features(struct dm_arg_set *as, struct dm_snapshot *s, + struct dm_target *ti) +{ + int r; + unsigned argc; + const char *arg_name; + + static const struct dm_arg _args[] = { + {0, 2, "Invalid number of feature arguments"}, + }; + + /* + * No feature arguments supplied. + */ + if (!as->argc) + return 0; + + r = dm_read_arg_group(_args, as, &argc, &ti->error); + if (r) + return -EINVAL; + + while (argc && !r) { + arg_name = dm_shift_arg(as); + argc--; + + if (!strcasecmp(arg_name, "discard_zeroes_cow")) + s->discard_zeroes_cow = true; + + else if (!strcasecmp(arg_name, "discard_passdown_origin")) + s->discard_passdown_origin = true; + + else { + ti->error = "Unrecognised feature requested"; + r = -EINVAL; + break; + } + } + + if (!s->discard_zeroes_cow && s->discard_passdown_origin) { + /* + * TODO: really these are disjoint.. but ti->num_discard_bios + * and dm_bio_get_target_bio_nr() require rigid constraints. + */ + ti->error = "discard_passdown_origin feature depends on discard_zeroes_cow"; + r = -EINVAL; + } + + return r; +} + /* - * Construct a snapshot mapping: <origin_dev> <COW-dev> <p|po|n> <chunk-size> + * Construct a snapshot mapping: + * <origin_dev> <COW-dev> <p|po|n> <chunk-size> [<# feature args> [<arg>]*] */ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct dm_snapshot *s; + struct dm_arg_set as; int i; int r = -EINVAL; char *origin_path, *cow_path; @@ -1186,8 +1239,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) unsigned args_used, num_flush_bios = 1; fmode_t origin_mode = FMODE_READ; - if (argc != 4) { - ti->error = "requires exactly 4 arguments"; + if (argc < 4) { + ti->error = "requires 4 or more arguments"; r = -EINVAL; goto bad; } @@ -1204,6 +1257,13 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad; } + as.argc = argc; + as.argv = argv; + dm_consume_args(&as, 4); + r = parse_snapshot_features(&as, s, ti); + if (r) + goto bad_features; + origin_path = argv[0]; argv++; argc--; @@ -1289,6 +1349,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->private = s; ti->num_flush_bios = num_flush_bios; + if (s->discard_zeroes_cow) + ti->num_discard_bios = (s->discard_passdown_origin ? 2 : 1); ti->per_io_data_size = sizeof(struct dm_snap_tracked_chunk); /* Add snapshot to the list of snapshots for this origin */ @@ -1336,29 +1398,22 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) bad_read_metadata: unregister_snapshot(s); - bad_load_and_register: mempool_exit(&s->pending_pool); - bad_pending_pool: dm_kcopyd_client_destroy(s->kcopyd_client); - bad_kcopyd: dm_exception_table_exit(&s->pending, pending_cache); dm_exception_table_exit(&s->complete, exception_cache); - bad_hash_tables: dm_exception_store_destroy(s->store); - bad_store: dm_put_device(ti, s->cow); - bad_cow: dm_put_device(ti, s->origin); - bad_origin: +bad_features: kfree(s); - bad: return r; } @@ -1806,6 +1861,37 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e, (bio->bi_iter.bi_sector & s->store->chunk_mask); } +static void zero_callback(int read_err, unsigned long write_err, void *context) +{ + struct bio *bio = context; + struct dm_snapshot *s = bio->bi_private; + + up(&s->cow_count); + bio->bi_status = write_err ? BLK_STS_IOERR : 0; + bio_endio(bio); +} + +static void zero_exception(struct dm_snapshot *s, struct dm_exception *e, + struct bio *bio, chunk_t chunk) +{ + struct dm_io_region dest; + + dest.bdev = s->cow->bdev; + dest.sector = bio->bi_iter.bi_sector; + dest.count = s->store->chunk_size; + + down(&s->cow_count); + WARN_ON_ONCE(bio->bi_private); + bio->bi_private = s; + dm_kcopyd_zero(s->kcopyd_client, 1, &dest, 0, zero_callback, bio); +} + +static bool io_overlaps_chunk(struct dm_snapshot *s, struct bio *bio) +{ + return bio->bi_iter.bi_size == + (s->store->chunk_size << SECTOR_SHIFT); +} + static int snapshot_map(struct dm_target *ti, struct bio *bio) { struct dm_exception *e; @@ -1839,10 +1925,43 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) goto out_unlock; } + if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) { + if (s->discard_passdown_origin && dm_bio_get_target_bio_nr(bio)) { + /* + * passdown discard to origin (without triggering + * snapshot exceptions via do_origin; doing so would + * defeat the goal of freeing space in origin that is + * implied by the "discard_passdown_origin" feature) + */ + bio_set_dev(bio, s->origin->bdev); + track_chunk(s, bio, chunk); + goto out_unlock; + } + /* discard to snapshot (target_bio_nr == 0) zeroes exceptions */ + } + /* If the block is already remapped - use that, else remap it */ e = dm_lookup_exception(&s->complete, chunk); if (e) { remap_exception(s, e, bio, chunk); + if (unlikely(bio_op(bio) == REQ_OP_DISCARD) && + io_overlaps_chunk(s, bio)) { + dm_exception_table_unlock(&lock); + up_read(&s->lock); + zero_exception(s, e, bio, chunk); + r = DM_MAPIO_SUBMITTED; /* discard is not issued */ + goto out; + } + goto out_unlock; + } + + if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) { + /* + * If no exception exists, complete discard immediately + * otherwise it'll trigger copy-out. + */ + bio_endio(bio); + r = DM_MAPIO_SUBMITTED; goto out_unlock; } @@ -1890,9 +2009,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) r = DM_MAPIO_SUBMITTED; - if (!pe->started && - bio->bi_iter.bi_size == - (s->store->chunk_size << SECTOR_SHIFT)) { + if (!pe->started && io_overlaps_chunk(s, bio)) { pe->started = 1; dm_exception_table_unlock(&lock); @@ -2138,6 +2255,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type, { unsigned sz = 0; struct dm_snapshot *snap = ti->private; + unsigned num_features; switch (type) { case STATUSTYPE_INFO: @@ -2178,8 +2296,16 @@ static void snapshot_status(struct dm_target *ti, status_type_t type, * make sense. */ DMEMIT("%s %s", snap->origin->name, snap->cow->name); - snap->store->type->status(snap->store, type, result + sz, - maxlen - sz); + sz += snap->store->type->status(snap->store, type, result + sz, + maxlen - sz); + num_features = snap->discard_zeroes_cow + snap->discard_passdown_origin; + if (num_features) { + DMEMIT(" %u", num_features); + if (snap->discard_zeroes_cow) + DMEMIT(" discard_zeroes_cow"); + if (snap->discard_passdown_origin) + DMEMIT(" discard_passdown_origin"); + } break; } } @@ -2198,6 +2324,22 @@ static int snapshot_iterate_devices(struct dm_target *ti, return r; } +static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits) +{ + struct dm_snapshot *snap = ti->private; + + if (snap->discard_zeroes_cow) { + struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; + + (void) __find_snapshots_sharing_cow(snap, &snap_src, &snap_dest, NULL); + if (snap_src && snap_dest) + snap = snap_src; + + /* All discards are split on chunk_size boundary */ + limits->discard_granularity = snap->store->chunk_size; + limits->max_discard_sectors = snap->store->chunk_size; + } +} /*----------------------------------------------------------------- * Origin methods @@ -2522,7 +2664,7 @@ static struct target_type origin_target = { static struct target_type snapshot_target = { .name = "snapshot", - .version = {1, 15, 0}, + .version = {1, 16, 0}, .module = THIS_MODULE, .ctr = snapshot_ctr, .dtr = snapshot_dtr, @@ -2532,11 +2674,12 @@ static struct target_type snapshot_target = { .resume = snapshot_resume, .status = snapshot_status, .iterate_devices = snapshot_iterate_devices, + .io_hints = snapshot_io_hints, }; static struct target_type merge_target = { .name = dm_snapshot_merge_target_name, - .version = {1, 4, 0}, + .version = {1, 5, 0}, .module = THIS_MODULE, .ctr = snapshot_ctr, .dtr = snapshot_dtr, @@ -2547,6 +2690,7 @@ static struct target_type merge_target = { .resume = snapshot_merge_resume, .status = snapshot_status, .iterate_devices = snapshot_iterate_devices, + .io_hints = snapshot_io_hints, }; static int __init dm_snapshot_init(void) diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 7f0840601737..4c68a7b93d5e 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -2046,16 +2046,19 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd, int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd) { - int r; + int r = -EINVAL; struct dm_block *sblock; struct thin_disk_superblock *disk_super; pmd_write_lock(pmd); + if (pmd->fail_io) + goto out; + pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG; r = superblock_lock(pmd, &sblock); if (r) { - DMERR("couldn't read superblock"); + DMERR("couldn't lock superblock"); goto out; } diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c index 8976f82785bb..2ee14d8a6d31 100644 --- a/drivers/mfd/altera-sysmgr.c +++ b/drivers/mfd/altera-sysmgr.c @@ -92,9 +92,9 @@ static struct regmap_config altr_sysmgr_regmap_cfg = { * Matching function used by driver_find_device(). * Return: True if match is found, otherwise false. */ -static int sysmgr_match_phandle(struct device *dev, void *data) +static int sysmgr_match_phandle(struct device *dev, const void *data) { - return dev->of_node == (struct device_node *)data; + return dev->of_node == (const struct device_node *)data; } /** diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 8ce1e41d632c..b65e585fc8c6 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -190,27 +190,6 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s) } EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); -static int syscon_match_pdevname(struct device *dev, void *data) -{ - return !strcmp(dev_name(dev), (const char *)data); -} - -struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) -{ - struct device *dev; - struct syscon *syscon; - - dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s, - syscon_match_pdevname); - if (!dev) - return ERR_PTR(-EPROBE_DEFER); - - syscon = dev_get_drvdata(dev); - - return syscon->regmap; -} -EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); - struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, const char *property) { diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index a73c9e669d78..5dc0f6093f9d 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -908,11 +908,11 @@ void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx); #ifdef CONFIG_DEBUG_FS -int cxl_debugfs_init(void); +void cxl_debugfs_init(void); void cxl_debugfs_exit(void); -int cxl_debugfs_adapter_add(struct cxl *adapter); +void cxl_debugfs_adapter_add(struct cxl *adapter); void cxl_debugfs_adapter_remove(struct cxl *adapter); -int cxl_debugfs_afu_add(struct cxl_afu *afu); +void cxl_debugfs_afu_add(struct cxl_afu *afu); void cxl_debugfs_afu_remove(struct cxl_afu *afu); void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir); void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir); @@ -921,27 +921,24 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir); #else /* CONFIG_DEBUG_FS */ -static inline int __init cxl_debugfs_init(void) +static inline void __init cxl_debugfs_init(void) { - return 0; } static inline void cxl_debugfs_exit(void) { } -static inline int cxl_debugfs_adapter_add(struct cxl *adapter) +static inline void cxl_debugfs_adapter_add(struct cxl *adapter) { - return 0; } static inline void cxl_debugfs_adapter_remove(struct cxl *adapter) { } -static inline int cxl_debugfs_afu_add(struct cxl_afu *afu) +static inline void cxl_debugfs_afu_add(struct cxl_afu *afu) { - return 0; } static inline void cxl_debugfs_afu_remove(struct cxl_afu *afu) diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c index 1fda22c24c93..7b987bf498b5 100644 --- a/drivers/misc/cxl/debugfs.c +++ b/drivers/misc/cxl/debugfs.c @@ -26,11 +26,11 @@ static int debugfs_io_u64_set(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set, "0x%016llx\n"); -static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode, - struct dentry *parent, u64 __iomem *value) +static void debugfs_create_io_x64(const char *name, umode_t mode, + struct dentry *parent, u64 __iomem *value) { - return debugfs_create_file_unsafe(name, mode, parent, - (void __force *)value, &fops_io_x64); + debugfs_create_file_unsafe(name, mode, parent, (void __force *)value, + &fops_io_x64); } void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir) @@ -54,25 +54,22 @@ void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir) debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_TRACE)); } -int cxl_debugfs_adapter_add(struct cxl *adapter) +void cxl_debugfs_adapter_add(struct cxl *adapter) { struct dentry *dir; char buf[32]; if (!cxl_debugfs) - return -ENODEV; + return; snprintf(buf, 32, "card%i", adapter->adapter_num); dir = debugfs_create_dir(buf, cxl_debugfs); - if (IS_ERR(dir)) - return PTR_ERR(dir); adapter->debugfs = dir; debugfs_create_io_x64("err_ivte", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_ErrIVTE)); if (adapter->native->sl_ops->debugfs_add_adapter_regs) adapter->native->sl_ops->debugfs_add_adapter_regs(adapter, dir); - return 0; } void cxl_debugfs_adapter_remove(struct cxl *adapter) @@ -96,18 +93,16 @@ void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir) debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SLICE_TRACE)); } -int cxl_debugfs_afu_add(struct cxl_afu *afu) +void cxl_debugfs_afu_add(struct cxl_afu *afu) { struct dentry *dir; char buf[32]; if (!afu->adapter->debugfs) - return -ENODEV; + return; snprintf(buf, 32, "psl%i.%i", afu->adapter->adapter_num, afu->slice); dir = debugfs_create_dir(buf, afu->adapter->debugfs); - if (IS_ERR(dir)) - return PTR_ERR(dir); afu->debugfs = dir; debugfs_create_io_x64("sr", S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SR_An)); @@ -118,8 +113,6 @@ int cxl_debugfs_afu_add(struct cxl_afu *afu) if (afu->adapter->native->sl_ops->debugfs_add_afu_regs) afu->adapter->native->sl_ops->debugfs_add_afu_regs(afu, dir); - - return 0; } void cxl_debugfs_afu_remove(struct cxl_afu *afu) @@ -127,19 +120,12 @@ void cxl_debugfs_afu_remove(struct cxl_afu *afu) debugfs_remove_recursive(afu->debugfs); } -int __init cxl_debugfs_init(void) +void __init cxl_debugfs_init(void) { - struct dentry *ent; - if (!cpu_has_feature(CPU_FTR_HVMODE)) - return 0; - - ent = debugfs_create_dir("cxl", NULL); - if (IS_ERR(ent)) - return PTR_ERR(ent); - cxl_debugfs = ent; + return; - return 0; + cxl_debugfs = debugfs_create_dir("cxl", NULL); } void cxl_debugfs_exit(void) diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c index ab7f2cd21c93..1dc6c7c5cbce 100644 --- a/drivers/misc/genwqe/card_base.c +++ b/drivers/misc/genwqe/card_base.c @@ -1369,10 +1369,6 @@ static int __init genwqe_init_module(void) class_genwqe->devnode = genwqe_devnode; debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL); - if (!debugfs_genwqe) { - rc = -ENOMEM; - goto err_out; - } rc = pci_register_driver(&genwqe_driver); if (rc != 0) { @@ -1384,7 +1380,6 @@ static int __init genwqe_init_module(void) err_out0: debugfs_remove(debugfs_genwqe); - err_out: class_destroy(class_genwqe); return rc; } diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index 2f6dd2f37942..0e902977d35f 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h @@ -437,7 +437,7 @@ int genwqe_device_create(struct genwqe_dev *cd); int genwqe_device_remove(struct genwqe_dev *cd); /* debugfs */ -int genwqe_init_debugfs(struct genwqe_dev *cd); +void genwqe_init_debugfs(struct genwqe_dev *cd); void genqwe_exit_debugfs(struct genwqe_dev *cd); int genwqe_read_softreset(struct genwqe_dev *cd); diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c index 49c945d0c488..1b5b82e65268 100644 --- a/drivers/misc/genwqe/card_debugfs.c +++ b/drivers/misc/genwqe/card_debugfs.c @@ -316,11 +316,9 @@ static int info_show(struct seq_file *s, void *unused) DEFINE_SHOW_ATTRIBUTE(info); -int genwqe_init_debugfs(struct genwqe_dev *cd) +void genwqe_init_debugfs(struct genwqe_dev *cd) { struct dentry *root; - struct dentry *file; - int ret; char card_name[64]; char name[64]; unsigned int i; @@ -328,153 +326,50 @@ int genwqe_init_debugfs(struct genwqe_dev *cd) sprintf(card_name, "%s%d_card", GENWQE_DEVNAME, cd->card_idx); root = debugfs_create_dir(card_name, cd->debugfs_genwqe); - if (!root) { - ret = -ENOMEM; - goto err0; - } /* non privileged interfaces are done here */ - file = debugfs_create_file("ddcb_info", S_IRUGO, root, cd, - &ddcb_info_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("info", S_IRUGO, root, cd, - &info_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_x64("err_inject", 0666, root, &cd->err_inject); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("ddcb_software_timeout", 0666, root, - &cd->ddcb_software_timeout); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("kill_timeout", 0666, root, - &cd->kill_timeout); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_file("ddcb_info", S_IRUGO, root, cd, &ddcb_info_fops); + debugfs_create_file("info", S_IRUGO, root, cd, &info_fops); + debugfs_create_x64("err_inject", 0666, root, &cd->err_inject); + debugfs_create_u32("ddcb_software_timeout", 0666, root, + &cd->ddcb_software_timeout); + debugfs_create_u32("kill_timeout", 0666, root, &cd->kill_timeout); /* privileged interfaces follow here */ if (!genwqe_is_privileged(cd)) { cd->debugfs_root = root; - return 0; + return; } - file = debugfs_create_file("curr_regs", S_IRUGO, root, cd, - &curr_regs_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd, - &curr_dbg_uid0_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd, - &curr_dbg_uid1_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd, - &curr_dbg_uid2_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_regs", S_IRUGO, root, cd, - &prev_regs_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd, - &prev_dbg_uid0_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd, - &prev_dbg_uid1_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd, - &prev_dbg_uid2_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_file("curr_regs", S_IRUGO, root, cd, &curr_regs_fops); + debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd, + &curr_dbg_uid0_fops); + debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd, + &curr_dbg_uid1_fops); + debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd, + &curr_dbg_uid2_fops); + debugfs_create_file("prev_regs", S_IRUGO, root, cd, &prev_regs_fops); + debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd, + &prev_dbg_uid0_fops); + debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd, + &prev_dbg_uid1_fops); + debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd, + &prev_dbg_uid2_fops); for (i = 0; i < GENWQE_MAX_VFS; i++) { sprintf(name, "vf%u_jobtimeout_msec", i); - - file = debugfs_create_u32(name, 0666, root, - &cd->vf_jobtimeout_msec[i]); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_u32(name, 0666, root, + &cd->vf_jobtimeout_msec[i]); } - file = debugfs_create_file("jobtimer", S_IRUGO, root, cd, - &jtimer_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("queue_working_time", S_IRUGO, root, cd, - &queue_working_time_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("skip_recovery", 0666, root, - &cd->skip_recovery); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_u32("use_platform_recovery", 0666, root, - &cd->use_platform_recovery); - if (!file) { - ret = -ENOMEM; - goto err1; - } + debugfs_create_file("jobtimer", S_IRUGO, root, cd, &jtimer_fops); + debugfs_create_file("queue_working_time", S_IRUGO, root, cd, + &queue_working_time_fops); + debugfs_create_u32("skip_recovery", 0666, root, &cd->skip_recovery); + debugfs_create_u32("use_platform_recovery", 0666, root, + &cd->use_platform_recovery); cd->debugfs_root = root; - return 0; -err1: - debugfs_remove_recursive(root); -err0: - return ret; } void genqwe_exit_debugfs(struct genwqe_dev *cd) diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 3bc51f19c734..0e34c0568fed 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -1301,14 +1301,10 @@ int genwqe_device_create(struct genwqe_dev *cd) goto err_cdev; } - rc = genwqe_init_debugfs(cd); - if (rc != 0) - goto err_debugfs; + genwqe_init_debugfs(cd); return 0; - err_debugfs: - device_destroy(cd->class_genwqe, cd->devnum_genwqe); err_cdev: cdev_del(&cd->cdev_genwqe); err_add: diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 756794ac8fd8..66ae6b2a6950 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -121,6 +121,9 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(READ_AFTER_FREE), CRASHTYPE(WRITE_BUDDY_AFTER_FREE), CRASHTYPE(READ_BUDDY_AFTER_FREE), + CRASHTYPE(SLAB_FREE_DOUBLE), + CRASHTYPE(SLAB_FREE_CROSS), + CRASHTYPE(SLAB_FREE_PAGE), CRASHTYPE(SOFTLOCKUP), CRASHTYPE(HARDLOCKUP), CRASHTYPE(SPINLOCKUP), @@ -388,7 +391,7 @@ static int __init lkdtm_module_init(void) { struct crashpoint *crashpoint = NULL; const struct crashtype *crashtype = NULL; - int ret = -EINVAL; + int ret; int i; /* Neither or both of these need to be set */ @@ -427,25 +430,17 @@ static int __init lkdtm_module_init(void) lkdtm_bugs_init(&recur_count); lkdtm_perms_init(); lkdtm_usercopy_init(); + lkdtm_heap_init(); /* Register debugfs interface */ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); - if (!lkdtm_debugfs_root) { - pr_err("creating root dir failed\n"); - return -ENODEV; - } /* Install debugfs trigger files. */ for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { struct crashpoint *cur = &crashpoints[i]; - struct dentry *de; - de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, - cur, &cur->fops); - if (de == NULL) { - pr_err("could not create crashpoint %s\n", cur->name); - goto out_err; - } + debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, cur, + &cur->fops); } /* Install crashpoint if one was selected. */ @@ -473,6 +468,7 @@ static void __exit lkdtm_module_exit(void) debugfs_remove_recursive(lkdtm_debugfs_root); /* Handle test-specific clean-up. */ + lkdtm_heap_exit(); lkdtm_usercopy_exit(); if (lkdtm_kprobe != NULL) diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 65026d7de130..3c5cec85edce 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -7,6 +7,10 @@ #include <linux/slab.h> #include <linux/sched.h> +static struct kmem_cache *double_free_cache; +static struct kmem_cache *a_cache; +static struct kmem_cache *b_cache; + /* * This tries to stay within the next largest power-of-2 kmalloc cache * to avoid actually overwriting anything important if it's not detected @@ -146,3 +150,71 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void) kfree(val); } + +void lkdtm_SLAB_FREE_DOUBLE(void) +{ + int *val; + + val = kmem_cache_alloc(double_free_cache, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate double_free_cache memory.\n"); + return; + } + + /* Just make sure we got real memory. */ + *val = 0x12345678; + pr_info("Attempting double slab free ...\n"); + kmem_cache_free(double_free_cache, val); + kmem_cache_free(double_free_cache, val); +} + +void lkdtm_SLAB_FREE_CROSS(void) +{ + int *val; + + val = kmem_cache_alloc(a_cache, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate a_cache memory.\n"); + return; + } + + /* Just make sure we got real memory. */ + *val = 0x12345679; + pr_info("Attempting cross-cache slab free ...\n"); + kmem_cache_free(b_cache, val); +} + +void lkdtm_SLAB_FREE_PAGE(void) +{ + unsigned long p = __get_free_page(GFP_KERNEL); + + pr_info("Attempting non-Slab slab free ...\n"); + kmem_cache_free(NULL, (void *)p); + free_page(p); +} + +/* + * We have constructors to keep the caches distinctly separated without + * needing to boot with "slab_nomerge". + */ +static void ctor_double_free(void *region) +{ } +static void ctor_a(void *region) +{ } +static void ctor_b(void *region) +{ } + +void __init lkdtm_heap_init(void) +{ + double_free_cache = kmem_cache_create("lkdtm-heap-double_free", + 64, 0, 0, ctor_double_free); + a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a); + b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b); +} + +void __exit lkdtm_heap_exit(void) +{ + kmem_cache_destroy(double_free_cache); + kmem_cache_destroy(a_cache); + kmem_cache_destroy(b_cache); +} diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index bbcd370786d4..6a284a87a037 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -29,11 +29,16 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void); void lkdtm_UNSET_SMEP(void); /* lkdtm_heap.c */ +void __init lkdtm_heap_init(void); +void __exit lkdtm_heap_exit(void); void lkdtm_OVERWRITE_ALLOCATION(void); void lkdtm_WRITE_AFTER_FREE(void); void lkdtm_READ_AFTER_FREE(void); void lkdtm_WRITE_BUDDY_AFTER_FREE(void); void lkdtm_READ_BUDDY_AFTER_FREE(void); +void lkdtm_SLAB_FREE_DOUBLE(void); +void lkdtm_SLAB_FREE_CROSS(void); +void lkdtm_SLAB_FREE_PAGE(void); /* lkdtm_perms.c */ void __init lkdtm_perms_init(void); diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index 47cfd5005e1b..a26c716c61a1 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -154,46 +154,21 @@ void mei_dbgfs_deregister(struct mei_device *dev) * * @dev: the mei device structure * @name: the mei device name - * - * Return: 0 on success, <0 on failure. */ -int mei_dbgfs_register(struct mei_device *dev, const char *name) +void mei_dbgfs_register(struct mei_device *dev, const char *name) { - struct dentry *dir, *f; + struct dentry *dir; dir = debugfs_create_dir(name, NULL); - if (!dir) - return -ENOMEM; - dev->dbgfs_dir = dir; - f = debugfs_create_file("meclients", S_IRUSR, dir, - dev, &mei_dbgfs_meclients_fops); - if (!f) { - dev_err(dev->dev, "meclients: registration failed\n"); - goto err; - } - f = debugfs_create_file("active", S_IRUSR, dir, - dev, &mei_dbgfs_active_fops); - if (!f) { - dev_err(dev->dev, "active: registration failed\n"); - goto err; - } - f = debugfs_create_file("devstate", S_IRUSR, dir, - dev, &mei_dbgfs_devstate_fops); - if (!f) { - dev_err(dev->dev, "devstate: registration failed\n"); - goto err; - } - f = debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir, - &dev->allow_fixed_address, - &mei_dbgfs_allow_fa_fops); - if (!f) { - dev_err(dev->dev, "allow_fixed_address: registration failed\n"); - goto err; - } - return 0; -err: - mei_dbgfs_deregister(dev); - return -ENODEV; + debugfs_create_file("meclients", S_IRUSR, dir, dev, + &mei_dbgfs_meclients_fops); + debugfs_create_file("active", S_IRUSR, dir, dev, + &mei_dbgfs_active_fops); + debugfs_create_file("devstate", S_IRUSR, dir, dev, + &mei_dbgfs_devstate_fops); + debugfs_create_file("allow_fixed_address", S_IRUSR | S_IWUSR, dir, + &dev->allow_fixed_address, + &mei_dbgfs_allow_fa_fops); } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index ad02097d7fee..f894d1f8a53e 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -984,16 +984,10 @@ int mei_register(struct mei_device *dev, struct device *parent) goto err_dev_create; } - ret = mei_dbgfs_register(dev, dev_name(clsdev)); - if (ret) { - dev_err(clsdev, "cannot register debugfs ret = %d\n", ret); - goto err_dev_dbgfs; - } + mei_dbgfs_register(dev, dev_name(clsdev)); return 0; -err_dev_dbgfs: - device_destroy(mei_class, devno); err_dev_create: cdev_del(&dev->cdev); err_dev_add: diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index fca832fcac57..f71a023aed3c 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -718,13 +718,10 @@ bool mei_hbuf_acquire(struct mei_device *dev); bool mei_write_is_idle(struct mei_device *dev); #if IS_ENABLED(CONFIG_DEBUG_FS) -int mei_dbgfs_register(struct mei_device *dev, const char *name); +void mei_dbgfs_register(struct mei_device *dev, const char *name); void mei_dbgfs_deregister(struct mei_device *dev); #else -static inline int mei_dbgfs_register(struct mei_device *dev, const char *name) -{ - return 0; -} +static inline void mei_dbgfs_register(struct mei_device *dev, const char *name) {} static inline void mei_dbgfs_deregister(struct mei_device *dev) {} #endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/misc/mic/card/mic_debugfs.c b/drivers/misc/mic/card/mic_debugfs.c index bf7a60ccc66c..3ee3d2402634 100644 --- a/drivers/misc/mic/card/mic_debugfs.c +++ b/drivers/misc/mic/card/mic_debugfs.c @@ -51,25 +51,13 @@ DEFINE_SHOW_ATTRIBUTE(mic_intr); */ void __init mic_create_card_debug_dir(struct mic_driver *mdrv) { - struct dentry *d; - if (!mic_dbg) return; mdrv->dbg_dir = debugfs_create_dir(mdrv->name, mic_dbg); - if (!mdrv->dbg_dir) { - dev_err(mdrv->dev, "Cant create dbg_dir %s\n", mdrv->name); - return; - } - - d = debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, - mdrv, &mic_intr_fops); - if (!d) { - dev_err(mdrv->dev, - "Cant create dbg intr_test %s\n", mdrv->name); - return; - } + debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, mdrv, + &mic_intr_fops); } /** @@ -89,8 +77,6 @@ void mic_delete_card_debug_dir(struct mic_driver *mdrv) void __init mic_init_card_debugfs(void) { mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!mic_dbg) - pr_err("can't create debugfs dir\n"); } /** diff --git a/drivers/misc/mic/cosm/cosm_debugfs.c b/drivers/misc/mic/cosm/cosm_debugfs.c index 8e3f4589f16d..2fc9f4bf7001 100644 --- a/drivers/misc/mic/cosm/cosm_debugfs.c +++ b/drivers/misc/mic/cosm/cosm_debugfs.c @@ -93,8 +93,6 @@ void cosm_create_debug_dir(struct cosm_device *cdev) scnprintf(name, sizeof(name), "mic%d", cdev->index); cdev->dbg_dir = debugfs_create_dir(name, cosm_dbg); - if (!cdev->dbg_dir) - return; debugfs_create_file("log_buf", 0444, cdev->dbg_dir, cdev, &log_buf_fops); @@ -113,8 +111,6 @@ void cosm_delete_debug_dir(struct cosm_device *cdev) void cosm_init_debugfs(void) { cosm_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!cosm_dbg) - pr_err("can't create debugfs dir\n"); } void cosm_exit_debugfs(void) diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c index 7ef8efe9552f..8a8e41677501 100644 --- a/drivers/misc/mic/host/mic_debugfs.c +++ b/drivers/misc/mic/host/mic_debugfs.c @@ -113,8 +113,6 @@ void mic_create_debug_dir(struct mic_device *mdev) scnprintf(name, sizeof(name), "mic%d", mdev->id); mdev->dbg_dir = debugfs_create_dir(name, mic_dbg); - if (!mdev->dbg_dir) - return; debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &mic_smpt_fops); @@ -143,8 +141,6 @@ void mic_delete_debug_dir(struct mic_device *mdev) void __init mic_init_debugfs(void) { mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!mic_dbg) - pr_err("can't create debugfs dir\n"); } /** diff --git a/drivers/misc/mic/scif/scif_debugfs.c b/drivers/misc/mic/scif/scif_debugfs.c index a6820480105a..8fe38e7ca6e6 100644 --- a/drivers/misc/mic/scif/scif_debugfs.c +++ b/drivers/misc/mic/scif/scif_debugfs.c @@ -103,11 +103,6 @@ DEFINE_SHOW_ATTRIBUTE(scif_rma); void __init scif_init_debugfs(void) { scif_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!scif_dbg) { - dev_err(scif_info.mdev.this_device, - "can't create debugfs dir scif\n"); - return; - } debugfs_create_file("scif_dev", 0444, scif_dbg, NULL, &scif_dev_fops); debugfs_create_file("scif_rma", 0444, scif_dbg, NULL, &scif_rma_fops); diff --git a/drivers/misc/mic/vop/vop_debugfs.c b/drivers/misc/mic/vop/vop_debugfs.c index ed59cd75e182..9d4f175f4dd1 100644 --- a/drivers/misc/mic/vop/vop_debugfs.c +++ b/drivers/misc/mic/vop/vop_debugfs.c @@ -174,10 +174,6 @@ void vop_init_debugfs(struct vop_info *vi) snprintf(name, sizeof(name), "%s%d", KBUILD_MODNAME, vi->vpdev->dnode); vi->dbg = debugfs_create_dir(name, NULL); - if (!vi->dbg) { - pr_err("can't create debugfs dir vop\n"); - return; - } debugfs_create_file("dp", 0444, vi->dbg, vi, &vop_dp_fops); debugfs_create_file("vdev_info", 0444, vi->dbg, vi, &vop_vdev_info_fops); } diff --git a/drivers/misc/ocxl/config.c b/drivers/misc/ocxl/config.c index 5e65acb8e134..c8e19bfb5ef9 100644 --- a/drivers/misc/ocxl/config.c +++ b/drivers/misc/ocxl/config.c @@ -20,11 +20,14 @@ #define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28 #define OCXL_DVSEC_TEMPL_MMIO_PP 0x30 #define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38 -#define OCXL_DVSEC_TEMPL_MEM_SZ 0x3C -#define OCXL_DVSEC_TEMPL_WWID 0x40 +#define OCXL_DVSEC_TEMPL_ALL_MEM_SZ 0x3C +#define OCXL_DVSEC_TEMPL_LPC_MEM_START 0x40 +#define OCXL_DVSEC_TEMPL_WWID 0x48 +#define OCXL_DVSEC_TEMPL_LPC_MEM_SZ 0x58 #define OCXL_MAX_AFU_PER_FUNCTION 64 -#define OCXL_TEMPL_LEN 0x58 +#define OCXL_TEMPL_LEN_1_0 0x58 +#define OCXL_TEMPL_LEN_1_1 0x60 #define OCXL_TEMPL_NAME_LEN 24 #define OCXL_CFG_TIMEOUT 3 @@ -269,34 +272,72 @@ static int read_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn, return 0; } +/** + * Read the template version from the AFU + * dev: the device for the AFU + * fn: the AFU offsets + * len: outputs the template length + * version: outputs the major<<8,minor version + * + * Returns 0 on success, negative on failure + */ +static int read_template_version(struct pci_dev *dev, struct ocxl_fn_config *fn, + u16 *len, u16 *version) +{ + u32 val32; + u8 major, minor; + int rc; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val32); + if (rc) + return rc; + + *len = EXTRACT_BITS(val32, 16, 31); + major = EXTRACT_BITS(val32, 8, 15); + minor = EXTRACT_BITS(val32, 0, 7); + *version = (major << 8) + minor; + return 0; +} + int ocxl_config_check_afu_index(struct pci_dev *dev, struct ocxl_fn_config *fn, int afu_idx) { - u32 val; - int rc, templ_major, templ_minor, len; + int rc; + u16 templ_version; + u16 len, expected_len; pci_write_config_byte(dev, fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX, afu_idx); - rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val); + + rc = read_template_version(dev, fn, &len, &templ_version); if (rc) return rc; - /* AFU index map can have holes */ - if (!val) + /* AFU index map can have holes, in which case we read all 0's */ + if (!templ_version && !len) return 0; - templ_major = EXTRACT_BITS(val, 8, 15); - templ_minor = EXTRACT_BITS(val, 0, 7); dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n", - templ_major, templ_minor); - - len = EXTRACT_BITS(val, 16, 31); - if (len != OCXL_TEMPL_LEN) { - dev_warn(&dev->dev, - "Unexpected template length in AFU information (%#x)\n", - len); + templ_version >> 8, templ_version & 0xFF); + + switch (templ_version) { + case 0x0005: // v0.5 was used prior to the spec approval + case 0x0100: + expected_len = OCXL_TEMPL_LEN_1_0; + break; + case 0x0101: + expected_len = OCXL_TEMPL_LEN_1_1; + break; + default: + dev_warn(&dev->dev, "Unknown AFU template version %#x\n", + templ_version); + expected_len = len; } + if (len != expected_len) + dev_warn(&dev->dev, + "Unexpected template length %#x in AFU information, expected %#x for version %#x\n", + len, expected_len, templ_version); return 1; } @@ -434,6 +475,102 @@ static int validate_afu(struct pci_dev *dev, struct ocxl_afu_config *afu) return 0; } +/** + * Populate AFU metadata regarding LPC memory + * dev: the device for the AFU + * fn: the AFU offsets + * afu: the AFU struct to populate the LPC metadata into + * + * Returns 0 on success, negative on failure + */ +static int read_afu_lpc_memory_info(struct pci_dev *dev, + struct ocxl_fn_config *fn, + struct ocxl_afu_config *afu) +{ + int rc; + u32 val32; + u16 templ_version; + u16 templ_len; + u64 total_mem_size = 0; + u64 lpc_mem_size = 0; + + afu->lpc_mem_offset = 0; + afu->lpc_mem_size = 0; + afu->special_purpose_mem_offset = 0; + afu->special_purpose_mem_size = 0; + /* + * For AFUs following template v1.0, the LPC memory covers the + * total memory. Its size is a power of 2. + * + * For AFUs with template >= v1.01, the total memory size is + * still a power of 2, but it is split in 2 parts: + * - the LPC memory, whose size can now be anything + * - the remainder memory is a special purpose memory, whose + * definition is AFU-dependent. It is not accessible through + * the usual commands for LPC memory + */ + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_ALL_MEM_SZ, &val32); + if (rc) + return rc; + + val32 = EXTRACT_BITS(val32, 0, 7); + if (!val32) + return 0; /* No LPC memory */ + + /* + * The configuration space spec allows for a memory size of up + * to 2^255 bytes. + * + * Current generation hardware uses 56-bit physical addresses, + * but we won't be able to get near close to that, as we won't + * have a hole big enough in the memory map. Let it pass in + * the driver for now. We'll get an error from the firmware + * when trying to configure something too big. + */ + total_mem_size = 1ull << val32; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START, &val32); + if (rc) + return rc; + + afu->lpc_mem_offset = val32; + + rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START + 4, &val32); + if (rc) + return rc; + + afu->lpc_mem_offset |= (u64) val32 << 32; + + rc = read_template_version(dev, fn, &templ_len, &templ_version); + if (rc) + return rc; + + if (templ_version >= 0x0101) { + rc = read_afu_info(dev, fn, + OCXL_DVSEC_TEMPL_LPC_MEM_SZ, &val32); + if (rc) + return rc; + lpc_mem_size = val32; + + rc = read_afu_info(dev, fn, + OCXL_DVSEC_TEMPL_LPC_MEM_SZ + 4, &val32); + if (rc) + return rc; + lpc_mem_size |= (u64) val32 << 32; + } else { + lpc_mem_size = total_mem_size; + } + afu->lpc_mem_size = lpc_mem_size; + + if (lpc_mem_size < total_mem_size) { + afu->special_purpose_mem_offset = + afu->lpc_mem_offset + lpc_mem_size; + afu->special_purpose_mem_size = + total_mem_size - lpc_mem_size; + } + return 0; +} + int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn, struct ocxl_afu_config *afu, u8 afu_idx) { @@ -467,10 +604,9 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn, if (rc) return rc; - rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MEM_SZ, &val32); + rc = read_afu_lpc_memory_info(dev, fn, afu); if (rc) return rc; - afu->log_mem_size = EXTRACT_BITS(val32, 0, 7); rc = read_afu_control(dev, afu); if (rc) @@ -487,7 +623,12 @@ int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn, dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar); dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset); dev_dbg(&dev->dev, " pp mmio stride = %#x\n", afu->pp_mmio_stride); - dev_dbg(&dev->dev, " mem size (log) = %hhu\n", afu->log_mem_size); + dev_dbg(&dev->dev, " lpc_mem offset = %#llx\n", afu->lpc_mem_offset); + dev_dbg(&dev->dev, " lpc_mem size = %#llx\n", afu->lpc_mem_size); + dev_dbg(&dev->dev, " special purpose mem offset = %#llx\n", + afu->special_purpose_mem_offset); + dev_dbg(&dev->dev, " special purpose mem size = %#llx\n", + afu->special_purpose_mem_size); dev_dbg(&dev->dev, " pasid supported (log) = %u\n", afu->pasid_supported_log); dev_dbg(&dev->dev, " actag supported = %u\n", diff --git a/drivers/misc/ocxl/pci.c b/drivers/misc/ocxl/pci.c index f2a3ef4b9bdd..cb920aa88d3a 100644 --- a/drivers/misc/ocxl/pci.c +++ b/drivers/misc/ocxl/pci.c @@ -41,7 +41,7 @@ static int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id) return 0; } -void ocxl_remove(struct pci_dev *dev) +static void ocxl_remove(struct pci_dev *dev) { struct ocxl_fn *fn; struct ocxl_afu *afu; diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 18ca938b86e6..a36ed1ff5967 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -748,10 +748,6 @@ static int kim_probe(struct platform_device *pdev) pr_info("sysfs entries created\n"); kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); - if (!kim_debugfs_dir) { - pr_err(" debugfs entries creation failed "); - return 0; - } debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, kim_gdata, &version_fops); diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 043eed845246..97b58e7ad901 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -1699,19 +1699,10 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) DEFINE_SHOW_ATTRIBUTE(vmballoon_debug); -static int __init vmballoon_debugfs_init(struct vmballoon *b) +static void __init vmballoon_debugfs_init(struct vmballoon *b) { - int error; - b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, &vmballoon_debug_fops); - if (IS_ERR(b->dbg_entry)) { - error = PTR_ERR(b->dbg_entry); - pr_err("failed to create debugfs entry, error: %d\n", error); - return error; - } - - return 0; } static void __exit vmballoon_debugfs_exit(struct vmballoon *b) @@ -1724,9 +1715,8 @@ static void __exit vmballoon_debugfs_exit(struct vmballoon *b) #else -static inline int vmballoon_debugfs_init(struct vmballoon *b) +static inline void vmballoon_debugfs_init(struct vmballoon *b) { - return 0; } static inline void vmballoon_debugfs_exit(struct vmballoon *b) @@ -1948,10 +1938,6 @@ static int __init vmballoon_init(void) if (error) goto fail; - error = vmballoon_debugfs_init(&balloon); - if (error) - goto fail; - /* * Initialization of compaction must be done after the call to * balloon_devinfo_init() . @@ -1971,6 +1957,8 @@ static int __init vmballoon_init(void) queue_delayed_work(system_freezable_wq, &balloon.dwork, 0); + vmballoon_debugfs_init(&balloon); + return 0; fail: vmballoon_unregister_shrinker(&balloon); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index fb31a7f649a3..80a6e2dcd085 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -274,4 +274,6 @@ source "drivers/mtd/spi-nor/Kconfig" source "drivers/mtd/ubi/Kconfig" +source "drivers/mtd/hyperbus/Kconfig" + endif # MTD diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 806287e80e84..62d649a959e2 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -34,3 +34,4 @@ obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ obj-$(CONFIG_MTD_UBI) += ubi/ +obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/ diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index c8fa5906bdf9..f4da7bd552e9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -49,6 +49,16 @@ #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 +/* + * Status Register bit description. Used by flash devices that don't + * support DQ polling (e.g. HyperFlash) + */ +#define CFI_SR_DRB BIT(7) +#define CFI_SR_ESB BIT(5) +#define CFI_SR_PSB BIT(4) +#define CFI_SR_WBASB BIT(3) +#define CFI_SR_SLSB BIT(1) + static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -97,6 +107,50 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = { .module = THIS_MODULE }; +/* + * Use status register to poll for Erase/write completion when DQ is not + * supported. This is indicated by Bit[1:0] of SoftwareFeatures field in + * CFI Primary Vendor-Specific Extended Query table 1.5 + */ +static int cfi_use_status_reg(struct cfi_private *cfi) +{ + struct cfi_pri_amdstd *extp = cfi->cmdset_priv; + u8 poll_mask = CFI_POLL_STATUS_REG | CFI_POLL_DQ; + + return extp->MinorVersion >= '5' && + (extp->SoftwareFeatures & poll_mask) == CFI_POLL_STATUS_REG; +} + +static void cfi_check_err_status(struct map_info *map, struct flchip *chip, + unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + map_word status; + + if (!cfi_use_status_reg(cfi)) + return; + + cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, + cfi->device_type, NULL); + status = map_read(map, adr); + + if (map_word_bitsset(map, status, CMD(0x3a))) { + unsigned long chipstatus = MERGESTATUS(status); + + if (chipstatus & CFI_SR_ESB) + pr_err("%s erase operation failed, status %lx\n", + map->name, chipstatus); + if (chipstatus & CFI_SR_PSB) + pr_err("%s program operation failed, status %lx\n", + map->name, chipstatus); + if (chipstatus & CFI_SR_WBASB) + pr_err("%s buffer program command aborted, status %lx\n", + map->name, chipstatus); + if (chipstatus & CFI_SR_SLSB) + pr_err("%s sector write protected, status %lx\n", + map->name, chipstatus); + } +} /* #define DEBUG_CFI_FEATURES */ @@ -742,10 +796,25 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) * correctly and is therefore not done (particularly with interleaved chips * as each chip must be checked independently of the others). */ -static int __xipram chip_ready(struct map_info *map, unsigned long addr) +static int __xipram chip_ready(struct map_info *map, struct flchip *chip, + unsigned long addr) { + struct cfi_private *cfi = map->fldrv_priv; map_word d, t; + if (cfi_use_status_reg(cfi)) { + map_word ready = CMD(CFI_SR_DRB); + /* + * For chips that support status register, check device + * ready bit + */ + cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, + cfi->device_type, NULL); + d = map_read(map, addr); + + return map_word_andequal(map, d, ready, ready); + } + d = map_read(map, addr); t = map_read(map, addr); @@ -767,10 +836,30 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr) * as each chip must be checked independently of the others). * */ -static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected) +static int __xipram chip_good(struct map_info *map, struct flchip *chip, + unsigned long addr, map_word expected) { + struct cfi_private *cfi = map->fldrv_priv; map_word oldd, curd; + if (cfi_use_status_reg(cfi)) { + map_word ready = CMD(CFI_SR_DRB); + map_word err = CMD(CFI_SR_PSB | CFI_SR_ESB); + /* + * For chips that support status register, check device + * ready bit and Erase/Program status bit to know if + * operation succeeded. + */ + cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi, + cfi->device_type, NULL); + curd = map_read(map, addr); + + if (map_word_andequal(map, curd, ready, ready)) + return !map_word_bitsset(map, curd, err); + + return 0; + } + oldd = map_read(map, addr); curd = map_read(map, addr); @@ -792,7 +881,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr case FL_STATUS: for (;;) { - if (chip_ready(map, adr)) + if (chip_ready(map, chip, adr)) break; if (time_after(jiffies, timeo)) { @@ -830,7 +919,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr chip->state = FL_ERASE_SUSPENDING; chip->erase_suspended = 1; for (;;) { - if (chip_ready(map, adr)) + if (chip_ready(map, chip, adr)) break; if (time_after(jiffies, timeo)) { @@ -1362,7 +1451,7 @@ static int do_otp_lock(struct map_info *map, struct flchip *chip, loff_t adr, /* wait for chip to become ready */ timeo = jiffies + msecs_to_jiffies(2); for (;;) { - if (chip_ready(map, adr)) + if (chip_ready(map, chip, adr)) break; if (time_after(jiffies, timeo)) { @@ -1628,22 +1717,24 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, continue; } - if (time_after(jiffies, timeo) && !chip_ready(map, adr)){ + if (time_after(jiffies, timeo) && + !chip_ready(map, chip, adr)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr); break; } - if (chip_ready(map, adr)) + if (chip_ready(map, chip, adr)) break; /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1); } /* Did we succeed? */ - if (!chip_good(map, adr, datum)) { + if (!chip_good(map, chip, adr, datum)) { /* reset on all failures. */ + cfi_check_err_status(map, chip, adr); map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ @@ -1881,10 +1972,11 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, * We check "time_after" and "!chip_good" before checking "chip_good" to avoid * the failure due to scheduling. */ - if (time_after(jiffies, timeo) && !chip_good(map, adr, datum)) + if (time_after(jiffies, timeo) && + !chip_good(map, chip, adr, datum)) break; - if (chip_good(map, adr, datum)) { + if (chip_good(map, chip, adr, datum)) { xip_enable(map, chip, adr); goto op_done; } @@ -1901,6 +1993,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, * See e.g. * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf */ + cfi_check_err_status(map, chip, adr); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, @@ -2018,7 +2111,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip, * If the driver thinks the chip is idle, and no toggle bits * are changing, then the chip is actually idle for sure. */ - if (chip->state == FL_READY && chip_ready(map, adr)) + if (chip->state == FL_READY && chip_ready(map, chip, adr)) return 0; /* @@ -2035,7 +2128,7 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip, /* wait for the chip to become ready */ for (i = 0; i < jiffies_to_usecs(timeo); i++) { - if (chip_ready(map, adr)) + if (chip_ready(map, chip, adr)) return 0; udelay(1); @@ -2099,14 +2192,15 @@ retry: map_write(map, datum, adr); for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) { - if (chip_ready(map, adr)) + if (chip_ready(map, chip, adr)) break; udelay(1); } - if (!chip_good(map, adr, datum)) { + if (!chip_good(map, chip, adr, datum)) { /* reset on all failures. */ + cfi_check_err_status(map, chip, adr); map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ @@ -2300,7 +2394,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->erase_suspended = 0; } - if (chip_good(map, adr, map_word_ff(map))) + if (chip_good(map, chip, adr, map_word_ff(map))) break; if (time_after(jiffies, timeo)) { @@ -2316,6 +2410,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) /* Did we succeed? */ if (ret) { /* reset on all failures. */ + cfi_check_err_status(map, chip, adr); map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ @@ -2396,7 +2491,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->erase_suspended = 0; } - if (chip_good(map, adr, map_word_ff(map))) + if (chip_good(map, chip, adr, map_word_ff(map))) break; if (time_after(jiffies, timeo)) { @@ -2412,6 +2507,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, /* Did we succeed? */ if (ret) { /* reset on all failures. */ + cfi_check_err_status(map, chip, adr); map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ @@ -2533,8 +2629,6 @@ struct ppb_lock { int locked; }; -#define MAX_SECTORS 512 - #define DO_XXLOCK_ONEBLOCK_LOCK ((void *)1) #define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *)2) #define DO_XXLOCK_ONEBLOCK_GETLOCK ((void *)3) @@ -2589,7 +2683,7 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, */ timeo = jiffies + msecs_to_jiffies(2000); /* 2s max (un)locking */ for (;;) { - if (chip_ready(map, adr)) + if (chip_ready(map, chip, adr)) break; if (time_after(jiffies, timeo)) { @@ -2633,6 +2727,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, int i; int sectors; int ret; + int max_sectors; /* * PPB unlocking always unlocks all sectors of the flash chip. @@ -2640,7 +2735,11 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, * first check the locking status of all sectors and save * it for future use. */ - sect = kcalloc(MAX_SECTORS, sizeof(struct ppb_lock), GFP_KERNEL); + max_sectors = 0; + for (i = 0; i < mtd->numeraseregions; i++) + max_sectors += regions[i].numblocks; + + sect = kcalloc(max_sectors, sizeof(struct ppb_lock), GFP_KERNEL); if (!sect) return -ENOMEM; @@ -2689,9 +2788,9 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, } sectors++; - if (sectors >= MAX_SECTORS) { + if (sectors >= max_sectors) { printk(KERN_ERR "Only %d sectors for PPB locking supported!\n", - MAX_SECTORS); + max_sectors); kfree(sect); return -EINVAL; } diff --git a/drivers/mtd/hyperbus/Kconfig b/drivers/mtd/hyperbus/Kconfig new file mode 100644 index 000000000000..cff6bbd226f5 --- /dev/null +++ b/drivers/mtd/hyperbus/Kconfig @@ -0,0 +1,23 @@ +menuconfig MTD_HYPERBUS + tristate "HyperBus support" + select MTD_CFI + select MTD_MAP_BANK_WIDTH_2 + select MTD_CFI_AMDSTD + select MTD_COMPLEX_MAPPINGS + help + This is the framework for the HyperBus which can be used by + the HyperBus Controller driver to communicate with + HyperFlash. See Cypress HyperBus specification for more + details + +if MTD_HYPERBUS + +config HBMC_AM654 + tristate "HyperBus controller driver for AM65x SoC" + select MULTIPLEXER + select MUX_MMIO + help + This is the driver for HyperBus controller on TI's AM65x and + other SoCs + +endif # MTD_HYPERBUS diff --git a/drivers/mtd/hyperbus/Makefile b/drivers/mtd/hyperbus/Makefile new file mode 100644 index 000000000000..8a936e066f48 --- /dev/null +++ b/drivers/mtd/hyperbus/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_MTD_HYPERBUS) += hyperbus-core.o +obj-$(CONFIG_HBMC_AM654) += hbmc-am654.o diff --git a/drivers/mtd/hyperbus/hbmc-am654.c b/drivers/mtd/hyperbus/hbmc-am654.c new file mode 100644 index 000000000000..08d543b124cd --- /dev/null +++ b/drivers/mtd/hyperbus/hbmc-am654.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ +// Author: Vignesh Raghavendra <vigneshr@ti.com> + +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mtd/cfi.h> +#include <linux/mtd/hyperbus.h> +#include <linux/mtd/mtd.h> +#include <linux/mux/consumer.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/types.h> + +#define AM654_HBMC_CALIB_COUNT 25 + +struct am654_hbmc_priv { + struct hyperbus_ctlr ctlr; + struct hyperbus_device hbdev; + struct mux_control *mux_ctrl; +}; + +static int am654_hbmc_calibrate(struct hyperbus_device *hbdev) +{ + struct map_info *map = &hbdev->map; + struct cfi_private cfi; + int count = AM654_HBMC_CALIB_COUNT; + int pass_count = 0; + int ret; + + cfi.interleave = 1; + cfi.device_type = CFI_DEVICETYPE_X16; + cfi_send_gen_cmd(0xF0, 0, 0, map, &cfi, cfi.device_type, NULL); + cfi_send_gen_cmd(0x98, 0x55, 0, map, &cfi, cfi.device_type, NULL); + + while (count--) { + ret = cfi_qry_present(map, 0, &cfi); + if (ret) + pass_count++; + else + pass_count = 0; + if (pass_count == 5) + break; + } + + cfi_qry_mode_off(0, map, &cfi); + + return ret; +} + +static const struct hyperbus_ops am654_hbmc_ops = { + .calibrate = am654_hbmc_calibrate, +}; + +static int am654_hbmc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct am654_hbmc_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + if (of_property_read_bool(dev->of_node, "mux-controls")) { + struct mux_control *control = devm_mux_control_get(dev, NULL); + + if (IS_ERR(control)) + return PTR_ERR(control); + + ret = mux_control_select(control, 1); + if (ret) { + dev_err(dev, "Failed to select HBMC mux\n"); + return ret; + } + priv->mux_ctrl = control; + } + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + goto disable_pm; + } + + priv->ctlr.dev = dev; + priv->ctlr.ops = &am654_hbmc_ops; + priv->hbdev.ctlr = &priv->ctlr; + priv->hbdev.np = of_get_next_child(dev->of_node, NULL); + ret = hyperbus_register_device(&priv->hbdev); + if (ret) { + dev_err(dev, "failed to register controller\n"); + pm_runtime_put_sync(&pdev->dev); + goto disable_pm; + } + + return 0; +disable_pm: + pm_runtime_disable(dev); + if (priv->mux_ctrl) + mux_control_deselect(priv->mux_ctrl); + return ret; +} + +static int am654_hbmc_remove(struct platform_device *pdev) +{ + struct am654_hbmc_priv *priv = platform_get_drvdata(pdev); + int ret; + + ret = hyperbus_unregister_device(&priv->hbdev); + if (priv->mux_ctrl) + mux_control_deselect(priv->mux_ctrl); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static const struct of_device_id am654_hbmc_dt_ids[] = { + { + .compatible = "ti,am654-hbmc", + }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, am654_hbmc_dt_ids); + +static struct platform_driver am654_hbmc_platform_driver = { + .probe = am654_hbmc_probe, + .remove = am654_hbmc_remove, + .driver = { + .name = "hbmc-am654", + .of_match_table = am654_hbmc_dt_ids, + }, +}; + +module_platform_driver(am654_hbmc_platform_driver); + +MODULE_DESCRIPTION("HBMC driver for AM654 SoC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:hbmc-am654"); +MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>"); diff --git a/drivers/mtd/hyperbus/hyperbus-core.c b/drivers/mtd/hyperbus/hyperbus-core.c new file mode 100644 index 000000000000..6af9ea34117d --- /dev/null +++ b/drivers/mtd/hyperbus/hyperbus-core.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ +// Author: Vignesh Raghavendra <vigneshr@ti.com> + +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mtd/hyperbus.h> +#include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/types.h> + +static struct hyperbus_device *map_to_hbdev(struct map_info *map) +{ + return container_of(map, struct hyperbus_device, map); +} + +static map_word hyperbus_read16(struct map_info *map, unsigned long addr) +{ + struct hyperbus_device *hbdev = map_to_hbdev(map); + struct hyperbus_ctlr *ctlr = hbdev->ctlr; + map_word read_data; + + read_data.x[0] = ctlr->ops->read16(hbdev, addr); + + return read_data; +} + +static void hyperbus_write16(struct map_info *map, map_word d, + unsigned long addr) +{ + struct hyperbus_device *hbdev = map_to_hbdev(map); + struct hyperbus_ctlr *ctlr = hbdev->ctlr; + + ctlr->ops->write16(hbdev, addr, d.x[0]); +} + +static void hyperbus_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + struct hyperbus_device *hbdev = map_to_hbdev(map); + struct hyperbus_ctlr *ctlr = hbdev->ctlr; + + ctlr->ops->copy_from(hbdev, to, from, len); +} + +static void hyperbus_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + struct hyperbus_device *hbdev = map_to_hbdev(map); + struct hyperbus_ctlr *ctlr = hbdev->ctlr; + + ctlr->ops->copy_to(hbdev, to, from, len); +} + +int hyperbus_register_device(struct hyperbus_device *hbdev) +{ + const struct hyperbus_ops *ops; + struct hyperbus_ctlr *ctlr; + struct device_node *np; + struct map_info *map; + struct resource res; + struct device *dev; + int ret; + + if (!hbdev || !hbdev->np || !hbdev->ctlr || !hbdev->ctlr->dev) { + pr_err("hyperbus: please fill all the necessary fields!\n"); + return -EINVAL; + } + + np = hbdev->np; + ctlr = hbdev->ctlr; + if (!of_device_is_compatible(np, "cypress,hyperflash")) + return -ENODEV; + + hbdev->memtype = HYPERFLASH; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + dev = ctlr->dev; + map = &hbdev->map; + map->size = resource_size(&res); + map->virt = devm_ioremap_resource(dev, &res); + if (IS_ERR(map->virt)) + return PTR_ERR(map->virt); + + map->name = dev_name(dev); + map->bankwidth = 2; + map->device_node = np; + + simple_map_init(map); + ops = ctlr->ops; + if (ops) { + if (ops->read16) + map->read = hyperbus_read16; + if (ops->write16) + map->write = hyperbus_write16; + if (ops->copy_to) + map->copy_to = hyperbus_copy_to; + if (ops->copy_from) + map->copy_from = hyperbus_copy_from; + + if (ops->calibrate && !ctlr->calibrated) { + ret = ops->calibrate(hbdev); + if (!ret) { + dev_err(dev, "Calibration failed\n"); + return -ENODEV; + } + ctlr->calibrated = true; + } + } + + hbdev->mtd = do_map_probe("cfi_probe", map); + if (!hbdev->mtd) { + dev_err(dev, "probing of hyperbus device failed\n"); + return -ENODEV; + } + + hbdev->mtd->dev.parent = dev; + mtd_set_of_node(hbdev->mtd, np); + + ret = mtd_device_register(hbdev->mtd, NULL, 0); + if (ret) { + dev_err(dev, "failed to register mtd device\n"); + map_destroy(hbdev->mtd); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(hyperbus_register_device); + +int hyperbus_unregister_device(struct hyperbus_device *hbdev) +{ + int ret = 0; + + if (hbdev && hbdev->mtd) { + ret = mtd_device_unregister(hbdev->mtd); + map_destroy(hbdev->mtd); + } + + return ret; +} +EXPORT_SYMBOL_GPL(hyperbus_unregister_device); + +MODULE_DESCRIPTION("HyperBus Framework"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>"); diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 7324ff832b41..170a7221b35f 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -437,7 +437,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) return err; } -static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +static int concat_xxlock(struct mtd_info *mtd, loff_t ofs, uint64_t len, + bool is_lock) { struct mtd_concat *concat = CONCAT(mtd); int i, err = -EINVAL; @@ -456,7 +457,10 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) else size = len; - err = mtd_lock(subdev, ofs, size); + if (is_lock) + err = mtd_lock(subdev, ofs, size); + else + err = mtd_unlock(subdev, ofs, size); if (err) break; @@ -471,35 +475,33 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) return err; } +static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + return concat_xxlock(mtd, ofs, len, true); +} + static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { + return concat_xxlock(mtd, ofs, len, false); +} + +static int concat_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ struct mtd_concat *concat = CONCAT(mtd); - int i, err = 0; + int i, err = -EINVAL; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - uint64_t size; if (ofs >= subdev->size) { - size = 0; ofs -= subdev->size; continue; } - if (ofs + len > subdev->size) - size = subdev->size - ofs; - else - size = len; - - err = mtd_unlock(subdev, ofs, size); - if (err) - break; - len -= size; - if (len == 0) + if (ofs + len > subdev->size) break; - err = -EINVAL; - ofs = 0; + return mtd_is_locked(subdev, ofs, len); } return err; @@ -704,6 +706,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd._sync = concat_sync; concat->mtd._lock = concat_lock; concat->mtd._unlock = concat_unlock; + concat->mtd._is_locked = concat_is_locked; concat->mtd._suspend = concat_suspend; concat->mtd._resume = concat_resume; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 453242d6cf56..408615f29e57 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1124,6 +1124,9 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, return -EROFS; if (!len) return 0; + if (!mtd->oops_panic_write) + mtd->oops_panic_write = true; + return mtd->_panic_write(mtd, to, len, retlen, buf); } EXPORT_SYMBOL_GPL(mtd_panic_write); diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c index d759c02d9cb2..a1f8fe1abb10 100644 --- a/drivers/mtd/nand/onenand/onenand_base.c +++ b/drivers/mtd/nand/onenand/onenand_base.c @@ -3257,6 +3257,8 @@ static void onenand_check_features(struct mtd_info *mtd) /* Lock scheme */ switch (density) { + case ONENAND_DEVICE_DENSITY_8Gb: + this->options |= ONENAND_HAS_NOP_1; case ONENAND_DEVICE_DENSITY_4Gb: if (ONENAND_IS_DDP(this)) this->options |= ONENAND_HAS_2PLANE; @@ -3277,12 +3279,15 @@ static void onenand_check_features(struct mtd_info *mtd) if ((this->version_id & 0xf) == 0xe) this->options |= ONENAND_HAS_NOP_1; } + this->options |= ONENAND_HAS_UNLOCK_ALL; + break; case ONENAND_DEVICE_DENSITY_2Gb: /* 2Gb DDP does not have 2 plane */ if (!ONENAND_IS_DDP(this)) this->options |= ONENAND_HAS_2PLANE; this->options |= ONENAND_HAS_UNLOCK_ALL; + break; case ONENAND_DEVICE_DENSITY_1Gb: /* A-Die has all block unlock */ diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 873527753f52..33310b8a6eb8 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -84,6 +84,12 @@ struct brcm_nand_dma_desc { #define FLASH_DMA_ECC_ERROR (1 << 8) #define FLASH_DMA_CORR_ERROR (1 << 9) +/* Bitfields for DMA_MODE */ +#define FLASH_DMA_MODE_STOP_ON_ERROR BIT(1) /* stop in Uncorr ECC error */ +#define FLASH_DMA_MODE_MODE BIT(0) /* link list */ +#define FLASH_DMA_MODE_MASK (FLASH_DMA_MODE_STOP_ON_ERROR | \ + FLASH_DMA_MODE_MODE) + /* 512B flash cache in the NAND controller HW */ #define FC_SHIFT 9U #define FC_BYTES 512U @@ -96,6 +102,51 @@ struct brcm_nand_dma_desc { #define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) #define NAND_POLL_STATUS_TIMEOUT_MS 100 +/* flash_dma registers */ +enum flash_dma_reg { + FLASH_DMA_REVISION = 0, + FLASH_DMA_FIRST_DESC, + FLASH_DMA_FIRST_DESC_EXT, + FLASH_DMA_CTRL, + FLASH_DMA_MODE, + FLASH_DMA_STATUS, + FLASH_DMA_INTERRUPT_DESC, + FLASH_DMA_INTERRUPT_DESC_EXT, + FLASH_DMA_ERROR_STATUS, + FLASH_DMA_CURRENT_DESC, + FLASH_DMA_CURRENT_DESC_EXT, +}; + +/* flash_dma registers v1*/ +static const u16 flash_dma_regs_v1[] = { + [FLASH_DMA_REVISION] = 0x00, + [FLASH_DMA_FIRST_DESC] = 0x04, + [FLASH_DMA_FIRST_DESC_EXT] = 0x08, + [FLASH_DMA_CTRL] = 0x0c, + [FLASH_DMA_MODE] = 0x10, + [FLASH_DMA_STATUS] = 0x14, + [FLASH_DMA_INTERRUPT_DESC] = 0x18, + [FLASH_DMA_INTERRUPT_DESC_EXT] = 0x1c, + [FLASH_DMA_ERROR_STATUS] = 0x20, + [FLASH_DMA_CURRENT_DESC] = 0x24, + [FLASH_DMA_CURRENT_DESC_EXT] = 0x28, +}; + +/* flash_dma registers v4 */ +static const u16 flash_dma_regs_v4[] = { + [FLASH_DMA_REVISION] = 0x00, + [FLASH_DMA_FIRST_DESC] = 0x08, + [FLASH_DMA_FIRST_DESC_EXT] = 0x0c, + [FLASH_DMA_CTRL] = 0x10, + [FLASH_DMA_MODE] = 0x14, + [FLASH_DMA_STATUS] = 0x18, + [FLASH_DMA_INTERRUPT_DESC] = 0x20, + [FLASH_DMA_INTERRUPT_DESC_EXT] = 0x24, + [FLASH_DMA_ERROR_STATUS] = 0x28, + [FLASH_DMA_CURRENT_DESC] = 0x30, + [FLASH_DMA_CURRENT_DESC_EXT] = 0x34, +}; + /* Controller feature flags */ enum { BRCMNAND_HAS_1K_SECTORS = BIT(0), @@ -128,6 +179,8 @@ struct brcmnand_controller { /* List of NAND hosts (one for each chip-select) */ struct list_head host_list; + /* flash_dma reg */ + const u16 *flash_dma_offsets; struct brcm_nand_dma_desc *dma_desc; dma_addr_t dma_pa; @@ -151,6 +204,7 @@ struct brcmnand_controller { u32 nand_cs_nand_xor; u32 corr_stat_threshold; u32 flash_dma_mode; + bool pio_poll_mode; }; struct brcmnand_cfg { @@ -462,7 +516,7 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) /* Register offsets */ if (ctrl->nand_version >= 0x0702) ctrl->reg_offsets = brcmnand_regs_v72; - else if (ctrl->nand_version >= 0x0701) + else if (ctrl->nand_version == 0x0701) ctrl->reg_offsets = brcmnand_regs_v71; else if (ctrl->nand_version >= 0x0600) ctrl->reg_offsets = brcmnand_regs_v60; @@ -507,7 +561,7 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) } /* Maximum spare area sector size (per 512B) */ - if (ctrl->nand_version >= 0x0702) + if (ctrl->nand_version == 0x0702) ctrl->max_oob = 128; else if (ctrl->nand_version >= 0x0600) ctrl->max_oob = 64; @@ -538,6 +592,15 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) return 0; } +static void brcmnand_flash_dma_revision_init(struct brcmnand_controller *ctrl) +{ + /* flash_dma register offsets */ + if (ctrl->nand_version >= 0x0703) + ctrl->flash_dma_offsets = flash_dma_regs_v4; + else + ctrl->flash_dma_offsets = flash_dma_regs_v1; +} + static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl, enum brcmnand_reg reg) { @@ -580,6 +643,54 @@ static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl, __raw_writel(val, ctrl->nand_fc + word * 4); } +static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl) +{ + + /* Clear error addresses */ + brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0); + brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0); + brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0); + brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0); +} + +static u64 brcmnand_get_uncorrecc_addr(struct brcmnand_controller *ctrl) +{ + u64 err_addr; + + err_addr = brcmnand_read_reg(ctrl, BRCMNAND_UNCORR_ADDR); + err_addr |= ((u64)(brcmnand_read_reg(ctrl, + BRCMNAND_UNCORR_EXT_ADDR) + & 0xffff) << 32); + + return err_addr; +} + +static u64 brcmnand_get_correcc_addr(struct brcmnand_controller *ctrl) +{ + u64 err_addr; + + err_addr = brcmnand_read_reg(ctrl, BRCMNAND_CORR_ADDR); + err_addr |= ((u64)(brcmnand_read_reg(ctrl, + BRCMNAND_CORR_EXT_ADDR) + & 0xffff) << 32); + + return err_addr; +} + +static void brcmnand_set_cmd_addr(struct mtd_info *mtd, u64 addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct brcmnand_host *host = nand_get_controller_data(chip); + struct brcmnand_controller *ctrl = host->ctrl; + + brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, + (host->cs << 16) | ((addr >> 32) & 0xffff)); + (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); + brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, + lower_32_bits(addr)); + (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); +} + static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs, enum brcmnand_cs_reg reg) { @@ -612,7 +723,7 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val) enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD; int cs = host->cs; - if (ctrl->nand_version >= 0x0702) + if (ctrl->nand_version == 0x0702) bits = 7; else if (ctrl->nand_version >= 0x0600) bits = 6; @@ -666,7 +777,7 @@ enum { static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl) { - if (ctrl->nand_version >= 0x0702) + if (ctrl->nand_version == 0x0702) return GENMASK(7, 0); else if (ctrl->nand_version >= 0x0600) return GENMASK(6, 0); @@ -796,39 +907,44 @@ static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en) * Flash DMA ***********************************************************************/ -enum flash_dma_reg { - FLASH_DMA_REVISION = 0x00, - FLASH_DMA_FIRST_DESC = 0x04, - FLASH_DMA_FIRST_DESC_EXT = 0x08, - FLASH_DMA_CTRL = 0x0c, - FLASH_DMA_MODE = 0x10, - FLASH_DMA_STATUS = 0x14, - FLASH_DMA_INTERRUPT_DESC = 0x18, - FLASH_DMA_INTERRUPT_DESC_EXT = 0x1c, - FLASH_DMA_ERROR_STATUS = 0x20, - FLASH_DMA_CURRENT_DESC = 0x24, - FLASH_DMA_CURRENT_DESC_EXT = 0x28, -}; - static inline bool has_flash_dma(struct brcmnand_controller *ctrl) { return ctrl->flash_dma_base; } +static inline void disable_ctrl_irqs(struct brcmnand_controller *ctrl) +{ + if (ctrl->pio_poll_mode) + return; + + if (has_flash_dma(ctrl)) { + ctrl->flash_dma_base = 0; + disable_irq(ctrl->dma_irq); + } + + disable_irq(ctrl->irq); + ctrl->pio_poll_mode = true; +} + static inline bool flash_dma_buf_ok(const void *buf) { return buf && !is_vmalloc_addr(buf) && likely(IS_ALIGNED((uintptr_t)buf, 4)); } -static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs, - u32 val) +static inline void flash_dma_writel(struct brcmnand_controller *ctrl, + enum flash_dma_reg dma_reg, u32 val) { + u16 offs = ctrl->flash_dma_offsets[dma_reg]; + brcmnand_writel(val, ctrl->flash_dma_base + offs); } -static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs) +static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, + enum flash_dma_reg dma_reg) { + u16 offs = ctrl->flash_dma_offsets[dma_reg]; + return brcmnand_readl(ctrl->flash_dma_base + offs); } @@ -931,7 +1047,7 @@ static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section, if (section >= sectors) return -ERANGE; - oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes; + oobregion->offset = ((section + 1) * sas) - chip->ecc.bytes; oobregion->length = chip->ecc.bytes; return 0; @@ -1205,9 +1321,12 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) { struct brcmnand_controller *ctrl = host->ctrl; int ret; + u64 cmd_addr; + + cmd_addr = brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + + dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr); - dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd, - brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS)); BUG_ON(ctrl->cmd_pending != 0); ctrl->cmd_pending = cmd; @@ -1229,15 +1348,42 @@ static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat, /* intentionally left blank */ } +static bool brcmstb_nand_wait_for_completion(struct nand_chip *chip) +{ + struct brcmnand_host *host = nand_get_controller_data(chip); + struct brcmnand_controller *ctrl = host->ctrl; + struct mtd_info *mtd = nand_to_mtd(chip); + bool err = false; + int sts; + + if (mtd->oops_panic_write) { + /* switch to interrupt polling and PIO mode */ + disable_ctrl_irqs(ctrl); + sts = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, + NAND_CTRL_RDY, 0); + err = (sts < 0) ? true : false; + } else { + unsigned long timeo = msecs_to_jiffies( + NAND_POLL_STATUS_TIMEOUT_MS); + /* wait for completion interrupt */ + sts = wait_for_completion_timeout(&ctrl->done, timeo); + err = (sts <= 0) ? true : false; + } + + return err; +} + static int brcmnand_waitfunc(struct nand_chip *chip) { struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_controller *ctrl = host->ctrl; - unsigned long timeo = msecs_to_jiffies(100); + bool err = false; dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending); - if (ctrl->cmd_pending && - wait_for_completion_timeout(&ctrl->done, timeo) <= 0) { + if (ctrl->cmd_pending) + err = brcmstb_nand_wait_for_completion(chip); + + if (err) { u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START) >> brcmnand_cmd_shift(ctrl); @@ -1366,12 +1512,7 @@ static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command, if (!native_cmd) return; - brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, - (host->cs << 16) | ((addr >> 32) & 0xffff)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); - brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); - + brcmnand_set_cmd_addr(mtd, addr); brcmnand_send_cmd(host, native_cmd); brcmnand_waitfunc(chip); @@ -1589,20 +1730,10 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, struct brcmnand_controller *ctrl = host->ctrl; int i, j, ret = 0; - /* Clear error addresses */ - brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0); - brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0); - brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0); - brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0); - - brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, - (host->cs << 16) | ((addr >> 32) & 0xffff)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); + brcmnand_clear_ecc_addr(ctrl); for (i = 0; i < trans; i++, addr += FC_BYTES) { - brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, - lower_32_bits(addr)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + brcmnand_set_cmd_addr(mtd, addr); /* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */ brcmnand_send_cmd(host, CMD_PAGE_READ); brcmnand_waitfunc(chip); @@ -1622,21 +1753,15 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, host->hwcfg.sector_size_1k); if (!ret) { - *err_addr = brcmnand_read_reg(ctrl, - BRCMNAND_UNCORR_ADDR) | - ((u64)(brcmnand_read_reg(ctrl, - BRCMNAND_UNCORR_EXT_ADDR) - & 0xffff) << 32); + *err_addr = brcmnand_get_uncorrecc_addr(ctrl); + if (*err_addr) ret = -EBADMSG; } if (!ret) { - *err_addr = brcmnand_read_reg(ctrl, - BRCMNAND_CORR_ADDR) | - ((u64)(brcmnand_read_reg(ctrl, - BRCMNAND_CORR_EXT_ADDR) - & 0xffff) << 32); + *err_addr = brcmnand_get_correcc_addr(ctrl); + if (*err_addr) ret = -EUCLEAN; } @@ -1703,7 +1828,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf); try_dmaread: - brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0); + brcmnand_clear_ecc_addr(ctrl); if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) { err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES, @@ -1850,15 +1975,9 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, goto out; } - brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, - (host->cs << 16) | ((addr >> 32) & 0xffff)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); - for (i = 0; i < trans; i++, addr += FC_BYTES) { /* full address MUST be set before populating FC */ - brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, - lower_32_bits(addr)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + brcmnand_set_cmd_addr(mtd, addr); if (buf) { brcmnand_soc_data_bus_prepare(ctrl->soc, false); @@ -2136,6 +2255,17 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) return -EINVAL; } + if (chip->ecc.mode != NAND_ECC_NONE && + (!chip->ecc.size || !chip->ecc.strength)) { + if (chip->base.eccreq.step_size && chip->base.eccreq.strength) { + /* use detected ECC parameters */ + chip->ecc.size = chip->base.eccreq.step_size; + chip->ecc.strength = chip->base.eccreq.strength; + dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n", + chip->ecc.size, chip->ecc.strength); + } + } + switch (chip->ecc.size) { case 512: if (chip->ecc.algo == NAND_ECC_HAMMING) @@ -2395,6 +2525,7 @@ static const struct of_device_id brcmnand_of_match[] = { { .compatible = "brcm,brcmnand-v7.0" }, { .compatible = "brcm,brcmnand-v7.1" }, { .compatible = "brcm,brcmnand-v7.2" }, + { .compatible = "brcm,brcmnand-v7.3" }, {}, }; MODULE_DEVICE_TABLE(of, brcmnand_of_match); @@ -2481,7 +2612,11 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) goto err; } - flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */ + /* initialize the dma version */ + brcmnand_flash_dma_revision_init(ctrl); + + /* linked-list and stop on error */ + flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK); flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0); /* Allocate descriptor(s) */ diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 6c7ca41354be..a6964feeec77 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -613,28 +613,20 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, for (op_id = 0; op_id < op->ninstrs; op_id++) { instr = &op->instrs[op_id]; + nand_op_trace(" ", instr); + switch (instr->type) { case NAND_OP_CMD_INSTR: - pr_debug(" ->CMD [0x%02x]\n", - instr->ctx.cmd.opcode); - writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va); break; case NAND_OP_ADDR_INSTR: - pr_debug(" ->ADDR [%d cyc]", - instr->ctx.addr.naddrs); - for (i = 0; i < instr->ctx.addr.naddrs; i++) writeb_relaxed(instr->ctx.addr.addrs[i], host->addr_va); break; case NAND_OP_DATA_IN_INSTR: - pr_debug(" ->DATA_IN [%d B%s]\n", instr->ctx.data.len, - instr->ctx.data.force_8bit ? - ", force 8-bit" : ""); - if (host->mode == USE_DMA_ACCESS) fsmc_read_buf_dma(host, instr->ctx.data.buf.in, instr->ctx.data.len); @@ -644,10 +636,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, break; case NAND_OP_DATA_OUT_INSTR: - pr_debug(" ->DATA_OUT [%d B%s]\n", instr->ctx.data.len, - instr->ctx.data.force_8bit ? - ", force 8-bit" : ""); - if (host->mode == USE_DMA_ACCESS) fsmc_write_buf_dma(host, instr->ctx.data.buf.out, @@ -658,9 +646,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, break; case NAND_OP_WAITRDY_INSTR: - pr_debug(" ->WAITRDY [max %d ms]\n", - instr->ctx.waitrdy.timeout_ms); - ret = nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms); break; diff --git a/drivers/mtd/nand/raw/gpmi-nand/Makefile b/drivers/mtd/nand/raw/gpmi-nand/Makefile index 30ceee9704d1..9bd81a31e02e 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/Makefile +++ b/drivers/mtd/nand/raw/gpmi-nand/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o gpmi_nand-objs += gpmi-nand.o -gpmi_nand-objs += gpmi-lib.o diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c deleted file mode 100644 index a8b26d2e793c..000000000000 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c +++ /dev/null @@ -1,934 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Freescale GPMI NAND Flash Driver - * - * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. - * Copyright (C) 2008 Embedded Alley Solutions, Inc. - */ -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/slab.h> - -#include "gpmi-nand.h" -#include "gpmi-regs.h" -#include "bch-regs.h" - -/* Converts time to clock cycles */ -#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period) - -#define MXS_SET_ADDR 0x4 -#define MXS_CLR_ADDR 0x8 -/* - * Clear the bit and poll it cleared. This is usually called with - * a reset address and mask being either SFTRST(bit 31) or CLKGATE - * (bit 30). - */ -static int clear_poll_bit(void __iomem *addr, u32 mask) -{ - int timeout = 0x400; - - /* clear the bit */ - writel(mask, addr + MXS_CLR_ADDR); - - /* - * SFTRST needs 3 GPMI clocks to settle, the reference manual - * recommends to wait 1us. - */ - udelay(1); - - /* poll the bit becoming clear */ - while ((readl(addr) & mask) && --timeout) - /* nothing */; - - return !timeout; -} - -#define MODULE_CLKGATE (1 << 30) -#define MODULE_SFTRST (1 << 31) -/* - * The current mxs_reset_block() will do two things: - * [1] enable the module. - * [2] reset the module. - * - * In most of the cases, it's ok. - * But in MX23, there is a hardware bug in the BCH block (see erratum #2847). - * If you try to soft reset the BCH block, it becomes unusable until - * the next hard reset. This case occurs in the NAND boot mode. When the board - * boots by NAND, the ROM of the chip will initialize the BCH blocks itself. - * So If the driver tries to reset the BCH again, the BCH will not work anymore. - * You will see a DMA timeout in this case. The bug has been fixed - * in the following chips, such as MX28. - * - * To avoid this bug, just add a new parameter `just_enable` for - * the mxs_reset_block(), and rewrite it here. - */ -static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) -{ - int ret; - int timeout = 0x400; - - /* clear and poll SFTRST */ - ret = clear_poll_bit(reset_addr, MODULE_SFTRST); - if (unlikely(ret)) - goto error; - - /* clear CLKGATE */ - writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); - - if (!just_enable) { - /* set SFTRST to reset the block */ - writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR); - udelay(1); - - /* poll CLKGATE becoming set */ - while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout) - /* nothing */; - if (unlikely(!timeout)) - goto error; - } - - /* clear and poll SFTRST */ - ret = clear_poll_bit(reset_addr, MODULE_SFTRST); - if (unlikely(ret)) - goto error; - - /* clear and poll CLKGATE */ - ret = clear_poll_bit(reset_addr, MODULE_CLKGATE); - if (unlikely(ret)) - goto error; - - return 0; - -error: - pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); - return -ETIMEDOUT; -} - -static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v) -{ - struct clk *clk; - int ret; - int i; - - for (i = 0; i < GPMI_CLK_MAX; i++) { - clk = this->resources.clock[i]; - if (!clk) - break; - - if (v) { - ret = clk_prepare_enable(clk); - if (ret) - goto err_clk; - } else { - clk_disable_unprepare(clk); - } - } - return 0; - -err_clk: - for (; i > 0; i--) - clk_disable_unprepare(this->resources.clock[i - 1]); - return ret; -} - -int gpmi_enable_clk(struct gpmi_nand_data *this) -{ - return __gpmi_enable_clk(this, true); -} - -int gpmi_disable_clk(struct gpmi_nand_data *this) -{ - return __gpmi_enable_clk(this, false); -} - -int gpmi_init(struct gpmi_nand_data *this) -{ - struct resources *r = &this->resources; - int ret; - - ret = gpmi_enable_clk(this); - if (ret) - return ret; - ret = gpmi_reset_block(r->gpmi_regs, false); - if (ret) - goto err_out; - - /* - * Reset BCH here, too. We got failures otherwise :( - * See later BCH reset for explanation of MX23 and MX28 handling - */ - ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this)); - if (ret) - goto err_out; - - /* Choose NAND mode. */ - writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); - - /* Set the IRQ polarity. */ - writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY, - r->gpmi_regs + HW_GPMI_CTRL1_SET); - - /* Disable Write-Protection. */ - writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET); - - /* Select BCH ECC. */ - writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); - - /* - * Decouple the chip select from dma channel. We use dma0 for all - * the chips. - */ - writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET); - - gpmi_disable_clk(this); - return 0; -err_out: - gpmi_disable_clk(this); - return ret; -} - -/* This function is very useful. It is called only when the bug occur. */ -void gpmi_dump_info(struct gpmi_nand_data *this) -{ - struct resources *r = &this->resources; - struct bch_geometry *geo = &this->bch_geometry; - u32 reg; - int i; - - dev_err(this->dev, "Show GPMI registers :\n"); - for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { - reg = readl(r->gpmi_regs + i * 0x10); - dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); - } - - /* start to print out the BCH info */ - dev_err(this->dev, "Show BCH registers :\n"); - for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) { - reg = readl(r->bch_regs + i * 0x10); - dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); - } - dev_err(this->dev, "BCH Geometry :\n" - "GF length : %u\n" - "ECC Strength : %u\n" - "Page Size in Bytes : %u\n" - "Metadata Size in Bytes : %u\n" - "ECC Chunk Size in Bytes: %u\n" - "ECC Chunk Count : %u\n" - "Payload Size in Bytes : %u\n" - "Auxiliary Size in Bytes: %u\n" - "Auxiliary Status Offset: %u\n" - "Block Mark Byte Offset : %u\n" - "Block Mark Bit Offset : %u\n", - geo->gf_len, - geo->ecc_strength, - geo->page_size, - geo->metadata_size, - geo->ecc_chunk_size, - geo->ecc_chunk_count, - geo->payload_size, - geo->auxiliary_size, - geo->auxiliary_status_offset, - geo->block_mark_byte_offset, - geo->block_mark_bit_offset); -} - -/* Configures the geometry for BCH. */ -int bch_set_geometry(struct gpmi_nand_data *this) -{ - struct resources *r = &this->resources; - struct bch_geometry *bch_geo = &this->bch_geometry; - unsigned int block_count; - unsigned int block_size; - unsigned int metadata_size; - unsigned int ecc_strength; - unsigned int page_size; - unsigned int gf_len; - int ret; - - ret = common_nfc_set_geometry(this); - if (ret) - return ret; - - block_count = bch_geo->ecc_chunk_count - 1; - block_size = bch_geo->ecc_chunk_size; - metadata_size = bch_geo->metadata_size; - ecc_strength = bch_geo->ecc_strength >> 1; - page_size = bch_geo->page_size; - gf_len = bch_geo->gf_len; - - ret = gpmi_enable_clk(this); - if (ret) - return ret; - - /* - * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this - * chip, otherwise it will lock up. So we skip resetting BCH on the MX23. - * and MX28. - */ - ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this)); - if (ret) - goto err_out; - - /* Configure layout 0. */ - writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) - | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) - | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) - | BF_BCH_FLASH0LAYOUT0_GF(gf_len, this) - | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this), - r->bch_regs + HW_BCH_FLASH0LAYOUT0); - - writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) - | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) - | BF_BCH_FLASH0LAYOUT1_GF(gf_len, this) - | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this), - r->bch_regs + HW_BCH_FLASH0LAYOUT1); - - /* Set *all* chip selects to use layout 0. */ - writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT); - - /* Enable interrupts. */ - writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, - r->bch_regs + HW_BCH_CTRL_SET); - - gpmi_disable_clk(this); - return 0; -err_out: - gpmi_disable_clk(this); - return ret; -} - -/* - * <1> Firstly, we should know what's the GPMI-clock means. - * The GPMI-clock is the internal clock in the gpmi nand controller. - * If you set 100MHz to gpmi nand controller, the GPMI-clock's period - * is 10ns. Mark the GPMI-clock's period as GPMI-clock-period. - * - * <2> Secondly, we should know what's the frequency on the nand chip pins. - * The frequency on the nand chip pins is derived from the GPMI-clock. - * We can get it from the following equation: - * - * F = G / (DS + DH) - * - * F : the frequency on the nand chip pins. - * G : the GPMI clock, such as 100MHz. - * DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP - * DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD - * - * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz, - * the nand EDO(extended Data Out) timing could be applied. - * The GPMI implements a feedback read strobe to sample the read data. - * The feedback read strobe can be delayed to support the nand EDO timing - * where the read strobe may deasserts before the read data is valid, and - * read data is valid for some time after read strobe. - * - * The following figure illustrates some aspects of a NAND Flash read: - * - * |<---tREA---->| - * | | - * | | | - * |<--tRP-->| | - * | | | - * __ ___|__________________________________ - * RDN \________/ | - * | - * /---------\ - * Read Data --------------< >--------- - * \---------/ - * | | - * |<-D->| - * FeedbackRDN ________ ____________ - * \___________/ - * - * D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY. - * - * - * <4> Now, we begin to describe how to compute the right RDN_DELAY. - * - * 4.1) From the aspect of the nand chip pins: - * Delay = (tREA + C - tRP) {1} - * - * tREA : the maximum read access time. - * C : a constant to adjust the delay. default is 4000ps. - * tRP : the read pulse width, which is exactly: - * tRP = (GPMI-clock-period) * DATA_SETUP - * - * 4.2) From the aspect of the GPMI nand controller: - * Delay = RDN_DELAY * 0.125 * RP {2} - * - * RP : the DLL reference period. - * if (GPMI-clock-period > DLL_THRETHOLD) - * RP = GPMI-clock-period / 2; - * else - * RP = GPMI-clock-period; - * - * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period - * is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD - * is 16000ps, but in mx6q, we use 12000ps. - * - * 4.3) since {1} equals {2}, we get: - * - * (tREA + 4000 - tRP) * 8 - * RDN_DELAY = ----------------------- {3} - * RP - */ -static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, - const struct nand_sdr_timings *sdr) -{ - struct gpmi_nfc_hardware_timing *hw = &this->hw; - unsigned int dll_threshold_ps = this->devdata->max_chain_delay; - unsigned int period_ps, reference_period_ps; - unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles; - unsigned int tRP_ps; - bool use_half_period; - int sample_delay_ps, sample_delay_factor; - u16 busy_timeout_cycles; - u8 wrn_dly_sel; - - if (sdr->tRC_min >= 30000) { - /* ONFI non-EDO modes [0-3] */ - hw->clk_rate = 22000000; - wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS; - } else if (sdr->tRC_min >= 25000) { - /* ONFI EDO mode 4 */ - hw->clk_rate = 80000000; - wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; - } else { - /* ONFI EDO mode 5 */ - hw->clk_rate = 100000000; - wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; - } - - /* SDR core timings are given in picoseconds */ - period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate); - - addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps); - data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps); - data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps); - busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps); - - hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) | - BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) | - BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles); - hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096); - - /* - * Derive NFC ideal delay from {3}: - * - * (tREA + 4000 - tRP) * 8 - * RDN_DELAY = ----------------------- - * RP - */ - if (period_ps > dll_threshold_ps) { - use_half_period = true; - reference_period_ps = period_ps / 2; - } else { - use_half_period = false; - reference_period_ps = period_ps; - } - - tRP_ps = data_setup_cycles * period_ps; - sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8; - if (sample_delay_ps > 0) - sample_delay_factor = sample_delay_ps / reference_period_ps; - else - sample_delay_factor = 0; - - hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel); - if (sample_delay_factor) - hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) | - BM_GPMI_CTRL1_DLL_ENABLE | - (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0); -} - -void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) -{ - struct gpmi_nfc_hardware_timing *hw = &this->hw; - struct resources *r = &this->resources; - void __iomem *gpmi_regs = r->gpmi_regs; - unsigned int dll_wait_time_us; - - clk_set_rate(r->clock[0], hw->clk_rate); - - writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0); - writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1); - - /* - * Clear several CTRL1 fields, DLL must be disabled when setting - * RDN_DELAY or HALF_PERIOD. - */ - writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR); - writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET); - - /* Wait 64 clock cycles before using the GPMI after enabling the DLL */ - dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64; - if (!dll_wait_time_us) - dll_wait_time_us = 1; - - /* Wait for the DLL to settle. */ - udelay(dll_wait_time_us); -} - -int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr, - const struct nand_data_interface *conf) -{ - struct gpmi_nand_data *this = nand_get_controller_data(chip); - const struct nand_sdr_timings *sdr; - - /* Retrieve required NAND timings */ - sdr = nand_get_sdr_timings(conf); - if (IS_ERR(sdr)) - return PTR_ERR(sdr); - - /* Only MX6 GPMI controller can reach EDO timings */ - if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this)) - return -ENOTSUPP; - - /* Stop here if this call was just a check */ - if (chipnr < 0) - return 0; - - /* Do the actual derivation of the controller timings */ - gpmi_nfc_compute_timings(this, sdr); - - this->hw.must_apply_timings = true; - - return 0; -} - -/* Clears a BCH interrupt. */ -void gpmi_clear_bch(struct gpmi_nand_data *this) -{ - struct resources *r = &this->resources; - writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR); -} - -/* Returns the Ready/Busy status of the given chip. */ -int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) -{ - struct resources *r = &this->resources; - uint32_t mask = 0; - uint32_t reg = 0; - - if (GPMI_IS_MX23(this)) { - mask = MX23_BM_GPMI_DEBUG_READY0 << chip; - reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); - } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) { - /* - * In the imx6, all the ready/busy pins are bound - * together. So we only need to check chip 0. - */ - if (GPMI_IS_MX6(this)) - chip = 0; - - /* MX28 shares the same R/B register as MX6Q. */ - mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); - reg = readl(r->gpmi_regs + HW_GPMI_STAT); - } else - dev_err(this->dev, "unknown arch.\n"); - return reg & mask; -} - -int gpmi_send_command(struct gpmi_nand_data *this) -{ - struct dma_chan *channel = get_dma_chan(this); - struct dma_async_tx_descriptor *desc; - struct scatterlist *sgl; - int chip = this->current_chip; - int ret; - u32 pio[3]; - - /* [1] send out the PIO words */ - pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) - | BM_GPMI_CTRL0_WORD_LENGTH - | BF_GPMI_CTRL0_CS(chip, this) - | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) - | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) - | BM_GPMI_CTRL0_ADDRESS_INCREMENT - | BF_GPMI_CTRL0_XFER_COUNT(this->command_length); - pio[1] = pio[2] = 0; - desc = dmaengine_prep_slave_sg(channel, - (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) - return -EINVAL; - - /* [2] send out the COMMAND + ADDRESS string stored in @buffer */ - sgl = &this->cmd_sgl; - - sg_init_one(sgl, this->cmd_buffer, this->command_length); - dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); - desc = dmaengine_prep_slave_sg(channel, - sgl, 1, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EINVAL; - - /* [3] submit the DMA */ - ret = start_dma_without_bch_irq(this, desc); - - dma_unmap_sg(this->dev, sgl, 1, DMA_TO_DEVICE); - - return ret; -} - -int gpmi_send_data(struct gpmi_nand_data *this, const void *buf, int len) -{ - struct dma_async_tx_descriptor *desc; - struct dma_chan *channel = get_dma_chan(this); - int chip = this->current_chip; - int ret; - uint32_t command_mode; - uint32_t address; - u32 pio[2]; - - /* [1] PIO */ - command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; - address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; - - pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) - | BM_GPMI_CTRL0_WORD_LENGTH - | BF_GPMI_CTRL0_CS(chip, this) - | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) - | BF_GPMI_CTRL0_ADDRESS(address) - | BF_GPMI_CTRL0_XFER_COUNT(len); - pio[1] = 0; - desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) - return -EINVAL; - - /* [2] send DMA request */ - prepare_data_dma(this, buf, len, DMA_TO_DEVICE); - desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, - 1, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EINVAL; - - /* [3] submit the DMA */ - ret = start_dma_without_bch_irq(this, desc); - - dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE); - - return ret; -} - -int gpmi_read_data(struct gpmi_nand_data *this, void *buf, int len) -{ - struct dma_async_tx_descriptor *desc; - struct dma_chan *channel = get_dma_chan(this); - int chip = this->current_chip; - int ret; - u32 pio[2]; - bool direct; - - /* [1] : send PIO */ - pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) - | BM_GPMI_CTRL0_WORD_LENGTH - | BF_GPMI_CTRL0_CS(chip, this) - | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) - | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) - | BF_GPMI_CTRL0_XFER_COUNT(len); - pio[1] = 0; - desc = dmaengine_prep_slave_sg(channel, - (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) - return -EINVAL; - - /* [2] : send DMA request */ - direct = prepare_data_dma(this, buf, len, DMA_FROM_DEVICE); - desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, - 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EINVAL; - - /* [3] : submit the DMA */ - - ret = start_dma_without_bch_irq(this, desc); - - dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE); - if (!direct) - memcpy(buf, this->data_buffer_dma, len); - - return ret; -} - -int gpmi_send_page(struct gpmi_nand_data *this, - dma_addr_t payload, dma_addr_t auxiliary) -{ - struct bch_geometry *geo = &this->bch_geometry; - uint32_t command_mode; - uint32_t address; - uint32_t ecc_command; - uint32_t buffer_mask; - struct dma_async_tx_descriptor *desc; - struct dma_chan *channel = get_dma_chan(this); - int chip = this->current_chip; - u32 pio[6]; - - /* A DMA descriptor that does an ECC page read. */ - command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; - address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; - ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE; - buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE | - BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; - - pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) - | BM_GPMI_CTRL0_WORD_LENGTH - | BF_GPMI_CTRL0_CS(chip, this) - | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) - | BF_GPMI_CTRL0_ADDRESS(address) - | BF_GPMI_CTRL0_XFER_COUNT(0); - pio[1] = 0; - pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC - | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) - | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); - pio[3] = geo->page_size; - pio[4] = payload; - pio[5] = auxiliary; - - desc = dmaengine_prep_slave_sg(channel, - (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_TRANS_NONE, - DMA_CTRL_ACK); - if (!desc) - return -EINVAL; - - return start_dma_with_bch_irq(this, desc); -} - -int gpmi_read_page(struct gpmi_nand_data *this, - dma_addr_t payload, dma_addr_t auxiliary) -{ - struct bch_geometry *geo = &this->bch_geometry; - uint32_t command_mode; - uint32_t address; - uint32_t ecc_command; - uint32_t buffer_mask; - struct dma_async_tx_descriptor *desc; - struct dma_chan *channel = get_dma_chan(this); - int chip = this->current_chip; - u32 pio[6]; - - /* [1] Wait for the chip to report ready. */ - command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; - address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; - - pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) - | BM_GPMI_CTRL0_WORD_LENGTH - | BF_GPMI_CTRL0_CS(chip, this) - | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) - | BF_GPMI_CTRL0_ADDRESS(address) - | BF_GPMI_CTRL0_XFER_COUNT(0); - pio[1] = 0; - desc = dmaengine_prep_slave_sg(channel, - (struct scatterlist *)pio, 2, - DMA_TRANS_NONE, 0); - if (!desc) - return -EINVAL; - - /* [2] Enable the BCH block and read. */ - command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ; - address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; - ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE; - buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE - | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; - - pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) - | BM_GPMI_CTRL0_WORD_LENGTH - | BF_GPMI_CTRL0_CS(chip, this) - | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) - | BF_GPMI_CTRL0_ADDRESS(address) - | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); - - pio[1] = 0; - pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC - | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) - | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); - pio[3] = geo->page_size; - pio[4] = payload; - pio[5] = auxiliary; - desc = dmaengine_prep_slave_sg(channel, - (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_TRANS_NONE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EINVAL; - - /* [3] Disable the BCH block */ - command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; - address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; - - pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) - | BM_GPMI_CTRL0_WORD_LENGTH - | BF_GPMI_CTRL0_CS(chip, this) - | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) - | BF_GPMI_CTRL0_ADDRESS(address) - | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); - pio[1] = 0; - pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */ - desc = dmaengine_prep_slave_sg(channel, - (struct scatterlist *)pio, 3, - DMA_TRANS_NONE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EINVAL; - - /* [4] submit the DMA */ - return start_dma_with_bch_irq(this, desc); -} - -/** - * gpmi_copy_bits - copy bits from one memory region to another - * @dst: destination buffer - * @dst_bit_off: bit offset we're starting to write at - * @src: source buffer - * @src_bit_off: bit offset we're starting to read from - * @nbits: number of bits to copy - * - * This functions copies bits from one memory region to another, and is used by - * the GPMI driver to copy ECC sections which are not guaranteed to be byte - * aligned. - * - * src and dst should not overlap. - * - */ -void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, - const u8 *src, size_t src_bit_off, - size_t nbits) -{ - size_t i; - size_t nbytes; - u32 src_buffer = 0; - size_t bits_in_src_buffer = 0; - - if (!nbits) - return; - - /* - * Move src and dst pointers to the closest byte pointer and store bit - * offsets within a byte. - */ - src += src_bit_off / 8; - src_bit_off %= 8; - - dst += dst_bit_off / 8; - dst_bit_off %= 8; - - /* - * Initialize the src_buffer value with bits available in the first - * byte of data so that we end up with a byte aligned src pointer. - */ - if (src_bit_off) { - src_buffer = src[0] >> src_bit_off; - if (nbits >= (8 - src_bit_off)) { - bits_in_src_buffer += 8 - src_bit_off; - } else { - src_buffer &= GENMASK(nbits - 1, 0); - bits_in_src_buffer += nbits; - } - nbits -= bits_in_src_buffer; - src++; - } - - /* Calculate the number of bytes that can be copied from src to dst. */ - nbytes = nbits / 8; - - /* Try to align dst to a byte boundary. */ - if (dst_bit_off) { - if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) { - src_buffer |= src[0] << bits_in_src_buffer; - bits_in_src_buffer += 8; - src++; - nbytes--; - } - - if (bits_in_src_buffer >= (8 - dst_bit_off)) { - dst[0] &= GENMASK(dst_bit_off - 1, 0); - dst[0] |= src_buffer << dst_bit_off; - src_buffer >>= (8 - dst_bit_off); - bits_in_src_buffer -= (8 - dst_bit_off); - dst_bit_off = 0; - dst++; - if (bits_in_src_buffer > 7) { - bits_in_src_buffer -= 8; - dst[0] = src_buffer; - dst++; - src_buffer >>= 8; - } - } - } - - if (!bits_in_src_buffer && !dst_bit_off) { - /* - * Both src and dst pointers are byte aligned, thus we can - * just use the optimized memcpy function. - */ - if (nbytes) - memcpy(dst, src, nbytes); - } else { - /* - * src buffer is not byte aligned, hence we have to copy each - * src byte to the src_buffer variable before extracting a byte - * to store in dst. - */ - for (i = 0; i < nbytes; i++) { - src_buffer |= src[i] << bits_in_src_buffer; - dst[i] = src_buffer; - src_buffer >>= 8; - } - } - /* Update dst and src pointers */ - dst += nbytes; - src += nbytes; - - /* - * nbits is the number of remaining bits. It should not exceed 8 as - * we've already copied as much bytes as possible. - */ - nbits %= 8; - - /* - * If there's no more bits to copy to the destination and src buffer - * was already byte aligned, then we're done. - */ - if (!nbits && !bits_in_src_buffer) - return; - - /* Copy the remaining bits to src_buffer */ - if (nbits) - src_buffer |= (*src & GENMASK(nbits - 1, 0)) << - bits_in_src_buffer; - bits_in_src_buffer += nbits; - - /* - * In case there were not enough bits to get a byte aligned dst buffer - * prepare the src_buffer variable to match the dst organization (shift - * src_buffer by dst_bit_off and retrieve the least significant bits - * from dst). - */ - if (dst_bit_off) - src_buffer = (src_buffer << dst_bit_off) | - (*dst & GENMASK(dst_bit_off - 1, 0)); - bits_in_src_buffer += dst_bit_off; - - /* - * Keep most significant bits from dst if we end up with an unaligned - * number of bits. - */ - nbytes = bits_in_src_buffer / 8; - if (bits_in_src_buffer % 8) { - src_buffer |= (dst[nbytes] & - GENMASK(7, bits_in_src_buffer % 8)) << - (nbytes * 8); - nbytes++; - } - - /* Copy the remaining bytes to dst */ - for (i = 0; i < nbytes; i++) { - dst[i] = src_buffer; - src_buffer >>= 8; - } -} diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 40df20d1adf5..334fe3130285 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -6,6 +6,7 @@ * Copyright (C) 2008 Embedded Alley Solutions, Inc. */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/slab.h> #include <linux/sched/task_stack.h> #include <linux/interrupt.h> @@ -13,7 +14,10 @@ #include <linux/mtd/partitions.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/dma/mxs-dma.h> #include "gpmi-nand.h" +#include "gpmi-regs.h" #include "bch-regs.h" /* Resource names for the GPMI NAND driver. */ @@ -21,149 +25,208 @@ #define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch" #define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch" -/* add our owner bbt descriptor */ -static uint8_t scan_ff_pattern[] = { 0xff }; -static struct nand_bbt_descr gpmi_bbt_descr = { - .options = 0, - .offs = 0, - .len = 1, - .pattern = scan_ff_pattern -}; +/* Converts time to clock cycles */ +#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period) +#define MXS_SET_ADDR 0x4 +#define MXS_CLR_ADDR 0x8 /* - * We may change the layout if we can get the ECC info from the datasheet, - * else we will use all the (page + OOB). + * Clear the bit and poll it cleared. This is usually called with + * a reset address and mask being either SFTRST(bit 31) or CLKGATE + * (bit 30). */ -static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) +static int clear_poll_bit(void __iomem *addr, u32 mask) { - struct nand_chip *chip = mtd_to_nand(mtd); - struct gpmi_nand_data *this = nand_get_controller_data(chip); - struct bch_geometry *geo = &this->bch_geometry; + int timeout = 0x400; - if (section) - return -ERANGE; + /* clear the bit */ + writel(mask, addr + MXS_CLR_ADDR); - oobregion->offset = 0; - oobregion->length = geo->page_size - mtd->writesize; + /* + * SFTRST needs 3 GPMI clocks to settle, the reference manual + * recommends to wait 1us. + */ + udelay(1); - return 0; + /* poll the bit becoming clear */ + while ((readl(addr) & mask) && --timeout) + /* nothing */; + + return !timeout; } -static int gpmi_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) +#define MODULE_CLKGATE (1 << 30) +#define MODULE_SFTRST (1 << 31) +/* + * The current mxs_reset_block() will do two things: + * [1] enable the module. + * [2] reset the module. + * + * In most of the cases, it's ok. + * But in MX23, there is a hardware bug in the BCH block (see erratum #2847). + * If you try to soft reset the BCH block, it becomes unusable until + * the next hard reset. This case occurs in the NAND boot mode. When the board + * boots by NAND, the ROM of the chip will initialize the BCH blocks itself. + * So If the driver tries to reset the BCH again, the BCH will not work anymore. + * You will see a DMA timeout in this case. The bug has been fixed + * in the following chips, such as MX28. + * + * To avoid this bug, just add a new parameter `just_enable` for + * the mxs_reset_block(), and rewrite it here. + */ +static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) { - struct nand_chip *chip = mtd_to_nand(mtd); - struct gpmi_nand_data *this = nand_get_controller_data(chip); - struct bch_geometry *geo = &this->bch_geometry; + int ret; + int timeout = 0x400; + + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; + + /* clear CLKGATE */ + writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); + + if (!just_enable) { + /* set SFTRST to reset the block */ + writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR); + udelay(1); + + /* poll CLKGATE becoming set */ + while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout) + /* nothing */; + if (unlikely(!timeout)) + goto error; + } - if (section) - return -ERANGE; + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; - /* The available oob size we have. */ - if (geo->page_size < mtd->writesize + mtd->oobsize) { - oobregion->offset = geo->page_size - mtd->writesize; - oobregion->length = mtd->oobsize - oobregion->offset; - } + /* clear and poll CLKGATE */ + ret = clear_poll_bit(reset_addr, MODULE_CLKGATE); + if (unlikely(ret)) + goto error; return 0; + +error: + pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); + return -ETIMEDOUT; } -static const char * const gpmi_clks_for_mx2x[] = { - "gpmi_io", -}; +static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v) +{ + struct clk *clk; + int ret; + int i; -static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = { - .ecc = gpmi_ooblayout_ecc, - .free = gpmi_ooblayout_free, -}; + for (i = 0; i < GPMI_CLK_MAX; i++) { + clk = this->resources.clock[i]; + if (!clk) + break; -static const struct gpmi_devdata gpmi_devdata_imx23 = { - .type = IS_MX23, - .bch_max_ecc_strength = 20, - .max_chain_delay = 16000, - .clks = gpmi_clks_for_mx2x, - .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x), -}; + if (v) { + ret = clk_prepare_enable(clk); + if (ret) + goto err_clk; + } else { + clk_disable_unprepare(clk); + } + } + return 0; -static const struct gpmi_devdata gpmi_devdata_imx28 = { - .type = IS_MX28, - .bch_max_ecc_strength = 20, - .max_chain_delay = 16000, - .clks = gpmi_clks_for_mx2x, - .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x), -}; +err_clk: + for (; i > 0; i--) + clk_disable_unprepare(this->resources.clock[i - 1]); + return ret; +} -static const char * const gpmi_clks_for_mx6[] = { - "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", -}; +static int gpmi_init(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + int ret; -static const struct gpmi_devdata gpmi_devdata_imx6q = { - .type = IS_MX6Q, - .bch_max_ecc_strength = 40, - .max_chain_delay = 12000, - .clks = gpmi_clks_for_mx6, - .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), -}; + ret = gpmi_reset_block(r->gpmi_regs, false); + if (ret) + goto err_out; -static const struct gpmi_devdata gpmi_devdata_imx6sx = { - .type = IS_MX6SX, - .bch_max_ecc_strength = 62, - .max_chain_delay = 12000, - .clks = gpmi_clks_for_mx6, - .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), -}; + /* + * Reset BCH here, too. We got failures otherwise :( + * See later BCH reset for explanation of MX23 and MX28 handling + */ + ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this)); + if (ret) + goto err_out; -static const char * const gpmi_clks_for_mx7d[] = { - "gpmi_io", "gpmi_bch_apb", -}; + /* Choose NAND mode. */ + writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); -static const struct gpmi_devdata gpmi_devdata_imx7d = { - .type = IS_MX7D, - .bch_max_ecc_strength = 62, - .max_chain_delay = 12000, - .clks = gpmi_clks_for_mx7d, - .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d), -}; + /* Set the IRQ polarity. */ + writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY, + r->gpmi_regs + HW_GPMI_CTRL1_SET); -static irqreturn_t bch_irq(int irq, void *cookie) -{ - struct gpmi_nand_data *this = cookie; + /* Disable Write-Protection. */ + writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET); - gpmi_clear_bch(this); - complete(&this->bch_done); - return IRQ_HANDLED; + /* Select BCH ECC. */ + writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + /* + * Decouple the chip select from dma channel. We use dma0 for all + * the chips. + */ + writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + return 0; +err_out: + return ret; } -/* - * Calculate the ECC strength by hand: - * E : The ECC strength. - * G : the length of Galois Field. - * N : The chunk count of per page. - * O : the oobsize of the NAND chip. - * M : the metasize of per page. - * - * The formula is : - * E * G * N - * ------------ <= (O - M) - * 8 - * - * So, we get E by: - * (O - M) * 8 - * E <= ------------- - * G * N - */ -static inline int get_ecc_strength(struct gpmi_nand_data *this) +/* This function is very useful. It is called only when the bug occur. */ +static void gpmi_dump_info(struct gpmi_nand_data *this) { + struct resources *r = &this->resources; struct bch_geometry *geo = &this->bch_geometry; - struct mtd_info *mtd = nand_to_mtd(&this->nand); - int ecc_strength; + u32 reg; + int i; - ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8) - / (geo->gf_len * geo->ecc_chunk_count); + dev_err(this->dev, "Show GPMI registers :\n"); + for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { + reg = readl(r->gpmi_regs + i * 0x10); + dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + } - /* We need the minor even number. */ - return round_down(ecc_strength, 2); + /* start to print out the BCH info */ + dev_err(this->dev, "Show BCH registers :\n"); + for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) { + reg = readl(r->bch_regs + i * 0x10); + dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + } + dev_err(this->dev, "BCH Geometry :\n" + "GF length : %u\n" + "ECC Strength : %u\n" + "Page Size in Bytes : %u\n" + "Metadata Size in Bytes : %u\n" + "ECC Chunk Size in Bytes: %u\n" + "ECC Chunk Count : %u\n" + "Payload Size in Bytes : %u\n" + "Auxiliary Size in Bytes: %u\n" + "Auxiliary Status Offset: %u\n" + "Block Mark Byte Offset : %u\n" + "Block Mark Bit Offset : %u\n", + geo->gf_len, + geo->ecc_strength, + geo->page_size, + geo->metadata_size, + geo->ecc_chunk_size, + geo->ecc_chunk_count, + geo->payload_size, + geo->auxiliary_size, + geo->auxiliary_status_offset, + geo->block_mark_byte_offset, + geo->block_mark_bit_offset); } static inline bool gpmi_check_ecc(struct gpmi_nand_data *this) @@ -296,6 +359,37 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this, return 0; } +/* + * Calculate the ECC strength by hand: + * E : The ECC strength. + * G : the length of Galois Field. + * N : The chunk count of per page. + * O : the oobsize of the NAND chip. + * M : the metasize of per page. + * + * The formula is : + * E * G * N + * ------------ <= (O - M) + * 8 + * + * So, we get E by: + * (O - M) * 8 + * E <= ------------- + * G * N + */ +static inline int get_ecc_strength(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct mtd_info *mtd = nand_to_mtd(&this->nand); + int ecc_strength; + + ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8) + / (geo->gf_len * geo->ecc_chunk_count); + + /* We need the minor even number. */ + return round_down(ecc_strength, 2); +} + static int legacy_set_geometry(struct gpmi_nand_data *this) { struct bch_geometry *geo = &this->bch_geometry; @@ -408,7 +502,7 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) return 0; } -int common_nfc_set_geometry(struct gpmi_nand_data *this) +static int common_nfc_set_geometry(struct gpmi_nand_data *this) { struct nand_chip *chip = &this->nand; @@ -430,18 +524,288 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this) return 0; } -struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) +/* Configures the geometry for BCH. */ +static int bch_set_geometry(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + int ret; + + ret = common_nfc_set_geometry(this); + if (ret) + return ret; + + ret = pm_runtime_get_sync(this->dev); + if (ret < 0) + return ret; + + /* + * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this + * chip, otherwise it will lock up. So we skip resetting BCH on the MX23. + * and MX28. + */ + ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MXS(this)); + if (ret) + goto err_out; + + /* Set *all* chip selects to use layout 0. */ + writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT); + + ret = 0; +err_out: + pm_runtime_mark_last_busy(this->dev); + pm_runtime_put_autosuspend(this->dev); + + return ret; +} + +/* + * <1> Firstly, we should know what's the GPMI-clock means. + * The GPMI-clock is the internal clock in the gpmi nand controller. + * If you set 100MHz to gpmi nand controller, the GPMI-clock's period + * is 10ns. Mark the GPMI-clock's period as GPMI-clock-period. + * + * <2> Secondly, we should know what's the frequency on the nand chip pins. + * The frequency on the nand chip pins is derived from the GPMI-clock. + * We can get it from the following equation: + * + * F = G / (DS + DH) + * + * F : the frequency on the nand chip pins. + * G : the GPMI clock, such as 100MHz. + * DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP + * DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD + * + * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz, + * the nand EDO(extended Data Out) timing could be applied. + * The GPMI implements a feedback read strobe to sample the read data. + * The feedback read strobe can be delayed to support the nand EDO timing + * where the read strobe may deasserts before the read data is valid, and + * read data is valid for some time after read strobe. + * + * The following figure illustrates some aspects of a NAND Flash read: + * + * |<---tREA---->| + * | | + * | | | + * |<--tRP-->| | + * | | | + * __ ___|__________________________________ + * RDN \________/ | + * | + * /---------\ + * Read Data --------------< >--------- + * \---------/ + * | | + * |<-D->| + * FeedbackRDN ________ ____________ + * \___________/ + * + * D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY. + * + * + * <4> Now, we begin to describe how to compute the right RDN_DELAY. + * + * 4.1) From the aspect of the nand chip pins: + * Delay = (tREA + C - tRP) {1} + * + * tREA : the maximum read access time. + * C : a constant to adjust the delay. default is 4000ps. + * tRP : the read pulse width, which is exactly: + * tRP = (GPMI-clock-period) * DATA_SETUP + * + * 4.2) From the aspect of the GPMI nand controller: + * Delay = RDN_DELAY * 0.125 * RP {2} + * + * RP : the DLL reference period. + * if (GPMI-clock-period > DLL_THRETHOLD) + * RP = GPMI-clock-period / 2; + * else + * RP = GPMI-clock-period; + * + * Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period + * is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD + * is 16000ps, but in mx6q, we use 12000ps. + * + * 4.3) since {1} equals {2}, we get: + * + * (tREA + 4000 - tRP) * 8 + * RDN_DELAY = ----------------------- {3} + * RP + */ +static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, + const struct nand_sdr_timings *sdr) +{ + struct gpmi_nfc_hardware_timing *hw = &this->hw; + unsigned int dll_threshold_ps = this->devdata->max_chain_delay; + unsigned int period_ps, reference_period_ps; + unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles; + unsigned int tRP_ps; + bool use_half_period; + int sample_delay_ps, sample_delay_factor; + u16 busy_timeout_cycles; + u8 wrn_dly_sel; + + if (sdr->tRC_min >= 30000) { + /* ONFI non-EDO modes [0-3] */ + hw->clk_rate = 22000000; + wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS; + } else if (sdr->tRC_min >= 25000) { + /* ONFI EDO mode 4 */ + hw->clk_rate = 80000000; + wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; + } else { + /* ONFI EDO mode 5 */ + hw->clk_rate = 100000000; + wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; + } + + /* SDR core timings are given in picoseconds */ + period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate); + + addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps); + data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps); + data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps); + busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps); + + hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles); + hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096); + + /* + * Derive NFC ideal delay from {3}: + * + * (tREA + 4000 - tRP) * 8 + * RDN_DELAY = ----------------------- + * RP + */ + if (period_ps > dll_threshold_ps) { + use_half_period = true; + reference_period_ps = period_ps / 2; + } else { + use_half_period = false; + reference_period_ps = period_ps; + } + + tRP_ps = data_setup_cycles * period_ps; + sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8; + if (sample_delay_ps > 0) + sample_delay_factor = sample_delay_ps / reference_period_ps; + else + sample_delay_factor = 0; + + hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel); + if (sample_delay_factor) + hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) | + BM_GPMI_CTRL1_DLL_ENABLE | + (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0); +} + +static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) +{ + struct gpmi_nfc_hardware_timing *hw = &this->hw; + struct resources *r = &this->resources; + void __iomem *gpmi_regs = r->gpmi_regs; + unsigned int dll_wait_time_us; + + clk_set_rate(r->clock[0], hw->clk_rate); + + writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0); + writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1); + + /* + * Clear several CTRL1 fields, DLL must be disabled when setting + * RDN_DELAY or HALF_PERIOD. + */ + writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR); + writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Wait 64 clock cycles before using the GPMI after enabling the DLL */ + dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64; + if (!dll_wait_time_us) + dll_wait_time_us = 1; + + /* Wait for the DLL to settle. */ + udelay(dll_wait_time_us); +} + +static int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr, + const struct nand_data_interface *conf) +{ + struct gpmi_nand_data *this = nand_get_controller_data(chip); + const struct nand_sdr_timings *sdr; + + /* Retrieve required NAND timings */ + sdr = nand_get_sdr_timings(conf); + if (IS_ERR(sdr)) + return PTR_ERR(sdr); + + /* Only MX6 GPMI controller can reach EDO timings */ + if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this)) + return -ENOTSUPP; + + /* Stop here if this call was just a check */ + if (chipnr < 0) + return 0; + + /* Do the actual derivation of the controller timings */ + gpmi_nfc_compute_timings(this, sdr); + + this->hw.must_apply_timings = true; + + return 0; +} + +/* Clears a BCH interrupt. */ +static void gpmi_clear_bch(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR); +} + +static struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) { /* We use the DMA channel 0 to access all the nand chips. */ return this->dma_chans[0]; } +/* This will be called after the DMA operation is finished. */ +static void dma_irq_callback(void *param) +{ + struct gpmi_nand_data *this = param; + struct completion *dma_c = &this->dma_done; + + complete(dma_c); +} + +static irqreturn_t bch_irq(int irq, void *cookie) +{ + struct gpmi_nand_data *this = cookie; + + gpmi_clear_bch(this); + complete(&this->bch_done); + return IRQ_HANDLED; +} + +static int gpmi_raw_len_to_len(struct gpmi_nand_data *this, int raw_len) +{ + /* + * raw_len is the length to read/write including bch data which + * we are passed in exec_op. Calculate the data length from it. + */ + if (this->bch) + return ALIGN_DOWN(raw_len, this->bch_geometry.ecc_chunk_size); + else + return raw_len; +} + /* Can we use the upper's buffer directly for DMA? */ -bool prepare_data_dma(struct gpmi_nand_data *this, const void *buf, int len, - enum dma_data_direction dr) +static bool prepare_data_dma(struct gpmi_nand_data *this, const void *buf, + int raw_len, struct scatterlist *sgl, + enum dma_data_direction dr) { - struct scatterlist *sgl = &this->data_sgl; int ret; + int len = gpmi_raw_len_to_len(this, raw_len); /* first try to map the upper buffer directly */ if (virt_addr_valid(buf) && !object_is_on_stack(buf)) { @@ -457,7 +821,7 @@ map_fail: /* We have to use our own DMA buffer. */ sg_init_one(sgl, this->data_buffer_dma, len); - if (dr == DMA_TO_DEVICE) + if (dr == DMA_TO_DEVICE && buf != this->data_buffer_dma) memcpy(this->data_buffer_dma, buf, len); dma_map_sg(this->dev, sgl, 1, dr); @@ -465,67 +829,263 @@ map_fail: return false; } -/* This will be called after the DMA operation is finished. */ -static void dma_irq_callback(void *param) +/** + * gpmi_copy_bits - copy bits from one memory region to another + * @dst: destination buffer + * @dst_bit_off: bit offset we're starting to write at + * @src: source buffer + * @src_bit_off: bit offset we're starting to read from + * @nbits: number of bits to copy + * + * This functions copies bits from one memory region to another, and is used by + * the GPMI driver to copy ECC sections which are not guaranteed to be byte + * aligned. + * + * src and dst should not overlap. + * + */ +static void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, const u8 *src, + size_t src_bit_off, size_t nbits) { - struct gpmi_nand_data *this = param; - struct completion *dma_c = &this->dma_done; + size_t i; + size_t nbytes; + u32 src_buffer = 0; + size_t bits_in_src_buffer = 0; - complete(dma_c); -} + if (!nbits) + return; -int start_dma_without_bch_irq(struct gpmi_nand_data *this, - struct dma_async_tx_descriptor *desc) -{ - struct completion *dma_c = &this->dma_done; - unsigned long timeout; + /* + * Move src and dst pointers to the closest byte pointer and store bit + * offsets within a byte. + */ + src += src_bit_off / 8; + src_bit_off %= 8; - init_completion(dma_c); + dst += dst_bit_off / 8; + dst_bit_off %= 8; - desc->callback = dma_irq_callback; - desc->callback_param = this; - dmaengine_submit(desc); - dma_async_issue_pending(get_dma_chan(this)); + /* + * Initialize the src_buffer value with bits available in the first + * byte of data so that we end up with a byte aligned src pointer. + */ + if (src_bit_off) { + src_buffer = src[0] >> src_bit_off; + if (nbits >= (8 - src_bit_off)) { + bits_in_src_buffer += 8 - src_bit_off; + } else { + src_buffer &= GENMASK(nbits - 1, 0); + bits_in_src_buffer += nbits; + } + nbits -= bits_in_src_buffer; + src++; + } - /* Wait for the interrupt from the DMA block. */ - timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); - if (!timeout) { - dev_err(this->dev, "DMA timeout, last DMA\n"); - gpmi_dump_info(this); - return -ETIMEDOUT; + /* Calculate the number of bytes that can be copied from src to dst. */ + nbytes = nbits / 8; + + /* Try to align dst to a byte boundary. */ + if (dst_bit_off) { + if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) { + src_buffer |= src[0] << bits_in_src_buffer; + bits_in_src_buffer += 8; + src++; + nbytes--; + } + + if (bits_in_src_buffer >= (8 - dst_bit_off)) { + dst[0] &= GENMASK(dst_bit_off - 1, 0); + dst[0] |= src_buffer << dst_bit_off; + src_buffer >>= (8 - dst_bit_off); + bits_in_src_buffer -= (8 - dst_bit_off); + dst_bit_off = 0; + dst++; + if (bits_in_src_buffer > 7) { + bits_in_src_buffer -= 8; + dst[0] = src_buffer; + dst++; + src_buffer >>= 8; + } + } + } + + if (!bits_in_src_buffer && !dst_bit_off) { + /* + * Both src and dst pointers are byte aligned, thus we can + * just use the optimized memcpy function. + */ + if (nbytes) + memcpy(dst, src, nbytes); + } else { + /* + * src buffer is not byte aligned, hence we have to copy each + * src byte to the src_buffer variable before extracting a byte + * to store in dst. + */ + for (i = 0; i < nbytes; i++) { + src_buffer |= src[i] << bits_in_src_buffer; + dst[i] = src_buffer; + src_buffer >>= 8; + } + } + /* Update dst and src pointers */ + dst += nbytes; + src += nbytes; + + /* + * nbits is the number of remaining bits. It should not exceed 8 as + * we've already copied as much bytes as possible. + */ + nbits %= 8; + + /* + * If there's no more bits to copy to the destination and src buffer + * was already byte aligned, then we're done. + */ + if (!nbits && !bits_in_src_buffer) + return; + + /* Copy the remaining bits to src_buffer */ + if (nbits) + src_buffer |= (*src & GENMASK(nbits - 1, 0)) << + bits_in_src_buffer; + bits_in_src_buffer += nbits; + + /* + * In case there were not enough bits to get a byte aligned dst buffer + * prepare the src_buffer variable to match the dst organization (shift + * src_buffer by dst_bit_off and retrieve the least significant bits + * from dst). + */ + if (dst_bit_off) + src_buffer = (src_buffer << dst_bit_off) | + (*dst & GENMASK(dst_bit_off - 1, 0)); + bits_in_src_buffer += dst_bit_off; + + /* + * Keep most significant bits from dst if we end up with an unaligned + * number of bits. + */ + nbytes = bits_in_src_buffer / 8; + if (bits_in_src_buffer % 8) { + src_buffer |= (dst[nbytes] & + GENMASK(7, bits_in_src_buffer % 8)) << + (nbytes * 8); + nbytes++; + } + + /* Copy the remaining bytes to dst */ + for (i = 0; i < nbytes; i++) { + dst[i] = src_buffer; + src_buffer >>= 8; } - return 0; } +/* add our owner bbt descriptor */ +static uint8_t scan_ff_pattern[] = { 0xff }; +static struct nand_bbt_descr gpmi_bbt_descr = { + .options = 0, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern +}; + /* - * This function is used in BCH reading or BCH writing pages. - * It will wait for the BCH interrupt as long as ONE second. - * Actually, we must wait for two interrupts : - * [1] firstly the DMA interrupt and - * [2] secondly the BCH interrupt. + * We may change the layout if we can get the ECC info from the datasheet, + * else we will use all the (page + OOB). */ -int start_dma_with_bch_irq(struct gpmi_nand_data *this, - struct dma_async_tx_descriptor *desc) +static int gpmi_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) { - struct completion *bch_c = &this->bch_done; - unsigned long timeout; + struct nand_chip *chip = mtd_to_nand(mtd); + struct gpmi_nand_data *this = nand_get_controller_data(chip); + struct bch_geometry *geo = &this->bch_geometry; - /* Prepare to receive an interrupt from the BCH block. */ - init_completion(bch_c); + if (section) + return -ERANGE; - /* start the DMA */ - start_dma_without_bch_irq(this, desc); + oobregion->offset = 0; + oobregion->length = geo->page_size - mtd->writesize; - /* Wait for the interrupt from the BCH block. */ - timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); - if (!timeout) { - dev_err(this->dev, "BCH timeout\n"); - gpmi_dump_info(this); - return -ETIMEDOUT; + return 0; +} + +static int gpmi_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct gpmi_nand_data *this = nand_get_controller_data(chip); + struct bch_geometry *geo = &this->bch_geometry; + + if (section) + return -ERANGE; + + /* The available oob size we have. */ + if (geo->page_size < mtd->writesize + mtd->oobsize) { + oobregion->offset = geo->page_size - mtd->writesize; + oobregion->length = mtd->oobsize - oobregion->offset; } + return 0; } +static const char * const gpmi_clks_for_mx2x[] = { + "gpmi_io", +}; + +static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = { + .ecc = gpmi_ooblayout_ecc, + .free = gpmi_ooblayout_free, +}; + +static const struct gpmi_devdata gpmi_devdata_imx23 = { + .type = IS_MX23, + .bch_max_ecc_strength = 20, + .max_chain_delay = 16000, + .clks = gpmi_clks_for_mx2x, + .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x), +}; + +static const struct gpmi_devdata gpmi_devdata_imx28 = { + .type = IS_MX28, + .bch_max_ecc_strength = 20, + .max_chain_delay = 16000, + .clks = gpmi_clks_for_mx2x, + .clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x), +}; + +static const char * const gpmi_clks_for_mx6[] = { + "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", +}; + +static const struct gpmi_devdata gpmi_devdata_imx6q = { + .type = IS_MX6Q, + .bch_max_ecc_strength = 40, + .max_chain_delay = 12000, + .clks = gpmi_clks_for_mx6, + .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), +}; + +static const struct gpmi_devdata gpmi_devdata_imx6sx = { + .type = IS_MX6SX, + .bch_max_ecc_strength = 62, + .max_chain_delay = 12000, + .clks = gpmi_clks_for_mx6, + .clks_count = ARRAY_SIZE(gpmi_clks_for_mx6), +}; + +static const char * const gpmi_clks_for_mx7d[] = { + "gpmi_io", "gpmi_bch_apb", +}; + +static const struct gpmi_devdata gpmi_devdata_imx7d = { + .type = IS_MX7D, + .bch_max_ecc_strength = 62, + .max_chain_delay = 12000, + .clks = gpmi_clks_for_mx7d, + .clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d), +}; + static int acquire_register_block(struct gpmi_nand_data *this, const char *res_name) { @@ -667,68 +1227,20 @@ static void release_resources(struct gpmi_nand_data *this) release_dma_channels(this); } -static int send_page_prepare(struct gpmi_nand_data *this, - const void *source, unsigned length, - void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, - const void **use_virt, dma_addr_t *use_phys) -{ - struct device *dev = this->dev; - - if (virt_addr_valid(source)) { - dma_addr_t source_phys; - - source_phys = dma_map_single(dev, (void *)source, length, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, source_phys)) { - if (alt_size < length) { - dev_err(dev, "Alternate buffer is too small\n"); - return -ENOMEM; - } - goto map_failed; - } - *use_virt = source; - *use_phys = source_phys; - return 0; - } -map_failed: - /* - * Copy the content of the source buffer into the alternate - * buffer and set up the return values accordingly. - */ - memcpy(alt_virt, source, length); - - *use_virt = alt_virt; - *use_phys = alt_phys; - return 0; -} - -static void send_page_end(struct gpmi_nand_data *this, - const void *source, unsigned length, - void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, - const void *used_virt, dma_addr_t used_phys) -{ - struct device *dev = this->dev; - if (used_virt == source) - dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE); -} - static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) { struct device *dev = this->dev; + struct bch_geometry *geo = &this->bch_geometry; - if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt)) - dma_free_coherent(dev, this->page_buffer_size, - this->page_buffer_virt, - this->page_buffer_phys); - kfree(this->cmd_buffer); + if (this->auxiliary_virt && virt_addr_valid(this->auxiliary_virt)) + dma_free_coherent(dev, geo->auxiliary_size, + this->auxiliary_virt, + this->auxiliary_phys); kfree(this->data_buffer_dma); kfree(this->raw_buffer); - this->cmd_buffer = NULL; this->data_buffer_dma = NULL; this->raw_buffer = NULL; - this->page_buffer_virt = NULL; - this->page_buffer_size = 0; } /* Allocate the DMA buffers */ @@ -738,11 +1250,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) struct device *dev = this->dev; struct mtd_info *mtd = nand_to_mtd(&this->nand); - /* [1] Allocate a command buffer. PAGE_SIZE is enough. */ - this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); - if (this->cmd_buffer == NULL) - goto error_alloc; - /* * [2] Allocate a read/write data buffer. * The gpmi_alloc_dma_buffer can be called twice. @@ -756,29 +1263,15 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) if (this->data_buffer_dma == NULL) goto error_alloc; - /* - * [3] Allocate the page buffer. - * - * Both the payload buffer and the auxiliary buffer must appear on - * 32-bit boundaries. We presume the size of the payload buffer is a - * power of two and is much larger than four, which guarantees the - * auxiliary buffer will appear on a 32-bit boundary. - */ - this->page_buffer_size = geo->payload_size + geo->auxiliary_size; - this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size, - &this->page_buffer_phys, GFP_DMA); - if (!this->page_buffer_virt) + this->auxiliary_virt = dma_alloc_coherent(dev, geo->auxiliary_size, + &this->auxiliary_phys, GFP_DMA); + if (!this->auxiliary_virt) goto error_alloc; - this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + this->raw_buffer = kzalloc((mtd->writesize ?: PAGE_SIZE) + mtd->oobsize, GFP_KERNEL); if (!this->raw_buffer) goto error_alloc; - /* Slice up the page buffer. */ - this->payload_virt = this->page_buffer_virt; - this->payload_phys = this->page_buffer_phys; - this->auxiliary_virt = this->payload_virt + geo->payload_size; - this->auxiliary_phys = this->payload_phys + geo->payload_size; return 0; error_alloc: @@ -786,106 +1279,6 @@ error_alloc: return -ENOMEM; } -static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl) -{ - struct gpmi_nand_data *this = nand_get_controller_data(chip); - int ret; - - /* - * Every operation begins with a command byte and a series of zero or - * more address bytes. These are distinguished by either the Address - * Latch Enable (ALE) or Command Latch Enable (CLE) signals being - * asserted. When MTD is ready to execute the command, it will deassert - * both latch enables. - * - * Rather than run a separate DMA operation for every single byte, we - * queue them up and run a single DMA operation for the entire series - * of command and data bytes. NAND_CMD_NONE means the END of the queue. - */ - if ((ctrl & (NAND_ALE | NAND_CLE))) { - if (data != NAND_CMD_NONE) - this->cmd_buffer[this->command_length++] = data; - return; - } - - if (!this->command_length) - return; - - ret = gpmi_send_command(this); - if (ret) - dev_err(this->dev, "Chip: %u, Error %d\n", - this->current_chip, ret); - - this->command_length = 0; -} - -static int gpmi_dev_ready(struct nand_chip *chip) -{ - struct gpmi_nand_data *this = nand_get_controller_data(chip); - - return gpmi_is_ready(this, this->current_chip); -} - -static void gpmi_select_chip(struct nand_chip *chip, int chipnr) -{ - struct gpmi_nand_data *this = nand_get_controller_data(chip); - int ret; - - /* - * For power consumption matters, disable/enable the clock each time a - * die is selected/unselected. - */ - if (this->current_chip < 0 && chipnr >= 0) { - ret = gpmi_enable_clk(this); - if (ret) - dev_err(this->dev, "Failed to enable the clock\n"); - } else if (this->current_chip >= 0 && chipnr < 0) { - ret = gpmi_disable_clk(this); - if (ret) - dev_err(this->dev, "Failed to disable the clock\n"); - } - - /* - * This driver currently supports only one NAND chip. Plus, dies share - * the same configuration. So once timings have been applied on the - * controller side, they will not change anymore. When the time will - * come, the check on must_apply_timings will have to be dropped. - */ - if (chipnr >= 0 && this->hw.must_apply_timings) { - this->hw.must_apply_timings = false; - gpmi_nfc_apply_timings(this); - } - - this->current_chip = chipnr; -} - -static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len) -{ - struct gpmi_nand_data *this = nand_get_controller_data(chip); - - dev_dbg(this->dev, "len is %d\n", len); - - gpmi_read_data(this, buf, len); -} - -static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len) -{ - struct gpmi_nand_data *this = nand_get_controller_data(chip); - - dev_dbg(this->dev, "len is %d\n", len); - - gpmi_send_data(this, buf, len); -} - -static uint8_t gpmi_read_byte(struct nand_chip *chip) -{ - struct gpmi_nand_data *this = nand_get_controller_data(chip); - uint8_t *buf = this->data_buffer_dma; - - gpmi_read_buf(chip, buf, 1); - return buf[0]; -} - /* * Handles block mark swapping. * It can be called in swapping the block mark, or swapping it back, @@ -934,54 +1327,20 @@ static void block_mark_swapping(struct gpmi_nand_data *this, p[1] = (p[1] & mask) | (from_oob >> (8 - bit)); } -static int gpmi_ecc_read_page_data(struct nand_chip *chip, - uint8_t *buf, int oob_required, - int page) +static int gpmi_count_bitflips(struct nand_chip *chip, void *buf, int first, + int last, int meta) { struct gpmi_nand_data *this = nand_get_controller_data(chip); struct bch_geometry *nfc_geo = &this->bch_geometry; struct mtd_info *mtd = nand_to_mtd(chip); - dma_addr_t payload_phys; - unsigned int i; + int i; unsigned char *status; - unsigned int max_bitflips = 0; - int ret; - bool direct = false; - - dev_dbg(this->dev, "page number is : %d\n", page); - - payload_phys = this->payload_phys; - - if (virt_addr_valid(buf)) { - dma_addr_t dest_phys; - - dest_phys = dma_map_single(this->dev, buf, nfc_geo->payload_size, - DMA_FROM_DEVICE); - if (!dma_mapping_error(this->dev, dest_phys)) { - payload_phys = dest_phys; - direct = true; - } - } - - /* go! */ - ret = gpmi_read_page(this, payload_phys, this->auxiliary_phys); - - if (direct) - dma_unmap_single(this->dev, payload_phys, nfc_geo->payload_size, - DMA_FROM_DEVICE); - - if (ret) { - dev_err(this->dev, "Error in ECC-based read: %d\n", ret); - return ret; - } + unsigned int max_bitflips = 0; /* Loop over status bytes, accumulating ECC status. */ - status = this->auxiliary_virt + nfc_geo->auxiliary_status_offset; - - if (!direct) - memcpy(buf, this->payload_virt, nfc_geo->payload_size); + status = this->auxiliary_virt + ALIGN(meta, 4); - for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) { + for (i = first; i < last; i++, status++) { if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED)) continue; @@ -1061,6 +1420,50 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip, max_bitflips = max_t(unsigned int, max_bitflips, *status); } + return max_bitflips; +} + +static void gpmi_bch_layout_std(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + unsigned int ecc_strength = geo->ecc_strength >> 1; + unsigned int gf_len = geo->gf_len; + unsigned int block_size = geo->ecc_chunk_size; + + this->bch_flashlayout0 = + BF_BCH_FLASH0LAYOUT0_NBLOCKS(geo->ecc_chunk_count - 1) | + BF_BCH_FLASH0LAYOUT0_META_SIZE(geo->metadata_size) | + BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) | + BF_BCH_FLASH0LAYOUT0_GF(gf_len, this) | + BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this); + + this->bch_flashlayout1 = + BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(geo->page_size) | + BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) | + BF_BCH_FLASH0LAYOUT1_GF(gf_len, this) | + BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this); +} + +static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct gpmi_nand_data *this = nand_get_controller_data(chip); + struct mtd_info *mtd = nand_to_mtd(chip); + struct bch_geometry *geo = &this->bch_geometry; + unsigned int max_bitflips; + int ret; + + gpmi_bch_layout_std(this); + this->bch = true; + + ret = nand_read_page_op(chip, page, 0, buf, geo->page_size); + if (ret) + return ret; + + max_bitflips = gpmi_count_bitflips(chip, buf, 0, + geo->ecc_chunk_count, + geo->auxiliary_status_offset); + /* handle the block mark swapping */ block_mark_swapping(this, buf, this->auxiliary_virt); @@ -1082,30 +1485,20 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip, return max_bitflips; } -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); - - return gpmi_ecc_read_page_data(chip, buf, oob_required, page); -} - /* Fake a virtual small page for the subpage read */ 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; - struct bch_geometry old_geo = this->bch_geometry; struct bch_geometry *geo = &this->bch_geometry; int size = chip->ecc.size; /* ECC chunk size */ int meta, n, page_size; - u32 r1_old, r2_old, r1_new, r2_new; unsigned int max_bitflips; + unsigned int ecc_strength; int first, last, marker_pos; int ecc_parity_size; int col = 0; - int old_swap_block_mark = this->swap_block_mark; + int ret; /* The size of ECC parity */ ecc_parity_size = geo->gf_len * geo->ecc_strength / 8; @@ -1138,43 +1531,33 @@ static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs, buf = buf + first * size; } - nand_read_page_op(chip, page, col, NULL, 0); - - /* Save the old environment */ - r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0); - r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1); + ecc_parity_size = geo->gf_len * geo->ecc_strength / 8; - /* change the BCH registers and bch_geometry{} */ n = last - first + 1; page_size = meta + (size + ecc_parity_size) * n; + ecc_strength = geo->ecc_strength >> 1; - r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS | - BM_BCH_FLASH0LAYOUT0_META_SIZE); - r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1) - | BF_BCH_FLASH0LAYOUT0_META_SIZE(meta); - writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0); + this->bch_flashlayout0 = BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1) | + BF_BCH_FLASH0LAYOUT0_META_SIZE(meta) | + BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) | + BF_BCH_FLASH0LAYOUT0_GF(geo->gf_len, this) | + BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(geo->ecc_chunk_size, this); - r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE; - r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size); - writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1); + this->bch_flashlayout1 = BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) | + BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) | + BF_BCH_FLASH0LAYOUT1_GF(geo->gf_len, this) | + BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(geo->ecc_chunk_size, this); - geo->ecc_chunk_count = n; - geo->payload_size = n * size; - geo->page_size = page_size; - geo->auxiliary_status_offset = ALIGN(meta, 4); + this->bch = true; + + ret = nand_read_page_op(chip, page, col, buf, page_size); + if (ret) + return ret; dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n", page, offs, len, col, first, n, page_size); - /* Read the subpage now */ - this->swap_block_mark = false; - max_bitflips = gpmi_ecc_read_page_data(chip, buf, 0, page); - - /* Restore */ - writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0); - writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1); - this->bch_geometry = old_geo; - this->swap_block_mark = old_swap_block_mark; + max_bitflips = gpmi_count_bitflips(chip, buf, first, last, meta); return max_bitflips; } @@ -1185,81 +1568,29 @@ static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf, 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; - dma_addr_t payload_phys; - const void *auxiliary_virt; - dma_addr_t auxiliary_phys; - int ret; + int ret; dev_dbg(this->dev, "ecc write page.\n"); - nand_prog_page_begin_op(chip, page, 0, NULL, 0); + gpmi_bch_layout_std(this); + this->bch = true; + + memcpy(this->auxiliary_virt, chip->oob_poi, nfc_geo->auxiliary_size); if (this->swap_block_mark) { /* - * If control arrives here, we're doing block mark swapping. - * Since we can't modify the caller's buffers, we must copy them - * into our own. - */ - memcpy(this->payload_virt, buf, mtd->writesize); - payload_virt = this->payload_virt; - payload_phys = this->payload_phys; - - memcpy(this->auxiliary_virt, chip->oob_poi, - nfc_geo->auxiliary_size); - auxiliary_virt = this->auxiliary_virt; - auxiliary_phys = this->auxiliary_phys; - - /* Handle block mark swapping. */ - block_mark_swapping(this, - (void *)payload_virt, (void *)auxiliary_virt); - } else { - /* - * If control arrives here, we're not doing block mark swapping, - * so we can to try and use the caller's buffers. + * When doing bad block marker swapping we must always copy the + * input buffer as we can't modify the const buffer. */ - ret = send_page_prepare(this, - buf, mtd->writesize, - this->payload_virt, this->payload_phys, - nfc_geo->payload_size, - &payload_virt, &payload_phys); - if (ret) { - dev_err(this->dev, "Inadequate payload DMA buffer\n"); - return 0; - } - - ret = send_page_prepare(this, - chip->oob_poi, mtd->oobsize, - this->auxiliary_virt, this->auxiliary_phys, - nfc_geo->auxiliary_size, - &auxiliary_virt, &auxiliary_phys); - if (ret) { - dev_err(this->dev, "Inadequate auxiliary DMA buffer\n"); - goto exit_auxiliary; - } + memcpy(this->data_buffer_dma, buf, mtd->writesize); + buf = this->data_buffer_dma; + block_mark_swapping(this, this->data_buffer_dma, + this->auxiliary_virt); } - /* Ask the NFC. */ - ret = gpmi_send_page(this, payload_phys, auxiliary_phys); - if (ret) - dev_err(this->dev, "Error in ECC-based write: %d\n", ret); - - if (!this->swap_block_mark) { - send_page_end(this, chip->oob_poi, mtd->oobsize, - this->auxiliary_virt, this->auxiliary_phys, - nfc_geo->auxiliary_size, - auxiliary_virt, auxiliary_phys); -exit_auxiliary: - send_page_end(this, buf, mtd->writesize, - this->payload_virt, this->payload_phys, - nfc_geo->payload_size, - payload_virt, payload_phys); - } + ret = nand_prog_page_op(chip, page, 0, buf, nfc_geo->page_size); - if (ret) - return ret; - - return nand_prog_page_end_op(chip); + return ret; } /* @@ -1326,14 +1657,16 @@ 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); + int ret; - dev_dbg(this->dev, "page number is %d\n", page); /* clear the OOB buffer */ memset(chip->oob_poi, ~0, mtd->oobsize); /* Read out the conventional OOB. */ - nand_read_page_op(chip, page, mtd->writesize, NULL, 0); - chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); + ret = nand_read_page_op(chip, page, mtd->writesize, chip->oob_poi, + mtd->oobsize); + if (ret) + return ret; /* * Now, we want to make sure the block mark is correct. In the @@ -1342,8 +1675,9 @@ static int gpmi_ecc_read_oob(struct nand_chip *chip, int page) */ 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->legacy.read_byte(chip); + ret = nand_read_page_op(chip, page, 0, chip->oob_poi, 1); + if (ret) + return ret; } return 0; @@ -1392,9 +1726,12 @@ static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf, size_t oob_byte_off; uint8_t *oob = chip->oob_poi; int step; + int ret; - nand_read_page_op(chip, page, 0, tmp_buf, - mtd->writesize + mtd->oobsize); + ret = nand_read_page_op(chip, page, 0, tmp_buf, + mtd->writesize + mtd->oobsize); + if (ret) + return ret; /* * If required, swap the bad block marker and the data stored in the @@ -1606,13 +1943,12 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) unsigned int stride; unsigned int page; u8 *buffer = nand_get_data_buf(chip); - int saved_chip_number; int found_an_ncb_fingerprint = false; + int ret; /* Compute the number of strides in a search area. */ search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; - saved_chip_number = this->current_chip; nand_select_target(chip, 0); /* @@ -1630,8 +1966,10 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) * Read the NCB fingerprint. The fingerprint is four bytes long * and starts in the 12th byte of the page. */ - nand_read_page_op(chip, page, 12, NULL, 0); - chip->legacy.read_buf(chip, buffer, strlen(fingerprint)); + ret = nand_read_page_op(chip, page, 12, buffer, + strlen(fingerprint)); + if (ret) + continue; /* Look for the fingerprint. */ if (!memcmp(buffer, fingerprint, strlen(fingerprint))) { @@ -1641,10 +1979,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) } - if (saved_chip_number >= 0) - nand_select_target(chip, saved_chip_number); - else - nand_deselect_target(chip); + nand_deselect_target(chip); if (found_an_ncb_fingerprint) dev_dbg(dev, "\tFound a fingerprint\n"); @@ -1668,7 +2003,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) unsigned int stride; unsigned int page; u8 *buffer = nand_get_data_buf(chip); - int saved_chip_number; int status; /* Compute the search area geometry. */ @@ -1685,8 +2019,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides); dev_dbg(dev, "\tin Pages : %u\n", search_area_size_in_pages); - /* Select chip 0. */ - saved_chip_number = this->current_chip; nand_select_target(chip, 0); /* Loop over blocks in the first search area, erasing them. */ @@ -1718,11 +2050,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) dev_err(dev, "[%s] Write failed.\n", __func__); } - /* Deselect chip 0. */ - if (saved_chip_number >= 0) - nand_select_target(chip, saved_chip_number); - else - nand_deselect_target(chip); + nand_deselect_target(chip); return 0; } @@ -1773,10 +2101,13 @@ static int mx23_boot_init(struct gpmi_nand_data *this) /* Send the command to read the conventional block mark. */ nand_select_target(chip, chipnr); - nand_read_page_op(chip, page, mtd->writesize, NULL, 0); - block_mark = chip->legacy.read_byte(chip); + ret = nand_read_page_op(chip, page, mtd->writesize, &block_mark, + 1); nand_deselect_target(chip); + if (ret) + continue; + /* * Check if the block is marked bad. If so, we need to mark it * again, but this time the result will be a mark in the @@ -1890,9 +2221,330 @@ static int gpmi_nand_attach_chip(struct nand_chip *chip) return 0; } +static struct gpmi_transfer *get_next_transfer(struct gpmi_nand_data *this) +{ + struct gpmi_transfer *transfer = &this->transfers[this->ntransfers]; + + this->ntransfers++; + + if (this->ntransfers == GPMI_MAX_TRANSFERS) + return NULL; + + return transfer; +} + +static struct dma_async_tx_descriptor *gpmi_chain_command( + struct gpmi_nand_data *this, u8 cmd, const u8 *addr, int naddr) +{ + struct dma_chan *channel = get_dma_chan(this); + struct dma_async_tx_descriptor *desc; + struct gpmi_transfer *transfer; + int chip = this->nand.cur_cs; + u32 pio[3]; + + /* [1] send out the PIO words */ + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) + | BM_GPMI_CTRL0_ADDRESS_INCREMENT + | BF_GPMI_CTRL0_XFER_COUNT(naddr + 1); + pio[1] = 0; + pio[2] = 0; + desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio), + DMA_TRANS_NONE, 0); + if (!desc) + return NULL; + + transfer = get_next_transfer(this); + if (!transfer) + return NULL; + + transfer->cmdbuf[0] = cmd; + if (naddr) + memcpy(&transfer->cmdbuf[1], addr, naddr); + + sg_init_one(&transfer->sgl, transfer->cmdbuf, naddr + 1); + dma_map_sg(this->dev, &transfer->sgl, 1, DMA_TO_DEVICE); + + transfer->direction = DMA_TO_DEVICE; + + desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1, DMA_MEM_TO_DEV, + MXS_DMA_CTRL_WAIT4END); + return desc; +} + +static struct dma_async_tx_descriptor *gpmi_chain_wait_ready( + struct gpmi_nand_data *this) +{ + struct dma_chan *channel = get_dma_chan(this); + u32 pio[2]; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) + | BF_GPMI_CTRL0_XFER_COUNT(0); + pio[1] = 0; + + return mxs_dmaengine_prep_pio(channel, pio, 2, DMA_TRANS_NONE, + MXS_DMA_CTRL_WAIT4END | MXS_DMA_CTRL_WAIT4RDY); +} + +static struct dma_async_tx_descriptor *gpmi_chain_data_read( + struct gpmi_nand_data *this, void *buf, int raw_len, bool *direct) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + struct gpmi_transfer *transfer; + u32 pio[6] = {}; + + transfer = get_next_transfer(this); + if (!transfer) + return NULL; + + transfer->direction = DMA_FROM_DEVICE; + + *direct = prepare_data_dma(this, buf, raw_len, &transfer->sgl, + DMA_FROM_DEVICE); + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) + | BF_GPMI_CTRL0_XFER_COUNT(raw_len); + + if (this->bch) { + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE) + | BF_GPMI_ECCCTRL_BUFFER_MASK(BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE + | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY); + pio[3] = raw_len; + pio[4] = transfer->sgl.dma_address; + pio[5] = this->auxiliary_phys; + } + + desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio), + DMA_TRANS_NONE, 0); + if (!desc) + return NULL; + + if (!this->bch) + desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1, + DMA_DEV_TO_MEM, + MXS_DMA_CTRL_WAIT4END); + + return desc; +} + +static struct dma_async_tx_descriptor *gpmi_chain_data_write( + struct gpmi_nand_data *this, const void *buf, int raw_len) +{ + struct dma_chan *channel = get_dma_chan(this); + struct dma_async_tx_descriptor *desc; + struct gpmi_transfer *transfer; + u32 pio[6] = {}; + + transfer = get_next_transfer(this); + if (!transfer) + return NULL; + + transfer->direction = DMA_TO_DEVICE; + + prepare_data_dma(this, buf, raw_len, &transfer->sgl, DMA_TO_DEVICE); + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(this->nand.cur_cs, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) + | BF_GPMI_CTRL0_XFER_COUNT(raw_len); + + if (this->bch) { + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE) + | BF_GPMI_ECCCTRL_BUFFER_MASK(BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE | + BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY); + pio[3] = raw_len; + pio[4] = transfer->sgl.dma_address; + pio[5] = this->auxiliary_phys; + } + + desc = mxs_dmaengine_prep_pio(channel, pio, ARRAY_SIZE(pio), + DMA_TRANS_NONE, + (this->bch ? MXS_DMA_CTRL_WAIT4END : 0)); + if (!desc) + return NULL; + + if (!this->bch) + desc = dmaengine_prep_slave_sg(channel, &transfer->sgl, 1, + DMA_MEM_TO_DEV, + MXS_DMA_CTRL_WAIT4END); + + return desc; +} + +static int gpmi_nfc_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + const struct nand_op_instr *instr; + struct gpmi_nand_data *this = nand_get_controller_data(chip); + struct dma_async_tx_descriptor *desc = NULL; + int i, ret, buf_len = 0, nbufs = 0; + u8 cmd = 0; + void *buf_read = NULL; + const void *buf_write = NULL; + bool direct = false; + struct completion *completion; + unsigned long to; + + this->ntransfers = 0; + for (i = 0; i < GPMI_MAX_TRANSFERS; i++) + this->transfers[i].direction = DMA_NONE; + + ret = pm_runtime_get_sync(this->dev); + if (ret < 0) + return ret; + + /* + * This driver currently supports only one NAND chip. Plus, dies share + * the same configuration. So once timings have been applied on the + * controller side, they will not change anymore. When the time will + * come, the check on must_apply_timings will have to be dropped. + */ + if (this->hw.must_apply_timings) { + this->hw.must_apply_timings = false; + gpmi_nfc_apply_timings(this); + } + + dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs); + + for (i = 0; i < op->ninstrs; i++) { + instr = &op->instrs[i]; + + nand_op_trace(" ", instr); + + switch (instr->type) { + case NAND_OP_WAITRDY_INSTR: + desc = gpmi_chain_wait_ready(this); + break; + case NAND_OP_CMD_INSTR: + cmd = instr->ctx.cmd.opcode; + + /* + * When this command has an address cycle chain it + * together with the address cycle + */ + if (i + 1 != op->ninstrs && + op->instrs[i + 1].type == NAND_OP_ADDR_INSTR) + continue; + + desc = gpmi_chain_command(this, cmd, NULL, 0); + + break; + case NAND_OP_ADDR_INSTR: + desc = gpmi_chain_command(this, cmd, instr->ctx.addr.addrs, + instr->ctx.addr.naddrs); + break; + case NAND_OP_DATA_OUT_INSTR: + buf_write = instr->ctx.data.buf.out; + buf_len = instr->ctx.data.len; + nbufs++; + + desc = gpmi_chain_data_write(this, buf_write, buf_len); + + break; + case NAND_OP_DATA_IN_INSTR: + if (!instr->ctx.data.len) + break; + buf_read = instr->ctx.data.buf.in; + buf_len = instr->ctx.data.len; + nbufs++; + + desc = gpmi_chain_data_read(this, buf_read, buf_len, + &direct); + break; + } + + if (!desc) { + ret = -ENXIO; + goto unmap; + } + } + + dev_dbg(this->dev, "%s setup done\n", __func__); + + if (nbufs > 1) { + dev_err(this->dev, "Multiple data instructions not supported\n"); + ret = -EINVAL; + goto unmap; + } + + if (this->bch) { + writel(this->bch_flashlayout0, + this->resources.bch_regs + HW_BCH_FLASH0LAYOUT0); + writel(this->bch_flashlayout1, + this->resources.bch_regs + HW_BCH_FLASH0LAYOUT1); + } + + if (this->bch && buf_read) { + writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, + this->resources.bch_regs + HW_BCH_CTRL_SET); + completion = &this->bch_done; + } else { + desc->callback = dma_irq_callback; + desc->callback_param = this; + completion = &this->dma_done; + } + + init_completion(completion); + + dmaengine_submit(desc); + dma_async_issue_pending(get_dma_chan(this)); + + to = wait_for_completion_timeout(completion, msecs_to_jiffies(1000)); + if (!to) { + dev_err(this->dev, "DMA timeout, last DMA\n"); + gpmi_dump_info(this); + ret = -ETIMEDOUT; + goto unmap; + } + + writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, + this->resources.bch_regs + HW_BCH_CTRL_CLR); + gpmi_clear_bch(this); + + ret = 0; + +unmap: + for (i = 0; i < this->ntransfers; i++) { + struct gpmi_transfer *transfer = &this->transfers[i]; + + if (transfer->direction != DMA_NONE) + dma_unmap_sg(this->dev, &transfer->sgl, 1, + transfer->direction); + } + + if (!ret && buf_read && !direct) + memcpy(buf_read, this->data_buffer_dma, + gpmi_raw_len_to_len(this, buf_len)); + + this->bch = false; + + pm_runtime_mark_last_busy(this->dev); + pm_runtime_put_autosuspend(this->dev); + + return ret; +} + static const struct nand_controller_ops gpmi_nand_controller_ops = { .attach_chip = gpmi_nand_attach_chip, .setup_data_interface = gpmi_setup_data_interface, + .exec_op = gpmi_nfc_exec_op, }; static int gpmi_nand_init(struct gpmi_nand_data *this) @@ -1901,9 +2553,6 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) struct mtd_info *mtd = nand_to_mtd(chip); int ret; - /* init current chip */ - this->current_chip = -1; - /* init the MTD data structures */ mtd->name = "gpmi-nand"; mtd->dev.parent = this->dev; @@ -1911,14 +2560,8 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */ nand_set_controller_data(chip, this); nand_set_flash_node(chip, this->pdev->dev.of_node); - chip->legacy.select_chip = gpmi_select_chip; - 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->legacy.block_markbad = gpmi_block_markbad; + chip->badblock_pattern = &gpmi_bbt_descr; chip->options |= NAND_NO_SUBPAGE_WRITE; /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ @@ -1934,7 +2577,10 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) if (ret) goto err_out; - chip->legacy.dummy_controller.ops = &gpmi_nand_controller_ops; + nand_controller_init(&this->base); + this->base.ops = &gpmi_nand_controller_ops; + chip->controller = &this->base; + ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1); if (ret) goto err_out; @@ -2004,6 +2650,16 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_acquire_resources; + ret = __gpmi_enable_clk(this, true); + if (ret) + goto exit_nfc_init; + + pm_runtime_set_autosuspend_delay(&pdev->dev, 500); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + ret = gpmi_init(this); if (ret) goto exit_nfc_init; @@ -2012,11 +2668,16 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_nfc_init; + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + dev_info(this->dev, "driver registered.\n"); return 0; exit_nfc_init: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); release_resources(this); exit_acquire_resources: @@ -2027,6 +2688,9 @@ static int gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + nand_release(&this->nand); gpmi_free_dma_buffer(this); release_resources(this); @@ -2069,8 +2733,23 @@ static int gpmi_pm_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ +static int __maybe_unused gpmi_runtime_suspend(struct device *dev) +{ + struct gpmi_nand_data *this = dev_get_drvdata(dev); + + return __gpmi_enable_clk(this, false); +} + +static int __maybe_unused gpmi_runtime_resume(struct device *dev) +{ + struct gpmi_nand_data *this = dev_get_drvdata(dev); + + return __gpmi_enable_clk(this, true); +} + static const struct dev_pm_ops gpmi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume) + SET_RUNTIME_PM_OPS(gpmi_runtime_suspend, gpmi_runtime_resume, NULL) }; static struct platform_driver gpmi_nand_driver = { diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h index a804a4a5bd46..fdc5ed7de083 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h @@ -103,6 +103,14 @@ struct gpmi_nfc_hardware_timing { u32 ctrl1n; }; +#define GPMI_MAX_TRANSFERS 8 + +struct gpmi_transfer { + u8 cmdbuf[8]; + struct scatterlist sgl; + enum dma_data_direction direction; +}; + struct gpmi_nand_data { /* Devdata */ const struct gpmi_devdata *devdata; @@ -126,25 +134,18 @@ struct gpmi_nand_data { struct boot_rom_geometry rom_geometry; /* MTD / NAND */ + struct nand_controller base; struct nand_chip nand; - /* General-use Variables */ - int current_chip; - unsigned int command_length; + struct gpmi_transfer transfers[GPMI_MAX_TRANSFERS]; + int ntransfers; - struct scatterlist cmd_sgl; - char *cmd_buffer; + bool bch; + uint32_t bch_flashlayout0; + uint32_t bch_flashlayout1; - struct scatterlist data_sgl; char *data_buffer_dma; - void *page_buffer_virt; - dma_addr_t page_buffer_phys; - unsigned int page_buffer_size; - - void *payload_virt; - dma_addr_t payload_phys; - void *auxiliary_virt; dma_addr_t auxiliary_phys; @@ -154,45 +155,8 @@ struct gpmi_nand_data { #define DMA_CHANS 8 struct dma_chan *dma_chans[DMA_CHANS]; struct completion dma_done; - - /* private */ - void *private; }; -/* Common Services */ -int common_nfc_set_geometry(struct gpmi_nand_data *); -struct dma_chan *get_dma_chan(struct gpmi_nand_data *); -bool prepare_data_dma(struct gpmi_nand_data *, const void *buf, int len, - enum dma_data_direction dr); -int start_dma_without_bch_irq(struct gpmi_nand_data *, - struct dma_async_tx_descriptor *); -int start_dma_with_bch_irq(struct gpmi_nand_data *, - struct dma_async_tx_descriptor *); - -/* GPMI-NAND helper function library */ -int gpmi_init(struct gpmi_nand_data *); -void gpmi_clear_bch(struct gpmi_nand_data *); -void gpmi_dump_info(struct gpmi_nand_data *); -int bch_set_geometry(struct gpmi_nand_data *); -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 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); -int gpmi_send_data(struct gpmi_nand_data *, const void *buf, int len); - -int gpmi_send_page(struct gpmi_nand_data *, - dma_addr_t payload, dma_addr_t auxiliary); -int gpmi_read_page(struct gpmi_nand_data *, - dma_addr_t payload, dma_addr_t auxiliary); - -void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, - const u8 *src, size_t src_bit_off, - size_t nbits); - /* BCH : Status Block Completion Codes */ #define STATUS_GOOD 0x00 #define STATUS_ERASED 0xff diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c index 0f90e060dae8..74595b644b7c 100644 --- a/drivers/mtd/nand/raw/mtk_ecc.c +++ b/drivers/mtd/nand/raw/mtk_ecc.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * MTK ECC controller driver. * Copyright (C) 2016 MediaTek Inc. @@ -596,4 +596,4 @@ module_platform_driver(mtk_ecc_driver); MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>"); MODULE_DESCRIPTION("MTK Nand ECC Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/mtd/nand/raw/mtk_ecc.h b/drivers/mtd/nand/raw/mtk_ecc.h index aa52e94c771d..0e48c36e6ca0 100644 --- a/drivers/mtd/nand/raw/mtk_ecc.h +++ b/drivers/mtd/nand/raw/mtk_ecc.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /* * MTK SDG1 ECC controller * diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index dceff28c9a31..373d47d1ba4c 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * MTK NAND Flash controller driver. * Copyright (C) 2016 MediaTek Inc. @@ -79,6 +79,10 @@ #define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2) #define NFI_FDM_MAX_SIZE (8) #define NFI_FDM_MIN_SIZE (1) +#define NFI_DEBUG_CON1 (0x220) +#define STROBE_MASK GENMASK(4, 3) +#define STROBE_SHIFT (3) +#define MAX_STROBE_DLY (3) #define NFI_MASTER_STA (0x224) #define MASTER_STA_MASK (0x0FFF) #define NFI_EMPTY_THRESH (0x23C) @@ -150,6 +154,8 @@ struct mtk_nfc { struct list_head chips; u8 *buffer; + + unsigned long assigned_cs; }; /* @@ -500,7 +506,8 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline, { struct mtk_nfc *nfc = nand_get_controller_data(chip); const struct nand_sdr_timings *timings; - u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt; + u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst = 0, trlt = 0; + u32 temp, tsel = 0; timings = nand_get_sdr_timings(conf); if (IS_ERR(timings)) @@ -536,14 +543,53 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline, twh = DIV_ROUND_UP(twh * rate, 1000000) - 1; twh &= 0xf; - twst = timings->tWP_min / 1000; + /* Calculate real WE#/RE# hold time in nanosecond */ + temp = (twh + 1) * 1000000 / rate; + /* nanosecond to picosecond */ + temp *= 1000; + + /* + * WE# low level time should be expaned to meet WE# pulse time + * and WE# cycle time at the same time. + */ + if (temp < timings->tWC_min) + twst = timings->tWC_min - temp; + twst = max(timings->tWP_min, twst) / 1000; twst = DIV_ROUND_UP(twst * rate, 1000000) - 1; twst &= 0xf; - trlt = max(timings->tREA_max, timings->tRP_min) / 1000; + /* + * RE# low level time should be expaned to meet RE# pulse time + * and RE# cycle time at the same time. + */ + if (temp < timings->tRC_min) + trlt = timings->tRC_min - temp; + trlt = max(trlt, timings->tRP_min) / 1000; trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1; trlt &= 0xf; + /* Calculate RE# pulse time in nanosecond. */ + temp = (trlt + 1) * 1000000 / rate; + /* nanosecond to picosecond */ + temp *= 1000; + /* + * If RE# access time is bigger than RE# pulse time, + * delay sampling data timing. + */ + if (temp < timings->tREA_max) { + tsel = timings->tREA_max / 1000; + tsel = DIV_ROUND_UP(tsel * rate, 1000000); + tsel -= (trlt + 1); + if (tsel > MAX_STROBE_DLY) { + trlt += tsel - MAX_STROBE_DLY; + tsel = MAX_STROBE_DLY; + } + } + temp = nfi_readl(nfc, NFI_DEBUG_CON1); + temp &= ~STROBE_MASK; + temp |= tsel << STROBE_SHIFT; + nfi_writel(nfc, temp, NFI_DEBUG_CON1); + /* * ACCON: access timing control register * ------------------------------------- @@ -835,19 +881,21 @@ static int mtk_nfc_write_oob_std(struct nand_chip *chip, int 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) +static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 start, + u32 sectors) { struct nand_chip *chip = mtd_to_nand(mtd); struct mtk_nfc *nfc = nand_get_controller_data(chip); struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip); struct mtk_ecc_stats stats; + u32 reg_size = mtk_nand->fdm.reg_size; int rc, i; rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE; if (rc) { memset(buf, 0xff, sectors * chip->ecc.size); for (i = 0; i < sectors; i++) - memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size); + memset(oob_ptr(chip, start + i), 0xff, reg_size); return 0; } @@ -867,7 +915,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, u32 spare = mtk_nand->spare_per_sector; u32 column, sectors, start, end, reg; dma_addr_t addr; - int bitflips; + int bitflips = 0; size_t len; u8 *buf; int rc; @@ -934,14 +982,11 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, if (rc < 0) { dev_err(nfc->dev, "subpage done timeout\n"); bitflips = -EIO; - } else { - bitflips = 0; - if (!raw) { - rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE); - bitflips = rc < 0 ? -ETIMEDOUT : - mtk_nfc_update_ecc_stats(mtd, buf, sectors); - mtk_nfc_read_fdm(chip, start, sectors); - } + } else if (!raw) { + rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE); + bitflips = rc < 0 ? -ETIMEDOUT : + mtk_nfc_update_ecc_stats(mtd, buf, start, sectors); + mtk_nfc_read_fdm(chip, start, sectors); } dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE); @@ -1315,6 +1360,17 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, dev_err(dev, "reg property failure : %d\n", ret); return ret; } + + if (tmp >= MTK_NAND_MAX_NSELS) { + dev_err(dev, "invalid CS: %u\n", tmp); + return -EINVAL; + } + + if (test_and_set_bit(tmp, &nfc->assigned_cs)) { + dev_err(dev, "CS %u already assigned\n", tmp); + return -EINVAL; + } + chip->sels[i] = tmp; } @@ -1589,6 +1645,6 @@ static struct platform_driver mtk_nfc_driver = { module_platform_driver(mtk_nfc_driver); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("Dual MIT/GPL"); MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>"); MODULE_DESCRIPTION("MTK Nand Flash Controller Driver"); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 6eb131292eb2..91f046d4d452 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -2111,35 +2111,7 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx) if (instr == &ctx->subop.instrs[0]) prefix = " ->"; - switch (instr->type) { - case NAND_OP_CMD_INSTR: - pr_debug("%sCMD [0x%02x]\n", prefix, - instr->ctx.cmd.opcode); - break; - case NAND_OP_ADDR_INSTR: - pr_debug("%sADDR [%d cyc: %*ph]\n", prefix, - instr->ctx.addr.naddrs, - instr->ctx.addr.naddrs < 64 ? - instr->ctx.addr.naddrs : 64, - instr->ctx.addr.addrs); - break; - case NAND_OP_DATA_IN_INSTR: - pr_debug("%sDATA_IN [%d B%s]\n", prefix, - instr->ctx.data.len, - instr->ctx.data.force_8bit ? - ", force 8-bit" : ""); - break; - case NAND_OP_DATA_OUT_INSTR: - pr_debug("%sDATA_OUT [%d B%s]\n", prefix, - instr->ctx.data.len, - instr->ctx.data.force_8bit ? - ", force 8-bit" : ""); - break; - case NAND_OP_WAITRDY_INSTR: - pr_debug("%sWAITRDY [max %d ms]\n", prefix, - instr->ctx.waitrdy.timeout_ms); - break; - } + nand_op_trace(prefix, instr); if (instr == &ctx->subop.instrs[ctx->subop.ninstrs - 1]) prefix = " "; @@ -2152,6 +2124,22 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx) } #endif +static int nand_op_parser_cmp_ctx(const struct nand_op_parser_ctx *a, + const struct nand_op_parser_ctx *b) +{ + if (a->subop.ninstrs < b->subop.ninstrs) + return -1; + else if (a->subop.ninstrs > b->subop.ninstrs) + return 1; + + if (a->subop.last_instr_end_off < b->subop.last_instr_end_off) + return -1; + else if (a->subop.last_instr_end_off > b->subop.last_instr_end_off) + return 1; + + return 0; +} + /** * nand_op_parser_exec_op - exec_op parser * @chip: the NAND chip @@ -2186,32 +2174,40 @@ int nand_op_parser_exec_op(struct nand_chip *chip, unsigned int i; while (ctx.subop.instrs < op->instrs + op->ninstrs) { - int ret; + const struct nand_op_parser_pattern *pattern; + struct nand_op_parser_ctx best_ctx; + int ret, best_pattern = -1; for (i = 0; i < parser->npatterns; i++) { - const struct nand_op_parser_pattern *pattern; + struct nand_op_parser_ctx test_ctx = ctx; pattern = &parser->patterns[i]; - if (!nand_op_parser_match_pat(pattern, &ctx)) + if (!nand_op_parser_match_pat(pattern, &test_ctx)) continue; - nand_op_parser_trace(&ctx); - - if (check_only) - break; - - ret = pattern->exec(chip, &ctx.subop); - if (ret) - return ret; + if (best_pattern >= 0 && + nand_op_parser_cmp_ctx(&test_ctx, &best_ctx) <= 0) + continue; - break; + best_pattern = i; + best_ctx = test_ctx; } - if (i == parser->npatterns) { + if (best_pattern < 0) { pr_debug("->exec_op() parser: pattern not found!\n"); return -ENOTSUPP; } + ctx = best_ctx; + nand_op_parser_trace(&ctx); + + if (!check_only) { + pattern = &parser->patterns[best_pattern]; + ret = pattern->exec(chip, &ctx.subop); + if (ret) + return ret; + } + /* * Update the context structure by pointing to the start of the * next subop. diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c index 55aa4c1cd414..17527310c3a1 100644 --- a/drivers/mtd/nand/raw/nand_bch.c +++ b/drivers/mtd/nand/raw/nand_bch.c @@ -170,7 +170,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) goto fail; } - nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); + nbc->eccmask = kzalloc(eccbytes, GFP_KERNEL); nbc->errloc = kmalloc_array(t, sizeof(*nbc->errloc), GFP_KERNEL); if (!nbc->eccmask || !nbc->errloc) goto fail; @@ -182,7 +182,6 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) goto fail; memset(erased_page, 0xff, eccsize); - memset(nbc->eccmask, 0, eccbytes); encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); kfree(erased_page); diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index fad57c378dd2..58511aeb0c9a 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -8,6 +8,50 @@ #include "internals.h" +#define MACRONIX_READ_RETRY_BIT BIT(0) +#define MACRONIX_NUM_READ_RETRY_MODES 6 + +struct nand_onfi_vendor_macronix { + u8 reserved; + u8 reliability_func; +} __packed; + +static int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + + if (!chip->parameters.supports_set_get_features || + !test_bit(ONFI_FEATURE_ADDR_READ_RETRY, + chip->parameters.set_feature_list)) + return -ENOTSUPP; + + feature[0] = mode; + return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); +} + +static void macronix_nand_onfi_init(struct nand_chip *chip) +{ + struct nand_parameters *p = &chip->parameters; + struct nand_onfi_vendor_macronix *mxic; + + if (!p->onfi) + return; + + mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor; + if ((mxic->reliability_func & MACRONIX_READ_RETRY_BIT) == 0) + return; + + chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES; + chip->setup_read_retry = macronix_nand_setup_read_retry; + + if (p->supports_set_get_features) { + bitmap_set(p->set_feature_list, + ONFI_FEATURE_ADDR_READ_RETRY, 1); + bitmap_set(p->get_feature_list, + ONFI_FEATURE_ADDR_READ_RETRY, 1); + } +} + /* * Macronix AC series does not support using SET/GET_FEATURES to change * the timings unlike what is declared in the parameter page. Unflag @@ -56,6 +100,7 @@ static int macronix_nand_init(struct nand_chip *chip) chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; macronix_nand_fix_broken_get_timings(chip); + macronix_nand_onfi_init(chip); return 0; } diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 999ca6a66036..e63acc077c18 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -37,6 +37,8 @@ /* Max ECC buffer length */ #define FMC2_MAX_ECC_BUF_LEN (FMC2_BCHDSRS_LEN * FMC2_MAX_SG) +#define FMC2_TIMEOUT_MS 1000 + /* Timings */ #define FMC2_THIZ 1 #define FMC2_TIO 8000 @@ -530,7 +532,8 @@ static int stm32_fmc2_ham_calculate(struct nand_chip *chip, const u8 *data, int ret; ret = readl_relaxed_poll_timeout(fmc2->io_base + FMC2_SR, - sr, sr & FMC2_SR_NWRF, 10, 1000); + sr, sr & FMC2_SR_NWRF, 10, + FMC2_TIMEOUT_MS); if (ret) { dev_err(fmc2->dev, "ham timeout\n"); return ret; @@ -611,7 +614,7 @@ static int stm32_fmc2_bch_calculate(struct nand_chip *chip, const u8 *data, /* Wait until the BCH code is ready */ if (!wait_for_completion_timeout(&fmc2->complete, - msecs_to_jiffies(1000))) { + msecs_to_jiffies(FMC2_TIMEOUT_MS))) { dev_err(fmc2->dev, "bch timeout\n"); stm32_fmc2_disable_bch_irq(fmc2); return -ETIMEDOUT; @@ -696,7 +699,7 @@ static int stm32_fmc2_bch_correct(struct nand_chip *chip, u8 *dat, /* Wait until the decoding error is ready */ if (!wait_for_completion_timeout(&fmc2->complete, - msecs_to_jiffies(1000))) { + msecs_to_jiffies(FMC2_TIMEOUT_MS))) { dev_err(fmc2->dev, "bch timeout\n"); stm32_fmc2_disable_bch_irq(fmc2); return -ETIMEDOUT; @@ -969,7 +972,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, /* Wait end of sequencer transfer */ if (!wait_for_completion_timeout(&fmc2->complete, - msecs_to_jiffies(1000))) { + msecs_to_jiffies(FMC2_TIMEOUT_MS))) { dev_err(fmc2->dev, "seq timeout\n"); stm32_fmc2_disable_seq_irq(fmc2); dmaengine_terminate_all(dma_ch); @@ -981,7 +984,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, /* Wait DMA data transfer completion */ if (!wait_for_completion_timeout(&fmc2->dma_data_complete, - msecs_to_jiffies(100))) { + msecs_to_jiffies(FMC2_TIMEOUT_MS))) { dev_err(fmc2->dev, "data DMA timeout\n"); dmaengine_terminate_all(dma_ch); ret = -ETIMEDOUT; @@ -990,7 +993,7 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, /* Wait DMA ECC transfer completion */ if (!write_data && !raw) { if (!wait_for_completion_timeout(&fmc2->dma_ecc_complete, - msecs_to_jiffies(100))) { + msecs_to_jiffies(FMC2_TIMEOUT_MS))) { dev_err(fmc2->dev, "ECC DMA timeout\n"); dmaengine_terminate_all(fmc2->dma_ecc_ch); ret = -ETIMEDOUT; @@ -1909,6 +1912,12 @@ static int stm32_fmc2_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); + if (irq < 0) { + if (irq != -EPROBE_DEFER) + dev_err(dev, "IRQ error missing or invalid\n"); + return irq; + } + ret = devm_request_irq(dev, irq, stm32_fmc2_irq, 0, dev_name(dev), fmc2); if (ret) { diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 753125082640..9662b9c1d5a9 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o +spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 4c15bb58c623..89f6beefb01c 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -511,12 +511,12 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, if (ret == -EBADMSG) { ecc_failed = true; mtd->ecc_stats.failed++; - ret = 0; } else { mtd->ecc_stats.corrected += ret; max_bitflips = max_t(unsigned int, max_bitflips, ret); } + ret = 0; ops->retlen += iter.req.datalen; ops->oobretlen += iter.req.ooblen; } @@ -757,6 +757,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, µn_spinand_manufacturer, + ¶gon_spinand_manufacturer, &toshiba_spinand_manufacturer, &winbond_spinand_manufacturer, }; @@ -845,7 +846,7 @@ spinand_select_op_variant(struct spinand_device *spinand, */ int spinand_match_and_init(struct spinand_device *spinand, const struct spinand_info *table, - unsigned int table_size, u8 devid) + unsigned int table_size, u16 devid) { struct nand_device *nand = spinand_to_nand(spinand); unsigned int i; diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index e6c646007cda..e99d425aa93f 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -9,11 +9,17 @@ #include <linux/mtd/spinand.h> #define SPINAND_MFR_GIGADEVICE 0xC8 + #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4) #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4) #define GD5FXGQ4UEXXG_REG_STATUS2 0xf0 +#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4) +#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4) +#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4) +#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4) + static SPINAND_OP_VARIANTS(read_cache_variants, SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), @@ -22,6 +28,14 @@ static SPINAND_OP_VARIANTS(read_cache_variants, SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); +static SPINAND_OP_VARIANTS(read_cache_variants_f, + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0)); + static SPINAND_OP_VARIANTS(write_cache_variants, SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), SPINAND_PROG_LOAD(true, 0, NULL, 0)); @@ -59,6 +73,11 @@ static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section, return 0; } +static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = { + .ecc = gd5fxgq4xa_ooblayout_ecc, + .free = gd5fxgq4xa_ooblayout_free, +}; + static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand, u8 status) { @@ -83,7 +102,7 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } -static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section, +static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { if (section) @@ -95,7 +114,7 @@ static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section, return 0; } -static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section, +static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { if (section) @@ -108,6 +127,11 @@ static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section, return 0; } +static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = { + .ecc = gd5fxgq4_variant2_ooblayout_ecc, + .free = gd5fxgq4_variant2_ooblayout_free, +}; + static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, u8 status) { @@ -150,15 +174,25 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } -static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = { - .ecc = gd5fxgq4xa_ooblayout_ecc, - .free = gd5fxgq4xa_ooblayout_free, -}; +static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) { + case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS: + return 0; -static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = { - .ecc = gd5fxgq4uexxg_ooblayout_ecc, - .free = gd5fxgq4uexxg_ooblayout_free, -}; + case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS: + return 3; + + case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */ + return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2; + } + + return -EINVAL; +} static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_INFO("GD5F1GQ4xA", 0xF1, @@ -195,25 +229,40 @@ static const struct spinand_info gigadevice_spinand_table[] = { &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout, + SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148, + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, + gd5fxgq4ufxxg_ecc_get_status)), }; static int gigadevice_spinand_detect(struct spinand_device *spinand) { u8 *id = spinand->id.data; + u16 did; int ret; /* - * For GD NANDs, There is an address byte needed to shift in before IDs - * are read out, so the first byte in raw_id is dummy. + * Earlier GDF5-series devices (A,E) return [0][MID][DID] + * Later (F) devices return [MID][DID1][DID2] */ - if (id[1] != SPINAND_MFR_GIGADEVICE) + + if (id[0] == SPINAND_MFR_GIGADEVICE) + did = (id[1] << 8) + id[2]; + else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE) + did = id[2]; + else return 0; ret = spinand_match_and_init(spinand, gigadevice_spinand_table, ARRAY_SIZE(gigadevice_spinand_table), - id[2]); + did); if (ret) return ret; diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c new file mode 100644 index 000000000000..52307681cbd0 --- /dev/null +++ b/drivers/mtd/nand/spi/paragon.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Jeff Kletsky + * + * Author: Jeff Kletsky <git-commits@allycomm.com> + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/mtd/spinand.h> + + +#define SPINAND_MFR_PARAGON 0xa1 + + +#define PN26G0XA_STATUS_ECC_BITMASK (3 << 4) + +#define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4) +#define PN26G0XA_STATUS_ECC_1_7_CORRECTED (1 << 4) +#define PN26G0XA_STATUS_ECC_ERRORED (2 << 4) +#define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4) + + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + + +static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */ + region->length = 13; + + return 0; +} + +static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 4) + return -ERANGE; + + if (section == 4) { + region->offset = 64; + region->length = 64; + } else { + region->offset = 4 + (15 * section); + region->length = 2; + } + + return 0; +} + +static int pn26g0xa_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + switch (status & PN26G0XA_STATUS_ECC_BITMASK) { + case PN26G0XA_STATUS_ECC_NONE_DETECTED: + return 0; + + case PN26G0XA_STATUS_ECC_1_7_CORRECTED: + return 7; /* Return upper limit by convention */ + + case PN26G0XA_STATUS_ECC_8_CORRECTED: + return 8; + + case PN26G0XA_STATUS_ECC_ERRORED: + return -EBADMSG; + + default: + break; + } + + return -EINVAL; +} + +static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = { + .ecc = pn26g0xa_ooblayout_ecc, + .free = pn26g0xa_ooblayout_free, +}; + + +static const struct spinand_info paragon_spinand_table[] = { + SPINAND_INFO("PN26G01A", 0xe1, + NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&pn26g0xa_ooblayout, + pn26g0xa_ecc_get_status)), + SPINAND_INFO("PN26G02A", 0xe2, + NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&pn26g0xa_ooblayout, + pn26g0xa_ecc_get_status)), +}; + +static int paragon_spinand_detect(struct spinand_device *spinand) +{ + u8 *id = spinand->id.data; + int ret; + + /* Read ID returns [0][MID][DID] */ + + if (id[1] != SPINAND_MFR_PARAGON) + return 0; + + ret = spinand_match_and_init(spinand, paragon_spinand_table, + ARRAY_SIZE(paragon_spinand_table), + id[2]); + if (ret) + return ret; + + return 1; +} + +static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = { + .detect = paragon_spinand_detect, +}; + +const struct spinand_manufacturer paragon_spinand_manufacturer = { + .id = SPINAND_MFR_PARAGON, + .name = "Paragon", + .ops = ¶gon_spinand_manuf_ops, +}; diff --git a/drivers/mtd/parsers/afs.c b/drivers/mtd/parsers/afs.c index f24d768eee30..752b6cf005f7 100644 --- a/drivers/mtd/parsers/afs.c +++ b/drivers/mtd/parsers/afs.c @@ -371,8 +371,7 @@ static int parse_afs_partitions(struct mtd_info *mtd, out_free_parts: while (i >= 0) { - if (parts[i].name) - kfree(parts[i].name); + kfree(parts[i].name); i--; } kfree(parts); diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 8e14248d2720..6de83277ce8b 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -105,11 +105,4 @@ config SPI_INTEL_SPI_PLATFORM To compile this driver as a module, choose M here: the module will be called intel-spi-platform. -config SPI_STM32_QUADSPI - tristate "STM32 Quad SPI controller" - depends on ARCH_STM32 || COMPILE_TEST - help - This enables support for the STM32 Quad SPI controller. - We only connect the NOR to this controller. - endif # MTD_SPI_NOR diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 189a15cca3ec..9c5ed03cdc19 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -8,4 +8,3 @@ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o -obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 67ade2c81b21..67f15a1f16fd 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -23,6 +23,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/sched.h> #include <linux/spi/spi.h> #include <linux/timer.h> @@ -1325,6 +1326,7 @@ static int cqspi_probe(struct platform_device *pdev) struct cqspi_st *cqspi; struct resource *res; struct resource *res_ahb; + struct reset_control *rstc, *rstc_ocp; const struct cqspi_driver_platdata *ddata; int ret; int irq; @@ -1391,6 +1393,25 @@ static int cqspi_probe(struct platform_device *pdev) goto probe_clk_failed; } + /* Obtain QSPI reset control */ + rstc = devm_reset_control_get_optional_exclusive(dev, "qspi"); + if (IS_ERR(rstc)) { + dev_err(dev, "Cannot get QSPI reset.\n"); + return PTR_ERR(rstc); + } + + rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp"); + if (IS_ERR(rstc_ocp)) { + dev_err(dev, "Cannot get QSPI OCP reset.\n"); + return PTR_ERR(rstc_ocp); + } + + reset_control_assert(rstc); + reset_control_deassert(rstc); + + reset_control_assert(rstc_ocp); + reset_control_deassert(rstc_ocp); + cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); ddata = of_device_get_match_data(dev); if (ddata && (ddata->quirks & CQSPI_NEEDS_WR_DELAY)) diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c index 5e2344768d53..b83c4ab6cd9f 100644 --- a/drivers/mtd/spi-nor/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/intel-spi-pci.c @@ -64,6 +64,7 @@ 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, 0x4b24), (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 0c2ec1c21434..03cc788511d5 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -200,7 +200,7 @@ struct sfdp_header { * register does not modify status register 2. * - 101b: QE is bit 1 of status register 2. Status register 1 is read using * Read Status instruction 05h. Status register2 is read using - * instruction 35h. QE is set via Writ Status instruction 01h with + * instruction 35h. QE is set via Write Status instruction 01h with * two data bytes where bit 1 of the second byte is one. * [...] */ @@ -1776,6 +1776,28 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor) .flags = SPI_NOR_NO_FR | SPI_S3AN, static int +is25lp256_post_bfpt_fixups(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + /* + * IS25LP256 supports 4B opcodes, but the BFPT advertises a + * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width. + * Overwrite the address width advertised by the BFPT. + */ + if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) == + BFPT_DWORD1_ADDRESS_BYTES_3_ONLY) + nor->addr_width = 4; + + return 0; +} + +static struct spi_nor_fixups is25lp256_fixups = { + .post_bfpt = is25lp256_post_bfpt_fixups, +}; + +static int mx25l25635_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt, @@ -1916,7 +1938,8 @@ static const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_4B_OPCODES) }, + SPI_NOR_4B_OPCODES) + .fixups = &is25lp256_fixups }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, @@ -1969,6 +1992,9 @@ static const struct flash_info spi_nor_ids[] = { { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096, + SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | + NO_CHIP_ERASE) }, { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, /* Micron */ @@ -2085,6 +2111,11 @@ static const struct flash_info spi_nor_ids[] = { SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, + { + "w25q16jv-im/jm", INFO(0xef7015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) }, @@ -2151,7 +2182,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); if (tmp < 0) { - dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp); + dev_err(nor->dev, "error %d reading JEDEC ID\n", tmp); return ERR_PTR(tmp); } diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c deleted file mode 100644 index 33534f9e296b..000000000000 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ /dev/null @@ -1,707 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for stm32 quadspi controller - * - * Copyright (C) 2017, STMicroelectronics - All Rights Reserved - * Author(s): Ludovic Barre author <ludovic.barre@st.com>. - */ -#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/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/spi-nor.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> - -#define QUADSPI_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_SHIFT 8 -#define CR_FTHRES_MASK GENMASK(12, 8) -#define CR_FTHRES(n) (((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK) -#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_SHIFT 24 -#define CR_PRESC_MASK GENMASK(31, 24) -#define CR_PRESC(n) (((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK) - -#define QUADSPI_DCR 0x04 -#define DCR_CSHT_SHIFT 8 -#define DCR_CSHT_MASK GENMASK(10, 8) -#define DCR_CSHT(n) (((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK) -#define DCR_FSIZE_SHIFT 16 -#define DCR_FSIZE_MASK GENMASK(20, 16) -#define DCR_FSIZE(n) (((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK) - -#define QUADSPI_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_SHIFT 8 -#define SR_FLEVEL_MASK GENMASK(13, 8) - -#define QUADSPI_FCR 0x0c -#define FCR_CTCF BIT(1) - -#define QUADSPI_DLR 0x10 - -#define QUADSPI_CCR 0x14 -#define CCR_INST_SHIFT 0 -#define CCR_INST_MASK GENMASK(7, 0) -#define CCR_INST(n) (((n) << CCR_INST_SHIFT) & CCR_INST_MASK) -#define CCR_IMODE_NONE (0U << 8) -#define CCR_IMODE_1 (1U << 8) -#define CCR_IMODE_2 (2U << 8) -#define CCR_IMODE_4 (3U << 8) -#define CCR_ADMODE_NONE (0U << 10) -#define CCR_ADMODE_1 (1U << 10) -#define CCR_ADMODE_2 (2U << 10) -#define CCR_ADMODE_4 (3U << 10) -#define CCR_ADSIZE_SHIFT 12 -#define CCR_ADSIZE_MASK GENMASK(13, 12) -#define CCR_ADSIZE(n) (((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK) -#define CCR_ABMODE_NONE (0U << 14) -#define CCR_ABMODE_1 (1U << 14) -#define CCR_ABMODE_2 (2U << 14) -#define CCR_ABMODE_4 (3U << 14) -#define CCR_ABSIZE_8 (0U << 16) -#define CCR_ABSIZE_16 (1U << 16) -#define CCR_ABSIZE_24 (2U << 16) -#define CCR_ABSIZE_32 (3U << 16) -#define CCR_DCYC_SHIFT 18 -#define CCR_DCYC_MASK GENMASK(22, 18) -#define CCR_DCYC(n) (((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK) -#define CCR_DMODE_NONE (0U << 24) -#define CCR_DMODE_1 (1U << 24) -#define CCR_DMODE_2 (2U << 24) -#define CCR_DMODE_4 (3U << 24) -#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 QUADSPI_AR 0x18 -#define QUADSPI_ABR 0x1c -#define QUADSPI_DR 0x20 -#define QUADSPI_PSMKR 0x24 -#define QUADSPI_PSMAR 0x28 -#define QUADSPI_PIR 0x2c -#define QUADSPI_LPTR 0x30 -#define LPTR_DFT_TIMEOUT 0x10 - -#define FSIZE_VAL(size) (__fls(size) - 1) - -#define STM32_MAX_MMAP_SZ SZ_256M -#define STM32_MAX_NORCHIP 2 - -#define STM32_QSPI_FIFO_SZ 32 -#define STM32_QSPI_FIFO_TIMEOUT_US 30000 -#define STM32_QSPI_BUSY_TIMEOUT_US 100000 - -struct stm32_qspi_flash { - struct spi_nor nor; - struct stm32_qspi *qspi; - u32 cs; - u32 fsize; - u32 presc; - u32 read_mode; - bool registered; - u32 prefetch_limit; -}; - -struct stm32_qspi { - struct device *dev; - void __iomem *io_base; - void __iomem *mm_base; - resource_size_t mm_size; - u32 nor_num; - struct clk *clk; - u32 clk_rate; - struct stm32_qspi_flash flash[STM32_MAX_NORCHIP]; - struct completion cmd_completion; - - /* - * to protect device configuration, could be different between - * 2 flash access (bk1, bk2) - */ - struct mutex lock; -}; - -struct stm32_qspi_cmd { - u8 addr_width; - u8 dummy; - bool tx_data; - u8 opcode; - u32 framemode; - u32 qspimode; - u32 addr; - size_t len; - void *buf; -}; - -static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi) -{ - u32 cr; - int err = 0; - - if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF) - return 0; - - reinit_completion(&qspi->cmd_completion); - cr = readl_relaxed(qspi->io_base + QUADSPI_CR); - writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR); - - if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion, - msecs_to_jiffies(1000))) - err = -ETIMEDOUT; - - writel_relaxed(cr, qspi->io_base + QUADSPI_CR); - return err; -} - -static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) -{ - u32 sr; - - return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr, - !(sr & SR_BUSY), 10, - STM32_QSPI_BUSY_TIMEOUT_US); -} - -static void stm32_qspi_set_framemode(struct spi_nor *nor, - struct stm32_qspi_cmd *cmd, bool read) -{ - u32 dmode = CCR_DMODE_1; - - cmd->framemode = CCR_IMODE_1; - - if (read) { - switch (nor->read_proto) { - default: - case SNOR_PROTO_1_1_1: - dmode = CCR_DMODE_1; - break; - case SNOR_PROTO_1_1_2: - dmode = CCR_DMODE_2; - break; - case SNOR_PROTO_1_1_4: - dmode = CCR_DMODE_4; - break; - } - } - - cmd->framemode |= cmd->tx_data ? dmode : 0; - cmd->framemode |= cmd->addr_width ? CCR_ADMODE_1 : 0; -} - -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 stm32_qspi_cmd *cmd) -{ - void (*tx_fifo)(u8 *, void __iomem *); - u32 len = cmd->len, sr; - u8 *buf = cmd->buf; - int ret; - - if (cmd->qspimode == CCR_FMODE_INDW) - tx_fifo = stm32_qspi_write_fifo; - else - tx_fifo = stm32_qspi_read_fifo; - - while (len--) { - ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, - sr, (sr & SR_FTF), 10, - STM32_QSPI_FIFO_TIMEOUT_US); - if (ret) { - dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); - return ret; - } - tx_fifo(buf++, qspi->io_base + QUADSPI_DR); - } - - return 0; -} - -static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, - const struct stm32_qspi_cmd *cmd) -{ - memcpy_fromio(cmd->buf, qspi->mm_base + cmd->addr, cmd->len); - return 0; -} - -static int stm32_qspi_tx(struct stm32_qspi *qspi, - const struct stm32_qspi_cmd *cmd) -{ - if (!cmd->tx_data) - return 0; - - if (cmd->qspimode == CCR_FMODE_MM) - return stm32_qspi_tx_mm(qspi, cmd); - - return stm32_qspi_tx_poll(qspi, cmd); -} - -static int stm32_qspi_send(struct stm32_qspi_flash *flash, - const struct stm32_qspi_cmd *cmd) -{ - struct stm32_qspi *qspi = flash->qspi; - u32 ccr, dcr, cr; - u32 last_byte; - int err; - - err = stm32_qspi_wait_nobusy(qspi); - if (err) - goto abort; - - dcr = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK; - dcr |= DCR_FSIZE(flash->fsize); - writel_relaxed(dcr, qspi->io_base + QUADSPI_DCR); - - cr = readl_relaxed(qspi->io_base + QUADSPI_CR); - cr &= ~CR_PRESC_MASK & ~CR_FSEL; - cr |= CR_PRESC(flash->presc); - cr |= flash->cs ? CR_FSEL : 0; - writel_relaxed(cr, qspi->io_base + QUADSPI_CR); - - if (cmd->tx_data) - writel_relaxed(cmd->len - 1, qspi->io_base + QUADSPI_DLR); - - ccr = cmd->framemode | cmd->qspimode; - - if (cmd->dummy) - ccr |= CCR_DCYC(cmd->dummy); - - if (cmd->addr_width) - ccr |= CCR_ADSIZE(cmd->addr_width - 1); - - ccr |= CCR_INST(cmd->opcode); - writel_relaxed(ccr, qspi->io_base + QUADSPI_CCR); - - if (cmd->addr_width && cmd->qspimode != CCR_FMODE_MM) - writel_relaxed(cmd->addr, qspi->io_base + QUADSPI_AR); - - err = stm32_qspi_tx(qspi, cmd); - if (err) - goto abort; - - if (cmd->qspimode != CCR_FMODE_MM) { - err = stm32_qspi_wait_cmd(qspi); - if (err) - goto abort; - writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR); - } else { - last_byte = cmd->addr + cmd->len; - if (last_byte > flash->prefetch_limit) - goto abort; - } - - return err; - -abort: - cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT; - writel_relaxed(cr, qspi->io_base + QUADSPI_CR); - - if (err) - dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); - - return err; -} - -static int stm32_qspi_read_reg(struct spi_nor *nor, - u8 opcode, u8 *buf, int len) -{ - struct stm32_qspi_flash *flash = nor->priv; - struct device *dev = flash->qspi->dev; - struct stm32_qspi_cmd cmd; - - dev_dbg(dev, "read_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len); - - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = opcode; - cmd.tx_data = true; - cmd.len = len; - cmd.buf = buf; - cmd.qspimode = CCR_FMODE_INDR; - - stm32_qspi_set_framemode(nor, &cmd, false); - - return stm32_qspi_send(flash, &cmd); -} - -static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode, - u8 *buf, int len) -{ - struct stm32_qspi_flash *flash = nor->priv; - struct device *dev = flash->qspi->dev; - struct stm32_qspi_cmd cmd; - - dev_dbg(dev, "write_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len); - - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = opcode; - cmd.tx_data = !!(buf && len > 0); - cmd.len = len; - cmd.buf = buf; - cmd.qspimode = CCR_FMODE_INDW; - - stm32_qspi_set_framemode(nor, &cmd, false); - - return stm32_qspi_send(flash, &cmd); -} - -static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len, - u_char *buf) -{ - struct stm32_qspi_flash *flash = nor->priv; - struct stm32_qspi *qspi = flash->qspi; - struct stm32_qspi_cmd cmd; - int err; - - dev_dbg(qspi->dev, "read(%#.2x): buf:%pK from:%#.8x len:%#zx\n", - nor->read_opcode, buf, (u32)from, len); - - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = nor->read_opcode; - cmd.addr_width = nor->addr_width; - cmd.addr = (u32)from; - cmd.tx_data = true; - cmd.dummy = nor->read_dummy; - cmd.len = len; - cmd.buf = buf; - cmd.qspimode = flash->read_mode; - - stm32_qspi_set_framemode(nor, &cmd, true); - err = stm32_qspi_send(flash, &cmd); - - return err ? err : len; -} - -static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len, - const u_char *buf) -{ - struct stm32_qspi_flash *flash = nor->priv; - struct device *dev = flash->qspi->dev; - struct stm32_qspi_cmd cmd; - int err; - - dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#zx\n", - nor->program_opcode, buf, (u32)to, len); - - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = nor->program_opcode; - cmd.addr_width = nor->addr_width; - cmd.addr = (u32)to; - cmd.tx_data = true; - cmd.len = len; - cmd.buf = (void *)buf; - cmd.qspimode = CCR_FMODE_INDW; - - stm32_qspi_set_framemode(nor, &cmd, false); - err = stm32_qspi_send(flash, &cmd); - - return err ? err : len; -} - -static int stm32_qspi_erase(struct spi_nor *nor, loff_t offs) -{ - struct stm32_qspi_flash *flash = nor->priv; - struct device *dev = flash->qspi->dev; - struct stm32_qspi_cmd cmd; - - dev_dbg(dev, "erase(%#.2x):offs:%#x\n", nor->erase_opcode, (u32)offs); - - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = nor->erase_opcode; - cmd.addr_width = nor->addr_width; - cmd.addr = (u32)offs; - cmd.qspimode = CCR_FMODE_INDW; - - stm32_qspi_set_framemode(nor, &cmd, false); - - return stm32_qspi_send(flash, &cmd); -} - -static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) -{ - struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; - u32 cr, sr, fcr = 0; - - cr = readl_relaxed(qspi->io_base + QUADSPI_CR); - sr = readl_relaxed(qspi->io_base + QUADSPI_SR); - - if ((cr & CR_TCIE) && (sr & SR_TCF)) { - /* tx complete */ - fcr |= FCR_CTCF; - complete(&qspi->cmd_completion); - } else { - dev_info_ratelimited(qspi->dev, "spurious interrupt\n"); - } - - writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR); - - return IRQ_HANDLED; -} - -static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) -{ - struct stm32_qspi_flash *flash = nor->priv; - struct stm32_qspi *qspi = flash->qspi; - - mutex_lock(&qspi->lock); - return 0; -} - -static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) -{ - struct stm32_qspi_flash *flash = nor->priv; - struct stm32_qspi *qspi = flash->qspi; - - mutex_unlock(&qspi->lock); -} - -static int stm32_qspi_flash_setup(struct stm32_qspi *qspi, - struct device_node *np) -{ - struct spi_nor_hwcaps hwcaps = { - .mask = SNOR_HWCAPS_READ | - SNOR_HWCAPS_READ_FAST | - SNOR_HWCAPS_PP, - }; - u32 width, presc, cs_num, max_rate = 0; - struct stm32_qspi_flash *flash; - struct mtd_info *mtd; - int ret; - - of_property_read_u32(np, "reg", &cs_num); - if (cs_num >= STM32_MAX_NORCHIP) - return -EINVAL; - - of_property_read_u32(np, "spi-max-frequency", &max_rate); - if (!max_rate) - return -EINVAL; - - presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1; - - if (of_property_read_u32(np, "spi-rx-bus-width", &width)) - width = 1; - - if (width == 4) - hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; - else if (width == 2) - hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2; - else if (width != 1) - return -EINVAL; - - flash = &qspi->flash[cs_num]; - flash->qspi = qspi; - flash->cs = cs_num; - flash->presc = presc; - - flash->nor.dev = qspi->dev; - spi_nor_set_flash_node(&flash->nor, np); - flash->nor.priv = flash; - mtd = &flash->nor.mtd; - - flash->nor.read = stm32_qspi_read; - flash->nor.write = stm32_qspi_write; - flash->nor.erase = stm32_qspi_erase; - flash->nor.read_reg = stm32_qspi_read_reg; - flash->nor.write_reg = stm32_qspi_write_reg; - flash->nor.prepare = stm32_qspi_prep; - flash->nor.unprepare = stm32_qspi_unprep; - - writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR); - - writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT - | CR_EN, qspi->io_base + QUADSPI_CR); - - /* - * in stm32 qspi controller, QUADSPI_DCR register has a fsize field - * which define the size of nor flash. - * if fsize is NULL, the controller can't sent spi-nor command. - * set a temporary value just to discover the nor flash with - * "spi_nor_scan". After, the right value (mtd->size) can be set. - */ - flash->fsize = FSIZE_VAL(SZ_1K); - - ret = spi_nor_scan(&flash->nor, NULL, &hwcaps); - if (ret) { - dev_err(qspi->dev, "device scan failed\n"); - return ret; - } - - flash->fsize = FSIZE_VAL(mtd->size); - flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ; - - flash->read_mode = CCR_FMODE_MM; - if (mtd->size > qspi->mm_size) - flash->read_mode = CCR_FMODE_INDR; - - writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR); - - ret = mtd_device_register(mtd, NULL, 0); - if (ret) { - dev_err(qspi->dev, "mtd device parse failed\n"); - return ret; - } - - flash->registered = true; - - dev_dbg(qspi->dev, "read mm:%s cs:%d bus:%d\n", - flash->read_mode == CCR_FMODE_MM ? "yes" : "no", cs_num, width); - - return 0; -} - -static void stm32_qspi_mtd_free(struct stm32_qspi *qspi) -{ - int i; - - for (i = 0; i < STM32_MAX_NORCHIP; i++) - if (qspi->flash[i].registered) - mtd_device_unregister(&qspi->flash[i].nor.mtd); -} - -static int stm32_qspi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *flash_np; - struct reset_control *rstc; - struct stm32_qspi *qspi; - struct resource *res; - int ret, irq; - - qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL); - if (!qspi) - return -ENOMEM; - - qspi->nor_num = of_get_child_count(dev->of_node); - if (!qspi->nor_num || qspi->nor_num > STM32_MAX_NORCHIP) - return -ENODEV; - - 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); - - 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->cmd_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); - - for_each_available_child_of_node(dev->of_node, flash_np) { - ret = stm32_qspi_flash_setup(qspi, flash_np); - if (ret) { - dev_err(dev, "unable to setup flash chip\n"); - goto err_flash; - } - } - - return 0; - -err_flash: - mutex_destroy(&qspi->lock); - stm32_qspi_mtd_free(qspi); - - clk_disable_unprepare(qspi->clk); - return ret; -} - -static int stm32_qspi_remove(struct platform_device *pdev) -{ - struct stm32_qspi *qspi = platform_get_drvdata(pdev); - - /* disable qspi */ - writel_relaxed(0, qspi->io_base + QUADSPI_CR); - - stm32_qspi_mtd_free(qspi); - mutex_destroy(&qspi->lock); - - clk_disable_unprepare(qspi->clk); - 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-quadspi", - .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/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 27709f866c23..232e8cc96f6d 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -14,7 +14,7 @@ #include <linux/of_platform.h> #include <linux/if_bridge.h> #include <linux/mdio.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/etherdevice.h> #include "qca8k.h" diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c index a76529a7662d..c2e92786608b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c @@ -1054,14 +1054,12 @@ static void cudbg_t4_fwcache(struct cudbg_init *pdbg_init, } } -static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init, - struct cudbg_buffer *dbg_buff, - struct cudbg_error *cudbg_err, - u8 mem_type) +static unsigned long cudbg_mem_region_size(struct cudbg_init *pdbg_init, + struct cudbg_error *cudbg_err, + u8 mem_type) { struct adapter *padap = pdbg_init->adap; struct cudbg_meminfo mem_info; - unsigned long size; u8 mc_idx; int rc; @@ -1075,7 +1073,16 @@ static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init, if (rc) return rc; - size = mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base; + return mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base; +} + +static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init, + struct cudbg_buffer *dbg_buff, + struct cudbg_error *cudbg_err, + u8 mem_type) +{ + unsigned long size = cudbg_mem_region_size(pdbg_init, cudbg_err, mem_type); + return cudbg_read_fw_mem(pdbg_init, dbg_buff, mem_type, size, cudbg_err); } diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 625635771b83..d60452845539 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -899,7 +899,6 @@ static int hip04_mac_probe(struct platform_device *pdev) struct of_phandle_args arg; struct net_device *ndev; struct hip04_priv *priv; - struct resource *res; int irq; int ret; @@ -912,16 +911,14 @@ static int hip04_mac_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(d, res); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); goto init_fail; } #if defined(CONFIG_HI13X1_GMAC) - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - priv->sysctrl_base = devm_ioremap_resource(d, res); + priv->sysctrl_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(priv->sysctrl_base)) { ret = PTR_ERR(priv->sysctrl_base); goto init_fail; diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index d2e019d89a6f..689f18e3100f 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -781,7 +781,6 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - struct resource *res; struct net_device *ndev; struct hisi_femac_priv *priv; struct phy_device *phy; @@ -799,15 +798,13 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) priv->dev = dev; priv->ndev = ndev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->port_base = devm_ioremap_resource(dev, res); + priv->port_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->port_base)) { ret = PTR_ERR(priv->port_base); goto out_free_netdev; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - priv->glb_base = devm_ioremap_resource(dev, res); + priv->glb_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(priv->glb_base)) { ret = PTR_ERR(priv->glb_base); goto out_free_netdev; diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index 89ef764e1c4b..349970557c52 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1097,7 +1097,6 @@ static int hix5hd2_dev_probe(struct platform_device *pdev) const struct of_device_id *of_id = NULL; struct net_device *ndev; struct hix5hd2_priv *priv; - struct resource *res; struct mii_bus *bus; const char *mac_addr; int ret; @@ -1119,15 +1118,13 @@ static int hix5hd2_dev_probe(struct platform_device *pdev) } priv->hw_cap = (unsigned long)of_id->data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(dev, res); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); goto out_free_netdev; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - priv->ctrl_base = devm_ioremap_resource(dev, res); + priv->ctrl_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(priv->ctrl_base)) { ret = PTR_ERR(priv->ctrl_base); goto out_free_netdev; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c index 09c16d88172e..bb6586d0e5af 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c @@ -754,7 +754,7 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) return (void *)misc_op; } -static int hns_dsaf_dev_match(struct device *dev, void *fwnode) +static int hns_dsaf_dev_match(struct device *dev, const void *fwnode) { return dev->fwnode == fwnode; } diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c index 918cab1c61cd..3e863a71c513 100644 --- a/drivers/net/ethernet/hisilicon/hns_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns_mdio.c @@ -417,7 +417,6 @@ static int hns_mdio_probe(struct platform_device *pdev) { struct hns_mdio_device *mdio_dev; struct mii_bus *new_bus; - struct resource *res; int ret = -ENODEV; if (!pdev) { @@ -442,8 +441,7 @@ static int hns_mdio_probe(struct platform_device *pdev) new_bus->priv = mdio_dev; new_bus->parent = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mdio_dev->vbase = devm_ioremap_resource(&pdev->dev, res); + mdio_dev->vbase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mdio_dev->vbase)) { ret = PTR_ERR(mdio_dev->vbase); return ret; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 28ec0d57941d..41c90f2ddb31 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2286,7 +2286,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) struct ice_hw *hw; int err; - /* this driver uses devres, see Documentation/driver-model/devres.txt */ + /* this driver uses devres, see Documentation/driver-model/devres.rst */ err = pcim_enable_device(pdev); if (err) return err; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index c6be599ed94d..bab94f763e2c 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -723,7 +723,7 @@ struct mtk_soc_data { #define MTK_MAX_DEVS 2 #define MTK_SGMII_PHYSPEED_AN BIT(31) -#define MTK_SGMII_PHYSPEED_MASK GENMASK(0, 2) +#define MTK_SGMII_PHYSPEED_MASK GENMASK(2, 0) #define MTK_SGMII_PHYSPEED_1000 BIT(0) #define MTK_SGMII_PHYSPEED_2500 BIT(1) #define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x)) diff --git a/drivers/net/ethernet/mediatek/mtk_sgmii.c b/drivers/net/ethernet/mediatek/mtk_sgmii.c index 136f90ce5a65..ff509d42d818 100644 --- a/drivers/net/ethernet/mediatek/mtk_sgmii.c +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c @@ -82,7 +82,7 @@ int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id) return -EINVAL; regmap_read(ss->regmap[id], ss->ana_rgc3, &val); - val &= ~GENMASK(2, 3); + val &= ~GENMASK(3, 2); mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK; val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2); regmap_write(ss->regmap[id], ss->ana_rgc3, val); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h index 879321b21616..d787bc0a4155 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h @@ -81,7 +81,6 @@ mlx5e_ktls_type_check(struct mlx5_core_dev *mdev, struct tls_crypto_info *crypto_info) { return false; } #endif -#ifdef CONFIG_MLX5_FPGA_TLS enum { MLX5_ACCEL_TLS_TX = BIT(0), MLX5_ACCEL_TLS_RX = BIT(1), @@ -103,6 +102,7 @@ struct mlx5_ifc_tls_flow_bits { u8 reserved_at_2[0x1e]; }; +#ifdef CONFIG_MLX5_FPGA_TLS int mlx5_accel_tls_add_flow(struct mlx5_core_dev *mdev, void *flow, struct tls_crypto_info *crypto_info, u32 start_offload_tcp_sn, u32 *p_swid, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 263558875f20..79d93d6c7d7a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -305,6 +305,7 @@ enum { MLX5E_RQ_STATE_ENABLED, MLX5E_RQ_STATE_AM, MLX5E_RQ_STATE_NO_CSUM_COMPLETE, + MLX5E_RQ_STATE_CSUM_FULL, /* cqe_csum_full hw bit is set */ }; struct mlx5e_cq { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c index 476dd97f7f2f..f3d98748b211 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c @@ -142,22 +142,20 @@ static int mlx5e_tx_reporter_timeout_recover(struct mlx5e_txqsq *sq) { struct mlx5_eq_comp *eq = sq->cq.mcq.eq; u32 eqe_count; - int ret; netdev_err(sq->channel->netdev, "EQ 0x%x: Cons = 0x%x, irqn = 0x%x\n", eq->core.eqn, eq->core.cons_index, eq->core.irqn); eqe_count = mlx5_eq_poll_irq_disabled(eq); - ret = eqe_count ? false : true; if (!eqe_count) { clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state); - return ret; + return -EIO; } netdev_err(sq->channel->netdev, "Recover %d eqes on EQ 0x%x\n", eqe_count, eq->core.eqn); sq->channel->stats->eq_rearm++; - return ret; + return 0; } int mlx5e_tx_reporter_timeout(struct mlx5e_txqsq *sq) @@ -264,13 +262,13 @@ static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter, err = mlx5_core_query_sq_state(priv->mdev, sq->sqn, &state); if (err) - break; + goto unlock; err = mlx5e_tx_reporter_build_diagnose_output(fmsg, sq->sqn, state, netif_xmit_stopped(sq->txq)); if (err) - break; + goto unlock; } err = devlink_fmsg_arr_pair_nest_end(fmsg); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c index 5c08891806f0..ea032f54197e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c @@ -25,23 +25,17 @@ static void fill_static_params_ctx(void *ctx, struct mlx5e_ktls_offload_context_tx *priv_tx) { struct tls_crypto_info *crypto_info = priv_tx->crypto_info; + struct tls12_crypto_info_aes_gcm_128 *info; char *initial_rn, *gcm_iv; u16 salt_sz, rec_seq_sz; char *salt, *rec_seq; u8 tls_version; - switch (crypto_info->cipher_type) { - case TLS_CIPHER_AES_GCM_128: { - struct tls12_crypto_info_aes_gcm_128 *info = - (struct tls12_crypto_info_aes_gcm_128 *)crypto_info; - - EXTRACT_INFO_FIELDS; - break; - } - default: - WARN_ON(1); + if (WARN_ON(crypto_info->cipher_type != TLS_CIPHER_AES_GCM_128)) return; - } + + info = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info; + EXTRACT_INFO_FIELDS; gcm_iv = MLX5_ADDR_OF(tls_static_params, ctx, gcm_iv); initial_rn = MLX5_ADDR_OF(tls_static_params, ctx, initial_record_number); @@ -234,24 +228,18 @@ tx_post_resync_params(struct mlx5e_txqsq *sq, u64 rcd_sn) { struct tls_crypto_info *crypto_info = priv_tx->crypto_info; + struct tls12_crypto_info_aes_gcm_128 *info; __be64 rn_be = cpu_to_be64(rcd_sn); bool skip_static_post; u16 rec_seq_sz; char *rec_seq; - switch (crypto_info->cipher_type) { - case TLS_CIPHER_AES_GCM_128: { - struct tls12_crypto_info_aes_gcm_128 *info = - (struct tls12_crypto_info_aes_gcm_128 *)crypto_info; - - rec_seq = info->rec_seq; - rec_seq_sz = sizeof(info->rec_seq); - break; - } - default: - WARN_ON(1); + if (WARN_ON(crypto_info->cipher_type != TLS_CIPHER_AES_GCM_128)) return; - } + + info = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info; + rec_seq = info->rec_seq; + rec_seq_sz = sizeof(info->rec_seq); skip_static_post = !memcmp(rec_seq, &rn_be, rec_seq_sz); if (!skip_static_post) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 6d0ae87c8ded..47eea6b3a1c3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -889,6 +889,9 @@ int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params, if (err) goto err_destroy_rq; + if (MLX5_CAP_ETH(c->mdev, cqe_checksum_full)) + __set_bit(MLX5E_RQ_STATE_CSUM_FULL, &c->rq.state); + if (params->rx_dim_enabled) __set_bit(MLX5E_RQ_STATE_AM, &c->rq.state); @@ -3390,10 +3393,9 @@ static int mlx5e_modify_channels_vsd(struct mlx5e_channels *chs, bool vsd) return 0; } -static int mlx5e_setup_tc_mqprio(struct net_device *netdev, +static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv, struct tc_mqprio_qopt *mqprio) { - struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_channels new_channels = {}; u8 tc = mqprio->num_tc; int err = 0; @@ -3475,7 +3477,7 @@ static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, priv, priv, true); #endif case TC_SETUP_QDISC_MQPRIO: - return mlx5e_setup_tc_mqprio(dev, type_data); + return mlx5e_setup_tc_mqprio(priv, type_data); default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 10ef90a7bddd..7245d287633d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1175,6 +1175,8 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data, } } +static LIST_HEAD(mlx5e_rep_block_cb_list); + static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) { @@ -1182,7 +1184,8 @@ static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type, switch (type) { case TC_SETUP_BLOCK: - return flow_block_cb_setup_simple(type_data, NULL, + return flow_block_cb_setup_simple(type_data, + &mlx5e_rep_block_cb_list, mlx5e_rep_setup_tc_cb, priv, priv, true); default: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 56a2f4666c47..ac6e586d403d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -923,8 +923,14 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, if (unlikely(get_ip_proto(skb, network_depth, proto) == IPPROTO_SCTP)) goto csum_unnecessary; + stats->csum_complete++; skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = csum_unfold((__force __sum16)cqe->check_sum); + + if (test_bit(MLX5E_RQ_STATE_CSUM_FULL, &rq->state)) + return; /* CQE csum covers all received bytes */ + + /* csum might need some fixups ...*/ if (network_depth > ETH_HLEN) /* CQE csum is calculated from the IP header and does * not cover VLAN headers (if present). This will add @@ -935,7 +941,6 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, skb->csum); mlx5e_skb_padding_csum(skb, network_depth, proto, stats); - stats->csum_complete++; return; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 7281f8d6cba6..3b04d8927fb1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1946,11 +1946,6 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) esw->enabled_vports = 0; esw->mode = MLX5_ESWITCH_NONE; esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE; - if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) && - MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)) - esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC; - else - esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE; dev->priv.eswitch = esw; return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 8ed4497929b9..957d9b09dc3f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1785,8 +1785,8 @@ static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { u8 action[MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)] = {}; + static const struct mlx5_flow_spec spec = {}; struct mlx5_flow_act flow_act = {}; - struct mlx5_flow_spec spec = {}; int err = 0; MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET); @@ -2131,6 +2131,12 @@ int esw_offloads_init(struct mlx5_eswitch *esw) { int err; + if (MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat) && + MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, decap)) + esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC; + else + esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE; + err = esw_offloads_steering_init(esw); if (err) return err; @@ -2187,6 +2193,7 @@ void esw_offloads_cleanup(struct mlx5_eswitch *esw) if (mlx5_eswitch_vport_match_metadata_enabled(esw)) mlx5_eswitch_disable_passing_vport_metadata(esw); esw_offloads_steering_cleanup(esw); + esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE; } static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index faf197d53743..6bfaaab362dc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -711,7 +711,9 @@ static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num, prof->init(mdev, netdev, prof, ipriv); - mlx5e_attach_netdev(epriv); + err = mlx5e_attach_netdev(epriv); + if (err) + goto detach; netif_carrier_off(netdev); /* set rdma_netdev func pointers */ @@ -727,6 +729,11 @@ static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num, return 0; +detach: + prof->cleanup(epriv); + if (ipriv->sub_interface) + return err; + mlx5e_destroy_mdev_resources(mdev); destroy_ht: mlx5i_pkey_qpn_ht_cleanup(netdev); return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c index be69c1d7941a..48b5c847b642 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c @@ -98,27 +98,12 @@ static int mlx5_set_entropy(struct mlx5_tun_entropy *tun_entropy, */ if (entropy_flags.gre_calc_supported && reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE) { - /* Other applications may change the global FW entropy - * calculations settings. Check that the current entropy value - * is the negative of the updated value. - */ - if (entropy_flags.force_enabled && - enable == entropy_flags.gre_calc_enabled) { - mlx5_core_warn(tun_entropy->mdev, - "Unexpected GRE entropy calc setting - expected %d", - !entropy_flags.gre_calc_enabled); - return -EOPNOTSUPP; - } - err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev, enable, - entropy_flags.force_supported); + if (!entropy_flags.force_supported) + return 0; + err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev, + enable, !enable); if (err) return err; - /* if we turn on the entropy we don't need to force it anymore */ - if (entropy_flags.force_supported && enable) { - err = mlx5_set_port_gre_tun_entropy_calc(tun_entropy->mdev, 1, 0); - if (err) - return err; - } } else if (entropy_flags.calc_supported) { /* Other applications may change the global FW entropy * calculations settings. Check that the current entropy value diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 7e725fa60347..faa8ba012a37 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -368,15 +368,12 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, break; default: - /* Other ethtype - we need check the masks for the - * remainder of the key to ensure we can offload. - */ - if (nfp_flower_check_higher_than_mac(flow)) { - NL_SET_ERR_MSG_MOD(extack, "unsupported offload: non IPv4/IPv6 offload with L3/L4 matches not supported"); - return -EOPNOTSUPP; - } - break; + NL_SET_ERR_MSG_MOD(extack, "unsupported offload: match on given EtherType is not supported"); + return -EOPNOTSUPP; } + } else if (nfp_flower_check_higher_than_mac(flow)) { + NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot match above L2 without specified EtherType"); + return -EOPNOTSUPP; } if (basic.mask && basic.mask->ip_proto) { @@ -389,18 +386,15 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, key_layer |= NFP_FLOWER_LAYER_TP; key_size += sizeof(struct nfp_flower_tp_ports); break; - default: - /* Other ip proto - we need check the masks for the - * remainder of the key to ensure we can offload. - */ - if (nfp_flower_check_higher_than_l3(flow)) { - NL_SET_ERR_MSG_MOD(extack, "unsupported offload: unknown IP protocol with L4 matches not supported"); - return -EOPNOTSUPP; - } - break; } } + if (!(key_layer & NFP_FLOWER_LAYER_TP) && + nfp_flower_check_higher_than_l3(flow)) { + NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot match on L4 information without specified IP protocol type"); + return -EOPNOTSUPP; + } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_TCP)) { struct flow_match_tcp tcp; u32 tcp_flags; diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h index 10429b05f932..9f0b9a9e63b3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/descs.h +++ b/drivers/net/ethernet/stmicro/stmmac/descs.h @@ -123,7 +123,7 @@ #define ETDES1_BUFFER2_SIZE_SHIFT 16 /* Extended Receive descriptor definitions */ -#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(2, 6) +#define ERDES4_IP_PAYLOAD_TYPE_MASK GENMASK(6, 2) #define ERDES4_IP_HDR_ERR BIT(3) #define ERDES4_IP_PAYLOAD_ERR BIT(4) #define ERDES4_IP_CSUM_BYPASSED BIT(5) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index 2856f3fe5266..4083019c547a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -192,7 +192,7 @@ static const struct emac_variant emac_variant_h6 = { /* Used in RX_CTL1*/ #define EMAC_RX_MD BIT(1) -#define EMAC_RX_TH_MASK GENMASK(4, 5) +#define EMAC_RX_TH_MASK GENMASK(5, 4) #define EMAC_RX_TH_32 0 #define EMAC_RX_TH_64 (0x1 << 4) #define EMAC_RX_TH_96 (0x2 << 4) @@ -203,7 +203,7 @@ static const struct emac_variant emac_variant_h6 = { /* Used in TX_CTL1*/ #define EMAC_TX_MD BIT(1) #define EMAC_TX_NEXT_FRM BIT(2) -#define EMAC_TX_TH_MASK GENMASK(8, 10) +#define EMAC_TX_TH_MASK GENMASK(10, 8) #define EMAC_TX_TH_64 0 #define EMAC_TX_TH_128 (0x1 << 8) #define EMAC_TX_TH_192 (0x2 << 8) diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c index 48e0924259f5..4e184eecc8e1 100644 --- a/drivers/net/ethernet/ti/cpsw-phy-sel.c +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -151,9 +151,9 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv, } static struct platform_driver cpsw_phy_sel_driver; -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return dev->of_node == node && dev->driver == &cpsw_phy_sel_driver.driver; } diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 0ca2a1a254de..a65edd2770e6 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -138,8 +138,8 @@ struct submit_info { struct cpdma_chan *chan; int directed; void *token; - void *data; - int flags; + void *data_virt; + dma_addr_t data_dma; int len; }; @@ -1043,12 +1043,12 @@ static int cpdma_chan_submit_si(struct submit_info *si) mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; cpdma_desc_to_port(chan, mode, si->directed); - if (si->flags & CPDMA_DMA_EXT_MAP) { - buffer = (dma_addr_t)si->data; + if (si->data_dma) { + buffer = si->data_dma; dma_sync_single_for_device(ctlr->dev, buffer, len, chan->dir); swlen |= CPDMA_DMA_EXT_MAP; } else { - buffer = dma_map_single(ctlr->dev, si->data, len, chan->dir); + buffer = dma_map_single(ctlr->dev, si->data_virt, len, chan->dir); ret = dma_mapping_error(ctlr->dev, buffer); if (ret) { cpdma_desc_free(ctlr->pool, desc, 1); @@ -1086,10 +1086,10 @@ int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data, si.chan = chan; si.token = token; - si.data = data; + si.data_virt = data; + si.data_dma = 0; si.len = len; si.directed = directed; - si.flags = 0; spin_lock_irqsave(&chan->lock, flags); if (chan->state == CPDMA_STATE_TEARDOWN) { @@ -1111,10 +1111,10 @@ int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token, si.chan = chan; si.token = token; - si.data = (void *)data; + si.data_virt = NULL; + si.data_dma = data; si.len = len; si.directed = directed; - si.flags = CPDMA_DMA_EXT_MAP; spin_lock_irqsave(&chan->lock, flags); if (chan->state == CPDMA_STATE_TEARDOWN) { @@ -1136,10 +1136,10 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, si.chan = chan; si.token = token; - si.data = data; + si.data_virt = data; + si.data_dma = 0; si.len = len; si.directed = directed; - si.flags = 0; spin_lock_irqsave(&chan->lock, flags); if (chan->state != CPDMA_STATE_ACTIVE) { @@ -1161,10 +1161,10 @@ int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token, si.chan = chan; si.token = token; - si.data = (void *)data; + si.data_virt = NULL; + si.data_dma = data; si.len = len; si.directed = directed; - si.flags = CPDMA_DMA_EXT_MAP; spin_lock_irqsave(&chan->lock, flags); if (chan->state != CPDMA_STATE_ACTIVE) { diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 5f4ece0d5a73..ae27be85e363 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1371,7 +1371,7 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) return -EOPNOTSUPP; } -static int match_first_device(struct device *dev, void *data) +static int match_first_device(struct device *dev, const void *data) { if (dev->parent && dev->parent->of_node) return of_device_is_compatible(dev->parent->of_node, diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index c50a9772f4af..8479a440527b 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -694,10 +694,10 @@ err_out: * should provide a "tc35815-mac" device with a MAC address in its * platform_data. */ -static int tc35815_mac_match(struct device *dev, void *data) +static int tc35815_mac_match(struct device *dev, const void *data) { struct platform_device *plat_dev = to_platform_device(dev); - struct pci_dev *pci_dev = data; + const struct pci_dev *pci_dev = data; unsigned int id = pci_dev->irq; return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 53878908adf4..6b5cb87f3866 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -56,19 +56,19 @@ EXPORT_SYMBOL_GPL(phy_10gbit_features); __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_fec_features) __ro_after_init; EXPORT_SYMBOL_GPL(phy_10gbit_fec_features); -static const int phy_basic_ports_array[] = { +const int phy_basic_ports_array[3] = { ETHTOOL_LINK_MODE_Autoneg_BIT, ETHTOOL_LINK_MODE_TP_BIT, ETHTOOL_LINK_MODE_MII_BIT, }; EXPORT_SYMBOL_GPL(phy_basic_ports_array); -static const int phy_fibre_port_array[] = { +const int phy_fibre_port_array[1] = { ETHTOOL_LINK_MODE_FIBRE_BIT, }; EXPORT_SYMBOL_GPL(phy_fibre_port_array); -static const int phy_all_ports_features_array[] = { +const int phy_all_ports_features_array[7] = { ETHTOOL_LINK_MODE_Autoneg_BIT, ETHTOOL_LINK_MODE_TP_BIT, ETHTOOL_LINK_MODE_MII_BIT, diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index bd3c80b0bc77..de3b57d09d0c 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -64,7 +64,6 @@ MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>"); MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE)); -MODULE_SOFTDEP("pre: arc4"); MODULE_VERSION("1.0.2"); #define SHA1_PAD_SIZE 40 diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 81caa3782ec0..3bdda1c98339 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -598,7 +598,7 @@ enum ht_channel_width { HT_CHANNEL_WIDTH_MAX, }; -/* Ref: 802.11i sepc D10.0 7.3.2.25.1 +/* Ref: 802.11i spec D10.0 7.3.2.25.1 * Cipher Suites Encryption Algorithms */ enum rt_enc_alg { diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index c7892c3da91f..ac5d945be88a 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -76,7 +76,7 @@ static struct bus_type nvmem_bus_type = { .name = "nvmem", }; -static int of_nvmem_match(struct device *dev, void *nvmem_np) +static int of_nvmem_match(struct device *dev, const void *nvmem_np) { return dev->of_node == nvmem_np; } diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 3b67896d9d74..44f53496cab1 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -281,7 +281,7 @@ unregister: EXPORT_SYMBOL(of_mdiobus_register); /* Helper function for of_phy_find_device */ -static int of_phy_match(struct device *dev, void *phy_np) +static int of_phy_match(struct device *dev, const void *phy_np) { return dev->of_node == phy_np; } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index efbff44581b3..7801e25e6895 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -37,7 +37,7 @@ static const struct of_device_id of_skipped_node_table[] = { {} /* Empty terminated list */ }; -static int of_dev_node_match(struct device *dev, void *data) +static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0e8e2c186f50..f9ef7ad3f75d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -64,7 +64,7 @@ static struct resource *get_pci_domain_busn_res(int domain_nr) return &r->res; } -static int find_anything(struct device *dev, void *data) +static int find_anything(struct device *dev, const void *data) { return 1; } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 5c7922612733..7f4e65872b8d 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -236,10 +236,10 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, } EXPORT_SYMBOL(pci_get_domain_bus_and_slot); -static int match_pci_dev_by_id(struct device *dev, void *data) +static int match_pci_dev_by_id(struct device *dev, const void *data) { struct pci_dev *pdev = to_pci_dev(dev); - struct pci_device_id *id = data; + const struct pci_device_id *id = data; if (pci_match_one_device(id, pdev)) return 1; diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile index 068729bf4f86..ea8962645e49 100644 --- a/drivers/pinctrl/aspeed/Makefile +++ b/drivers/pinctrl/aspeed/Makefile @@ -2,6 +2,6 @@ # Aspeed pinctrl support ccflags-y += $(call cc-option,-Woverride-init) -obj-$(CONFIG_PINCTRL_ASPEED) += pinctrl-aspeed.o +obj-$(CONFIG_PINCTRL_ASPEED) += pinctrl-aspeed.o pinmux-aspeed.o obj-$(CONFIG_PINCTRL_ASPEED_G4) += pinctrl-aspeed-g4.o obj-$(CONFIG_PINCTRL_ASPEED_G5) += pinctrl-aspeed-g5.o diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c index 73e2c9c0e549..384396cbb22d 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c @@ -18,9 +18,35 @@ #include "../core.h" #include "../pinctrl-utils.h" +#include "pinmux-aspeed.h" #include "pinctrl-aspeed.h" /* + * The "Multi-function Pins Mapping and Control" table in the SoC datasheet + * references registers by the device/offset mnemonic. The register macros + * below are named the same way to ease transcription and verification (as + * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions + * reference registers beyond those dedicated to pinmux, such as the system + * reset control and MAC clock configuration registers. + */ +#define SCU2C 0x2C /* Misc. Control Register */ +#define SCU3C 0x3C /* System Reset Control/Status Register */ +#define SCU48 0x48 /* MAC Interface Clock Delay Setting */ +#define HW_STRAP1 0x70 /* AST2400 strapping is 33 bits, is split */ +#define HW_REVISION_ID 0x7C /* Silicon revision ID register */ +#define SCU80 0x80 /* Multi-function Pin Control #1 */ +#define SCU84 0x84 /* Multi-function Pin Control #2 */ +#define SCU88 0x88 /* Multi-function Pin Control #3 */ +#define SCU8C 0x8C /* Multi-function Pin Control #4 */ +#define SCU90 0x90 /* Multi-function Pin Control #5 */ +#define SCU94 0x94 /* Multi-function Pin Control #6 */ +#define SCUA0 0xA0 /* Multi-function Pin Control #7 */ +#define SCUA4 0xA4 /* Multi-function Pin Control #8 */ +#define SCUA8 0xA8 /* Multi-function Pin Control #9 */ +#define SCUAC 0xAC /* Multi-function Pin Control #10 */ +#define HW_STRAP2 0xD0 /* Strapping */ + +/* * Uses undefined macros for symbol naming and references, eg GPIOA0, MAC1LINK, * TIMER3 etc. * @@ -2386,13 +2412,73 @@ static const struct aspeed_pin_config aspeed_g4_configs[] = { { PIN_CONFIG_INPUT_DEBOUNCE, { C14, B14 }, SCUA8, 27 }, }; +static int aspeed_g4_sig_expr_set(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr, + bool enable) +{ + int ret; + int i; + + for (i = 0; i < expr->ndescs; i++) { + const struct aspeed_sig_desc *desc = &expr->descs[i]; + u32 pattern = enable ? desc->enable : desc->disable; + u32 val = (pattern << __ffs(desc->mask)); + + if (!ctx->maps[desc->ip]) + return -ENODEV; + + /* + * Strap registers are configured in hardware or by early-boot + * firmware. Treat them as read-only despite that we can write + * them. This may mean that certain functions cannot be + * deconfigured and is the reason we re-evaluate after writing + * all descriptor bits. + * + * Port D and port E GPIO loopback modes are the only exception + * as those are commonly used with front-panel buttons to allow + * normal operation of the host when the BMC is powered off or + * fails to boot. Once the BMC has booted, the loopback mode + * must be disabled for the BMC to control host power-on and + * reset. + */ + if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 && + !(desc->mask & (BIT(21) | BIT(22)))) + continue; + + if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2) + continue; + + ret = regmap_update_bits(ctx->maps[desc->ip], desc->reg, + desc->mask, val); + + if (ret) + return ret; + } + + ret = aspeed_sig_expr_eval(ctx, expr, enable); + if (ret < 0) + return ret; + + if (!ret) + return -EPERM; + + return 0; +} + +static const struct aspeed_pinmux_ops aspeed_g4_ops = { + .set = aspeed_g4_sig_expr_set, +}; + static struct aspeed_pinctrl_data aspeed_g4_pinctrl_data = { .pins = aspeed_g4_pins, .npins = ARRAY_SIZE(aspeed_g4_pins), - .groups = aspeed_g4_groups, - .ngroups = ARRAY_SIZE(aspeed_g4_groups), - .functions = aspeed_g4_functions, - .nfunctions = ARRAY_SIZE(aspeed_g4_functions), + .pinmux = { + .ops = &aspeed_g4_ops, + .groups = aspeed_g4_groups, + .ngroups = ARRAY_SIZE(aspeed_g4_groups), + .functions = aspeed_g4_functions, + .nfunctions = ARRAY_SIZE(aspeed_g4_functions), + }, .configs = aspeed_g4_configs, .nconfigs = ARRAY_SIZE(aspeed_g4_configs), }; diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index aa7e148b38bb..053101f795a2 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -21,6 +21,32 @@ #include "../pinctrl-utils.h" #include "pinctrl-aspeed.h" +/* + * The "Multi-function Pins Mapping and Control" table in the SoC datasheet + * references registers by the device/offset mnemonic. The register macros + * below are named the same way to ease transcription and verification (as + * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions + * reference registers beyond those dedicated to pinmux, such as the system + * reset control and MAC clock configuration registers. The AST2500 goes a step + * further and references registers in the graphics IP block. + */ +#define SCU2C 0x2C /* Misc. Control Register */ +#define SCU3C 0x3C /* System Reset Control/Status Register */ +#define SCU48 0x48 /* MAC Interface Clock Delay Setting */ +#define HW_STRAP1 0x70 /* AST2400 strapping is 33 bits, is split */ +#define HW_REVISION_ID 0x7C /* Silicon revision ID register */ +#define SCU80 0x80 /* Multi-function Pin Control #1 */ +#define SCU84 0x84 /* Multi-function Pin Control #2 */ +#define SCU88 0x88 /* Multi-function Pin Control #3 */ +#define SCU8C 0x8C /* Multi-function Pin Control #4 */ +#define SCU90 0x90 /* Multi-function Pin Control #5 */ +#define SCU94 0x94 /* Multi-function Pin Control #6 */ +#define SCUA0 0xA0 /* Multi-function Pin Control #7 */ +#define SCUA4 0xA4 /* Multi-function Pin Control #8 */ +#define SCUA8 0xA8 /* Multi-function Pin Control #9 */ +#define SCUAC 0xAC /* Multi-function Pin Control #10 */ +#define HW_STRAP2 0xD0 /* Strapping */ + #define ASPEED_G5_NR_PINS 236 #define COND1 { ASPEED_IP_SCU, SCU90, BIT(6), 0, 0 } @@ -573,6 +599,8 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO); SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); SS_PIN_DECL(N4, GPIOJ3, SGPMI); +FUNC_GROUP_DECL(SGPM, R2, L2, N3, N4); + #define N5 76 SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12)); SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8)); @@ -2123,6 +2151,7 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = { ASPEED_PINCTRL_GROUP(SD2), ASPEED_PINCTRL_GROUP(SDA1), ASPEED_PINCTRL_GROUP(SDA2), + ASPEED_PINCTRL_GROUP(SGPM), ASPEED_PINCTRL_GROUP(SGPS1), ASPEED_PINCTRL_GROUP(SGPS2), ASPEED_PINCTRL_GROUP(SIOONCTRL), @@ -2292,6 +2321,7 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = { ASPEED_PINCTRL_FUNC(SD2), ASPEED_PINCTRL_FUNC(SDA1), ASPEED_PINCTRL_FUNC(SDA2), + ASPEED_PINCTRL_FUNC(SGPM), ASPEED_PINCTRL_FUNC(SGPS1), ASPEED_PINCTRL_FUNC(SGPS2), ASPEED_PINCTRL_FUNC(SIOONCTRL), @@ -2477,13 +2507,98 @@ static struct aspeed_pin_config aspeed_g5_configs[] = { { PIN_CONFIG_INPUT_DEBOUNCE, { A20, B19 }, SCUA8, 27 }, }; +/** + * Configure a pin's signal by applying an expression's descriptor state for + * all descriptors in the expression. + * + * @ctx: The pinmux context + * @expr: The expression associated with the function whose signal is to be + * configured + * @enable: true to enable an function's signal through a pin's signal + * expression, false to disable the function's signal + * + * Return: 0 if the expression is configured as requested and a negative error + * code otherwise + */ +static int aspeed_g5_sig_expr_set(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr, + bool enable) +{ + int ret; + int i; + + for (i = 0; i < expr->ndescs; i++) { + const struct aspeed_sig_desc *desc = &expr->descs[i]; + u32 pattern = enable ? desc->enable : desc->disable; + u32 val = (pattern << __ffs(desc->mask)); + + if (!ctx->maps[desc->ip]) + return -ENODEV; + + /* + * Strap registers are configured in hardware or by early-boot + * firmware. Treat them as read-only despite that we can write + * them. This may mean that certain functions cannot be + * deconfigured and is the reason we re-evaluate after writing + * all descriptor bits. + * + * Port D and port E GPIO loopback modes are the only exception + * as those are commonly used with front-panel buttons to allow + * normal operation of the host when the BMC is powered off or + * fails to boot. Once the BMC has booted, the loopback mode + * must be disabled for the BMC to control host power-on and + * reset. + */ + if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 && + !(desc->mask & (BIT(21) | BIT(22)))) + continue; + + if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2) + continue; + + /* On AST2500, Set bits in SCU70 are cleared from SCU7C */ + if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1) { + u32 value = ~val & desc->mask; + + if (value) { + ret = regmap_write(ctx->maps[desc->ip], + HW_REVISION_ID, value); + if (ret < 0) + return ret; + } + } + + ret = regmap_update_bits(ctx->maps[desc->ip], desc->reg, + desc->mask, val); + + if (ret) + return ret; + } + + ret = aspeed_sig_expr_eval(ctx, expr, enable); + if (ret < 0) + return ret; + + if (!ret) + return -EPERM; + + return 0; +} + +static const struct aspeed_pinmux_ops aspeed_g5_ops = { + .set = aspeed_g5_sig_expr_set, +}; + static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = { .pins = aspeed_g5_pins, .npins = ARRAY_SIZE(aspeed_g5_pins), - .groups = aspeed_g5_groups, - .ngroups = ARRAY_SIZE(aspeed_g5_groups), - .functions = aspeed_g5_functions, - .nfunctions = ARRAY_SIZE(aspeed_g5_functions), + .pinmux = { + .ops = &aspeed_g5_ops, + .groups = aspeed_g5_groups, + .ngroups = ARRAY_SIZE(aspeed_g5_groups), + .functions = aspeed_g5_functions, + .nfunctions = ARRAY_SIZE(aspeed_g5_functions), + }, .configs = aspeed_g5_configs, .nconfigs = ARRAY_SIZE(aspeed_g5_configs), }; @@ -2539,7 +2654,7 @@ static int aspeed_g5_pinctrl_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "No GFX phandle found, some mux configurations may fail\n"); map = NULL; } - aspeed_g5_pinctrl_data.maps[ASPEED_IP_GFX] = map; + aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_GFX] = map; node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 1); if (node) { @@ -2553,7 +2668,7 @@ static int aspeed_g5_pinctrl_probe(struct platform_device *pdev) map = NULL; } of_node_put(node); - aspeed_g5_pinctrl_data.maps[ASPEED_IP_LPC] = map; + aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_LPC] = map; return aspeed_pinctrl_probe(pdev, &aspeed_g5_pinctrl_desc, &aspeed_g5_pinctrl_data); diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c index 4c775b8ffdc4..535db3de490b 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c @@ -10,17 +10,11 @@ #include "../core.h" #include "pinctrl-aspeed.h" -static const char *const aspeed_pinmux_ips[] = { - [ASPEED_IP_SCU] = "SCU", - [ASPEED_IP_GFX] = "GFX", - [ASPEED_IP_LPC] = "LPC", -}; - int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->ngroups; + return pdata->pinmux.ngroups; } const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev, @@ -28,7 +22,7 @@ const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev, { struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->groups[group].name; + return pdata->pinmux.groups[group].name; } int aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, @@ -37,8 +31,8 @@ int aspeed_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, { struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - *pins = &pdata->groups[group].pins[0]; - *npins = pdata->groups[group].npins; + *pins = &pdata->pinmux.groups[group].pins[0]; + *npins = pdata->pinmux.groups[group].npins; return 0; } @@ -53,7 +47,7 @@ int aspeed_pinmux_get_fn_count(struct pinctrl_dev *pctldev) { struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->nfunctions; + return pdata->pinmux.nfunctions; } const char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev, @@ -61,7 +55,7 @@ const char *aspeed_pinmux_get_fn_name(struct pinctrl_dev *pctldev, { struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - return pdata->functions[function].name; + return pdata->pinmux.functions[function].name; } int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev, @@ -71,208 +65,38 @@ int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev, { struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - *groups = pdata->functions[function].groups; - *num_groups = pdata->functions[function].ngroups; + *groups = pdata->pinmux.functions[function].groups; + *num_groups = pdata->pinmux.functions[function].ngroups; return 0; } -static inline void aspeed_sig_desc_print_val( - const struct aspeed_sig_desc *desc, bool enable, u32 rv) -{ - pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n", - aspeed_pinmux_ips[desc->ip], desc->reg, - desc->mask, enable ? desc->enable : desc->disable, - (rv & desc->mask) >> __ffs(desc->mask), rv); -} - -/** - * Query the enabled or disabled state of a signal descriptor - * - * @desc: The signal descriptor of interest - * @enabled: True to query the enabled state, false to query disabled state - * @map: The IP block's regmap instance - * - * Return: 1 if the descriptor's bitfield is configured to the state - * selected by @enabled, 0 if not, and less than zero if an unrecoverable - * failure occurred - * - * Evaluation of descriptor state is non-trivial in that it is not a binary - * outcome: The bitfields can be greater than one bit in size and thus can take - * a value that is neither the enabled nor disabled state recorded in the - * descriptor (typically this means a different function to the one of interest - * is enabled). Thus we must explicitly test for either condition as required. - */ -static int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, - bool enabled, struct regmap *map) +static int aspeed_sig_expr_enable(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr) { int ret; - unsigned int raw; - u32 want; - if (!map) - return -ENODEV; - - ret = regmap_read(map, desc->reg, &raw); - if (ret) - return ret; - - aspeed_sig_desc_print_val(desc, enabled, raw); - want = enabled ? desc->enable : desc->disable; - - return ((raw & desc->mask) >> __ffs(desc->mask)) == want; -} - -/** - * Query the enabled or disabled state for a mux function's signal on a pin - * - * @expr: An expression controlling the signal for a mux function on a pin - * @enabled: True to query the enabled state, false to query disabled state - * @maps: The list of regmap instances - * - * Return: 1 if the expression composed by @enabled evaluates true, 0 if not, - * and less than zero if an unrecoverable failure occurred. - * - * A mux function is enabled or disabled if the function's signal expression - * for each pin in the function's pin group evaluates true for the desired - * state. An signal expression evaluates true if all of its associated signal - * descriptors evaluate true for the desired state. - * - * If an expression's state is described by more than one bit, either through - * multi-bit bitfields in a single signal descriptor or through multiple signal - * descriptors of a single bit then it is possible for the expression to be in - * neither the enabled nor disabled state. Thus we must explicitly test for - * either condition as required. - */ -static int aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr, - bool enabled, struct regmap * const *maps) -{ - int i; - int ret; - - for (i = 0; i < expr->ndescs; i++) { - const struct aspeed_sig_desc *desc = &expr->descs[i]; - - ret = aspeed_sig_desc_eval(desc, enabled, maps[desc->ip]); - if (ret <= 0) - return ret; - } - - return 1; -} - -/** - * Configure a pin's signal by applying an expression's descriptor state for - * all descriptors in the expression. - * - * @expr: The expression associated with the function whose signal is to be - * configured - * @enable: true to enable an function's signal through a pin's signal - * expression, false to disable the function's signal - * @maps: The list of regmap instances for pinmux register access. - * - * Return: 0 if the expression is configured as requested and a negative error - * code otherwise - */ -static int aspeed_sig_expr_set(const struct aspeed_sig_expr *expr, - bool enable, struct regmap * const *maps) -{ - int ret; - int i; - - for (i = 0; i < expr->ndescs; i++) { - const struct aspeed_sig_desc *desc = &expr->descs[i]; - u32 pattern = enable ? desc->enable : desc->disable; - u32 val = (pattern << __ffs(desc->mask)); - - if (!maps[desc->ip]) - return -ENODEV; - - /* - * Strap registers are configured in hardware or by early-boot - * firmware. Treat them as read-only despite that we can write - * them. This may mean that certain functions cannot be - * deconfigured and is the reason we re-evaluate after writing - * all descriptor bits. - * - * Port D and port E GPIO loopback modes are the only exception - * as those are commonly used with front-panel buttons to allow - * normal operation of the host when the BMC is powered off or - * fails to boot. Once the BMC has booted, the loopback mode - * must be disabled for the BMC to control host power-on and - * reset. - */ - if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1 && - !(desc->mask & (BIT(21) | BIT(22)))) - continue; - - if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP2) - continue; - - /* On AST2500, Set bits in SCU7C are cleared from SCU70 */ - if (desc->ip == ASPEED_IP_SCU && desc->reg == HW_STRAP1) { - unsigned int rev_id; - - ret = regmap_read(maps[ASPEED_IP_SCU], - HW_REVISION_ID, &rev_id); - if (ret < 0) - return ret; - - if (0x04 == (rev_id >> 24)) { - u32 value = ~val & desc->mask; - - if (value) { - ret = regmap_write(maps[desc->ip], - HW_REVISION_ID, value); - if (ret < 0) - return ret; - } - } - } - - ret = regmap_update_bits(maps[desc->ip], desc->reg, - desc->mask, val); - - if (ret) - return ret; - } - - ret = aspeed_sig_expr_eval(expr, enable, maps); - if (ret < 0) - return ret; - - if (!ret) - return -EPERM; - - return 0; -} - -static int aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr, - struct regmap * const *maps) -{ - int ret; - - ret = aspeed_sig_expr_eval(expr, true, maps); + ret = aspeed_sig_expr_eval(ctx, expr, true); if (ret < 0) return ret; if (!ret) - return aspeed_sig_expr_set(expr, true, maps); + return aspeed_sig_expr_set(ctx, expr, true); return 0; } -static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr, - struct regmap * const *maps) +static int aspeed_sig_expr_disable(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr) { int ret; - ret = aspeed_sig_expr_eval(expr, true, maps); + ret = aspeed_sig_expr_eval(ctx, expr, true); if (ret < 0) return ret; if (ret) - return aspeed_sig_expr_set(expr, false, maps); + return aspeed_sig_expr_set(ctx, expr, false); return 0; } @@ -280,13 +104,13 @@ static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr, /** * Disable a signal on a pin by disabling all provided signal expressions. * + * @ctx: The pinmux context * @exprs: The list of signal expressions (from a priority level on a pin) - * @maps: The list of regmap instances for pinmux register access. * * Return: 0 if all expressions are disabled, otherwise a negative error code */ -static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs, - struct regmap * const *maps) +static int aspeed_disable_sig(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr **exprs) { int ret = 0; @@ -294,7 +118,7 @@ static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs, return true; while (*exprs && !ret) { - ret = aspeed_sig_expr_disable(*exprs, maps); + ret = aspeed_sig_expr_disable(ctx, *exprs); exprs++; } @@ -395,9 +219,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, int ret; const struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - const struct aspeed_pin_group *pgroup = &pdata->groups[group]; + const struct aspeed_pin_group *pgroup = &pdata->pinmux.groups[group]; const struct aspeed_pin_function *pfunc = - &pdata->functions[function]; + &pdata->pinmux.functions[function]; for (i = 0; i < pgroup->npins; i++) { int pin = pgroup->pins[i]; @@ -423,7 +247,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, if (expr) break; - ret = aspeed_disable_sig(funcs, pdata->maps); + ret = aspeed_disable_sig(&pdata->pinmux, funcs); if (ret) return ret; @@ -443,7 +267,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, return -ENXIO; } - ret = aspeed_sig_expr_enable(expr, pdata->maps); + ret = aspeed_sig_expr_enable(&pdata->pinmux, expr); if (ret) return ret; } @@ -500,7 +324,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, if (aspeed_gpio_in_exprs(funcs)) break; - ret = aspeed_disable_sig(funcs, pdata->maps); + ret = aspeed_disable_sig(&pdata->pinmux, funcs); if (ret) return ret; @@ -531,7 +355,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, * If GPIO is not the lowest priority signal type, assume there is only * one expression defined to enable the GPIO function */ - return aspeed_sig_expr_enable(expr, pdata->maps); + return aspeed_sig_expr_enable(&pdata->pinmux, expr); } int aspeed_pinctrl_probe(struct platform_device *pdev, @@ -547,12 +371,14 @@ int aspeed_pinctrl_probe(struct platform_device *pdev, return -ENODEV; } - pdata->maps[ASPEED_IP_SCU] = syscon_node_to_regmap(parent->of_node); - if (IS_ERR(pdata->maps[ASPEED_IP_SCU])) { + pdata->scu = syscon_node_to_regmap(parent->of_node); + if (IS_ERR(pdata->scu)) { dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n"); - return PTR_ERR(pdata->maps[ASPEED_IP_SCU]); + return PTR_ERR(pdata->scu); } + pdata->pinmux.maps[ASPEED_IP_SCU] = pdata->scu; + pctl = pinctrl_register(pdesc, &pdev->dev, pdata); if (IS_ERR(pctl)) { @@ -587,7 +413,9 @@ static inline const struct aspeed_pin_config *find_pinconf_config( return NULL; } -/** +/* + * Aspeed pin configuration description. + * * @param: pinconf configuration parameter * @arg: The supported argument for @param, or -1 if any value is supported * @val: The register value to write to configure @arg for @param @@ -661,7 +489,7 @@ int aspeed_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset, if (!pconf) return -ENOTSUPP; - rc = regmap_read(pdata->maps[ASPEED_IP_SCU], pconf->reg, &val); + rc = regmap_read(pdata->scu, pconf->reg, &val); if (rc < 0) return rc; @@ -716,8 +544,8 @@ int aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset, val = pmap->val << pconf->bit; - rc = regmap_update_bits(pdata->maps[ASPEED_IP_SCU], pconf->reg, - BIT(pconf->bit), val); + rc = regmap_update_bits(pdata->scu, pconf->reg, + BIT(pconf->bit), val); if (rc < 0) return rc; diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h index 4b06ddbc6aec..a5d83986f32e 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h @@ -12,504 +12,7 @@ #include <linux/pinctrl/pinconf-generic.h> #include <linux/regmap.h> -/* - * The ASPEED SoCs provide typically more than 200 pins for GPIO and other - * functions. The SoC function enabled on a pin is determined on a priority - * basis where a given pin can provide a number of different signal types. - * - * The signal active on a pin is described by both a priority level and - * compound logical expressions involving multiple operators, registers and - * bits. Some difficulty arises as the pin's function bit masks for each - * priority level are frequently not the same (i.e. cannot just flip a bit to - * change from a high to low priority signal), or even in the same register. - * Further, not all signals can be unmuxed, as some expressions depend on - * values in the hardware strapping register (which is treated as read-only). - * - * SoC Multi-function Pin Expression Examples - * ------------------------------------------ - * - * Here are some sample mux configurations from the AST2400 and AST2500 - * datasheets to illustrate the corner cases, roughly in order of least to most - * corner. The signal priorities are in decending order from P0 (highest). - * - * D6 is a pin with a single function (beside GPIO); a high priority signal - * that participates in one function: - * - * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other - * -----+---------+-----------+-----------------------------+-----------+---------------+---------- - * D6 GPIOA0 MAC1LINK SCU80[0]=1 GPIOA0 - * -----+---------+-----------+-----------------------------+-----------+---------------+---------- - * - * C5 is a multi-signal pin (high and low priority signals). Here we touch - * different registers for the different functions that enable each signal: - * - * -----+---------+-----------+-----------------------------+-----------+---------------+---------- - * C5 GPIOA4 SCL9 SCU90[22]=1 TIMER5 SCU80[4]=1 GPIOA4 - * -----+---------+-----------+-----------------------------+-----------+---------------+---------- - * - * E19 is a single-signal pin with two functions that influence the active - * signal. In this case both bits have the same meaning - enable a dedicated - * LPC reset pin. However it's not always the case that the bits in the - * OR-relationship have the same meaning. - * - * -----+---------+-----------+-----------------------------+-----------+---------------+---------- - * E19 GPIOB4 LPCRST# SCU80[12]=1 | Strap[14]=1 GPIOB4 - * -----+---------+-----------+-----------------------------+-----------+---------------+---------- - * - * For example, pin B19 has a low-priority signal that's enabled by two - * distinct SoC functions: A specific SIOPBI bit in register SCUA4, and an ACPI - * bit in the STRAP register. The ACPI bit configures signals on pins in - * addition to B19. Both of the low priority functions as well as the high - * priority function must be disabled for GPIOF1 to be used. - * - * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other - * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- - * B19 GPIOF1 NDCD4 SCU80[25]=1 SIOPBI# SCUA4[12]=1 | Strap[19]=0 GPIOF1 - * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- - * - * For pin E18, the SoC ANDs the expected state of three bits to determine the - * pin's active signal: - * - * * SCU3C[3]: Enable external SOC reset function - * * SCU80[15]: Enable SPICS1# or EXTRST# function pin - * * SCU90[31]: Select SPI interface CS# output - * - * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- - * E18 GPIOB7 EXTRST# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0 SPICS1# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1 GPIOB7 - * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- - * - * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for - * selecting the signals on pin E18) - * - * Pin T5 is a multi-signal pin with a more complex configuration: - * - * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other - * -----+---------+-----------+------------------------------+-----------+---------------+---------- - * T5 GPIOL1 VPIDE SCU90[5:4]!=0 & SCU84[17]=1 NDCD1 SCU84[17]=1 GPIOL1 - * -----+---------+-----------+------------------------------+-----------+---------------+---------- - * - * The high priority signal configuration is best thought of in terms of its - * exploded form, with reference to the SCU90[5:4] bits: - * - * * SCU90[5:4]=00: disable - * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode. - * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode. - * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode. - * - * Re-writing: - * - * -----+---------+-----------+------------------------------+-----------+---------------+---------- - * T5 GPIOL1 VPIDE (SCU90[5:4]=1 & SCU84[17]=1) NDCD1 SCU84[17]=1 GPIOL1 - * | (SCU90[5:4]=2 & SCU84[17]=1) - * | (SCU90[5:4]=3 & SCU84[17]=1) - * -----+---------+-----------+------------------------------+-----------+---------------+---------- - * - * For reference the SCU84[17] bit configure the "UART1 NDCD1 or Video VPIDE - * function pin", where the signal itself is determined by whether SCU94[5:4] - * is disabled or in one of the 18, 24 or 30bit video modes. - * - * Other video-input-related pins require an explicit state in SCU90[5:4], e.g. - * W1 and U5: - * - * -----+---------+-----------+------------------------------+-----------+---------------+---------- - * W1 GPIOL6 VPIB0 SCU90[5:4]=3 & SCU84[22]=1 TXD1 SCU84[22]=1 GPIOL6 - * U5 GPIOL7 VPIB1 SCU90[5:4]=3 & SCU84[23]=1 RXD1 SCU84[23]=1 GPIOL7 - * -----+---------+-----------+------------------------------+-----------+---------------+---------- - * - * The examples of T5 and W1 are particularly fertile, as they also demonstrate - * that despite operating as part of the video input bus each signal needs to - * be enabled individually via it's own SCU84 (in the cases of T5 and W1) - * register bit. This is a little crazy if the bus doesn't have optional - * signals, but is used to decent effect with some of the UARTs where not all - * signals are required. However, this isn't done consistently - UART1 is - * enabled on a per-pin basis, and by contrast, all signals for UART6 are - * enabled by a single bit. - * - * Further, the high and low priority signals listed in the table above share - * a configuration bit. The VPI signals should operate in concert in a single - * function, but the UART signals should retain the ability to be configured - * independently. This pushes the implementation down the path of tagging a - * signal's expressions with the function they participate in, rather than - * defining masks affecting multiple signals per function. The latter approach - * fails in this instance where applying the configuration for the UART pin of - * interest will stomp on the state of other UART signals when disabling the - * VPI functions on the current pin. - * - * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other - * -----+------------+-----------+---------------------------+-----------+---------------+------------ - * A12 RGMII1TXCK GPIOT0 SCUA0[0]=1 RMII1TXEN Strap[6]=0 RGMII1TXCK - * B12 RGMII1TXCTL GPIOT1 SCUA0[1]=1 – Strap[6]=0 RGMII1TXCTL - * -----+------------+-----------+---------------------------+-----------+---------------+------------ - * - * A12 demonstrates that the "Other" signal isn't always GPIO - in this case - * GPIOT0 is a high-priority signal and RGMII1TXCK is Other. Thus, GPIO - * should be treated like any other signal type with full function expression - * requirements, and not assumed to be the default case. Separately, GPIOT0 and - * GPIOT1's signal descriptor bits are distinct, therefore we must iterate all - * pins in the function's group to disable the higher-priority signals such - * that the signal for the function of interest is correctly enabled. - * - * Finally, three priority levels aren't always enough; the AST2500 brings with - * it 18 pins of five priority levels, however the 18 pins only use three of - * the five priority levels. - * - * Ultimately the requirement to control pins in the examples above drive the - * design: - * - * * Pins provide signals according to functions activated in the mux - * configuration - * - * * Pins provide up to five signal types in a priority order - * - * * For priorities levels defined on a pin, each priority provides one signal - * - * * Enabling lower priority signals requires higher priority signals be - * disabled - * - * * A function represents a set of signals; functions are distinct if their - * sets of signals are not equal - * - * * Signals participate in one or more functions - * - * * A function is described by an expression of one or more signal - * descriptors, which compare bit values in a register - * - * * A signal expression is the smallest set of signal descriptors whose - * comparisons must evaluate 'true' for a signal to be enabled on a pin. - * - * * A function's signal is active on a pin if evaluating all signal - * descriptors in the pin's signal expression for the function yields a 'true' - * result - * - * * A signal at a given priority on a given pin is active if any of the - * functions in which the signal participates are active, and no higher - * priority signal on the pin is active - * - * * GPIO is configured per-pin - * - * And so: - * - * * To disable a signal, any function(s) activating the signal must be - * disabled - * - * * Each pin must know the signal expressions of functions in which it - * participates, for the purpose of enabling the Other function. This is done - * by deactivating all functions that activate higher priority signals on the - * pin. - * - * As a concrete example: - * - * * T5 provides three signals types: VPIDE, NDCD1 and GPIO - * - * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30 - * - * * The NDCD1 signal participates in just its own NDCD1 function - * - * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least - * prioritised - * - * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24 - * and VPI30 functions all be disabled - * - * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled - * to provide GPIOL6 - * - * Considerations - * -------------- - * - * If pinctrl allows us to allocate a pin we can configure a function without - * concern for the function of already allocated pins, if pin groups are - * created with respect to the SoC functions in which they participate. This is - * intuitive, but it did not feel obvious from the bit/pin relationships. - * - * Conversely, failing to allocate all pins in a group indicates some bits (as - * well as pins) required for the group's configuration will already be in use, - * likely in a way that's inconsistent with the requirements of the failed - * group. - */ - -#define ASPEED_IP_SCU 0 -#define ASPEED_IP_GFX 1 -#define ASPEED_IP_LPC 2 -#define ASPEED_NR_PINMUX_IPS 3 - -/* - * The "Multi-function Pins Mapping and Control" table in the SoC datasheet - * references registers by the device/offset mnemonic. The register macros - * below are named the same way to ease transcription and verification (as - * opposed to naming them e.g. PINMUX_CTRL_[0-9]). Further, signal expressions - * reference registers beyond those dedicated to pinmux, such as the system - * reset control and MAC clock configuration registers. The AST2500 goes a step - * further and references registers in the graphics IP block, but that isn't - * handled yet. - */ -#define SCU2C 0x2C /* Misc. Control Register */ -#define SCU3C 0x3C /* System Reset Control/Status Register */ -#define SCU48 0x48 /* MAC Interface Clock Delay Setting */ -#define HW_STRAP1 0x70 /* AST2400 strapping is 33 bits, is split */ -#define HW_REVISION_ID 0x7C /* Silicon revision ID register */ -#define SCU80 0x80 /* Multi-function Pin Control #1 */ -#define SCU84 0x84 /* Multi-function Pin Control #2 */ -#define SCU88 0x88 /* Multi-function Pin Control #3 */ -#define SCU8C 0x8C /* Multi-function Pin Control #4 */ -#define SCU90 0x90 /* Multi-function Pin Control #5 */ -#define SCU94 0x94 /* Multi-function Pin Control #6 */ -#define SCUA0 0xA0 /* Multi-function Pin Control #7 */ -#define SCUA4 0xA4 /* Multi-function Pin Control #8 */ -#define SCUA8 0xA8 /* Multi-function Pin Control #9 */ -#define SCUAC 0xAC /* Multi-function Pin Control #10 */ -#define HW_STRAP2 0xD0 /* Strapping */ - - /** - * A signal descriptor, which describes the register, bits and the - * enable/disable values that should be compared or written. - * - * @ip: The IP block identifier, used as an index into the regmap array in - * struct aspeed_pinctrl_data - * @reg: The register offset with respect to the base address of the IP block - * @mask: The mask to apply to the register. The lowest set bit of the mask is - * used to derive the shift value. - * @enable: The value that enables the function. Value should be in the LSBs, - * not at the position of the mask. - * @disable: The value that disables the function. Value should be in the - * LSBs, not at the position of the mask. - */ -struct aspeed_sig_desc { - unsigned int ip; - unsigned int reg; - u32 mask; - u32 enable; - u32 disable; -}; - -/** - * Describes a signal expression. The expression is evaluated by ANDing the - * evaluation of the descriptors. - * - * @signal: The signal name for the priority level on the pin. If the signal - * type is GPIO, then the signal name must begin with the string - * "GPIO", e.g. GPIOA0, GPIOT4 etc. - * @function: The name of the function the signal participates in for the - * associated expression - * @ndescs: The number of signal descriptors in the expression - * @descs: Pointer to an array of signal descriptors that comprise the - * function expression - */ -struct aspeed_sig_expr { - const char *signal; - const char *function; - int ndescs; - const struct aspeed_sig_desc *descs; -}; - -/** - * A struct capturing the list of expressions enabling signals at each priority - * for a given pin. The signal configuration for a priority level is evaluated - * by ORing the evaluation of the signal expressions in the respective - * priority's list. - * - * @name: A name for the pin - * @prios: A pointer to an array of expression list pointers - * - */ -struct aspeed_pin_desc { - const char *name; - const struct aspeed_sig_expr ***prios; -}; - -/* Macro hell */ - -#define SIG_DESC_IP_BIT(ip, reg, idx, val) \ - { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) } - -/** - * Short-hand macro for describing an SCU descriptor enabled by the state of - * one bit. The disable value is derived. - * - * @reg: The signal's associated register, offset from base - * @idx: The signal's bit index in the register - * @val: The value (0 or 1) that enables the function - */ -#define SIG_DESC_BIT(reg, idx, val) \ - SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val) - -#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1) - -/** - * A further short-hand macro expanding to an SCU descriptor enabled by a set - * bit. - * - * @reg: The register, offset from base - * @idx: The bit index in the register - */ -#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1) - -#define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func -#define SIG_DESC_LIST_DECL(sig, func, ...) \ - static const struct aspeed_sig_desc SIG_DESC_LIST_SYM(sig, func)[] = \ - { __VA_ARGS__ } - -#define SIG_EXPR_SYM(sig, func) sig_expr_ ## sig ## _ ## func -#define SIG_EXPR_DECL_(sig, func) \ - static const struct aspeed_sig_expr SIG_EXPR_SYM(sig, func) = \ - { \ - .signal = #sig, \ - .function = #func, \ - .ndescs = ARRAY_SIZE(SIG_DESC_LIST_SYM(sig, func)), \ - .descs = &(SIG_DESC_LIST_SYM(sig, func))[0], \ - } - -/** - * Declare a signal expression. - * - * @sig: A macro symbol name for the signal (is subjected to stringification - * and token pasting) - * @func: The function in which the signal is participating - * @...: Signal descriptors that define the signal expression - * - * For example, the following declares the ROMD8 signal for the ROM16 function: - * - * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6)); - * - * And with multiple signal descriptors: - * - * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4), - * { HW_STRAP1, GENMASK(1, 0), 0, 0 }); - */ -#define SIG_EXPR_DECL(sig, func, ...) \ - SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \ - SIG_EXPR_DECL_(sig, func) - -/** - * Declare a pointer to a signal expression - * - * @sig: The macro symbol name for the signal (subjected to token pasting) - * @func: The macro symbol name for the function (subjected to token pasting) - */ -#define SIG_EXPR_PTR(sig, func) (&SIG_EXPR_SYM(sig, func)) - -#define SIG_EXPR_LIST_SYM(sig) sig_exprs_ ## sig - -/** - * Declare a signal expression list for reference in a struct aspeed_pin_prio. - * - * @sig: A macro symbol name for the signal (is subjected to token pasting) - * @...: Signal expression structure pointers (use SIG_EXPR_PTR()) - * - * For example, the 16-bit ROM bus can be enabled by one of two possible signal - * expressions: - * - * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6)); - * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4), - * { HW_STRAP1, GENMASK(1, 0), 0, 0 }); - * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16), - * SIG_EXPR_PTR(ROMD8, ROM16S)); - */ -#define SIG_EXPR_LIST_DECL(sig, ...) \ - static const struct aspeed_sig_expr *SIG_EXPR_LIST_SYM(sig)[] = \ - { __VA_ARGS__, NULL } - -/** - * A short-hand macro for declaring a function expression and an expression - * list with a single function. - * - * @func: A macro symbol name for the function (is subjected to token pasting) - * @...: Function descriptors that define the function expression - * - * For example, signal NCTS6 participates in its own function with one group: - * - * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7)); - */ -#define SIG_EXPR_LIST_DECL_SINGLE(sig, func, ...) \ - SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \ - SIG_EXPR_DECL_(sig, func); \ - SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, func)) - -#define SIG_EXPR_LIST_DECL_DUAL(sig, f0, f1) \ - SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, f0), SIG_EXPR_PTR(sig, f1)) - -#define SIG_EXPR_LIST_PTR(sig) (&SIG_EXPR_LIST_SYM(sig)[0]) - -#define PIN_EXPRS_SYM(pin) pin_exprs_ ## pin -#define PIN_EXPRS_PTR(pin) (&PIN_EXPRS_SYM(pin)[0]) -#define PIN_SYM(pin) pin_ ## pin - -#define MS_PIN_DECL_(pin, ...) \ - static const struct aspeed_sig_expr **PIN_EXPRS_SYM(pin)[] = \ - { __VA_ARGS__, NULL }; \ - static const struct aspeed_pin_desc PIN_SYM(pin) = \ - { #pin, PIN_EXPRS_PTR(pin) } - -/** - * Declare a multi-signal pin - * - * @pin: The pin number - * @other: Macro name for "other" functionality (subjected to stringification) - * @high: Macro name for the highest priority signal functions - * @low: Macro name for the low signal functions - * - * For example: - * - * #define A8 56 - * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6)); - * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4), - * { HW_STRAP1, GENMASK(1, 0), 0, 0 }); - * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16), - * SIG_EXPR_PTR(ROMD8, ROM16S)); - * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7)); - * MS_PIN_DECL(A8, GPIOH0, ROMD8, NCTS6); - */ -#define MS_PIN_DECL(pin, other, high, low) \ - SIG_EXPR_LIST_DECL_SINGLE(other, other); \ - MS_PIN_DECL_(pin, \ - SIG_EXPR_LIST_PTR(high), \ - SIG_EXPR_LIST_PTR(low), \ - SIG_EXPR_LIST_PTR(other)) - -#define PIN_GROUP_SYM(func) pins_ ## func -#define FUNC_GROUP_SYM(func) groups_ ## func -#define FUNC_GROUP_DECL(func, ...) \ - static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \ - static const char *FUNC_GROUP_SYM(func)[] = { #func } - -/** - * Declare a single signal pin - * - * @pin: The pin number - * @other: Macro name for "other" functionality (subjected to stringification) - * @sig: Macro name for the signal (subjected to stringification) - * - * For example: - * - * #define E3 80 - * SIG_EXPR_LIST_DECL_SINGLE(SCL5, I2C5, I2C5_DESC); - * SS_PIN_DECL(E3, GPIOK0, SCL5); - */ -#define SS_PIN_DECL(pin, other, sig) \ - SIG_EXPR_LIST_DECL_SINGLE(other, other); \ - MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)) - -/** - * Single signal, single function pin declaration - * - * @pin: The pin number - * @other: Macro name for "other" functionality (subjected to stringification) - * @sig: Macro name for the signal (subjected to stringification) - * @...: Signal descriptors that define the function expression - * - * For example: - * - * SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2)); - */ -#define SSSF_PIN_DECL(pin, other, sig, ...) \ - SIG_EXPR_LIST_DECL_SINGLE(sig, sig, __VA_ARGS__); \ - SIG_EXPR_LIST_DECL_SINGLE(other, other); \ - MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)); \ - FUNC_GROUP_DECL(sig, pin) - -#define GPIO_PIN_DECL(pin, gpio) \ - SIG_EXPR_LIST_DECL_SINGLE(gpio, gpio); \ - MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio)) +#include "pinmux-aspeed.h" /** * @param The pinconf parameter type @@ -525,22 +28,6 @@ struct aspeed_pin_config { u8 value; }; -struct aspeed_pinctrl_data { - struct regmap *maps[ASPEED_NR_PINMUX_IPS]; - - const struct pinctrl_pin_desc *pins; - const unsigned int npins; - - const struct aspeed_pin_group *groups; - const unsigned int ngroups; - - const struct aspeed_pin_function *functions; - const unsigned int nfunctions; - - const struct aspeed_pin_config *configs; - const unsigned int nconfigs; -}; - #define ASPEED_PINCTRL_PIN(name_) \ [name_] = { \ .number = name_, \ @@ -548,30 +35,19 @@ struct aspeed_pinctrl_data { .drv_data = (void *) &(PIN_SYM(name_)) \ } -struct aspeed_pin_group { - const char *name; - const unsigned int *pins; +struct aspeed_pinctrl_data { + struct regmap *scu; + + const struct pinctrl_pin_desc *pins; const unsigned int npins; -}; -#define ASPEED_PINCTRL_GROUP(name_) { \ - .name = #name_, \ - .pins = &(PIN_GROUP_SYM(name_))[0], \ - .npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \ -} + const struct aspeed_pin_config *configs; + const unsigned int nconfigs; -struct aspeed_pin_function { - const char *name; - const char *const *groups; - unsigned int ngroups; + struct aspeed_pinmux_data pinmux; }; -#define ASPEED_PINCTRL_FUNC(name_, ...) { \ - .name = #name_, \ - .groups = &FUNC_GROUP_SYM(name_)[0], \ - .ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \ -} - +/* Aspeed pinctrl helpers */ int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev); const char *aspeed_pinctrl_get_group_name(struct pinctrl_dev *pctldev, unsigned int group); diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.c b/drivers/pinctrl/aspeed/pinmux-aspeed.c new file mode 100644 index 000000000000..5b0fe178ccf2 --- /dev/null +++ b/drivers/pinctrl/aspeed/pinmux-aspeed.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (C) 2019 IBM Corp. */ + +/* Pieces to enable drivers to implement the .set callback */ + +#include "pinmux-aspeed.h" + +const char *const aspeed_pinmux_ips[] = { + [ASPEED_IP_SCU] = "SCU", + [ASPEED_IP_GFX] = "GFX", + [ASPEED_IP_LPC] = "LPC", +}; + +static inline void aspeed_sig_desc_print_val( + const struct aspeed_sig_desc *desc, bool enable, u32 rv) +{ + pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n", + aspeed_pinmux_ips[desc->ip], desc->reg, + desc->mask, enable ? desc->enable : desc->disable, + (rv & desc->mask) >> __ffs(desc->mask), rv); +} + +/** + * Query the enabled or disabled state of a signal descriptor + * + * @desc: The signal descriptor of interest + * @enabled: True to query the enabled state, false to query disabled state + * @map: The IP block's regmap instance + * + * Return: 1 if the descriptor's bitfield is configured to the state + * selected by @enabled, 0 if not, and less than zero if an unrecoverable + * failure occurred + * + * Evaluation of descriptor state is non-trivial in that it is not a binary + * outcome: The bitfields can be greater than one bit in size and thus can take + * a value that is neither the enabled nor disabled state recorded in the + * descriptor (typically this means a different function to the one of interest + * is enabled). Thus we must explicitly test for either condition as required. + */ +int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, + bool enabled, struct regmap *map) +{ + int ret; + unsigned int raw; + u32 want; + + if (!map) + return -ENODEV; + + ret = regmap_read(map, desc->reg, &raw); + if (ret) + return ret; + + aspeed_sig_desc_print_val(desc, enabled, raw); + want = enabled ? desc->enable : desc->disable; + + return ((raw & desc->mask) >> __ffs(desc->mask)) == want; +} + +/** + * Query the enabled or disabled state for a mux function's signal on a pin + * + * @ctx: The driver context for the pinctrl IP + * @expr: An expression controlling the signal for a mux function on a pin + * @enabled: True to query the enabled state, false to query disabled state + * + * Return: 1 if the expression composed by @enabled evaluates true, 0 if not, + * and less than zero if an unrecoverable failure occurred. + * + * A mux function is enabled or disabled if the function's signal expression + * for each pin in the function's pin group evaluates true for the desired + * state. An signal expression evaluates true if all of its associated signal + * descriptors evaluate true for the desired state. + * + * If an expression's state is described by more than one bit, either through + * multi-bit bitfields in a single signal descriptor or through multiple signal + * descriptors of a single bit then it is possible for the expression to be in + * neither the enabled nor disabled state. Thus we must explicitly test for + * either condition as required. + */ +int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr, bool enabled) +{ + int i; + int ret; + + for (i = 0; i < expr->ndescs; i++) { + const struct aspeed_sig_desc *desc = &expr->descs[i]; + + ret = aspeed_sig_desc_eval(desc, enabled, ctx->maps[desc->ip]); + if (ret <= 0) + return ret; + } + + return 1; +} diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.h b/drivers/pinctrl/aspeed/pinmux-aspeed.h new file mode 100644 index 000000000000..329d54d48667 --- /dev/null +++ b/drivers/pinctrl/aspeed/pinmux-aspeed.h @@ -0,0 +1,735 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2019 IBM Corp. */ + +#ifndef ASPEED_PINMUX_H +#define ASPEED_PINMUX_H + +#include <linux/regmap.h> +#include <stdbool.h> + +/* + * The ASPEED SoCs provide typically more than 200 pins for GPIO and other + * functions. The SoC function enabled on a pin is determined on a priority + * basis where a given pin can provide a number of different signal types. + * + * The signal active on a pin is described by both a priority level and + * compound logical expressions involving multiple operators, registers and + * bits. Some difficulty arises as the pin's function bit masks for each + * priority level are frequently not the same (i.e. cannot just flip a bit to + * change from a high to low priority signal), or even in the same register. + * Further, not all signals can be unmuxed, as some expressions depend on + * values in the hardware strapping register (which may be treated as + * read-only). + * + * SoC Multi-function Pin Expression Examples + * ------------------------------------------ + * + * Here are some sample mux configurations from the AST2400 and AST2500 + * datasheets to illustrate the corner cases, roughly in order of least to most + * corner. The signal priorities are in decending order from P0 (highest). + * + * D6 is a pin with a single function (beside GPIO); a high priority signal + * that participates in one function: + * + * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * D6 GPIOA0 MAC1LINK SCU80[0]=1 GPIOA0 + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * + * C5 is a multi-signal pin (high and low priority signals). Here we touch + * different registers for the different functions that enable each signal: + * + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * C5 GPIOA4 SCL9 SCU90[22]=1 TIMER5 SCU80[4]=1 GPIOA4 + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * + * E19 is a single-signal pin with two functions that influence the active + * signal. In this case both bits have the same meaning - enable a dedicated + * LPC reset pin. However it's not always the case that the bits in the + * OR-relationship have the same meaning. + * + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * E19 GPIOB4 LPCRST# SCU80[12]=1 | Strap[14]=1 GPIOB4 + * -----+---------+-----------+-----------------------------+-----------+---------------+---------- + * + * For example, pin B19 has a low-priority signal that's enabled by two + * distinct SoC functions: A specific SIOPBI bit in register SCUA4, and an ACPI + * bit in the STRAP register. The ACPI bit configures signals on pins in + * addition to B19. Both of the low priority functions as well as the high + * priority function must be disabled for GPIOF1 to be used. + * + * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * B19 GPIOF1 NDCD4 SCU80[25]=1 SIOPBI# SCUA4[12]=1 | Strap[19]=0 GPIOF1 + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * + * For pin E18, the SoC ANDs the expected state of three bits to determine the + * pin's active signal: + * + * * SCU3C[3]: Enable external SOC reset function + * * SCU80[15]: Enable SPICS1# or EXTRST# function pin + * * SCU90[31]: Select SPI interface CS# output + * + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * E18 GPIOB7 EXTRST# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0 SPICS1# SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1 GPIOB7 + * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+---------- + * + * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for + * selecting the signals on pin E18) + * + * Pin T5 is a multi-signal pin with a more complex configuration: + * + * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * T5 GPIOL1 VPIDE SCU90[5:4]!=0 & SCU84[17]=1 NDCD1 SCU84[17]=1 GPIOL1 + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * + * The high priority signal configuration is best thought of in terms of its + * exploded form, with reference to the SCU90[5:4] bits: + * + * * SCU90[5:4]=00: disable + * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode. + * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode. + * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode. + * + * Re-writing: + * + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * T5 GPIOL1 VPIDE (SCU90[5:4]=1 & SCU84[17]=1) NDCD1 SCU84[17]=1 GPIOL1 + * | (SCU90[5:4]=2 & SCU84[17]=1) + * | (SCU90[5:4]=3 & SCU84[17]=1) + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * + * For reference the SCU84[17] bit configure the "UART1 NDCD1 or Video VPIDE + * function pin", where the signal itself is determined by whether SCU94[5:4] + * is disabled or in one of the 18, 24 or 30bit video modes. + * + * Other video-input-related pins require an explicit state in SCU90[5:4], e.g. + * W1 and U5: + * + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * W1 GPIOL6 VPIB0 SCU90[5:4]=3 & SCU84[22]=1 TXD1 SCU84[22]=1 GPIOL6 + * U5 GPIOL7 VPIB1 SCU90[5:4]=3 & SCU84[23]=1 RXD1 SCU84[23]=1 GPIOL7 + * -----+---------+-----------+------------------------------+-----------+---------------+---------- + * + * The examples of T5 and W1 are particularly fertile, as they also demonstrate + * that despite operating as part of the video input bus each signal needs to + * be enabled individually via it's own SCU84 (in the cases of T5 and W1) + * register bit. This is a little crazy if the bus doesn't have optional + * signals, but is used to decent effect with some of the UARTs where not all + * signals are required. However, this isn't done consistently - UART1 is + * enabled on a per-pin basis, and by contrast, all signals for UART6 are + * enabled by a single bit. + * + * Further, the high and low priority signals listed in the table above share + * a configuration bit. The VPI signals should operate in concert in a single + * function, but the UART signals should retain the ability to be configured + * independently. This pushes the implementation down the path of tagging a + * signal's expressions with the function they participate in, rather than + * defining masks affecting multiple signals per function. The latter approach + * fails in this instance where applying the configuration for the UART pin of + * interest will stomp on the state of other UART signals when disabling the + * VPI functions on the current pin. + * + * Ball | Default | P0 Signal | P0 Expression | P1 Signal | P1 Expression | Other + * -----+------------+-----------+---------------------------+-----------+---------------+------------ + * A12 RGMII1TXCK GPIOT0 SCUA0[0]=1 RMII1TXEN Strap[6]=0 RGMII1TXCK + * B12 RGMII1TXCTL GPIOT1 SCUA0[1]=1 – Strap[6]=0 RGMII1TXCTL + * -----+------------+-----------+---------------------------+-----------+---------------+------------ + * + * A12 demonstrates that the "Other" signal isn't always GPIO - in this case + * GPIOT0 is a high-priority signal and RGMII1TXCK is Other. Thus, GPIO + * should be treated like any other signal type with full function expression + * requirements, and not assumed to be the default case. Separately, GPIOT0 and + * GPIOT1's signal descriptor bits are distinct, therefore we must iterate all + * pins in the function's group to disable the higher-priority signals such + * that the signal for the function of interest is correctly enabled. + * + * Finally, three priority levels aren't always enough; the AST2500 brings with + * it 18 pins of five priority levels, however the 18 pins only use three of + * the five priority levels. + * + * Ultimately the requirement to control pins in the examples above drive the + * design: + * + * * Pins provide signals according to functions activated in the mux + * configuration + * + * * Pins provide up to five signal types in a priority order + * + * * For priorities levels defined on a pin, each priority provides one signal + * + * * Enabling lower priority signals requires higher priority signals be + * disabled + * + * * A function represents a set of signals; functions are distinct if their + * sets of signals are not equal + * + * * Signals participate in one or more functions + * + * * A function is described by an expression of one or more signal + * descriptors, which compare bit values in a register + * + * * A signal expression is the smallest set of signal descriptors whose + * comparisons must evaluate 'true' for a signal to be enabled on a pin. + * + * * A signal participating in a function is active on a pin if evaluating all + * signal descriptors in the pin's signal expression for the function yields + * a 'true' result + * + * * A signal at a given priority on a given pin is active if any of the + * functions in which the signal participates are active, and no higher + * priority signal on the pin is active + * + * * GPIO is configured per-pin + * + * And so: + * + * * To disable a signal, any function(s) activating the signal must be + * disabled + * + * * Each pin must know the signal expressions of functions in which it + * participates, for the purpose of enabling the Other function. This is done + * by deactivating all functions that activate higher priority signals on the + * pin. + * + * As a concrete example: + * + * * T5 provides three signals types: VPIDE, NDCD1 and GPIO + * + * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30 + * + * * The NDCD1 signal participates in just its own NDCD1 function + * + * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least + * prioritised + * + * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24 + * and VPI30 functions all be disabled + * + * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled + * to provide GPIOL6 + * + * Considerations + * -------------- + * + * If pinctrl allows us to allocate a pin we can configure a function without + * concern for the function of already allocated pins, if pin groups are + * created with respect to the SoC functions in which they participate. This is + * intuitive, but it did not feel obvious from the bit/pin relationships. + * + * Conversely, failing to allocate all pins in a group indicates some bits (as + * well as pins) required for the group's configuration will already be in use, + * likely in a way that's inconsistent with the requirements of the failed + * group. + * + * Implementation + * -------------- + * + * Beyond the documentation below the various structures and helper macros that + * allow the implementation to hang together are defined. The macros are fairly + * dense, so below we walk through some raw examples of the configuration + * tables in an effort to clarify the concepts. + * + * The complexity of configuring the mux combined with the scale of the pins + * and functions was a concern, so the table design along with the macro jungle + * is an attempt to address it. The rough principles of the approach are: + * + * 1. Use a data-driven solution rather than embedding state into code + * 2. Minimise editing to the specifics of the given mux configuration + * 3. Detect as many errors as possible at compile time + * + * Addressing point 3 leads to naming of symbols in terms of the four + * properties associated with a given mux configuration: The pin, the signal, + * the group and the function. In this way copy/paste errors cause duplicate + * symbols to be defined, which prevents successful compilation. Failing to + * properly parent the tables leads to unused symbol warnings, and use of + * designated initialisers and additional warnings ensures that there are + * no override errors in the pin, group and function arrays. + * + * Addressing point 2 drives the development of the macro jungle, as it + * centralises the definition noise at the cost of taking some time to + * understand. + * + * Here's a complete, concrete "pre-processed" example of the table structures + * used to describe the D6 ball from the examples above: + * + * ``` + * static const struct aspeed_sig_desc sig_descs_MAC1LINK_MAC1LINK[] = { + * { + * .ip = ASPEED_IP_SCU, + * .reg = 0x80, + * .mask = BIT(0), + * .enable = 1, + * .disable = 0 + * }, + * }; + * + * static const struct aspeed_sig_expr sig_expr_MAC1LINK_MAC1LINK = { + * .signal = "MAC1LINK", + * .function = "MAC1LINK", + * .ndescs = ARRAY_SIZE(sig_descs_MAC1LINK_MAC1LINK), + * .descs = &(sig_descs_MAC1LINK_MAC1LINK)[0], + * }; + * + * static const struct aspeed_sig_expr *sig_exprs_MAC1LINK_MAC1LINK[] = { + * &sig_expr_MAC1LINK_MAC1LINK, + * NULL, + * }; + * + * static const struct aspeed_sig_desc sig_descs_GPIOA0_GPIOA0[] = { }; + * + * static const struct aspeed_sig_expr sig_expr_GPIOA0_GPIOA0 = { + * .signal = "GPIOA0", + * .function = "GPIOA0", + * .ndescs = ARRAY_SIZE(sig_descs_GPIOA0_GPIOA0), + * .descs = &(sig_descs_GPIOA0_GPIOA0)[0], + * }; + * + * static const struct aspeed_sig_expr *sig_exprs_GPIOA0_GPIOA0[] = { + * &sig_expr_GPIOA0_GPIOA0, + * NULL + * }; + * + * static const struct aspeed_sig_expr **pin_exprs_0[] = { + * sig_exprs_MAC1LINK_MAC1LINK, + * sig_exprs_GPIOA0_GPIOA0, + * NULL + * }; + * + * static const struct aspeed_pin_desc pin_0 = { "0", (&pin_exprs_0[0]) }; + * static const int group_pins_MAC1LINK[] = { 0 }; + * static const char *func_groups_MAC1LINK[] = { "MAC1LINK" }; + * + * static struct pinctrl_pin_desc aspeed_g4_pins[] = { + * [0] = { .number = 0, .name = "D6", .drv_data = &pin_0 }, + * }; + * + * static const struct aspeed_pin_group aspeed_g4_groups[] = { + * { + * .name = "MAC1LINK", + * .pins = &(group_pins_MAC1LINK)[0], + * .npins = ARRAY_SIZE(group_pins_MAC1LINK), + * }, + * }; + * + * static const struct aspeed_pin_function aspeed_g4_functions[] = { + * { + * .name = "MAC1LINK", + * .groups = &func_groups_MAC1LINK[0], + * .ngroups = ARRAY_SIZE(func_groups_MAC1LINK), + * }, + * }; + * ``` + * + * At the end of the day much of the above code is compressed into the + * following two lines: + * + * ``` + * #define D6 0 + * SSSF_PIN_DECL(D6, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0)); + * ``` + * + * The two examples below show just the differences from the example above. + * + * Ball E18 demonstrates a function, EXTRST, that requires multiple descriptors + * be set for it to be muxed: + * + * ``` + * static const struct aspeed_sig_desc sig_descs_EXTRST_EXTRST[] = { + * { + * .ip = ASPEED_IP_SCU, + * .reg = 0x3C, + * .mask = BIT(3), + * .enable = 1, + * .disable = 0 + * }, + * { + * .ip = ASPEED_IP_SCU, + * .reg = 0x80, + * .mask = BIT(15), + * .enable = 1, + * .disable = 0 + * }, + * { + * .ip = ASPEED_IP_SCU, + * .reg = 0x90, + * .mask = BIT(31), + * .enable = 0, + * .disable = 1 + * }, + * }; + * + * static const struct aspeed_sig_expr sig_expr_EXTRST_EXTRST = { + * .signal = "EXTRST", + * .function = "EXTRST", + * .ndescs = ARRAY_SIZE(sig_descs_EXTRST_EXTRST), + * .descs = &(sig_descs_EXTRST_EXTRST)[0], + * }; + * ... + * ``` + * + * For ball E19, we have multiple functions enabling a single signal, LPCRST#. + * The data structures look like: + * + * static const struct aspeed_sig_desc sig_descs_LPCRST_LPCRST[] = { + * { + * .ip = ASPEED_IP_SCU, + * .reg = 0x80, + * .mask = BIT(12), + * .enable = 1, + * .disable = 0 + * }, + * }; + * + * static const struct aspeed_sig_expr sig_expr_LPCRST_LPCRST = { + * .signal = "LPCRST", + * .function = "LPCRST", + * .ndescs = ARRAY_SIZE(sig_descs_LPCRST_LPCRST), + * .descs = &(sig_descs_LPCRST_LPCRST)[0], + * }; + * + * static const struct aspeed_sig_desc sig_descs_LPCRST_LPCRSTS[] = { + * { + * .ip = ASPEED_IP_SCU, + * .reg = 0x70, + * .mask = BIT(14), + * .enable = 1, + * .disable = 0 + * }, + * }; + * + * static const struct aspeed_sig_expr sig_expr_LPCRST_LPCRSTS = { + * .signal = "LPCRST", + * .function = "LPCRSTS", + * .ndescs = ARRAY_SIZE(sig_descs_LPCRST_LPCRSTS), + * .descs = &(sig_descs_LPCRST_LPCRSTS)[0], + * }; + * + * static const struct aspeed_sig_expr *sig_exprs_LPCRST_LPCRST[] = { + * &sig_expr_LPCRST_LPCRST, + * &sig_expr_LPCRST_LPCRSTS, + * NULL, + * }; + * ... + * ``` + * + * Both expressions listed in the sig_exprs_LPCRST_LPCRST array need to be set + * to disabled for the associated GPIO to be muxed. + * + */ + +#define ASPEED_IP_SCU 0 +#define ASPEED_IP_GFX 1 +#define ASPEED_IP_LPC 2 +#define ASPEED_NR_PINMUX_IPS 3 + + /** + * A signal descriptor, which describes the register, bits and the + * enable/disable values that should be compared or written. + * + * @ip: The IP block identifier, used as an index into the regmap array in + * struct aspeed_pinctrl_data + * @reg: The register offset with respect to the base address of the IP block + * @mask: The mask to apply to the register. The lowest set bit of the mask is + * used to derive the shift value. + * @enable: The value that enables the function. Value should be in the LSBs, + * not at the position of the mask. + * @disable: The value that disables the function. Value should be in the + * LSBs, not at the position of the mask. + */ +struct aspeed_sig_desc { + unsigned int ip; + unsigned int reg; + u32 mask; + u32 enable; + u32 disable; +}; + +/** + * Describes a signal expression. The expression is evaluated by ANDing the + * evaluation of the descriptors. + * + * @signal: The signal name for the priority level on the pin. If the signal + * type is GPIO, then the signal name must begin with the string + * "GPIO", e.g. GPIOA0, GPIOT4 etc. + * @function: The name of the function the signal participates in for the + * associated expression + * @ndescs: The number of signal descriptors in the expression + * @descs: Pointer to an array of signal descriptors that comprise the + * function expression + */ +struct aspeed_sig_expr { + const char *signal; + const char *function; + int ndescs; + const struct aspeed_sig_desc *descs; +}; + +/** + * A struct capturing the list of expressions enabling signals at each priority + * for a given pin. The signal configuration for a priority level is evaluated + * by ORing the evaluation of the signal expressions in the respective + * priority's list. + * + * @name: A name for the pin + * @prios: A pointer to an array of expression list pointers + * + */ +struct aspeed_pin_desc { + const char *name; + const struct aspeed_sig_expr ***prios; +}; + +/* Macro hell */ + +#define SIG_DESC_IP_BIT(ip, reg, idx, val) \ + { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) } + +/** + * Short-hand macro for describing an SCU descriptor enabled by the state of + * one bit. The disable value is derived. + * + * @reg: The signal's associated register, offset from base + * @idx: The signal's bit index in the register + * @val: The value (0 or 1) that enables the function + */ +#define SIG_DESC_BIT(reg, idx, val) \ + SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val) + +#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1) + +/** + * A further short-hand macro expanding to an SCU descriptor enabled by a set + * bit. + * + * @reg: The register, offset from base + * @idx: The bit index in the register + */ +#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1) + +#define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func +#define SIG_DESC_LIST_DECL(sig, func, ...) \ + static const struct aspeed_sig_desc SIG_DESC_LIST_SYM(sig, func)[] = \ + { __VA_ARGS__ } + +#define SIG_EXPR_SYM(sig, func) sig_expr_ ## sig ## _ ## func +#define SIG_EXPR_DECL_(sig, func) \ + static const struct aspeed_sig_expr SIG_EXPR_SYM(sig, func) = \ + { \ + .signal = #sig, \ + .function = #func, \ + .ndescs = ARRAY_SIZE(SIG_DESC_LIST_SYM(sig, func)), \ + .descs = &(SIG_DESC_LIST_SYM(sig, func))[0], \ + } + +/** + * Declare a signal expression. + * + * @sig: A macro symbol name for the signal (is subjected to stringification + * and token pasting) + * @func: The function in which the signal is participating + * @...: Signal descriptors that define the signal expression + * + * For example, the following declares the ROMD8 signal for the ROM16 function: + * + * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6)); + * + * And with multiple signal descriptors: + * + * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4), + * { HW_STRAP1, GENMASK(1, 0), 0, 0 }); + */ +#define SIG_EXPR_DECL(sig, func, ...) \ + SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \ + SIG_EXPR_DECL_(sig, func) + +/** + * Declare a pointer to a signal expression + * + * @sig: The macro symbol name for the signal (subjected to token pasting) + * @func: The macro symbol name for the function (subjected to token pasting) + */ +#define SIG_EXPR_PTR(sig, func) (&SIG_EXPR_SYM(sig, func)) + +#define SIG_EXPR_LIST_SYM(sig) sig_exprs_ ## sig + +/** + * Declare a signal expression list for reference in a struct aspeed_pin_prio. + * + * @sig: A macro symbol name for the signal (is subjected to token pasting) + * @...: Signal expression structure pointers (use SIG_EXPR_PTR()) + * + * For example, the 16-bit ROM bus can be enabled by one of two possible signal + * expressions: + * + * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6)); + * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4), + * { HW_STRAP1, GENMASK(1, 0), 0, 0 }); + * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16), + * SIG_EXPR_PTR(ROMD8, ROM16S)); + */ +#define SIG_EXPR_LIST_DECL(sig, ...) \ + static const struct aspeed_sig_expr *SIG_EXPR_LIST_SYM(sig)[] = \ + { __VA_ARGS__, NULL } + +/** + * A short-hand macro for declaring a function expression and an expression + * list with a single function. + * + * @func: A macro symbol name for the function (is subjected to token pasting) + * @...: Function descriptors that define the function expression + * + * For example, signal NCTS6 participates in its own function with one group: + * + * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7)); + */ +#define SIG_EXPR_LIST_DECL_SINGLE(sig, func, ...) \ + SIG_DESC_LIST_DECL(sig, func, __VA_ARGS__); \ + SIG_EXPR_DECL_(sig, func); \ + SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, func)) + +#define SIG_EXPR_LIST_DECL_DUAL(sig, f0, f1) \ + SIG_EXPR_LIST_DECL(sig, SIG_EXPR_PTR(sig, f0), SIG_EXPR_PTR(sig, f1)) + +#define SIG_EXPR_LIST_PTR(sig) (&SIG_EXPR_LIST_SYM(sig)[0]) + +#define PIN_EXPRS_SYM(pin) pin_exprs_ ## pin +#define PIN_EXPRS_PTR(pin) (&PIN_EXPRS_SYM(pin)[0]) +#define PIN_SYM(pin) pin_ ## pin + +#define MS_PIN_DECL_(pin, ...) \ + static const struct aspeed_sig_expr **PIN_EXPRS_SYM(pin)[] = \ + { __VA_ARGS__, NULL }; \ + static const struct aspeed_pin_desc PIN_SYM(pin) = \ + { #pin, PIN_EXPRS_PTR(pin) } + +/** + * Declare a multi-signal pin + * + * @pin: The pin number + * @other: Macro name for "other" functionality (subjected to stringification) + * @high: Macro name for the highest priority signal functions + * @low: Macro name for the low signal functions + * + * For example: + * + * #define A8 56 + * SIG_EXPR_DECL(ROMD8, ROM16, SIG_DESC_SET(SCU90, 6)); + * SIG_EXPR_DECL(ROMD8, ROM16S, SIG_DESC_SET(HW_STRAP1, 4), + * { HW_STRAP1, GENMASK(1, 0), 0, 0 }); + * SIG_EXPR_LIST_DECL(ROMD8, SIG_EXPR_PTR(ROMD8, ROM16), + * SIG_EXPR_PTR(ROMD8, ROM16S)); + * SIG_EXPR_LIST_DECL_SINGLE(NCTS6, NCTS6, SIG_DESC_SET(SCU90, 7)); + * MS_PIN_DECL(A8, GPIOH0, ROMD8, NCTS6); + */ +#define MS_PIN_DECL(pin, other, high, low) \ + SIG_EXPR_LIST_DECL_SINGLE(other, other); \ + MS_PIN_DECL_(pin, \ + SIG_EXPR_LIST_PTR(high), \ + SIG_EXPR_LIST_PTR(low), \ + SIG_EXPR_LIST_PTR(other)) + +#define PIN_GROUP_SYM(func) pins_ ## func +#define FUNC_GROUP_SYM(func) groups_ ## func +#define FUNC_GROUP_DECL(func, ...) \ + static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \ + static const char *FUNC_GROUP_SYM(func)[] = { #func } + +/** + * Declare a single signal pin + * + * @pin: The pin number + * @other: Macro name for "other" functionality (subjected to stringification) + * @sig: Macro name for the signal (subjected to stringification) + * + * For example: + * + * #define E3 80 + * SIG_EXPR_LIST_DECL_SINGLE(SCL5, I2C5, I2C5_DESC); + * SS_PIN_DECL(E3, GPIOK0, SCL5); + */ +#define SS_PIN_DECL(pin, other, sig) \ + SIG_EXPR_LIST_DECL_SINGLE(other, other); \ + MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)) + +/** + * Single signal, single function pin declaration + * + * @pin: The pin number + * @other: Macro name for "other" functionality (subjected to stringification) + * @sig: Macro name for the signal (subjected to stringification) + * @...: Signal descriptors that define the function expression + * + * For example: + * + * SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2)); + */ +#define SSSF_PIN_DECL(pin, other, sig, ...) \ + SIG_EXPR_LIST_DECL_SINGLE(sig, sig, __VA_ARGS__); \ + SIG_EXPR_LIST_DECL_SINGLE(other, other); \ + MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(sig), SIG_EXPR_LIST_PTR(other)); \ + FUNC_GROUP_DECL(sig, pin) + +#define GPIO_PIN_DECL(pin, gpio) \ + SIG_EXPR_LIST_DECL_SINGLE(gpio, gpio); \ + MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio)) + +struct aspeed_pin_group { + const char *name; + const unsigned int *pins; + const unsigned int npins; +}; + +#define ASPEED_PINCTRL_GROUP(name_) { \ + .name = #name_, \ + .pins = &(PIN_GROUP_SYM(name_))[0], \ + .npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \ +} + +struct aspeed_pin_function { + const char *name; + const char *const *groups; + unsigned int ngroups; +}; + +#define ASPEED_PINCTRL_FUNC(name_, ...) { \ + .name = #name_, \ + .groups = &FUNC_GROUP_SYM(name_)[0], \ + .ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \ +} + +struct aspeed_pinmux_data; + +struct aspeed_pinmux_ops { + int (*set)(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr, bool enabled); +}; + +struct aspeed_pinmux_data { + struct regmap *maps[ASPEED_NR_PINMUX_IPS]; + + const struct aspeed_pinmux_ops *ops; + + const struct aspeed_pin_group *groups; + const unsigned int ngroups; + + const struct aspeed_pin_function *functions; + const unsigned int nfunctions; +}; + +int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc, bool enabled, + struct regmap *map); + +int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr, + bool enabled); + +static inline int aspeed_sig_expr_set(const struct aspeed_pinmux_data *ctx, + const struct aspeed_sig_expr *expr, + bool enabled) +{ + return ctx->ops->set(ctx, expr, enabled); +} + +#endif /* ASPEED_PINMUX_H */ diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig index 97284c3f9e83..dcf7df797af7 100644 --- a/drivers/pinctrl/bcm/Kconfig +++ b/drivers/pinctrl/bcm/Kconfig @@ -18,11 +18,15 @@ config PINCTRL_BCM281XX framework. GPIO is provided by a separate GPIO driver. config PINCTRL_BCM2835 - bool + bool "Broadcom BCM2835 GPIO (with PINCONF) driver" + depends on OF && (ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST) select PINMUX select PINCONF select GENERIC_PINCONF select GPIOLIB_IRQCHIP + default ARCH_BCM2835 || ARCH_BRCMSTB + help + Say Y here to enable the Broadcom BCM2835 GPIO driver. config PINCTRL_IPROC_GPIO bool "Broadcom iProc GPIO (with PINCONF) driver" diff --git a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c index 4b5cf0e0f16e..2bf6af7df7d9 100644 --- a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c @@ -1048,6 +1048,8 @@ static int ns2_pinmux_probe(struct platform_device *pdev) return PTR_ERR(pinctrl->base0); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -EINVAL; pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!pinctrl->base1) { diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l35.c b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c index 06b59160783d..53a8eab19aad 100644 --- a/drivers/pinctrl/cirrus/pinctrl-cs47l35.c +++ b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c @@ -1,12 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Pinctrl for Cirrus Logic CS47L35 * * Copyright (C) 2016-2017 Cirrus Logic - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2. */ #include <linux/err.h> diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l85.c b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c index 0a322e2a0fde..e08c7992d252 100644 --- a/drivers/pinctrl/cirrus/pinctrl-cs47l85.c +++ b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c @@ -1,12 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Pinctrl for Cirrus Logic CS47L85 * * Copyright (C) 2016-2017 Cirrus Logic - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2. */ #include <linux/err.h> diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l90.c b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c index fc38f579f492..3151f107adc4 100644 --- a/drivers/pinctrl/cirrus/pinctrl-cs47l90.c +++ b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c @@ -1,12 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Pinctrl for Cirrus Logic CS47L90 * * Copyright (C) 2016-2017 Cirrus Logic - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2. */ #include <linux/err.h> diff --git a/drivers/pinctrl/cirrus/pinctrl-madera-core.c b/drivers/pinctrl/cirrus/pinctrl-madera-core.c index 7c9694593f79..c6b9f65f2362 100644 --- a/drivers/pinctrl/cirrus/pinctrl-madera-core.c +++ b/drivers/pinctrl/cirrus/pinctrl-madera-core.c @@ -1,12 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Pinctrl for Cirrus Logic Madera codecs * * Copyright (C) 2016-2018 Cirrus Logic - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2. */ #include <linux/err.h> diff --git a/drivers/pinctrl/cirrus/pinctrl-madera.h b/drivers/pinctrl/cirrus/pinctrl-madera.h index 8000f4f832a1..4ae13918316f 100644 --- a/drivers/pinctrl/cirrus/pinctrl-madera.h +++ b/drivers/pinctrl/cirrus/pinctrl-madera.h @@ -1,12 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Pinctrl for Cirrus Logic Madera codecs * * Copyright (C) 2016-2017 Cirrus Logic - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2. */ #ifndef PINCTRL_MADERA_H diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index a64849a9d1b0..b70df27874d1 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata); */ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname) { - struct pinctrl_dev *pctldev = NULL; + struct pinctrl_dev *pctldev; if (!devname) return NULL; @@ -177,29 +177,6 @@ const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin) return desc->name; } -/** - * pin_is_valid() - check if pin exists on controller - * @pctldev: the pin control device to check the pin on - * @pin: pin to check, use the local pin controller index number - * - * This tells us whether a certain pin exist on a certain pin controller or - * not. Pin lists may be sparse, so some pins may not exist. - */ -bool pin_is_valid(struct pinctrl_dev *pctldev, int pin) -{ - struct pin_desc *pindesc; - - if (pin < 0) - return false; - - mutex_lock(&pctldev->mutex); - pindesc = pin_desc_get(pctldev, pin); - mutex_unlock(&pctldev->mutex); - - return pindesc != NULL; -} -EXPORT_SYMBOL_GPL(pin_is_valid); - /* Deletes a range of pin descriptors */ static void pinctrl_free_pindescs(struct pinctrl_dev *pctldev, const struct pinctrl_pin_desc *pins, @@ -311,7 +288,7 @@ static inline int gpio_to_pin(struct pinctrl_gpio_range *range, static struct pinctrl_gpio_range * pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio) { - struct pinctrl_gpio_range *range = NULL; + struct pinctrl_gpio_range *range; mutex_lock(&pctldev->mutex); /* Loop over the ranges */ @@ -391,7 +368,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio, struct pinctrl_dev **outdev, struct pinctrl_gpio_range **outrange) { - struct pinctrl_dev *pctldev = NULL; + struct pinctrl_dev *pctldev; mutex_lock(&pinctrldev_list_mutex); @@ -1215,6 +1192,15 @@ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, } EXPORT_SYMBOL_GPL(pinctrl_lookup_state); +static void pinctrl_link_add(struct pinctrl_dev *pctldev, + struct device *consumer) +{ + if (pctldev->desc->link_consumers) + device_link_add(consumer, pctldev->dev, + DL_FLAG_PM_RUNTIME | + DL_FLAG_AUTOREMOVE_CONSUMER); +} + /** * pinctrl_commit_state() - select/activate/program a pinctrl state to HW * @p: the pinctrl handle for the device that requests configuration @@ -1260,6 +1246,10 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) if (ret < 0) { goto unapply_new_state; } + + /* Do not link hogs (circular dependency) */ + if (p != setting->pctldev->p) + pinctrl_link_add(setting->pctldev, p->dev); } p->state = state; @@ -1665,7 +1655,7 @@ DEFINE_SHOW_ATTRIBUTE(pinctrl_groups); static int pinctrl_gpioranges_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; - struct pinctrl_gpio_range *range = NULL; + struct pinctrl_gpio_range *range; seq_puts(s, "GPIO ranges handled:\n"); diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index f7e354f85518..88ddbb2e30de 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -112,12 +112,11 @@ static int dt_to_map_one_config(struct pinctrl *p, np_pctldev = of_get_next_parent(np_pctldev); if (!np_pctldev || of_node_is_root(np_pctldev)) { of_node_put(np_pctldev); - ret = driver_deferred_probe_check_state(p->dev); /* keep deferring if modules are enabled unless we've timed out */ - if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret == -ENODEV) - ret = -EPROBE_DEFER; + if (IS_ENABLED(CONFIG_MODULES) && !allow_default) + return driver_deferred_probe_check_state_continue(p->dev); - return ret; + return driver_deferred_probe_check_state(p->dev); } /* If we're creating a hog we can use the passed pctldev */ if (hog_pctldev && (np_pctldev == p->dev->of_node)) { diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index aeab0d9af23e..5f4058033ec6 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -130,6 +130,13 @@ config PINCTRL_IMX8MM help Say Y here to enable the imx8mm pinctrl driver +config PINCTRL_IMX8MN + bool "IMX8MN pinctrl driver" + depends on ARCH_MXC && ARM64 + select PINCTRL_IMX + help + Say Y here to enable the imx8mn pinctrl driver + config PINCTRL_IMX8MQ bool "IMX8MQ pinctrl driver" depends on ARCH_MXC && ARM64 diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 02020a76bd9c..78e9140c13e3 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D) += pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o obj-$(CONFIG_PINCTRL_IMX8MM) += pinctrl-imx8mm.o +obj-$(CONFIG_PINCTRL_IMX8MN) += pinctrl-imx8mn.o obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o obj-$(CONFIG_PINCTRL_IMX8QM) += pinctrl-imx8qm.o obj-$(CONFIG_PINCTRL_IMX8QXP) += pinctrl-imx8qxp.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mn.c b/drivers/pinctrl/freescale/pinctrl-imx8mn.c new file mode 100644 index 000000000000..100ed8c1039a --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx8mn.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018-2019 NXP + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> + +#include "pinctrl-imx.h" + +enum imx8mn_pads { + MX8MN_PAD_RESERVE0 = 0, + MX8MN_PAD_RESERVE1 = 1, + MX8MN_PAD_RESERVE2 = 2, + MX8MN_PAD_RESERVE3 = 3, + MX8MN_PAD_RESERVE4 = 4, + MX8MN_PAD_RESERVE5 = 5, + MX8MN_PAD_RESERVE6 = 6, + MX8MN_PAD_RESERVE7 = 7, + MX8MN_IOMUXC_BOOT_MODE2 = 8, + MX8MN_IOMUXC_BOOT_MODE3 = 9, + MX8MN_IOMUXC_GPIO1_IO00 = 10, + MX8MN_IOMUXC_GPIO1_IO01 = 11, + MX8MN_IOMUXC_GPIO1_IO02 = 12, + MX8MN_IOMUXC_GPIO1_IO03 = 13, + MX8MN_IOMUXC_GPIO1_IO04 = 14, + MX8MN_IOMUXC_GPIO1_IO05 = 15, + MX8MN_IOMUXC_GPIO1_IO06 = 16, + MX8MN_IOMUXC_GPIO1_IO07 = 17, + MX8MN_IOMUXC_GPIO1_IO08 = 18, + MX8MN_IOMUXC_GPIO1_IO09 = 19, + MX8MN_IOMUXC_GPIO1_IO10 = 20, + MX8MN_IOMUXC_GPIO1_IO11 = 21, + MX8MN_IOMUXC_GPIO1_IO12 = 22, + MX8MN_IOMUXC_GPIO1_IO13 = 23, + MX8MN_IOMUXC_GPIO1_IO14 = 24, + MX8MN_IOMUXC_GPIO1_IO15 = 25, + MX8MN_IOMUXC_ENET_MDC = 26, + MX8MN_IOMUXC_ENET_MDIO = 27, + MX8MN_IOMUXC_ENET_TD3 = 28, + MX8MN_IOMUXC_ENET_TD2 = 29, + MX8MN_IOMUXC_ENET_TD1 = 30, + MX8MN_IOMUXC_ENET_TD0 = 31, + MX8MN_IOMUXC_ENET_TX_CTL = 32, + MX8MN_IOMUXC_ENET_TXC = 33, + MX8MN_IOMUXC_ENET_RX_CTL = 34, + MX8MN_IOMUXC_ENET_RXC = 35, + MX8MN_IOMUXC_ENET_RD0 = 36, + MX8MN_IOMUXC_ENET_RD1 = 37, + MX8MN_IOMUXC_ENET_RD2 = 38, + MX8MN_IOMUXC_ENET_RD3 = 39, + MX8MN_IOMUXC_SD1_CLK = 40, + MX8MN_IOMUXC_SD1_CMD = 41, + MX8MN_IOMUXC_SD1_DATA0 = 42, + MX8MN_IOMUXC_SD1_DATA1 = 43, + MX8MN_IOMUXC_SD1_DATA2 = 44, + MX8MN_IOMUXC_SD1_DATA3 = 45, + MX8MN_IOMUXC_SD1_DATA4 = 46, + MX8MN_IOMUXC_SD1_DATA5 = 47, + MX8MN_IOMUXC_SD1_DATA6 = 48, + MX8MN_IOMUXC_SD1_DATA7 = 49, + MX8MN_IOMUXC_SD1_RESET_B = 50, + MX8MN_IOMUXC_SD1_STROBE = 51, + MX8MN_IOMUXC_SD2_CD_B = 52, + MX8MN_IOMUXC_SD2_CLK = 53, + MX8MN_IOMUXC_SD2_CMD = 54, + MX8MN_IOMUXC_SD2_DATA0 = 55, + MX8MN_IOMUXC_SD2_DATA1 = 56, + MX8MN_IOMUXC_SD2_DATA2 = 57, + MX8MN_IOMUXC_SD2_DATA3 = 58, + MX8MN_IOMUXC_SD2_RESET_B = 59, + MX8MN_IOMUXC_SD2_WP = 60, + MX8MN_IOMUXC_NAND_ALE = 61, + MX8MN_IOMUXC_NAND_CE0 = 62, + MX8MN_IOMUXC_NAND_CE1 = 63, + MX8MN_IOMUXC_NAND_CE2 = 64, + MX8MN_IOMUXC_NAND_CE3 = 65, + MX8MN_IOMUXC_NAND_CLE = 66, + MX8MN_IOMUXC_NAND_DATA00 = 67, + MX8MN_IOMUXC_NAND_DATA01 = 68, + MX8MN_IOMUXC_NAND_DATA02 = 69, + MX8MN_IOMUXC_NAND_DATA03 = 70, + MX8MN_IOMUXC_NAND_DATA04 = 71, + MX8MN_IOMUXC_NAND_DATA05 = 72, + MX8MN_IOMUXC_NAND_DATA06 = 73, + MX8MN_IOMUXC_NAND_DATA07 = 74, + MX8MN_IOMUXC_NAND_DQS = 75, + MX8MN_IOMUXC_NAND_RE_B = 76, + MX8MN_IOMUXC_NAND_READY_B = 77, + MX8MN_IOMUXC_NAND_WE_B = 78, + MX8MN_IOMUXC_NAND_WP_B = 79, + MX8MN_IOMUXC_SAI5_RXFS = 80, + MX8MN_IOMUXC_SAI5_RXC = 81, + MX8MN_IOMUXC_SAI5_RXD0 = 82, + MX8MN_IOMUXC_SAI5_RXD1 = 83, + MX8MN_IOMUXC_SAI5_RXD2 = 84, + MX8MN_IOMUXC_SAI5_RXD3 = 85, + MX8MN_IOMUXC_SAI5_MCLK = 86, + MX8MN_IOMUXC_SAI1_RXFS = 87, + MX8MN_IOMUXC_SAI1_RXC = 88, + MX8MN_IOMUXC_SAI1_RXD0 = 89, + MX8MN_IOMUXC_SAI1_RXD1 = 90, + MX8MN_IOMUXC_SAI1_RXD2 = 91, + MX8MN_IOMUXC_SAI1_RXD3 = 92, + MX8MN_IOMUXC_SAI1_RXD4 = 93, + MX8MN_IOMUXC_SAI1_RXD5 = 94, + MX8MN_IOMUXC_SAI1_RXD6 = 95, + MX8MN_IOMUXC_SAI1_RXD7 = 96, + MX8MN_IOMUXC_SAI1_TXFS = 97, + MX8MN_IOMUXC_SAI1_TXC = 98, + MX8MN_IOMUXC_SAI1_TXD0 = 99, + MX8MN_IOMUXC_SAI1_TXD1 = 100, + MX8MN_IOMUXC_SAI1_TXD2 = 101, + MX8MN_IOMUXC_SAI1_TXD3 = 102, + MX8MN_IOMUXC_SAI1_TXD4 = 103, + MX8MN_IOMUXC_SAI1_TXD5 = 104, + MX8MN_IOMUXC_SAI1_TXD6 = 105, + MX8MN_IOMUXC_SAI1_TXD7 = 106, + MX8MN_IOMUXC_SAI1_MCLK = 107, + MX8MN_IOMUXC_SAI2_RXFS = 108, + MX8MN_IOMUXC_SAI2_RXC = 109, + MX8MN_IOMUXC_SAI2_RXD0 = 110, + MX8MN_IOMUXC_SAI2_TXFS = 111, + MX8MN_IOMUXC_SAI2_TXC = 112, + MX8MN_IOMUXC_SAI2_TXD0 = 113, + MX8MN_IOMUXC_SAI2_MCLK = 114, + MX8MN_IOMUXC_SAI3_RXFS = 115, + MX8MN_IOMUXC_SAI3_RXC = 116, + MX8MN_IOMUXC_SAI3_RXD = 117, + MX8MN_IOMUXC_SAI3_TXFS = 118, + MX8MN_IOMUXC_SAI3_TXC = 119, + MX8MN_IOMUXC_SAI3_TXD = 120, + MX8MN_IOMUXC_SAI3_MCLK = 121, + MX8MN_IOMUXC_SPDIF_TX = 122, + MX8MN_IOMUXC_SPDIF_RX = 123, + MX8MN_IOMUXC_SPDIF_EXT_CLK = 124, + MX8MN_IOMUXC_ECSPI1_SCLK = 125, + MX8MN_IOMUXC_ECSPI1_MOSI = 126, + MX8MN_IOMUXC_ECSPI1_MISO = 127, + MX8MN_IOMUXC_ECSPI1_SS0 = 128, + MX8MN_IOMUXC_ECSPI2_SCLK = 129, + MX8MN_IOMUXC_ECSPI2_MOSI = 130, + MX8MN_IOMUXC_ECSPI2_MISO = 131, + MX8MN_IOMUXC_ECSPI2_SS0 = 132, + MX8MN_IOMUXC_I2C1_SCL = 133, + MX8MN_IOMUXC_I2C1_SDA = 134, + MX8MN_IOMUXC_I2C2_SCL = 135, + MX8MN_IOMUXC_I2C2_SDA = 136, + MX8MN_IOMUXC_I2C3_SCL = 137, + MX8MN_IOMUXC_I2C3_SDA = 138, + MX8MN_IOMUXC_I2C4_SCL = 139, + MX8MN_IOMUXC_I2C4_SDA = 140, + MX8MN_IOMUXC_UART1_RXD = 141, + MX8MN_IOMUXC_UART1_TXD = 142, + MX8MN_IOMUXC_UART2_RXD = 143, + MX8MN_IOMUXC_UART2_TXD = 144, + MX8MN_IOMUXC_UART3_RXD = 145, + MX8MN_IOMUXC_UART3_TXD = 146, + MX8MN_IOMUXC_UART4_RXD = 147, + MX8MN_IOMUXC_UART4_TXD = 148, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx8mn_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE0), + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE1), + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE2), + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE3), + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE4), + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE5), + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE6), + IMX_PINCTRL_PIN(MX8MN_PAD_RESERVE7), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_BOOT_MODE2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_BOOT_MODE3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO00), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO01), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO02), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO03), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO04), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO05), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO06), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO07), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO08), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO09), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO10), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO11), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO12), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO13), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO14), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_GPIO1_IO15), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_MDC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_MDIO), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TD0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TX_CTL), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_TXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RX_CTL), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ENET_RD3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_CLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_CMD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA4), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA5), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA6), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_DATA7), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_RESET_B), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD1_STROBE), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CD_B), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_CMD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_DATA3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_RESET_B), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SD2_WP), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_ALE), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CE3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_CLE), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA00), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA01), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA02), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA03), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA04), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA05), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA06), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DATA07), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_DQS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_RE_B), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_READY_B), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_WE_B), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_NAND_WP_B), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXFS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_RXD3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI5_MCLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXFS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD4), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD5), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD6), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_RXD7), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXFS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD1), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD2), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD3), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD4), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD5), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD6), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_TXD7), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI1_MCLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXFS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_RXD0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXFS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_TXD0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI2_MCLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXFS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_RXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXFS), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXC), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_TXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SAI3_MCLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_TX), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_RX), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_SPDIF_EXT_CLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_SCLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_MOSI), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_MISO), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI1_SS0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_SCLK), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_MOSI), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_MISO), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_ECSPI2_SS0), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C1_SCL), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C1_SDA), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C2_SCL), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C2_SDA), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C3_SCL), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C3_SDA), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C4_SCL), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_I2C4_SDA), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART1_RXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART1_TXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART2_RXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART2_TXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART3_RXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART3_TXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART4_RXD), + IMX_PINCTRL_PIN(MX8MN_IOMUXC_UART4_TXD), +}; + +static struct imx_pinctrl_soc_info imx8mn_pinctrl_info = { + .pins = imx8mn_pinctrl_pads, + .npins = ARRAY_SIZE(imx8mn_pinctrl_pads), + .gpr_compatible = "fsl,imx8mn-iomuxc-gpr", +}; + +static const struct of_device_id imx8mn_pinctrl_of_match[] = { + { .compatible = "fsl,imx8mn-iomuxc", .data = &imx8mn_pinctrl_info, }, + { /* sentinel */ } +}; + +static int imx8mn_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx8mn_pinctrl_info); +} + +static struct platform_driver imx8mn_pinctrl_driver = { + .driver = { + .name = "imx8mn-pinctrl", + .of_match_table = of_match_ptr(imx8mn_pinctrl_of_match), + .suppress_bind_attrs = true, + }, + .probe = imx8mn_pinctrl_probe, +}; + +static int __init imx8mn_pinctrl_init(void) +{ + return platform_driver_register(&imx8mn_pinctrl_driver); +} +arch_initcall(imx8mn_pinctrl_init); diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 18d9ad504194..e5a112a8e067 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -24,6 +24,8 @@ #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> +#include "pinctrl-intel.h" + /* memory mapped register offsets */ #define BYT_CONF0_REG 0x000 #define BYT_CONF1_REG 0x004 @@ -35,6 +37,7 @@ /* BYT_CONF0_REG register bits */ #define BYT_IODEN BIT(31) #define BYT_DIRECT_IRQ_EN BIT(27) +#define BYT_TRIG_MASK GENMASK(26, 24) #define BYT_TRIG_NEG BIT(26) #define BYT_TRIG_POS BIT(25) #define BYT_TRIG_LVL BIT(24) @@ -43,31 +46,28 @@ #define BYT_GLITCH_F_SLOW_CLK BIT(17) #define BYT_GLITCH_F_FAST_CLK BIT(16) #define BYT_PULL_STR_SHIFT 9 -#define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT) +#define BYT_PULL_STR_MASK GENMASK(10, 9) #define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT) #define BYT_PULL_STR_10K (1 << BYT_PULL_STR_SHIFT) #define BYT_PULL_STR_20K (2 << BYT_PULL_STR_SHIFT) #define BYT_PULL_STR_40K (3 << BYT_PULL_STR_SHIFT) #define BYT_PULL_ASSIGN_SHIFT 7 -#define BYT_PULL_ASSIGN_MASK (3 << BYT_PULL_ASSIGN_SHIFT) +#define BYT_PULL_ASSIGN_MASK GENMASK(8, 7) #define BYT_PULL_ASSIGN_UP (1 << BYT_PULL_ASSIGN_SHIFT) #define BYT_PULL_ASSIGN_DOWN (2 << BYT_PULL_ASSIGN_SHIFT) -#define BYT_PIN_MUX 0x07 +#define BYT_PIN_MUX GENMASK(2, 0) /* BYT_VAL_REG register bits */ +#define BYT_DIR_MASK GENMASK(2, 1) #define BYT_INPUT_EN BIT(2) /* 0: input enabled (active low)*/ #define BYT_OUTPUT_EN BIT(1) /* 0: output enabled (active low)*/ #define BYT_LEVEL BIT(0) -#define BYT_DIR_MASK (BIT(1) | BIT(2)) -#define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24)) - -#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \ - BYT_PIN_MUX) +#define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | BYT_PIN_MUX) #define BYT_VAL_RESTORE_MASK (BYT_DIR_MASK | BYT_LEVEL) /* BYT_DEBOUNCE_REG bits */ -#define BYT_DEBOUNCE_PULSE_MASK 0x7 +#define BYT_DEBOUNCE_PULSE_MASK GENMASK(2, 0) #define BYT_DEBOUNCE_PULSE_375US 1 #define BYT_DEBOUNCE_PULSE_750US 2 #define BYT_DEBOUNCE_PULSE_1500US 3 @@ -91,40 +91,13 @@ * does not find a match for the requested function. */ #define BYT_DEFAULT_GPIO_MUX 0 +#define BYT_ALTER_GPIO_MUX 1 struct byt_gpio_pin_context { u32 conf0; u32 val; }; -struct byt_simple_func_mux { - const char *name; - unsigned short func; -}; - -struct byt_mixed_func_mux { - const char *name; - const unsigned short *func_values; -}; - -struct byt_pingroup { - const char *name; - const unsigned int *pins; - size_t npins; - unsigned short has_simple_funcs; - union { - const struct byt_simple_func_mux *simple_funcs; - const struct byt_mixed_func_mux *mixed_funcs; - }; - size_t nfuncs; -}; - -struct byt_function { - const char *name; - const char * const *groups; - size_t ngroups; -}; - struct byt_community { unsigned int pin_base; size_t npins; @@ -132,47 +105,6 @@ struct byt_community { void __iomem *reg_base; }; -#define SIMPLE_FUNC(n, f) \ - { \ - .name = (n), \ - .func = (f), \ - } -#define MIXED_FUNC(n, f) \ - { \ - .name = (n), \ - .func_values = (f), \ - } - -#define PIN_GROUP_SIMPLE(n, p, f) \ - { \ - .name = (n), \ - .pins = (p), \ - .npins = ARRAY_SIZE((p)), \ - .has_simple_funcs = 1, \ - { \ - .simple_funcs = (f), \ - }, \ - .nfuncs = ARRAY_SIZE((f)), \ - } -#define PIN_GROUP_MIXED(n, p, f) \ - { \ - .name = (n), \ - .pins = (p), \ - .npins = ARRAY_SIZE((p)), \ - .has_simple_funcs = 0, \ - { \ - .mixed_funcs = (f), \ - }, \ - .nfuncs = ARRAY_SIZE((f)), \ - } - -#define FUNCTION(n, g) \ - { \ - .name = (n), \ - .groups = (g), \ - .ngroups = ARRAY_SIZE((g)), \ - } - #define COMMUNITY(p, n, map) \ { \ .pin_base = (p), \ @@ -184,9 +116,9 @@ struct byt_pinctrl_soc_data { const char *uid; const struct pinctrl_pin_desc *pins; size_t npins; - const struct byt_pingroup *groups; + const struct intel_pingroup *groups; size_t ngroups; - const struct byt_function *functions; + const struct intel_function *functions; size_t nfunctions; const struct byt_community *communities; size_t ncommunities; @@ -326,20 +258,11 @@ static const unsigned int byt_score_pins_map[BYT_NGPIO_SCORE] = { /* SCORE groups */ static const unsigned int byt_score_uart1_pins[] = { 70, 71, 72, 73 }; static const unsigned int byt_score_uart2_pins[] = { 74, 75, 76, 77 }; -static const struct byt_simple_func_mux byt_score_uart_mux[] = { - SIMPLE_FUNC("uart", 1), -}; static const unsigned int byt_score_pwm0_pins[] = { 94 }; static const unsigned int byt_score_pwm1_pins[] = { 95 }; -static const struct byt_simple_func_mux byt_score_pwm_mux[] = { - SIMPLE_FUNC("pwm", 1), -}; static const unsigned int byt_score_sio_spi_pins[] = { 66, 67, 68, 69 }; -static const struct byt_simple_func_mux byt_score_spi_mux[] = { - SIMPLE_FUNC("spi", 1), -}; static const unsigned int byt_score_i2c5_pins[] = { 88, 89 }; static const unsigned int byt_score_i2c6_pins[] = { 90, 91 }; @@ -348,50 +271,29 @@ static const unsigned int byt_score_i2c3_pins[] = { 84, 85 }; static const unsigned int byt_score_i2c2_pins[] = { 82, 83 }; static const unsigned int byt_score_i2c1_pins[] = { 80, 81 }; static const unsigned int byt_score_i2c0_pins[] = { 78, 79 }; -static const struct byt_simple_func_mux byt_score_i2c_mux[] = { - SIMPLE_FUNC("i2c", 1), -}; static const unsigned int byt_score_ssp0_pins[] = { 8, 9, 10, 11 }; static const unsigned int byt_score_ssp1_pins[] = { 12, 13, 14, 15 }; static const unsigned int byt_score_ssp2_pins[] = { 62, 63, 64, 65 }; -static const struct byt_simple_func_mux byt_score_ssp_mux[] = { - SIMPLE_FUNC("ssp", 1), -}; static const unsigned int byt_score_sdcard_pins[] = { 7, 33, 34, 35, 36, 37, 38, 39, 40, 41, }; -static const unsigned short byt_score_sdcard_mux_values[] = { +static const unsigned int byt_score_sdcard_mux_values[] = { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; -static const struct byt_mixed_func_mux byt_score_sdcard_mux[] = { - MIXED_FUNC("sdcard", byt_score_sdcard_mux_values), -}; static const unsigned int byt_score_sdio_pins[] = { 27, 28, 29, 30, 31, 32 }; -static const struct byt_simple_func_mux byt_score_sdio_mux[] = { - SIMPLE_FUNC("sdio", 1), -}; static const unsigned int byt_score_emmc_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, }; -static const struct byt_simple_func_mux byt_score_emmc_mux[] = { - SIMPLE_FUNC("emmc", 1), -}; static const unsigned int byt_score_ilb_lpc_pins[] = { 42, 43, 44, 45, 46, 47, 48, 49, 50, }; -static const struct byt_simple_func_mux byt_score_lpc_mux[] = { - SIMPLE_FUNC("lpc", 1), -}; static const unsigned int byt_score_sata_pins[] = { 0, 1, 2 }; -static const struct byt_simple_func_mux byt_score_sata_mux[] = { - SIMPLE_FUNC("sata", 1), -}; static const unsigned int byt_score_plt_clk0_pins[] = { 96 }; static const unsigned int byt_score_plt_clk1_pins[] = { 97 }; @@ -399,70 +301,37 @@ static const unsigned int byt_score_plt_clk2_pins[] = { 98 }; static const unsigned int byt_score_plt_clk3_pins[] = { 99 }; static const unsigned int byt_score_plt_clk4_pins[] = { 100 }; static const unsigned int byt_score_plt_clk5_pins[] = { 101 }; -static const struct byt_simple_func_mux byt_score_plt_clk_mux[] = { - SIMPLE_FUNC("plt_clk", 1), -}; static const unsigned int byt_score_smbus_pins[] = { 51, 52, 53 }; -static const struct byt_simple_func_mux byt_score_smbus_mux[] = { - SIMPLE_FUNC("smbus", 1), -}; -static const struct byt_pingroup byt_score_groups[] = { - PIN_GROUP_SIMPLE("uart1_grp", - byt_score_uart1_pins, byt_score_uart_mux), - PIN_GROUP_SIMPLE("uart2_grp", - byt_score_uart2_pins, byt_score_uart_mux), - PIN_GROUP_SIMPLE("pwm0_grp", - byt_score_pwm0_pins, byt_score_pwm_mux), - PIN_GROUP_SIMPLE("pwm1_grp", - byt_score_pwm1_pins, byt_score_pwm_mux), - PIN_GROUP_SIMPLE("ssp2_grp", - byt_score_ssp2_pins, byt_score_pwm_mux), - PIN_GROUP_SIMPLE("sio_spi_grp", - byt_score_sio_spi_pins, byt_score_spi_mux), - PIN_GROUP_SIMPLE("i2c5_grp", - byt_score_i2c5_pins, byt_score_i2c_mux), - PIN_GROUP_SIMPLE("i2c6_grp", - byt_score_i2c6_pins, byt_score_i2c_mux), - PIN_GROUP_SIMPLE("i2c4_grp", - byt_score_i2c4_pins, byt_score_i2c_mux), - PIN_GROUP_SIMPLE("i2c3_grp", - byt_score_i2c3_pins, byt_score_i2c_mux), - PIN_GROUP_SIMPLE("i2c2_grp", - byt_score_i2c2_pins, byt_score_i2c_mux), - PIN_GROUP_SIMPLE("i2c1_grp", - byt_score_i2c1_pins, byt_score_i2c_mux), - PIN_GROUP_SIMPLE("i2c0_grp", - byt_score_i2c0_pins, byt_score_i2c_mux), - PIN_GROUP_SIMPLE("ssp0_grp", - byt_score_ssp0_pins, byt_score_ssp_mux), - PIN_GROUP_SIMPLE("ssp1_grp", - byt_score_ssp1_pins, byt_score_ssp_mux), - PIN_GROUP_MIXED("sdcard_grp", - byt_score_sdcard_pins, byt_score_sdcard_mux), - PIN_GROUP_SIMPLE("sdio_grp", - byt_score_sdio_pins, byt_score_sdio_mux), - PIN_GROUP_SIMPLE("emmc_grp", - byt_score_emmc_pins, byt_score_emmc_mux), - PIN_GROUP_SIMPLE("lpc_grp", - byt_score_ilb_lpc_pins, byt_score_lpc_mux), - PIN_GROUP_SIMPLE("sata_grp", - byt_score_sata_pins, byt_score_sata_mux), - PIN_GROUP_SIMPLE("plt_clk0_grp", - byt_score_plt_clk0_pins, byt_score_plt_clk_mux), - PIN_GROUP_SIMPLE("plt_clk1_grp", - byt_score_plt_clk1_pins, byt_score_plt_clk_mux), - PIN_GROUP_SIMPLE("plt_clk2_grp", - byt_score_plt_clk2_pins, byt_score_plt_clk_mux), - PIN_GROUP_SIMPLE("plt_clk3_grp", - byt_score_plt_clk3_pins, byt_score_plt_clk_mux), - PIN_GROUP_SIMPLE("plt_clk4_grp", - byt_score_plt_clk4_pins, byt_score_plt_clk_mux), - PIN_GROUP_SIMPLE("plt_clk5_grp", - byt_score_plt_clk5_pins, byt_score_plt_clk_mux), - PIN_GROUP_SIMPLE("smbus_grp", - byt_score_smbus_pins, byt_score_smbus_mux), +static const struct intel_pingroup byt_score_groups[] = { + PIN_GROUP("uart1_grp", byt_score_uart1_pins, 1), + PIN_GROUP("uart2_grp", byt_score_uart2_pins, 1), + PIN_GROUP("pwm0_grp", byt_score_pwm0_pins, 1), + PIN_GROUP("pwm1_grp", byt_score_pwm1_pins, 1), + PIN_GROUP("ssp2_grp", byt_score_ssp2_pins, 1), + PIN_GROUP("sio_spi_grp", byt_score_sio_spi_pins, 1), + PIN_GROUP("i2c5_grp", byt_score_i2c5_pins, 1), + PIN_GROUP("i2c6_grp", byt_score_i2c6_pins, 1), + PIN_GROUP("i2c4_grp", byt_score_i2c4_pins, 1), + PIN_GROUP("i2c3_grp", byt_score_i2c3_pins, 1), + PIN_GROUP("i2c2_grp", byt_score_i2c2_pins, 1), + PIN_GROUP("i2c1_grp", byt_score_i2c1_pins, 1), + PIN_GROUP("i2c0_grp", byt_score_i2c0_pins, 1), + PIN_GROUP("ssp0_grp", byt_score_ssp0_pins, 1), + PIN_GROUP("ssp1_grp", byt_score_ssp1_pins, 1), + PIN_GROUP("sdcard_grp", byt_score_sdcard_pins, byt_score_sdcard_mux_values), + PIN_GROUP("sdio_grp", byt_score_sdio_pins, 1), + PIN_GROUP("emmc_grp", byt_score_emmc_pins, 1), + PIN_GROUP("lpc_grp", byt_score_ilb_lpc_pins, 1), + PIN_GROUP("sata_grp", byt_score_sata_pins, 1), + PIN_GROUP("plt_clk0_grp", byt_score_plt_clk0_pins, 1), + PIN_GROUP("plt_clk1_grp", byt_score_plt_clk1_pins, 1), + PIN_GROUP("plt_clk2_grp", byt_score_plt_clk2_pins, 1), + PIN_GROUP("plt_clk3_grp", byt_score_plt_clk3_pins, 1), + PIN_GROUP("plt_clk4_grp", byt_score_plt_clk4_pins, 1), + PIN_GROUP("plt_clk5_grp", byt_score_plt_clk5_pins, 1), + PIN_GROUP("smbus_grp", byt_score_smbus_pins, 1), }; static const char * const byt_score_uart_groups[] = { @@ -496,10 +365,9 @@ static const char * const byt_score_gpio_groups[] = { "sdcard_grp", "sdio_grp", "emmc_grp", "lpc_grp", "sata_grp", "plt_clk0_grp", "plt_clk1_grp", "plt_clk2_grp", "plt_clk3_grp", "plt_clk4_grp", "plt_clk5_grp", "smbus_grp", - }; -static const struct byt_function byt_score_functions[] = { +static const struct intel_function byt_score_functions[] = { FUNCTION("uart", byt_score_uart_groups), FUNCTION("pwm", byt_score_pwm_groups), FUNCTION("ssp", byt_score_ssp_groups), @@ -588,38 +456,30 @@ static const unsigned int byt_sus_pins_map[BYT_NGPIO_SUS] = { }; static const unsigned int byt_sus_usb_over_current_pins[] = { 19, 20 }; -static const struct byt_simple_func_mux byt_sus_usb_oc_mux[] = { - SIMPLE_FUNC("usb", 0), - SIMPLE_FUNC("gpio", 1), -}; +static const unsigned int byt_sus_usb_over_current_mode_values[] = { 0, 0 }; +static const unsigned int byt_sus_usb_over_current_gpio_mode_values[] = { 1, 1 }; static const unsigned int byt_sus_usb_ulpi_pins[] = { 14, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, }; -static const unsigned short byt_sus_usb_ulpi_mode_values[] = { +static const unsigned int byt_sus_usb_ulpi_mode_values[] = { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; -static const unsigned short byt_sus_usb_ulpi_gpio_mode_values[] = { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; -static const struct byt_mixed_func_mux byt_sus_usb_ulpi_mux[] = { - MIXED_FUNC("usb", byt_sus_usb_ulpi_mode_values), - MIXED_FUNC("gpio", byt_sus_usb_ulpi_gpio_mode_values), +static const unsigned int byt_sus_usb_ulpi_gpio_mode_values[] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const unsigned int byt_sus_pcu_spi_pins[] = { 21 }; -static const struct byt_simple_func_mux byt_sus_pcu_spi_mux[] = { - SIMPLE_FUNC("spi", 0), - SIMPLE_FUNC("gpio", 1), -}; +static const unsigned int byt_sus_pcu_spi_mode_values[] = { 0 }; +static const unsigned int byt_sus_pcu_spi_gpio_mode_values[] = { 1 }; -static const struct byt_pingroup byt_sus_groups[] = { - PIN_GROUP_SIMPLE("usb_oc_grp", - byt_sus_usb_over_current_pins, byt_sus_usb_oc_mux), - PIN_GROUP_MIXED("usb_ulpi_grp", - byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_mux), - PIN_GROUP_SIMPLE("pcu_spi_grp", - byt_sus_pcu_spi_pins, byt_sus_pcu_spi_mux), +static const struct intel_pingroup byt_sus_groups[] = { + PIN_GROUP("usb_oc_grp", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_mode_values), + PIN_GROUP("usb_ulpi_grp", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_mode_values), + PIN_GROUP("pcu_spi_grp", byt_sus_pcu_spi_pins, byt_sus_pcu_spi_mode_values), + PIN_GROUP("usb_oc_grp_gpio", byt_sus_usb_over_current_pins, byt_sus_usb_over_current_gpio_mode_values), + PIN_GROUP("usb_ulpi_grp_gpio", byt_sus_usb_ulpi_pins, byt_sus_usb_ulpi_gpio_mode_values), + PIN_GROUP("pcu_spi_grp_gpio", byt_sus_pcu_spi_pins, byt_sus_pcu_spi_gpio_mode_values), }; static const char * const byt_sus_usb_groups[] = { @@ -627,10 +487,10 @@ static const char * const byt_sus_usb_groups[] = { }; static const char * const byt_sus_spi_groups[] = { "pcu_spi_grp" }; static const char * const byt_sus_gpio_groups[] = { - "usb_oc_grp", "usb_ulpi_grp", "pcu_spi_grp", + "usb_oc_grp_gpio", "usb_ulpi_grp_gpio", "pcu_spi_grp_gpio", }; -static const struct byt_function byt_sus_functions[] = { +static const struct intel_function byt_sus_functions[] = { FUNCTION("usb", byt_sus_usb_groups), FUNCTION("spi", byt_sus_spi_groups), FUNCTION("gpio", byt_sus_gpio_groups), @@ -810,41 +670,9 @@ static int byt_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int byt_get_group_simple_mux(const struct byt_pingroup group, - const char *func_name, - unsigned short *func) -{ - int i; - - for (i = 0; i < group.nfuncs; i++) { - if (!strcmp(group.simple_funcs[i].name, func_name)) { - *func = group.simple_funcs[i].func; - return 0; - } - } - - return 1; -} - -static int byt_get_group_mixed_mux(const struct byt_pingroup group, - const char *func_name, - const unsigned short **func) -{ - int i; - - for (i = 0; i < group.nfuncs; i++) { - if (!strcmp(group.mixed_funcs[i].name, func_name)) { - *func = group.mixed_funcs[i].func_values; - return 0; - } - } - - return 1; -} - static void byt_set_group_simple_mux(struct byt_gpio *vg, - const struct byt_pingroup group, - unsigned short func) + const struct intel_pingroup group, + unsigned int func) { unsigned long flags; int i; @@ -873,8 +701,8 @@ static void byt_set_group_simple_mux(struct byt_gpio *vg, } static void byt_set_group_mixed_mux(struct byt_gpio *vg, - const struct byt_pingroup group, - const unsigned short *func) + const struct intel_pingroup group, + const unsigned int *func) { unsigned long flags; int i; @@ -906,23 +734,15 @@ static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, unsigned int group_selector) { struct byt_gpio *vg = pinctrl_dev_get_drvdata(pctldev); - const struct byt_function func = vg->soc_data->functions[func_selector]; - const struct byt_pingroup group = vg->soc_data->groups[group_selector]; - const unsigned short *mixed_func; - unsigned short simple_func; - int ret = 1; - - if (group.has_simple_funcs) - ret = byt_get_group_simple_mux(group, func.name, &simple_func); - else - ret = byt_get_group_mixed_mux(group, func.name, &mixed_func); + const struct intel_function func = vg->soc_data->functions[func_selector]; + const struct intel_pingroup group = vg->soc_data->groups[group_selector]; - if (ret) + if (group.modes) + byt_set_group_mixed_mux(vg, group, group.modes); + else if (!strcmp(func.name, "gpio")) byt_set_group_simple_mux(vg, group, BYT_DEFAULT_GPIO_MUX); - else if (group.has_simple_funcs) - byt_set_group_simple_mux(vg, group, simple_func); else - byt_set_group_mixed_mux(vg, group, mixed_func); + byt_set_group_simple_mux(vg, group, group.mode); return 0; } @@ -932,14 +752,14 @@ 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) && offset >= 92 && offset <= 93) - return 1; + return BYT_ALTER_GPIO_MUX; /* SUS pin 11-21 */ if (!strcmp(vg->soc_data->uid, BYT_SUS_ACPI_UID) && offset >= 11 && offset <= 21) - return 1; + return BYT_ALTER_GPIO_MUX; - return 0; + return BYT_DEFAULT_GPIO_MUX; } static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned int offset) diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8183.c b/drivers/pinctrl/mediatek/pinctrl-mt8183.c index 2c7409ed16fa..9a74d5025be6 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8183.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8183.c @@ -583,6 +583,7 @@ static struct platform_driver mt8183_pinctrl_driver = { .driver = { .name = "mt8183-pinctrl", .of_match_table = mt8183_pinctrl_of_match, + .pm = &mtk_paris_pinctrl_pm_ops, }, .probe = mt8183_pinctrl_probe, }; diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c index d3b34e9a7507..923264d0e9ef 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.c +++ b/drivers/pinctrl/mediatek/pinctrl-paris.c @@ -926,3 +926,22 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev, return 0; } + +static int mtk_paris_pinctrl_suspend(struct device *device) +{ + struct mtk_pinctrl *pctl = dev_get_drvdata(device); + + return mtk_eint_do_suspend(pctl->eint); +} + +static int mtk_paris_pinctrl_resume(struct device *device) +{ + struct mtk_pinctrl *pctl = dev_get_drvdata(device); + + return mtk_eint_do_resume(pctl->eint); +} + +const struct dev_pm_ops mtk_paris_pinctrl_pm_ops = { + .suspend_noirq = mtk_paris_pinctrl_suspend, + .resume_noirq = mtk_paris_pinctrl_resume, +}; diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h index 37146caa667d..3d43771074e6 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.h +++ b/drivers/pinctrl/mediatek/pinctrl-paris.h @@ -60,4 +60,6 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev, const struct mtk_pin_soc *soc); +extern const struct dev_pm_ops mtk_paris_pinctrl_pm_ops; + #endif /* __PINCTRL_PARIS_H */ diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c index d494492e98e9..3475cd7bd2af 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c +++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c @@ -1304,28 +1304,28 @@ static struct meson_pmx_func meson_g12a_aobus_functions[] = { }; 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), + /* name first last irq pullen pull dir out in ds */ + BANK_DS("Z", GPIOZ_0, GPIOZ_15, 12, 27, + 4, 0, 4, 0, 12, 0, 13, 0, 14, 0, 5, 0), + BANK_DS("H", GPIOH_0, GPIOH_8, 28, 36, + 3, 0, 3, 0, 9, 0, 10, 0, 11, 0, 4, 0), + BANK_DS("BOOT", BOOT_0, BOOT_15, 37, 52, + 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0), + BANK_DS("C", GPIOC_0, GPIOC_7, 53, 60, + 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0), + BANK_DS("A", GPIOA_0, GPIOA_15, 61, 76, + 5, 0, 5, 0, 16, 0, 17, 0, 18, 0, 6, 0), + BANK_DS("X", GPIOX_0, GPIOX_19, 77, 96, + 2, 0, 2, 0, 6, 0, 7, 0, 8, 0, 2, 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), + /* name first last irq pullen pull dir out in ds */ + BANK_DS("AO", GPIOAO_0, GPIOAO_11, 0, 11, 3, 0, 2, 0, 0, 0, 4, 0, 1, 0, + 0, 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), + BANK_DS("E", GPIOE_0, GPIOE_2, 97, 99, 3, 16, 2, 16, 0, 16, 4, 16, 1, + 16, 1, 0), }; static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = { diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 077de5925783..596786926209 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -168,68 +168,223 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, return 0; } -static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, - unsigned long *configs, unsigned num_configs) +static int meson_pinconf_set_gpio_bit(struct meson_pinctrl *pc, + unsigned int pin, + unsigned int reg_type, + bool arg) { - struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); struct meson_bank *bank; - enum pin_config_param param; unsigned int reg, bit; - int i, ret; + int ret; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, reg_type, ®, &bit); + return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), + arg ? BIT(bit) : 0); +} + +static int meson_pinconf_get_gpio_bit(struct meson_pinctrl *pc, + unsigned int pin, + unsigned int reg_type) +{ + struct meson_bank *bank; + unsigned int reg, bit, val; + int ret; ret = meson_get_bank(pc, pin, &bank); if (ret) return ret; + meson_calc_reg_and_bit(bank, pin, reg_type, ®, &bit); + ret = regmap_read(pc->reg_gpio, reg, &val); + if (ret) + return ret; + + return BIT(bit) & val ? 1 : 0; +} + +static int meson_pinconf_set_output(struct meson_pinctrl *pc, + unsigned int pin, + bool out) +{ + return meson_pinconf_set_gpio_bit(pc, pin, REG_DIR, !out); +} + +static int meson_pinconf_get_output(struct meson_pinctrl *pc, + unsigned int pin) +{ + int ret = meson_pinconf_get_gpio_bit(pc, pin, REG_DIR); + + if (ret < 0) + return ret; + + return !ret; +} + +static int meson_pinconf_set_drive(struct meson_pinctrl *pc, + unsigned int pin, + bool high) +{ + return meson_pinconf_set_gpio_bit(pc, pin, REG_OUT, high); +} + +static int meson_pinconf_get_drive(struct meson_pinctrl *pc, + unsigned int pin) +{ + return meson_pinconf_get_gpio_bit(pc, pin, REG_OUT); +} + +static int meson_pinconf_set_output_drive(struct meson_pinctrl *pc, + unsigned int pin, + bool high) +{ + int ret; + + ret = meson_pinconf_set_output(pc, pin, true); + if (ret) + return ret; + + return meson_pinconf_set_drive(pc, pin, high); +} + +static int meson_pinconf_disable_bias(struct meson_pinctrl *pc, + unsigned int pin) +{ + struct meson_bank *bank; + unsigned int reg, bit = 0; + int ret; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); + ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0); + if (ret) + return ret; + + return 0; +} + +static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin, + bool pull_up) +{ + struct meson_bank *bank; + unsigned int reg, bit, val = 0; + int ret; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); + if (pull_up) + val = BIT(bit); + + ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); + ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit)); + if (ret) + return ret; + + return 0; +} + +static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc, + unsigned int pin, + u16 drive_strength_ua) +{ + struct meson_bank *bank; + unsigned int reg, bit, ds_val; + int ret; + + if (!pc->reg_ds) { + dev_err(pc->dev, "drive-strength not supported\n"); + return -ENOTSUPP; + } + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); + bit = bit << 1; + + if (drive_strength_ua <= 500) { + ds_val = MESON_PINCONF_DRV_500UA; + } else if (drive_strength_ua <= 2500) { + ds_val = MESON_PINCONF_DRV_2500UA; + } else if (drive_strength_ua <= 3000) { + ds_val = MESON_PINCONF_DRV_3000UA; + } else if (drive_strength_ua <= 4000) { + ds_val = MESON_PINCONF_DRV_4000UA; + } else { + dev_warn_once(pc->dev, + "pin %u: invalid drive-strength : %d , default to 4mA\n", + pin, drive_strength_ua); + ds_val = MESON_PINCONF_DRV_4000UA; + } + + ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit); + if (ret) + return ret; + + return 0; +} + +static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *configs, unsigned num_configs) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param; + unsigned int arg = 0; + int i, ret; + for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); switch (param) { + case PIN_CONFIG_DRIVE_STRENGTH_UA: + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_OUTPUT: + arg = pinconf_to_config_argument(configs[i]); + break; + + default: + break; + } + + switch (param) { case PIN_CONFIG_BIAS_DISABLE: - dev_dbg(pc->dev, "pin %u: disable bias\n", pin); - - meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, - &bit); - ret = regmap_update_bits(pc->reg_pullen, reg, - BIT(bit), 0); - if (ret) - return ret; + ret = meson_pinconf_disable_bias(pc, pin); break; case PIN_CONFIG_BIAS_PULL_UP: - dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin); - - meson_calc_reg_and_bit(bank, pin, REG_PULLEN, - ®, &bit); - ret = regmap_update_bits(pc->reg_pullen, reg, - BIT(bit), BIT(bit)); - if (ret) - return ret; - - meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); - ret = regmap_update_bits(pc->reg_pull, reg, - BIT(bit), BIT(bit)); - if (ret) - return ret; + ret = meson_pinconf_enable_bias(pc, pin, true); break; case PIN_CONFIG_BIAS_PULL_DOWN: - dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin); - - meson_calc_reg_and_bit(bank, pin, REG_PULLEN, - ®, &bit); - ret = regmap_update_bits(pc->reg_pullen, reg, - BIT(bit), BIT(bit)); - if (ret) - return ret; - - meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); - ret = regmap_update_bits(pc->reg_pull, reg, - BIT(bit), 0); - if (ret) - return ret; + ret = meson_pinconf_enable_bias(pc, pin, false); + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = meson_pinconf_set_drive_strength(pc, pin, arg); + break; + case PIN_CONFIG_OUTPUT_ENABLE: + ret = meson_pinconf_set_output(pc, pin, arg); + break; + case PIN_CONFIG_OUTPUT: + ret = meson_pinconf_set_output_drive(pc, pin, arg); break; default: - return -ENOTSUPP; + ret = -ENOTSUPP; } + + if (ret) + return ret; } return 0; @@ -269,12 +424,55 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin) return conf; } +static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc, + unsigned int pin, + u16 *drive_strength_ua) +{ + struct meson_bank *bank; + unsigned int reg, bit; + unsigned int val; + int ret; + + if (!pc->reg_ds) + return -ENOTSUPP; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); + + ret = regmap_read(pc->reg_ds, reg, &val); + if (ret) + return ret; + + switch ((val >> bit) & 0x3) { + case MESON_PINCONF_DRV_500UA: + *drive_strength_ua = 500; + break; + case MESON_PINCONF_DRV_2500UA: + *drive_strength_ua = 2500; + break; + case MESON_PINCONF_DRV_3000UA: + *drive_strength_ua = 3000; + break; + case MESON_PINCONF_DRV_4000UA: + *drive_strength_ua = 4000; + break; + default: + return -EINVAL; + } + + return 0; +} + static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, unsigned long *config) { struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); enum pin_config_param param = pinconf_to_config_param(*config); u16 arg; + int ret; switch (param) { case PIN_CONFIG_BIAS_DISABLE: @@ -285,6 +483,29 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, else return -EINVAL; break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = meson_pinconf_get_drive_strength(pc, pin, &arg); + if (ret) + return ret; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + ret = meson_pinconf_get_output(pc, pin); + if (ret <= 0) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_OUTPUT: + ret = meson_pinconf_get_output(pc, pin); + if (ret <= 0) + return -EINVAL; + + ret = meson_pinconf_get_drive(pc, pin); + if (ret < 0) + return -EINVAL; + + arg = ret; + break; + default: return -ENOTSUPP; } @@ -329,56 +550,19 @@ static const struct pinconf_ops meson_pinconf_ops = { static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { - struct meson_pinctrl *pc = gpiochip_get_data(chip); - unsigned int reg, bit; - struct meson_bank *bank; - int ret; - - ret = meson_get_bank(pc, gpio, &bank); - if (ret) - return ret; - - meson_calc_reg_and_bit(bank, gpio, REG_DIR, ®, &bit); - - return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), BIT(bit)); + return meson_pinconf_set_output(gpiochip_get_data(chip), gpio, false); } static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { - struct meson_pinctrl *pc = gpiochip_get_data(chip); - unsigned int reg, bit; - struct meson_bank *bank; - int ret; - - ret = meson_get_bank(pc, gpio, &bank); - if (ret) - return ret; - - meson_calc_reg_and_bit(bank, gpio, REG_DIR, ®, &bit); - ret = regmap_update_bits(pc->reg_gpio, reg, BIT(bit), 0); - if (ret) - return ret; - - meson_calc_reg_and_bit(bank, gpio, REG_OUT, ®, &bit); - return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), - value ? BIT(bit) : 0); + return meson_pinconf_set_output_drive(gpiochip_get_data(chip), + gpio, value); } static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) { - struct meson_pinctrl *pc = gpiochip_get_data(chip); - unsigned int reg, bit; - struct meson_bank *bank; - int ret; - - ret = meson_get_bank(pc, gpio, &bank); - if (ret) - return; - - meson_calc_reg_and_bit(bank, gpio, REG_OUT, ®, &bit); - regmap_update_bits(pc->reg_gpio, reg, BIT(bit), - value ? BIT(bit) : 0); + meson_pinconf_set_drive(gpiochip_get_data(chip), gpio, value); } static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio) diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h index adab4ea078f9..c696f3241a36 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.h +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -65,10 +65,21 @@ enum meson_reg_type { REG_DIR, REG_OUT, REG_IN, + REG_DS, NUM_REG, }; /** + * enum meson_pinconf_drv - value of drive-strength supported + */ +enum meson_pinconf_drv { + MESON_PINCONF_DRV_500UA, + MESON_PINCONF_DRV_2500UA, + MESON_PINCONF_DRV_3000UA, + MESON_PINCONF_DRV_4000UA, +}; + +/** * struct meson bank * * @name: bank name @@ -126,7 +137,8 @@ struct meson_pinctrl { .num_groups = ARRAY_SIZE(fn ## _groups), \ } -#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ +#define BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, \ + dsr, dsb) \ { \ .name = n, \ .first = f, \ @@ -139,9 +151,13 @@ struct meson_pinctrl { [REG_DIR] = { dr, db }, \ [REG_OUT] = { or, ob }, \ [REG_IN] = { ir, ib }, \ + [REG_DS] = { dsr, dsb }, \ }, \ } +#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ + BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, 0, 0) + #define MESON_PIN(x) PINCTRL_PIN(x, #x) /* Common pmx functions */ diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c index 19e69701747d..d45c31f281c8 100644 --- a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c +++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c @@ -16,341 +16,347 @@ #include "pinctrl-mvebu.h" -#define V(f6180, f6190, f6192, f6281, f6282, dx4122) \ +#define V(f6180, f6190, f6192, f6281, f6282, dx4122, dx1135) \ ((f6180 << 0) | (f6190 << 1) | (f6192 << 2) | \ - (f6281 << 3) | (f6282 << 4) | (dx4122 << 5)) + (f6281 << 3) | (f6282 << 4) | (dx4122 << 5) | \ + (dx1135 << 6)) enum kirkwood_variant { - VARIANT_MV88F6180 = V(1, 0, 0, 0, 0, 0), - VARIANT_MV88F6190 = V(0, 1, 0, 0, 0, 0), - VARIANT_MV88F6192 = V(0, 0, 1, 0, 0, 0), - VARIANT_MV88F6281 = V(0, 0, 0, 1, 0, 0), - VARIANT_MV88F6282 = V(0, 0, 0, 0, 1, 0), - VARIANT_MV98DX4122 = V(0, 0, 0, 0, 0, 1), + VARIANT_MV88F6180 = V(1, 0, 0, 0, 0, 0, 0), + VARIANT_MV88F6190 = V(0, 1, 0, 0, 0, 0, 0), + VARIANT_MV88F6192 = V(0, 0, 1, 0, 0, 0, 0), + VARIANT_MV88F6281 = V(0, 0, 0, 1, 0, 0, 0), + VARIANT_MV88F6282 = V(0, 0, 0, 0, 1, 0, 0), + VARIANT_MV98DX4122 = V(0, 0, 0, 0, 0, 1, 0), + VARIANT_MV98DX1135 = V(0, 0, 0, 0, 0, 0, 1), }; static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = { MPP_MODE(0, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io2", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io2", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1, 1))), MPP_MODE(1, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io3", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io3", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1, 1))), MPP_MODE(2, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io4", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io4", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1, 1))), MPP_MODE(3, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io5", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io5", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1, 1))), MPP_MODE(4, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io6", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "rxd", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io6", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "rxd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0))), MPP_MODE(5, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io7", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "txd", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "ptp", "trig", V(1, 1, 1, 1, 0, 0)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io7", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "txd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(6, - MPP_VAR_FUNCTION(0x1, "sysrst", "out", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0))), + MPP_VAR_FUNCTION(0x1, "sysrst", "out", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0))), MPP_MODE(7, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(8, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "twsi0", "sda", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "rts", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xc, "ptp", "clk", V(1, 1, 1, 1, 0, 0)), - MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "twsi0", "sda", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "rts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0, 0))), MPP_MODE(9, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "twsi0", "sck", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "cts", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xc, "ptp", "evreq", V(1, 1, 1, 1, 0, 0)), - MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "twsi0", "sck", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "cts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "evreq", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0, 0))), MPP_MODE(10, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0X3, "uart0", "txd", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xc, "ptp", "trig", V(1, 1, 1, 1, 0, 0))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0X3, "uart0", "txd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0))), MPP_MODE(11, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart0", "rxd", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq", V(1, 1, 1, 1, 0, 0)), - MPP_VAR_FUNCTION(0xc, "ptp-2", "trig", V(1, 1, 1, 1, 0, 0)), - MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart0", "rxd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp-2", "trig", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0))), MPP_MODE(12, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 0, 1, 0)), - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 0)), - MPP_VAR_FUNCTION(0x1, "sdio", "clk", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xb, "spi", "mosi", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xd, "twsi1", "sda", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x1, "sdio", "clk", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "spi", "mosi", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "twsi1", "sda", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(13, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "cmd", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0xa, "audio", "rmclk", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "cmd", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0xa, "audio", "rmclk", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(14, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "d0", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xb, "audio-1", "sdi", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d0", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "audio-1", "sdi", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0, 0))), MPP_MODE(15, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "d1", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "sata0", "act", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "spi", "cs", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d1", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "spi", "cs", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(16, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "sdio", "d2", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "sata1", "act", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "extclk", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d2", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "extclk", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0, 0))), MPP_MODE(17, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "sdio", "d3", V(1, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xa, "sata1", "act", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xd, "twsi1", "sck", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "sdio", "d3", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xa, "sata1", "act", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "twsi1", "sck", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(18, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io0", V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "pex", "clkreq", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io0", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "pex", "clkreq", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(19, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "nand", "io1", V(1, 1, 1, 1, 1, 1))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io1", V(1, 1, 1, 1, 1, 1, 1))), MPP_MODE(20, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd0", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d0", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(0, 0, 0, 0, 0, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd0", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d0", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(0, 0, 0, 0, 0, 0, 0))), MPP_MODE(21, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd1", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d1", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd1", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d1", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(22, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd2", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d2", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd2", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d2", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(23, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txd3", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d3", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd3", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d3", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(24, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd0", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d4", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd0", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d4", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(25, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd1", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d5", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd1", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d5", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(26, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd2", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d6", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd2", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d6", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(27, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxd3", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d7", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd3", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d7", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(28, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "col", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d8", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "col", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d8", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "ren", V(0, 0, 0, 0, 0, 0, 1))), MPP_MODE(29, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txclk", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d9", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txclk", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d9", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "wen", V(0, 0, 0, 0, 0, 0, 1))), MPP_MODE(30, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxctl", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d10", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxctl", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d10", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(31, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxclk", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d11", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxclk", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d11", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(32, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txclko", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d12", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txclko", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d12", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(33, - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txctl", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d13", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txctl", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d13", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(34, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "txen", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d14", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txen", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d14", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "ale", V(0, 0, 0, 0, 0, 0, 1))), MPP_MODE(35, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x3, "ge1", "rxerr", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d15", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(1, 1, 1, 1, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxerr", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d15", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "cen", V(0, 0, 0, 0, 0, 0, 1))), MPP_MODE(36, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "twsi1", "sda", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "twsi1", "sda", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(37, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "twsi1", "sck", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "twsi1", "sck", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(38, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d18", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d18", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(39, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d19", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d19", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(40, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d20", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d20", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(41, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d21", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d21", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(42, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d22", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d22", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(43, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d23", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d23", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(44, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "clk", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "clk", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(45, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1)), - MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "e", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "e", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(46, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(47, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(48, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d16", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d16", V(0, 0, 0, 0, 1, 0, 0))), MPP_MODE(49, - MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 1)), - MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 0, 0)), - MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 0, 1, 1, 0)), - MPP_VAR_FUNCTION(0x5, "ptp", "clk", V(0, 0, 0, 1, 0, 0)), - MPP_VAR_FUNCTION(0xa, "pex", "clkreq", V(0, 0, 0, 0, 1, 0)), - MPP_VAR_FUNCTION(0xb, "lcd", "d17", V(0, 0, 0, 0, 1, 0))), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 1, 1)), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "ptp", "clk", V(0, 0, 0, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xa, "pex", "clkreq", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d17", V(0, 0, 0, 0, 1, 0, 0))), }; static const struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = { @@ -440,6 +446,17 @@ static struct mvebu_pinctrl_soc_info mv98dx4122_info = { .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), }; +static struct mvebu_pinctrl_soc_info mv98dx1135_info = { + .variant = VARIANT_MV98DX1135, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + + static const struct of_device_id kirkwood_pinctrl_of_match[] = { { .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info }, { .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info }, @@ -447,6 +464,7 @@ static const struct of_device_id kirkwood_pinctrl_of_match[] = { { .compatible = "marvell,88f6281-pinctrl", .data = &mv88f6281_info }, { .compatible = "marvell,88f6282-pinctrl", .data = &mv88f6282_info }, { .compatible = "marvell,98dx4122-pinctrl", .data = &mv98dx4122_info }, + { .compatible = "marvell,98dx1135-pinctrl", .data = &mv98dx1135_info }, { } }; diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 4ccd71bbc72a..9eb86309c70b 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -38,6 +38,7 @@ static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true), + PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true), PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true), PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false), @@ -166,6 +167,7 @@ static const struct pinconf_generic_params dt_params[] = { { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 }, { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, diff --git a/drivers/pinctrl/pinctrl-bm1880.c b/drivers/pinctrl/pinctrl-bm1880.c index 446b07d8fbfc..63b130cb1ffb 100644 --- a/drivers/pinctrl/pinctrl-bm1880.c +++ b/drivers/pinctrl/pinctrl-bm1880.c @@ -27,6 +27,7 @@ * @ngroups: Number of @groups * @funcs: Pinmux functions * @nfuncs: Number of @funcs + * @pconf: Pinconf data */ struct bm1880_pinctrl { void __iomem *base; @@ -35,6 +36,7 @@ struct bm1880_pinctrl { unsigned int ngroups; const struct bm1880_pinmux_function *funcs; unsigned int nfuncs; + const struct bm1880_pinconf_data *pinconf; }; /** @@ -55,7 +57,6 @@ struct bm1880_pctrl_group { * @groups: List of pingroups for this function. * @ngroups: Number of entries in @groups. * @mux_val: Selector for this function - * @mux_mask: Mask for function specific selector * @mux: Offset of function specific mux * @mux_shift: Shift for function specific selector */ @@ -64,11 +65,18 @@ struct bm1880_pinmux_function { const char * const *groups; unsigned int ngroups; u32 mux_val; - u32 mux_mask; u32 mux; u8 mux_shift; }; +/** + * struct bm1880_pinconf_data - pinconf data + * @drv_bits: Drive strength bit width + */ +struct bm1880_pinconf_data { + u32 drv_bits; +}; + static const struct pinctrl_pin_desc bm1880_pins[] = { PINCTRL_PIN(0, "MIO0"), PINCTRL_PIN(1, "MIO1"), @@ -636,165 +644,273 @@ static const char * const i2s1_group[] = { "i2s1_grp" }; static const char * const i2s1_mclkin_group[] = { "i2s1_mclkin_grp" }; static const char * const spi0_group[] = { "spi0_grp" }; -#define BM1880_PINMUX_FUNCTION(fname, mval, mask) \ +#define BM1880_PINMUX_FUNCTION(fname, mval) \ [F_##fname] = { \ .name = #fname, \ .groups = fname##_group, \ .ngroups = ARRAY_SIZE(fname##_group), \ .mux_val = mval, \ - .mux_mask = mask, \ } -#define BM1880_PINMUX_FUNCTION_MUX(fname, mval, mask, offset, shift)\ - [F_##fname] = { \ - .name = #fname, \ - .groups = fname##_group, \ - .ngroups = ARRAY_SIZE(fname##_group), \ - .mux_val = mval, \ - .mux_mask = mask, \ - .mux = offset, \ - .mux_shift = shift, \ +static const struct bm1880_pinmux_function bm1880_pmux_functions[] = { + BM1880_PINMUX_FUNCTION(nand, 2), + BM1880_PINMUX_FUNCTION(spi, 0), + BM1880_PINMUX_FUNCTION(emmc, 1), + BM1880_PINMUX_FUNCTION(sdio, 0), + BM1880_PINMUX_FUNCTION(eth0, 0), + BM1880_PINMUX_FUNCTION(pwm0, 2), + BM1880_PINMUX_FUNCTION(pwm1, 2), + BM1880_PINMUX_FUNCTION(pwm2, 2), + BM1880_PINMUX_FUNCTION(pwm3, 2), + BM1880_PINMUX_FUNCTION(pwm4, 2), + BM1880_PINMUX_FUNCTION(pwm5, 2), + BM1880_PINMUX_FUNCTION(pwm6, 2), + BM1880_PINMUX_FUNCTION(pwm7, 2), + BM1880_PINMUX_FUNCTION(pwm8, 2), + BM1880_PINMUX_FUNCTION(pwm9, 2), + BM1880_PINMUX_FUNCTION(pwm10, 2), + BM1880_PINMUX_FUNCTION(pwm11, 2), + BM1880_PINMUX_FUNCTION(pwm12, 2), + BM1880_PINMUX_FUNCTION(pwm13, 2), + BM1880_PINMUX_FUNCTION(pwm14, 2), + BM1880_PINMUX_FUNCTION(pwm15, 2), + BM1880_PINMUX_FUNCTION(pwm16, 2), + BM1880_PINMUX_FUNCTION(pwm17, 2), + BM1880_PINMUX_FUNCTION(pwm18, 2), + BM1880_PINMUX_FUNCTION(pwm19, 2), + BM1880_PINMUX_FUNCTION(pwm20, 2), + BM1880_PINMUX_FUNCTION(pwm21, 2), + BM1880_PINMUX_FUNCTION(pwm22, 2), + BM1880_PINMUX_FUNCTION(pwm23, 2), + BM1880_PINMUX_FUNCTION(pwm24, 2), + BM1880_PINMUX_FUNCTION(pwm25, 2), + BM1880_PINMUX_FUNCTION(pwm26, 2), + BM1880_PINMUX_FUNCTION(pwm27, 2), + BM1880_PINMUX_FUNCTION(pwm28, 2), + BM1880_PINMUX_FUNCTION(pwm29, 2), + BM1880_PINMUX_FUNCTION(pwm30, 2), + BM1880_PINMUX_FUNCTION(pwm31, 2), + BM1880_PINMUX_FUNCTION(pwm32, 2), + BM1880_PINMUX_FUNCTION(pwm33, 2), + BM1880_PINMUX_FUNCTION(pwm34, 2), + BM1880_PINMUX_FUNCTION(pwm35, 2), + BM1880_PINMUX_FUNCTION(pwm36, 2), + BM1880_PINMUX_FUNCTION(pwm37, 2), + BM1880_PINMUX_FUNCTION(i2c0, 1), + BM1880_PINMUX_FUNCTION(i2c1, 1), + BM1880_PINMUX_FUNCTION(i2c2, 1), + BM1880_PINMUX_FUNCTION(i2c3, 1), + BM1880_PINMUX_FUNCTION(i2c4, 1), + BM1880_PINMUX_FUNCTION(uart0, 3), + BM1880_PINMUX_FUNCTION(uart1, 3), + BM1880_PINMUX_FUNCTION(uart2, 3), + BM1880_PINMUX_FUNCTION(uart3, 3), + BM1880_PINMUX_FUNCTION(uart4, 1), + BM1880_PINMUX_FUNCTION(uart5, 1), + BM1880_PINMUX_FUNCTION(uart6, 1), + BM1880_PINMUX_FUNCTION(uart7, 1), + BM1880_PINMUX_FUNCTION(uart8, 1), + BM1880_PINMUX_FUNCTION(uart9, 1), + BM1880_PINMUX_FUNCTION(uart10, 1), + BM1880_PINMUX_FUNCTION(uart11, 1), + BM1880_PINMUX_FUNCTION(uart12, 3), + BM1880_PINMUX_FUNCTION(uart13, 3), + BM1880_PINMUX_FUNCTION(uart14, 3), + BM1880_PINMUX_FUNCTION(uart15, 3), + BM1880_PINMUX_FUNCTION(gpio0, 0), + BM1880_PINMUX_FUNCTION(gpio1, 0), + BM1880_PINMUX_FUNCTION(gpio2, 0), + BM1880_PINMUX_FUNCTION(gpio3, 0), + BM1880_PINMUX_FUNCTION(gpio4, 0), + BM1880_PINMUX_FUNCTION(gpio5, 0), + BM1880_PINMUX_FUNCTION(gpio6, 0), + BM1880_PINMUX_FUNCTION(gpio7, 0), + BM1880_PINMUX_FUNCTION(gpio8, 0), + BM1880_PINMUX_FUNCTION(gpio9, 0), + BM1880_PINMUX_FUNCTION(gpio10, 0), + BM1880_PINMUX_FUNCTION(gpio11, 0), + BM1880_PINMUX_FUNCTION(gpio12, 1), + BM1880_PINMUX_FUNCTION(gpio13, 1), + BM1880_PINMUX_FUNCTION(gpio14, 0), + BM1880_PINMUX_FUNCTION(gpio15, 0), + BM1880_PINMUX_FUNCTION(gpio16, 0), + BM1880_PINMUX_FUNCTION(gpio17, 0), + BM1880_PINMUX_FUNCTION(gpio18, 0), + BM1880_PINMUX_FUNCTION(gpio19, 0), + BM1880_PINMUX_FUNCTION(gpio20, 0), + BM1880_PINMUX_FUNCTION(gpio21, 0), + BM1880_PINMUX_FUNCTION(gpio22, 0), + BM1880_PINMUX_FUNCTION(gpio23, 0), + BM1880_PINMUX_FUNCTION(gpio24, 0), + BM1880_PINMUX_FUNCTION(gpio25, 0), + BM1880_PINMUX_FUNCTION(gpio26, 0), + BM1880_PINMUX_FUNCTION(gpio27, 0), + BM1880_PINMUX_FUNCTION(gpio28, 0), + BM1880_PINMUX_FUNCTION(gpio29, 0), + BM1880_PINMUX_FUNCTION(gpio30, 0), + BM1880_PINMUX_FUNCTION(gpio31, 0), + BM1880_PINMUX_FUNCTION(gpio32, 0), + BM1880_PINMUX_FUNCTION(gpio33, 0), + BM1880_PINMUX_FUNCTION(gpio34, 0), + BM1880_PINMUX_FUNCTION(gpio35, 0), + BM1880_PINMUX_FUNCTION(gpio36, 0), + BM1880_PINMUX_FUNCTION(gpio37, 0), + BM1880_PINMUX_FUNCTION(gpio38, 0), + BM1880_PINMUX_FUNCTION(gpio39, 0), + BM1880_PINMUX_FUNCTION(gpio40, 0), + BM1880_PINMUX_FUNCTION(gpio41, 0), + BM1880_PINMUX_FUNCTION(gpio42, 0), + BM1880_PINMUX_FUNCTION(gpio43, 0), + BM1880_PINMUX_FUNCTION(gpio44, 0), + BM1880_PINMUX_FUNCTION(gpio45, 0), + BM1880_PINMUX_FUNCTION(gpio46, 0), + BM1880_PINMUX_FUNCTION(gpio47, 0), + BM1880_PINMUX_FUNCTION(gpio48, 0), + BM1880_PINMUX_FUNCTION(gpio49, 0), + BM1880_PINMUX_FUNCTION(gpio50, 0), + BM1880_PINMUX_FUNCTION(gpio51, 0), + BM1880_PINMUX_FUNCTION(gpio52, 0), + BM1880_PINMUX_FUNCTION(gpio53, 0), + BM1880_PINMUX_FUNCTION(gpio54, 0), + BM1880_PINMUX_FUNCTION(gpio55, 0), + BM1880_PINMUX_FUNCTION(gpio56, 0), + BM1880_PINMUX_FUNCTION(gpio57, 0), + BM1880_PINMUX_FUNCTION(gpio58, 0), + BM1880_PINMUX_FUNCTION(gpio59, 0), + BM1880_PINMUX_FUNCTION(gpio60, 0), + BM1880_PINMUX_FUNCTION(gpio61, 0), + BM1880_PINMUX_FUNCTION(gpio62, 0), + BM1880_PINMUX_FUNCTION(gpio63, 0), + BM1880_PINMUX_FUNCTION(gpio64, 0), + BM1880_PINMUX_FUNCTION(gpio65, 0), + BM1880_PINMUX_FUNCTION(gpio66, 0), + BM1880_PINMUX_FUNCTION(gpio67, 0), + BM1880_PINMUX_FUNCTION(eth1, 1), + BM1880_PINMUX_FUNCTION(i2s0, 2), + BM1880_PINMUX_FUNCTION(i2s0_mclkin, 1), + BM1880_PINMUX_FUNCTION(i2s1, 2), + BM1880_PINMUX_FUNCTION(i2s1_mclkin, 1), + BM1880_PINMUX_FUNCTION(spi0, 1), +}; + +#define BM1880_PINCONF_DAT(_width) \ + { \ + .drv_bits = _width, \ } -static const struct bm1880_pinmux_function bm1880_pmux_functions[] = { - BM1880_PINMUX_FUNCTION(nand, 2, 0x03), - BM1880_PINMUX_FUNCTION(spi, 0, 0x03), - BM1880_PINMUX_FUNCTION(emmc, 1, 0x03), - BM1880_PINMUX_FUNCTION(sdio, 0, 0x03), - BM1880_PINMUX_FUNCTION(eth0, 0, 0x03), - BM1880_PINMUX_FUNCTION_MUX(pwm0, 2, 0x0F, 0x50, 0x00), - BM1880_PINMUX_FUNCTION_MUX(pwm1, 2, 0x0F, 0x50, 0x04), - BM1880_PINMUX_FUNCTION_MUX(pwm2, 2, 0x0F, 0x50, 0x08), - BM1880_PINMUX_FUNCTION_MUX(pwm3, 2, 0x0F, 0x50, 0x0C), - BM1880_PINMUX_FUNCTION_MUX(pwm4, 2, 0x0F, 0x50, 0x10), - BM1880_PINMUX_FUNCTION_MUX(pwm5, 2, 0x0F, 0x50, 0x14), - BM1880_PINMUX_FUNCTION_MUX(pwm6, 2, 0x0F, 0x50, 0x18), - BM1880_PINMUX_FUNCTION_MUX(pwm7, 2, 0x0F, 0x50, 0x1C), - BM1880_PINMUX_FUNCTION_MUX(pwm8, 2, 0x0F, 0x54, 0x00), - BM1880_PINMUX_FUNCTION_MUX(pwm9, 2, 0x0F, 0x54, 0x04), - BM1880_PINMUX_FUNCTION_MUX(pwm10, 2, 0x0F, 0x54, 0x08), - BM1880_PINMUX_FUNCTION_MUX(pwm11, 2, 0x0F, 0x54, 0x0C), - BM1880_PINMUX_FUNCTION_MUX(pwm12, 2, 0x0F, 0x54, 0x10), - BM1880_PINMUX_FUNCTION_MUX(pwm13, 2, 0x0F, 0x54, 0x14), - BM1880_PINMUX_FUNCTION_MUX(pwm14, 2, 0x0F, 0x54, 0x18), - BM1880_PINMUX_FUNCTION_MUX(pwm15, 2, 0x0F, 0x54, 0x1C), - BM1880_PINMUX_FUNCTION_MUX(pwm16, 2, 0x0F, 0x58, 0x00), - BM1880_PINMUX_FUNCTION_MUX(pwm17, 2, 0x0F, 0x58, 0x04), - BM1880_PINMUX_FUNCTION_MUX(pwm18, 2, 0x0F, 0x58, 0x08), - BM1880_PINMUX_FUNCTION_MUX(pwm19, 2, 0x0F, 0x58, 0x0C), - BM1880_PINMUX_FUNCTION_MUX(pwm20, 2, 0x0F, 0x58, 0x10), - BM1880_PINMUX_FUNCTION_MUX(pwm21, 2, 0x0F, 0x58, 0x14), - BM1880_PINMUX_FUNCTION_MUX(pwm22, 2, 0x0F, 0x58, 0x18), - BM1880_PINMUX_FUNCTION_MUX(pwm23, 2, 0x0F, 0x58, 0x1C), - BM1880_PINMUX_FUNCTION_MUX(pwm24, 2, 0x0F, 0x5C, 0x00), - BM1880_PINMUX_FUNCTION_MUX(pwm25, 2, 0x0F, 0x5C, 0x04), - BM1880_PINMUX_FUNCTION_MUX(pwm26, 2, 0x0F, 0x5C, 0x08), - BM1880_PINMUX_FUNCTION_MUX(pwm27, 2, 0x0F, 0x5C, 0x0C), - BM1880_PINMUX_FUNCTION_MUX(pwm28, 2, 0x0F, 0x5C, 0x10), - BM1880_PINMUX_FUNCTION_MUX(pwm29, 2, 0x0F, 0x5C, 0x14), - BM1880_PINMUX_FUNCTION_MUX(pwm30, 2, 0x0F, 0x5C, 0x18), - BM1880_PINMUX_FUNCTION_MUX(pwm31, 2, 0x0F, 0x5C, 0x1C), - BM1880_PINMUX_FUNCTION_MUX(pwm32, 2, 0x0F, 0x60, 0x00), - BM1880_PINMUX_FUNCTION_MUX(pwm33, 2, 0x0F, 0x60, 0x04), - BM1880_PINMUX_FUNCTION_MUX(pwm34, 2, 0x0F, 0x60, 0x08), - BM1880_PINMUX_FUNCTION_MUX(pwm35, 2, 0x0F, 0x60, 0x0C), - BM1880_PINMUX_FUNCTION_MUX(pwm36, 2, 0x0F, 0x60, 0x10), - BM1880_PINMUX_FUNCTION_MUX(pwm37, 2, 0x0F, 0x60, 0x1C), - BM1880_PINMUX_FUNCTION(i2c0, 1, 0x03), - BM1880_PINMUX_FUNCTION(i2c1, 1, 0x03), - BM1880_PINMUX_FUNCTION(i2c2, 1, 0x03), - BM1880_PINMUX_FUNCTION(i2c3, 1, 0x03), - BM1880_PINMUX_FUNCTION(i2c4, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart0, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart1, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart2, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart3, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart4, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart5, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart6, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart7, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart8, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart9, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart10, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart11, 1, 0x03), - BM1880_PINMUX_FUNCTION(uart12, 3, 0x03), - BM1880_PINMUX_FUNCTION(uart13, 3, 0x03), - BM1880_PINMUX_FUNCTION(uart14, 3, 0x03), - BM1880_PINMUX_FUNCTION(uart15, 3, 0x03), - BM1880_PINMUX_FUNCTION_MUX(gpio0, 0, 0x03, 0x4E0, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio1, 0, 0x03, 0x4E4, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio2, 0, 0x03, 0x4E4, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio3, 0, 0x03, 0x4E8, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio4, 0, 0x03, 0x4E8, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio5, 0, 0x03, 0x4EC, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio6, 0, 0x03, 0x4EC, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio7, 0, 0x03, 0x4F0, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio8, 0, 0x03, 0x4F0, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio9, 0, 0x03, 0x4F4, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio10, 0, 0x03, 0x4F4, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio11, 0, 0x03, 0x4F8, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio12, 1, 0x03, 0x4F8, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio13, 1, 0x03, 0x4FC, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio14, 0, 0x03, 0x474, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio15, 0, 0x03, 0x478, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio16, 0, 0x03, 0x478, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio17, 0, 0x03, 0x47C, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio18, 0, 0x03, 0x47C, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio19, 0, 0x03, 0x480, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio20, 0, 0x03, 0x480, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio21, 0, 0x03, 0x484, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio22, 0, 0x03, 0x484, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio23, 0, 0x03, 0x488, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio24, 0, 0x03, 0x488, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio25, 0, 0x03, 0x48C, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio26, 0, 0x03, 0x48C, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio27, 0, 0x03, 0x490, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio28, 0, 0x03, 0x490, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio29, 0, 0x03, 0x494, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio30, 0, 0x03, 0x494, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio31, 0, 0x03, 0x498, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio32, 0, 0x03, 0x498, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio33, 0, 0x03, 0x49C, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio34, 0, 0x03, 0x49C, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio35, 0, 0x03, 0x4A0, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio36, 0, 0x03, 0x4A0, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio37, 0, 0x03, 0x4A4, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio38, 0, 0x03, 0x4A4, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio39, 0, 0x03, 0x4A8, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio40, 0, 0x03, 0x4A8, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio41, 0, 0x03, 0x4AC, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio42, 0, 0x03, 0x4AC, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio43, 0, 0x03, 0x4B0, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio44, 0, 0x03, 0x4B0, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio45, 0, 0x03, 0x4B4, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio46, 0, 0x03, 0x4B4, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio47, 0, 0x03, 0x4B8, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio48, 0, 0x03, 0x4B8, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio49, 0, 0x03, 0x4BC, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio50, 0, 0x03, 0x4BC, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio51, 0, 0x03, 0x4C0, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio52, 0, 0x03, 0x4C0, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio53, 0, 0x03, 0x4C4, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio54, 0, 0x03, 0x4C4, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio55, 0, 0x03, 0x4C8, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio56, 0, 0x03, 0x4C8, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio57, 0, 0x03, 0x4CC, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio58, 0, 0x03, 0x4CC, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio59, 0, 0x03, 0x4D0, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio60, 0, 0x03, 0x4D0, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio61, 0, 0x03, 0x4D4, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio62, 0, 0x03, 0x4D4, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio63, 0, 0x03, 0x4D8, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio64, 0, 0x03, 0x4D8, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio65, 0, 0x03, 0x4DC, 0x04), - BM1880_PINMUX_FUNCTION_MUX(gpio66, 0, 0x03, 0x4DC, 0x14), - BM1880_PINMUX_FUNCTION_MUX(gpio67, 0, 0x03, 0x4E0, 0x04), - BM1880_PINMUX_FUNCTION(eth1, 1, 0x03), - BM1880_PINMUX_FUNCTION(i2s0, 2, 0x03), - BM1880_PINMUX_FUNCTION(i2s0_mclkin, 1, 0x03), - BM1880_PINMUX_FUNCTION(i2s1, 2, 0x03), - BM1880_PINMUX_FUNCTION(i2s1_mclkin, 1, 0x03), - BM1880_PINMUX_FUNCTION(spi0, 1, 0x03), +static const struct bm1880_pinconf_data bm1880_pinconf[] = { + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x03), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), + BM1880_PINCONF_DAT(0x02), }; static int bm1880_pctrl_get_groups_count(struct pinctrl_dev *pctldev) @@ -870,33 +986,308 @@ static int bm1880_pinmux_set_mux(struct pinctrl_dev *pctldev, const struct bm1880_pinmux_function *func = &pctrl->funcs[function]; int i; - if (func->mux) { + for (i = 0; i < pgrp->npins; i++) { + unsigned int pin = pgrp->pins[i]; + u32 offset = (pin >> 1) << 2; + u32 mux_offset = ((!((pin + 1) & 1) << 4) + 4); u32 regval = readl_relaxed(pctrl->base + BM1880_REG_MUX + - func->mux); + offset); + + regval &= ~(0x03 << mux_offset); + regval |= func->mux_val << mux_offset; + + writel_relaxed(regval, pctrl->base + BM1880_REG_MUX + offset); + } + + return 0; +} + +#define BM1880_PINCONF(pin, idx) ((!((pin + 1) & 1) << 4) + idx) +#define BM1880_PINCONF_PULLCTRL(pin) BM1880_PINCONF(pin, 0) +#define BM1880_PINCONF_PULLUP(pin) BM1880_PINCONF(pin, 1) +#define BM1880_PINCONF_PULLDOWN(pin) BM1880_PINCONF(pin, 2) +#define BM1880_PINCONF_DRV(pin) BM1880_PINCONF(pin, 6) +#define BM1880_PINCONF_SCHMITT(pin) BM1880_PINCONF(pin, 9) +#define BM1880_PINCONF_SLEW(pin) BM1880_PINCONF(pin, 10) + +static int bm1880_pinconf_drv_set(unsigned int mA, u32 width, + u32 *regval, u32 bit_offset) +{ + u32 _regval; + + _regval = *regval; + + /* + * There are two sets of drive strength bit width exposed by the + * SoC at 4mA step, hence we need to handle them separately. + */ + if (width == 0x03) { + switch (mA) { + case 4: + _regval &= ~(width << bit_offset); + _regval |= (0 << bit_offset); + break; + case 8: + _regval &= ~(width << bit_offset); + _regval |= (1 << bit_offset); + break; + case 12: + _regval &= ~(width << bit_offset); + _regval |= (2 << bit_offset); + break; + case 16: + _regval &= ~(width << bit_offset); + _regval |= (3 << bit_offset); + break; + case 20: + _regval &= ~(width << bit_offset); + _regval |= (4 << bit_offset); + break; + case 24: + _regval &= ~(width << bit_offset); + _regval |= (5 << bit_offset); + break; + case 28: + _regval &= ~(width << bit_offset); + _regval |= (6 << bit_offset); + break; + case 32: + _regval &= ~(width << bit_offset); + _regval |= (7 << bit_offset); + break; + default: + return -EINVAL; + } + } else { + switch (mA) { + case 4: + _regval &= ~(width << bit_offset); + _regval |= (0 << bit_offset); + break; + case 8: + _regval &= ~(width << bit_offset); + _regval |= (1 << bit_offset); + break; + case 12: + _regval &= ~(width << bit_offset); + _regval |= (2 << bit_offset); + break; + case 16: + _regval &= ~(width << bit_offset); + _regval |= (3 << bit_offset); + break; + default: + return -EINVAL; + } + } + + *regval = _regval; + + return 0; +} + +static int bm1880_pinconf_drv_get(u32 width, u32 drv) +{ + int ret = -ENOTSUPP; - regval &= ~(func->mux_mask << func->mux_shift); - regval |= func->mux_val << func->mux_shift; - writel_relaxed(regval, pctrl->base + BM1880_REG_MUX + - func->mux); + /* + * There are two sets of drive strength bit width exposed by the + * SoC at 4mA step, hence we need to handle them separately. + */ + if (width == 0x03) { + switch (drv) { + case 0: + ret = 4; + break; + case 1: + ret = 8; + break; + case 2: + ret = 12; + break; + case 3: + ret = 16; + break; + case 4: + ret = 20; + break; + case 5: + ret = 24; + break; + case 6: + ret = 28; + break; + case 7: + ret = 32; + break; + default: + break; + } } else { - for (i = 0; i < pgrp->npins; i++) { - unsigned int pin = pgrp->pins[i]; - u32 offset = (pin >> 1) << 2; - u32 mux_offset = ((!((pin + 1) & 1) << 4) + 4); - u32 regval = readl_relaxed(pctrl->base + - BM1880_REG_MUX + offset); - - regval &= ~(func->mux_mask << mux_offset); - regval |= func->mux_val << mux_offset; - - writel_relaxed(regval, pctrl->base + - BM1880_REG_MUX + offset); + switch (drv) { + case 0: + ret = 4; + break; + case 1: + ret = 8; + break; + case 2: + ret = 12; + break; + case 3: + ret = 16; + break; + default: + break; + } + } + + return ret; +} + +static int bm1880_pinconf_cfg_get(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *config) +{ + struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned int param = pinconf_to_config_param(*config); + unsigned int arg = 0; + u32 regval, offset, bit_offset; + int ret; + + offset = (pin >> 1) << 2; + regval = readl_relaxed(pctrl->base + BM1880_REG_MUX + offset); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + bit_offset = BM1880_PINCONF_PULLUP(pin); + arg = !!(regval & BIT(bit_offset)); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + bit_offset = BM1880_PINCONF_PULLDOWN(pin); + arg = !!(regval & BIT(bit_offset)); + break; + case PIN_CONFIG_BIAS_DISABLE: + bit_offset = BM1880_PINCONF_PULLCTRL(pin); + arg = !!(regval & BIT(bit_offset)); + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + bit_offset = BM1880_PINCONF_SCHMITT(pin); + arg = !!(regval & BIT(bit_offset)); + break; + case PIN_CONFIG_SLEW_RATE: + bit_offset = BM1880_PINCONF_SLEW(pin); + arg = !!(regval & BIT(bit_offset)); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + bit_offset = BM1880_PINCONF_DRV(pin); + ret = bm1880_pinconf_drv_get(pctrl->pinconf[pin].drv_bits, + !!(regval & BIT(bit_offset))); + if (ret < 0) + return ret; + + arg = ret; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int bm1880_pinconf_cfg_set(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned long *configs, + unsigned int num_configs) +{ + struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + u32 regval, offset, bit_offset; + int i, ret; + + offset = (pin >> 1) << 2; + regval = readl_relaxed(pctrl->base + BM1880_REG_MUX + offset); + + for (i = 0; i < num_configs; i++) { + unsigned int param = pinconf_to_config_param(configs[i]); + unsigned int arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + bit_offset = BM1880_PINCONF_PULLUP(pin); + regval |= BIT(bit_offset); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + bit_offset = BM1880_PINCONF_PULLDOWN(pin); + regval |= BIT(bit_offset); + break; + case PIN_CONFIG_BIAS_DISABLE: + bit_offset = BM1880_PINCONF_PULLCTRL(pin); + regval |= BIT(bit_offset); + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + bit_offset = BM1880_PINCONF_SCHMITT(pin); + if (arg) + regval |= BIT(bit_offset); + else + regval &= ~BIT(bit_offset); + break; + case PIN_CONFIG_SLEW_RATE: + bit_offset = BM1880_PINCONF_SLEW(pin); + if (arg) + regval |= BIT(bit_offset); + else + regval &= ~BIT(bit_offset); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + bit_offset = BM1880_PINCONF_DRV(pin); + ret = bm1880_pinconf_drv_set(arg, + pctrl->pinconf[pin].drv_bits, + ®val, bit_offset); + if (ret < 0) + return ret; + + break; + default: + dev_warn(pctldev->dev, + "unsupported configuration parameter '%u'\n", + param); + continue; } + + writel_relaxed(regval, pctrl->base + BM1880_REG_MUX + offset); } return 0; } +static int bm1880_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + int i, ret; + struct bm1880_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct bm1880_pctrl_group *pgrp = &pctrl->groups[selector]; + + for (i = 0; i < pgrp->npins; i++) { + ret = bm1880_pinconf_cfg_set(pctldev, pgrp->pins[i], configs, + num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops bm1880_pinconf_ops = { + .is_generic = true, + .pin_config_get = bm1880_pinconf_cfg_get, + .pin_config_set = bm1880_pinconf_cfg_set, + .pin_config_group_set = bm1880_pinconf_group_set, +}; + static const struct pinmux_ops bm1880_pinmux_ops = { .get_functions_count = bm1880_pmux_get_functions_count, .get_function_name = bm1880_pmux_get_function_name, @@ -910,6 +1301,7 @@ static struct pinctrl_desc bm1880_desc = { .npins = ARRAY_SIZE(bm1880_pins), .pctlops = &bm1880_pctrl_ops, .pmxops = &bm1880_pinmux_ops, + .confops = &bm1880_pinconf_ops, .owner = THIS_MODULE, }; @@ -932,6 +1324,7 @@ static int bm1880_pinctrl_probe(struct platform_device *pdev) pctrl->ngroups = ARRAY_SIZE(bm1880_pctrl_groups); pctrl->funcs = bm1880_pmux_functions; pctrl->nfuncs = ARRAY_SIZE(bm1880_pmux_functions); + pctrl->pinconf = bm1880_pinconf; pctrl->pctrldev = devm_pinctrl_register(&pdev->dev, &bm1880_desc, pctrl); diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 807a3263d849..62a622159006 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -3204,6 +3204,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank, base, &rockchip_regmap_config); } + of_node_put(node); } bank->irq = irq_of_parse_and_map(bank->of_node, 0); diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index eba872ce4a7c..d3332da35637 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -622,6 +622,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev) pctl->pctl_desc.pins = stmfx_pins; pctl->pctl_desc.npins = ARRAY_SIZE(stmfx_pins); pctl->pctl_desc.owner = THIS_MODULE; + pctl->pctl_desc.link_consumers = true; ret = devm_pinctrl_register_and_init(pctl->dev, &pctl->pctl_desc, pctl, &pctl->pctl_dev); diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c index 02b43f559e83..1f64e2e7efd9 100644 --- a/drivers/pinctrl/pinctrl-tb10x.c +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -471,22 +471,22 @@ struct tb10x_port { * @base: register set base address. * @pingroups: pointer to an array of the pin groups this driver manages. * @pinfuncgrpcnt: number of pingroups in @pingroups. - * @pinfuncs: pointer to an array of pin functions this driver manages. * @pinfuncnt: number of pin functions in @pinfuncs. * @mutex: mutex for exclusive access to a pin controller's state. * @ports: current state of each port. * @gpios: Indicates if a given pin is currently used as GPIO (1) or not (0). + * @pinfuncs: flexible array of pin functions this driver manages. */ struct tb10x_pinctrl { struct pinctrl_dev *pctl; void *base; const struct tb10x_pinfuncgrp *pingroups; unsigned int pinfuncgrpcnt; - struct tb10x_of_pinfunc *pinfuncs; unsigned int pinfuncnt; struct mutex mutex; struct tb10x_port ports[TB10X_PORTS]; DECLARE_BITMAP(gpios, MAX_PIN + 1); + struct tb10x_of_pinfunc pinfuncs[]; }; static inline void tb10x_pinctrl_set_config(struct tb10x_pinctrl *state, @@ -759,15 +759,13 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev) return -EINVAL; } - state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) + - of_get_child_count(of_node) - * sizeof(struct tb10x_of_pinfunc), - GFP_KERNEL); + state = devm_kzalloc(dev, struct_size(state, pinfuncs, + of_get_child_count(of_node)), + GFP_KERNEL); if (!state) return -ENOMEM; platform_set_drvdata(pdev, state); - state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1); mutex_init(&state->mutex); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 890d0a3a790b..8e14a5f2e970 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -169,11 +169,20 @@ config PINCTRL_SDM660 config PINCTRL_SDM845 tristate "Qualcomm Technologies Inc SDM845 pin controller driver" - depends on GPIOLIB && OF + depends on GPIOLIB && (OF || ACPI) 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 SDM845 platform. +config PINCTRL_SM8150 + tristate "Qualcomm Technologies Inc SM8150 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 SM8150 platform. + endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 344b4c6a6c6e..ebe906872272 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -22,3 +22,4 @@ 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 +obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 6e319bcc2326..7f35c196bb3e 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -599,8 +599,23 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip) int ret; unsigned int len, i; unsigned int max_gpios = pctrl->soc->ngpios; + const int *reserved = pctrl->soc->reserved_gpios; u16 *tmp; + /* Driver provided reserved list overrides DT and ACPI */ + if (reserved) { + bitmap_fill(chip->valid_mask, max_gpios); + for (i = 0; reserved[i] >= 0; i++) { + if (i >= max_gpios || reserved[i] >= max_gpios) { + dev_err(pctrl->dev, "invalid list of reserved GPIOs\n"); + return -EINVAL; + } + clear_bit(reserved[i], chip->valid_mask); + } + + return 0; + } + /* The number of GPIOs in the ACPI tables */ len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0); @@ -729,7 +744,7 @@ static void msm_gpio_irq_mask(struct irq_data *d) raw_spin_unlock_irqrestore(&pctrl->lock, flags); } -static void msm_gpio_irq_unmask(struct irq_data *d) +static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); @@ -741,6 +756,17 @@ static void msm_gpio_irq_unmask(struct irq_data *d) raw_spin_lock_irqsave(&pctrl->lock, flags); + if (status_clear) { + /* + * clear the interrupt status bit before unmask to avoid + * any erroneous interrupts that would have got latched + * when the interrupt is not in use. + */ + val = msm_readl_intr_status(pctrl, g); + val &= ~BIT(g->intr_status_bit); + msm_writel_intr_status(val, pctrl, g); + } + val = msm_readl_intr_cfg(pctrl, g); val |= BIT(g->intr_raw_status_bit); val |= BIT(g->intr_enable_bit); @@ -751,6 +777,17 @@ static void msm_gpio_irq_unmask(struct irq_data *d) raw_spin_unlock_irqrestore(&pctrl->lock, flags); } +static void msm_gpio_irq_enable(struct irq_data *d) +{ + + msm_gpio_irq_clear_unmask(d, true); +} + +static void msm_gpio_irq_unmask(struct irq_data *d) +{ + msm_gpio_irq_clear_unmask(d, false); +} + static void msm_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); @@ -956,6 +993,9 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) { + if (pctrl->soc->reserved_gpios) + return true; + return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0; } @@ -978,6 +1018,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl); pctrl->irq_chip.name = "msmgpio"; + pctrl->irq_chip.irq_enable = msm_gpio_irq_enable; pctrl->irq_chip.irq_mask = msm_gpio_irq_mask; pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask; pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index b724581c605c..48569cda8471 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -113,6 +113,7 @@ struct msm_pinctrl_soc_data { bool pull_no_keeper; const char *const *tiles; unsigned int ntiles; + const int *reserved_gpios; }; extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops; diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c index c97f20fca5fd..39f498c09906 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm845.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c @@ -3,6 +3,7 @@ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ +#include <linux/acpi.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -420,10 +421,10 @@ DECLARE_MSM_GPIO_PINS(147); DECLARE_MSM_GPIO_PINS(148); DECLARE_MSM_GPIO_PINS(149); -static const unsigned int sdc2_clk_pins[] = { 150 }; -static const unsigned int sdc2_cmd_pins[] = { 151 }; -static const unsigned int sdc2_data_pins[] = { 152 }; -static const unsigned int ufs_reset_pins[] = { 153 }; +static const unsigned int ufs_reset_pins[] = { 150 }; +static const unsigned int sdc2_clk_pins[] = { 151 }; +static const unsigned int sdc2_cmd_pins[] = { 152 }; +static const unsigned int sdc2_data_pins[] = { 153 }; enum sdm845_functions { msm_mux_gpio, @@ -1271,10 +1272,14 @@ static const struct msm_pingroup sdm845_groups[] = { PINGROUP(147, NORTH, _, _, _, _, _, _, _, _, _, _), PINGROUP(148, NORTH, _, _, _, _, _, _, _, _, _, _), PINGROUP(149, NORTH, _, _, _, _, _, _, _, _, _, _), + UFS_RESET(ufs_reset, 0x99f000), SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6), SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3), SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0), - UFS_RESET(ufs_reset, 0x99f000), +}; + +static const int sdm845_acpi_reserved_gpios[] = { + 0, 1, 2, 3, 81, 82, 83, 84, -1 }; static const struct msm_pinctrl_soc_data sdm845_pinctrl = { @@ -1284,14 +1289,42 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = { .nfunctions = ARRAY_SIZE(sdm845_functions), .groups = sdm845_groups, .ngroups = ARRAY_SIZE(sdm845_groups), + .ngpios = 151, +}; + +static const struct msm_pinctrl_soc_data sdm845_acpi_pinctrl = { + .pins = sdm845_pins, + .npins = ARRAY_SIZE(sdm845_pins), + .groups = sdm845_groups, + .ngroups = ARRAY_SIZE(sdm845_groups), + .reserved_gpios = sdm845_acpi_reserved_gpios, .ngpios = 150, }; static int sdm845_pinctrl_probe(struct platform_device *pdev) { - return msm_pinctrl_probe(pdev, &sdm845_pinctrl); + int ret; + + if (pdev->dev.of_node) { + ret = msm_pinctrl_probe(pdev, &sdm845_pinctrl); + } else if (has_acpi_companion(&pdev->dev)) { + ret = msm_pinctrl_probe(pdev, &sdm845_acpi_pinctrl); + } else { + dev_err(&pdev->dev, "DT and ACPI disabled\n"); + return -EINVAL; + } + + return ret; } +#ifdef CONFIG_ACPI +static const struct acpi_device_id sdm845_pinctrl_acpi_match[] = { + { "QCOM0217"}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, sdm845_pinctrl_acpi_match); +#endif + static const struct of_device_id sdm845_pinctrl_of_match[] = { { .compatible = "qcom,sdm845-pinctrl", }, { }, @@ -1302,6 +1335,7 @@ static struct platform_driver sdm845_pinctrl_driver = { .name = "sdm845-pinctrl", .pm = &msm_pinctrl_dev_pm_ops, .of_match_table = sdm845_pinctrl_of_match, + .acpi_match_table = ACPI_PTR(sdm845_pinctrl_acpi_match), }, .probe = sdm845_pinctrl_probe, .remove = msm_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c new file mode 100644 index 000000000000..7359bae68c69 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c @@ -0,0 +1,1548 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018-2019, 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 sm8150_tiles[] = { + "north", + "south", + "east", + "west" +}; + +enum { + NORTH, + SOUTH, + EAST, + WEST +}; + +#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 = 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 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 = SOUTH, \ + .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 sm8150_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, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + PINCTRL_PIN(147, "GPIO_147"), + PINCTRL_PIN(148, "GPIO_148"), + PINCTRL_PIN(149, "GPIO_149"), + PINCTRL_PIN(150, "GPIO_150"), + PINCTRL_PIN(151, "GPIO_151"), + PINCTRL_PIN(152, "GPIO_152"), + PINCTRL_PIN(153, "GPIO_153"), + PINCTRL_PIN(154, "GPIO_154"), + PINCTRL_PIN(155, "GPIO_155"), + PINCTRL_PIN(156, "GPIO_156"), + PINCTRL_PIN(157, "GPIO_157"), + PINCTRL_PIN(158, "GPIO_158"), + PINCTRL_PIN(159, "GPIO_159"), + PINCTRL_PIN(160, "GPIO_160"), + PINCTRL_PIN(161, "GPIO_161"), + PINCTRL_PIN(162, "GPIO_162"), + PINCTRL_PIN(163, "GPIO_163"), + PINCTRL_PIN(164, "GPIO_164"), + PINCTRL_PIN(165, "GPIO_165"), + PINCTRL_PIN(166, "GPIO_166"), + PINCTRL_PIN(167, "GPIO_167"), + PINCTRL_PIN(168, "GPIO_168"), + PINCTRL_PIN(169, "GPIO_169"), + PINCTRL_PIN(170, "GPIO_170"), + PINCTRL_PIN(171, "GPIO_171"), + PINCTRL_PIN(172, "GPIO_172"), + PINCTRL_PIN(173, "GPIO_173"), + PINCTRL_PIN(174, "GPIO_174"), + PINCTRL_PIN(175, "UFS_RESET"), + PINCTRL_PIN(176, "SDC2_CLK"), + PINCTRL_PIN(177, "SDC2_CMD"), + PINCTRL_PIN(178, "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); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); +DECLARE_MSM_GPIO_PINS(133); +DECLARE_MSM_GPIO_PINS(134); +DECLARE_MSM_GPIO_PINS(135); +DECLARE_MSM_GPIO_PINS(136); +DECLARE_MSM_GPIO_PINS(137); +DECLARE_MSM_GPIO_PINS(138); +DECLARE_MSM_GPIO_PINS(139); +DECLARE_MSM_GPIO_PINS(140); +DECLARE_MSM_GPIO_PINS(141); +DECLARE_MSM_GPIO_PINS(142); +DECLARE_MSM_GPIO_PINS(143); +DECLARE_MSM_GPIO_PINS(144); +DECLARE_MSM_GPIO_PINS(145); +DECLARE_MSM_GPIO_PINS(146); +DECLARE_MSM_GPIO_PINS(147); +DECLARE_MSM_GPIO_PINS(148); +DECLARE_MSM_GPIO_PINS(149); +DECLARE_MSM_GPIO_PINS(150); +DECLARE_MSM_GPIO_PINS(151); +DECLARE_MSM_GPIO_PINS(152); +DECLARE_MSM_GPIO_PINS(153); +DECLARE_MSM_GPIO_PINS(154); +DECLARE_MSM_GPIO_PINS(155); +DECLARE_MSM_GPIO_PINS(156); +DECLARE_MSM_GPIO_PINS(157); +DECLARE_MSM_GPIO_PINS(158); +DECLARE_MSM_GPIO_PINS(159); +DECLARE_MSM_GPIO_PINS(160); +DECLARE_MSM_GPIO_PINS(161); +DECLARE_MSM_GPIO_PINS(162); +DECLARE_MSM_GPIO_PINS(163); +DECLARE_MSM_GPIO_PINS(164); +DECLARE_MSM_GPIO_PINS(165); +DECLARE_MSM_GPIO_PINS(166); +DECLARE_MSM_GPIO_PINS(167); +DECLARE_MSM_GPIO_PINS(168); +DECLARE_MSM_GPIO_PINS(169); +DECLARE_MSM_GPIO_PINS(170); +DECLARE_MSM_GPIO_PINS(171); +DECLARE_MSM_GPIO_PINS(172); +DECLARE_MSM_GPIO_PINS(173); +DECLARE_MSM_GPIO_PINS(174); + +static const unsigned int ufs_reset_pins[] = { 175 }; +static const unsigned int sdc2_clk_pins[] = { 176 }; +static const unsigned int sdc2_cmd_pins[] = { 177 }; +static const unsigned int sdc2_data_pins[] = { 178 }; + +enum sm8150_functions { + msm_mux_adsp_ext, + msm_mux_agera_pll, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_usb1, + msm_mux_atest_usb2, + msm_mux_atest_usb10, + msm_mux_atest_usb11, + msm_mux_atest_usb12, + msm_mux_atest_usb13, + msm_mux_atest_usb20, + msm_mux_atest_usb21, + msm_mux_atest_usb22, + msm_mux_atest_usb23, + msm_mux_audio_ref, + msm_mux_btfm_slimbus, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c, + msm_mux_cci_timer0, + msm_mux_cci_timer1, + msm_mux_cci_timer2, + msm_mux_cci_timer3, + msm_mux_cci_timer4, + msm_mux_cri_trng, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_dbg_out, + msm_mux_ddr_bist, + msm_mux_ddr_pxi0, + msm_mux_ddr_pxi1, + msm_mux_ddr_pxi2, + msm_mux_ddr_pxi3, + msm_mux_edp_hot, + msm_mux_edp_lcd, + msm_mux_emac_phy, + msm_mux_emac_pps, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_gpio, + msm_mux_jitter_bist, + msm_mux_hs1_mi2s, + msm_mux_hs2_mi2s, + msm_mux_hs3_mi2s, + msm_mux_lpass_slimbus, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_mss_lte, + msm_mux_m_voc, + msm_mux_nav_pps, + msm_mux_pa_indicator, + msm_mux_pci_e0, + msm_mux_pci_e1, + msm_mux_phase_flag, + msm_mux_pll_bist, + msm_mux_pll_bypassnl, + msm_mux_pll_reset, + msm_mux_pri_mi2s, + msm_mux_pri_mi2s_ws, + msm_mux_prng_rosc, + msm_mux_qdss, + msm_mux_qdss_cti, + msm_mux_qlink_enable, + msm_mux_qlink_request, + msm_mux_qspi0, + msm_mux_qspi1, + msm_mux_qspi2, + msm_mux_qspi3, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qua_mi2s, + msm_mux_qup0, + msm_mux_qup1, + msm_mux_qup2, + msm_mux_qup3, + msm_mux_qup4, + msm_mux_qup5, + msm_mux_qup6, + msm_mux_qup7, + msm_mux_qup8, + msm_mux_qup9, + msm_mux_qup10, + msm_mux_qup11, + msm_mux_qup12, + msm_mux_qup13, + msm_mux_qup14, + msm_mux_qup15, + msm_mux_qup16, + msm_mux_qup17, + msm_mux_qup18, + msm_mux_qup19, + msm_mux_qup_l4, + msm_mux_qup_l5, + msm_mux_qup_l6, + msm_mux_rgmii, + msm_mux_sdc4, + msm_mux_sd_write, + msm_mux_sec_mi2s, + msm_mux_spkr_i2s, + msm_mux_sp_cmu, + msm_mux_ter_mi2s, + msm_mux_tgu_ch0, + msm_mux_tgu_ch2, + msm_mux_tgu_ch1, + msm_mux_tgu_ch3, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_tsif1, + msm_mux_tsif2, + msm_mux_uim1, + msm_mux_uim2, + msm_mux_uim_batt, + msm_mux_usb2phy_ac, + msm_mux_usb_phy, + msm_mux_vfr_1, + msm_mux_vsense_trigger, + msm_mux_wlan1_adc1, + msm_mux_wlan1_adc0, + msm_mux_wlan2_adc1, + msm_mux_wlan2_adc0, + msm_mux_wmss_reset, + msm_mux__, +}; + +static const char * const phase_flag_groups[] = { + "gpio18", "gpio19", "gpio20", "gpio55", "gpio56", + "gpio57", "gpio59", "gpio64", "gpio68", "gpio76", + "gpio79", "gpio80", "gpio90", "gpio91", "gpio92", + "gpio93", "gpio94", "gpio96", "gpio114", "gpio115", + "gpio116", "gpio117", "gpio118", "gpio119", "gpio120", + "gpio121", "gpio122", "gpio126", "gpio127", "gpio128", + "gpio144", "gpio145", +}; + +static const char * const emac_pps_groups[] = { + "gpio81", +}; + +static const char * const qup12_groups[] = { + "gpio83", "gpio84", "gpio85", "gpio86", +}; + +static const char * const qup16_groups[] = { + "gpio83", "gpio84", "gpio85", "gpio86", +}; + +static const char * const tsif1_groups[] = { + "gpio88", "gpio89", "gpio90", "gpio91", "gpio97", +}; + +static const char * const qup8_groups[] = { + "gpio88", "gpio89", "gpio90", "gpio91", +}; + +static const char * const qspi_cs_groups[] = { + "gpio88", "gpio94", +}; + +static const char * const tgu_ch3_groups[] = { + "gpio88", +}; + +static const char * const qspi0_groups[] = { + "gpio89", +}; + +static const char * const mdp_vsync0_groups[] = { + "gpio89", +}; + +static const char * const mdp_vsync1_groups[] = { + "gpio89", +}; + +static const char * const mdp_vsync2_groups[] = { + "gpio89", +}; + +static const char * const mdp_vsync3_groups[] = { + "gpio89", +}; + +static const char * const tgu_ch0_groups[] = { + "gpio89", +}; + +static const char * const qspi1_groups[] = { + "gpio90", +}; + +static const char * const sdc4_groups[] = { + "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", +}; + +static const char * const tgu_ch1_groups[] = { + "gpio90", +}; + +static const char * const wlan1_adc1_groups[] = { + "gpio90", +}; + +static const char * const qspi2_groups[] = { + "gpio91", +}; + +static const char * const vfr_1_groups[] = { + "gpio91", +}; + +static const char * const tgu_ch2_groups[] = { + "gpio91", +}; + +static const char * const wlan1_adc0_groups[] = { + "gpio91", +}; + +static const char * const tsif2_groups[] = { + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", +}; + +static const char * const qup11_groups[] = { + "gpio92", "gpio93", "gpio94", "gpio95", +}; + +static const char * const qspi_clk_groups[] = { + "gpio92", +}; + +static const char * const wlan2_adc1_groups[] = { + "gpio92", +}; + +static const char * const qspi3_groups[] = { + "gpio93", +}; + +static const char * const wlan2_adc0_groups[] = { + "gpio93", +}; + +static const char * const sd_write_groups[] = { + "gpio97", +}; + +static const char * const qup7_groups[] = { + "gpio98", "gpio99", "gpio100", "gpio101", +}; + +static const char * const ddr_bist_groups[] = { + "gpio98", "gpio99", "gpio145", "gpio146", +}; + +static const char * const ddr_pxi3_groups[] = { + "gpio98", "gpio101", +}; + +static const char * const atest_usb13_groups[] = { + "gpio99", +}; + +static const char * const ddr_pxi1_groups[] = { + "gpio99", "gpio100", +}; + +static const char * const pll_bypassnl_groups[] = { + "gpio100", +}; + +static const char * const atest_usb12_groups[] = { + "gpio100", +}; + +static const char * const pll_reset_groups[] = { + "gpio101", +}; + +static const char * const pci_e1_groups[] = { + "gpio102", "gpio103", +}; + +static const char * const uim2_groups[] = { + "gpio105", "gpio106", "gpio107", "gpio108", +}; + +static const char * const uim1_groups[] = { + "gpio109", "gpio110", "gpio111", "gpio112", +}; + +static const char * const uim_batt_groups[] = { + "gpio113", +}; + +static const char * const usb2phy_ac_groups[] = { + "gpio113", "gpio123", +}; + +static const char * const aoss_cti_groups[] = { + "gpio113", +}; + +static const char * const qup1_groups[] = { + "gpio114", "gpio115", "gpio116", "gpio117", +}; + +static const char * const rgmii_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", "gpio59", + "gpio114", "gpio115", "gpio116", "gpio117", + "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", +}; + +static const char * const adsp_ext_groups[] = { + "gpio115", +}; + +static const char * const qup5_groups[] = { + "gpio119", "gpio120", "gpio121", "gpio122", +}; + +static const char * const atest_usb22_groups[] = { + "gpio123", +}; + +static const char * const emac_phy_groups[] = { + "gpio124", +}; + +static const char * const hs3_mi2s_groups[] = { + "gpio125", "gpio165", "gpio166", "gpio167", "gpio168", +}; + +static const char * const sec_mi2s_groups[] = { + "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", +}; + +static const char * const qup2_groups[] = { + "gpio126", "gpio127", "gpio128", "gpio129", +}; + +static const char * const jitter_bist_groups[] = { + "gpio129", +}; + +static const char * const atest_usb21_groups[] = { + "gpio129", +}; + +static const char * const pll_bist_groups[] = { + "gpio130", +}; + +static const char * const atest_usb20_groups[] = { + "gpio130", +}; + +static const char * const atest_char0_groups[] = { + "gpio130", +}; + +static const char * const ter_mi2s_groups[] = { + "gpio131", "gpio132", "gpio133", "gpio134", "gpio135", +}; + +static const char * const gcc_gp1_groups[] = { + "gpio131", "gpio136", +}; + +static const char * const atest_char1_groups[] = { + "gpio133", +}; + +static const char * const atest_char2_groups[] = { + "gpio134", +}; + +static const char * const atest_char3_groups[] = { + "gpio135", +}; + +static const char * const qua_mi2s_groups[] = { + "gpio136", "gpio137", "gpio138", "gpio139", "gpio140", "gpio141", + "gpio142", +}; + +static const char * const pri_mi2s_groups[] = { + "gpio143", "gpio144", "gpio146", "gpio147", +}; + +static const char * const qup3_groups[] = { + "gpio144", "gpio145", "gpio146", "gpio147", +}; + +static const char * const ddr_pxi0_groups[] = { + "gpio144", "gpio145", +}; + +static const char * const pri_mi2s_ws_groups[] = { + "gpio145", +}; + +static const char * const vsense_trigger_groups[] = { + "gpio145", +}; + +static const char * const atest_usb1_groups[] = { + "gpio145", +}; + +static const char * const atest_usb11_groups[] = { + "gpio146", +}; + +static const char * const ddr_pxi2_groups[] = { + "gpio146", "gpio147", +}; + +static const char * const dbg_out_groups[] = { + "gpio147", +}; + +static const char * const atest_usb10_groups[] = { + "gpio147", +}; + +static const char * const spkr_i2s_groups[] = { + "gpio148", "gpio149", "gpio150", "gpio151", "gpio152", +}; + +static const char * const audio_ref_groups[] = { + "gpio148", +}; + +static const char * const lpass_slimbus_groups[] = { + "gpio149", "gpio150", "gpio151", "gpio152", +}; + +static const char * const tsense_pwm1_groups[] = { + "gpio150", +}; + +static const char * const tsense_pwm2_groups[] = { + "gpio150", +}; + +static const char * const btfm_slimbus_groups[] = { + "gpio153", "gpio154", +}; + +static const char * const hs1_mi2s_groups[] = { + "gpio155", "gpio156", "gpio157", "gpio158", "gpio159", +}; + +static const char * const cri_trng0_groups[] = { + "gpio159", +}; + +static const char * const hs2_mi2s_groups[] = { + "gpio160", "gpio161", "gpio162", "gpio163", "gpio164", +}; + +static const char * const cri_trng1_groups[] = { + "gpio160", +}; + +static const char * const cri_trng_groups[] = { + "gpio161", +}; + +static const char * const sp_cmu_groups[] = { + "gpio162", +}; + +static const char * const prng_rosc_groups[] = { + "gpio163", +}; + +static const char * const qup0_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; + +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", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", + "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128", + "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134", + "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140", + "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146", + "gpio147", "gpio148", "gpio149", "gpio150", "gpio151", "gpio152", + "gpio153", "gpio154", "gpio155", "gpio156", "gpio157", "gpio158", + "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164", + "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170", + "gpio171", "gpio172", "gpio173", "gpio174", +}; + +static const char * const qup6_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; + +static const char * const qup_l6_groups[] = { + "gpio6", "gpio34", "gpio97", "gpio123", +}; + +static const char * const qup_l5_groups[] = { + "gpio7", "gpio33", "gpio82", "gpio96", +}; + +static const char * const mdp_vsync_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio81", "gpio82", +}; + +static const char * const edp_lcd_groups[] = { + "gpio9", +}; + +static const char * const qup10_groups[] = { + "gpio9", "gpio10", "gpio11", "gpio12", +}; + +static const char * const m_voc_groups[] = { + "gpio10", +}; + +static const char * const edp_hot_groups[] = { + "gpio10", +}; + +static const char * const cam_mclk_groups[] = { + "gpio13", "gpio14", "gpio15", "gpio16", +}; + +static const char * const qdss_groups[] = { + "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", + "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", + "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", + "gpio33", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio47", "gpio48", "gpio83", "gpio117", "gpio118", + "gpio119", "gpio120", "gpio121", "gpio132", + "gpio133", "gpio134", +}; + +static const char * const cci_i2c_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", "gpio31", "gpio32", "gpio33", + "gpio34", +}; + +static const char * const cci_timer0_groups[] = { + "gpio21", +}; + +static const char * const gcc_gp2_groups[] = { + "gpio21", "gpio137", +}; + +static const char * const cci_timer1_groups[] = { + "gpio22", +}; + +static const char * const gcc_gp3_groups[] = { + "gpio22", "gpio138", +}; + +static const char * const cci_timer2_groups[] = { + "gpio23", +}; + +static const char * const qup18_groups[] = { + "gpio23", "gpio24", "gpio25", "gpio26", +}; + +static const char * const cci_timer3_groups[] = { + "gpio24", +}; + +static const char * const cci_async_groups[] = { + "gpio24", "gpio25", "gpio26", +}; + +static const char * const cci_timer4_groups[] = { + "gpio25", +}; + +static const char * const qup15_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30", +}; + +static const char * const pci_e0_groups[] = { + "gpio35", "gpio36", +}; + +static const char * const qup_l4_groups[] = { + "gpio37", "gpio59", "gpio81", "gpio95", +}; + +static const char * const agera_pll_groups[] = { + "gpio37", +}; + +static const char * const usb_phy_groups[] = { + "gpio38", +}; + +static const char * const qup9_groups[] = { + "gpio39", "gpio40", "gpio41", "gpio42", +}; + +static const char * const qup13_groups[] = { + "gpio43", "gpio44", "gpio45", "gpio46", +}; + +static const char * const qdss_cti_groups[] = { + "gpio45", "gpio46", "gpio49", "gpio50", "gpio56", "gpio57", "gpio58", + "gpio58", +}; + +static const char * const qup14_groups[] = { + "gpio47", "gpio48", "gpio49", "gpio50", +}; + +static const char * const qup4_groups[] = { + "gpio51", "gpio52", "gpio53", "gpio54", +}; + +static const char * const qup17_groups[] = { + "gpio55", "gpio56", "gpio57", "gpio58", +}; + +static const char * const qup19_groups[] = { + "gpio55", "gpio56", "gpio57", "gpio58", +}; + +static const char * const atest_char_groups[] = { + "gpio59", +}; + +static const char * const nav_pps_groups[] = { + "gpio60", "gpio60", "gpio76", "gpio76", "gpio77", "gpio77", "gpio81", + "gpio81", "gpio82", "gpio82", +}; + +static const char * const atest_usb2_groups[] = { + "gpio60", +}; + +static const char * const qlink_request_groups[] = { + "gpio61", +}; + +static const char * const qlink_enable_groups[] = { + "gpio62", +}; + +static const char * const wmss_reset_groups[] = { + "gpio63", +}; + +static const char * const atest_usb23_groups[] = { + "gpio63", +}; + +static const char * const pa_indicator_groups[] = { + "gpio68", +}; + +static const char * const mss_lte_groups[] = { + "gpio69", "gpio70", +}; + +static const struct msm_function sm8150_functions[] = { + FUNCTION(adsp_ext), + FUNCTION(agera_pll), + FUNCTION(aoss_cti), + FUNCTION(ddr_pxi2), + FUNCTION(atest_char), + FUNCTION(atest_char0), + FUNCTION(atest_char1), + FUNCTION(atest_char2), + FUNCTION(atest_char3), + FUNCTION(audio_ref), + FUNCTION(atest_usb1), + FUNCTION(atest_usb2), + FUNCTION(atest_usb10), + FUNCTION(atest_usb11), + FUNCTION(atest_usb12), + FUNCTION(atest_usb13), + FUNCTION(atest_usb20), + FUNCTION(atest_usb21), + FUNCTION(atest_usb22), + FUNCTION(atest_usb23), + FUNCTION(btfm_slimbus), + FUNCTION(cam_mclk), + FUNCTION(cci_async), + FUNCTION(cci_i2c), + FUNCTION(cci_timer0), + FUNCTION(cci_timer1), + FUNCTION(cci_timer2), + FUNCTION(cci_timer3), + FUNCTION(cci_timer4), + FUNCTION(cri_trng), + FUNCTION(cri_trng0), + FUNCTION(cri_trng1), + FUNCTION(dbg_out), + FUNCTION(ddr_bist), + FUNCTION(ddr_pxi0), + FUNCTION(ddr_pxi1), + FUNCTION(ddr_pxi3), + FUNCTION(edp_hot), + FUNCTION(edp_lcd), + FUNCTION(emac_phy), + FUNCTION(emac_pps), + FUNCTION(gcc_gp1), + FUNCTION(gcc_gp2), + FUNCTION(gcc_gp3), + FUNCTION(gpio), + FUNCTION(hs1_mi2s), + FUNCTION(hs2_mi2s), + FUNCTION(hs3_mi2s), + FUNCTION(jitter_bist), + FUNCTION(lpass_slimbus), + FUNCTION(mdp_vsync), + FUNCTION(mdp_vsync0), + FUNCTION(mdp_vsync1), + FUNCTION(mdp_vsync2), + FUNCTION(mdp_vsync3), + FUNCTION(mss_lte), + FUNCTION(m_voc), + FUNCTION(nav_pps), + FUNCTION(pa_indicator), + FUNCTION(pci_e0), + FUNCTION(phase_flag), + FUNCTION(pll_bypassnl), + FUNCTION(pll_bist), + FUNCTION(pci_e1), + FUNCTION(pll_reset), + FUNCTION(pri_mi2s), + FUNCTION(pri_mi2s_ws), + FUNCTION(prng_rosc), + FUNCTION(qdss), + FUNCTION(qdss_cti), + FUNCTION(qlink_request), + FUNCTION(qlink_enable), + FUNCTION(qspi0), + FUNCTION(qspi1), + FUNCTION(qspi2), + FUNCTION(qspi3), + FUNCTION(qspi_clk), + FUNCTION(qspi_cs), + FUNCTION(qua_mi2s), + FUNCTION(qup0), + FUNCTION(qup1), + FUNCTION(qup2), + FUNCTION(qup3), + FUNCTION(qup4), + FUNCTION(qup5), + FUNCTION(qup6), + FUNCTION(qup7), + FUNCTION(qup8), + FUNCTION(qup9), + FUNCTION(qup10), + FUNCTION(qup11), + FUNCTION(qup12), + FUNCTION(qup13), + FUNCTION(qup14), + FUNCTION(qup15), + FUNCTION(qup16), + FUNCTION(qup17), + FUNCTION(qup18), + FUNCTION(qup19), + FUNCTION(qup_l4), + FUNCTION(qup_l5), + FUNCTION(qup_l6), + FUNCTION(rgmii), + FUNCTION(sdc4), + FUNCTION(sd_write), + FUNCTION(sec_mi2s), + FUNCTION(spkr_i2s), + FUNCTION(sp_cmu), + FUNCTION(ter_mi2s), + FUNCTION(tgu_ch0), + FUNCTION(tgu_ch1), + FUNCTION(tgu_ch2), + FUNCTION(tgu_ch3), + FUNCTION(tsense_pwm1), + FUNCTION(tsense_pwm2), + FUNCTION(tsif1), + FUNCTION(tsif2), + FUNCTION(uim1), + FUNCTION(uim2), + FUNCTION(uim_batt), + FUNCTION(usb2phy_ac), + FUNCTION(usb_phy), + FUNCTION(vfr_1), + FUNCTION(vsense_trigger), + FUNCTION(wlan1_adc0), + FUNCTION(wlan1_adc1), + FUNCTION(wlan2_adc0), + FUNCTION(wlan2_adc1), + FUNCTION(wmss_reset), +}; + +/* + * 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 sm8150_groups[] = { + [0] = PINGROUP(0, SOUTH, qup0, _, _, _, _, _, _, _, _), + [1] = PINGROUP(1, SOUTH, qup0, _, _, _, _, _, _, _, _), + [2] = PINGROUP(2, SOUTH, qup0, _, _, _, _, _, _, _, _), + [3] = PINGROUP(3, SOUTH, qup0, _, _, _, _, _, _, _, _), + [4] = PINGROUP(4, SOUTH, qup6, rgmii, _, _, _, _, _, _, _), + [5] = PINGROUP(5, SOUTH, qup6, rgmii, _, _, _, _, _, _, _), + [6] = PINGROUP(6, SOUTH, qup6, rgmii, qup_l6, _, _, _, _, _, _), + [7] = PINGROUP(7, SOUTH, qup6, rgmii, qup_l5, _, _, _, _, _, _), + [8] = PINGROUP(8, NORTH, mdp_vsync, _, _, _, _, _, _, _, _), + [9] = PINGROUP(9, NORTH, mdp_vsync, edp_lcd, qup10, _, _, _, _, _, _), + [10] = PINGROUP(10, NORTH, mdp_vsync, m_voc, edp_hot, qup10, _, _, _, _, _), + [11] = PINGROUP(11, NORTH, qup10, _, _, _, _, _, _, _, _), + [12] = PINGROUP(12, NORTH, qup10, _, _, _, _, _, _, _, _), + [13] = PINGROUP(13, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _), + [14] = PINGROUP(14, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _), + [15] = PINGROUP(15, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _), + [16] = PINGROUP(16, NORTH, cam_mclk, qdss, _, _, _, _, _, _, _), + [17] = PINGROUP(17, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _), + [18] = PINGROUP(18, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _), + [19] = PINGROUP(19, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _), + [20] = PINGROUP(20, NORTH, cci_i2c, phase_flag, _, qdss, _, _, _, _, _), + [21] = PINGROUP(21, EAST, cci_timer0, gcc_gp2, qdss, _, _, _, _, _, _), + [22] = PINGROUP(22, EAST, cci_timer1, gcc_gp3, qdss, _, _, _, _, _, _), + [23] = PINGROUP(23, EAST, cci_timer2, qup18, qdss, _, _, _, _, _, _), + [24] = PINGROUP(24, EAST, cci_timer3, cci_async, qup18, qdss, _, _, _, _, _), + [25] = PINGROUP(25, EAST, cci_timer4, cci_async, qup18, qdss, _, _, _, _, _), + [26] = PINGROUP(26, EAST, cci_async, qup18, qdss, _, _, _, _, _, _), + [27] = PINGROUP(27, EAST, qup15, _, qdss, _, _, _, _, _, _), + [28] = PINGROUP(28, EAST, qup15, qdss, _, _, _, _, _, _, _), + [29] = PINGROUP(29, EAST, qup15, qdss, _, _, _, _, _, _, _), + [30] = PINGROUP(30, EAST, qup15, qdss, _, _, _, _, _, _, _), + [31] = PINGROUP(31, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _), + [32] = PINGROUP(32, NORTH, cci_i2c, qdss, _, _, _, _, _, _, _), + [33] = PINGROUP(33, NORTH, cci_i2c, qup_l5, qdss, _, _, _, _, _, _), + [34] = PINGROUP(34, NORTH, cci_i2c, qup_l6, _, _, _, _, _, _, _), + [35] = PINGROUP(35, NORTH, pci_e0, _, _, _, _, _, _, _, _), + [36] = PINGROUP(36, NORTH, pci_e0, _, _, _, _, _, _, _, _), + [37] = PINGROUP(37, NORTH, qup_l4, agera_pll, _, _, _, _, _, _, _), + [38] = PINGROUP(38, SOUTH, usb_phy, _, _, _, _, _, _, _, _), + [39] = PINGROUP(39, NORTH, qup9, qdss, _, _, _, _, _, _, _), + [40] = PINGROUP(40, NORTH, qup9, qdss, _, _, _, _, _, _, _), + [41] = PINGROUP(41, NORTH, qup9, qdss, _, _, _, _, _, _, _), + [42] = PINGROUP(42, NORTH, qup9, qdss, _, _, _, _, _, _, _), + [43] = PINGROUP(43, EAST, qup13, _, _, _, _, _, _, _, _), + [44] = PINGROUP(44, EAST, qup13, _, _, _, _, _, _, _, _), + [45] = PINGROUP(45, EAST, qup13, qdss_cti, _, _, _, _, _, _, _), + [46] = PINGROUP(46, EAST, qup13, qdss_cti, _, _, _, _, _, _, _), + [47] = PINGROUP(47, EAST, qup14, qdss, _, _, _, _, _, _, _), + [48] = PINGROUP(48, EAST, qup14, qdss, _, _, _, _, _, _, _), + [49] = PINGROUP(49, EAST, qup14, _, qdss_cti, _, _, _, _, _, _), + [50] = PINGROUP(50, EAST, qup14, qdss_cti, _, _, _, _, _, _, _), + [51] = PINGROUP(51, SOUTH, qup4, _, _, _, _, _, _, _, _), + [52] = PINGROUP(52, SOUTH, qup4, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, SOUTH, qup4, _, _, _, _, _, _, _, _), + [54] = PINGROUP(54, SOUTH, qup4, _, _, _, _, _, _, _, _), + [55] = PINGROUP(55, SOUTH, qup17, qup19, phase_flag, _, _, _, _, _, _), + [56] = PINGROUP(56, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _), + [57] = PINGROUP(57, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _), + [58] = PINGROUP(58, SOUTH, qup17, qup19, qdss_cti, phase_flag, _, _, _, _, _), + [59] = PINGROUP(59, SOUTH, rgmii, qup_l4, phase_flag, _, atest_char, _, _, _, _), + [60] = PINGROUP(60, SOUTH, _, nav_pps, nav_pps, atest_usb2, _, _, _, _, _), + [61] = PINGROUP(61, SOUTH, qlink_request, _, _, _, _, _, _, _, _), + [62] = PINGROUP(62, SOUTH, qlink_enable, _, _, _, _, _, _, _, _), + [63] = PINGROUP(63, SOUTH, wmss_reset, atest_usb23, _, _, _, _, _, _, _), + [64] = PINGROUP(64, SOUTH, _, phase_flag, _, _, _, _, _, _, _), + [65] = PINGROUP(65, SOUTH, _, _, _, _, _, _, _, _, _), + [66] = PINGROUP(66, SOUTH, _, _, _, _, _, _, _, _, _), + [67] = PINGROUP(67, SOUTH, _, _, _, _, _, _, _, _, _), + [68] = PINGROUP(68, SOUTH, _, pa_indicator, phase_flag, _, _, _, _, _, _), + [69] = PINGROUP(69, SOUTH, mss_lte, _, _, _, _, _, _, _, _), + [70] = PINGROUP(70, SOUTH, mss_lte, _, _, _, _, _, _, _, _), + [71] = PINGROUP(71, SOUTH, _, _, _, _, _, _, _, _, _), + [72] = PINGROUP(72, SOUTH, _, _, _, _, _, _, _, _, _), + [73] = PINGROUP(73, SOUTH, _, _, _, _, _, _, _, _, _), + [74] = PINGROUP(74, SOUTH, _, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, SOUTH, _, _, _, _, _, _, _, _, _), + [76] = PINGROUP(76, SOUTH, _, _, _, nav_pps, nav_pps, phase_flag, _, _, _), + [77] = PINGROUP(77, SOUTH, _, _, _, nav_pps, nav_pps, _, _, _, _), + [78] = PINGROUP(78, SOUTH, _, _, _, _, _, _, _, _, _), + [79] = PINGROUP(79, SOUTH, _, _, phase_flag, _, _, _, _, _, _), + [80] = PINGROUP(80, SOUTH, _, _, phase_flag, _, _, _, _, _, _), + [81] = PINGROUP(81, SOUTH, _, _, _, nav_pps, nav_pps, qup_l4, mdp_vsync, emac_pps, _), + [82] = PINGROUP(82, SOUTH, _, _, _, nav_pps, nav_pps, qup_l5, mdp_vsync, _, _), + [83] = PINGROUP(83, NORTH, qup12, qup16, _, qdss, _, _, _, _, _), + [84] = PINGROUP(84, NORTH, qup12, qup16, _, _, _, _, _, _, _), + [85] = PINGROUP(85, NORTH, qup12, qup16, _, _, _, _, _, _, _), + [86] = PINGROUP(86, NORTH, qup12, qup16, _, _, _, _, _, _, _), + [87] = PINGROUP(87, EAST, _, _, _, _, _, _, _, _, _), + [88] = PINGROUP(88, NORTH, tsif1, qup8, qspi_cs, tgu_ch3, _, _, _, _, _), + [89] = PINGROUP(89, NORTH, tsif1, qup8, qspi0, mdp_vsync0, mdp_vsync1, mdp_vsync2, mdp_vsync3, tgu_ch0, _), + [90] = PINGROUP(90, NORTH, tsif1, qup8, qspi1, sdc4, phase_flag, tgu_ch1, _, _, wlan1_adc1), + [91] = PINGROUP(91, NORTH, tsif1, qup8, qspi2, sdc4, vfr_1, phase_flag, tgu_ch2, _, _), + [92] = PINGROUP(92, NORTH, tsif2, qup11, qspi_clk, sdc4, phase_flag, _, wlan2_adc1, _, _), + [93] = PINGROUP(93, NORTH, tsif2, qup11, qspi3, sdc4, phase_flag, _, wlan2_adc0, _, _), + [94] = PINGROUP(94, NORTH, tsif2, qup11, qspi_cs, sdc4, phase_flag, _, _, _, _), + [95] = PINGROUP(95, NORTH, tsif2, qup11, sdc4, qup_l4, _, _, _, _, _), + [96] = PINGROUP(96, NORTH, tsif2, qup_l5, phase_flag, _, _, _, _, _, _), + [97] = PINGROUP(97, NORTH, sd_write, tsif1, qup_l6, _, _, _, _, _, _), + [98] = PINGROUP(98, SOUTH, qup7, ddr_bist, ddr_pxi3, _, _, _, _, _, _), + [99] = PINGROUP(99, SOUTH, qup7, ddr_bist, atest_usb13, ddr_pxi1, _, _, _, _, _), + [100] = PINGROUP(100, SOUTH, qup7, pll_bypassnl, atest_usb12, ddr_pxi1, _, _, _, _, _), + [101] = PINGROUP(101, SOUTH, qup7, pll_reset, ddr_pxi3, _, _, _, _, _, _), + [102] = PINGROUP(102, NORTH, pci_e1, _, _, _, _, _, _, _, _), + [103] = PINGROUP(103, NORTH, pci_e1, _, _, _, _, _, _, _, _), + [104] = PINGROUP(104, NORTH, _, _, _, _, _, _, _, _, _), + [105] = PINGROUP(105, WEST, uim2, _, _, _, _, _, _, _, _), + [106] = PINGROUP(106, WEST, uim2, _, _, _, _, _, _, _, _), + [107] = PINGROUP(107, WEST, uim2, _, _, _, _, _, _, _, _), + [108] = PINGROUP(108, WEST, uim2, _, _, _, _, _, _, _, _), + [109] = PINGROUP(109, WEST, uim1, _, _, _, _, _, _, _, _), + [110] = PINGROUP(110, WEST, uim1, _, _, _, _, _, _, _, _), + [111] = PINGROUP(111, WEST, uim1, _, _, _, _, _, _, _, _), + [112] = PINGROUP(112, WEST, uim1, _, _, _, _, _, _, _, _), + [113] = PINGROUP(113, WEST, uim_batt, usb2phy_ac, aoss_cti, _, _, _, _, _, _), + [114] = PINGROUP(114, SOUTH, qup1, rgmii, phase_flag, _, _, _, _, _, _), + [115] = PINGROUP(115, SOUTH, qup1, rgmii, phase_flag, adsp_ext, _, _, _, _, _), + [116] = PINGROUP(116, SOUTH, qup1, rgmii, phase_flag, _, _, _, _, _, _), + [117] = PINGROUP(117, SOUTH, qup1, rgmii, phase_flag, _, qdss, _, _, _, _), + [118] = PINGROUP(118, SOUTH, rgmii, phase_flag, _, qdss, _, _, _, _, _), + [119] = PINGROUP(119, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _), + [120] = PINGROUP(120, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _), + [121] = PINGROUP(121, SOUTH, qup5, rgmii, phase_flag, _, qdss, _, _, _, _), + [122] = PINGROUP(122, SOUTH, qup5, rgmii, phase_flag, _, _, _, _, _, _), + [123] = PINGROUP(123, SOUTH, usb2phy_ac, qup_l6, atest_usb22, _, _, _, _, _, _), + [124] = PINGROUP(124, SOUTH, emac_phy, _, _, _, _, _, _, _, _), + [125] = PINGROUP(125, WEST, hs3_mi2s, _, _, _, _, _, _, _, _), + [126] = PINGROUP(126, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _), + [127] = PINGROUP(127, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _), + [128] = PINGROUP(128, SOUTH, sec_mi2s, qup2, phase_flag, _, _, _, _, _, _), + [129] = PINGROUP(129, SOUTH, sec_mi2s, qup2, jitter_bist, atest_usb21, _, _, _, _, _), + [130] = PINGROUP(130, SOUTH, sec_mi2s, pll_bist, atest_usb20, atest_char0, _, _, _, _, _), + [131] = PINGROUP(131, SOUTH, ter_mi2s, gcc_gp1, _, _, _, _, _, _, _), + [132] = PINGROUP(132, SOUTH, ter_mi2s, _, qdss, _, _, _, _, _, _), + [133] = PINGROUP(133, SOUTH, ter_mi2s, qdss, atest_char1, _, _, _, _, _, _), + [134] = PINGROUP(134, SOUTH, ter_mi2s, qdss, atest_char2, _, _, _, _, _, _), + [135] = PINGROUP(135, SOUTH, ter_mi2s, atest_char3, _, _, _, _, _, _, _), + [136] = PINGROUP(136, SOUTH, qua_mi2s, gcc_gp1, _, _, _, _, _, _, _), + [137] = PINGROUP(137, SOUTH, qua_mi2s, gcc_gp2, _, _, _, _, _, _, _), + [138] = PINGROUP(138, SOUTH, qua_mi2s, gcc_gp3, _, _, _, _, _, _, _), + [139] = PINGROUP(139, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _), + [140] = PINGROUP(140, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _), + [141] = PINGROUP(141, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _), + [142] = PINGROUP(142, SOUTH, qua_mi2s, _, _, _, _, _, _, _, _), + [143] = PINGROUP(143, SOUTH, pri_mi2s, _, _, _, _, _, _, _, _), + [144] = PINGROUP(144, SOUTH, pri_mi2s, qup3, phase_flag, _, ddr_pxi0, _, _, _, _), + [145] = PINGROUP(145, SOUTH, pri_mi2s_ws, qup3, phase_flag, ddr_bist, _, vsense_trigger, atest_usb1, ddr_pxi0, _), + [146] = PINGROUP(146, SOUTH, pri_mi2s, qup3, ddr_bist, atest_usb11, ddr_pxi2, _, _, _, _), + [147] = PINGROUP(147, SOUTH, pri_mi2s, qup3, dbg_out, atest_usb10, ddr_pxi2, _, _, _, _), + [148] = PINGROUP(148, SOUTH, spkr_i2s, audio_ref, _, _, _, _, _, _, _), + [149] = PINGROUP(149, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _), + [150] = PINGROUP(150, SOUTH, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2, _, _, _, _, _), + [151] = PINGROUP(151, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _), + [152] = PINGROUP(152, SOUTH, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _), + [153] = PINGROUP(153, SOUTH, btfm_slimbus, _, _, _, _, _, _, _, _), + [154] = PINGROUP(154, SOUTH, btfm_slimbus, _, _, _, _, _, _, _, _), + [155] = PINGROUP(155, WEST, hs1_mi2s, _, _, _, _, _, _, _, _), + [156] = PINGROUP(156, WEST, hs1_mi2s, _, _, _, _, _, _, _, _), + [157] = PINGROUP(157, WEST, hs1_mi2s, _, _, _, _, _, _, _, _), + [158] = PINGROUP(158, WEST, hs1_mi2s, _, _, _, _, _, _, _, _), + [159] = PINGROUP(159, WEST, hs1_mi2s, cri_trng0, _, _, _, _, _, _, _), + [160] = PINGROUP(160, WEST, hs2_mi2s, cri_trng1, _, _, _, _, _, _, _), + [161] = PINGROUP(161, WEST, hs2_mi2s, cri_trng, _, _, _, _, _, _, _), + [162] = PINGROUP(162, WEST, hs2_mi2s, sp_cmu, _, _, _, _, _, _, _), + [163] = PINGROUP(163, WEST, hs2_mi2s, prng_rosc, _, _, _, _, _, _, _), + [164] = PINGROUP(164, WEST, hs2_mi2s, _, _, _, _, _, _, _, _), + [165] = PINGROUP(165, WEST, hs3_mi2s, _, _, _, _, _, _, _, _), + [166] = PINGROUP(166, WEST, hs3_mi2s, _, _, _, _, _, _, _, _), + [167] = PINGROUP(167, WEST, hs3_mi2s, _, _, _, _, _, _, _, _), + [168] = PINGROUP(168, WEST, hs3_mi2s, _, _, _, _, _, _, _, _), + [169] = PINGROUP(169, NORTH, _, _, _, _, _, _, _, _, _), + [170] = PINGROUP(170, NORTH, _, _, _, _, _, _, _, _, _), + [171] = PINGROUP(171, NORTH, _, _, _, _, _, _, _, _, _), + [172] = PINGROUP(172, NORTH, _, _, _, _, _, _, _, _, _), + [173] = PINGROUP(173, NORTH, _, _, _, _, _, _, _, _, _), + [174] = PINGROUP(174, NORTH, _, _, _, _, _, _, _, _, _), + [175] = UFS_RESET(ufs_reset, 0xB6000), + [176] = SDC_QDSD_PINGROUP(sdc2_clk, 0xB2000, 14, 6), + [177] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xB2000, 11, 3), + [178] = SDC_QDSD_PINGROUP(sdc2_data, 0xB2000, 9, 0), +}; + +static const struct msm_pinctrl_soc_data sm8150_pinctrl = { + .pins = sm8150_pins, + .npins = ARRAY_SIZE(sm8150_pins), + .functions = sm8150_functions, + .nfunctions = ARRAY_SIZE(sm8150_functions), + .groups = sm8150_groups, + .ngroups = ARRAY_SIZE(sm8150_groups), + .ngpios = 176, + .tiles = sm8150_tiles, + .ntiles = ARRAY_SIZE(sm8150_tiles), +}; + +static int sm8150_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &sm8150_pinctrl); +} + +static const struct of_device_id sm8150_pinctrl_of_match[] = { + { .compatible = "qcom,sm8150-pinctrl", }, + { }, +}; + +static struct platform_driver sm8150_pinctrl_driver = { + .driver = { + .name = "sm8150-pinctrl", + .of_match_table = sm8150_pinctrl_of_match, + }, + .probe = sm8150_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init sm8150_pinctrl_init(void) +{ + return platform_driver_register(&sm8150_pinctrl_driver); +} +arch_initcall(sm8150_pinctrl_init); + +static void __exit sm8150_pinctrl_exit(void) +{ + platform_driver_unregister(&sm8150_pinctrl_driver); +} +module_exit(sm8150_pinctrl_exit); + +MODULE_DESCRIPTION("QTI sm8150 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, sm8150_pinctrl_of_match); diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 3f989f5cb021..b8640ad41bef 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -717,7 +717,7 @@ static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; } #endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */ #ifdef DEBUG -static bool is0s(const u16 *enum_ids, unsigned int n) +static bool __init is0s(const u16 *enum_ids, unsigned int n) { unsigned int i; @@ -728,11 +728,11 @@ static bool is0s(const u16 *enum_ids, unsigned int n) return true; } -static unsigned int sh_pfc_errors; -static unsigned int sh_pfc_warnings; +static unsigned int sh_pfc_errors __initdata = 0; +static unsigned int sh_pfc_warnings __initdata = 0; -static void sh_pfc_check_cfg_reg(const char *drvname, - const struct pinmux_cfg_reg *cfg_reg) +static void __init sh_pfc_check_cfg_reg(const char *drvname, + const struct pinmux_cfg_reg *cfg_reg) { unsigned int i, n, rw, fw; @@ -764,7 +764,7 @@ static void sh_pfc_check_cfg_reg(const char *drvname, } } -static void sh_pfc_check_info(const struct sh_pfc_soc_info *info) +static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info) { const struct sh_pfc_function *func; const char *drvname = info->name; @@ -773,6 +773,35 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info) pr_info("Checking %s\n", drvname); + /* Check pins */ + for (i = 0; i < info->nr_pins; i++) { + for (j = 0; j < i; j++) { + if (!strcmp(info->pins[i].name, info->pins[j].name)) { + pr_err("%s: pin %s/%s: name conflict\n", + drvname, info->pins[i].name, + info->pins[j].name); + sh_pfc_errors++; + } + + if (info->pins[i].pin != (u16)-1 && + info->pins[i].pin == info->pins[j].pin) { + pr_err("%s: pin %s/%s: pin %u conflict\n", + drvname, info->pins[i].name, + info->pins[j].name, info->pins[i].pin); + sh_pfc_errors++; + } + + if (info->pins[i].enum_id && + info->pins[i].enum_id == info->pins[j].enum_id) { + pr_err("%s: pin %s/%s: enum_id %u conflict\n", + drvname, info->pins[i].name, + info->pins[j].name, + info->pins[i].enum_id); + sh_pfc_errors++; + } + } + } + /* Check groups and functions */ refcnts = kcalloc(info->nr_groups, sizeof(*refcnts), GFP_KERNEL); if (!refcnts) @@ -780,9 +809,15 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info) for (i = 0; i < info->nr_functions; i++) { func = &info->functions[i]; + if (!func->name) { + pr_err("%s: empty function %u\n", drvname, i); + sh_pfc_errors++; + continue; + } for (j = 0; j < func->nr_groups; j++) { for (k = 0; k < info->nr_groups; k++) { - if (!strcmp(func->groups[j], + if (info->groups[k].name && + !strcmp(func->groups[j], info->groups[k].name)) { refcnts[k]++; break; @@ -798,13 +833,18 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info) } for (i = 0; i < info->nr_groups; i++) { + if (!info->groups[i].name) { + pr_err("%s: empty group %u\n", drvname, i); + sh_pfc_errors++; + continue; + } if (!refcnts[i]) { pr_err("%s: orphan group %s\n", drvname, info->groups[i].name); sh_pfc_errors++; } else if (refcnts[i] > 1) { - pr_err("%s: group %s referred by %u functions\n", - drvname, info->groups[i].name, refcnts[i]); + pr_warn("%s: group %s referenced by %u functions\n", + drvname, info->groups[i].name, refcnts[i]); sh_pfc_warnings++; } } @@ -816,7 +856,7 @@ static void sh_pfc_check_info(const struct sh_pfc_soc_info *info) sh_pfc_check_cfg_reg(drvname, &info->cfg_regs[i]); } -static void sh_pfc_check_driver(const struct platform_driver *pdrv) +static void __init sh_pfc_check_driver(const struct platform_driver *pdrv) { unsigned int i; diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c index 0af1ef82a1a8..6c66fc335d2f 100644 --- a/drivers/pinctrl/sh-pfc/pfc-emev2.c +++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c @@ -19,6 +19,20 @@ PORT_1(155, fn, pfx##155, sfx), PORT_1(156, fn, pfx##156, sfx), \ PORT_1(157, fn, pfx##157, sfx), PORT_1(158, fn, pfx##158, sfx) +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP(LCD3_B2, "B15", fn), \ + PIN_NOGP(LCD3_B3, "C15", fn), \ + PIN_NOGP(LCD3_B4, "D15", fn), \ + PIN_NOGP(LCD3_B5, "B14", fn), \ + PIN_NOGP(LCD3_B6, "C14", fn), \ + PIN_NOGP(LCD3_B7, "D14", fn), \ + PIN_NOGP(LCD3_G2, "B17", fn), \ + PIN_NOGP(LCD3_G3, "C17", fn), \ + PIN_NOGP(LCD3_G4, "D17", fn), \ + PIN_NOGP(LCD3_G5, "B16", fn), \ + PIN_NOGP(LCD3_G6, "C16", fn), \ + PIN_NOGP(LCD3_G7, "D16", fn) + enum { PINMUX_RESERVED = 0, @@ -218,10 +232,13 @@ enum { PINMUX_MARK_END, }; -/* Pin numbers for pins without a corresponding GPIO port number are computed - * from the row and column numbers with a 1000 offset to avoid collisions with - * GPIO port numbers. */ -#define PIN_NUMBER(row, col) (1000+((row)-1)*23+(col)-1) +/* + * Pins not associated with a GPIO port. + */ +enum { + PORT_ASSIGN_LAST(), + NOGP_ALL(), +}; /* Expand to a list of sh_pfc_pin entries (named PORT#). * NOTE: No config are recorded since the driver do not handle pinconf. */ @@ -230,20 +247,7 @@ enum { static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_EMEV_GPIO_ALL(), - - /* Pins not associated with a GPIO port */ - SH_PFC_PIN_NAMED(2, 14, B14), - SH_PFC_PIN_NAMED(2, 15, B15), - SH_PFC_PIN_NAMED(2, 16, B16), - SH_PFC_PIN_NAMED(2, 17, B17), - SH_PFC_PIN_NAMED(3, 14, C14), - SH_PFC_PIN_NAMED(3, 15, C15), - SH_PFC_PIN_NAMED(3, 16, C16), - SH_PFC_PIN_NAMED(3, 17, C17), - SH_PFC_PIN_NAMED(4, 14, D14), - SH_PFC_PIN_NAMED(4, 15, D15), - SH_PFC_PIN_NAMED(4, 16, D16), - SH_PFC_PIN_NAMED(4, 17, D17), + PINMUX_NOGP_ALL(), }; /* Expand to a list of name_DATA, name_FN marks */ @@ -829,12 +833,10 @@ static const unsigned int lcd3_rgb888_pins[] = { /* R[0:7], G[0:7], B[0:7] */ 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17), - PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16), - PIN_NUMBER(4, 16), - 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15), - PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14), - PIN_NUMBER(4, 14) + 40, 41, PIN_LCD3_G2, PIN_LCD3_G3, + PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7, + 42, 43, PIN_LCD3_B2, PIN_LCD3_B3, + PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7 }; static const unsigned int lcd3_rgb888_mux[] = { LCD3_R0_MARK, LCD3_R1_MARK, LCD3_R2_MARK, LCD3_R3_MARK, @@ -850,12 +852,10 @@ static const unsigned int yuv3_pins[] = { /* CLK_O, HS, VS, DE */ 18, 21, 22, 23, /* YUV3_D[0:15] */ - 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17), - PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16), - PIN_NUMBER(4, 16), - 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15), - PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14), - PIN_NUMBER(4, 14), + 40, 41, PIN_LCD3_G2, PIN_LCD3_G3, + PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7, + 42, 43, PIN_LCD3_B2, PIN_LCD3_B3, + PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7, }; static const unsigned int yuv3_mux[] = { YUV3_CLK_O_MARK, YUV3_HS_MARK, YUV3_VS_MARK, YUV3_DE_MARK, @@ -972,12 +972,10 @@ static const unsigned int tp33_pins[] = { /* CLK, CTRL */ 38, 39, /* TP33_DATA[0:15] */ - 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17), - PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16), - PIN_NUMBER(4, 16), - 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15), - PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14), - PIN_NUMBER(4, 14), + 40, 41, PIN_LCD3_G2, PIN_LCD3_G3, + PIN_LCD3_G4, PIN_LCD3_G5, PIN_LCD3_G6, PIN_LCD3_G7, + 42, 43, PIN_LCD3_B2, PIN_LCD3_B3, + PIN_LCD3_B4, PIN_LCD3_B5, PIN_LCD3_B6, PIN_LCD3_B7, }; static const unsigned int tp33_mux[] = { TP33_CLK_MARK, TP33_CTRL_MARK, diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c index bf12849defdb..b21f5afe610f 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c @@ -1252,7 +1252,7 @@ static const u16 pinmux_data[] = { #define __O (SH_PFC_PIN_CFG_OUTPUT) #define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT) -#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP) +#define __PUD (SH_PFC_PIN_CFG_PULL_UP_DOWN) #define R8A73A4_PIN_IO_PU_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PUD) #define R8A73A4_PIN_O(pin) SH_PFC_PIN_CFG(pin, __O) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index 696a0f6fc1da..fdf1b0f09f57 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -1515,7 +1515,7 @@ static const u16 pinmux_data[] = { #define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT) #define __PD (SH_PFC_PIN_CFG_PULL_DOWN) #define __PU (SH_PFC_PIN_CFG_PULL_UP) -#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP) +#define __PUD (SH_PFC_PIN_CFG_PULL_UP_DOWN) #define R8A7740_PIN_I_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PD) #define R8A7740_PIN_I_PU(pin) SH_PFC_PIN_CFG(pin, __I | __PU) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c index c05dc1490486..b3b116da1bb0 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c @@ -10,7 +10,7 @@ #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_4(0, fn, sfx), \ PORT_GP_1(0, 4, fn, sfx), \ PORT_GP_CFG_1(0, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c index 49fe52d35f30..24866a5958ae 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c @@ -22,28 +22,17 @@ #define PORT_GP_PUP_1(bank, pin, fn, sfx) \ PORT_GP_CFG_1(bank, pin, fn, sfx, SH_PFC_PIN_CFG_PULL_UP) -#define PORT_GP_PUP_27(bank, fn, sfx) \ - PORT_GP_PUP_1(bank, 0, fn, sfx), PORT_GP_PUP_1(bank, 1, fn, sfx), \ - PORT_GP_PUP_1(bank, 2, fn, sfx), PORT_GP_PUP_1(bank, 3, fn, sfx), \ - PORT_GP_PUP_1(bank, 4, fn, sfx), PORT_GP_PUP_1(bank, 5, fn, sfx), \ - PORT_GP_PUP_1(bank, 6, fn, sfx), PORT_GP_PUP_1(bank, 7, fn, sfx), \ - PORT_GP_PUP_1(bank, 8, fn, sfx), PORT_GP_PUP_1(bank, 9, fn, sfx), \ - PORT_GP_PUP_1(bank, 10, fn, sfx), PORT_GP_PUP_1(bank, 11, fn, sfx), \ - PORT_GP_PUP_1(bank, 12, fn, sfx), PORT_GP_PUP_1(bank, 13, fn, sfx), \ - PORT_GP_PUP_1(bank, 14, fn, sfx), PORT_GP_PUP_1(bank, 15, fn, sfx), \ - PORT_GP_PUP_1(bank, 16, fn, sfx), PORT_GP_PUP_1(bank, 17, fn, sfx), \ - PORT_GP_PUP_1(bank, 18, fn, sfx), PORT_GP_PUP_1(bank, 19, fn, sfx), \ - PORT_GP_PUP_1(bank, 20, fn, sfx), PORT_GP_PUP_1(bank, 21, fn, sfx), \ - PORT_GP_PUP_1(bank, 22, fn, sfx), PORT_GP_PUP_1(bank, 23, fn, sfx), \ - PORT_GP_PUP_1(bank, 24, fn, sfx), PORT_GP_PUP_1(bank, 25, fn, sfx), \ - PORT_GP_PUP_1(bank, 26, fn, sfx) - -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_32(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(2, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_PUP_27(4, fn, sfx) + PORT_GP_CFG_27(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP) + +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP(CLKOUT, "B25", fn), \ + PIN_NOGP(CS0, "A20", fn), \ + PIN_NOGP(CS1_A26, "C20", fn) enum { PINMUX_RESERVED = 0, @@ -1253,19 +1242,17 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP10_24_22, CAN_CLK_C, SEL_CANCLK_C), }; -/* Pin numbers for pins without a corresponding GPIO port number are computed - * from the row and column numbers with a 1000 offset to avoid collisions with - * GPIO port numbers. +/* + * Pins not associated with a GPIO port. */ -#define PIN_NUMBER(row, col) (1000+((row)-1)*25+(col)-1) +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), - - /* Pins not associated with a GPIO port */ - SH_PFC_PIN_NAMED(3, 20, C20), - SH_PFC_PIN_NAMED(1, 20, A20), - SH_PFC_PIN_NAMED(2, 25, B25), + PINMUX_NOGP_ALL(), }; /* - macro */ @@ -1400,7 +1387,7 @@ HSPI_PFC_DAT(hspi1_a, HSPI_CLK1_A, HSPI_CS1_A, HSPI_RX1_A, HSPI_TX1_A); HSPI_PFC_PIN(hspi1_b, RCAR_GP_PIN(0, 27), RCAR_GP_PIN(0, 26), - PIN_NUMBER(1, 20), PIN_NUMBER(2, 25)); + PIN_CS0, PIN_CLKOUT); HSPI_PFC_DAT(hspi1_b, HSPI_CLK1_B, HSPI_CS1_B, HSPI_RX1_B, HSPI_TX1_B); @@ -1426,7 +1413,7 @@ I2C_PFC_PIN(i2c1_b, RCAR_GP_PIN(4, 17), RCAR_GP_PIN(4, 18)); I2C_PFC_MUX(i2c1_b, SDA1_B, SCL1_B); /* - I2C2 ------------------------------------------------------------------ */ -I2C_PFC_PIN(i2c2_a, PIN_NUMBER(3, 20), RCAR_GP_PIN(1, 3)); +I2C_PFC_PIN(i2c2_a, PIN_CS1_A26, RCAR_GP_PIN(1, 3)); I2C_PFC_MUX(i2c2_a, SDA2_A, SCL2_A); I2C_PFC_PIN(i2c2_b, RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 4)); I2C_PFC_MUX(i2c2_b, SDA2_B, SCL2_B); @@ -1516,7 +1503,7 @@ SCIF_PFC_PIN(scif2_data_e, RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 4)); SCIF_PFC_DAT(scif2_data_e, TX2_E, RX2_E); SCIF_PFC_PIN(scif2_clk_a, RCAR_GP_PIN(3, 9)); SCIF_PFC_CLK(scif2_clk_a, SCK2_A); -SCIF_PFC_PIN(scif2_clk_b, PIN_NUMBER(3, 20)); +SCIF_PFC_PIN(scif2_clk_b, PIN_CS1_A26); SCIF_PFC_CLK(scif2_clk_b, SCK2_B); SCIF_PFC_PIN(scif2_clk_c, RCAR_GP_PIN(4, 12)); SCIF_PFC_CLK(scif2_clk_c, SCK2_C); @@ -1631,7 +1618,7 @@ SSI_PFC_PINS(ssi0_data, RCAR_GP_PIN(3, 10)); SSI_PFC_DATA(ssi0_data, SSI_SDATA0); SSI_PFC_PINS(ssi1_a_ctrl, RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 21)); SSI_PFC_CTRL(ssi1_a_ctrl, SSI_SCK1_A, SSI_WS1_A); -SSI_PFC_PINS(ssi1_b_ctrl, PIN_NUMBER(3, 20), RCAR_GP_PIN(1, 3)); +SSI_PFC_PINS(ssi1_b_ctrl, PIN_CS1_A26, RCAR_GP_PIN(1, 3)); SSI_PFC_CTRL(ssi1_b_ctrl, SSI_SCK1_B, SSI_WS1_B); SSI_PFC_PINS(ssi1_data, RCAR_GP_PIN(3, 9)); SSI_PFC_DATA(ssi1_data, SSI_SDATA1); @@ -2921,8 +2908,6 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { { }, }; -#define PIN_NONE U16_MAX - static const struct pinmux_bias_reg pinmux_bias_regs[] = { { PINMUX_BIAS_REG("PUPR0", 0x100, "N/A", 0) { [ 0] = RCAR_GP_PIN(0, 6), /* A0 */ @@ -2969,28 +2954,28 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 7] = RCAR_GP_PIN(1, 10), /* DACK0 */ [ 8] = RCAR_GP_PIN(1, 12), /* IRQ0 */ [ 9] = RCAR_GP_PIN(1, 13), /* IRQ1 */ - [10] = PIN_NONE, - [11] = PIN_NONE, - [12] = PIN_NONE, - [13] = PIN_NONE, - [14] = PIN_NONE, - [15] = PIN_NONE, - [16] = PIN_NONE, - [17] = PIN_NONE, - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_NONE, - [21] = PIN_NONE, - [22] = PIN_NONE, - [23] = PIN_NONE, - [24] = PIN_NONE, - [25] = PIN_NONE, - [26] = PIN_NONE, - [27] = PIN_NONE, - [28] = PIN_NONE, - [29] = PIN_NONE, - [30] = PIN_NONE, - [31] = PIN_NONE, + [10] = SH_PFC_PIN_NONE, + [11] = SH_PFC_PIN_NONE, + [12] = SH_PFC_PIN_NONE, + [13] = SH_PFC_PIN_NONE, + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, } }, { PINMUX_BIAS_REG("PUPR2", 0x108, "N/A", 0) { [ 0] = RCAR_GP_PIN(1, 22), /* DU0_DR0 */ @@ -3112,21 +3097,21 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [14] = RCAR_GP_PIN(4, 20), /* ETH_MAGIC */ [15] = RCAR_GP_PIN(4, 25), /* AVS1 */ [16] = RCAR_GP_PIN(4, 26), /* AVS2 */ - [17] = PIN_NONE, - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_NONE, - [21] = PIN_NONE, - [22] = PIN_NONE, - [23] = PIN_NONE, - [24] = PIN_NONE, - [25] = PIN_NONE, - [26] = PIN_NONE, - [27] = PIN_NONE, - [28] = PIN_NONE, - [29] = PIN_NONE, - [30] = PIN_NONE, - [31] = PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, } }, { /* sentinel */ }, }; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c index 0c121b28ec3f..3e47cdc1411d 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c @@ -11,7 +11,7 @@ #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ PORT_GP_32(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c index c41a6761cf9d..3366ed561cce 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c @@ -20,7 +20,7 @@ * All pins assigned to GPIO bank 3 can be used for SD interfaces in * which case they support both 3.3V and 1.8V signalling. */ -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ PORT_GP_30(1, fn, sfx), \ PORT_GP_30(2, fn, sfx), \ @@ -28,6 +28,12 @@ PORT_GP_32(4, fn, sfx), \ PORT_GP_32(5, fn, sfx) +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP(IIC0_SDA, "AF15", fn), \ + PIN_NOGP(IIC0_SCL, "AG15", fn), \ + PIN_NOGP(IIC3_SDA, "AH15", fn), \ + PIN_NOGP(IIC3_SCL, "AJ15", fn) + enum { PINMUX_RESERVED = 0, @@ -1727,19 +1733,17 @@ static const u16 pinmux_data[] = { PINMUX_DATA(I2C3_SDA_MARK, FN_SEL_IICDVFS_1), }; -/* R8A7790 has 6 banks with 32 GPIOs in each = 192 GPIOs */ -#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) -#define PIN_NUMBER(r, c) (((r) - 'A') * 31 + (c) + 200) -#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) +/* + * Pins not associated with a GPIO port. + */ +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), - - /* Pins not associated with a GPIO port */ - SH_PFC_PIN_NAMED(ROW_GROUP_A('F'), 15, AF15), - SH_PFC_PIN_NAMED(ROW_GROUP_A('G'), 15, AG15), - SH_PFC_PIN_NAMED(ROW_GROUP_A('H'), 15, AH15), - SH_PFC_PIN_NAMED(ROW_GROUP_A('J'), 15, AJ15), + PINMUX_NOGP_ALL(), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -2135,7 +2139,7 @@ static const unsigned int hscif1_ctrl_b_mux[] = { /* - I2C0 ------------------------------------------------------------------- */ static const unsigned int i2c0_pins[] = { /* SCL, SDA */ - PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15), + PIN_IIC0_SCL, PIN_IIC0_SDA, }; static const unsigned int i2c0_mux[] = { I2C0_SCL_MARK, I2C0_SDA_MARK, @@ -2201,7 +2205,7 @@ static const unsigned int i2c2_e_mux[] = { /* - I2C3 ------------------------------------------------------------------- */ static const unsigned int i2c3_pins[] = { /* SCL, SDA */ - PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15), + PIN_IIC3_SCL, PIN_IIC3_SDA, }; static const unsigned int i2c3_mux[] = { I2C3_SCL_MARK, I2C3_SDA_MARK, @@ -2209,7 +2213,7 @@ static const unsigned int i2c3_mux[] = { /* - IIC0 (I2C4) ------------------------------------------------------------ */ static const unsigned int iic0_pins[] = { /* SCL, SDA */ - PIN_A_NUMBER('G', 15), PIN_A_NUMBER('F', 15), + PIN_IIC0_SCL, PIN_IIC0_SDA, }; static const unsigned int iic0_mux[] = { IIC0_SCL_MARK, IIC0_SDA_MARK, @@ -2274,8 +2278,8 @@ static const unsigned int iic2_e_mux[] = { }; /* - IIC3 (I2C7) ------------------------------------------------------------ */ static const unsigned int iic3_pins[] = { -/* SCL, SDA */ - PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15), + /* SCL, SDA */ + PIN_IIC3_SCL, PIN_IIC3_SDA, }; static const unsigned int iic3_mux[] = { IIC3_SCL_MARK, IIC3_SDA_MARK, diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 1292ec8d268f..bc9caf812fc1 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -15,7 +15,7 @@ * Pins 0-23 assigned to GPIO bank 6 can be used for SD interfaces in * which case they support both 3.3V and 1.8V signalling. */ -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ PORT_GP_26(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c index bbace1478613..258f82fb31c0 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c @@ -11,7 +11,7 @@ #include "core.h" #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_29(0, fn, sfx), \ PORT_GP_23(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index 1ff4969d8381..34481b6c4328 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -14,7 +14,7 @@ #include "core.h" #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ PORT_GP_26(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c index f16dfbad3f17..95f9aae3bfba 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c @@ -11,11 +11,9 @@ #include "core.h" #include "sh_pfc.h" -#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \ - SH_PFC_PIN_CFG_PULL_UP | \ - SH_PFC_PIN_CFG_PULL_DOWN) +#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN) -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_28(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ @@ -28,6 +26,53 @@ PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) + +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(CLKOUT, "CLKOUT", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\ + PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN) + /* * F_() : just information * FM() : macro for FN_xxx / xxx_MARK @@ -1447,69 +1492,16 @@ static const u16 pinmux_data[] = { }; /* - * R8A7795 has 8 banks with 32 GPIOs in each => 256 GPIOs. - * Physical layout rows: A - AW, cols: 1 - 39. + * Pins not associated with a GPIO port. */ -#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) -#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300) -#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) -#define PIN_NONE U16_MAX +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), - - /* - * Pins not associated with a GPIO port. - * - * The pin positions are different between different r8a7795 - * packages, all that is needed for the pfc driver is a unique - * number for each pin. To this end use the pin layout from - * R-Car H3SiP to calculate a unique number for each pin. - */ - SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('F', 1, CLKOUT, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 7, DU_DOTCLKIN2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS), + PINMUX_NOGP_ALL(), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -1658,7 +1650,7 @@ static const unsigned int avb_phy_int_mux[] = { }; static const unsigned int avb_mdio_pins[] = { /* AVB_MDC, AVB_MDIO */ - RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9), + RCAR_GP_PIN(2, 9), PIN_AVB_MDIO, }; static const unsigned int avb_mdio_mux[] = { AVB_MDC_MARK, AVB_MDIO_MARK, @@ -1671,11 +1663,11 @@ static const unsigned int avb_mii_pins[] = { * AVB_RD1, AVB_RD2, AVB_RD3, * AVB_TXCREFCLK */ - PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18), - PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17), - PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13), - PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14), - PIN_NUMBER('A', 12), + PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0, + PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3, + PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0, + PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3, + PIN_AVB_TXCREFCLK, }; static const unsigned int avb_mii_mux[] = { @@ -3137,22 +3129,21 @@ static const unsigned int pwm6_b_mux[] = { /* - QSPI0 ------------------------------------------------------------------ */ static const unsigned int qspi0_ctrl_pins[] = { /* QSPI0_SPCLK, QSPI0_SSL */ - PIN_NUMBER('W', 3), PIN_NUMBER('Y', 3), + PIN_QSPI0_SPCLK, PIN_QSPI0_SSL, }; static const unsigned int qspi0_ctrl_mux[] = { QSPI0_SPCLK_MARK, QSPI0_SSL_MARK, }; static const unsigned int qspi0_data2_pins[] = { /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1 */ - PIN_A_NUMBER('C', 5), PIN_A_NUMBER('B', 4), + PIN_QSPI0_MOSI_IO0, PIN_QSPI0_MISO_IO1, }; static const unsigned int qspi0_data2_mux[] = { QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK, }; static const unsigned int qspi0_data4_pins[] = { /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1, QSPI0_IO2, QSPI0_IO3 */ - PIN_A_NUMBER('C', 5), PIN_A_NUMBER('B', 4), - PIN_NUMBER('Y', 6), PIN_A_NUMBER('B', 6), + PIN_QSPI0_MOSI_IO0, PIN_QSPI0_MISO_IO1, PIN_QSPI0_IO2, PIN_QSPI0_IO3, }; static const unsigned int qspi0_data4_mux[] = { QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK, @@ -3161,22 +3152,21 @@ static const unsigned int qspi0_data4_mux[] = { /* - QSPI1 ------------------------------------------------------------------ */ static const unsigned int qspi1_ctrl_pins[] = { /* QSPI1_SPCLK, QSPI1_SSL */ - PIN_NUMBER('V', 3), PIN_NUMBER('V', 5), + PIN_QSPI1_SPCLK, PIN_QSPI1_SSL, }; static const unsigned int qspi1_ctrl_mux[] = { QSPI1_SPCLK_MARK, QSPI1_SSL_MARK, }; static const unsigned int qspi1_data2_pins[] = { /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1 */ - PIN_A_NUMBER('C', 7), PIN_A_NUMBER('E', 5), + PIN_QSPI1_MOSI_IO0, PIN_QSPI1_MISO_IO1, }; static const unsigned int qspi1_data2_mux[] = { QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK, }; static const unsigned int qspi1_data4_pins[] = { /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1, QSPI1_IO2, QSPI1_IO3 */ - PIN_A_NUMBER('C', 7), PIN_A_NUMBER('E', 5), - PIN_A_NUMBER('E', 4), PIN_A_NUMBER('C', 3), + PIN_QSPI1_MOSI_IO0, PIN_QSPI1_MISO_IO1, PIN_QSPI1_IO2, PIN_QSPI1_IO3, }; static const unsigned int qspi1_data4_mux[] = { QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK, @@ -3812,6 +3802,36 @@ static const unsigned int tmu_tclk2_b_mux[] = { TCLK2_B_MARK, }; +/* - TPU ------------------------------------------------------------------- */ +static const unsigned int tpu_to0_pins[] = { + /* TPU0TO0 */ + RCAR_GP_PIN(6, 28), +}; +static const unsigned int tpu_to0_mux[] = { + TPU0TO0_MARK, +}; +static const unsigned int tpu_to1_pins[] = { + /* TPU0TO1 */ + RCAR_GP_PIN(6, 29), +}; +static const unsigned int tpu_to1_mux[] = { + TPU0TO1_MARK, +}; +static const unsigned int tpu_to2_pins[] = { + /* TPU0TO2 */ + RCAR_GP_PIN(6, 30), +}; +static const unsigned int tpu_to2_mux[] = { + TPU0TO2_MARK, +}; +static const unsigned int tpu_to3_pins[] = { + /* TPU0TO3 */ + RCAR_GP_PIN(6, 31), +}; +static const unsigned int tpu_to3_mux[] = { + TPU0TO3_MARK, +}; + /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { /* PWEN, OVC */ @@ -4165,6 +4185,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { 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(tpu_to0), + SH_PFC_PIN_GROUP(tpu_to1), + SH_PFC_PIN_GROUP(tpu_to2), + SH_PFC_PIN_GROUP(tpu_to3), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), SH_PFC_PIN_GROUP(usb2), @@ -4635,6 +4659,13 @@ static const char * const tmu_groups[] = { "tmu_tclk2_b", }; +static const char * const tpu_groups[] = { + "tpu_to0", + "tpu_to1", + "tpu_to2", + "tpu_to3", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -4707,6 +4738,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi3), SH_PFC_FUNCTION(ssi), SH_PFC_FUNCTION(tmu), + SH_PFC_FUNCTION(tpu), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(usb2), @@ -5272,44 +5304,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { static const struct pinmux_drive_reg pinmux_drive_regs[] = { { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) { - { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */ - { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */ - { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */ - { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */ - { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */ - { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */ - { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */ - { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */ + { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */ + { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */ + { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */ + { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */ + { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */ + { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */ + { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) { - { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */ - { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */ - { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */ - { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */ - { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */ - { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */ - { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */ - { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */ + { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */ + { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */ + { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */ + { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */ + { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */ + { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */ + { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */ + { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */ } }, { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) { - { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */ - { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */ - { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */ - { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */ - { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */ - { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */ - { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */ - { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */ + { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */ + { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */ + { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */ + { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */ + { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */ + { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */ + { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */ + { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) { - { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */ - { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */ - { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */ - { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */ - { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */ - { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ - { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ - { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ + { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */ + { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */ + { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */ + { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */ + { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */ + { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ + { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ } }, { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) { { RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */ @@ -5352,7 +5384,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(1, 19), 0, 3 }, /* A19 */ } }, { PINMUX_DRIVE_REG("DRVCTRL8", 0xe6060320) { - { PIN_NUMBER('F', 1), 28, 3 }, /* CLKOUT */ + { PIN_CLKOUT, 28, 3 }, /* CLKOUT */ { RCAR_GP_PIN(1, 20), 24, 3 }, /* CS0 */ { RCAR_GP_PIN(1, 21), 20, 3 }, /* CS1_A26 */ { RCAR_GP_PIN(1, 22), 16, 3 }, /* BS */ @@ -5363,7 +5395,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { } }, { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) { { RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */ - { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */ + { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */ { RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */ { RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */ { RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */ @@ -5382,30 +5414,30 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */ } }, { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) { - { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ - { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ - { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ - { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ - { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ - { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ - { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */ - { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */ + { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ + { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ + { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ + { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ + { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ + { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ + { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */ + { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */ } }, { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) { - { PIN_A_NUMBER('R', 7), 28, 2 }, /* DU_DOTCLKIN2 */ - { PIN_A_NUMBER('R', 8), 24, 2 }, /* DU_DOTCLKIN3 */ - { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST# */ - { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */ + { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */ + { PIN_DU_DOTCLKIN3, 24, 2 }, /* DU_DOTCLKIN3 */ + { PIN_FSCLKST_N, 20, 2 }, /* FSCLKST# */ + { PIN_TMS, 4, 2 }, /* TMS */ } }, { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) { - { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */ - { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */ - { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ - { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ - { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ - { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ - { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ - { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ + { PIN_TDO, 28, 2 }, /* TDO */ + { PIN_ASEBRK, 24, 2 }, /* ASEBRK */ + { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ + { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ } }, { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) { { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ @@ -5474,7 +5506,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */ { RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */ { RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */ - { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */ + { PIN_MLB_REF, 4, 3 }, /* MLB_REF */ { RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */ } }, { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) { @@ -5548,35 +5580,35 @@ static int r8a7795es1_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, static const struct pinmux_bias_reg pinmux_bias_regs[] = { { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) { - [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */ - [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */ - [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */ - [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */ - [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */ - [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */ - [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */ - [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */ - [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */ - [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */ - [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */ - [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */ - [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */ - [13] = PIN_NUMBER('V', 6), /* RPC_WP# */ - [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */ - [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */ - [16] = PIN_NUMBER('B', 19), /* AVB_RXC */ - [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */ - [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */ - [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */ - [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */ - [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */ - [22] = PIN_NUMBER('A', 19), /* AVB_TXC */ - [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */ - [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */ - [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */ - [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */ - [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */ - [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */ + [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */ + [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */ + [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */ + [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */ + [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */ + [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */ + [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */ + [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */ + [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */ + [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */ + [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */ + [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */ + [12] = PIN_RPC_INT_N, /* RPC_INT# */ + [13] = PIN_RPC_WP_N, /* RPC_WP# */ + [14] = PIN_RPC_RESET_N, /* RPC_RESET# */ + [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */ + [16] = PIN_AVB_RXC, /* AVB_RXC */ + [17] = PIN_AVB_RD0, /* AVB_RD0 */ + [18] = PIN_AVB_RD1, /* AVB_RD1 */ + [19] = PIN_AVB_RD2, /* AVB_RD2 */ + [20] = PIN_AVB_RD3, /* AVB_RD3 */ + [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */ + [22] = PIN_AVB_TXC, /* AVB_TXC */ + [23] = PIN_AVB_TD0, /* AVB_TD0 */ + [24] = PIN_AVB_TD1, /* AVB_TD1 */ + [25] = PIN_AVB_TD2, /* AVB_TD2 */ + [26] = PIN_AVB_TD3, /* AVB_TD3 */ + [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */ + [28] = PIN_AVB_MDIO, /* AVB_MDIO */ [29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */ [30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */ [31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */ @@ -5616,7 +5648,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [31] = RCAR_GP_PIN(1, 19), /* A19 */ } }, { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) { - [ 0] = PIN_NUMBER('F', 1), /* CLKOUT */ + [ 0] = PIN_CLKOUT, /* CLKOUT */ [ 1] = RCAR_GP_PIN(1, 20), /* CS0_N */ [ 2] = RCAR_GP_PIN(1, 21), /* CS1_N_A26 */ [ 3] = RCAR_GP_PIN(1, 22), /* BS_N */ @@ -5625,7 +5657,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */ [ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */ [ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */ - [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */ + [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */ [10] = RCAR_GP_PIN(0, 0), /* D0 */ [11] = RCAR_GP_PIN(0, 1), /* D1 */ [12] = RCAR_GP_PIN(0, 2), /* D2 */ @@ -5646,20 +5678,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [27] = RCAR_GP_PIN(7, 1), /* AVS2 */ [28] = RCAR_GP_PIN(7, 2), /* GP7_02 */ [29] = RCAR_GP_PIN(7, 3), /* GP7_03 */ - [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */ - [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */ + [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */ + [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */ } }, { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) { - [ 0] = PIN_A_NUMBER('R', 7), /* DU_DOTCLKIN2 */ - [ 1] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN3 */ - [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST# */ - [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/ - [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */ - [ 5] = PIN_A_NUMBER('T', 27), /* TCK */ - [ 6] = PIN_A_NUMBER('R', 30), /* TMS */ - [ 7] = PIN_A_NUMBER('R', 29), /* TDI */ - [ 8] = PIN_NONE, - [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */ + [ 0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */ + [ 1] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */ + [ 2] = PIN_FSCLKST_N, /* FSCLKST# */ + [ 3] = PIN_EXTALR, /* EXTALR*/ + [ 4] = PIN_TRST_N, /* TRST# */ + [ 5] = PIN_TCK, /* TCK */ + [ 6] = PIN_TMS, /* TMS */ + [ 7] = PIN_TDI, /* TDI */ + [ 8] = SH_PFC_PIN_NONE, + [ 9] = PIN_ASEBRK, /* ASEBRK */ [10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ [11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ [12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ @@ -5724,7 +5756,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */ [ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */ [ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */ - [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */ + [ 6] = PIN_MLB_REF, /* MLB_REF */ [ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */ [ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */ [ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */ @@ -5759,31 +5791,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */ [ 5] = RCAR_GP_PIN(6, 30), /* USB31_PWEN */ [ 6] = RCAR_GP_PIN(6, 31), /* USB31_OVC */ - [ 7] = PIN_NONE, - [ 8] = PIN_NONE, - [ 9] = PIN_NONE, - [10] = PIN_NONE, - [11] = PIN_NONE, - [12] = PIN_NONE, - [13] = PIN_NONE, - [14] = PIN_NONE, - [15] = PIN_NONE, - [16] = PIN_NONE, - [17] = PIN_NONE, - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_NONE, - [21] = PIN_NONE, - [22] = PIN_NONE, - [23] = PIN_NONE, - [24] = PIN_NONE, - [25] = PIN_NONE, - [26] = PIN_NONE, - [27] = PIN_NONE, - [28] = PIN_NONE, - [29] = PIN_NONE, - [30] = PIN_NONE, - [31] = PIN_NONE, + [ 7] = SH_PFC_PIN_NONE, + [ 8] = SH_PFC_PIN_NONE, + [ 9] = SH_PFC_PIN_NONE, + [10] = SH_PFC_PIN_NONE, + [11] = SH_PFC_PIN_NONE, + [12] = SH_PFC_PIN_NONE, + [13] = SH_PFC_PIN_NONE, + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, } }, { /* sentinel */ }, }; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c index 68bcb8980b16..7df010f757b1 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c @@ -12,11 +12,9 @@ #include "core.h" #include "sh_pfc.h" -#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \ - SH_PFC_PIN_CFG_PULL_UP | \ - SH_PFC_PIN_CFG_PULL_DOWN) +#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN) -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ @@ -29,6 +27,52 @@ PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) + +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\ + PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN) + /* * F_() : just information * FM() : macro for FN_xxx / xxx_MARK @@ -1508,68 +1552,16 @@ static const u16 pinmux_data[] = { }; /* - * R8A7795 has 8 banks with 32 GPIOs in each => 256 GPIOs. - * Physical layout rows: A - AW, cols: 1 - 39. + * Pins not associated with a GPIO port. */ -#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) -#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300) -#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) -#define PIN_NONE U16_MAX +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), - - /* - * Pins not associated with a GPIO port. - * - * The pin positions are different between different r8a7795 - * packages, all that is needed for the pfc driver is a unique - * number for each pin. To this end use the pin layout from - * R-Car H3SiP to calculate a unique number for each pin. - */ - SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 7, DU_DOTCLKIN2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS), + PINMUX_NOGP_ALL(), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -1717,7 +1709,7 @@ static const unsigned int avb_phy_int_mux[] = { }; static const unsigned int avb_mdio_pins[] = { /* AVB_MDC, AVB_MDIO */ - RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9), + RCAR_GP_PIN(2, 9), PIN_AVB_MDIO, }; static const unsigned int avb_mdio_mux[] = { AVB_MDC_MARK, AVB_MDIO_MARK, @@ -1730,11 +1722,11 @@ static const unsigned int avb_mii_pins[] = { * AVB_RD1, AVB_RD2, AVB_RD3, * AVB_TXCREFCLK */ - PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18), - PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17), - PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13), - PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14), - PIN_NUMBER('A', 12), + PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0, + PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3, + PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0, + PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3, + PIN_AVB_TXCREFCLK, }; static const unsigned int avb_mii_mux[] = { @@ -3901,6 +3893,36 @@ static const unsigned int tmu_tclk2_b_mux[] = { TCLK2_B_MARK, }; +/* - TPU ------------------------------------------------------------------- */ +static const unsigned int tpu_to0_pins[] = { + /* TPU0TO0 */ + RCAR_GP_PIN(6, 28), +}; +static const unsigned int tpu_to0_mux[] = { + TPU0TO0_MARK, +}; +static const unsigned int tpu_to1_pins[] = { + /* TPU0TO1 */ + RCAR_GP_PIN(6, 29), +}; +static const unsigned int tpu_to1_mux[] = { + TPU0TO1_MARK, +}; +static const unsigned int tpu_to2_pins[] = { + /* TPU0TO2 */ + RCAR_GP_PIN(6, 30), +}; +static const unsigned int tpu_to2_mux[] = { + TPU0TO2_MARK, +}; +static const unsigned int tpu_to3_pins[] = { + /* TPU0TO3 */ + RCAR_GP_PIN(6, 31), +}; +static const unsigned int tpu_to3_mux[] = { + TPU0TO3_MARK, +}; + /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { /* PWEN, OVC */ @@ -4451,6 +4473,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { 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(tpu_to0), + SH_PFC_PIN_GROUP(tpu_to1), + SH_PFC_PIN_GROUP(tpu_to2), + SH_PFC_PIN_GROUP(tpu_to3), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), SH_PFC_PIN_GROUP(usb2), @@ -4946,6 +4972,13 @@ static const char * const tmu_groups[] = { "tmu_tclk2_b", }; +static const char * const tpu_groups[] = { + "tpu_to0", + "tpu_to1", + "tpu_to2", + "tpu_to3", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -5048,6 +5081,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi3), SH_PFC_FUNCTION(ssi), SH_PFC_FUNCTION(tmu), + SH_PFC_FUNCTION(tpu), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(usb2), @@ -5623,44 +5657,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { static const struct pinmux_drive_reg pinmux_drive_regs[] = { { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) { - { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */ - { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */ - { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */ - { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */ - { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */ - { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */ - { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */ - { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */ + { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */ + { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */ + { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */ + { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */ + { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */ + { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */ + { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) { - { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */ - { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */ - { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */ - { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */ - { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */ - { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */ - { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */ - { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */ + { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */ + { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */ + { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */ + { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */ + { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */ + { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */ + { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */ + { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */ } }, { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) { - { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */ - { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */ - { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */ - { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */ - { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */ - { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */ - { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */ - { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */ + { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */ + { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */ + { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */ + { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */ + { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */ + { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */ + { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */ + { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) { - { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */ - { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */ - { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */ - { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */ - { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */ - { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ - { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ - { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ + { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */ + { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */ + { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */ + { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */ + { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */ + { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ + { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ } }, { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) { { RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */ @@ -5714,7 +5748,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { } }, { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) { { RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */ - { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */ + { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */ { RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */ { RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */ { RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */ @@ -5733,30 +5767,30 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */ } }, { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) { - { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ - { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ - { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ - { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ - { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ - { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ - { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */ - { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */ + { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ + { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ + { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ + { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ + { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ + { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ + { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */ + { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */ } }, { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) { - { PIN_A_NUMBER('R', 7), 28, 2 }, /* DU_DOTCLKIN2 */ - { PIN_A_NUMBER('R', 8), 24, 2 }, /* DU_DOTCLKIN3 */ - { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST# */ - { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */ + { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */ + { PIN_DU_DOTCLKIN3, 24, 2 }, /* DU_DOTCLKIN3 */ + { PIN_FSCLKST_N, 20, 2 }, /* FSCLKST# */ + { PIN_TMS, 4, 2 }, /* TMS */ } }, { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) { - { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */ - { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */ - { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ - { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ - { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ - { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ - { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ - { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ + { PIN_TDO, 28, 2 }, /* TDO */ + { PIN_ASEBRK, 24, 2 }, /* ASEBRK */ + { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ + { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ } }, { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) { { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ @@ -5825,7 +5859,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */ { RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */ { RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */ - { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */ + { PIN_MLB_REF, 4, 3 }, /* MLB_REF */ { RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */ } }, { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) { @@ -5898,35 +5932,35 @@ static int r8a7795_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc static const struct pinmux_bias_reg pinmux_bias_regs[] = { { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) { - [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */ - [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */ - [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */ - [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */ - [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */ - [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */ - [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */ - [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */ - [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */ - [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */ - [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */ - [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */ - [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */ - [13] = PIN_NUMBER('V', 6), /* RPC_WP# */ - [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */ - [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */ - [16] = PIN_NUMBER('B', 19), /* AVB_RXC */ - [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */ - [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */ - [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */ - [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */ - [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */ - [22] = PIN_NUMBER('A', 19), /* AVB_TXC */ - [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */ - [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */ - [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */ - [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */ - [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */ - [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */ + [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */ + [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */ + [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */ + [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */ + [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */ + [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */ + [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */ + [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */ + [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */ + [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */ + [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */ + [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */ + [12] = PIN_RPC_INT_N, /* RPC_INT# */ + [13] = PIN_RPC_WP_N, /* RPC_WP# */ + [14] = PIN_RPC_RESET_N, /* RPC_RESET# */ + [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */ + [16] = PIN_AVB_RXC, /* AVB_RXC */ + [17] = PIN_AVB_RD0, /* AVB_RD0 */ + [18] = PIN_AVB_RD1, /* AVB_RD1 */ + [19] = PIN_AVB_RD2, /* AVB_RD2 */ + [20] = PIN_AVB_RD3, /* AVB_RD3 */ + [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */ + [22] = PIN_AVB_TXC, /* AVB_TXC */ + [23] = PIN_AVB_TD0, /* AVB_TD0 */ + [24] = PIN_AVB_TD1, /* AVB_TD1 */ + [25] = PIN_AVB_TD2, /* AVB_TD2 */ + [26] = PIN_AVB_TD3, /* AVB_TD3 */ + [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */ + [28] = PIN_AVB_MDIO, /* AVB_MDIO */ [29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */ [30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */ [31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */ @@ -5975,7 +6009,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */ [ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */ [ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */ - [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */ + [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */ [10] = RCAR_GP_PIN(0, 0), /* D0 */ [11] = RCAR_GP_PIN(0, 1), /* D1 */ [12] = RCAR_GP_PIN(0, 2), /* D2 */ @@ -5996,20 +6030,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [27] = RCAR_GP_PIN(7, 1), /* AVS2 */ [28] = RCAR_GP_PIN(7, 2), /* GP7_02 */ [29] = RCAR_GP_PIN(7, 3), /* GP7_03 */ - [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */ - [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */ + [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */ + [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */ } }, { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) { - [ 0] = PIN_A_NUMBER('R', 7), /* DU_DOTCLKIN2 */ - [ 1] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN3 */ - [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST# */ - [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/ - [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */ - [ 5] = PIN_A_NUMBER('T', 27), /* TCK */ - [ 6] = PIN_A_NUMBER('R', 30), /* TMS */ - [ 7] = PIN_A_NUMBER('R', 29), /* TDI */ - [ 8] = PIN_NONE, - [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */ + [ 0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */ + [ 1] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */ + [ 2] = PIN_FSCLKST_N, /* FSCLKST# */ + [ 3] = PIN_EXTALR, /* EXTALR*/ + [ 4] = PIN_TRST_N, /* TRST# */ + [ 5] = PIN_TCK, /* TCK */ + [ 6] = PIN_TMS, /* TMS */ + [ 7] = PIN_TDI, /* TDI */ + [ 8] = SH_PFC_PIN_NONE, + [ 9] = PIN_ASEBRK, /* ASEBRK */ [10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ [11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ [12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ @@ -6074,7 +6108,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */ [ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */ [ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */ - [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */ + [ 6] = PIN_MLB_REF, /* MLB_REF */ [ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */ [ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */ [ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */ @@ -6109,31 +6143,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */ [ 5] = RCAR_GP_PIN(6, 30), /* USB2_CH3_PWEN */ [ 6] = RCAR_GP_PIN(6, 31), /* USB2_CH3_OVC */ - [ 7] = PIN_NONE, - [ 8] = PIN_NONE, - [ 9] = PIN_NONE, - [10] = PIN_NONE, - [11] = PIN_NONE, - [12] = PIN_NONE, - [13] = PIN_NONE, - [14] = PIN_NONE, - [15] = PIN_NONE, - [16] = PIN_NONE, - [17] = PIN_NONE, - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_NONE, - [21] = PIN_NONE, - [22] = PIN_NONE, - [23] = PIN_NONE, - [24] = PIN_NONE, - [25] = PIN_NONE, - [26] = PIN_NONE, - [27] = PIN_NONE, - [28] = PIN_NONE, - [29] = PIN_NONE, - [30] = PIN_NONE, - [31] = PIN_NONE, + [ 7] = SH_PFC_PIN_NONE, + [ 8] = SH_PFC_PIN_NONE, + [ 9] = SH_PFC_PIN_NONE, + [10] = SH_PFC_PIN_NONE, + [11] = SH_PFC_PIN_NONE, + [12] = SH_PFC_PIN_NONE, + [13] = SH_PFC_PIN_NONE, + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, } }, { /* sentinel */ }, }; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c index 38cce690db70..61db7c7a35ec 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c @@ -17,11 +17,9 @@ #include "core.h" #include "sh_pfc.h" -#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \ - SH_PFC_PIN_CFG_PULL_UP | \ - SH_PFC_PIN_CFG_PULL_DOWN) +#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN) -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ @@ -34,6 +32,51 @@ PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) + +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\ + PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN) + /* * F_() : just information * FM() : macro for FN_xxx / xxx_MARK @@ -1512,67 +1555,16 @@ static const u16 pinmux_data[] = { }; /* - * R8A7796 has 8 banks with 32 GPIOs in each => 256 GPIOs. - * Physical layout rows: A - AW, cols: 1 - 39. + * Pins not associated with a GPIO port. */ -#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) -#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300) -#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) -#define PIN_NONE U16_MAX +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), - - /* - * Pins not associated with a GPIO port. - * - * The pin positions are different between different r8a7796 - * packages, all that is needed for the pfc driver is a unique - * number for each pin. To this end use the pin layout from - * R-Car M3SiP to calculate a unique number for each pin. - */ - SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS), + PINMUX_NOGP_ALL(), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -1721,7 +1713,7 @@ static const unsigned int avb_phy_int_mux[] = { }; static const unsigned int avb_mdio_pins[] = { /* AVB_MDC, AVB_MDIO */ - RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9), + RCAR_GP_PIN(2, 9), PIN_AVB_MDIO, }; static const unsigned int avb_mdio_mux[] = { AVB_MDC_MARK, AVB_MDIO_MARK, @@ -1734,11 +1726,11 @@ static const unsigned int avb_mii_pins[] = { * AVB_RD1, AVB_RD2, AVB_RD3, * AVB_TXCREFCLK */ - PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18), - PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17), - PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13), - PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14), - PIN_NUMBER('A', 12), + PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0, + PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3, + PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0, + PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3, + PIN_AVB_TXCREFCLK, }; static const unsigned int avb_mii_mux[] = { @@ -3891,6 +3883,36 @@ static const unsigned int tmu_tclk2_b_mux[] = { TCLK2_B_MARK, }; +/* - TPU ------------------------------------------------------------------- */ +static const unsigned int tpu_to0_pins[] = { + /* TPU0TO0 */ + RCAR_GP_PIN(6, 28), +}; +static const unsigned int tpu_to0_mux[] = { + TPU0TO0_MARK, +}; +static const unsigned int tpu_to1_pins[] = { + /* TPU0TO1 */ + RCAR_GP_PIN(6, 29), +}; +static const unsigned int tpu_to1_mux[] = { + TPU0TO1_MARK, +}; +static const unsigned int tpu_to2_pins[] = { + /* TPU0TO2 */ + RCAR_GP_PIN(6, 30), +}; +static const unsigned int tpu_to2_mux[] = { + TPU0TO2_MARK, +}; +static const unsigned int tpu_to3_pins[] = { + /* TPU0TO3 */ + RCAR_GP_PIN(6, 31), +}; +static const unsigned int tpu_to3_mux[] = { + TPU0TO3_MARK, +}; + /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { /* PWEN, OVC */ @@ -4110,7 +4132,7 @@ static const unsigned int vin5_clk_mux[] = { }; static const struct { - struct sh_pfc_pin_group common[312]; + struct sh_pfc_pin_group common[316]; struct sh_pfc_pin_group automotive[30]; } pinmux_groups = { .common = { @@ -4397,6 +4419,10 @@ static const struct { 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(tpu_to0), + SH_PFC_PIN_GROUP(tpu_to1), + SH_PFC_PIN_GROUP(tpu_to2), + SH_PFC_PIN_GROUP(tpu_to3), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), SH_PFC_PIN_GROUP(usb30), @@ -4918,6 +4944,13 @@ static const char * const tmu_groups[] = { "tmu_tclk2_b", }; +static const char * const tpu_groups[] = { + "tpu_to0", + "tpu_to1", + "tpu_to2", + "tpu_to3", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -4963,7 +4996,7 @@ static const char * const vin5_groups[] = { }; static const struct { - struct sh_pfc_function common[49]; + struct sh_pfc_function common[50]; struct sh_pfc_function automotive[4]; } pinmux_functions = { .common = { @@ -5011,6 +5044,7 @@ static const struct { SH_PFC_FUNCTION(sdhi3), SH_PFC_FUNCTION(ssi), SH_PFC_FUNCTION(tmu), + SH_PFC_FUNCTION(tpu), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(usb30), @@ -5590,44 +5624,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { static const struct pinmux_drive_reg pinmux_drive_regs[] = { { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) { - { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */ - { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */ - { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */ - { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */ - { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */ - { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */ - { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */ - { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */ + { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */ + { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */ + { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */ + { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */ + { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */ + { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */ + { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) { - { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */ - { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */ - { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */ - { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */ - { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */ - { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */ - { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */ - { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */ + { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */ + { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */ + { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */ + { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */ + { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */ + { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */ + { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */ + { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */ } }, { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) { - { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */ - { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */ - { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */ - { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */ - { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */ - { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */ - { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */ - { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */ + { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */ + { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */ + { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */ + { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */ + { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */ + { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */ + { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */ + { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) { - { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */ - { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */ - { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */ - { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */ - { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */ - { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ - { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ - { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ + { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */ + { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */ + { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */ + { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */ + { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */ + { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ + { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ } }, { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) { { RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */ @@ -5681,7 +5715,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { } }, { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) { { RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */ - { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */ + { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */ { RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */ { RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */ { RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */ @@ -5700,29 +5734,29 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */ } }, { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) { - { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ - { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ - { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ - { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ - { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ - { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ - { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */ - { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */ + { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ + { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ + { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ + { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ + { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ + { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ + { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */ + { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */ } }, { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) { - { PIN_A_NUMBER('R', 8), 28, 2 }, /* DU_DOTCLKIN2 */ - { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST */ - { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */ + { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */ + { PIN_FSCLKST, 20, 2 }, /* FSCLKST */ + { PIN_TMS, 4, 2 }, /* TMS */ } }, { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) { - { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */ - { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */ - { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ - { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ - { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ - { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ - { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ - { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ + { PIN_TDO, 28, 2 }, /* TDO */ + { PIN_ASEBRK, 24, 2 }, /* ASEBRK */ + { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ + { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ } }, { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) { { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ @@ -5791,7 +5825,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */ { RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */ { RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */ - { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */ + { PIN_MLB_REF, 4, 3 }, /* MLB_REF */ { RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */ } }, { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) { @@ -5864,35 +5898,35 @@ static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc static const struct pinmux_bias_reg pinmux_bias_regs[] = { { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) { - [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */ - [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */ - [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */ - [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */ - [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */ - [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */ - [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */ - [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */ - [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */ - [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */ - [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */ - [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */ - [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */ - [13] = PIN_NUMBER('V', 6), /* RPC_WP# */ - [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */ - [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */ - [16] = PIN_NUMBER('B', 19), /* AVB_RXC */ - [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */ - [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */ - [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */ - [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */ - [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */ - [22] = PIN_NUMBER('A', 19), /* AVB_TXC */ - [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */ - [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */ - [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */ - [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */ - [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */ - [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */ + [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */ + [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */ + [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */ + [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */ + [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */ + [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */ + [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */ + [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */ + [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */ + [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */ + [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */ + [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */ + [12] = PIN_RPC_INT_N, /* RPC_INT# */ + [13] = PIN_RPC_WP_N, /* RPC_WP# */ + [14] = PIN_RPC_RESET_N, /* RPC_RESET# */ + [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */ + [16] = PIN_AVB_RXC, /* AVB_RXC */ + [17] = PIN_AVB_RD0, /* AVB_RD0 */ + [18] = PIN_AVB_RD1, /* AVB_RD1 */ + [19] = PIN_AVB_RD2, /* AVB_RD2 */ + [20] = PIN_AVB_RD3, /* AVB_RD3 */ + [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */ + [22] = PIN_AVB_TXC, /* AVB_TXC */ + [23] = PIN_AVB_TD0, /* AVB_TD0 */ + [24] = PIN_AVB_TD1, /* AVB_TD1 */ + [25] = PIN_AVB_TD2, /* AVB_TD2 */ + [26] = PIN_AVB_TD3, /* AVB_TD3 */ + [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */ + [28] = PIN_AVB_MDIO, /* AVB_MDIO */ [29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */ [30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */ [31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */ @@ -5941,7 +5975,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */ [ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */ [ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */ - [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */ + [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */ [10] = RCAR_GP_PIN(0, 0), /* D0 */ [11] = RCAR_GP_PIN(0, 1), /* D1 */ [12] = RCAR_GP_PIN(0, 2), /* D2 */ @@ -5962,20 +5996,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [27] = RCAR_GP_PIN(7, 1), /* AVS2 */ [28] = RCAR_GP_PIN(7, 2), /* GP7_02 */ [29] = RCAR_GP_PIN(7, 3), /* GP7_03 */ - [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */ - [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */ + [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */ + [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */ } }, { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) { - [ 0] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN2 */ - [ 1] = PIN_NONE, - [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST */ - [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/ - [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */ - [ 5] = PIN_A_NUMBER('T', 27), /* TCK */ - [ 6] = PIN_A_NUMBER('R', 30), /* TMS */ - [ 7] = PIN_A_NUMBER('R', 29), /* TDI */ - [ 8] = PIN_NONE, - [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */ + [ 0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */ + [ 1] = SH_PFC_PIN_NONE, + [ 2] = PIN_FSCLKST, /* FSCLKST */ + [ 3] = PIN_EXTALR, /* EXTALR*/ + [ 4] = PIN_TRST_N, /* TRST# */ + [ 5] = PIN_TCK, /* TCK */ + [ 6] = PIN_TMS, /* TMS */ + [ 7] = PIN_TDI, /* TDI */ + [ 8] = SH_PFC_PIN_NONE, + [ 9] = PIN_ASEBRK, /* ASEBRK */ [10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ [11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ [12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ @@ -6040,7 +6074,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */ [ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */ [ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */ - [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */ + [ 6] = PIN_MLB_REF, /* MLB_REF */ [ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */ [ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */ [ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */ @@ -6075,31 +6109,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */ [ 5] = RCAR_GP_PIN(6, 30), /* GP6_30 */ [ 6] = RCAR_GP_PIN(6, 31), /* GP6_31 */ - [ 7] = PIN_NONE, - [ 8] = PIN_NONE, - [ 9] = PIN_NONE, - [10] = PIN_NONE, - [11] = PIN_NONE, - [12] = PIN_NONE, - [13] = PIN_NONE, - [14] = PIN_NONE, - [15] = PIN_NONE, - [16] = PIN_NONE, - [17] = PIN_NONE, - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_NONE, - [21] = PIN_NONE, - [22] = PIN_NONE, - [23] = PIN_NONE, - [24] = PIN_NONE, - [25] = PIN_NONE, - [26] = PIN_NONE, - [27] = PIN_NONE, - [28] = PIN_NONE, - [29] = PIN_NONE, - [30] = PIN_NONE, - [31] = PIN_NONE, + [ 7] = SH_PFC_PIN_NONE, + [ 8] = SH_PFC_PIN_NONE, + [ 9] = SH_PFC_PIN_NONE, + [10] = SH_PFC_PIN_NONE, + [11] = SH_PFC_PIN_NONE, + [12] = SH_PFC_PIN_NONE, + [13] = SH_PFC_PIN_NONE, + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, } }, { /* sentinel */ }, }; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c index 090024355eba..697c77a4ea95 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c @@ -18,11 +18,9 @@ #include "core.h" #include "sh_pfc.h" -#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \ - SH_PFC_PIN_CFG_PULL_UP | \ - SH_PFC_PIN_CFG_PULL_DOWN) +#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN) -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ @@ -35,6 +33,51 @@ PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) + +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\ + PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN) + /* * F_() : just information * FM() : macro for FN_xxx / xxx_MARK @@ -1517,67 +1560,16 @@ static const u16 pinmux_data[] = { }; /* - * R8A77965 has 8 banks with 32 GPIOs in each => 256 GPIOs. - * Physical layout rows: A - AW, cols: 1 - 39. + * Pins not associated with a GPIO port. */ -#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) -#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300) -#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) -#define PIN_NONE U16_MAX +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), - - /* - * Pins not associated with a GPIO port. - * - * The pin positions are different between different r8a77965 - * packages, all that is needed for the pfc driver is a unique - * number for each pin. To this end use the pin layout from - * R-Car M3SiP to calculate a unique number for each pin. - */ - SH_PFC_PIN_NAMED_CFG('A', 8, AVB_TX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 9, AVB_MDIO, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('C', 1, PRESETOUT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 3, QSPI1_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 5, QSPI1_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 6, RPC_WP#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('V', 7, RPC_RESET#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('W', 3, QSPI0_SPCLK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 3, QSPI0_SSL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 6, QSPI0_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('Y', 7, RPC_INT#, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 4, QSPI0_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'), 6, QSPI0_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 3, QSPI1_IO3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 5, QSPI0_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'), 7, QSPI1_MOSI_IO0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 4, QSPI1_IO2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'), 5, QSPI1_MISO_IO1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 7, DU_DOTCLKIN0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'), 8, DU_DOTCLKIN1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 8, DU_DOTCLKIN3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS), + PINMUX_NOGP_ALL(), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -1726,7 +1718,7 @@ static const unsigned int avb_phy_int_mux[] = { }; static const unsigned int avb_mdio_pins[] = { /* AVB_MDC, AVB_MDIO */ - RCAR_GP_PIN(2, 9), PIN_NUMBER('A', 9), + RCAR_GP_PIN(2, 9), PIN_AVB_MDIO, }; static const unsigned int avb_mdio_mux[] = { AVB_MDC_MARK, AVB_MDIO_MARK, @@ -1739,11 +1731,11 @@ static const unsigned int avb_mii_pins[] = { * AVB_RD1, AVB_RD2, AVB_RD3, * AVB_TXCREFCLK */ - PIN_NUMBER('A', 8), PIN_NUMBER('A', 19), PIN_NUMBER('A', 18), - PIN_NUMBER('B', 18), PIN_NUMBER('A', 17), PIN_NUMBER('B', 17), - PIN_NUMBER('A', 16), PIN_NUMBER('B', 19), PIN_NUMBER('A', 13), - PIN_NUMBER('B', 13), PIN_NUMBER('A', 14), PIN_NUMBER('B', 14), - PIN_NUMBER('A', 12), + PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0, + PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3, + PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0, + PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3, + PIN_AVB_TXCREFCLK, }; static const unsigned int avb_mii_mux[] = { @@ -4116,6 +4108,36 @@ static const unsigned int tmu_tclk2_b_mux[] = { TCLK2_B_MARK, }; +/* - TPU ------------------------------------------------------------------- */ +static const unsigned int tpu_to0_pins[] = { + /* TPU0TO0 */ + RCAR_GP_PIN(6, 28), +}; +static const unsigned int tpu_to0_mux[] = { + TPU0TO0_MARK, +}; +static const unsigned int tpu_to1_pins[] = { + /* TPU0TO1 */ + RCAR_GP_PIN(6, 29), +}; +static const unsigned int tpu_to1_mux[] = { + TPU0TO1_MARK, +}; +static const unsigned int tpu_to2_pins[] = { + /* TPU0TO2 */ + RCAR_GP_PIN(6, 30), +}; +static const unsigned int tpu_to2_mux[] = { + TPU0TO2_MARK, +}; +static const unsigned int tpu_to3_pins[] = { + /* TPU0TO3 */ + RCAR_GP_PIN(6, 31), +}; +static const unsigned int tpu_to3_mux[] = { + TPU0TO3_MARK, +}; + /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { /* PWEN, OVC */ @@ -4672,6 +4694,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { 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(tpu_to0), + SH_PFC_PIN_GROUP(tpu_to1), + SH_PFC_PIN_GROUP(tpu_to2), + SH_PFC_PIN_GROUP(tpu_to3), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb1), SH_PFC_PIN_GROUP(usb30), @@ -5164,6 +5190,13 @@ static const char * const tmu_groups[] = { "tmu_tclk2_b", }; +static const char * const tpu_groups[] = { + "tpu_to0", + "tpu_to1", + "tpu_to2", + "tpu_to3", +}; + static const char * const usb0_groups[] = { "usb0", }; @@ -5258,6 +5291,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi3), SH_PFC_FUNCTION(ssi), SH_PFC_FUNCTION(tmu), + SH_PFC_FUNCTION(tpu), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(usb30), @@ -5830,44 +5864,44 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { static const struct pinmux_drive_reg pinmux_drive_regs[] = { { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) { - { PIN_NUMBER('W', 3), 28, 2 }, /* QSPI0_SPCLK */ - { PIN_A_NUMBER('C', 5), 24, 2 }, /* QSPI0_MOSI_IO0 */ - { PIN_A_NUMBER('B', 4), 20, 2 }, /* QSPI0_MISO_IO1 */ - { PIN_NUMBER('Y', 6), 16, 2 }, /* QSPI0_IO2 */ - { PIN_A_NUMBER('B', 6), 12, 2 }, /* QSPI0_IO3 */ - { PIN_NUMBER('Y', 3), 8, 2 }, /* QSPI0_SSL */ - { PIN_NUMBER('V', 3), 4, 2 }, /* QSPI1_SPCLK */ - { PIN_A_NUMBER('C', 7), 0, 2 }, /* QSPI1_MOSI_IO0 */ + { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */ + { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */ + { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */ + { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */ + { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */ + { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */ + { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) { - { PIN_A_NUMBER('E', 5), 28, 2 }, /* QSPI1_MISO_IO1 */ - { PIN_A_NUMBER('E', 4), 24, 2 }, /* QSPI1_IO2 */ - { PIN_A_NUMBER('C', 3), 20, 2 }, /* QSPI1_IO3 */ - { PIN_NUMBER('V', 5), 16, 2 }, /* QSPI1_SSL */ - { PIN_NUMBER('Y', 7), 12, 2 }, /* RPC_INT# */ - { PIN_NUMBER('V', 6), 8, 2 }, /* RPC_WP# */ - { PIN_NUMBER('V', 7), 4, 2 }, /* RPC_RESET# */ - { PIN_NUMBER('A', 16), 0, 3 }, /* AVB_RX_CTL */ + { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */ + { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */ + { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */ + { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */ + { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */ + { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */ + { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */ + { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */ } }, { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) { - { PIN_NUMBER('B', 19), 28, 3 }, /* AVB_RXC */ - { PIN_NUMBER('A', 13), 24, 3 }, /* AVB_RD0 */ - { PIN_NUMBER('B', 13), 20, 3 }, /* AVB_RD1 */ - { PIN_NUMBER('A', 14), 16, 3 }, /* AVB_RD2 */ - { PIN_NUMBER('B', 14), 12, 3 }, /* AVB_RD3 */ - { PIN_NUMBER('A', 8), 8, 3 }, /* AVB_TX_CTL */ - { PIN_NUMBER('A', 19), 4, 3 }, /* AVB_TXC */ - { PIN_NUMBER('A', 18), 0, 3 }, /* AVB_TD0 */ + { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */ + { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */ + { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */ + { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */ + { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */ + { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */ + { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */ + { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */ } }, { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) { - { PIN_NUMBER('B', 18), 28, 3 }, /* AVB_TD1 */ - { PIN_NUMBER('A', 17), 24, 3 }, /* AVB_TD2 */ - { PIN_NUMBER('B', 17), 20, 3 }, /* AVB_TD3 */ - { PIN_NUMBER('A', 12), 16, 3 }, /* AVB_TXCREFCLK */ - { PIN_NUMBER('A', 9), 12, 3 }, /* AVB_MDIO */ - { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ - { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ - { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ + { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */ + { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */ + { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */ + { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */ + { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */ + { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ + { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ } }, { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) { { RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */ @@ -5921,7 +5955,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { } }, { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) { { RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */ - { PIN_NUMBER('C', 1), 24, 3 }, /* PRESETOUT# */ + { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */ { RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */ { RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */ { RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */ @@ -5940,29 +5974,29 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */ } }, { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) { - { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ - { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ - { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ - { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ - { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ - { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ - { PIN_A_NUMBER('P', 7), 4, 2 }, /* DU_DOTCLKIN0 */ - { PIN_A_NUMBER('P', 8), 0, 2 }, /* DU_DOTCLKIN1 */ + { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ + { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ + { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ + { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ + { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ + { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ + { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */ + { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */ } }, { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) { - { PIN_A_NUMBER('R', 8), 28, 2 }, /* DU_DOTCLKIN3 */ - { PIN_A_NUMBER('D', 38), 20, 2 }, /* FSCLKST */ - { PIN_A_NUMBER('R', 30), 4, 2 }, /* TMS */ + { PIN_DU_DOTCLKIN3, 28, 2 }, /* DU_DOTCLKIN3 */ + { PIN_FSCLKST, 20, 2 }, /* FSCLKST */ + { PIN_TMS, 4, 2 }, /* TMS */ } }, { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) { - { PIN_A_NUMBER('T', 28), 28, 2 }, /* TDO */ - { PIN_A_NUMBER('T', 30), 24, 2 }, /* ASEBRK */ - { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ - { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ - { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ - { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ - { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ - { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ + { PIN_TDO, 28, 2 }, /* TDO */ + { PIN_ASEBRK, 24, 2 }, /* ASEBRK */ + { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ + { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ } }, { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) { { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ @@ -6031,7 +6065,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */ { RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */ { RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */ - { PIN_NUMBER('H', 37), 4, 3 }, /* MLB_REF */ + { PIN_MLB_REF, 4, 3 }, /* MLB_REF */ { RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */ } }, { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) { @@ -6104,35 +6138,35 @@ static int r8a77965_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *po static const struct pinmux_bias_reg pinmux_bias_regs[] = { { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) { - [ 0] = PIN_NUMBER('W', 3), /* QSPI0_SPCLK */ - [ 1] = PIN_A_NUMBER('C', 5), /* QSPI0_MOSI_IO0 */ - [ 2] = PIN_A_NUMBER('B', 4), /* QSPI0_MISO_IO1 */ - [ 3] = PIN_NUMBER('Y', 6), /* QSPI0_IO2 */ - [ 4] = PIN_A_NUMBER('B', 6), /* QSPI0_IO3 */ - [ 5] = PIN_NUMBER('Y', 3), /* QSPI0_SSL */ - [ 6] = PIN_NUMBER('V', 3), /* QSPI1_SPCLK */ - [ 7] = PIN_A_NUMBER('C', 7), /* QSPI1_MOSI_IO0 */ - [ 8] = PIN_A_NUMBER('E', 5), /* QSPI1_MISO_IO1 */ - [ 9] = PIN_A_NUMBER('E', 4), /* QSPI1_IO2 */ - [10] = PIN_A_NUMBER('C', 3), /* QSPI1_IO3 */ - [11] = PIN_NUMBER('V', 5), /* QSPI1_SSL */ - [12] = PIN_NUMBER('Y', 7), /* RPC_INT# */ - [13] = PIN_NUMBER('V', 6), /* RPC_WP# */ - [14] = PIN_NUMBER('V', 7), /* RPC_RESET# */ - [15] = PIN_NUMBER('A', 16), /* AVB_RX_CTL */ - [16] = PIN_NUMBER('B', 19), /* AVB_RXC */ - [17] = PIN_NUMBER('A', 13), /* AVB_RD0 */ - [18] = PIN_NUMBER('B', 13), /* AVB_RD1 */ - [19] = PIN_NUMBER('A', 14), /* AVB_RD2 */ - [20] = PIN_NUMBER('B', 14), /* AVB_RD3 */ - [21] = PIN_NUMBER('A', 8), /* AVB_TX_CTL */ - [22] = PIN_NUMBER('A', 19), /* AVB_TXC */ - [23] = PIN_NUMBER('A', 18), /* AVB_TD0 */ - [24] = PIN_NUMBER('B', 18), /* AVB_TD1 */ - [25] = PIN_NUMBER('A', 17), /* AVB_TD2 */ - [26] = PIN_NUMBER('B', 17), /* AVB_TD3 */ - [27] = PIN_NUMBER('A', 12), /* AVB_TXCREFCLK */ - [28] = PIN_NUMBER('A', 9), /* AVB_MDIO */ + [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */ + [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */ + [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */ + [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */ + [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */ + [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */ + [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */ + [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */ + [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */ + [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */ + [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */ + [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */ + [12] = PIN_RPC_INT_N, /* RPC_INT# */ + [13] = PIN_RPC_WP_N, /* RPC_WP# */ + [14] = PIN_RPC_RESET_N, /* RPC_RESET# */ + [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */ + [16] = PIN_AVB_RXC, /* AVB_RXC */ + [17] = PIN_AVB_RD0, /* AVB_RD0 */ + [18] = PIN_AVB_RD1, /* AVB_RD1 */ + [19] = PIN_AVB_RD2, /* AVB_RD2 */ + [20] = PIN_AVB_RD3, /* AVB_RD3 */ + [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */ + [22] = PIN_AVB_TXC, /* AVB_TXC */ + [23] = PIN_AVB_TD0, /* AVB_TD0 */ + [24] = PIN_AVB_TD1, /* AVB_TD1 */ + [25] = PIN_AVB_TD2, /* AVB_TD2 */ + [26] = PIN_AVB_TD3, /* AVB_TD3 */ + [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */ + [28] = PIN_AVB_MDIO, /* AVB_MDIO */ [29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */ [30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */ [31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */ @@ -6181,7 +6215,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */ [ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */ [ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */ - [ 9] = PIN_NUMBER('C', 1), /* PRESETOUT# */ + [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */ [10] = RCAR_GP_PIN(0, 0), /* D0 */ [11] = RCAR_GP_PIN(0, 1), /* D1 */ [12] = RCAR_GP_PIN(0, 2), /* D2 */ @@ -6202,20 +6236,20 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [27] = RCAR_GP_PIN(7, 1), /* AVS2 */ [28] = RCAR_GP_PIN(7, 2), /* GP7_02 */ [29] = RCAR_GP_PIN(7, 3), /* GP7_03 */ - [30] = PIN_A_NUMBER('P', 7), /* DU_DOTCLKIN0 */ - [31] = PIN_A_NUMBER('P', 8), /* DU_DOTCLKIN1 */ + [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */ + [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */ } }, { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) { - [ 0] = PIN_A_NUMBER('R', 8), /* DU_DOTCLKIN3 */ - [ 1] = PIN_NONE, - [ 2] = PIN_A_NUMBER('D', 38), /* FSCLKST */ - [ 3] = PIN_A_NUMBER('D', 39), /* EXTALR*/ - [ 4] = PIN_A_NUMBER('R', 26), /* TRST# */ - [ 5] = PIN_A_NUMBER('T', 27), /* TCK */ - [ 6] = PIN_A_NUMBER('R', 30), /* TMS */ - [ 7] = PIN_A_NUMBER('R', 29), /* TDI */ - [ 8] = PIN_NONE, - [ 9] = PIN_A_NUMBER('T', 30), /* ASEBRK */ + [ 0] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */ + [ 1] = SH_PFC_PIN_NONE, + [ 2] = PIN_FSCLKST, /* FSCLKST */ + [ 3] = PIN_EXTALR, /* EXTALR*/ + [ 4] = PIN_TRST_N, /* TRST# */ + [ 5] = PIN_TCK, /* TCK */ + [ 6] = PIN_TMS, /* TMS */ + [ 7] = PIN_TDI, /* TDI */ + [ 8] = SH_PFC_PIN_NONE, + [ 9] = PIN_ASEBRK, /* ASEBRK */ [10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ [11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ [12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ @@ -6280,7 +6314,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */ [ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */ [ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */ - [ 6] = PIN_NUMBER('H', 37), /* MLB_REF */ + [ 6] = PIN_MLB_REF, /* MLB_REF */ [ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */ [ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */ [ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */ @@ -6315,31 +6349,31 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */ [ 5] = RCAR_GP_PIN(6, 30), /* GP6_30 */ [ 6] = RCAR_GP_PIN(6, 31), /* GP6_31 */ - [ 7] = PIN_NONE, - [ 8] = PIN_NONE, - [ 9] = PIN_NONE, - [10] = PIN_NONE, - [11] = PIN_NONE, - [12] = PIN_NONE, - [13] = PIN_NONE, - [14] = PIN_NONE, - [15] = PIN_NONE, - [16] = PIN_NONE, - [17] = PIN_NONE, - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_NONE, - [21] = PIN_NONE, - [22] = PIN_NONE, - [23] = PIN_NONE, - [24] = PIN_NONE, - [25] = PIN_NONE, - [26] = PIN_NONE, - [27] = PIN_NONE, - [28] = PIN_NONE, - [29] = PIN_NONE, - [30] = PIN_NONE, - [31] = PIN_NONE, + [ 7] = SH_PFC_PIN_NONE, + [ 8] = SH_PFC_PIN_NONE, + [ 9] = SH_PFC_PIN_NONE, + [10] = SH_PFC_PIN_NONE, + [11] = SH_PFC_PIN_NONE, + [12] = SH_PFC_PIN_NONE, + [13] = SH_PFC_PIN_NONE, + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, } }, { /* sentinel */ }, }; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c index 2d76b548b942..25e27b6bee89 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c @@ -19,7 +19,7 @@ #include "core.h" #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ PORT_GP_28(1, fn, sfx), \ PORT_GP_CFG_17(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ @@ -205,8 +205,8 @@ #define IP6_19_16 FM(VI1_DATA8) F_(0, 0) FM(CTS4_N) FM(D11) FM(MMC_D5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP6_23_20 FM(VI1_DATA9) F_(0, 0) FM(RTS4_N) FM(D12) FM(MMC_D6) FM(SCL3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP6_27_24 FM(VI1_DATA10) F_(0, 0) F_(0, 0) FM(D13) FM(MMC_D7) FM(SDA3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP6_31_28 FM(VI1_DATA11) FM(SCL4) FM(IRQ4) FM(D14) FM(MMC_WP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP7_3_0 FM(VI1_FIELD) FM(SDA4) FM(IRQ5) FM(D15) FM(MMC_CD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP6_31_28 FM(VI1_DATA11) FM(SCL4) FM(IRQ4) FM(D14) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP7_3_0 FM(VI1_FIELD) FM(SDA4) FM(IRQ5) FM(D15) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP7_7_4 FM(SCL0) FM(DU_DR0) FM(TPU0TO0) FM(CLKOUT) F_(0, 0) FM(MSIOF0_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP7_11_8 FM(SDA0) FM(DU_DR1) FM(TPU0TO1) FM(BS_N) FM(SCK0) FM(MSIOF0_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP7_15_12 FM(SCL1) FM(DU_DG0) FM(TPU0TO2) FM(RD_N) FM(CTS0_N) FM(MSIOF0_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -631,14 +631,12 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP6_31_28, SCL4), PINMUX_IPSR_GPSR(IP6_31_28, IRQ4), PINMUX_IPSR_GPSR(IP6_31_28, D14), - PINMUX_IPSR_GPSR(IP6_31_28, MMC_WP), /* IPSR7 */ PINMUX_IPSR_GPSR(IP7_3_0, VI1_FIELD), PINMUX_IPSR_GPSR(IP7_3_0, SDA4), PINMUX_IPSR_GPSR(IP7_3_0, IRQ5), PINMUX_IPSR_GPSR(IP7_3_0, D15), - PINMUX_IPSR_GPSR(IP7_3_0, MMC_CD), PINMUX_IPSR_GPSR(IP7_7_4, SCL0), PINMUX_IPSR_GPSR(IP7_7_4, DU_DR0), @@ -1121,20 +1119,6 @@ static const unsigned int mmc_ctrl_pins[] = { static const unsigned int mmc_ctrl_mux[] = { MMC_CLK_MARK, MMC_CMD_MARK, }; -static const unsigned int mmc_cd_pins[] = { - /* CD */ - RCAR_GP_PIN(3, 16), -}; -static const unsigned int mmc_cd_mux[] = { - MMC_CD_MARK, -}; -static const unsigned int mmc_wp_pins[] = { - /* WP */ - RCAR_GP_PIN(3, 15), -}; -static const unsigned int mmc_wp_mux[] = { - MMC_WP_MARK, -}; /* - MSIOF0 ----------------------------------------------------------------- */ static const unsigned int msiof0_clk_pins[] = { @@ -1726,8 +1710,6 @@ 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(mmc_cd), - SH_PFC_PIN_GROUP(mmc_wp), SH_PFC_PIN_GROUP(msiof0_clk), SH_PFC_PIN_GROUP(msiof0_sync), SH_PFC_PIN_GROUP(msiof0_ss1), @@ -1897,8 +1879,6 @@ static const char * const mmc_groups[] = { "mmc_data4", "mmc_data8", "mmc_ctrl", - "mmc_cd", - "mmc_wp", }; static const char * const msiof0_groups[] = { diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77980.c b/drivers/pinctrl/sh-pfc/pfc-r8a77980.c index 9ed4ead2dafb..14fe4032a52d 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77980.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77980.c @@ -19,7 +19,7 @@ #include "core.h" #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ PORT_GP_28(1, fn, sfx), \ PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c index 91a837b02a36..2dfb8d9cfda1 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c @@ -17,10 +17,9 @@ #include "core.h" #include "sh_pfc.h" -#define CFG_FLAGS (SH_PFC_PIN_CFG_PULL_UP | \ - SH_PFC_PIN_CFG_PULL_DOWN) +#define CFG_FLAGS (SH_PFC_PIN_CFG_PULL_UP_DOWN) -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_18(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_23(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_26(2, fn, sfx, CFG_FLAGS), \ @@ -41,6 +40,25 @@ PORT_GP_CFG_1(6, 15, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_1(6, 16, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_1(6, 17, fn, sfx, CFG_FLAGS) + +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_MDC, "AVB_MDC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(FSCLKST_N, "FSCLKST_N", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT_N", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TCK, "TCK", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TDI, "TDI", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \ + PIN_NOGP_CFG(TRST_N, "TRST_N", fn, CFG_FLAGS) + /* * F_() : just information * FM() : macro for FN_xxx / xxx_MARK @@ -1277,41 +1295,16 @@ static const u16 pinmux_data[] = { }; /* - * R8A77990 has 7 banks with 32 GPIOs in each => 224 GPIOs. - * Physical layout rows: A - AE, cols: 1 - 25. + * Pins not associated with a GPIO port. */ -#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) -#define PIN_NUMBER(r, c) (((r) - 'A') * 25 + (c) + 300) -#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) -#define PIN_NONE U16_MAX +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), - - /* - * Pins not associated with a GPIO port. - * - * The pin positions are different between different R8A77990 - * packages, all that is needed for the pfc driver is a unique - * number for each pin. To this end use the pin layout from - * R8A77990 to calculate a unique number for each pin. - */ - SH_PFC_PIN_NAMED_CFG('F', 1, TRST_N, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('F', 3, TMS, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('F', 4, TCK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('G', 2, TDI, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('G', 3, FSCLKST_N, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('H', 1, ASEBRK, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('N', 1, AVB_TXC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('N', 2, AVB_TD0, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('N', 3, AVB_TD1, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('N', 5, AVB_TD2, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('N', 6, AVB_TD3, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('P', 3, AVB_TX_CTL, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('P', 4, AVB_MDIO, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('P', 5, AVB_MDC, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG('T', 21, MLB_REF, CFG_FLAGS), - SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 3, PRESETOUT_N, CFG_FLAGS), + PINMUX_NOGP_ALL(), }; /* - AUDIO CLOCK ------------------------------------------------------------ */ @@ -5026,15 +5019,15 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [0] = RCAR_GP_PIN(2, 23), /* RD# */ [1] = RCAR_GP_PIN(2, 22), /* BS# */ [2] = RCAR_GP_PIN(2, 21), /* AVB_PHY_INT */ - [3] = PIN_NUMBER('P', 5), /* AVB_MDC */ - [4] = PIN_NUMBER('P', 4), /* AVB_MDIO */ + [3] = PIN_AVB_MDC, /* AVB_MDC */ + [4] = PIN_AVB_MDIO, /* AVB_MDIO */ [5] = RCAR_GP_PIN(2, 20), /* AVB_TXCREFCLK */ - [6] = PIN_NUMBER('N', 6), /* AVB_TD3 */ - [7] = PIN_NUMBER('N', 5), /* AVB_TD2 */ - [8] = PIN_NUMBER('N', 3), /* AVB_TD1 */ - [9] = PIN_NUMBER('N', 2), /* AVB_TD0 */ - [10] = PIN_NUMBER('N', 1), /* AVB_TXC */ - [11] = PIN_NUMBER('P', 3), /* AVB_TX_CTL */ + [6] = PIN_AVB_TD3, /* AVB_TD3 */ + [7] = PIN_AVB_TD2, /* AVB_TD2 */ + [8] = PIN_AVB_TD1, /* AVB_TD1 */ + [9] = PIN_AVB_TD0, /* AVB_TD0 */ + [10] = PIN_AVB_TXC, /* AVB_TXC */ + [11] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */ [12] = RCAR_GP_PIN(2, 19), /* AVB_RD3 */ [13] = RCAR_GP_PIN(2, 18), /* AVB_RD2 */ [14] = RCAR_GP_PIN(2, 17), /* AVB_RD1 */ @@ -5085,33 +5078,33 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [25] = RCAR_GP_PIN(1, 2), /* A2 */ [26] = RCAR_GP_PIN(1, 1), /* A1 */ [27] = RCAR_GP_PIN(1, 0), /* A0 */ - [28] = PIN_NONE, - [29] = PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, [30] = RCAR_GP_PIN(2, 25), /* PUEN_EX_WAIT0 */ [31] = RCAR_GP_PIN(2, 24), /* PUEN_RD/WR# */ } }, { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) { [0] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ [1] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ - [2] = PIN_NUMBER('H', 1), /* ASEBRK */ - [3] = PIN_NONE, - [4] = PIN_NUMBER('G', 2), /* TDI */ - [5] = PIN_NUMBER('F', 3), /* TMS */ - [6] = PIN_NUMBER('F', 4), /* TCK */ - [7] = PIN_NUMBER('F', 1), /* TRST# */ - [8] = PIN_NONE, - [9] = PIN_NONE, - [10] = PIN_NONE, - [11] = PIN_NONE, - [12] = PIN_NONE, - [13] = PIN_NONE, - [14] = PIN_NONE, - [15] = PIN_NUMBER('G', 3), /* FSCLKST# */ + [2] = PIN_ASEBRK, /* ASEBRK */ + [3] = SH_PFC_PIN_NONE, + [4] = PIN_TDI, /* TDI */ + [5] = PIN_TMS, /* TMS */ + [6] = PIN_TCK, /* TCK */ + [7] = PIN_TRST_N, /* TRST# */ + [8] = SH_PFC_PIN_NONE, + [9] = SH_PFC_PIN_NONE, + [10] = SH_PFC_PIN_NONE, + [11] = SH_PFC_PIN_NONE, + [12] = SH_PFC_PIN_NONE, + [13] = SH_PFC_PIN_NONE, + [14] = SH_PFC_PIN_NONE, + [15] = PIN_FSCLKST_N, /* FSCLKST# */ [16] = RCAR_GP_PIN(0, 17), /* SDA4 */ [17] = RCAR_GP_PIN(0, 16), /* SCL4 */ - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_A_NUMBER('D', 3), /* PRESETOUT# */ + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = PIN_PRESETOUT_N, /* PRESETOUT# */ [21] = RCAR_GP_PIN(0, 15), /* D15 */ [22] = RCAR_GP_PIN(0, 14), /* D14 */ [23] = RCAR_GP_PIN(0, 13), /* D13 */ @@ -5130,8 +5123,8 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [2] = RCAR_GP_PIN(5, 3), /* CTS0#_A */ [3] = RCAR_GP_PIN(5, 2), /* TX0_A */ [4] = RCAR_GP_PIN(5, 1), /* RX0_A */ - [5] = PIN_NONE, - [6] = PIN_NONE, + [5] = SH_PFC_PIN_NONE, + [6] = SH_PFC_PIN_NONE, [7] = RCAR_GP_PIN(3, 15), /* SD1_WP */ [8] = RCAR_GP_PIN(3, 14), /* SD1_CD */ [9] = RCAR_GP_PIN(3, 13), /* SD0_WP */ @@ -5175,7 +5168,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [13] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */ [14] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */ [15] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */ - [16] = PIN_NUMBER('T', 21), /* MLB_REF */ + [16] = PIN_MLB_REF, /* MLB_REF */ [17] = RCAR_GP_PIN(5, 19), /* MLB_DAT */ [18] = RCAR_GP_PIN(5, 18), /* MLB_SIG */ [19] = RCAR_GP_PIN(5, 17), /* MLB_CLK */ @@ -5193,36 +5186,36 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [31] = RCAR_GP_PIN(5, 5), /* RX1 */ } }, { PINMUX_BIAS_REG("PUEN5", 0xe6060414, "PUD5", 0xe6060454) { - [0] = PIN_NONE, - [1] = PIN_NONE, - [2] = PIN_NONE, - [3] = PIN_NONE, - [4] = PIN_NONE, - [5] = PIN_NONE, - [6] = PIN_NONE, - [7] = PIN_NONE, - [8] = PIN_NONE, - [9] = PIN_NONE, - [10] = PIN_NONE, - [11] = PIN_NONE, - [12] = PIN_NONE, - [13] = PIN_NONE, - [14] = PIN_NONE, - [15] = PIN_NONE, - [16] = PIN_NONE, - [17] = PIN_NONE, - [18] = PIN_NONE, - [19] = PIN_NONE, - [20] = PIN_NONE, - [21] = PIN_NONE, - [22] = PIN_NONE, - [23] = PIN_NONE, - [24] = PIN_NONE, - [25] = PIN_NONE, - [26] = PIN_NONE, - [27] = PIN_NONE, - [28] = PIN_NONE, - [29] = PIN_NONE, + [0] = SH_PFC_PIN_NONE, + [1] = SH_PFC_PIN_NONE, + [2] = SH_PFC_PIN_NONE, + [3] = SH_PFC_PIN_NONE, + [4] = SH_PFC_PIN_NONE, + [5] = SH_PFC_PIN_NONE, + [6] = SH_PFC_PIN_NONE, + [7] = SH_PFC_PIN_NONE, + [8] = SH_PFC_PIN_NONE, + [9] = SH_PFC_PIN_NONE, + [10] = SH_PFC_PIN_NONE, + [11] = SH_PFC_PIN_NONE, + [12] = SH_PFC_PIN_NONE, + [13] = SH_PFC_PIN_NONE, + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, [30] = RCAR_GP_PIN(6, 9), /* PUEN_USB30_OVC */ [31] = RCAR_GP_PIN(6, 17), /* PUEN_USB30_PWEN */ } }, diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c index dd87085d48cb..c10b756476b1 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c @@ -17,7 +17,7 @@ #include "core.h" #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_9(0, fn, sfx), \ PORT_GP_32(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index e1276d143117..afabd95105d5 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -43,6 +43,9 @@ PORT_1(288, fn, pfx##288, sfx), PORT_1(289, fn, pfx##289, sfx), \ PORT_10(290, fn, pfx##29, sfx), PORT_10(300, fn, pfx##30, sfx) +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP(A11, "F26", fn) + enum { PINMUX_RESERVED = 0, @@ -1147,7 +1150,7 @@ static const u16 pinmux_data[] = { #define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT) #define __PD (SH_PFC_PIN_CFG_PULL_DOWN) #define __PU (SH_PFC_PIN_CFG_PULL_UP) -#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP) +#define __PUD (SH_PFC_PIN_CFG_PULL_UP_DOWN) #define SH73A0_PIN_I_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PD) #define SH73A0_PIN_I_PU(pin) SH_PFC_PIN_CFG(pin, __I | __PU) @@ -1158,11 +1161,13 @@ static const u16 pinmux_data[] = { #define SH73A0_PIN_IO_PU_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PUD) #define SH73A0_PIN_O(pin) SH_PFC_PIN_CFG(pin, __O) -/* Pin numbers for pins without a corresponding GPIO port number are computed - * from the row and column numbers with a 1000 offset to avoid collisions with - * GPIO port numbers. +/* + * Pins not associated with a GPIO port. */ -#define PIN_NUMBER(row, col) (1000+((row)-1)*34+(col)-1) +enum { + PORT_ASSIGN_LAST(), + NOGP_ALL(), +}; static const struct sh_pfc_pin pinmux_pins[] = { /* Table 25-1 (I/O and Pull U/D) */ @@ -1437,7 +1442,7 @@ static const struct sh_pfc_pin pinmux_pins[] = { SH73A0_PIN_O(309), /* Pins not associated with a GPIO port */ - SH_PFC_PIN_NAMED(6, 26, F26), + PINMUX_NOGP_ALL(), }; /* - BSC -------------------------------------------------------------------- */ @@ -1863,7 +1868,7 @@ static const unsigned int keysc_out7_2_mux[] = { }; static const unsigned int keysc_out8_0_pins[] = { /* KEYOUT8 */ - PIN_NUMBER(6, 26), + PIN_A11, }; static const unsigned int keysc_out8_0_mux[] = { KEYOUT8_MARK, @@ -3073,7 +3078,7 @@ static const unsigned int tpu4_to2_mux[] = { }; static const unsigned int tpu4_to3_pins[] = { /* TO */ - PIN_NUMBER(6, 26), + PIN_A11, }; static const unsigned int tpu4_to3_mux[] = { TPU4TO3_MARK, diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c index fac7b4699121..5dfd991ffdaa 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c @@ -11,7 +11,7 @@ #include "sh_pfc.h" -#define CPU_ALL_PORT(fn, sfx) \ +#define CPU_ALL_GP(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ PORT_GP_32(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index c97d2ba7677c..2824be4eb887 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -569,8 +569,7 @@ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin, switch (param) { case PIN_CONFIG_BIAS_DISABLE: - return pin->configs & - (SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN); + return pin->configs & SH_PFC_PIN_CFG_PULL_UP_DOWN; case PIN_CONFIG_BIAS_PULL_UP: return pin->configs & SH_PFC_PIN_CFG_PULL_UP; diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h index 7db5819eea7e..835148fc0f28 100644 --- a/drivers/pinctrl/sh-pfc/sh_pfc.h +++ b/drivers/pinctrl/sh-pfc/sh_pfc.h @@ -21,10 +21,14 @@ enum { PINMUX_TYPE_INPUT, }; +#define SH_PFC_PIN_NONE U16_MAX + #define SH_PFC_PIN_CFG_INPUT (1 << 0) #define SH_PFC_PIN_CFG_OUTPUT (1 << 1) #define SH_PFC_PIN_CFG_PULL_UP (1 << 2) #define SH_PFC_PIN_CFG_PULL_DOWN (1 << 3) +#define SH_PFC_PIN_CFG_PULL_UP_DOWN (SH_PFC_PIN_CFG_PULL_UP | \ + SH_PFC_PIN_CFG_PULL_DOWN) #define SH_PFC_PIN_CFG_IO_VOLTAGE (1 << 4) #define SH_PFC_PIN_CFG_DRIVE_STRENGTH (1 << 5) #define SH_PFC_PIN_CFG_NO_GPIO (1 << 31) @@ -542,9 +546,13 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; PORT_GP_CFG_1(bank, 25, fn, sfx, cfg) #define PORT_GP_26(bank, fn, sfx) PORT_GP_CFG_26(bank, fn, sfx, 0) -#define PORT_GP_CFG_28(bank, fn, sfx, cfg) \ +#define PORT_GP_CFG_27(bank, fn, sfx, cfg) \ PORT_GP_CFG_26(bank, fn, sfx, cfg), \ - PORT_GP_CFG_1(bank, 26, fn, sfx, cfg), \ + PORT_GP_CFG_1(bank, 26, fn, sfx, cfg) +#define PORT_GP_27(bank, fn, sfx) PORT_GP_CFG_27(bank, fn, sfx, 0) + +#define PORT_GP_CFG_28(bank, fn, sfx, cfg) \ + PORT_GP_CFG_27(bank, fn, sfx, cfg), \ PORT_GP_CFG_1(bank, 27, fn, sfx, cfg) #define PORT_GP_28(bank, fn, sfx) PORT_GP_CFG_28(bank, fn, sfx, 0) @@ -584,7 +592,7 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; /* GP_ALL(suffix) - Expand to a list of GP_#_#_suffix */ #define _GP_ALL(bank, pin, name, sfx, cfg) name##_##sfx -#define GP_ALL(str) CPU_ALL_PORT(_GP_ALL, str) +#define GP_ALL(str) CPU_ALL_GP(_GP_ALL, str) /* PINMUX_GPIO_GP_ALL - Expand to a list of sh_pfc_pin entries */ #define _GP_GPIO(bank, _pin, _name, sfx, cfg) \ @@ -594,11 +602,29 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; .enum_id = _name##_DATA, \ .configs = cfg, \ } -#define PINMUX_GPIO_GP_ALL() CPU_ALL_PORT(_GP_GPIO, unused) +#define PINMUX_GPIO_GP_ALL() CPU_ALL_GP(_GP_GPIO, unused) /* PINMUX_DATA_GP_ALL - Expand to a list of name_DATA, name_FN marks */ #define _GP_DATA(bank, pin, name, sfx, cfg) PINMUX_DATA(name##_DATA, name##_FN) -#define PINMUX_DATA_GP_ALL() CPU_ALL_PORT(_GP_DATA, unused) +#define PINMUX_DATA_GP_ALL() CPU_ALL_GP(_GP_DATA, unused) + +/* + * GP_ASSIGN_LAST() - Expand to an enum definition for the last GP pin + * + * The largest GP pin index is obtained by taking the size of a union, + * containing one array per GP pin, sized by the corresponding pin index. + * As the fields in the CPU_ALL_GP() macro definition are separated by commas, + * while the members of a union must be terminated by semicolons, the commas + * are absorbed by wrapping them inside dummy attributes. + */ +#define _GP_ENTRY(bank, pin, name, sfx, cfg) \ + deprecated)); char name[(bank * 32) + pin] __attribute__((deprecated +#define GP_ASSIGN_LAST() \ + GP_LAST = sizeof(union { \ + char dummy[0] __attribute__((deprecated, \ + CPU_ALL_GP(_GP_ENTRY, unused), \ + deprecated)); \ + }) /* * PORT style (linear pin space) @@ -641,22 +667,6 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; .configs = cfgs, \ } -/* SH_PFC_PIN_NAMED - Expand to a sh_pfc_pin entry with the given name */ -#define SH_PFC_PIN_NAMED(row, col, _name) \ - { \ - .pin = PIN_NUMBER(row, col), \ - .name = __stringify(PIN_##_name), \ - .configs = SH_PFC_PIN_CFG_NO_GPIO, \ - } - -/* SH_PFC_PIN_NAMED_CFG - Expand to a sh_pfc_pin entry with the given name */ -#define SH_PFC_PIN_NAMED_CFG(row, col, _name, cfgs) \ - { \ - .pin = PIN_NUMBER(row, col), \ - .name = __stringify(PIN_##_name), \ - .configs = SH_PFC_PIN_CFG_NO_GPIO | cfgs, \ - } - /* PINMUX_DATA_ALL - Expand to a list of PORT_name_DATA, PORT_name_FN0, * PORT_name_OUT, PORT_name_IN marks */ @@ -665,6 +675,24 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; PORT##pfx##_OUT, PORT##pfx##_IN) #define PINMUX_DATA_ALL() CPU_ALL_PORT(_PORT_DATA, , unused) +/* + * PORT_ASSIGN_LAST() - Expand to an enum definition for the last PORT pin + * + * The largest PORT pin index is obtained by taking the size of a union, + * containing one array per PORT pin, sized by the corresponding pin index. + * As the fields in the CPU_ALL_PORT() macro definition are separated by + * commas, while the members of a union must be terminated by semicolons, the + * commas are absorbed by wrapping them inside dummy attributes. + */ +#define _PORT_ENTRY(pn, pfx, sfx) \ + deprecated)); char pfx[pn] __attribute__((deprecated +#define PORT_ASSIGN_LAST() \ + PORT_LAST = sizeof(union { \ + char dummy[0] __attribute__((deprecated, \ + CPU_ALL_PORT(_PORT_ENTRY, PORT, unused), \ + deprecated)); \ + }) + /* GPIO_FN(name) - Expand to a sh_pfc_pin entry for a function GPIO */ #define PINMUX_GPIO_FN(gpio, base, data_or_mark) \ [gpio - (base)] = { \ @@ -675,6 +703,26 @@ extern const struct sh_pfc_soc_info shx3_pinmux_info; PINMUX_GPIO_FN(GPIO_FN_##str, PINMUX_FN_BASE, str##_MARK) /* + * Pins not associated with a GPIO port + */ + +#define PIN_NOGP_CFG(pin, name, fn, cfg) fn(pin, name, cfg) +#define PIN_NOGP(pin, name, fn) fn(pin, name, 0) + +/* NOGP_ALL - Expand to a list of PIN_id */ +#define _NOGP_ALL(pin, name, cfg) PIN_##pin +#define NOGP_ALL() CPU_ALL_NOGP(_NOGP_ALL) + +/* PINMUX_NOGP_ALL - Expand to a list of sh_pfc_pin entries */ +#define _NOGP_PINMUX(_pin, _name, cfg) \ + { \ + .pin = PIN_##_pin, \ + .name = "PIN_" _name, \ + .configs = SH_PFC_PIN_CFG_NO_GPIO | cfg, \ + } +#define PINMUX_NOGP_ALL() CPU_ALL_NOGP(_NOGP_PINMUX) + +/* * PORTnCR helper macro for SH-Mobile/R-Mobile */ #define PORTCR(nr, reg) \ diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 2317ccf63321..b453aed1bbeb 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -44,6 +44,18 @@ #define STM32_GPIO_AFRL 0x20 #define STM32_GPIO_AFRH 0x24 +/* custom bitfield to backup pin status */ +#define STM32_GPIO_BKP_MODE_SHIFT 0 +#define STM32_GPIO_BKP_MODE_MASK GENMASK(1, 0) +#define STM32_GPIO_BKP_ALT_SHIFT 2 +#define STM32_GPIO_BKP_ALT_MASK GENMASK(5, 2) +#define STM32_GPIO_BKP_SPEED_SHIFT 6 +#define STM32_GPIO_BKP_SPEED_MASK GENMASK(7, 6) +#define STM32_GPIO_BKP_PUPD_SHIFT 8 +#define STM32_GPIO_BKP_PUPD_MASK GENMASK(9, 8) +#define STM32_GPIO_BKP_TYPE 10 +#define STM32_GPIO_BKP_VAL 11 + #define STM32_GPIO_PINS_PER_BANK 16 #define STM32_GPIO_IRQ_LINE 16 @@ -79,6 +91,7 @@ struct stm32_gpio_bank { struct irq_domain *domain; u32 bank_nr; u32 bank_ioport_nr; + u32 pin_backup[STM32_GPIO_PINS_PER_BANK]; }; struct stm32_pinctrl { @@ -98,6 +111,8 @@ struct stm32_pinctrl { struct stm32_desc_pin *pins; u32 npins; u32 pkg; + u16 irqmux_map; + spinlock_t irqmux_lock; }; static inline int stm32_gpio_pin(int gpio) @@ -133,11 +148,50 @@ static inline u32 stm32_gpio_get_alt(u32 function) return 0; } +static void stm32_gpio_backup_value(struct stm32_gpio_bank *bank, + u32 offset, u32 value) +{ + bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_VAL); + bank->pin_backup[offset] |= value << STM32_GPIO_BKP_VAL; +} + +static void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, u32 offset, + u32 mode, u32 alt) +{ + bank->pin_backup[offset] &= ~(STM32_GPIO_BKP_MODE_MASK | + STM32_GPIO_BKP_ALT_MASK); + bank->pin_backup[offset] |= mode << STM32_GPIO_BKP_MODE_SHIFT; + bank->pin_backup[offset] |= alt << STM32_GPIO_BKP_ALT_SHIFT; +} + +static void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, u32 offset, + u32 drive) +{ + bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_TYPE); + bank->pin_backup[offset] |= drive << STM32_GPIO_BKP_TYPE; +} + +static void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, u32 offset, + u32 speed) +{ + bank->pin_backup[offset] &= ~STM32_GPIO_BKP_SPEED_MASK; + bank->pin_backup[offset] |= speed << STM32_GPIO_BKP_SPEED_SHIFT; +} + +static void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, u32 offset, + u32 bias) +{ + bank->pin_backup[offset] &= ~STM32_GPIO_BKP_PUPD_MASK; + bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT; +} + /* GPIO functions */ static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank, unsigned offset, int value) { + stm32_gpio_backup_value(bank, offset, value); + if (!value) offset += STM32_GPIO_PINS_PER_BANK; @@ -307,9 +361,53 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, { struct stm32_gpio_bank *bank = d->host_data; struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); + unsigned long flags; + int ret = 0; + + /* + * gpio irq mux is shared between several banks, a lock has to be done + * to avoid overriding. + */ + spin_lock_irqsave(&pctl->irqmux_lock, flags); + if (pctl->hwlock) + ret = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); + + if (ret) { + dev_err(pctl->dev, "Can't get hwspinlock\n"); + goto unlock; + } + + if (pctl->irqmux_map & BIT(irq_data->hwirq)) { + dev_err(pctl->dev, "irq line %ld already requested.\n", + irq_data->hwirq); + ret = -EBUSY; + if (pctl->hwlock) + hwspin_unlock(pctl->hwlock); + goto unlock; + } else { + pctl->irqmux_map |= BIT(irq_data->hwirq); + } regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr); - return 0; + + if (pctl->hwlock) + hwspin_unlock(pctl->hwlock); + +unlock: + spin_unlock_irqrestore(&pctl->irqmux_lock, flags); + return ret; +} + +static void stm32_gpio_domain_deactivate(struct irq_domain *d, + struct irq_data *irq_data) +{ + struct stm32_gpio_bank *bank = d->host_data; + struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); + unsigned long flags; + + spin_lock_irqsave(&pctl->irqmux_lock, flags); + pctl->irqmux_map &= ~BIT(irq_data->hwirq); + spin_unlock_irqrestore(&pctl->irqmux_lock, flags); } static int stm32_gpio_domain_alloc(struct irq_domain *d, @@ -338,6 +436,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = { .alloc = stm32_gpio_domain_alloc, .free = irq_domain_free_irqs_common, .activate = stm32_gpio_domain_activate, + .deactivate = stm32_gpio_domain_deactivate, }; /* Pinctrl functions */ @@ -620,6 +719,8 @@ static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank, if (pctl->hwlock) hwspin_unlock(pctl->hwlock); + stm32_gpio_backup_mode(bank, pin, mode, alt); + unlock: spin_unlock_irqrestore(&bank->lock, flags); clk_disable(bank->clk); @@ -732,6 +833,8 @@ static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank, if (pctl->hwlock) hwspin_unlock(pctl->hwlock); + stm32_gpio_backup_driving(bank, offset, drive); + unlock: spin_unlock_irqrestore(&bank->lock, flags); clk_disable(bank->clk); @@ -784,6 +887,8 @@ static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank, if (pctl->hwlock) hwspin_unlock(pctl->hwlock); + stm32_gpio_backup_speed(bank, offset, speed); + unlock: spin_unlock_irqrestore(&bank->lock, flags); clk_disable(bank->clk); @@ -836,6 +941,8 @@ static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank, if (pctl->hwlock) hwspin_unlock(pctl->hwlock); + stm32_gpio_backup_bias(bank, offset, bias); + unlock: spin_unlock_irqrestore(&bank->lock, flags); clk_disable(bank->clk); @@ -1290,6 +1397,8 @@ int stm32_pctl_probe(struct platform_device *pdev) pctl->hwlock = hwspin_lock_request_specific(hwlock_id); } + spin_lock_init(&pctl->irqmux_lock); + pctl->dev = dev; pctl->match_data = match->data; @@ -1329,6 +1438,7 @@ int stm32_pctl_probe(struct platform_device *pdev) pctl->pctl_desc.owner = THIS_MODULE; pctl->pctl_desc.pins = pins; pctl->pctl_desc.npins = pctl->npins; + pctl->pctl_desc.link_consumers = true; pctl->pctl_desc.confops = &stm32_pconf_ops; pctl->pctl_desc.pctlops = &stm32_pctrl_ops; pctl->pctl_desc.pmxops = &stm32_pmx_ops; @@ -1369,3 +1479,75 @@ int stm32_pctl_probe(struct platform_device *pdev) return 0; } + +static int __maybe_unused stm32_pinctrl_restore_gpio_regs( + struct stm32_pinctrl *pctl, u32 pin) +{ + const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin); + u32 val, alt, mode, offset = stm32_gpio_pin(pin); + struct pinctrl_gpio_range *range; + struct stm32_gpio_bank *bank; + bool pin_is_irq; + int ret; + + range = pinctrl_find_gpio_range_from_pin(pctl->pctl_dev, pin); + if (!range) + return 0; + + pin_is_irq = gpiochip_line_is_irq(range->gc, offset); + + if (!desc || (!pin_is_irq && !desc->gpio_owner)) + return 0; + + bank = gpiochip_get_data(range->gc); + + alt = bank->pin_backup[offset] & STM32_GPIO_BKP_ALT_MASK; + alt >>= STM32_GPIO_BKP_ALT_SHIFT; + mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK; + mode >>= STM32_GPIO_BKP_MODE_SHIFT; + + ret = stm32_pmx_set_mode(bank, offset, mode, alt); + if (ret) + return ret; + + if (mode == 1) { + val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL); + val = val >> STM32_GPIO_BKP_VAL; + __stm32_gpio_set(bank, offset, val); + } + + val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE); + val >>= STM32_GPIO_BKP_TYPE; + ret = stm32_pconf_set_driving(bank, offset, val); + if (ret) + return ret; + + val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK; + val >>= STM32_GPIO_BKP_SPEED_SHIFT; + ret = stm32_pconf_set_speed(bank, offset, val); + if (ret) + return ret; + + val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK; + val >>= STM32_GPIO_BKP_PUPD_SHIFT; + ret = stm32_pconf_set_bias(bank, offset, val); + if (ret) + return ret; + + if (pin_is_irq) + regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr); + + return 0; +} + +int __maybe_unused stm32_pinctrl_resume(struct device *dev) +{ + struct stm32_pinctrl *pctl = dev_get_drvdata(dev); + struct stm32_pinctrl_group *g = pctl->groups; + int i; + + for (i = g->pin; i < g->pin + pctl->ngroups; i++) + stm32_pinctrl_restore_gpio_regs(pctl, i); + + return 0; +} diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h index de5e7012ca03..ec0d34c33903 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.h +++ b/drivers/pinctrl/stm32/pinctrl-stm32.h @@ -65,5 +65,7 @@ struct stm32_gpio_bank; int stm32_pctl_probe(struct platform_device *pdev); void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, u32 *alt); +int stm32_pinctrl_resume(struct device *dev); + #endif /* __PINCTRL_STM32_H */ diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c index 320544f69e57..2ccb99d64df8 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c @@ -2342,11 +2342,16 @@ static const struct of_device_id stm32mp157_pctrl_match[] = { { } }; +static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume) +}; + static struct platform_driver stm32mp157_pinctrl_driver = { .probe = stm32_pctl_probe, .driver = { .name = "stm32mp157-pinctrl", .of_match_table = stm32mp157_pctrl_match, + .pm = &stm32_pinctrl_dev_pm_ops, }, }; diff --git a/drivers/pinctrl/tegra/Kconfig b/drivers/pinctrl/tegra/Kconfig index 5906a856be38..a67d0d9ae8cd 100644 --- a/drivers/pinctrl/tegra/Kconfig +++ b/drivers/pinctrl/tegra/Kconfig @@ -24,6 +24,10 @@ config PINCTRL_TEGRA210 bool select PINCTRL_TEGRA +config PINCTRL_TEGRA194 + bool + select PINCTRL_TEGRA + config PINCTRL_TEGRA_XUSB def_bool y if ARCH_TEGRA select GENERIC_PHY diff --git a/drivers/pinctrl/tegra/Makefile b/drivers/pinctrl/tegra/Makefile index bbcb043c34a2..ead4e10097d0 100644 --- a/drivers/pinctrl/tegra/Makefile +++ b/drivers/pinctrl/tegra/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o obj-$(CONFIG_PINCTRL_TEGRA124) += pinctrl-tegra124.o obj-$(CONFIG_PINCTRL_TEGRA210) += pinctrl-tegra210.o +obj-$(CONFIG_PINCTRL_TEGRA194) += pinctrl-tegra194.o obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index abcfbad94f00..186ef98e7b2b 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -284,7 +284,7 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, const struct tegra_pingroup *g, enum tegra_pinconf_param param, bool report_err, - s8 *bank, s16 *reg, s8 *bit, s8 *width) + s8 *bank, s32 *reg, s8 *bit, s8 *width) { switch (param) { case TEGRA_PINCONF_PARAM_PULL: @@ -443,7 +443,7 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev, const struct tegra_pingroup *g; int ret; s8 bank, bit, width; - s16 reg; + s32 reg; u32 val, mask; g = &pmx->soc->groups[group]; @@ -472,7 +472,7 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, const struct tegra_pingroup *g; int ret, i; s8 bank, bit, width; - s16 reg; + s32 reg; u32 val, mask; g = &pmx->soc->groups[group]; @@ -540,7 +540,7 @@ static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, const struct tegra_pingroup *g; int i, ret; s8 bank, bit, width; - s16 reg; + s32 reg; u32 val; g = &pmx->soc->groups[group]; @@ -613,10 +613,20 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx) for (i = 0; i < pmx->soc->ngroups; ++i) { g = &pmx->soc->groups[i]; - if (g->parked_bit >= 0) { - val = pmx_readl(pmx, g->mux_bank, g->mux_reg); - val &= ~(1 << g->parked_bit); - pmx_writel(pmx, val, g->mux_bank, g->mux_reg); + if (g->parked_bitmask > 0) { + unsigned int bank, reg; + + if (g->mux_reg != -1) { + bank = g->mux_bank; + reg = g->mux_reg; + } else { + bank = g->drv_bank; + reg = g->drv_reg; + } + + val = pmx_readl(pmx, bank, reg); + val &= ~g->parked_bitmask; + pmx_writel(pmx, val, bank, reg); } } } diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h index 9b5a71624fd0..105309774079 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.h +++ b/drivers/pinctrl/tegra/pinctrl-tegra.h @@ -96,7 +96,6 @@ struct tegra_function { * @tri_reg: Tri-state register offset. * @tri_bank: Tri-state register bank. * @tri_bit: Tri-state register bit. - * @parked_bit: Parked register bit. -1 if unsupported. * @einput_bit: Enable-input register bit. * @odrain_bit: Open-drain register bit. * @lock_bit: Lock register bit. @@ -118,6 +117,7 @@ struct tegra_function { * @slwf_bit: Slew Falling register bit. * @slwf_width: Slew Falling field width. * @drvtype_bit: Drive type register bit. + * @parked_bitmask: Parked register mask. 0 if unsupported. * * -1 in a *_reg field means that feature is unsupported for this group. * *_bank and *_reg values are irrelevant when *_reg is -1. @@ -135,10 +135,10 @@ struct tegra_pingroup { const unsigned *pins; u8 npins; u8 funcs[4]; - s16 mux_reg; - s16 pupd_reg; - s16 tri_reg; - s16 drv_reg; + s32 mux_reg; + s32 pupd_reg; + s32 tri_reg; + s32 drv_reg; u32 mux_bank:2; u32 pupd_bank:2; u32 tri_bank:2; @@ -146,7 +146,6 @@ struct tegra_pingroup { s32 mux_bit:6; s32 pupd_bit:6; s32 tri_bit:6; - s32 parked_bit:6; s32 einput_bit:6; s32 odrain_bit:6; s32 lock_bit:6; @@ -164,6 +163,7 @@ struct tegra_pingroup { s32 drvup_width:6; s32 slwr_width:6; s32 slwf_width:6; + u32 parked_bitmask; }; /** diff --git a/drivers/pinctrl/tegra/pinctrl-tegra114.c b/drivers/pinctrl/tegra/pinctrl-tegra114.c index 762151f17a88..e72ab1eb2398 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra114.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra114.c @@ -1572,8 +1572,8 @@ static struct tegra_function tegra114_functions[] = { .lock_bit = 7, \ .ioreset_bit = PINGROUP_BIT_##ior(8), \ .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9), \ - .parked_bit = -1, \ .drv_reg = -1, \ + .parked_bitmask = 0, \ } #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, \ @@ -1593,7 +1593,6 @@ static struct tegra_function tegra114_functions[] = { .rcv_sel_bit = -1, \ .drv_reg = DRV_PINGROUP_REG(r), \ .drv_bank = 0, \ - .parked_bit = -1, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ .lpmd_bit = lpmd_b, \ @@ -1606,6 +1605,7 @@ static struct tegra_function tegra114_functions[] = { .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ .drvtype_bit = PINGROUP_BIT_##drvtype(6), \ + .parked_bitmask = 0, \ } static const struct tegra_pingroup tegra114_groups[] = { @@ -1831,7 +1831,7 @@ static const struct tegra_pingroup tegra114_groups[] = { static const struct tegra_pinctrl_soc_data tegra114_pinctrl = { .ngpios = NUM_GPIOS, - .gpio_compatible = "nvidia,tegra30-gpio", + .gpio_compatible = "nvidia,tegra114-gpio", .pins = tegra114_pins, .npins = ARRAY_SIZE(tegra114_pins), .functions = tegra114_functions, diff --git a/drivers/pinctrl/tegra/pinctrl-tegra124.c b/drivers/pinctrl/tegra/pinctrl-tegra124.c index 930c43758c92..26096c6b967e 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra124.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra124.c @@ -1741,8 +1741,8 @@ static struct tegra_function tegra124_functions[] = { .lock_bit = 7, \ .ioreset_bit = PINGROUP_BIT_##ior(8), \ .rcv_sel_bit = PINGROUP_BIT_##rcv_sel(9), \ - .parked_bit = -1, \ .drv_reg = -1, \ + .parked_bitmask = 0, \ } #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, \ @@ -1762,7 +1762,6 @@ static struct tegra_function tegra124_functions[] = { .rcv_sel_bit = -1, \ .drv_reg = DRV_PINGROUP_REG(r), \ .drv_bank = 0, \ - .parked_bit = -1, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ .lpmd_bit = lpmd_b, \ @@ -1775,6 +1774,7 @@ static struct tegra_function tegra124_functions[] = { .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ .drvtype_bit = PINGROUP_BIT_##drvtype(6), \ + .parked_bitmask = 0, \ } #define MIPI_PAD_CTRL_PINGROUP(pg_name, r, b, f0, f1) \ @@ -2043,7 +2043,7 @@ static const struct tegra_pingroup tegra124_groups[] = { static const struct tegra_pinctrl_soc_data tegra124_pinctrl = { .ngpios = NUM_GPIOS, - .gpio_compatible = "nvidia,tegra30-gpio", + .gpio_compatible = "nvidia,tegra124-gpio", .pins = tegra124_pins, .npins = ARRAY_SIZE(tegra124_pins), .functions = tegra124_functions, diff --git a/drivers/pinctrl/tegra/pinctrl-tegra194.c b/drivers/pinctrl/tegra/pinctrl-tegra194.c new file mode 100644 index 000000000000..daf44cf240c9 --- /dev/null +++ b/drivers/pinctrl/tegra/pinctrl-tegra194.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl data for the NVIDIA Tegra194 pinmux + * + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * 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/init.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include "pinctrl-tegra.h" + +/* Define unique ID for each pins */ +enum pin_id { + TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0 = 256, + TEGRA_PIN_PEX_L5_RST_N_PGG1 = 257, + TEGRA_PIN_NUM_GPIOS = 258, +}; + +/* Table for pin descriptor */ +static const struct pinctrl_pin_desc tegra194_pins[] = { + PINCTRL_PIN(TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0, + "TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0"), + PINCTRL_PIN(TEGRA_PIN_PEX_L5_RST_N_PGG1, + "TEGRA_PIN_PEX_L5_RST_N_PGG1"), +}; + +static const unsigned int pex_l5_clkreq_n_pgg0_pins[] = { + TEGRA_PIN_PEX_L5_CLKREQ_N_PGG0, +}; + +static const unsigned int pex_l5_rst_n_pgg1_pins[] = { + TEGRA_PIN_PEX_L5_RST_N_PGG1, +}; + +/* Define unique ID for each function */ +enum tegra_mux_dt { + TEGRA_MUX_RSVD0, + TEGRA_MUX_RSVD1, + TEGRA_MUX_RSVD2, + TEGRA_MUX_RSVD3, + TEGRA_MUX_PE5, +}; + +/* Make list of each function name */ +#define TEGRA_PIN_FUNCTION(lid) \ + { \ + .name = #lid, \ + } +static struct tegra_function tegra194_functions[] = { + TEGRA_PIN_FUNCTION(rsvd0), + TEGRA_PIN_FUNCTION(rsvd1), + TEGRA_PIN_FUNCTION(rsvd2), + TEGRA_PIN_FUNCTION(rsvd3), + TEGRA_PIN_FUNCTION(pe5), +}; + +#define DRV_PINGROUP_ENTRY_Y(r, drvdn_b, drvdn_w, drvup_b, \ + drvup_w, slwr_b, slwr_w, slwf_b, \ + slwf_w, bank) \ + .drv_reg = ((r)), \ + .drv_bank = bank, \ + .drvdn_bit = drvdn_b, \ + .drvdn_width = drvdn_w, \ + .drvup_bit = drvup_b, \ + .drvup_width = drvup_w, \ + .slwr_bit = slwr_b, \ + .slwr_width = slwr_w, \ + .slwf_bit = slwf_b, \ + .slwf_width = slwf_w + +#define PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_lpbk, e_input, \ + e_od, schmitt_b, drvtype) \ + .mux_reg = ((r)), \ + .lpmd_bit = -1, \ + .lock_bit = -1, \ + .hsm_bit = -1, \ + .mux_bank = bank, \ + .mux_bit = 0, \ + .pupd_reg = ((r)), \ + .pupd_bank = bank, \ + .pupd_bit = 2, \ + .tri_reg = ((r)), \ + .tri_bank = bank, \ + .tri_bit = 4, \ + .einput_bit = e_input, \ + .odrain_bit = e_od, \ + .schmitt_bit = schmitt_b, \ + .drvtype_bit = 13, \ + .drv_reg = -1, \ + .parked_bitmask = 0 + +#define drive_pex_l5_clkreq_n_pgg0 \ + DRV_PINGROUP_ENTRY_Y(0x14004, 12, 5, 20, 5, -1, -1, -1, -1, 0) +#define drive_pex_l5_rst_n_pgg1 \ + DRV_PINGROUP_ENTRY_Y(0x1400c, 12, 5, 20, 5, -1, -1, -1, -1, 0) + +#define PINGROUP(pg_name, f0, f1, f2, f3, r, bank, pupd, e_lpbk, \ + e_input, e_lpdr, e_od, schmitt_b, drvtype, io_rail) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .funcs = { \ + TEGRA_MUX_##f0, \ + TEGRA_MUX_##f1, \ + TEGRA_MUX_##f2, \ + TEGRA_MUX_##f3, \ + }, \ + PIN_PINGROUP_ENTRY_Y(r, bank, pupd, e_lpbk, \ + e_input, e_od, \ + schmitt_b, drvtype), \ + drive_##pg_name, \ + } + +static const struct tegra_pingroup tegra194_groups[] = { + PINGROUP(pex_l5_clkreq_n_pgg0, PE5, RSVD1, RSVD2, RSVD3, 0x14000, 0, + Y, -1, 6, 8, 11, 12, N, "vddio_pex_ctl_2"), + PINGROUP(pex_l5_rst_n_pgg1, PE5, RSVD1, RSVD2, RSVD3, 0x14008, 0, + Y, -1, 6, 8, 11, 12, N, "vddio_pex_ctl_2"), +}; + +static const struct tegra_pinctrl_soc_data tegra194_pinctrl = { + .ngpios = TEGRA_PIN_NUM_GPIOS, + .pins = tegra194_pins, + .npins = ARRAY_SIZE(tegra194_pins), + .functions = tegra194_functions, + .nfunctions = ARRAY_SIZE(tegra194_functions), + .groups = tegra194_groups, + .ngroups = ARRAY_SIZE(tegra194_groups), + .hsm_in_mux = true, + .schmitt_in_mux = true, + .drvtype_in_mux = true, +}; + +static int tegra194_pinctrl_probe(struct platform_device *pdev) +{ + return tegra_pinctrl_probe(pdev, &tegra194_pinctrl); +} + +static const struct of_device_id tegra194_pinctrl_of_match[] = { + { .compatible = "nvidia,tegra194-pinmux", }, + { }, +}; + +static struct platform_driver tegra194_pinctrl_driver = { + .driver = { + .name = "tegra194-pinctrl", + .of_match_table = tegra194_pinctrl_of_match, + }, + .probe = tegra194_pinctrl_probe, +}; + +static int __init tegra194_pinctrl_init(void) +{ + return platform_driver_register(&tegra194_pinctrl_driver); +} +arch_initcall(tegra194_pinctrl_init); diff --git a/drivers/pinctrl/tegra/pinctrl-tegra20.c b/drivers/pinctrl/tegra/pinctrl-tegra20.c index 4b7837e38fb5..0dc2cf0d05b1 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra20.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra20.c @@ -1989,13 +1989,13 @@ static struct tegra_function tegra20_functions[] = { .tri_reg = ((tri_r) - TRISTATE_REG_A), \ .tri_bank = 0, \ .tri_bit = tri_b, \ - .parked_bit = -1, \ .einput_bit = -1, \ .odrain_bit = -1, \ .lock_bit = -1, \ .ioreset_bit = -1, \ .rcv_sel_bit = -1, \ .drv_reg = -1, \ + .parked_bitmask = 0, \ } /* Pin groups with only pull up and pull down control */ @@ -2009,7 +2009,7 @@ static struct tegra_function tegra20_functions[] = { .pupd_bank = 2, \ .pupd_bit = pupd_b, \ .drv_reg = -1, \ - .parked_bit = -1, \ + .parked_bitmask = 0, \ } /* Pin groups for drive strength registers (configurable version) */ @@ -2025,7 +2025,7 @@ static struct tegra_function tegra20_functions[] = { .tri_reg = -1, \ .drv_reg = ((r) - PINGROUP_REG_A), \ .drv_bank = 3, \ - .parked_bit = -1, \ + .parked_bitmask = 0, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ .lpmd_bit = lpmd_b, \ diff --git a/drivers/pinctrl/tegra/pinctrl-tegra210.c b/drivers/pinctrl/tegra/pinctrl-tegra210.c index 0b56ad5c9c1c..39ab6480a941 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra210.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra210.c @@ -1302,7 +1302,6 @@ static struct tegra_function tegra210_functions[] = { .lock_bit = 7, \ .ioreset_bit = -1, \ .rcv_sel_bit = PINGROUP_BIT_##e_io_hv(10), \ - .parked_bit = 5, \ .hsm_bit = PINGROUP_BIT_##hsm(9), \ .schmitt_bit = 12, \ .drvtype_bit = PINGROUP_BIT_##drvtype(13), \ @@ -1317,10 +1316,11 @@ static struct tegra_function tegra210_functions[] = { .slwr_width = slwr_w, \ .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ + .parked_bitmask = BIT(5), \ } -#define DRV_PINGROUP(pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, \ - slwr_b, slwr_w, slwf_b, slwf_w) \ +#define DRV_PINGROUP(pg_name, r, prk_mask, drvdn_b, drvdn_w, drvup_b, \ + drvup_w, slwr_b, slwr_w, slwf_b, slwf_w) \ { \ .name = "drive_" #pg_name, \ .pins = drive_##pg_name##_pins, \ @@ -1335,7 +1335,6 @@ static struct tegra_function tegra210_functions[] = { .rcv_sel_bit = -1, \ .drv_reg = DRV_PINGROUP_REG(r), \ .drv_bank = 0, \ - .parked_bit = -1, \ .hsm_bit = -1, \ .schmitt_bit = -1, \ .lpmd_bit = -1, \ @@ -1348,6 +1347,7 @@ static struct tegra_function tegra210_functions[] = { .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ .drvtype_bit = -1, \ + .parked_bitmask = prk_mask, \ } static const struct tegra_pingroup tegra210_groups[] = { @@ -1515,37 +1515,37 @@ static const struct tegra_pingroup tegra210_groups[] = { PINGROUP(pz4, SDMMC1, RSVD1, RSVD2, RSVD3, 0x328c, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), PINGROUP(pz5, SOC, RSVD1, RSVD2, RSVD3, 0x3290, N, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1), - /* pg_name, r, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */ - DRV_PINGROUP(pa6, 0x9c0, 12, 5, 20, 5, -1, -1, -1, -1), - DRV_PINGROUP(pcc7, 0x9c4, 12, 5, 20, 5, -1, -1, -1, -1), - DRV_PINGROUP(pe6, 0x9c8, 12, 5, 20, 5, -1, -1, -1, -1), - DRV_PINGROUP(pe7, 0x9cc, 12, 5, 20, 5, -1, -1, -1, -1), - DRV_PINGROUP(ph6, 0x9d0, 12, 5, 20, 5, -1, -1, -1, -1), - DRV_PINGROUP(pk0, 0x9d4, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pk1, 0x9d8, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pk2, 0x9dc, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pk3, 0x9e0, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pk4, 0x9e4, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pk5, 0x9e8, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pk6, 0x9ec, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pk7, 0x9f0, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pl0, 0x9f4, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pl1, 0x9f8, -1, -1, -1, -1, 28, 2, 30, 2), - DRV_PINGROUP(pz0, 0x9fc, 12, 7, 20, 7, -1, -1, -1, -1), - DRV_PINGROUP(pz1, 0xa00, 12, 7, 20, 7, -1, -1, -1, -1), - DRV_PINGROUP(pz2, 0xa04, 12, 7, 20, 7, -1, -1, -1, -1), - DRV_PINGROUP(pz3, 0xa08, 12, 7, 20, 7, -1, -1, -1, -1), - DRV_PINGROUP(pz4, 0xa0c, 12, 7, 20, 7, -1, -1, -1, -1), - DRV_PINGROUP(pz5, 0xa10, 12, 7, 20, 7, -1, -1, -1, -1), - DRV_PINGROUP(sdmmc1, 0xa98, 12, 7, 20, 7, 28, 2, 30, 2), - DRV_PINGROUP(sdmmc2, 0xa9c, 2, 6, 8, 6, 28, 2, 30, 2), - DRV_PINGROUP(sdmmc3, 0xab0, 12, 7, 20, 7, 28, 2, 30, 2), - DRV_PINGROUP(sdmmc4, 0xab4, 2, 6, 8, 6, 28, 2, 30, 2), + /* pg_name, r, prk_mask, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */ + DRV_PINGROUP(pa6, 0x9c0, 0x0, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pcc7, 0x9c4, 0x0, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pe6, 0x9c8, 0x0, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pe7, 0x9cc, 0x0, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(ph6, 0x9d0, 0x0, 12, 5, 20, 5, -1, -1, -1, -1), + DRV_PINGROUP(pk0, 0x9d4, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk1, 0x9d8, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk2, 0x9dc, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk3, 0x9e0, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk4, 0x9e4, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk5, 0x9e8, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk6, 0x9ec, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pk7, 0x9f0, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pl0, 0x9f4, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pl1, 0x9f8, 0x0, -1, -1, -1, -1, 28, 2, 30, 2), + DRV_PINGROUP(pz0, 0x9fc, 0x0, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz1, 0xa00, 0x0, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz2, 0xa04, 0x0, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz3, 0xa08, 0x0, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz4, 0xa0c, 0x0, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(pz5, 0xa10, 0x0, 12, 7, 20, 7, -1, -1, -1, -1), + DRV_PINGROUP(sdmmc1, 0xa98, 0x0, 12, 7, 20, 7, 28, 2, 30, 2), + DRV_PINGROUP(sdmmc2, 0xa9c, 0x7ffc000, 2, 6, 8, 6, 28, 2, 30, 2), + DRV_PINGROUP(sdmmc3, 0xab0, 0x0, 12, 7, 20, 7, 28, 2, 30, 2), + DRV_PINGROUP(sdmmc4, 0xab4, 0x7ffc000, 2, 6, 8, 6, 28, 2, 30, 2), }; static const struct tegra_pinctrl_soc_data tegra210_pinctrl = { .ngpios = NUM_GPIOS, - .gpio_compatible = "nvidia,tegra30-gpio", + .gpio_compatible = "nvidia,tegra210-gpio", .pins = tegra210_pins, .npins = ARRAY_SIZE(tegra210_pins), .functions = tegra210_functions, diff --git a/drivers/pinctrl/tegra/pinctrl-tegra30.c b/drivers/pinctrl/tegra/pinctrl-tegra30.c index 610124c3d192..7299a371827f 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra30.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra30.c @@ -2133,8 +2133,8 @@ static struct tegra_function tegra30_functions[] = { .lock_bit = 7, \ .ioreset_bit = PINGROUP_BIT_##ior(8), \ .rcv_sel_bit = -1, \ - .parked_bit = -1, \ .drv_reg = -1, \ + .parked_bitmask = 0, \ } #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, \ @@ -2154,7 +2154,6 @@ static struct tegra_function tegra30_functions[] = { .rcv_sel_bit = -1, \ .drv_reg = DRV_PINGROUP_REG(r), \ .drv_bank = 0, \ - .parked_bit = -1, \ .hsm_bit = hsm_b, \ .schmitt_bit = schmitt_b, \ .lpmd_bit = lpmd_b, \ @@ -2167,6 +2166,7 @@ static struct tegra_function tegra30_functions[] = { .slwf_bit = slwf_b, \ .slwf_width = slwf_w, \ .drvtype_bit = -1, \ + .parked_bitmask = 0, \ } static const struct tegra_pingroup tegra30_groups[] = { diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index e03304fe25bb..6cca72782af6 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -70,7 +70,6 @@ MODULE_LICENSE("GPL"); * SECTION: prototypes for static functions of dasd.c */ static int dasd_alloc_queue(struct dasd_block *); -static void dasd_setup_queue(struct dasd_block *); static void dasd_free_queue(struct dasd_block *); static int dasd_flush_block_queue(struct dasd_block *); static void dasd_device_tasklet(unsigned long); @@ -120,9 +119,18 @@ struct dasd_device *dasd_alloc_device(void) kfree(device); return ERR_PTR(-ENOMEM); } + /* Get two pages for ese format. */ + device->ese_mem = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, 1); + if (!device->ese_mem) { + free_page((unsigned long) device->erp_mem); + free_pages((unsigned long) device->ccw_mem, 1); + kfree(device); + return ERR_PTR(-ENOMEM); + } dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2); dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE); + dasd_init_chunklist(&device->ese_chunks, device->ese_mem, PAGE_SIZE * 2); spin_lock_init(&device->mem_lock); atomic_set(&device->tasklet_scheduled, 0); tasklet_init(&device->tasklet, dasd_device_tasklet, @@ -146,6 +154,7 @@ struct dasd_device *dasd_alloc_device(void) void dasd_free_device(struct dasd_device *device) { kfree(device->private); + free_pages((unsigned long) device->ese_mem, 1); free_page((unsigned long) device->erp_mem); free_pages((unsigned long) device->ccw_mem, 1); kfree(device); @@ -348,7 +357,8 @@ static int dasd_state_basic_to_ready(struct dasd_device *device) } return rc; } - dasd_setup_queue(block); + if (device->discipline->setup_blk_queue) + device->discipline->setup_blk_queue(block); set_capacity(block->gdp, block->blocks << block->s2b_shift); device->state = DASD_STATE_READY; @@ -1258,6 +1268,49 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, int datasize, } EXPORT_SYMBOL(dasd_smalloc_request); +struct dasd_ccw_req *dasd_fmalloc_request(int magic, int cplength, + int datasize, + struct dasd_device *device) +{ + struct dasd_ccw_req *cqr; + unsigned long flags; + int size, cqr_size; + char *data; + + cqr_size = (sizeof(*cqr) + 7L) & -8L; + size = cqr_size; + if (cplength > 0) + size += cplength * sizeof(struct ccw1); + if (datasize > 0) + size += datasize; + + spin_lock_irqsave(&device->mem_lock, flags); + cqr = dasd_alloc_chunk(&device->ese_chunks, size); + spin_unlock_irqrestore(&device->mem_lock, flags); + if (!cqr) + return ERR_PTR(-ENOMEM); + memset(cqr, 0, sizeof(*cqr)); + data = (char *)cqr + cqr_size; + cqr->cpaddr = NULL; + if (cplength > 0) { + cqr->cpaddr = data; + data += cplength * sizeof(struct ccw1); + memset(cqr->cpaddr, 0, cplength * sizeof(struct ccw1)); + } + cqr->data = NULL; + if (datasize > 0) { + cqr->data = data; + memset(cqr->data, 0, datasize); + } + + cqr->magic = magic; + set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + dasd_get_device(device); + + return cqr; +} +EXPORT_SYMBOL(dasd_fmalloc_request); + void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) { unsigned long flags; @@ -1269,6 +1322,17 @@ void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) } EXPORT_SYMBOL(dasd_sfree_request); +void dasd_ffree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) +{ + unsigned long flags; + + spin_lock_irqsave(&device->mem_lock, flags); + dasd_free_chunk(&device->ese_chunks, cqr); + spin_unlock_irqrestore(&device->mem_lock, flags); + dasd_put_device(device); +} +EXPORT_SYMBOL(dasd_ffree_request); + /* * Check discipline magic in cqr. */ @@ -1573,13 +1637,43 @@ static int dasd_check_hpf_error(struct irb *irb) irb->scsw.tm.sesq == SCSW_SESQ_PATH_NOFCX)); } +static int dasd_ese_needs_format(struct dasd_block *block, struct irb *irb) +{ + struct dasd_device *device = NULL; + u8 *sense = NULL; + + if (!block) + return 0; + device = block->base; + if (!device || !device->discipline->is_ese) + return 0; + if (!device->discipline->is_ese(device)) + return 0; + + sense = dasd_get_sense(irb); + if (!sense) + return 0; + + return !!(sense[1] & SNS1_NO_REC_FOUND) || + !!(sense[1] & SNS1_FILE_PROTECTED) || + scsw_cstat(&irb->scsw) == SCHN_STAT_INCORR_LEN; +} + +static int dasd_ese_oos_cond(u8 *sense) +{ + return sense[0] & SNS0_EQUIPMENT_CHECK && + sense[1] & SNS1_PERM_ERR && + sense[1] & SNS1_WRITE_INHIBITED && + sense[25] == 0x01; +} + /* * Interrupt handler for "normal" ssch-io based dasd devices. */ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) { - struct dasd_ccw_req *cqr, *next; + struct dasd_ccw_req *cqr, *next, *fcqr; struct dasd_device *device; unsigned long now; int nrf_suppressed = 0; @@ -1641,6 +1735,17 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); nrf_suppressed = (sense[1] & SNS1_NO_REC_FOUND) && test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); + + /* + * Extent pool probably out-of-space. + * Stop device and check exhaust level. + */ + if (dasd_ese_oos_cond(sense)) { + dasd_generic_space_exhaust(device, cqr); + device->discipline->ext_pool_exhaust(device, cqr); + dasd_put_device(device); + return; + } } if (!(fp_suppressed || nrf_suppressed)) device->discipline->dump_sense_dbf(device, irb, "int"); @@ -1672,6 +1777,31 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } + if (dasd_ese_needs_format(cqr->block, irb)) { + if (rq_data_dir((struct request *)cqr->callback_data) == READ) { + device->discipline->ese_read(cqr); + cqr->status = DASD_CQR_SUCCESS; + cqr->stopclk = now; + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); + return; + } + fcqr = device->discipline->ese_format(device, cqr); + if (IS_ERR(fcqr)) { + /* + * If we can't format now, let the request go + * one extra round. Maybe we can format later. + */ + cqr->status = DASD_CQR_QUEUED; + } else { + fcqr->status = DASD_CQR_QUEUED; + cqr->status = DASD_CQR_QUEUED; + list_add(&fcqr->devlist, &device->ccw_queue); + dasd_schedule_device_bh(device); + return; + } + } + /* Check for clear pending */ if (cqr->status == DASD_CQR_CLEAR_PENDING && scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) { @@ -1910,7 +2040,7 @@ static void __dasd_device_check_expire(struct dasd_device *device) static int __dasd_device_is_unusable(struct dasd_device *device, struct dasd_ccw_req *cqr) { - int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM); + int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM | DASD_STOPPED_NOSPC); if (test_bit(DASD_FLAG_OFFLINE, &device->flags) && !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { @@ -2412,6 +2542,15 @@ int dasd_sleep_on_queue(struct list_head *ccw_queue) EXPORT_SYMBOL(dasd_sleep_on_queue); /* + * Start requests from a ccw_queue and wait interruptible for their completion. + */ +int dasd_sleep_on_queue_interruptible(struct list_head *ccw_queue) +{ + return _dasd_sleep_on_queue(ccw_queue, 1); +} +EXPORT_SYMBOL(dasd_sleep_on_queue_interruptible); + +/* * Queue a request to the tail of the device ccw_queue and wait * interruptible for it's completion. */ @@ -3130,55 +3269,6 @@ static int dasd_alloc_queue(struct dasd_block *block) } /* - * Allocate and initialize request queue. - */ -static void dasd_setup_queue(struct dasd_block *block) -{ - unsigned int logical_block_size = block->bp_block; - struct request_queue *q = block->request_queue; - unsigned int max_bytes, max_discard_sectors; - int max; - - if (block->base->features & DASD_FEATURE_USERAW) { - /* - * the max_blocks value for raw_track access is 256 - * it is higher than the native ECKD value because we - * only need one ccw per track - * so the max_hw_sectors are - * 2048 x 512B = 1024kB = 16 tracks - */ - max = 2048; - } else { - max = block->base->discipline->max_blocks << block->s2b_shift; - } - blk_queue_flag_set(QUEUE_FLAG_NONROT, q); - q->limits.max_dev_sectors = max; - blk_queue_logical_block_size(q, logical_block_size); - blk_queue_max_hw_sectors(q, max); - blk_queue_max_segments(q, USHRT_MAX); - /* with page sized segments we can translate each segement into - * one idaw/tidaw - */ - blk_queue_max_segment_size(q, PAGE_SIZE); - blk_queue_segment_boundary(q, PAGE_SIZE - 1); - - /* Only activate blocklayer discard support for devices that support it */ - if (block->base->features & DASD_FEATURE_DISCARD) { - q->limits.discard_granularity = logical_block_size; - q->limits.discard_alignment = PAGE_SIZE; - - /* Calculate max_discard_sectors and make it PAGE aligned */ - max_bytes = USHRT_MAX * logical_block_size; - max_bytes = ALIGN(max_bytes, PAGE_SIZE) - PAGE_SIZE; - max_discard_sectors = max_bytes / logical_block_size; - - blk_queue_max_discard_sectors(q, max_discard_sectors); - blk_queue_max_write_zeroes_sectors(q, max_discard_sectors); - blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); - } -} - -/* * Deactivate and free request queue. */ static void dasd_free_queue(struct dasd_block *block) @@ -3806,6 +3896,43 @@ int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm) } EXPORT_SYMBOL_GPL(dasd_generic_verify_path); +void dasd_generic_space_exhaust(struct dasd_device *device, + struct dasd_ccw_req *cqr) +{ + dasd_eer_write(device, NULL, DASD_EER_NOSPC); + + if (device->state < DASD_STATE_BASIC) + return; + + if (cqr->status == DASD_CQR_IN_IO || + cqr->status == DASD_CQR_CLEAR_PENDING) { + cqr->status = DASD_CQR_QUEUED; + cqr->retries++; + } + dasd_device_set_stop_bits(device, DASD_STOPPED_NOSPC); + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); +} +EXPORT_SYMBOL_GPL(dasd_generic_space_exhaust); + +void dasd_generic_space_avail(struct dasd_device *device) +{ + dev_info(&device->cdev->dev, "Extent pool space is available\n"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "space available"); + + dasd_device_remove_stop_bits(device, DASD_STOPPED_NOSPC); + dasd_schedule_device_bh(device); + + if (device->block) { + dasd_schedule_block_bh(device->block); + if (device->block->request_queue) + blk_mq_run_hw_queues(device->block->request_queue, true); + } + if (!device->stopped) + wake_up(&generic_waitq); +} +EXPORT_SYMBOL_GPL(dasd_generic_space_avail); + /* * clear active requests and requeue them to block layer if possible */ diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 245f33c2f71e..32fc51341d99 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1642,6 +1642,35 @@ static DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show, dasd_path_interval_store); +#define DASD_DEFINE_ATTR(_name, _func) \ +static ssize_t dasd_##_name##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct ccw_device *cdev = to_ccwdev(dev); \ + struct dasd_device *device = dasd_device_from_cdev(cdev); \ + int val = 0; \ + \ + if (IS_ERR(device)) \ + return -ENODEV; \ + if (device->discipline && _func) \ + val = _func(device); \ + dasd_put_device(device); \ + \ + return snprintf(buf, PAGE_SIZE, "%d\n", val); \ +} \ +static DEVICE_ATTR(_name, 0444, dasd_##_name##_show, NULL); \ + +DASD_DEFINE_ATTR(ese, device->discipline->is_ese); +DASD_DEFINE_ATTR(extent_size, device->discipline->ext_size); +DASD_DEFINE_ATTR(pool_id, device->discipline->ext_pool_id); +DASD_DEFINE_ATTR(space_configured, device->discipline->space_configured); +DASD_DEFINE_ATTR(space_allocated, device->discipline->space_allocated); +DASD_DEFINE_ATTR(logical_capacity, device->discipline->logical_capacity); +DASD_DEFINE_ATTR(warn_threshold, device->discipline->ext_pool_warn_thrshld); +DASD_DEFINE_ATTR(cap_at_warnlevel, device->discipline->ext_pool_cap_at_warnlevel); +DASD_DEFINE_ATTR(pool_oos, device->discipline->ext_pool_oos); + static struct attribute * dasd_attrs[] = { &dev_attr_readonly.attr, &dev_attr_discipline.attr, @@ -1667,6 +1696,7 @@ static struct attribute * dasd_attrs[] = { &dev_attr_path_interval.attr, &dev_attr_path_reset.attr, &dev_attr_hpf.attr, + &dev_attr_ese.attr, NULL, }; @@ -1674,6 +1704,39 @@ static const struct attribute_group dasd_attr_group = { .attrs = dasd_attrs, }; +static struct attribute *capacity_attrs[] = { + &dev_attr_space_configured.attr, + &dev_attr_space_allocated.attr, + &dev_attr_logical_capacity.attr, + NULL, +}; + +static const struct attribute_group capacity_attr_group = { + .name = "capacity", + .attrs = capacity_attrs, +}; + +static struct attribute *ext_pool_attrs[] = { + &dev_attr_pool_id.attr, + &dev_attr_extent_size.attr, + &dev_attr_warn_threshold.attr, + &dev_attr_cap_at_warnlevel.attr, + &dev_attr_pool_oos.attr, + NULL, +}; + +static const struct attribute_group ext_pool_attr_group = { + .name = "extent_pool", + .attrs = ext_pool_attrs, +}; + +static const struct attribute_group *dasd_attr_groups[] = { + &dasd_attr_group, + &capacity_attr_group, + &ext_pool_attr_group, + NULL, +}; + /* * Return value of the specified feature. */ @@ -1715,16 +1778,15 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) EXPORT_SYMBOL(dasd_set_feature); -int -dasd_add_sysfs_files(struct ccw_device *cdev) +int dasd_add_sysfs_files(struct ccw_device *cdev) { - return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group); + return sysfs_create_groups(&cdev->dev.kobj, dasd_attr_groups); } void dasd_remove_sysfs_files(struct ccw_device *cdev) { - sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group); + sysfs_remove_groups(&cdev->dev.kobj, dasd_attr_groups); } diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index e1fe02477ea8..8d4971645cf1 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -615,14 +615,34 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, "dump sense not available for DIAG data"); } +/* + * Initialize block layer request queue. + */ +static void dasd_diag_setup_blk_queue(struct dasd_block *block) +{ + unsigned int logical_block_size = block->bp_block; + struct request_queue *q = block->request_queue; + int max; + + max = DIAG_MAX_BLOCKS << block->s2b_shift; + blk_queue_flag_set(QUEUE_FLAG_NONROT, q); + q->limits.max_dev_sectors = max; + blk_queue_logical_block_size(q, logical_block_size); + blk_queue_max_hw_sectors(q, max); + blk_queue_max_segments(q, USHRT_MAX); + /* With page sized segments each segment can be translated into one idaw/tidaw */ + blk_queue_max_segment_size(q, PAGE_SIZE); + blk_queue_segment_boundary(q, PAGE_SIZE - 1); +} + static struct dasd_discipline dasd_diag_discipline = { .owner = THIS_MODULE, .name = "DIAG", .ebcname = "DIAG", - .max_blocks = DIAG_MAX_BLOCKS, .check_device = dasd_diag_check_device, .verify_path = dasd_generic_verify_path, .fill_geometry = dasd_diag_fill_geometry, + .setup_blk_queue = dasd_diag_setup_blk_queue, .start_IO = dasd_start_diag, .term_IO = dasd_diag_term_IO, .handle_terminated_request = dasd_diag_handle_terminated_request, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index c09039eea707..fc53e1e221f0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -42,20 +42,6 @@ #endif /* PRINTK_HEADER */ #define PRINTK_HEADER "dasd(eckd):" -#define ECKD_C0(i) (i->home_bytes) -#define ECKD_F(i) (i->formula) -#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):\ - (i->factors.f_0x02.f1)) -#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):\ - (i->factors.f_0x02.f2)) -#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):\ - (i->factors.f_0x02.f3)) -#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0) -#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0) -#define ECKD_F6(i) (i->factor6) -#define ECKD_F7(i) (i->factor7) -#define ECKD_F8(i) (i->factor8) - /* * raw track access always map to 64k in memory * so it maps to 16 blocks of 4k per track @@ -103,6 +89,19 @@ static struct { } *dasd_reserve_req; static DEFINE_MUTEX(dasd_reserve_mutex); +static struct { + struct dasd_ccw_req cqr; + struct ccw1 ccw[2]; + char data[40]; +} *dasd_vol_info_req; +static DEFINE_MUTEX(dasd_vol_info_mutex); + +struct ext_pool_exhaust_work_data { + struct work_struct worker; + struct dasd_device *device; + struct dasd_device *base; +}; + /* definitions for the path verification worker */ struct path_verification_work_data { struct work_struct worker; @@ -122,6 +121,7 @@ struct check_attention_work_data { __u8 lpum; }; +static int dasd_eckd_ext_pool_id(struct dasd_device *); static int prepare_itcw(struct itcw *, unsigned int, unsigned int, int, struct dasd_device *, struct dasd_device *, unsigned int, int, unsigned int, unsigned int, @@ -157,17 +157,10 @@ static const int sizes_trk0[] = { 28, 148, 84 }; #define LABEL_SIZE 140 /* head and record addresses of count_area read in analysis ccw */ -static const int count_area_head[] = { 0, 0, 0, 0, 2 }; +static const int count_area_head[] = { 0, 0, 0, 0, 1 }; static const int count_area_rec[] = { 1, 2, 3, 4, 1 }; static inline unsigned int -round_up_multiple(unsigned int no, unsigned int mult) -{ - int rem = no % mult; - return (rem ? no - rem + mult : no); -} - -static inline unsigned int ceil_quot(unsigned int d1, unsigned int d2) { return (d1 + (d2 - 1)) / d2; @@ -1491,6 +1484,311 @@ static int dasd_eckd_read_features(struct dasd_device *device) return rc; } +/* Read Volume Information - Volume Storage Query */ +static int dasd_eckd_read_vol_info(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + struct dasd_psf_prssd_data *prssdp; + struct dasd_rssd_vsq *vsq; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + int useglobal; + int rc; + + /* This command cannot be executed on an alias device */ + if (private->uid.type == UA_BASE_PAV_ALIAS || + private->uid.type == UA_HYPER_PAV_ALIAS) + return 0; + + useglobal = 0; + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */, + sizeof(*prssdp) + sizeof(*vsq), device, NULL); + if (IS_ERR(cqr)) { + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", + "Could not allocate initialization request"); + mutex_lock(&dasd_vol_info_mutex); + useglobal = 1; + cqr = &dasd_vol_info_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(dasd_vol_info_req, 0, sizeof(*dasd_vol_info_req)); + cqr->cpaddr = &dasd_vol_info_req->ccw; + cqr->data = &dasd_vol_info_req->data; + cqr->magic = DASD_ECKD_MAGIC; + } + + /* Prepare for Read Subsystem Data */ + prssdp = cqr->data; + prssdp->order = PSF_ORDER_PRSSD; + prssdp->suborder = PSF_SUBORDER_VSQ; /* Volume Storage Query */ + prssdp->lss = private->ned->ID; + prssdp->volume = private->ned->unit_addr; + + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_PSF; + ccw->count = sizeof(*prssdp); + ccw->flags |= CCW_FLAG_CC; + ccw->cda = (__u32)(addr_t)prssdp; + + /* Read Subsystem Data - Volume Storage Query */ + vsq = (struct dasd_rssd_vsq *)(prssdp + 1); + memset(vsq, 0, sizeof(*vsq)); + + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_RSSD; + ccw->count = sizeof(*vsq); + ccw->flags |= CCW_FLAG_SLI; + ccw->cda = (__u32)(addr_t)vsq; + + cqr->buildclk = get_tod_clock(); + cqr->status = DASD_CQR_FILLED; + cqr->startdev = device; + cqr->memdev = device; + cqr->block = NULL; + cqr->retries = 256; + cqr->expires = device->default_expires * HZ; + /* The command might not be supported. Suppress the error output */ + __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags); + + rc = dasd_sleep_on_interruptible(cqr); + if (rc == 0) { + memcpy(&private->vsq, vsq, sizeof(*vsq)); + } else { + dev_warn(&device->cdev->dev, + "Reading the volume storage information failed with rc=%d\n", rc); + } + + if (useglobal) + mutex_unlock(&dasd_vol_info_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); + + return rc; +} + +static int dasd_eckd_is_ese(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + + return private->vsq.vol_info.ese; +} + +static int dasd_eckd_ext_pool_id(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + + return private->vsq.extent_pool_id; +} + +/* + * This value represents the total amount of available space. As more space is + * allocated by ESE volumes, this value will decrease. + * The data for this value is therefore updated on any call. + */ +static int dasd_eckd_space_configured(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + int rc; + + rc = dasd_eckd_read_vol_info(device); + + return rc ? : private->vsq.space_configured; +} + +/* + * The value of space allocated by an ESE volume may have changed and is + * therefore updated on any call. + */ +static int dasd_eckd_space_allocated(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + int rc; + + rc = dasd_eckd_read_vol_info(device); + + return rc ? : private->vsq.space_allocated; +} + +static int dasd_eckd_logical_capacity(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + + return private->vsq.logical_capacity; +} + +static void dasd_eckd_ext_pool_exhaust_work(struct work_struct *work) +{ + struct ext_pool_exhaust_work_data *data; + struct dasd_device *device; + struct dasd_device *base; + + data = container_of(work, struct ext_pool_exhaust_work_data, worker); + device = data->device; + base = data->base; + + if (!base) + base = device; + if (dasd_eckd_space_configured(base) != 0) { + dasd_generic_space_avail(device); + } else { + dev_warn(&device->cdev->dev, "No space left in the extent pool\n"); + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "out of space"); + } + + dasd_put_device(device); + kfree(data); +} + +static int dasd_eckd_ext_pool_exhaust(struct dasd_device *device, + struct dasd_ccw_req *cqr) +{ + struct ext_pool_exhaust_work_data *data; + + data = kzalloc(sizeof(*data), GFP_ATOMIC); + if (!data) + return -ENOMEM; + INIT_WORK(&data->worker, dasd_eckd_ext_pool_exhaust_work); + dasd_get_device(device); + data->device = device; + + if (cqr->block) + data->base = cqr->block->base; + else if (cqr->basedev) + data->base = cqr->basedev; + else + data->base = NULL; + + schedule_work(&data->worker); + + return 0; +} + +static void dasd_eckd_cpy_ext_pool_data(struct dasd_device *device, + struct dasd_rssd_lcq *lcq) +{ + struct dasd_eckd_private *private = device->private; + int pool_id = dasd_eckd_ext_pool_id(device); + struct dasd_ext_pool_sum eps; + int i; + + for (i = 0; i < lcq->pool_count; i++) { + eps = lcq->ext_pool_sum[i]; + if (eps.pool_id == pool_id) { + memcpy(&private->eps, &eps, + sizeof(struct dasd_ext_pool_sum)); + } + } +} + +/* Read Extent Pool Information - Logical Configuration Query */ +static int dasd_eckd_read_ext_pool_info(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + struct dasd_psf_prssd_data *prssdp; + struct dasd_rssd_lcq *lcq; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + int rc; + + /* This command cannot be executed on an alias device */ + if (private->uid.type == UA_BASE_PAV_ALIAS || + private->uid.type == UA_HYPER_PAV_ALIAS) + return 0; + + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */, + sizeof(*prssdp) + sizeof(*lcq), device, NULL); + if (IS_ERR(cqr)) { + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", + "Could not allocate initialization request"); + return PTR_ERR(cqr); + } + + /* Prepare for Read Subsystem Data */ + prssdp = cqr->data; + memset(prssdp, 0, sizeof(*prssdp)); + prssdp->order = PSF_ORDER_PRSSD; + prssdp->suborder = PSF_SUBORDER_LCQ; /* Logical Configuration Query */ + + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_PSF; + ccw->count = sizeof(*prssdp); + ccw->flags |= CCW_FLAG_CC; + ccw->cda = (__u32)(addr_t)prssdp; + + lcq = (struct dasd_rssd_lcq *)(prssdp + 1); + memset(lcq, 0, sizeof(*lcq)); + + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_RSSD; + ccw->count = sizeof(*lcq); + ccw->flags |= CCW_FLAG_SLI; + ccw->cda = (__u32)(addr_t)lcq; + + cqr->buildclk = get_tod_clock(); + cqr->status = DASD_CQR_FILLED; + cqr->startdev = device; + cqr->memdev = device; + cqr->block = NULL; + cqr->retries = 256; + cqr->expires = device->default_expires * HZ; + /* The command might not be supported. Suppress the error output */ + __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags); + + rc = dasd_sleep_on_interruptible(cqr); + if (rc == 0) { + dasd_eckd_cpy_ext_pool_data(device, lcq); + } else { + dev_warn(&device->cdev->dev, + "Reading the logical configuration failed with rc=%d\n", rc); + } + + dasd_sfree_request(cqr, cqr->memdev); + + return rc; +} + +/* + * Depending on the device type, the extent size is specified either as + * cylinders per extent (CKD) or size per extent (FBA) + * A 1GB size corresponds to 1113cyl, and 16MB to 21cyl. + */ +static int dasd_eckd_ext_size(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + struct dasd_ext_pool_sum eps = private->eps; + + if (!eps.flags.extent_size_valid) + return 0; + if (eps.extent_size.size_1G) + return 1113; + if (eps.extent_size.size_16M) + return 21; + + return 0; +} + +static int dasd_eckd_ext_pool_warn_thrshld(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + + return private->eps.warn_thrshld; +} + +static int dasd_eckd_ext_pool_cap_at_warnlevel(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + + return private->eps.flags.capacity_at_warnlevel; +} + +/* + * Extent Pool out of space + */ +static int dasd_eckd_ext_pool_oos(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + + return private->eps.flags.pool_oos; +} /* * Build CP for Perform Subsystem Function - SSC. @@ -1721,6 +2019,16 @@ dasd_eckd_check_characteristics(struct dasd_device *device) /* Read Feature Codes */ dasd_eckd_read_features(device); + /* Read Volume Information */ + rc = dasd_eckd_read_vol_info(device); + if (rc) + goto out_err3; + + /* Read Extent Pool Information */ + rc = dasd_eckd_read_ext_pool_info(device); + if (rc) + goto out_err3; + /* Read Device Characteristics */ rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, &private->rdc_data, 64); @@ -1751,6 +2059,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) if (readonly) set_bit(DASD_FLAG_DEVICE_RO, &device->flags); + if (dasd_eckd_is_ese(device)) + dasd_set_feature(device->cdev, DASD_FEATURE_DISCARD, 1); + dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " "with %d cylinders, %d heads, %d sectors%s\n", private->rdc_data.dev_type, @@ -1823,8 +2134,8 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; - /* Define extent for the first 3 tracks. */ - define_extent(ccw++, cqr->data, 0, 2, + /* Define extent for the first 2 tracks. */ + define_extent(ccw++, cqr->data, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); LO_data = cqr->data + sizeof(struct DE_eckd_data); /* Locate record for the first 4 records on track 0. */ @@ -1843,9 +2154,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) count_data++; } - /* Locate record for the first record on track 2. */ + /* Locate record for the first record on track 1. */ ccw[-1].flags |= CCW_FLAG_CC; - locate_record(ccw++, LO_data++, 2, 0, 1, + locate_record(ccw++, LO_data++, 1, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0); /* Read count ccw. */ ccw[-1].flags |= CCW_FLAG_CC; @@ -1860,6 +2171,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) cqr->retries = 255; cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; + /* Set flags to suppress output for expected errors */ + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); + return cqr; } @@ -1967,7 +2281,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) } } if (i == 3) - count_area = &private->count_area[4]; + count_area = &private->count_area[3]; if (private->uses_cdl == 0) { for (i = 0; i < 5; i++) { @@ -2099,8 +2413,7 @@ dasd_eckd_build_check_tcw(struct dasd_device *base, struct format_data_t *fdata, */ itcw_size = itcw_calc_size(0, count, 0); - cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev, - NULL); + cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev); if (IS_ERR(cqr)) return cqr; @@ -2193,8 +2506,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata, } cplength += count; - cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, - startdev, NULL); + cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev); if (IS_ERR(cqr)) return cqr; @@ -2241,13 +2553,11 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata, } static struct dasd_ccw_req * -dasd_eckd_build_format(struct dasd_device *base, - struct format_data_t *fdata, - int enable_pav) +dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev, + struct format_data_t *fdata, int enable_pav) { struct dasd_eckd_private *base_priv; struct dasd_eckd_private *start_priv; - struct dasd_device *startdev = NULL; struct dasd_ccw_req *fcp; struct eckd_count *ect; struct ch_t address; @@ -2338,9 +2648,8 @@ dasd_eckd_build_format(struct dasd_device *base, fdata->intensity); return ERR_PTR(-EINVAL); } - /* Allocate the format ccw request. */ - fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, - datasize, startdev, NULL); + + fcp = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev); if (IS_ERR(fcp)) return fcp; @@ -2513,7 +2822,7 @@ dasd_eckd_format_build_ccw_req(struct dasd_device *base, struct dasd_ccw_req *ccw_req; if (!fmt_buffer) { - ccw_req = dasd_eckd_build_format(base, fdata, enable_pav); + ccw_req = dasd_eckd_build_format(base, NULL, fdata, enable_pav); } else { if (tpm) ccw_req = dasd_eckd_build_check_tcw(base, fdata, @@ -2659,7 +2968,7 @@ out_err: rc = -EIO; } list_del_init(&cqr->blocklist); - dasd_sfree_request(cqr, device); + dasd_ffree_request(cqr, device); private->count--; } @@ -2699,6 +3008,96 @@ static int dasd_eckd_format_device(struct dasd_device *base, } /* + * Callback function to free ESE format requests. + */ +static void dasd_eckd_ese_format_cb(struct dasd_ccw_req *cqr, void *data) +{ + struct dasd_device *device = cqr->startdev; + struct dasd_eckd_private *private = device->private; + + private->count--; + dasd_ffree_request(cqr, device); +} + +static struct dasd_ccw_req * +dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr) +{ + struct dasd_eckd_private *private; + struct format_data_t fdata; + unsigned int recs_per_trk; + struct dasd_ccw_req *fcqr; + struct dasd_device *base; + struct dasd_block *block; + unsigned int blksize; + struct request *req; + sector_t first_trk; + sector_t last_trk; + int rc; + + req = cqr->callback_data; + base = cqr->block->base; + private = base->private; + block = base->block; + blksize = block->bp_block; + recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize); + + first_trk = blk_rq_pos(req) >> block->s2b_shift; + sector_div(first_trk, recs_per_trk); + last_trk = + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; + sector_div(last_trk, recs_per_trk); + + fdata.start_unit = first_trk; + fdata.stop_unit = last_trk; + fdata.blksize = blksize; + fdata.intensity = private->uses_cdl ? DASD_FMT_INT_COMPAT : 0; + + rc = dasd_eckd_format_sanity_checks(base, &fdata); + if (rc) + return ERR_PTR(-EINVAL); + + /* + * We're building the request with PAV disabled as we're reusing + * the former startdev. + */ + fcqr = dasd_eckd_build_format(base, startdev, &fdata, 0); + if (IS_ERR(fcqr)) + return fcqr; + + fcqr->callback = dasd_eckd_ese_format_cb; + + return fcqr; +} + +/* + * When data is read from an unformatted area of an ESE volume, this function + * returns zeroed data and thereby mimics a read of zero data. + */ +static void dasd_eckd_ese_read(struct dasd_ccw_req *cqr) +{ + unsigned int blksize, off; + struct dasd_device *base; + struct req_iterator iter; + struct request *req; + struct bio_vec bv; + char *dst; + + req = (struct request *) cqr->callback_data; + base = cqr->block->base; + blksize = base->block->bp_block; + + rq_for_each_segment(bv, req, iter) { + dst = page_address(bv.bv_page) + bv.bv_offset; + for (off = 0; off < bv.bv_len; off += blksize) { + if (dst && rq_data_dir(req) == READ) { + dst += off; + memset(dst, 0, blksize); + } + } + } +} + +/* * Helper function to count consecutive records of a single track. */ static int dasd_eckd_count_records(struct eckd_count *fmt_buffer, int start, @@ -3033,6 +3432,277 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, } } +static int dasd_eckd_ras_sanity_checks(struct dasd_device *device, + unsigned int first_trk, + unsigned int last_trk) +{ + struct dasd_eckd_private *private = device->private; + unsigned int trks_per_vol; + int rc = 0; + + trks_per_vol = private->real_cyl * private->rdc_data.trk_per_cyl; + + if (first_trk >= trks_per_vol) { + dev_warn(&device->cdev->dev, + "Start track number %u used in the space release command is too big\n", + first_trk); + rc = -EINVAL; + } else if (last_trk >= trks_per_vol) { + dev_warn(&device->cdev->dev, + "Stop track number %u used in the space release command is too big\n", + last_trk); + rc = -EINVAL; + } else if (first_trk > last_trk) { + dev_warn(&device->cdev->dev, + "Start track %u used in the space release command exceeds the end track\n", + first_trk); + rc = -EINVAL; + } + return rc; +} + +/* + * Helper function to count the amount of involved extents within a given range + * with extent alignment in mind. + */ +static int count_exts(unsigned int from, unsigned int to, int trks_per_ext) +{ + int cur_pos = 0; + int count = 0; + int tmp; + + if (from == to) + return 1; + + /* Count first partial extent */ + if (from % trks_per_ext != 0) { + tmp = from + trks_per_ext - (from % trks_per_ext) - 1; + if (tmp > to) + tmp = to; + cur_pos = tmp - from + 1; + count++; + } + /* Count full extents */ + if (to - (from + cur_pos) + 1 >= trks_per_ext) { + tmp = to - ((to - trks_per_ext + 1) % trks_per_ext); + count += (tmp - (from + cur_pos) + 1) / trks_per_ext; + cur_pos = tmp; + } + /* Count last partial extent */ + if (cur_pos < to) + count++; + + return count; +} + +/* + * Release allocated space for a given range or an entire volume. + */ +static struct dasd_ccw_req * +dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, + struct request *req, unsigned int first_trk, + unsigned int last_trk, int by_extent) +{ + struct dasd_eckd_private *private = device->private; + struct dasd_dso_ras_ext_range *ras_range; + struct dasd_rssd_features *features; + struct dasd_dso_ras_data *ras_data; + u16 heads, beg_head, end_head; + int cur_to_trk, cur_from_trk; + struct dasd_ccw_req *cqr; + u32 beg_cyl, end_cyl; + struct ccw1 *ccw; + int trks_per_ext; + size_t ras_size; + size_t size; + int nr_exts; + void *rq; + int i; + + if (dasd_eckd_ras_sanity_checks(device, first_trk, last_trk)) + return ERR_PTR(-EINVAL); + + rq = req ? blk_mq_rq_to_pdu(req) : NULL; + + features = &private->features; + + trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl; + nr_exts = 0; + if (by_extent) + nr_exts = count_exts(first_trk, last_trk, trks_per_ext); + ras_size = sizeof(*ras_data); + size = ras_size + (nr_exts * sizeof(*ras_range)); + + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, size, device, rq); + if (IS_ERR(cqr)) { + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", + "Could not allocate RAS request"); + return cqr; + } + + ras_data = cqr->data; + memset(ras_data, 0, size); + + ras_data->order = DSO_ORDER_RAS; + ras_data->flags.vol_type = 0; /* CKD volume */ + /* Release specified extents or entire volume */ + ras_data->op_flags.by_extent = by_extent; + /* + * This bit guarantees initialisation of tracks within an extent that is + * not fully specified, but is only supported with a certain feature + * subset. + */ + ras_data->op_flags.guarantee_init = !!(features->feature[56] & 0x01); + ras_data->lss = private->ned->ID; + ras_data->dev_addr = private->ned->unit_addr; + ras_data->nr_exts = nr_exts; + + if (by_extent) { + heads = private->rdc_data.trk_per_cyl; + cur_from_trk = first_trk; + cur_to_trk = first_trk + trks_per_ext - + (first_trk % trks_per_ext) - 1; + if (cur_to_trk > last_trk) + cur_to_trk = last_trk; + ras_range = (struct dasd_dso_ras_ext_range *)(cqr->data + ras_size); + + for (i = 0; i < nr_exts; i++) { + beg_cyl = cur_from_trk / heads; + beg_head = cur_from_trk % heads; + end_cyl = cur_to_trk / heads; + end_head = cur_to_trk % heads; + + set_ch_t(&ras_range->beg_ext, beg_cyl, beg_head); + set_ch_t(&ras_range->end_ext, end_cyl, end_head); + + cur_from_trk = cur_to_trk + 1; + cur_to_trk = cur_from_trk + trks_per_ext - 1; + if (cur_to_trk > last_trk) + cur_to_trk = last_trk; + ras_range++; + } + } + + ccw = cqr->cpaddr; + ccw->cda = (__u32)(addr_t)cqr->data; + ccw->cmd_code = DASD_ECKD_CCW_DSO; + ccw->count = size; + + cqr->startdev = device; + cqr->memdev = device; + cqr->block = block; + cqr->retries = 256; + cqr->expires = device->default_expires * HZ; + cqr->buildclk = get_tod_clock(); + cqr->status = DASD_CQR_FILLED; + + return cqr; +} + +static int dasd_eckd_release_space_full(struct dasd_device *device) +{ + struct dasd_ccw_req *cqr; + int rc; + + cqr = dasd_eckd_dso_ras(device, NULL, NULL, 0, 0, 0); + if (IS_ERR(cqr)) + return PTR_ERR(cqr); + + rc = dasd_sleep_on_interruptible(cqr); + + dasd_sfree_request(cqr, cqr->memdev); + + return rc; +} + +static int dasd_eckd_release_space_trks(struct dasd_device *device, + unsigned int from, unsigned int to) +{ + struct dasd_eckd_private *private = device->private; + struct dasd_block *block = device->block; + struct dasd_ccw_req *cqr, *n; + struct list_head ras_queue; + unsigned int device_exts; + int trks_per_ext; + int stop, step; + int cur_pos; + int rc = 0; + int retry; + + INIT_LIST_HEAD(&ras_queue); + + device_exts = private->real_cyl / dasd_eckd_ext_size(device); + trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl; + + /* Make sure device limits are not exceeded */ + step = trks_per_ext * min(device_exts, DASD_ECKD_RAS_EXTS_MAX); + cur_pos = from; + + do { + retry = 0; + while (cur_pos < to) { + stop = cur_pos + step - + ((cur_pos + step) % trks_per_ext) - 1; + if (stop > to) + stop = to; + + cqr = dasd_eckd_dso_ras(device, NULL, NULL, cur_pos, stop, 1); + if (IS_ERR(cqr)) { + rc = PTR_ERR(cqr); + if (rc == -ENOMEM) { + if (list_empty(&ras_queue)) + goto out; + retry = 1; + break; + } + goto err_out; + } + + spin_lock_irq(&block->queue_lock); + list_add_tail(&cqr->blocklist, &ras_queue); + spin_unlock_irq(&block->queue_lock); + cur_pos = stop + 1; + } + + rc = dasd_sleep_on_queue_interruptible(&ras_queue); + +err_out: + list_for_each_entry_safe(cqr, n, &ras_queue, blocklist) { + device = cqr->startdev; + private = device->private; + + spin_lock_irq(&block->queue_lock); + list_del_init(&cqr->blocklist); + spin_unlock_irq(&block->queue_lock); + dasd_sfree_request(cqr, device); + private->count--; + } + } while (retry); + +out: + return rc; +} + +static int dasd_eckd_release_space(struct dasd_device *device, + struct format_data_t *rdata) +{ + if (rdata->intensity & DASD_FMT_INT_ESE_FULL) + return dasd_eckd_release_space_full(device); + else if (rdata->intensity == 0) + return dasd_eckd_release_space_trks(device, rdata->start_unit, + rdata->stop_unit); + else + return -EINVAL; +} + +static struct dasd_ccw_req * +dasd_eckd_build_cp_discard(struct dasd_device *device, struct dasd_block *block, + struct request *req, sector_t first_trk, + sector_t last_trk) +{ + return dasd_eckd_dso_ras(device, block, req, first_trk, last_trk, 1); +} + static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( struct dasd_device *startdev, struct dasd_block *block, @@ -3214,6 +3884,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( cqr->retries = startdev->default_retries; cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; + + /* Set flags to suppress output for expected errors */ + if (dasd_eckd_is_ese(basedev)) { + set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); + set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags); + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); + } + return cqr; } @@ -3385,6 +4063,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( cqr->retries = startdev->default_retries; cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; + + /* Set flags to suppress output for expected errors */ + if (dasd_eckd_is_ese(basedev)) + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); + return cqr; } @@ -3704,6 +4387,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( cqr->retries = startdev->default_retries; cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; + + /* Set flags to suppress output for expected errors */ + if (dasd_eckd_is_ese(basedev)) { + set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); + set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags); + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); + } + return cqr; out_error: dasd_sfree_request(cqr, startdev); @@ -3756,6 +4447,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, cmdwtd = private->features.feature[12] & 0x40; use_prefix = private->features.feature[8] & 0x01; + if (req_op(req) == REQ_OP_DISCARD) + return dasd_eckd_build_cp_discard(startdev, block, req, + first_trk, last_trk); + cqr = NULL; if (cdlspecial || dasd_page_cache) { /* do nothing, just fall through to the cmd mode single case */ @@ -4034,12 +4729,14 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, struct dasd_block *block, struct request *req) { + struct dasd_device *startdev = NULL; struct dasd_eckd_private *private; - struct dasd_device *startdev; - unsigned long flags; struct dasd_ccw_req *cqr; + unsigned long flags; - startdev = dasd_alias_get_start_dev(base); + /* Discard requests can only be processed on base devices */ + if (req_op(req) != REQ_OP_DISCARD) + startdev = dasd_alias_get_start_dev(base); if (!startdev) startdev = base; private = startdev->private; @@ -4965,6 +5662,16 @@ static int dasd_eckd_restore_device(struct dasd_device *device) /* Read Feature Codes */ dasd_eckd_read_features(device); + /* Read Volume Information */ + rc = dasd_eckd_read_vol_info(device); + if (rc) + goto out_err2; + + /* Read Extent Pool Information */ + rc = dasd_eckd_read_ext_pool_info(device); + if (rc) + goto out_err2; + /* Read Device Characteristics */ rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, &temp_rdc_data, 64); @@ -5635,6 +6342,73 @@ static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages, device->discipline->check_attention(device, lpum); } +static void dasd_eckd_oos_resume(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + struct alias_pav_group *pavgroup, *tempgroup; + struct dasd_device *dev, *n; + unsigned long flags; + + spin_lock_irqsave(&private->lcu->lock, flags); + list_for_each_entry_safe(dev, n, &private->lcu->active_devices, + alias_list) { + if (dev->stopped & DASD_STOPPED_NOSPC) + dasd_generic_space_avail(dev); + } + list_for_each_entry_safe(dev, n, &private->lcu->inactive_devices, + alias_list) { + if (dev->stopped & DASD_STOPPED_NOSPC) + dasd_generic_space_avail(dev); + } + /* devices in PAV groups */ + list_for_each_entry_safe(pavgroup, tempgroup, + &private->lcu->grouplist, + group) { + list_for_each_entry_safe(dev, n, &pavgroup->baselist, + alias_list) { + if (dev->stopped & DASD_STOPPED_NOSPC) + dasd_generic_space_avail(dev); + } + list_for_each_entry_safe(dev, n, &pavgroup->aliaslist, + alias_list) { + if (dev->stopped & DASD_STOPPED_NOSPC) + dasd_generic_space_avail(dev); + } + } + spin_unlock_irqrestore(&private->lcu->lock, flags); +} + +static void dasd_eckd_handle_oos(struct dasd_device *device, void *messages, + __u8 lpum) +{ + struct dasd_oos_message *oos = messages; + + switch (oos->code) { + case REPO_WARN: + case POOL_WARN: + dev_warn(&device->cdev->dev, + "Extent pool usage has reached a critical value\n"); + dasd_eckd_oos_resume(device); + break; + case REPO_EXHAUST: + case POOL_EXHAUST: + dev_warn(&device->cdev->dev, + "Extent pool is exhausted\n"); + break; + case REPO_RELIEVE: + case POOL_RELIEVE: + dev_info(&device->cdev->dev, + "Extent pool physical space constraint has been relieved\n"); + break; + } + + /* In any case, update related data */ + dasd_eckd_read_ext_pool_info(device); + + /* to make sure there is no attention left schedule work again */ + device->discipline->check_attention(device, lpum); +} + static void dasd_eckd_check_attention_work(struct work_struct *work) { struct check_attention_work_data *data; @@ -5653,9 +6427,14 @@ static void dasd_eckd_check_attention_work(struct work_struct *work) rc = dasd_eckd_read_message_buffer(device, messages, data->lpum); if (rc) goto out; + if (messages->length == ATTENTION_LENGTH_CUIR && messages->format == ATTENTION_FORMAT_CUIR) dasd_eckd_handle_cuir(device, messages, data->lpum); + if (messages->length == ATTENTION_LENGTH_OOS && + messages->format == ATTENTION_FORMAT_OOS) + dasd_eckd_handle_oos(device, messages, data->lpum); + out: dasd_put_device(device); kfree(messages); @@ -5734,6 +6513,72 @@ static void dasd_eckd_handle_hpf_error(struct dasd_device *device, dasd_schedule_requeue(device); } +/* + * Initialize block layer request queue. + */ +static void dasd_eckd_setup_blk_queue(struct dasd_block *block) +{ + unsigned int logical_block_size = block->bp_block; + struct request_queue *q = block->request_queue; + struct dasd_device *device = block->base; + struct dasd_eckd_private *private; + unsigned int max_discard_sectors; + unsigned int max_bytes; + unsigned int ext_bytes; /* Extent Size in Bytes */ + int recs_per_trk; + int trks_per_cyl; + int ext_limit; + int ext_size; /* Extent Size in Cylinders */ + int max; + + private = device->private; + trks_per_cyl = private->rdc_data.trk_per_cyl; + recs_per_trk = recs_per_track(&private->rdc_data, 0, logical_block_size); + + if (device->features & DASD_FEATURE_USERAW) { + /* + * the max_blocks value for raw_track access is 256 + * it is higher than the native ECKD value because we + * only need one ccw per track + * so the max_hw_sectors are + * 2048 x 512B = 1024kB = 16 tracks + */ + max = DASD_ECKD_MAX_BLOCKS_RAW << block->s2b_shift; + } else { + max = DASD_ECKD_MAX_BLOCKS << block->s2b_shift; + } + blk_queue_flag_set(QUEUE_FLAG_NONROT, q); + q->limits.max_dev_sectors = max; + blk_queue_logical_block_size(q, logical_block_size); + blk_queue_max_hw_sectors(q, max); + blk_queue_max_segments(q, USHRT_MAX); + /* With page sized segments each segment can be translated into one idaw/tidaw */ + blk_queue_max_segment_size(q, PAGE_SIZE); + blk_queue_segment_boundary(q, PAGE_SIZE - 1); + + if (dasd_eckd_is_ese(device)) { + /* + * Depending on the extent size, up to UINT_MAX bytes can be + * accepted. However, neither DASD_ECKD_RAS_EXTS_MAX nor the + * device limits should be exceeded. + */ + ext_size = dasd_eckd_ext_size(device); + ext_limit = min(private->real_cyl / ext_size, DASD_ECKD_RAS_EXTS_MAX); + ext_bytes = ext_size * trks_per_cyl * recs_per_trk * + logical_block_size; + max_bytes = UINT_MAX - (UINT_MAX % ext_bytes); + if (max_bytes / ext_bytes > ext_limit) + max_bytes = ext_bytes * ext_limit; + + max_discard_sectors = max_bytes / 512; + + blk_queue_max_discard_sectors(q, max_discard_sectors); + blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); + q->limits.discard_granularity = ext_bytes; + q->limits.discard_alignment = ext_bytes; + } +} + static struct ccw_driver dasd_eckd_driver = { .driver = { .name = "dasd-eckd", @@ -5754,24 +6599,10 @@ static struct ccw_driver dasd_eckd_driver = { .int_class = IRQIO_DAS, }; -/* - * max_blocks is dependent on the amount of storage that is available - * in the static io buffer for each device. Currently each device has - * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has - * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use - * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In - * addition we have one define extent ccw + 16 bytes of data and one - * locate record ccw + 16 bytes of data. That makes: - * (8192 - 24 - 136 - 8 - 16 - 8 - 16) / 16 = 499 blocks at maximum. - * We want to fit two into the available memory so that we can immediately - * start the next request if one finishes off. That makes 249.5 blocks - * for one request. Give a little safety and the result is 240. - */ static struct dasd_discipline dasd_eckd_discipline = { .owner = THIS_MODULE, .name = "ECKD", .ebcname = "ECKD", - .max_blocks = 190, .check_device = dasd_eckd_check_characteristics, .uncheck_device = dasd_eckd_uncheck_device, .do_analysis = dasd_eckd_do_analysis, @@ -5779,6 +6610,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .basic_to_ready = dasd_eckd_basic_to_ready, .online_to_ready = dasd_eckd_online_to_ready, .basic_to_known = dasd_eckd_basic_to_known, + .setup_blk_queue = dasd_eckd_setup_blk_queue, .fill_geometry = dasd_eckd_fill_geometry, .start_IO = dasd_start_IO, .term_IO = dasd_term_IO, @@ -5806,6 +6638,19 @@ static struct dasd_discipline dasd_eckd_discipline = { .disable_hpf = dasd_eckd_disable_hpf_device, .hpf_enabled = dasd_eckd_hpf_enabled, .reset_path = dasd_eckd_reset_path, + .is_ese = dasd_eckd_is_ese, + .space_allocated = dasd_eckd_space_allocated, + .space_configured = dasd_eckd_space_configured, + .logical_capacity = dasd_eckd_logical_capacity, + .release_space = dasd_eckd_release_space, + .ext_pool_id = dasd_eckd_ext_pool_id, + .ext_size = dasd_eckd_ext_size, + .ext_pool_cap_at_warnlevel = dasd_eckd_ext_pool_cap_at_warnlevel, + .ext_pool_warn_thrshld = dasd_eckd_ext_pool_warn_thrshld, + .ext_pool_oos = dasd_eckd_ext_pool_oos, + .ext_pool_exhaust = dasd_eckd_ext_pool_exhaust, + .ese_format = dasd_eckd_ese_format, + .ese_read = dasd_eckd_ese_read, }; static int __init @@ -5818,16 +6663,22 @@ dasd_eckd_init(void) GFP_KERNEL | GFP_DMA); if (!dasd_reserve_req) return -ENOMEM; + dasd_vol_info_req = kmalloc(sizeof(*dasd_vol_info_req), + GFP_KERNEL | GFP_DMA); + if (!dasd_vol_info_req) + return -ENOMEM; path_verification_worker = kmalloc(sizeof(*path_verification_worker), GFP_KERNEL | GFP_DMA); if (!path_verification_worker) { kfree(dasd_reserve_req); + kfree(dasd_vol_info_req); return -ENOMEM; } rawpadpage = (void *)__get_free_page(GFP_KERNEL); if (!rawpadpage) { kfree(path_verification_worker); kfree(dasd_reserve_req); + kfree(dasd_vol_info_req); return -ENOMEM; } ret = ccw_driver_register(&dasd_eckd_driver); @@ -5836,6 +6687,7 @@ dasd_eckd_init(void) else { kfree(path_verification_worker); kfree(dasd_reserve_req); + kfree(dasd_vol_info_req); free_page((unsigned long)rawpadpage); } return ret; diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 5869d2fede35..6943508d0f1d 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -50,16 +50,26 @@ #define DASD_ECKD_CCW_PFX_READ 0xEA #define DASD_ECKD_CCW_RSCK 0xF9 #define DASD_ECKD_CCW_RCD 0xFA +#define DASD_ECKD_CCW_DSO 0xF7 + +/* Define Subssystem Function / Orders */ +#define DSO_ORDER_RAS 0x81 /* - * Perform Subsystem Function / Sub-Orders + * Perform Subsystem Function / Orders */ #define PSF_ORDER_PRSSD 0x18 #define PSF_ORDER_CUIR_RESPONSE 0x1A -#define PSF_SUBORDER_QHA 0x1C #define PSF_ORDER_SSC 0x1D /* + * Perform Subsystem Function / Sub-Orders + */ +#define PSF_SUBORDER_QHA 0x1C /* Query Host Access */ +#define PSF_SUBORDER_VSQ 0x52 /* Volume Storage Query */ +#define PSF_SUBORDER_LCQ 0x53 /* Logical Configuration Query */ + +/* * CUIR response condition codes */ #define PSF_CUIR_INVALID 0x00 @@ -80,10 +90,22 @@ #define CUIR_RESUME 0x02 /* + * Out-of-space (OOS) Codes + */ +#define REPO_WARN 0x01 +#define REPO_EXHAUST 0x02 +#define POOL_WARN 0x03 +#define POOL_EXHAUST 0x04 +#define REPO_RELIEVE 0x05 +#define POOL_RELIEVE 0x06 + +/* * attention message definitions */ #define ATTENTION_LENGTH_CUIR 0x0e #define ATTENTION_FORMAT_CUIR 0x01 +#define ATTENTION_LENGTH_OOS 0x10 +#define ATTENTION_FORMAT_OOS 0x06 #define DASD_ECKD_PG_GROUPED 0x10 @@ -99,6 +121,12 @@ #define DASD_ECKD_PATH_THRHLD 256 #define DASD_ECKD_PATH_INTERVAL 300 +/* + * Maximum number of blocks to be chained + */ +#define DASD_ECKD_MAX_BLOCKS 190 +#define DASD_ECKD_MAX_BLOCKS_RAW 256 + /***************************************************************************** * SECTION: Type Definitions ****************************************************************************/ @@ -116,35 +144,12 @@ struct ch_t { __u16 head; } __attribute__ ((packed)); -struct chs_t { - __u16 cyl; - __u16 head; - __u32 sector; -} __attribute__ ((packed)); - struct chr_t { __u16 cyl; __u16 head; __u8 record; } __attribute__ ((packed)); -struct geom_t { - __u16 cyl; - __u16 head; - __u32 sector; -} __attribute__ ((packed)); - -struct eckd_home { - __u8 skip_control[14]; - __u16 cell_number; - __u8 physical_addr[3]; - __u8 flag; - struct ch_t track_addr; - __u8 reserved; - __u8 key_length; - __u8 reserved2[2]; -} __attribute__ ((packed)); - struct DE_eckd_data { struct { unsigned char perm:2; /* Permissions on this extent */ @@ -387,6 +392,86 @@ struct dasd_rssd_messages { char messages[4087]; } __packed; +/* + * Read Subsystem Data - Volume Storage Query + */ +struct dasd_rssd_vsq { + struct { + __u8 tse:1; + __u8 space_not_available:1; + __u8 ese:1; + __u8 unused:5; + } __packed vol_info; + __u8 unused1; + __u16 extent_pool_id; + __u8 warn_cap_limit; + __u8 warn_cap_guaranteed; + __u16 unused2; + __u32 limit_capacity; + __u32 guaranteed_capacity; + __u32 space_allocated; + __u32 space_configured; + __u32 logical_capacity; +} __packed; + +/* + * Extent Pool Summary + */ +struct dasd_ext_pool_sum { + __u16 pool_id; + __u8 repo_warn_thrshld; + __u8 warn_thrshld; + struct { + __u8 type:1; /* 0 - CKD / 1 - FB */ + __u8 track_space_efficient:1; + __u8 extent_space_efficient:1; + __u8 standard_volume:1; + __u8 extent_size_valid:1; + __u8 capacity_at_warnlevel:1; + __u8 pool_oos:1; + __u8 unused0:1; + __u8 unused1; + } __packed flags; + struct { + __u8 reserved0:1; + __u8 size_1G:1; + __u8 reserved1:5; + __u8 size_16M:1; + } __packed extent_size; + __u8 unused; +} __packed; + +/* + * Read Subsystem Data-Response - Logical Configuration Query - Header + */ +struct dasd_rssd_lcq { + __u16 data_length; /* Length of data returned */ + __u16 pool_count; /* Count of extent pools returned - Max: 448 */ + struct { + __u8 pool_info_valid:1; /* Detailed Information valid */ + __u8 pool_id_volume:1; + __u8 pool_id_cec:1; + __u8 unused0:5; + __u8 unused1; + } __packed header_flags; + char sfi_type[6]; /* Storage Facility Image Type (EBCDIC) */ + char sfi_model[3]; /* Storage Facility Image Model (EBCDIC) */ + __u8 sfi_seq_num[10]; /* Storage Facility Image Sequence Number */ + __u8 reserved[7]; + struct dasd_ext_pool_sum ext_pool_sum[448]; +} __packed; + +struct dasd_oos_message { + __u16 length; + __u8 format; + __u8 code; + __u8 percentage_empty; + __u8 reserved; + __u16 ext_pool_id; + __u16 token; + __u8 unused[6]; +} __packed; + struct dasd_cuir_message { __u16 length; __u8 format; @@ -461,6 +546,42 @@ struct dasd_psf_ssc_data { unsigned char reserved[59]; } __attribute__((packed)); +/* Maximum number of extents for a single Release Allocated Space command */ +#define DASD_ECKD_RAS_EXTS_MAX 110U + +struct dasd_dso_ras_ext_range { + struct ch_t beg_ext; + struct ch_t end_ext; +} __packed; + +/* + * Define Subsytem Operation - Release Allocated Space + */ +struct dasd_dso_ras_data { + __u8 order; + struct { + __u8 message:1; /* Must be zero */ + __u8 reserved1:2; + __u8 vol_type:1; /* 0 - CKD/FBA, 1 - FB */ + __u8 reserved2:4; + } __packed flags; + /* Operation Flags to specify scope */ + struct { + __u8 reserved1:2; + /* Release Space by Extent */ + __u8 by_extent:1; /* 0 - entire volume, 1 - specified extents */ + __u8 guarantee_init:1; + __u8 force_release:1; /* Internal - will be ignored */ + __u16 reserved2:11; + } __packed op_flags; + __u8 lss; + __u8 dev_addr; + __u32 reserved1; + __u8 reserved2[10]; + __u16 nr_exts; /* Defines number of ext_scope - max 110 */ + __u16 reserved3; +} __packed; + /* * some structures and definitions for alias handling @@ -551,6 +672,8 @@ struct dasd_eckd_private { int uses_cdl; struct attrib_data_t attrib; /* e.g. cache operations */ struct dasd_rssd_features features; + struct dasd_rssd_vsq vsq; + struct dasd_ext_pool_sum eps; u32 real_cyl; /* alias managemnet */ @@ -572,7 +695,5 @@ int dasd_alias_remove_device(struct dasd_device *); struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *); void dasd_alias_handle_summary_unit_check(struct work_struct *); void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); -void dasd_alias_lcu_setup_complete(struct dasd_device *); -void dasd_alias_wait_for_lcu_setup(struct dasd_device *); int dasd_alias_update_add_device(struct dasd_device *); #endif /* DASD_ECKD_H */ diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 93bb09da7fdc..5ae64af9ccea 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -386,6 +386,7 @@ void dasd_eer_write(struct dasd_device *device, struct dasd_ccw_req *cqr, dasd_eer_write_standard_trigger(device, cqr, id); break; case DASD_EER_NOPATH: + case DASD_EER_NOSPC: dasd_eer_write_standard_trigger(device, NULL, id); break; case DASD_EER_STATECHANGE: diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 56007a3e7f11..cbb770824226 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -770,27 +770,46 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, } /* - * max_blocks is dependent on the amount of storage that is available - * in the static io buffer for each device. Currently each device has - * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has - * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use - * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In - * addition we have one define extent ccw + 16 bytes of data and a - * locate record ccw for each block (stupid devices!) + 16 bytes of data. - * That makes: - * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum. - * We want to fit two into the available memory so that we can immediately - * start the next request if one finishes off. That makes 100.1 blocks - * for one request. Give a little safety and the result is 96. + * Initialize block layer request queue. */ +static void dasd_fba_setup_blk_queue(struct dasd_block *block) +{ + unsigned int logical_block_size = block->bp_block; + struct request_queue *q = block->request_queue; + unsigned int max_bytes, max_discard_sectors; + int max; + + max = DASD_FBA_MAX_BLOCKS << block->s2b_shift; + blk_queue_flag_set(QUEUE_FLAG_NONROT, q); + q->limits.max_dev_sectors = max; + blk_queue_logical_block_size(q, logical_block_size); + blk_queue_max_hw_sectors(q, max); + blk_queue_max_segments(q, USHRT_MAX); + /* With page sized segments each segment can be translated into one idaw/tidaw */ + blk_queue_max_segment_size(q, PAGE_SIZE); + blk_queue_segment_boundary(q, PAGE_SIZE - 1); + + q->limits.discard_granularity = logical_block_size; + q->limits.discard_alignment = PAGE_SIZE; + + /* Calculate max_discard_sectors and make it PAGE aligned */ + max_bytes = USHRT_MAX * logical_block_size; + max_bytes = ALIGN_DOWN(max_bytes, PAGE_SIZE); + max_discard_sectors = max_bytes / logical_block_size; + + blk_queue_max_discard_sectors(q, max_discard_sectors); + blk_queue_max_write_zeroes_sectors(q, max_discard_sectors); + blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); +} + static struct dasd_discipline dasd_fba_discipline = { .owner = THIS_MODULE, .name = "FBA ", .ebcname = "FBA ", - .max_blocks = 96, .check_device = dasd_fba_check_characteristics, .do_analysis = dasd_fba_do_analysis, .verify_path = dasd_generic_verify_path, + .setup_blk_queue = dasd_fba_setup_blk_queue, .fill_geometry = dasd_fba_fill_geometry, .start_IO = dasd_start_IO, .term_IO = dasd_term_IO, diff --git a/drivers/s390/block/dasd_fba.h b/drivers/s390/block/dasd_fba.h index b14bf1b2c691..8f75df06e893 100644 --- a/drivers/s390/block/dasd_fba.h +++ b/drivers/s390/block/dasd_fba.h @@ -9,6 +9,11 @@ #ifndef DASD_FBA_H #define DASD_FBA_H +/* + * Maximum number of blocks to be chained + */ +#define DASD_FBA_MAX_BLOCKS 96 + struct DE_fba_data { struct { unsigned char perm:2; /* Permissions on this extent */ diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index de6b96036aa4..91c9f9586e0f 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -268,7 +268,6 @@ struct dasd_discipline { struct module *owner; char ebcname[8]; /* a name used for tagging and printks */ char name[8]; /* a name used for tagging and printks */ - int max_blocks; /* maximum number of blocks to be chained */ struct list_head list; /* used for list of disciplines */ @@ -307,6 +306,10 @@ struct dasd_discipline { int (*online_to_ready) (struct dasd_device *); int (*basic_to_known)(struct dasd_device *); + /* + * Initialize block layer request queue. + */ + void (*setup_blk_queue)(struct dasd_block *); /* (struct dasd_device *); * Device operation functions. build_cp creates a ccw chain for * a block device request, start_io starts the request and @@ -367,6 +370,25 @@ struct dasd_discipline { void (*disable_hpf)(struct dasd_device *); int (*hpf_enabled)(struct dasd_device *); void (*reset_path)(struct dasd_device *, __u8); + + /* + * Extent Space Efficient (ESE) relevant functions + */ + int (*is_ese)(struct dasd_device *); + /* Capacity */ + int (*space_allocated)(struct dasd_device *); + int (*space_configured)(struct dasd_device *); + int (*logical_capacity)(struct dasd_device *); + int (*release_space)(struct dasd_device *, struct format_data_t *); + /* Extent Pool */ + int (*ext_pool_id)(struct dasd_device *); + int (*ext_size)(struct dasd_device *); + int (*ext_pool_cap_at_warnlevel)(struct dasd_device *); + int (*ext_pool_warn_thrshld)(struct dasd_device *); + int (*ext_pool_oos)(struct dasd_device *); + int (*ext_pool_exhaust)(struct dasd_device *, struct dasd_ccw_req *); + struct dasd_ccw_req *(*ese_format)(struct dasd_device *, struct dasd_ccw_req *); + void (*ese_read)(struct dasd_ccw_req *); }; extern struct dasd_discipline *dasd_diag_discipline_pointer; @@ -386,6 +408,7 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer; #define DASD_EER_NOPATH 2 #define DASD_EER_STATECHANGE 3 #define DASD_EER_PPRCSUSPEND 4 +#define DASD_EER_NOSPC 5 /* DASD path handling */ @@ -482,8 +505,10 @@ struct dasd_device { spinlock_t mem_lock; void *ccw_mem; void *erp_mem; + void *ese_mem; struct list_head ccw_chunks; struct list_head erp_chunks; + struct list_head ese_chunks; atomic_t tasklet_scheduled; struct tasklet_struct tasklet; @@ -558,6 +583,7 @@ struct dasd_queue { #define DASD_STOPPED_SU 16 /* summary unit check handling */ #define DASD_STOPPED_PM 32 /* pm state transition */ #define DASD_UNRESUMED_PM 64 /* pm resume failed state */ +#define DASD_STOPPED_NOSPC 128 /* no space left */ /* per device flags */ #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ @@ -700,7 +726,9 @@ extern struct kmem_cache *dasd_page_cache; struct dasd_ccw_req * dasd_smalloc_request(int, int, int, struct dasd_device *, struct dasd_ccw_req *); +struct dasd_ccw_req *dasd_fmalloc_request(int, int, int, struct dasd_device *); void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *); +void dasd_ffree_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_wakeup_cb(struct dasd_ccw_req *, void *); struct dasd_device *dasd_alloc_device(void); @@ -727,6 +755,7 @@ void dasd_schedule_block_bh(struct dasd_block *); int dasd_sleep_on(struct dasd_ccw_req *); int dasd_sleep_on_queue(struct list_head *); int dasd_sleep_on_immediatly(struct dasd_ccw_req *); +int dasd_sleep_on_queue_interruptible(struct list_head *); int dasd_sleep_on_interruptible(struct dasd_ccw_req *); void dasd_device_set_timer(struct dasd_device *, int); void dasd_device_clear_timer(struct dasd_device *); @@ -750,6 +779,8 @@ int dasd_generic_restore_device(struct ccw_device *); enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *); void dasd_generic_path_event(struct ccw_device *, int *); int dasd_generic_verify_path(struct dasd_device *, __u8); +void dasd_generic_space_exhaust(struct dasd_device *, struct dasd_ccw_req *); +void dasd_generic_space_avail(struct dasd_device *); int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); char *dasd_get_sense(struct irb *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 8e26001dc11c..9a5f3add325f 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -333,6 +333,59 @@ out_err: return rc; } +static int dasd_release_space(struct dasd_device *device, + struct format_data_t *rdata) +{ + if (!device->discipline->is_ese && !device->discipline->is_ese(device)) + return -ENOTSUPP; + if (!device->discipline->release_space) + return -ENOTSUPP; + + return device->discipline->release_space(device, rdata); +} + +/* + * Release allocated space + */ +static int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp) +{ + struct format_data_t rdata; + struct dasd_device *base; + int rc = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (!argp) + return -EINVAL; + + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + if (base->features & DASD_FEATURE_READONLY || + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { + rc = -EROFS; + goto out_err; + } + if (bdev != bdev->bd_contains) { + pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n", + dev_name(&base->cdev->dev)); + rc = -EINVAL; + goto out_err; + } + + if (copy_from_user(&rdata, argp, sizeof(rdata))) { + rc = -EFAULT; + goto out_err; + } + + rc = dasd_release_space(base, &rdata); + +out_err: + dasd_put_device(base); + + return rc; +} + #ifdef CONFIG_DASD_PROFILE /* * Reset device profile information @@ -595,6 +648,9 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode, case BIODASDREADALLCMB: rc = dasd_ioctl_readall_cmb(block, cmd, argp); break; + case BIODASDRAS: + rc = dasd_ioctl_release_space(bdev, argp); + break; default: /* if the discipline has an ioctl method try it. */ rc = -ENOTTY; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 6c90aa725f23..e71992a3c55f 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -41,7 +41,6 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_kss = !!(sccb->fac98 & 0x01); sclp.has_sipl = !!(sccb->cbl & 0x02); - sclp.has_sipl_g2 = !!(sccb->cbl & 0x04); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; if (sccb->fac91 & 0x40) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 4ebf6d4fc66c..c522e9313c50 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -581,7 +581,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) } EXPORT_SYMBOL(ccwgroup_driver_register); -static int __ccwgroup_match_all(struct device *dev, void *data) +static int __ccwgroup_match_all(struct device *dev, const void *data) { return 1; } @@ -608,9 +608,9 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) } EXPORT_SYMBOL(ccwgroup_driver_unregister); -static int __ccwgroupdev_check_busid(struct device *dev, void *id) +static int __ccwgroupdev_check_busid(struct device *dev, const void *id) { - char *bus_id = id; + const char *bus_id = id; return (strcmp(bus_id, dev_name(dev)) == 0); } diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 8d9f36625ba5..8f080d3fd380 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -203,7 +203,7 @@ static void chsc_cleanup_sch_driver(void) static DEFINE_SPINLOCK(chsc_lock); -static int chsc_subchannel_match_next_free(struct device *dev, void *data) +static int chsc_subchannel_match_next_free(struct device *dev, const void *data) { struct subchannel *sch = to_subchannel(dev); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index e1f2d0eed544..22c55816100b 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -491,10 +491,10 @@ static int css_probe_device(struct subchannel_id schid, struct schib *schib) } static int -check_subchannel(struct device * dev, void * data) +check_subchannel(struct device *dev, const void *data) { struct subchannel *sch; - struct subchannel_id *schid = data; + struct subchannel_id *schid = (void *)data; sch = to_subchannel(dev); return schid_equal(&sch->schid, schid); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 9985b7484a6b..c421899be20f 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -643,10 +643,10 @@ static int ccw_device_add(struct ccw_device *cdev) return device_add(dev); } -static int match_dev_id(struct device *dev, void *data) +static int match_dev_id(struct device *dev, const void *data) { struct ccw_device *cdev = to_ccwdev(dev); - struct ccw_dev_id *dev_id = data; + struct ccw_dev_id *dev_id = (void *)data; return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); } @@ -1699,11 +1699,9 @@ EXPORT_SYMBOL_GPL(ccw_device_force_console); * get ccw_device matching the busid, but only if owned by cdrv */ static int -__ccwdev_check_busid(struct device *dev, void *id) +__ccwdev_check_busid(struct device *dev, const void *id) { - char *bus_id; - - bus_id = id; + const char *bus_id = id; return (strcmp(bus_id, dev_name(dev)) == 0); } diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c index 6bca1d5455d4..9f26d4310bb3 100644 --- a/drivers/s390/cio/scm.c +++ b/drivers/s390/cio/scm.c @@ -174,10 +174,10 @@ out: kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE); } -static int check_address(struct device *dev, void *data) +static int check_address(struct device *dev, const void *data) { struct scm_device *scmdev = to_scm_dev(dev); - struct sale *sale = data; + const struct sale *sale = data; return scmdev->address == sale->sa; } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index b9fc502c58c2..a76b8a8bcbbb 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -208,7 +208,6 @@ static inline int ap_query_configuration(struct ap_config_info *info) return -EINVAL; return ap_qci(info); } -EXPORT_SYMBOL(ap_query_configuration); /** * ap_init_configuration(): Allocate and query configuration array. @@ -1356,16 +1355,16 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func) * Helper function to be used with bus_find_dev * matches for the card device with the given id */ -static int __match_card_device_with_id(struct device *dev, void *data) +static int __match_card_device_with_id(struct device *dev, const void *data) { - return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; + return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long)(void *) data; } /* * Helper function to be used with bus_find_dev * matches for the queue device with a given qid */ -static int __match_queue_device_with_qid(struct device *dev, void *data) +static int __match_queue_device_with_qid(struct device *dev, const void *data) { return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; } @@ -1374,7 +1373,7 @@ static int __match_queue_device_with_qid(struct device *dev, void *data) * Helper function to be used with bus_find_dev * matches any queue device with given queue id */ -static int __match_queue_device_with_queue_id(struct device *dev, void *data) +static int __match_queue_device_with_queue_id(struct device *dev, const void *data) { return is_queue_dev(dev) && AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data; diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 2c9fb1423a39..0604b49a4d32 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -26,7 +26,7 @@ static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev); -static int match_apqn(struct device *dev, void *data) +static int match_apqn(struct device *dev, const void *data) { struct vfio_ap_queue *q = dev_get_drvdata(dev); @@ -115,7 +115,6 @@ static void vfio_ap_wait_for_irqclear(int apqn) * Unregisters the ISC in the GIB when the saved ISC not invalid. * Unpin the guest's page holding the NIB when it exist. * Reset the saved_pfn and saved_isc to invalid values. - * Clear the pointer to the matrix mediated device. * */ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) @@ -127,7 +126,6 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) &q->saved_pfn, 1); q->saved_pfn = 0; q->saved_isc = VFIO_AP_ISC_INVALID; - q->matrix_mdev = NULL; } /** @@ -179,6 +177,7 @@ struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q) status.response_code); end_free: vfio_ap_free_aqic_resources(q); + q->matrix_mdev = NULL; return status; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6d6b14295734..faf43b1d3dbe 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2965,7 +2965,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) del_timer_sync(&phba->fcp_poll_timer); break; case LPFC_PCI_DEV_OC: - /* Stop any OneConnect device sepcific driver timers */ + /* Stop any OneConnect device specific driver timers */ lpfc_sli4_stop_fcf_redisc_wait_timer(phba); break; default: diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 7f0ceb65c3f3..c074631086a4 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -372,7 +372,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, return err; } -static int always_match(struct device *dev, void *data) +static int always_match(struct device *dev, const void *data) { return 1; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 91673351bcf3..75ac046cae52 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3652,7 +3652,7 @@ EXPORT_SYMBOL_GPL(spi_write_then_read); /*-------------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_OF) -static int __spi_of_device_match(struct device *dev, void *data) +static int __spi_of_device_match(struct device *dev, const void *data) { return dev->of_node == data; } @@ -3753,7 +3753,7 @@ static int spi_acpi_controller_match(struct device *dev, const void *data) return ACPI_COMPANION(dev->parent) == data; } -static int spi_acpi_device_match(struct device *dev, void *data) +static int spi_acpi_device_match(struct device *dev, const void *data) { return ACPI_COMPANION(dev) == data; } diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c index 86a8545c8d97..b9841adb7181 100644 --- a/drivers/staging/most/core.c +++ b/drivers/staging/most/core.c @@ -561,13 +561,6 @@ static int split_string(char *buf, char **a, char **b, char **c, char **d) return 0; } -static int match_bus_dev(struct device *dev, void *data) -{ - char *mdev_name = data; - - return !strcmp(dev_name(dev), mdev_name); -} - /** * get_channel - get pointer to channel * @mdev: name of the device interface @@ -579,7 +572,7 @@ static struct most_channel *get_channel(char *mdev, char *mdev_ch) struct most_interface *iface; struct most_channel *c, *tmp; - dev = bus_find_device(&mc.bus, NULL, mdev, match_bus_dev); + dev = bus_find_device_by_name(&mc.bus, NULL, mdev); if (!dev) return NULL; iface = to_most_interface(dev); diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c index d26bdfd11266..25c75b977666 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c @@ -45,7 +45,7 @@ static u32 phy_CalculateBitShift(u32 BitMask) /** * Function: PHY_QueryBBReg * -* OverView: Read "sepcific bits" from BB register +* OverView: Read "specific bits" from BB register * * Input: * struct adapter * Adapter, diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c index ba39647a690c..3199977f1e73 100644 --- a/drivers/thermal/broadcom/bcm2835_thermal.c +++ b/drivers/thermal/broadcom/bcm2835_thermal.c @@ -123,8 +123,6 @@ static void bcm2835_thermal_debugfs(struct platform_device *pdev) struct debugfs_regset32 *regset; data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL); - if (!data->debugfsdir) - return; regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL); if (!regset) diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index 79d214b7291c..5149a817456b 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -698,17 +698,9 @@ DEFINE_SHOW_ATTRIBUTE(powerclamp_debug); static inline void powerclamp_create_debug_files(void) { debug_dir = debugfs_create_dir("intel_powerclamp", NULL); - if (!debug_dir) - return; - - if (!debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir, - cal_data, &powerclamp_debug_fops)) - goto file_error; - return; - -file_error: - debugfs_remove_recursive(debug_dir); + debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir, cal_data, + &powerclamp_debug_fops); } static enum cpuhp_state hp_state; diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index e85d54d1cdf3..ddb4a973c698 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c @@ -75,29 +75,14 @@ static struct dentry *debugfs; static unsigned int pkg_interrupt_cnt; static unsigned int pkg_work_cnt; -static int pkg_temp_debugfs_init(void) +static void pkg_temp_debugfs_init(void) { - struct dentry *d; - debugfs = debugfs_create_dir("pkg_temp_thermal", NULL); - if (!debugfs) - return -ENOENT; - - d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs, - &pkg_interrupt_cnt); - if (!d) - goto err_out; - - d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs, - &pkg_work_cnt); - if (!d) - goto err_out; - return 0; - -err_out: - debugfs_remove_recursive(debugfs); - return -ENOENT; + debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs, + &pkg_interrupt_cnt); + debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs, + &pkg_work_cnt); } /* diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index fcf70a3728b6..43941eb734eb 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -1485,23 +1485,13 @@ DEFINE_SHOW_ATTRIBUTE(regs); static void soctherm_debug_init(struct platform_device *pdev) { struct tegra_soctherm *tegra = platform_get_drvdata(pdev); - struct dentry *root, *file; + struct dentry *root; root = debugfs_create_dir("soctherm", NULL); - if (!root) { - dev_err(&pdev->dev, "failed to create debugfs directory\n"); - return; - } tegra->debugfs_dir = root; - file = debugfs_create_file("reg_contents", 0644, root, - pdev, ®s_fops); - if (!file) { - dev_err(&pdev->dev, "failed to create debugfs file\n"); - debugfs_remove_recursive(tegra->debugfs_dir); - tegra->debugfs_dir = NULL; - } + debugfs_create_file("reg_contents", 0644, root, pdev, ®s_fops); } #else static inline void soctherm_debug_init(struct platform_device *pdev) {} diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 10b56c66fec3..5668a44e0653 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -1967,10 +1967,10 @@ struct tb_sw_lookup { u64 route; }; -static int tb_switch_match(struct device *dev, void *data) +static int tb_switch_match(struct device *dev, const void *data) { struct tb_switch *sw = tb_to_switch(dev); - struct tb_sw_lookup *lookup = data; + const struct tb_sw_lookup *lookup = data; if (!sw) return 0; diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 6de6d4a1a221..7af54d6ed5b8 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -107,6 +107,14 @@ static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count) return got; } +/** + * hvterm_raw_put_chars: send characters to firmware for given vterm adapter + * @vtermno: The virtual terminal number. + * @buf: The characters to send. Because of the underlying hypercall in + * hvc_put_chars(), this buffer must be at least 16 bytes long, even if + * you are sending fewer chars. + * @count: number of chars to send. + */ static int hvterm_raw_put_chars(uint32_t vtermno, const char *buf, int count) { struct hvterm_priv *pv = hvterm_privs[vtermno]; @@ -219,6 +227,7 @@ static const struct hv_ops hvterm_hvsi_ops = { static void udbg_hvc_putc(char c) { int count = -1; + unsigned char bounce_buffer[16]; if (!hvterm_privs[0]) return; @@ -229,7 +238,12 @@ static void udbg_hvc_putc(char c) do { switch(hvterm_privs[0]->proto) { case HV_PROTOCOL_RAW: - count = hvterm_raw_put_chars(0, &c, 1); + /* + * hvterm_raw_put_chars requires at least a 16-byte + * buffer, so go via the bounce buffer + */ + bounce_buffer[0] = c; + count = hvterm_raw_put_chars(0, bounce_buffer, 1); break; case HV_PROTOCOL_HVSI: count = hvterm_hvsi_put_chars(0, &c, 1); diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 63e34d868de8..f8503f8fc44e 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -397,7 +397,7 @@ static const struct uart_ops sunhv_pops = { static struct uart_driver sunhv_reg = { .owner = THIS_MODULE, .driver_name = "sunhv", - .dev_name = "ttyS", + .dev_name = "ttyHV", .major = TTY_MAJOR, }; diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 94573fb68304..6e59d370ef81 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -45,6 +45,7 @@ config USB_ARCH_HAS_HCD config USB tristate "Support for Host-side USB" depends on USB_ARCH_HAS_HCD + select GENERIC_ALLOCATOR select USB_COMMON select NLS # for UTF-8 strings ---help--- diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index f641342cdec0..1359b78a624e 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -16,6 +16,7 @@ #include <linux/io.h> #include <linux/dma-mapping.h> #include <linux/dmapool.h> +#include <linux/genalloc.h> #include <linux/usb.h> #include <linux/usb/hcd.h> @@ -67,7 +68,7 @@ int hcd_buffer_create(struct usb_hcd *hcd) if (!IS_ENABLED(CONFIG_HAS_DMA) || (!is_device_dma_capable(hcd->self.sysdev) && - !(hcd->driver->flags & HCD_LOCAL_MEM))) + !hcd->localmem_pool)) return 0; for (i = 0; i < HCD_BUFFER_POOLS; i++) { @@ -124,10 +125,12 @@ void *hcd_buffer_alloc( if (size == 0) return NULL; + if (hcd->localmem_pool) + return gen_pool_dma_alloc(hcd->localmem_pool, size, dma); + /* some USB hosts just use PIO */ if (!IS_ENABLED(CONFIG_HAS_DMA) || - (!is_device_dma_capable(bus->sysdev) && - !(hcd->driver->flags & HCD_LOCAL_MEM))) { + !is_device_dma_capable(bus->sysdev)) { *dma = ~(dma_addr_t) 0; return kmalloc(size, mem_flags); } @@ -152,9 +155,13 @@ void hcd_buffer_free( if (!addr) return; + if (hcd->localmem_pool) { + gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size); + return; + } + if (!IS_ENABLED(CONFIG_HAS_DMA) || - (!is_device_dma_capable(bus->sysdev) && - !(hcd->driver->flags & HCD_LOCAL_MEM))) { + !is_device_dma_capable(bus->sysdev)) { kfree(addr); return; } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e2f316ac8b01..b265ab5405f9 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -942,9 +942,9 @@ error: return ret; } -static int match_devt(struct device *dev, void *data) +static int match_devt(struct device *dev, const void *data) { - return dev->devt == (dev_t) (unsigned long) data; + return dev->devt == (dev_t)(unsigned long)(void *)data; } static struct usb_device *usbdev_lookup_by_devt(dev_t devt) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 94d22551fc1b..88533938ce19 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -29,6 +29,8 @@ #include <linux/workqueue.h> #include <linux/pm_runtime.h> #include <linux/types.h> +#include <linux/genalloc.h> +#include <linux/io.h> #include <linux/phy/phy.h> #include <linux/usb.h> @@ -1345,14 +1347,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); * using regular system memory - like pci devices doing bus mastering. * * To support host controllers with limited dma capabilities we provide dma - * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag. + * bounce buffers. This feature can be enabled by initializing + * hcd->localmem_pool using usb_hcd_setup_local_mem(). * For this to work properly the host controller code must first use the * function dma_declare_coherent_memory() to point out which memory area * that should be used for dma allocations. * - * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for - * dma using dma_alloc_coherent() which in turn allocates from the memory - * area pointed out with dma_declare_coherent_memory(). + * The initialized hcd->localmem_pool then tells the usb code to allocate all + * data for dma using the genalloc API. * * So, to summarize... * @@ -1362,9 +1364,6 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); * (a) "normal" kernel memory is no good, and * (b) there's not enough to share * - * - The only *portable* hook for such stuff in the - * DMA framework is dma_declare_coherent_memory() - * * - So we use that, even though the primary requirement * is that the memory be "local" (hence addressable * by that device), not "coherent". @@ -1531,7 +1530,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, urb->setup_dma)) return -EAGAIN; urb->transfer_flags |= URB_SETUP_MAP_SINGLE; - } else if (hcd->driver->flags & HCD_LOCAL_MEM) { + } else if (hcd->localmem_pool) { ret = hcd_alloc_coherent( urb->dev->bus, mem_flags, &urb->setup_dma, @@ -1601,7 +1600,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, else urb->transfer_flags |= URB_DMA_MAP_SINGLE; } - } else if (hcd->driver->flags & HCD_LOCAL_MEM) { + } else if (hcd->localmem_pool) { ret = hcd_alloc_coherent( urb->dev->bus, mem_flags, &urb->transfer_dma, @@ -3039,6 +3038,40 @@ usb_hcd_platform_shutdown(struct platform_device *dev) } EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); +int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr, + dma_addr_t dma, size_t size) +{ + int err; + void *local_mem; + + hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, 4, + dev_to_node(hcd->self.sysdev), + dev_name(hcd->self.sysdev)); + if (IS_ERR(hcd->localmem_pool)) + return PTR_ERR(hcd->localmem_pool); + + local_mem = devm_memremap(hcd->self.sysdev, phys_addr, + size, MEMREMAP_WC); + if (!local_mem) + return -ENOMEM; + + /* + * Here we pass a dma_addr_t but the arg type is a phys_addr_t. + * It's not backed by system memory and thus there's no kernel mapping + * for it. + */ + err = gen_pool_add_virt(hcd->localmem_pool, (unsigned long)local_mem, + dma, size, dev_to_node(hcd->self.sysdev)); + if (err < 0) { + dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n", + err); + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(usb_hcd_setup_local_mem); + /*-------------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_USB_MON) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 5a0df527a8ca..0ab8738047da 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -325,9 +325,9 @@ struct find_interface_arg { struct device_driver *drv; }; -static int __find_interface(struct device *dev, void *data) +static int __find_interface(struct device *dev, const void *data) { - struct find_interface_arg *arg = data; + const struct find_interface_arg *arg = data; struct usb_interface *intf; if (!is_usb_interface(dev)) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index cdafa97f632d..9da7e22848c9 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -559,7 +559,7 @@ static int ehci_init(struct usb_hcd *hcd) ehci->command = temp; /* Accept arbitrarily long scatter-gather lists */ - if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + if (!hcd->localmem_pool) hcd->self.sg_tablesize = ~0; /* Prepare for unlinking active QHs */ diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index e835a22b12af..77cc36efae95 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -4996,7 +4996,7 @@ static int hcd_fotg210_init(struct usb_hcd *hcd) fotg210->command = temp; /* Accept arbitrarily long scatter-gather lists */ - if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + if (!hcd->localmem_pool) hcd->self.sg_tablesize = ~0; return 0; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 210181fd98d2..b457fdaff297 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -40,6 +40,7 @@ #include <linux/dmapool.h> #include <linux/workqueue.h> #include <linux/debugfs.h> +#include <linux/genalloc.h> #include <asm/io.h> #include <asm/irq.h> @@ -447,7 +448,7 @@ static int ohci_init (struct ohci_hcd *ohci) struct usb_hcd *hcd = ohci_to_hcd(ohci); /* Accept arbitrarily long scatter-gather lists */ - if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + if (!hcd->localmem_pool) hcd->self.sg_tablesize = ~0; if (distrust_firmware) @@ -505,8 +506,15 @@ static int ohci_init (struct ohci_hcd *ohci) timer_setup(&ohci->io_watchdog, io_watchdog_func, 0); ohci->prev_frame_no = IO_WATCHDOG_OFF; - ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); + if (hcd->localmem_pool) + ohci->hcca = gen_pool_dma_alloc_align(hcd->localmem_pool, + sizeof(*ohci->hcca), + &ohci->hcca_dma, 256); + else + ohci->hcca = dma_alloc_coherent(hcd->self.controller, + sizeof(*ohci->hcca), + &ohci->hcca_dma, + GFP_KERNEL); if (!ohci->hcca) return -ENOMEM; @@ -990,9 +998,14 @@ static void ohci_stop (struct usb_hcd *hcd) remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { - dma_free_coherent (hcd->self.controller, - sizeof *ohci->hcca, - ohci->hcca, ohci->hcca_dma); + if (hcd->localmem_pool) + gen_pool_free(hcd->localmem_pool, + (unsigned long)ohci->hcca, + sizeof(*ohci->hcca)); + else + dma_free_coherent(hcd->self.controller, + sizeof(*ohci->hcca), + ohci->hcca, ohci->hcca_dma); ohci->hcca = NULL; ohci->hcca_dma = 0; } diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 3965ac0341eb..1425335c6baf 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -36,6 +36,13 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) static int ohci_mem_init (struct ohci_hcd *ohci) { + /* + * HCs with local memory allocate from localmem_pool so there's + * no need to create the below dma pools. + */ + if (ohci_to_hcd(ohci)->localmem_pool) + return 0; + ohci->td_cache = dma_pool_create ("ohci_td", ohci_to_hcd(ohci)->self.controller, sizeof (struct td), @@ -84,8 +91,13 @@ td_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct td *td; + struct usb_hcd *hcd = ohci_to_hcd(hc); - td = dma_pool_zalloc (hc->td_cache, mem_flags, &dma); + if (hcd->localmem_pool) + td = gen_pool_dma_zalloc_align(hcd->localmem_pool, + sizeof(*td), &dma, 32); + else + td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma); if (td) { /* in case hc fetches it, make it look dead */ td->hwNextTD = cpu_to_hc32 (hc, dma); @@ -99,6 +111,7 @@ static void td_free (struct ohci_hcd *hc, struct td *td) { struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; + struct usb_hcd *hcd = ohci_to_hcd(hc); while (*prev && *prev != td) prev = &(*prev)->td_hash; @@ -106,7 +119,12 @@ td_free (struct ohci_hcd *hc, struct td *td) *prev = td->td_hash; else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0) ohci_dbg (hc, "no hash for td %p\n", td); - dma_pool_free (hc->td_cache, td, td->td_dma); + + if (hcd->localmem_pool) + gen_pool_free(hcd->localmem_pool, (unsigned long)td, + sizeof(*td)); + else + dma_pool_free(hc->td_cache, td, td->td_dma); } /*-------------------------------------------------------------------------*/ @@ -117,8 +135,13 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct ed *ed; + struct usb_hcd *hcd = ohci_to_hcd(hc); - ed = dma_pool_zalloc (hc->ed_cache, mem_flags, &dma); + if (hcd->localmem_pool) + ed = gen_pool_dma_zalloc_align(hcd->localmem_pool, + sizeof(*ed), &dma, 16); + else + ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma); if (ed) { INIT_LIST_HEAD (&ed->td_list); ed->dma = dma; @@ -129,6 +152,12 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags) static void ed_free (struct ohci_hcd *hc, struct ed *ed) { - dma_pool_free (hc->ed_cache, ed, ed->dma); + struct usb_hcd *hcd = ohci_to_hcd(hc); + + if (hcd->localmem_pool) + gen_pool_free(hcd->localmem_pool, (unsigned long)ed, + sizeof(*ed)); + else + dma_pool_free(hc->ed_cache, ed, ed->dma); } diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index c26228c25f99..c158cda9e4b9 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -49,7 +49,7 @@ static const struct hc_driver ohci_sm501_hc_driver = { * generic hardware linkage */ .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM, + .flags = HCD_USB11 | HCD_MEMORY, /* * basic lifecycle operations @@ -110,40 +110,18 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) goto err0; } - /* The sm501 chip is equipped with local memory that may be used - * by on-chip devices such as the video controller and the usb host. - * This driver uses dma_declare_coherent_memory() to make sure - * usb allocations with dma_alloc_coherent() allocate from - * this local memory. The dma_handle returned by dma_alloc_coherent() - * will be an offset starting from 0 for the first local memory byte. - * - * So as long as data is allocated using dma_alloc_coherent() all is - * fine. This is however not always the case - buffers may be allocated - * using kmalloc() - so the usb core needs to be told that it must copy - * data into our local memory if the buffers happen to be placed in - * regular memory. The HCD_LOCAL_MEM flag does just that. - */ - - retval = dma_declare_coherent_memory(dev, mem->start, - mem->start - mem->parent->start, - resource_size(mem)); - if (retval) { - dev_err(dev, "cannot declare coherent memory\n"); - goto err1; - } - /* allocate, reserve and remap resources for registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev, "no resource definition for registers\n"); retval = -ENOENT; - goto err2; + goto err1; } hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { retval = -ENOMEM; - goto err2; + goto err1; } hcd->rsrc_start = res->start; @@ -164,6 +142,25 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) ohci_hcd_init(hcd_to_ohci(hcd)); + /* The sm501 chip is equipped with local memory that may be used + * by on-chip devices such as the video controller and the usb host. + * This driver uses genalloc so that usb allocations with + * gen_pool_dma_alloc() allocate from this local memory. The dma_handle + * returned by gen_pool_dma_alloc() will be an offset starting from 0 + * for the first local memory byte. + * + * So as long as data is allocated using gen_pool_dma_alloc() all is + * fine. This is however not always the case - buffers may be allocated + * using kmalloc() - so the usb core needs to be told that it must copy + * data into our local memory if the buffers happen to be placed in + * regular memory. A non-null hcd->localmem_pool initialized by the + * the call to usb_hcd_setup_local_mem() below does just that. + */ + + if (usb_hcd_setup_local_mem(hcd, mem->start, + mem->start - mem->parent->start, + resource_size(mem)) < 0) + goto err5; retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) goto err5; @@ -181,8 +178,6 @@ err4: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err3: usb_put_hcd(hcd); -err2: - dma_release_declared_memory(dev); err1: release_mem_region(mem->start, resource_size(mem)); err0: @@ -197,7 +192,6 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); - dma_release_declared_memory(&pdev->dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (mem) release_mem_region(mem->start, resource_size(mem)); diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index f88a0370659f..d5a293a707b6 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -153,7 +153,7 @@ static const struct hc_driver ohci_tmio_hc_driver = { /* generic hardware linkage */ .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM, + .flags = HCD_USB11 | HCD_MEMORY, /* basic lifecycle operations */ .start = ohci_tmio_start, @@ -224,11 +224,6 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev) goto err_ioremap_regs; } - ret = dma_declare_coherent_memory(&dev->dev, sram->start, sram->start, - resource_size(sram)); - if (ret) - goto err_dma_declare; - if (cell->enable) { ret = cell->enable(dev); if (ret) @@ -239,6 +234,11 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev) ohci = hcd_to_ohci(hcd); ohci_hcd_init(ohci); + ret = usb_hcd_setup_local_mem(hcd, sram->start, sram->start, + resource_size(sram)); + if (ret < 0) + goto err_enable; + ret = usb_add_hcd(hcd, irq, 0); if (ret) goto err_add_hcd; @@ -254,8 +254,6 @@ err_add_hcd: if (cell->disable) cell->disable(dev); err_enable: - dma_release_declared_memory(&dev->dev); -err_dma_declare: iounmap(hcd->regs); err_ioremap_regs: iounmap(tmio->ccr); @@ -276,7 +274,6 @@ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev) tmio_stop_hc(dev); if (cell->disable) cell->disable(dev); - dma_release_declared_memory(&dev->dev); iounmap(hcd->regs); iounmap(tmio->ccr); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index ef4813bfc5bf..b015b00774b2 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -385,6 +385,8 @@ struct ohci_hcd { /* * memory management for queue data structures + * + * @td_cache and @ed_cache are %NULL if &usb_hcd.localmem_pool is used. */ struct dma_pool *td_cache; struct dma_pool *ed_cache; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 98deb5f64268..03bc59755123 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -581,7 +581,7 @@ static int uhci_start(struct usb_hcd *hcd) hcd->uses_new_polling = 1; /* Accept arbitrarily long scatter-gather lists */ - if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + if (!hcd->localmem_pool) hcd->self.sg_tablesize = ~0; spin_lock_init(&uhci->lock); diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index a3cb25cb74f8..d16dfc320faa 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -118,9 +118,9 @@ static const struct of_device_id omap_control_usb_id_table[] = { MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); static struct platform_driver am335x_control_driver; -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return dev->of_node == node && dev->driver == &am335x_control_driver.driver; } diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index 93b7d6a30aad..6cf6fbd39237 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -142,9 +142,9 @@ static struct i2c_driver isp1301_driver = { module_i2c_driver(isp1301_driver); -static int match(struct device *dev, void *data) +static int match(struct device *dev, const void *data) { - struct device_node *node = (struct device_node *)data; + const struct device_node *node = (const struct device_node *)data; return (dev->of_node == node) && (dev->driver == &isp1301_driver.driver); } diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c index 0adf0683cf08..99941ae1f3a1 100644 --- a/drivers/video/fbdev/au1100fb.c +++ b/drivers/video/fbdev/au1100fb.c @@ -340,14 +340,12 @@ int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) */ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) { - struct au1100fb_device *fbdev; - - fbdev = to_au1100fb_device(fbi); + struct au1100fb_device *fbdev = to_au1100fb_device(fbi); - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6 - return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len); + return dma_mmap_coherent(fbdev->dev, vma, fbdev->fb_mem, fbdev->fb_phys, + fbdev->fb_len); } static struct fb_ops au1100fb_ops = @@ -412,7 +410,6 @@ static int au1100fb_drv_probe(struct platform_device *dev) { struct au1100fb_device *fbdev; struct resource *regs_res; - unsigned long page; struct clk *c; /* Allocate new device private */ @@ -424,6 +421,7 @@ static int au1100fb_drv_probe(struct platform_device *dev) goto failed; platform_set_drvdata(dev, (void *)fbdev); + fbdev->dev = &dev->dev; /* Allocate region for our registers and map them */ regs_res = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -472,20 +470,6 @@ static int au1100fb_drv_probe(struct platform_device *dev) au1100fb_fix.smem_start = fbdev->fb_phys; au1100fb_fix.smem_len = fbdev->fb_len; - /* - * Set page reserved so that mmap will work. This is necessary - * since we'll be remapping normal memory. - */ - for (page = (unsigned long)fbdev->fb_mem; - page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len); - page += PAGE_SIZE) { -#ifdef CONFIG_DMA_NONCOHERENT - SetPageReserved(virt_to_page(CAC_ADDR((void *)page))); -#else - SetPageReserved(virt_to_page(page)); -#endif - } - print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); diff --git a/drivers/video/fbdev/au1100fb.h b/drivers/video/fbdev/au1100fb.h index 9af19939a9c6..e7239bceefd3 100644 --- a/drivers/video/fbdev/au1100fb.h +++ b/drivers/video/fbdev/au1100fb.h @@ -110,6 +110,7 @@ struct au1100fb_device { dma_addr_t fb_phys; int panel_idx; struct clk *lcdclk; + struct device *dev; }; /********************************************************************/ diff --git a/drivers/visorbus/visorbus_main.c b/drivers/visorbus/visorbus_main.c index 0b2434cc4ecd..152fd29f04f2 100644 --- a/drivers/visorbus/visorbus_main.c +++ b/drivers/visorbus/visorbus_main.c @@ -171,10 +171,10 @@ struct visor_busdev { u32 dev_no; }; -static int match_visorbus_dev_by_id(struct device *dev, void *data) +static int match_visorbus_dev_by_id(struct device *dev, const void *data) { struct visor_device *vdev = to_visor_device(dev); - struct visor_busdev *id = data; + const struct visor_busdev *id = data; if (vdev->chipset_bus_no == id->bus_no && vdev->chipset_dev_no == id->dev_no) diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index e2ad44816359..921291025680 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c @@ -143,24 +143,18 @@ static void bcm_kona_wdt_debug_init(struct platform_device *pdev) wdt->debugfs = NULL; dir = debugfs_create_dir(BCM_KONA_WDT_NAME, NULL); - if (IS_ERR_OR_NULL(dir)) - return; - if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt, - &bcm_kona_fops)) - wdt->debugfs = dir; - else - debugfs_remove_recursive(dir); + debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt, + &bcm_kona_fops); + wdt->debugfs = dir; } static void bcm_kona_wdt_debug_exit(struct platform_device *pdev) { struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev); - if (wdt && wdt->debugfs) { + if (wdt) debugfs_remove_recursive(wdt->debugfs); - wdt->debugfs = NULL; - } } #else diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c index 8023cf28657a..96a770938ff0 100644 --- a/drivers/watchdog/mei_wdt.c +++ b/drivers/watchdog/mei_wdt.c @@ -539,38 +539,23 @@ static void dbgfs_unregister(struct mei_wdt *wdt) wdt->dbgfs_dir = NULL; } -static int dbgfs_register(struct mei_wdt *wdt) +static void dbgfs_register(struct mei_wdt *wdt) { - struct dentry *dir, *f; + struct dentry *dir; dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!dir) - return -ENOMEM; - wdt->dbgfs_dir = dir; - f = debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state); - if (!f) - goto err; - f = debugfs_create_file("activation", S_IRUSR, - dir, wdt, &dbgfs_fops_activation); - if (!f) - goto err; + debugfs_create_file("state", S_IRUSR, dir, wdt, &dbgfs_fops_state); - return 0; -err: - dbgfs_unregister(wdt); - return -ENODEV; + debugfs_create_file("activation", S_IRUSR, dir, wdt, + &dbgfs_fops_activation); } #else static inline void dbgfs_unregister(struct mei_wdt *wdt) {} - -static inline int dbgfs_register(struct mei_wdt *wdt) -{ - return 0; -} +static inline void dbgfs_register(struct mei_wdt *wdt) {} #endif /* CONFIG_DEBUG_FS */ static int mei_wdt_probe(struct mei_cl_device *cldev, @@ -623,8 +608,7 @@ static int mei_wdt_probe(struct mei_cl_device *cldev, if (ret) goto err_disable; - if (dbgfs_register(wdt)) - dev_warn(&cldev->dev, "cannot register debugfs\n"); + dbgfs_register(wdt); return 0; diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 469dfbd6cf90..4c339c7e66e5 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -264,8 +264,7 @@ void gntdev_put_map(struct gntdev_priv *priv, struct gntdev_grant_map *map) /* ------------------------------------------------------------------ */ -static int find_grant_ptes(pte_t *pte, pgtable_t token, - unsigned long addr, void *data) +static int find_grant_ptes(pte_t *pte, unsigned long addr, void *data) { struct gntdev_grant_map *map = data; unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT; @@ -292,8 +291,7 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token, } #ifdef CONFIG_X86 -static int set_grant_ptes_as_special(pte_t *pte, pgtable_t token, - unsigned long addr, void *data) +static int set_grant_ptes_as_special(pte_t *pte, unsigned long addr, void *data) { set_pte_at(current->mm, addr, pte, pte_mkspecial(*pte)); return 0; diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 1ff38d8036e9..2f5ce7230a43 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -731,8 +731,7 @@ struct remap_pfn { unsigned long i; }; -static int remap_pfn_fn(pte_t *ptep, pgtable_t token, unsigned long addr, - void *data) +static int remap_pfn_fn(pte_t *ptep, unsigned long addr, void *data) { struct remap_pfn *r = data; struct page *page = r->pages[r->i]; @@ -966,8 +965,7 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma) * on a per pfn/pte basis. Mapping calls that fail with ENOENT * can be then retried until success. */ -static int is_mapped_fn(pte_t *pte, struct page *pmd_page, - unsigned long addr, void *data) +static int is_mapped_fn(pte_t *pte, unsigned long addr, void *data) { return pte_none(*pte) ? 0 : -EBUSY; } diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c index e7df65d32c91..ba883a80b3c0 100644 --- a/drivers/xen/xlate_mmu.c +++ b/drivers/xen/xlate_mmu.c @@ -93,8 +93,7 @@ static void setup_hparams(unsigned long gfn, void *data) info->fgfn++; } -static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, - void *data) +static int remap_pte_fn(pte_t *ptep, unsigned long addr, void *data) { struct remap_data *info = data; struct page *page = info->pages[info->index++]; |