From e1f6c9ca6daef8e86b237e6bee09ee71ddace734 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Mon, 4 Nov 2013 14:51:20 -0600 Subject: [PATCH 01/97] scripts: Add pre-generated copy for arm-nilrt-linux-gnueabi-elfconfig.h In preparation for upgrading to gcc 4.7 we need a copy of the pre-generated header arm-nilrt-linux-gnueabi-elfconfig.h that matches the toolchain prefix. This file is identical to: arm-none-linux-gnueabi-elfconfig.h Signed-off-by: Gratian Crisan Acked-by: Brad Mouring --- scripts/mod/arm-nilrt-linux-gnueabi-elfconfig.h | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 scripts/mod/arm-nilrt-linux-gnueabi-elfconfig.h diff --git a/scripts/mod/arm-nilrt-linux-gnueabi-elfconfig.h b/scripts/mod/arm-nilrt-linux-gnueabi-elfconfig.h new file mode 100644 index 0000000000000..807d67db5eed8 --- /dev/null +++ b/scripts/mod/arm-nilrt-linux-gnueabi-elfconfig.h @@ -0,0 +1,4 @@ +#define KERNEL_ELFCLASS ELFCLASS32 +#define KERNEL_ELFDATA ELFDATA2LSB +#define HOST_ELFCLASS ELFCLASS32 +#define HOST_ELFDATA ELFDATA2LSB From ca1a7bc48138f6fc1f0b2d28d4ad38727bcccca8 Mon Sep 17 00:00:00 2001 From: Brad Mouring Date: Wed, 13 Nov 2013 15:00:01 -0600 Subject: [PATCH 02/97] scripts: Add pre-generated copy for x86_64 In order to support building the tools needed for on-target versioning for x86_64 targets (since HOSTCC continues to be x86), adding a pregenerated header for that toolchain. Signed-off-by: Brad Mouring Acked-by: Gratian Crisan --- scripts/mod/x86_64-nilrt-linux-elfconfig.h | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 scripts/mod/x86_64-nilrt-linux-elfconfig.h diff --git a/scripts/mod/x86_64-nilrt-linux-elfconfig.h b/scripts/mod/x86_64-nilrt-linux-elfconfig.h new file mode 100644 index 0000000000000..6dff0d9351a82 --- /dev/null +++ b/scripts/mod/x86_64-nilrt-linux-elfconfig.h @@ -0,0 +1,4 @@ +#define KERNEL_ELFCLASS ELFCLASS64 +#define KERNEL_ELFDATA ELFDATA2LSB +#define HOST_ELFCLASS ELFCLASS64 +#define HOST_ELFDATA ELFDATA2LSB From e74d4fd5b48701ac3c64ae4547835250f0cad988 Mon Sep 17 00:00:00 2001 From: Ben Shelton Date: Tue, 1 Apr 2014 11:31:31 -0500 Subject: [PATCH 03/97] shared: Adding mcopy syscall for Zynq Signed-off-by: Ben Shelton Acked-by: Scot Salmon Acked-by: Terry Wilcox Natinst-ReviewBoard-ID: 69848 [gratian: convert to new syscall table format for arm] Signed-off-by: Gratian Crisan [cvadrevu: Updated to just add missing Zynq code] Signed-off-by: Chaitanya Vadrevu --- arch/arm/tools/syscall.tbl | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl index b07e699aaa3c2..a176b55d1dc3e 100644 --- a/arch/arm/tools/syscall.tbl +++ b/arch/arm/tools/syscall.tbl @@ -484,3 +484,4 @@ 467 common open_tree_attr sys_open_tree_attr 468 common file_getattr sys_file_getattr 469 common file_setattr sys_file_setattr +470 common mcopy sys_mcopy From 4918d56439d66d1fba980be81dcea5f6f301ea85 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 14 Mar 2014 16:52:23 -0500 Subject: [PATCH 04/97] nirtfeatures: set HARD_BOOT_N if necessary when the driver loads On systems where FPGA autoload is controlled by software, we need a way to determine if a system has just had power applied. This is necessary to implement the autoload on every power-on feature. Once the FPGA has been autloaded after power-on, software sets a bit in the CPLD so that subsequent (non power-on) resets don't cause the FPGA to be autoloaded again. The CPLD provides the HARD_BOOT_N bit for this purpose. On systems where FPGA autoload is controlled by hardware, such as Smasher, we need to set this bit at some point after power-on so that software can correctly determine the reset state of the controller. Since software has no insight into the status of FPGA autoload on these systems, we can just set this bit if necessary when the driver loads. Signed-off-by: Jeff Westfahl [cvadrevu: Fixed trivial conflicts with 91d93a7e35e0 ("nirtfeatures: Only register bi-color LEDs on supported targets")] 6c83dd7f8821 ("nirtfeatures: Added NI RT features driver")] Signed-off-by: Chaitanya Vadrevu --- drivers/misc/nirtfeatures.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 449efb186f910..835ac7c89d197 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -1434,6 +1434,7 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) struct nirtfeatures *nirtfeatures; acpi_status acpi_ret; u8 bpinfo; + u8 procmode; int err, i; nirtfeatures = devm_kzalloc(&device->dev, sizeof(*nirtfeatures), @@ -1487,6 +1488,13 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) nirtfeatures->revision[3] = inb(nirtfeatures->io_base + NIRTF_HOUR); nirtfeatures->revision[4] = inb(nirtfeatures->io_base + NIRTF_MINUTE); + procmode = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + if (!(procmode & NIRTF_PROCESSOR_MODE_HARD_BOOT_N)) { + procmode |= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; + outb(procmode, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + } + err = nirtfeatures_create_leds(nirtfeatures); if (err) return err; From aac93a25bd7f90c83467179364f3b4cfb1253125 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 10 Apr 2014 16:59:41 -0500 Subject: [PATCH 05/97] nirtfeatures: BIOS writes HARD_BOOT_N, so driver doesn't need to The BIOS will set the HARD_BOOT_N bit at post, so the driver no longer needs to do this. Signed-off-by: Jeff Westfahl [cvadrevu: Fixed trivial conflicts with 91d93a7e35e00: ("nirtfeatures: Only register bi-color LEDs on supported targets") f3ab444549a08: ("nirtfeatures: Use managed resource allocation")] Signed-off-by: Chaitanya Vadrevu --- drivers/misc/nirtfeatures.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 835ac7c89d197..449efb186f910 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -1434,7 +1434,6 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) struct nirtfeatures *nirtfeatures; acpi_status acpi_ret; u8 bpinfo; - u8 procmode; int err, i; nirtfeatures = devm_kzalloc(&device->dev, sizeof(*nirtfeatures), @@ -1488,13 +1487,6 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) nirtfeatures->revision[3] = inb(nirtfeatures->io_base + NIRTF_HOUR); nirtfeatures->revision[4] = inb(nirtfeatures->io_base + NIRTF_MINUTE); - procmode = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - - if (!(procmode & NIRTF_PROCESSOR_MODE_HARD_BOOT_N)) { - procmode |= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; - outb(procmode, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - } - err = nirtfeatures_create_leds(nirtfeatures); if (err) return err; From d1a9df494bff3cb256aa57a31a85ef0930621cac Mon Sep 17 00:00:00 2001 From: Francesca Ramadori Date: Thu, 26 Mar 2015 16:47:37 -0500 Subject: [PATCH 06/97] leds-ni793x: Add leds-ni793x driver to control the RT User 1 LED Add the leds-ni793x driver which controls the RT User 1 LED on the NI-793xR devices. The RT User 1 LED control is exposed through the Zynq FPGA logic. Signed-off-by: Francesca Ramadori Signed-off-by: Brad Mouring Acked-by: Josh Cartwright Acked-by: Ben Shelton [cvadrevu: Fixed trivial conflicts due to newer modules] [cvadrevu: Updated ni793x_leds_remove signature for newer kernel] [cvadrevu: Replaced ni793x_leds_ids with ni793x_led_ids] Signed-off-by: Chaitanya Vadrevu --- drivers/leds/Kconfig | 10 ++++ drivers/leds/Makefile | 1 + drivers/leds/leds-ni793x.c | 114 +++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 drivers/leds/leds-ni793x.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 06e6291be11b2..40a0a6116ffca 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -936,6 +936,16 @@ config LEDS_USER support in kernel. To compile this driver as a module, choose 'm' here: the module will be called uleds. +config LEDS_NI793X + tristate "LED support for NI 793xR devices" + depends on LEDS_CLASS + help + This option enables support for the User1 LED on the NI 793xR family + of devices. + + To compile this driver as a module, choose M here: the module will be + called leds-ni793x. + config LEDS_NIC78BX tristate "LED support for NI PXI NIC78bx devices" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 9a0333ec1a861..db2dd3c511410 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o +obj-$(CONFIG_LEDS_NI793X) += leds-ni793x.o obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o obj-$(CONFIG_LEDS_NS2) += leds-ns2.o obj-$(CONFIG_LEDS_OT200) += leds-ot200.o diff --git a/drivers/leds/leds-ni793x.c b/drivers/leds/leds-ni793x.c new file mode 100644 index 0000000000000..b9edcc4bfb0ba --- /dev/null +++ b/drivers/leds/leds-ni793x.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +#define USER1_STATUS_BIT BIT(0) +#define USER1_OFF_CMD 0x1 +#define USER1_ON_CMD 0x2 + +struct ni793x_led { + void __iomem *user1; + struct led_classdev cdev; +}; + +static inline struct ni793x_led *to_ni793x_led(struct led_classdev *cdev) +{ + return container_of(cdev, struct ni793x_led, cdev); +} + +static void ni793x_led_set_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct ni793x_led *led = to_ni793x_led(cdev); + + if (brightness == LED_OFF) + writel_relaxed(USER1_OFF_CMD, led->user1); + else + writel_relaxed(USER1_ON_CMD, led->user1); +} + +static enum led_brightness +ni793x_led_get_brightness(struct led_classdev *cdev) +{ + struct ni793x_led *led = to_ni793x_led(cdev); + + return readl_relaxed(led->user1) & USER1_STATUS_BIT; +} + +static int ni793x_leds_probe(struct platform_device *pdev) +{ + struct device_node *node; + struct ni793x_led *led; + struct resource *res; + + led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + platform_set_drvdata(pdev, led); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + led->user1 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(led->user1)) + return PTR_ERR(led->user1); + + node = of_get_child_by_name(pdev->dev.of_node, "user1"); + if (!node) { + dev_err(&pdev->dev, "user1 LED description not found\n"); + return -ENOENT; + } + + led->cdev.name = of_get_property(node, "label", NULL) ? : node->name; + led->cdev.default_trigger = of_get_property(node, + "linux,default-trigger", + NULL); + led->cdev.max_brightness = 1; + led->cdev.brightness_set = ni793x_led_set_brightness; + led->cdev.brightness_get = ni793x_led_get_brightness; + + return led_classdev_register(&pdev->dev, &led->cdev); +} + +static void ni793x_leds_remove(struct platform_device *pdev) +{ + struct ni793x_led *led = platform_get_drvdata(pdev); + + led_classdev_unregister(&led->cdev); +} + +static const struct of_device_id ni793x_led_ids[] = { + { .compatible = "ni,led-793x" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ni793x_led_ids); + +static struct platform_driver ni793x_leds_driver = { + .driver = { + .name = "leds-ni793x", + .of_match_table = of_match_ptr(ni793x_led_ids), + }, + .probe = ni793x_leds_probe, + .remove = ni793x_leds_remove, +}; +module_platform_driver(ni793x_leds_driver); + +MODULE_DESCRIPTION("Driver for RT User1 LED on FlexRIO NI-793xR Products"); +MODULE_AUTHOR("National Instruments"); +MODULE_LICENSE("GPL"); From 2aed524df049813abea218ece036aa3638e6920e Mon Sep 17 00:00:00 2001 From: Francesca Ramadori Date: Fri, 3 Apr 2015 16:37:13 -0500 Subject: [PATCH 07/97] leds-ni793x: Add documentation for leds-ni793x devicetree bindings Add documentation for leds-ni793x devicetree bindings. This driver controls the RT User1 LED on the FlexRIO NI-793xR devices. Signed-off-by: Francesca Ramadori Signed-off-by: Brad Mouring Acked-by: Josh Cartwright Acked-by: Ben Shelton --- .../devicetree/bindings/leds/leds-ni793x.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/leds-ni793x.txt diff --git a/Documentation/devicetree/bindings/leds/leds-ni793x.txt b/Documentation/devicetree/bindings/leds/leds-ni793x.txt new file mode 100644 index 0000000000000..5124e694cf88b --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-ni793x.txt @@ -0,0 +1,21 @@ +LEDs connected to NI-793xR + +Required properties: +- compatible : should be : "ni,led-793x". +- reg: base address of LED control register space. + +The ni,led-793x device node only contains a single sub-node, 'user1'. + +LED sub-node properties: +- label : (optional) see leds/common.txt +- linux,default-trigger : (optional) see leds/common.txt + +Examples: + +leds-ni793x@4020F000 { + compatible = "ni,led-793x"; + reg = <0x4020F000 4>; + user1 { + label = "nilrt:user1:green"; + }; +}; From 19cdfd1686c0d1f6c1ec6760c3c86377c63984d0 Mon Sep 17 00:00:00 2001 From: Kyle Teske Date: Tue, 28 Aug 2012 12:48:18 -0500 Subject: [PATCH 08/97] fpgaperipheral: Add driver to notify clients on FPGA downloads Clients are drivers for peripherals with physical lines routed through the FPGA. Ethernet and serial will want to receive notifications so they can avoid accessing hardware while the FPGA is unprogrammed. Signed-off-by: Kyle Teske Natinst-ReviewBoard-ID: 26536 [cvadrevu: Fixed trivial conflicts due to newer modules] Signed-off-by: Chaitanya Vadrevu --- drivers/misc/Kconfig | 9 ++ drivers/misc/Makefile | 19 +++ drivers/misc/fpgaperipheral.c | 236 ++++++++++++++++++++++++++++++++++ include/misc/fpgaperipheral.h | 34 +++++ 4 files changed, 298 insertions(+) create mode 100644 drivers/misc/fpgaperipheral.c create mode 100644 include/misc/fpgaperipheral.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2504de4c99b8e..62ca3814ce43e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -57,6 +57,15 @@ config DUMMY_IRQ The sole purpose of this module is to help with debugging of systems on which spurious IRQs would happen on disabled IRQ vector. +config FPGA_PERIPHERAL + bool "FPGA Peripheral Driver" + help + FPGA Peripheral driver to notify peripheral devices of an + impending download. + + Used to make sure the devices routed through the FPGA are + powered off when an FPGA download occurs. + config IBM_ASM tristate "Device driver for IBM RSA service processor" depends on X86 && PCI && INPUT diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 2ce11031cd58f..59e6fe9a576b7 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -77,3 +77,22 @@ obj-y += amd-sbi/ obj-$(CONFIG_MISC_RP1) += rp1/ obj-$(CONFIG_NI_RT_FEATURES) += nirtfeatures.o obj-$(CONFIG_NI_WATCHDOG) += niwatchdog.o +obj-$(CONFIG_FPGA_PERIPHERAL) += fpgaperipheral.o + +lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_refcount.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o + +KCOV_INSTRUMENT_lkdtm_rodata.o := n + +OBJCOPYFLAGS := +OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ + --rename-section .text=.rodata,alloc,readonly,load +targets += lkdtm_rodata.o lkdtm_rodata_objcopy.o +$(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o FORCE + $(call if_changed,objcopy) +>>>>>>> b00bd564209c (fpgaperipheral: Add driver to notify clients on FPGA downloads) diff --git a/drivers/misc/fpgaperipheral.c b/drivers/misc/fpgaperipheral.c new file mode 100644 index 0000000000000..3432e4d580ce6 --- /dev/null +++ b/drivers/misc/fpgaperipheral.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2012 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FPGAPERIPHERAL_NAME "fpgaperipheral" +#define DEVCFG_INT_STS_OFFSET 0x0C +#define INT_STS_FPGA_DONE_MASK 0x04 + +BLOCKING_NOTIFIER_HEAD(fpgaperipheral_notifier_list); +EXPORT_SYMBOL_GPL(fpgaperipheral_notifier_list); + +/** + * struct fpgaperipheral_drvdata - fpgaperipheral driver structure + * @devcfg_addr: Pointer (from ioremap) to the devcfg memory region + */ +struct fpgaperipheral_drvdata { + void __iomem *devcfg_addr; +}; + +/* + * drvdata given filewide scope instead of dynamically + * allocated and passed around so it's easier to share between the + * platform driver (probe/remove) and misc device driver (open/release). + * This is okay since there is only ever 1 device. + */ +static struct fpgaperipheral_drvdata drvdata; + +/* Access control: Only allow one open at a time */ +static atomic_t fpgaperipheral_available = ATOMIC_INIT(1); + +/** + * is_fpga_programmed() - Checks if the FPGA is currently programmed + * Returns non-zero iff FPGA is programmed + */ +static int is_fpga_programmed(void) +{ + return ioread32(drvdata.devcfg_addr + DEVCFG_INT_STS_OFFSET) & + INT_STS_FPGA_DONE_MASK; +} + +/** + * notify_clients() - Depending on up_or_down, notifies clients FPGA is about + * to be unprogrammed, or is now programmed. + * @up_or_down: Whether FPGA is about to go down, or is now up. + */ +static void notify_clients(unsigned long up_or_down) +{ + blocking_notifier_call_chain(&fpgaperipheral_notifier_list, + up_or_down, NULL); +} + +/** + * fpgaperipheral_misc_open() - Notifies clients that FPGA is about to go down. + * Only allows 1 open() at a time. + * @inode: Pointer to the inode structure of this device. + * @file: Pointer to the file structure. + * Returns 0 on success, negative error otherwise + */ +static int fpgaperipheral_misc_open(struct inode *inode, struct file *file) +{ + if (!atomic_dec_and_test(&fpgaperipheral_available)) { + atomic_inc(&fpgaperipheral_available); + return -EBUSY; + } + + notify_clients(FPGA_PERIPHERAL_DOWN); + return 0; +} + +/** + * fpgaperipheral_misc_release() - Notifies clients that FPGA is back up. + * @inode: Pointer to the inode structure of this device. + * @file: Pointer to the file structure. + * Returns 0 on success, negative error otherwise + */ +static int fpgaperipheral_misc_release(struct inode *inode, struct file *file) +{ + if (is_fpga_programmed()) + notify_clients(FPGA_PERIPHERAL_UP); + + atomic_inc(&fpgaperipheral_available); + return 0; +} + +static const struct file_operations fpgaperipheral_misc_fops = { + .owner = THIS_MODULE, + .open = fpgaperipheral_misc_open, + .release = fpgaperipheral_misc_release +}; + +static struct miscdevice fpgaperipheral_misc_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = FPGAPERIPHERAL_NAME, + .fops = &fpgaperipheral_misc_fops, +}; + +/** + * fpgaperipheral_probe - Platform driver probe + * @pdev: Pointer to the platform device structure + * Returns 0 on success, negative error otherwise + */ +static int fpgaperipheral_probe(struct platform_device *pdev) +{ + int retval; + void __iomem *devcfg_addr; + struct resource *devcfg_res; + + /* Get devcfg resource */ + devcfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!devcfg_res) { + dev_err(&pdev->dev, "Couldn't get io resource\n"); + return -ENODEV; + } + + /* Get the mem region for devcfg */ + if (!request_mem_region(devcfg_res->start, + resource_size(devcfg_res), + FPGAPERIPHERAL_NAME)) { + dev_err(&pdev->dev, "Couldn't lock memory region at %Lx\n", + (unsigned long long) devcfg_res->start); + return -EBUSY; + } + + /* Map the devcfg mem region */ + devcfg_addr = ioremap(devcfg_res->start, resource_size(devcfg_res)); + if (!devcfg_addr) { + dev_err(&pdev->dev, "ioremap failed\n"); + retval = -EIO; + goto failed_after_request_mem_region; + } + + /* Set the drvdata where the misc device can find it */ + drvdata.devcfg_addr = devcfg_addr; + + /* Now register the misc device */ + retval = misc_register(&fpgaperipheral_misc_dev); + if (retval) { + dev_err(&pdev->dev, "Couldn't register misc device\n"); + goto failed_after_ioremap; + } + + return 0; + +failed_after_ioremap: + iounmap(drvdata.devcfg_addr); + +failed_after_request_mem_region: + release_mem_region(devcfg_res->start, resource_size(devcfg_res)); + + drvdata.devcfg_addr = NULL; + return retval; +} + +/** + * fpgaperipheral_remove - called when the platform driver is unregistered + * @pdev: Pointer to the platform device structure + * Returns 0 on success, negative error otherwise + */ +static int __exit fpgaperipheral_remove(struct platform_device *pdev) +{ + struct resource *devcfg_res; + + devcfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + misc_deregister(&fpgaperipheral_misc_dev); + iounmap(drvdata.devcfg_addr); + release_mem_region(devcfg_res->start, resource_size(devcfg_res)); + + drvdata.devcfg_addr = NULL; + return 0; +} + +/* Match table for of_platform binding */ +#ifdef CONFIG_OF +static const struct of_device_id fpgaperipheral_of_match[] = { + { .compatible = FPGAPERIPHERAL_NAME, }, + {} +}; +MODULE_DEVICE_TABLE(of, fpgaperipheral_of_match); +#else +#define fpgaperipheral_of_match NULL +#endif + +static struct platform_driver fpgaperipheral_platform_driver = { + .probe = fpgaperipheral_probe, /* Probe method */ + .remove = __exit_p(fpgaperipheral_remove), /* Detach method */ + .driver = { + .owner = THIS_MODULE, + .name = FPGAPERIPHERAL_NAME, /* Driver name */ + .of_match_table = fpgaperipheral_of_match, + }, +}; + +/** + * fpgaperipheral_init - Initial driver registration call + * Returns 0 on success, negative error otherwise + */ +static int __init fpgaperipheral_init(void) +{ + return platform_driver_register(&fpgaperipheral_platform_driver); +} +module_init(fpgaperipheral_init); + +/** + * fpgaperipheral_exit - Driver unregistration call + * Returns 0 on success, negative error otherwise + */ +static void __exit fpgaperipheral_exit(void) +{ + platform_driver_unregister(&fpgaperipheral_platform_driver); +} +module_exit(fpgaperipheral_exit); + +MODULE_DESCRIPTION("Bus driver for FPGA peripherals on NI's Zynq-based controllers"); +MODULE_AUTHOR("Kyle Teske "); +MODULE_LICENSE("GPL"); diff --git a/include/misc/fpgaperipheral.h b/include/misc/fpgaperipheral.h new file mode 100644 index 0000000000000..aec44e06ae2d6 --- /dev/null +++ b/include/misc/fpgaperipheral.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2012 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _FPGA_PERIPHERAL_H_ +#define _FPGA_PERIPHERAL_H_ + +#include + +/* + * The value passed to notifier callbacks will be one of these. + * FPGA_PERIPHERAL_DOWN: The FPGA is about to be unprogrammed. + * FPGA_PERIPHERAL_UP: The FPGA is now programmed. + * This may be called even if not preceded by an FPGA_PERIPHERAL_DOWN. + * + * Client callbacks should always return notifier_from_errno(0) so the + * call chain continues to all clients. + */ +#define FPGA_PERIPHERAL_DOWN 0 +#define FPGA_PERIPHERAL_UP 1 + +extern struct blocking_notifier_head fpgaperipheral_notifier_list; + +#endif /* _FPGA_PERIPHERAL_H_ */ From 615bd22566fd63c098fcc03863bbb6dc8749e65b Mon Sep 17 00:00:00 2001 From: Brad Mouring Date: Thu, 27 Oct 2016 17:18:54 -0500 Subject: [PATCH 09/97] fpgaperipheral: Add notification for failure We add a separate notification which will get called when FPGA programming fails. This is to enable client drivers to know when to stop waiting for FPGA to come up, if the re-programming fails. Signed-off-by: Karthik Manamcheri --- drivers/misc/fpgaperipheral.c | 2 ++ include/misc/fpgaperipheral.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/misc/fpgaperipheral.c b/drivers/misc/fpgaperipheral.c index 3432e4d580ce6..355f50f443dcc 100644 --- a/drivers/misc/fpgaperipheral.c +++ b/drivers/misc/fpgaperipheral.c @@ -97,6 +97,8 @@ static int fpgaperipheral_misc_release(struct inode *inode, struct file *file) { if (is_fpga_programmed()) notify_clients(FPGA_PERIPHERAL_UP); + else + notify_clients(FPGA_PERIPHERAL_FAILED); atomic_inc(&fpgaperipheral_available); return 0; diff --git a/include/misc/fpgaperipheral.h b/include/misc/fpgaperipheral.h index aec44e06ae2d6..37817cad66b64 100644 --- a/include/misc/fpgaperipheral.h +++ b/include/misc/fpgaperipheral.h @@ -22,12 +22,17 @@ * FPGA_PERIPHERAL_DOWN: The FPGA is about to be unprogrammed. * FPGA_PERIPHERAL_UP: The FPGA is now programmed. * This may be called even if not preceded by an FPGA_PERIPHERAL_DOWN. + * FPGA_PERIPHERAL_FAILED: The FPGA programming failed. + * If this is called, clients should not use the FPGA as it might be in + * a bad state. This is to notify the clients to abort any waiting for + * the FPGA to come back up. * * Client callbacks should always return notifier_from_errno(0) so the * call chain continues to all clients. */ #define FPGA_PERIPHERAL_DOWN 0 #define FPGA_PERIPHERAL_UP 1 +#define FPGA_PERIPHERAL_FAILED 2 extern struct blocking_notifier_head fpgaperipheral_notifier_list; From 6f78d5255dce59b2d5acbbddd460f2bf5a366e89 Mon Sep 17 00:00:00 2001 From: Ben Shelton Date: Tue, 10 Jun 2014 11:47:28 -0500 Subject: [PATCH 10/97] fpgaperipheral: Add dev_info message if probe succeeded If fpgaperipheral_probe succeeds, it generates no debug output, even at the highest loglevel. Add a success message to make device tree debugging easier. Signed-off-by: Ben Shelton --- drivers/misc/fpgaperipheral.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/fpgaperipheral.c b/drivers/misc/fpgaperipheral.c index 355f50f443dcc..e4015cb96bab7 100644 --- a/drivers/misc/fpgaperipheral.c +++ b/drivers/misc/fpgaperipheral.c @@ -161,6 +161,8 @@ static int fpgaperipheral_probe(struct platform_device *pdev) goto failed_after_ioremap; } + dev_info(&pdev->dev, "probe succeeded\n"); + return 0; failed_after_ioremap: From ee41560d2bd957c6e65fdb2ba41b501dbf60a0db Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Wed, 3 Jun 2015 17:57:24 -0500 Subject: [PATCH 11/97] mtd: nand: pl353: add snapshot of driver from linux-xlnx tree This is a snapshot of the Xilinx-provided PL353 NAND driver as of commit 3fa059cfa4b105f09752a4eb7480d122dd5e796b ("nand: pl353: Renamed zynq_nand driver as pl353_nand"). The original driver author is Punnaiah Choudary Kalluri . Signed-off-by: Josh Cartwright [cvadrevu: Fixed trivial conflicts due to newer modules] Signed-off-by: Chaitanya Vadrevu --- drivers/mtd/nand/Kconfig | 7 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/pl353_nand.c | 1122 +++++++++++++++++++++++++++++++++ 3 files changed, 1130 insertions(+) create mode 100644 drivers/mtd/nand/pl353_nand.c diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1e57c8de85782..495bd833ba68d 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -69,6 +69,13 @@ config MTD_NAND_ECC_REALTEK help This enables support for the hardware ECC engine from Realtek. +config MTD_NAND_PL353 + tristate "ARM Pl353 NAND flash driver" + depends on MTD_NAND && ARM + select PL353_SMC + help + This enables access to the NAND flash device on PL353 SMC controller. + endmenu endmenu diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 2e0e562677183..96281c82c09a1 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -4,6 +4,7 @@ nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o obj-$(CONFIG_MTD_NAND_ECC_REALTEK) += ecc-realtek.o +obj-$(CONFIG_MTD_NAND_PL353) += pl353_nand.o obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o obj-y += onenand/ diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c new file mode 100644 index 0000000000000..fd500d59f90e2 --- /dev/null +++ b/drivers/mtd/nand/pl353_nand.c @@ -0,0 +1,1122 @@ +/* + * ARM PL353 NAND Flash Controller Driver + * + * Copyright (C) 2009 - 2014 Xilinx, Inc. + * + * This driver is based on plat_nand.c and mxc_nand.c drivers + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PL353_NAND_DRIVER_NAME "pl353-nand" + +/* NAND flash driver defines */ +#define PL353_NAND_CMD_PHASE 1 /* End command valid in command phase */ +#define PL353_NAND_DATA_PHASE 2 /* End command valid in data phase */ +#define PL353_NAND_ECC_SIZE 512 /* Size of data for ECC operation */ + +/* Flash memory controller operating parameters */ + +#define PL353_NAND_ECC_CONFIG (BIT(4) | /* ECC read at end of page */ \ + (0 << 5)) /* No Jumping */ + +/* AXI Address definitions */ +#define START_CMD_SHIFT 3 +#define END_CMD_SHIFT 11 +#define END_CMD_VALID_SHIFT 20 +#define ADDR_CYCLES_SHIFT 21 +#define CLEAR_CS_SHIFT 21 +#define ECC_LAST_SHIFT 10 +#define COMMAND_PHASE (0 << 19) +#define DATA_PHASE BIT(19) + +#define PL353_NAND_ECC_LAST BIT(ECC_LAST_SHIFT) /* Set ECC_Last */ +#define PL353_NAND_CLEAR_CS BIT(CLEAR_CS_SHIFT) /* Clear chip select */ + +#define ONDIE_ECC_FEATURE_ADDR 0x90 +#define PL353_NAND_ECC_BUSY_TIMEOUT (1 * HZ) +#define PL353_NAND_DEV_BUSY_TIMEOUT (1 * HZ) +#define PL353_NAND_LAST_TRANSFER_LENGTH 4 + +/* Inline function for the NAND controller register write */ +static inline void pl353_nand_write32(void __iomem *addr, u32 val) +{ + writel_relaxed((val), (addr)); +} + +/** + * struct pl353_nand_command_format - Defines NAND flash command format + * @start_cmd: First cycle command (Start command) + * @end_cmd: Second cycle command (Last command) + * @addr_cycles: Number of address cycles required to send the address + * @end_cmd_valid: The second cycle command is valid for cmd or data phase + */ +struct pl353_nand_command_format { + int start_cmd; + int end_cmd; + u8 addr_cycles; + u8 end_cmd_valid; +}; + +/** + * struct pl353_nand_info - Defines the NAND flash driver instance + * @chip: NAND chip information structure + * @mtd: MTD information structure + * @parts: Pointer to the mtd_partition structure + * @nand_base: Virtual address of the NAND flash device + * @end_cmd_pending: End command is pending + * @end_cmd: End command + */ +struct pl353_nand_info { + struct nand_chip chip; + struct mtd_info mtd; + struct mtd_partition *parts; + void __iomem *nand_base; + unsigned long end_cmd_pending; + unsigned long end_cmd; +}; + +/* + * The NAND flash operations command format + */ +static const struct pl353_nand_command_format pl353_nand_commands[] = { + {NAND_CMD_READ0, NAND_CMD_READSTART, 5, PL353_NAND_CMD_PHASE}, + {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, PL353_NAND_CMD_PHASE}, + {NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE}, + {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, PL353_NAND_DATA_PHASE}, + {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE}, + {NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, PL353_NAND_CMD_PHASE}, + {NAND_CMD_RESET, NAND_CMD_NONE, 0, NAND_CMD_NONE}, + {NAND_CMD_PARAM, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE}, + {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0}, + /* Add all the flash commands supported by the flash device and Linux */ + /* + * The cache program command is not supported by driver because driver + * cant differentiate between page program and cached page program from + * start command, these commands can be differentiated through end + * command, which doesn't fit in to the driver design. The cache program + * command is not supported by NAND subsystem also, look at 1612 line + * number (in nand_write_page function) of nand_base.c file. + * {NAND_CMD_SEQIN, NAND_CMD_CACHEDPROG, 5, PL353_NAND_YES}, + */ +}; + +/* Define default oob placement schemes for large and small page devices */ +static struct nand_ecclayout nand_oob_16 = { + .eccbytes = 3, + .eccpos = {0, 1, 2}, + .oobfree = { + {.offset = 8, + . length = 8} } +}; + +static struct nand_ecclayout nand_oob_64 = { + .eccbytes = 12, + .eccpos = { + 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 2, + .length = 50} } +}; + +static struct nand_ecclayout ondie_nand_oob_64 = { + .eccbytes = 32, + + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 24, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 46, 47, + 56, 57, 58, 59, 60, 61, 62, 63 + }, + + .oobfree = { + { .offset = 4, .length = 4 }, + { .offset = 20, .length = 4 }, + { .offset = 36, .length = 4 }, + { .offset = 52, .length = 4 } + } +}; + +/* Generic flash bbt decriptors */ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +/** + * pl353_nand_calculate_hwecc - Calculate Hardware ECC + * @mtd: Pointer to the mtd_info structure + * @data: Pointer to the page data + * @ecc_code: Pointer to the ECC buffer where ECC data needs to be stored + * + * This function retrieves the Hardware ECC data from the controller and returns + * ECC data back to the MTD subsystem. + * + * Return: 0 on success or error value on failure + */ +static int pl353_nand_calculate_hwecc(struct mtd_info *mtd, + const u8 *data, u8 *ecc_code) +{ + u32 ecc_value, ecc_status; + u8 ecc_reg, ecc_byte; + unsigned long timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT; + + /* Wait till the ECC operation is complete or timeout */ + do { + if (pl353_smc_ecc_is_busy()) + cpu_relax(); + else + break; + } while (!time_after_eq(jiffies, timeout)); + + if (time_after_eq(jiffies, timeout)) { + pr_err("%s timed out\n", __func__); + return -ETIMEDOUT; + } + + for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) { + /* Read ECC value for each block */ + ecc_value = pl353_smc_get_ecc_val(ecc_reg); + ecc_status = (ecc_value >> 24) & 0xFF; + /* ECC value valid */ + if (ecc_status & 0x40) { + for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) { + /* Copy ECC bytes to MTD buffer */ + *ecc_code = ecc_value & 0xFF; + ecc_value = ecc_value >> 8; + ecc_code++; + } + } else { + pr_warn("%s status failed\n", __func__); + return -1; + } + } + return 0; +} + +/** + * onehot - onehot function + * @value: Value to check for onehot + * + * This function checks whether a value is onehot or not. + * onehot is if and only if onebit is set. + * + * Return: 1 if it is onehot else 0 + */ +static int onehot(unsigned short value) +{ + return (value & (value - 1)) == 0; +} + +/** + * pl353_nand_correct_data - ECC correction function + * @mtd: Pointer to the mtd_info structure + * @buf: Pointer to the page data + * @read_ecc: Pointer to the ECC value read from spare data area + * @calc_ecc: Pointer to the calculated ECC value + * + * This function corrects the ECC single bit errors & detects 2-bit errors. + * + * Return: 0 if no ECC errors found + * 1 if single bit error found and corrected. + * -1 if multiple ECC errors found. + */ +static int pl353_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, + unsigned char *read_ecc, + unsigned char *calc_ecc) +{ + unsigned char bit_addr; + unsigned int byte_addr; + unsigned short ecc_odd, ecc_even, read_ecc_lower, read_ecc_upper; + unsigned short calc_ecc_lower, calc_ecc_upper; + + read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff; + read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff; + + calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff; + calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff; + + ecc_odd = read_ecc_lower ^ calc_ecc_lower; + ecc_even = read_ecc_upper ^ calc_ecc_upper; + + if ((ecc_odd == 0) && (ecc_even == 0)) + return 0; /* no error */ + + if (ecc_odd == (~ecc_even & 0xfff)) { + /* bits [11:3] of error code is byte offset */ + byte_addr = (ecc_odd >> 3) & 0x1ff; + /* bits [2:0] of error code is bit offset */ + bit_addr = ecc_odd & 0x7; + /* Toggling error bit */ + buf[byte_addr] ^= (1 << bit_addr); + return 1; + } + + if (onehot(ecc_odd | ecc_even) == 1) + return 1; /* one error in parity */ + + return -1; /* Uncorrectable error */ +} + +/** + * pl353_nand_read_oob - [REPLACABLE] the most common OOB data read function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @page: Page number to read + * + * Return: Always return zero + */ +static int pl353_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + unsigned long data_phase_addr; + uint8_t *p; + + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + + p = chip->oob_poi; + chip->read_buf(mtd, p, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + p += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= PL353_NAND_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + chip->read_buf(mtd, p, PL353_NAND_LAST_TRANSFER_LENGTH); + + return 0; +} + +/** + * pl353_nand_write_oob - [REPLACABLE] the most common OOB data write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @page: Page number to write + * + * Return: Zero on success and EIO on failure + */ +static int pl353_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int status = 0; + const uint8_t *buf = chip->oob_poi; + unsigned long data_phase_addr; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + + chip->write_buf(mtd, buf, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + buf += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= PL353_NAND_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + chip->write_buf(mtd, buf, PL353_NAND_LAST_TRANSFER_LENGTH); + + /* Send command to program the OOB data */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/** + * pl353_nand_read_page_raw - [Intern] read raw page data without ecc + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + * + * Return: Always return zero + */ +static int pl353_nand_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + unsigned long data_phase_addr; + uint8_t *p; + + chip->read_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->read_buf(mtd, p, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + p += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= PL353_NAND_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + + chip->read_buf(mtd, p, PL353_NAND_LAST_TRANSFER_LENGTH); + return 0; +} + +/** + * pl353_nand_write_page_raw - [Intern] raw page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * + * Return: Always return zero + */ +static int pl353_nand_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + unsigned long data_phase_addr; + uint8_t *p; + + chip->write_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->write_buf(mtd, p, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + p += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= PL353_NAND_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + + chip->write_buf(mtd, p, PL353_NAND_LAST_TRANSFER_LENGTH); + + return 0; +} + +/** + * nand_write_page_hwecc - Hardware ECC based page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * + * This functions writes data and hardware generated ECC values in to the page. + * + * Return: Always return zero + */ +static int pl353_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required) +{ + int i, eccsize = chip->ecc.size; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + unsigned long data_phase_addr; + uint8_t *oob_ptr; + + for ( ; (eccsteps - 1); eccsteps--) { + chip->write_buf(mtd, p, eccsize); + p += eccsize; + } + chip->write_buf(mtd, p, (eccsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + p += (eccsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + /* Set ECC Last bit to 1 */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= PL353_NAND_ECC_LAST; + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + chip->write_buf(mtd, p, PL353_NAND_LAST_TRANSFER_LENGTH); + + /* Wait for ECC to be calculated and read the error values */ + p = buf; + chip->ecc.calculate(mtd, p, &ecc_calc[0]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]); + + /* Clear ECC last bit */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr &= ~PL353_NAND_ECC_LAST; + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + + /* Write the spare area with ECC bytes */ + oob_ptr = chip->oob_poi; + chip->write_buf(mtd, oob_ptr, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= PL353_NAND_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + oob_ptr += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + chip->write_buf(mtd, oob_ptr, PL353_NAND_LAST_TRANSFER_LENGTH); + + return 0; +} + +/** + * pl353_nand_write_page_swecc - [REPLACABLE] software ecc based page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * + * Return: Always return zero + */ +static int pl353_nand_write_page_swecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + /* Software ecc calculation */ + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + chip->ecc.write_page_raw(mtd, chip, buf, 1); + + return 0; +} + +/** + * pl353_nand_read_page_hwecc - Hardware ECC based page read function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the buffer to store read data + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + * + * This functions reads data and checks the data integrity by comparing hardware + * generated ECC values and read ECC values from spare area. + * + * Return: 0 always and updates ECC operation status in to MTD structure + */ +static int pl353_nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i, stat, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + unsigned long data_phase_addr; + uint8_t *oob_ptr; + + for ( ; (eccsteps - 1); eccsteps--) { + chip->read_buf(mtd, p, eccsize); + p += eccsize; + } + chip->read_buf(mtd, p, (eccsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + p += (eccsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + /* Set ECC Last bit to 1 */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= PL353_NAND_ECC_LAST; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + chip->read_buf(mtd, p, PL353_NAND_LAST_TRANSFER_LENGTH); + + /* Read the calculated ECC value */ + p = buf; + chip->ecc.calculate(mtd, p, &ecc_calc[0]); + + /* Clear ECC last bit */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr &= ~PL353_NAND_ECC_LAST; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + + /* Read the stored ECC value */ + oob_ptr = chip->oob_poi; + chip->read_buf(mtd, oob_ptr, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + + /* de-assert chip select */ + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= PL353_NAND_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + + oob_ptr += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + chip->read_buf(mtd, oob_ptr, PL353_NAND_LAST_TRANSFER_LENGTH); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = ~(chip->oob_poi[eccpos[i]]); + + eccsteps = chip->ecc.steps; + p = buf; + + /* Check ECC error for all blocks and correct if it is correctable */ + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/** + * pl353_nand_read_page_swecc - [REPLACABLE] software ecc based page read function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the buffer to store read data + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + * + * Return: Always return zero + */ +static int pl353_nand_read_page_swecc(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + chip->ecc.read_page_raw(mtd, chip, buf, page, 1); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + p = buf; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/** + * pl353_nand_select_chip - Select the flash device + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * + * This function is empty as the NAND controller handles chip select line + * internally based on the chip address passed in command and data phase. + */ +static void pl353_nand_select_chip(struct mtd_info *mtd, int chip) +{ + return; +} + +/** + * pl353_nand_cmd_function - Send command to NAND device + * @mtd: Pointer to the mtd_info structure + * @command: The command to be sent to the flash device + * @column: The column address for this command, -1 if none + * @page_addr: The page address for this command, -1 if none + */ +static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd->priv; + const struct pl353_nand_command_format *curr_cmd = NULL; + struct pl353_nand_info *xnand = + container_of(mtd, struct pl353_nand_info, mtd); + void __iomem *cmd_addr; + unsigned long cmd_data = 0, end_cmd_valid = 0; + unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i; + unsigned long timeout = jiffies + PL353_NAND_DEV_BUSY_TIMEOUT; + + if (xnand->end_cmd_pending) { + /* + * Check for end command if this command request is same as the + * pending command then return + */ + if (xnand->end_cmd == command) { + xnand->end_cmd = 0; + xnand->end_cmd_pending = 0; + return; + } + } + + /* Emulate NAND_CMD_READOOB for large page device */ + if ((mtd->writesize > PL353_NAND_ECC_SIZE) && + (command == NAND_CMD_READOOB)) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Get the command format */ + for (i = 0; (pl353_nand_commands[i].start_cmd != NAND_CMD_NONE || + pl353_nand_commands[i].end_cmd != NAND_CMD_NONE); i++) + if (command == pl353_nand_commands[i].start_cmd) + curr_cmd = &pl353_nand_commands[i]; + + if (curr_cmd == NULL) + return; + + /* Clear interrupt */ + pl353_smc_clr_nand_int(); + + /* Get the command phase address */ + if (curr_cmd->end_cmd_valid == PL353_NAND_CMD_PHASE) + end_cmd_valid = 1; + + if (curr_cmd->end_cmd == NAND_CMD_NONE) + end_cmd = 0x0; + else + end_cmd = curr_cmd->end_cmd; + + cmd_phase_addr = (unsigned long __force)xnand->nand_base | + (curr_cmd->addr_cycles << ADDR_CYCLES_SHIFT) | + (end_cmd_valid << END_CMD_VALID_SHIFT) | + (COMMAND_PHASE) | + (end_cmd << END_CMD_SHIFT) | + (curr_cmd->start_cmd << START_CMD_SHIFT); + + cmd_addr = (void __iomem * __force)cmd_phase_addr; + + /* Get the data phase address */ + end_cmd_valid = 0; + + data_phase_addr = (unsigned long __force)xnand->nand_base | + (0x0 << CLEAR_CS_SHIFT) | + (end_cmd_valid << END_CMD_VALID_SHIFT) | + (DATA_PHASE) | + (end_cmd << END_CMD_SHIFT) | + (0x0 << ECC_LAST_SHIFT); + + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + chip->IO_ADDR_W = chip->IO_ADDR_R; + + /* Command phase AXI write */ + /* Read & Write */ + if (column != -1 && page_addr != -1) { + /* Adjust columns for 16 bit bus width */ + if (chip->options & NAND_BUSWIDTH_16) + column >>= 1; + cmd_data = column; + if (mtd->writesize > PL353_NAND_ECC_SIZE) { + cmd_data |= page_addr << 16; + /* Another address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) { + pl353_nand_write32(cmd_addr, cmd_data); + cmd_data = (page_addr >> 16); + } + } else { + cmd_data |= page_addr << 8; + } + } else if (page_addr != -1) { + /* Erase */ + cmd_data = page_addr; + } else if (column != -1) { + /* + * Change read/write column, read id etc + * Adjust columns for 16 bit bus width + */ + if ((chip->options & NAND_BUSWIDTH_16) && + ((command == NAND_CMD_READ0) || + (command == NAND_CMD_SEQIN) || + (command == NAND_CMD_RNDOUT) || + (command == NAND_CMD_RNDIN))) + column >>= 1; + cmd_data = column; + } + + pl353_nand_write32(cmd_addr, cmd_data); + + if (curr_cmd->end_cmd_valid) { + xnand->end_cmd = curr_cmd->end_cmd; + xnand->end_cmd_pending = 1; + } + + ndelay(100); + + if ((command == NAND_CMD_READ0) || + (command == NAND_CMD_RESET) || + (command == NAND_CMD_PARAM) || + (command == NAND_CMD_GET_FEATURES)) { + + /* Wait till the device is ready or timeout */ + do { + if (chip->dev_ready(mtd)) + break; + else + cpu_relax(); + } while (!time_after_eq(jiffies, timeout)); + + if (time_after_eq(jiffies, timeout)) + pr_err("%s timed out\n", __func__); + return; + } +} + +/** + * pl353_nand_read_buf - read chip data into buffer + * @mtd: Pointer to the mtd info structure + * @buf: Pointer to the buffer to store read data + * @len: Number of bytes to read + */ +static void pl353_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + unsigned long *ptr = (unsigned long *)buf; + + len >>= 2; + for (i = 0; i < len; i++) + ptr[i] = readl(chip->IO_ADDR_R); +} + +/** + * pl353_nand_write_buf - write buffer to chip + * @mtd: Pointer to the mtd info structure + * @buf: Pointer to the buffer to store read data + * @len: Number of bytes to write + */ +static void pl353_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + unsigned long *ptr = (unsigned long *)buf; + + len >>= 2; + + for (i = 0; i < len; i++) + writel(ptr[i], chip->IO_ADDR_W); +} + +/** + * pl353_nand_device_ready - Check device ready/busy line + * @mtd: Pointer to the mtd_info structure + * + * Return: 0 on busy or 1 on ready state + */ +static int pl353_nand_device_ready(struct mtd_info *mtd) +{ + if (pl353_smc_get_nand_int_status_raw()) { + pl353_smc_clr_nand_int(); + return 1; + } + return 0; +} + +/** + * pl353_nand_detect_ondie_ecc - Get the flash ondie ecc state + * @mtd: Pointer to the mtd_info structure + * + * This function enables the ondie ecc for the Micron ondie ecc capable devices + * + * Return: 1 on detect, 0 if fail to detect + */ +static int pl353_nand_detect_ondie_ecc(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + u8 maf_id, dev_id, i, get_feature; + u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; + + /* Check if On-Die ECC flash */ + nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + maf_id = readb(nand_chip->IO_ADDR_R); + dev_id = readb(nand_chip->IO_ADDR_R); + + if ((maf_id == NAND_MFR_MICRON) && + ((dev_id == 0xf1) || (dev_id == 0xa1) || + (dev_id == 0xb1) || (dev_id == 0xaa) || + (dev_id == 0xba) || (dev_id == 0xda) || + (dev_id == 0xca) || (dev_id == 0xac) || + (dev_id == 0xbc) || (dev_id == 0xdc) || + (dev_id == 0xcc) || (dev_id == 0xa3) || + (dev_id == 0xb3) || + (dev_id == 0xd3) || (dev_id == 0xc3))) { + + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = readb(nand_chip->IO_ADDR_R); + + if (get_feature & 0x08) { + return 1; + } else { + nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + for (i = 0; i < 4; i++) + writeb(set_feature[i], nand_chip->IO_ADDR_W); + + ndelay(1000); + + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = readb(nand_chip->IO_ADDR_R); + + if (get_feature & 0x08) + return 1; + + } + } + + return 0; +} + +/** + * pl353_nand_ecc_init - Initialize the ecc information as per the ecc mode + * @mtd: Pointer to the mtd_info structure + * @ondie_ecc_state: ondie ecc status + * + * This function initializes the ecc block and functional pointers as per the + * ecc mode + */ +static void pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) +{ + struct nand_chip *nand_chip = mtd->priv; + + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.read_oob = pl353_nand_read_oob; + nand_chip->ecc.read_page_raw = pl353_nand_read_page_raw; + nand_chip->ecc.strength = 1; + nand_chip->ecc.write_oob = pl353_nand_write_oob; + nand_chip->ecc.write_page_raw = pl353_nand_write_page_raw; + + if (ondie_ecc_state) { + /* bypass the controller ECC block */ + pl353_smc_set_ecc_mode(PL353_SMC_ECCMODE_BYPASS); + + /* + * The software ECC routines won't work with the + * SMC controller + */ + nand_chip->ecc.bytes = 0; + nand_chip->ecc.layout = &ondie_nand_oob_64; + nand_chip->ecc.read_page = pl353_nand_read_page_raw; + nand_chip->ecc.write_page = pl353_nand_write_page_raw; + nand_chip->ecc.size = mtd->writesize; + /* + * On-Die ECC spare bytes offset 8 is used for ECC codes + * Use the BBT pattern descriptors + */ + nand_chip->bbt_td = &bbt_main_descr; + nand_chip->bbt_md = &bbt_mirror_descr; + } else { + /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ + nand_chip->ecc.bytes = 3; + nand_chip->ecc.calculate = pl353_nand_calculate_hwecc; + nand_chip->ecc.correct = pl353_nand_correct_data; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = pl353_nand_read_page_hwecc; + nand_chip->ecc.size = PL353_NAND_ECC_SIZE; + nand_chip->ecc.write_page = pl353_nand_write_page_hwecc; + + pl353_smc_set_ecc_pg_size(mtd->writesize); + switch (mtd->writesize) { + case 512: + case 1024: + case 2048: + pl353_smc_set_ecc_mode(PL353_SMC_ECCMODE_APB); + break; + default: + /* + * The software ECC routines won't work with the + * SMC controller + */ + nand_chip->ecc.calculate = nand_calculate_ecc; + nand_chip->ecc.correct = nand_correct_data; + nand_chip->ecc.read_page = pl353_nand_read_page_swecc; + nand_chip->ecc.write_page = pl353_nand_write_page_swecc; + nand_chip->ecc.size = 256; + break; + } + + if (mtd->oobsize == 16) + nand_chip->ecc.layout = &nand_oob_16; + else if (mtd->oobsize == 64) + nand_chip->ecc.layout = &nand_oob_64; + } +} + +/** + * pl353_nand_probe - Probe method for the NAND driver + * @pdev: Pointer to the platform_device structure + * + * This function initializes the driver data structures and the hardware. + * + * Return: 0 on success or error value on failure + */ +static int pl353_nand_probe(struct platform_device *pdev) +{ + struct pl353_nand_info *xnand; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + struct resource *res; + struct mtd_part_parser_data ppdata; + int ondie_ecc_state; + + xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL); + if (!xnand) + return -ENOMEM; + + /* Map physical address of NAND flash */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xnand->nand_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xnand->nand_base)) + return PTR_ERR(xnand->nand_base); + + /* Link the private data with the MTD structure */ + mtd = &xnand->mtd; + nand_chip = &xnand->chip; + + nand_chip->priv = xnand; + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + mtd->name = PL353_NAND_DRIVER_NAME; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = xnand->nand_base; + nand_chip->IO_ADDR_W = xnand->nand_base; + + /* Set the driver entry points for MTD */ + nand_chip->cmdfunc = pl353_nand_cmd_function; + nand_chip->dev_ready = pl353_nand_device_ready; + nand_chip->select_chip = pl353_nand_select_chip; + + /* If we don't set this delay driver sets 20us by default */ + nand_chip->chip_delay = 30; + + /* Buffer read/write routines */ + nand_chip->read_buf = pl353_nand_read_buf; + nand_chip->write_buf = pl353_nand_write_buf; + + /* Set the device option and flash width */ + nand_chip->options = NAND_BUSWIDTH_AUTO; + nand_chip->bbt_options = NAND_BBT_USE_FLASH; + + platform_set_drvdata(pdev, xnand); + + ondie_ecc_state = pl353_nand_detect_ondie_ecc(mtd); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1, NULL)) { + dev_err(&pdev->dev, "nand_scan_ident for NAND failed\n"); + return -ENXIO; + } + + pl353_nand_ecc_init(mtd, ondie_ecc_state); + if (nand_chip->options & NAND_BUSWIDTH_16) + pl353_smc_set_buswidth(PL353_SMC_MEM_WIDTH_16); + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + dev_err(&pdev->dev, "nand_scan_tail for NAND failed\n"); + return -ENXIO; + } + + ppdata.of_node = pdev->dev.of_node; + + mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0); + + return 0; +} + +/** + * pl353_nand_remove - Remove method for the NAND driver + * @pdev: Pointer to the platform_device structure + * + * This function is called if the driver module is being unloaded. It frees all + * resources allocated to the device. + * + * Return: 0 on success or error value on failure + */ +static int pl353_nand_remove(struct platform_device *pdev) +{ + struct pl353_nand_info *xnand = platform_get_drvdata(pdev); + + /* Release resources, unregister device */ + nand_release(&xnand->mtd); + /* kfree(NULL) is safe */ + kfree(xnand->parts); + + return 0; +} + +/* Match table for device tree binding */ +static const struct of_device_id pl353_nand_of_match[] = { + { .compatible = "arm,pl353-nand-r2p1" }, + {}, +}; +MODULE_DEVICE_TABLE(of, pl353_nand_of_match); + +/* + * pl353_nand_driver - This structure defines the NAND subsystem platform driver + */ +static struct platform_driver pl353_nand_driver = { + .probe = pl353_nand_probe, + .remove = pl353_nand_remove, + .driver = { + .name = PL353_NAND_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = pl353_nand_of_match, + }, +}; + +module_platform_driver(pl353_nand_driver); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_ALIAS("platform:" PL353_NAND_DRIVER_NAME); +MODULE_DESCRIPTION("ARM PL353 NAND Flash Driver"); +MODULE_LICENSE("GPL"); From 94876136d1a6470004a91259f75380d7ffba8a6f Mon Sep 17 00:00:00 2001 From: Ben Shelton Date: Wed, 4 Dec 2013 16:33:05 -0600 Subject: [PATCH 12/97] Zynq NAND: enable subpage reads and writes The default 3.10 NAND driver does not support subpage reads or writes for our device, which causes it not to play nicely with partitions that have already been formatted with this support. This commit forward-ports the following commits to enable this feature: - NAND: Added subpage read support for on-die ECC devices using Xilinx PS NAND controller. - Zynq NAND: Fixed block erase timeout problem and off-by-one math error - Zynq NAND: Subpage write support. Acked-by: Jeff Westfahl Signed-off-by: Ben Shelton --- drivers/mtd/nand/pl353_nand.c | 60 ++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index fd500d59f90e2..320e7ed844ee7 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -397,6 +397,22 @@ static int pl353_nand_read_page_raw(struct mtd_info *mtd, return 0; } +static int pl353_nand_read_subpage_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint32_t data_offs, + uint32_t readlen, uint8_t *buf, int page) +{ + if (data_offs != 0) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_offs, -1); + buf += data_offs; + } + + /* readlen must be a multiple of 4. */ + readlen = (((readlen + 3) >> 2) << 2); + + chip->read_buf(mtd, buf, readlen); + return 0; +} + /** * pl353_nand_write_page_raw - [Intern] raw page write function * @mtd: Pointer to the mtd info structure @@ -408,7 +424,8 @@ static int pl353_nand_read_page_raw(struct mtd_info *mtd, */ static int pl353_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, + int oob_required, int page) { unsigned long data_phase_addr; uint8_t *p; @@ -430,6 +447,25 @@ static int pl353_nand_write_page_raw(struct mtd_info *mtd, return 0; } +/** + * pl353_nand_write_subpage_raw - [Intern] raw subpage write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @column: column address of subpage within the page + * @data_len: data length + * @data_buf: data buffer + * @oob_required: must write chip->oob_poi to OOB + * + */ +static int pl353_nand_write_subpage_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint32_t offset, + uint32_t data_len, const uint8_t *data_buf, + int oob_required, int page) +{ + return pl353_nand_write_page_raw(mtd, chip, data_buf, oob_required, + page); +} + /** * nand_write_page_hwecc - Hardware ECC based page write function * @mtd: Pointer to the mtd info structure @@ -443,7 +479,7 @@ static int pl353_nand_write_page_raw(struct mtd_info *mtd, */ static int pl353_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, - int oob_required) + int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccsteps = chip->ecc.steps; @@ -504,7 +540,7 @@ static int pl353_nand_write_page_hwecc(struct mtd_info *mtd, */ static int pl353_nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, - int oob_required) + int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -520,7 +556,7 @@ static int pl353_nand_write_page_swecc(struct mtd_info *mtd, for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->ecc.write_page_raw(mtd, chip, buf, 1); + chip->ecc.write_page_raw(mtd, chip, buf, 1, page); return 0; } @@ -945,8 +981,19 @@ static void pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) nand_chip->ecc.bytes = 0; nand_chip->ecc.layout = &ondie_nand_oob_64; nand_chip->ecc.read_page = pl353_nand_read_page_raw; + nand_chip->ecc.read_subpage = pl353_nand_read_subpage_raw; nand_chip->ecc.write_page = pl353_nand_write_page_raw; + nand_chip->ecc.write_subpage = pl353_nand_write_subpage_raw; nand_chip->ecc.size = mtd->writesize; + + /* NAND with on-die ECC supports subpage reads */ + nand_chip->options |= NAND_SUBPAGE_READ; + + /* NAND with on-die ECC may support subpage writes */ + if (nand_chip->onfi_version) + nand_chip->ecc.size /= + nand_chip->onfi_params.programs_per_page; + /* * On-Die ECC spare bytes offset 8 is used for ECC codes * Use the BBT pattern descriptors @@ -1004,7 +1051,6 @@ static int pl353_nand_probe(struct platform_device *pdev) struct mtd_info *mtd; struct nand_chip *nand_chip; struct resource *res; - struct mtd_part_parser_data ppdata; int ondie_ecc_state; xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL); @@ -1066,9 +1112,7 @@ static int pl353_nand_probe(struct platform_device *pdev) return -ENXIO; } - ppdata.of_node = pdev->dev.of_node; - - mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0); + mtd_device_parse_register(&xnand->mtd, NULL, NULL, NULL, 0); return 0; } From 73d528d54e8460a041f8b53d8e196b25c1415e1f Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 19 Apr 2013 15:31:08 -0500 Subject: [PATCH 13/97] Xilinx: ARM: nand: Replace READ0 of the last read page with RNDOUT Replace the NAND READ0 command with an RNDOUT command if the READ0 is for the most recently read page and no other command has been sent to the NAND that would make another READ0 necessary. Signed-off-by: Jeff Westfahl --- drivers/mtd/nand/pl353_nand.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index 320e7ed844ee7..b174390fd59fd 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -96,6 +96,7 @@ struct pl353_nand_info { void __iomem *nand_base; unsigned long end_cmd_pending; unsigned long end_cmd; + int last_read_page; }; /* @@ -736,6 +737,16 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, command = NAND_CMD_READ0; } + /* If we receive a READ0 for the page that we've most recently read, + * without an intervening command that would change the state of the + * NAND cache register, we can replace the READ0 with a RNDOUT. + */ + if ((command == NAND_CMD_READ0) && + (xnand->last_read_page == page_addr)) { + command = NAND_CMD_RNDOUT; + page_addr = -1; + } + /* Get the command format */ for (i = 0; (pl353_nand_commands[i].start_cmd != NAND_CMD_NONE || pl353_nand_commands[i].end_cmd != NAND_CMD_NONE); i++) @@ -745,6 +756,12 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, if (curr_cmd == NULL) return; + /* We want to preserve the page address of the last READ0 + * when just changing the read column address. + */ + if (command != NAND_CMD_RNDOUT) + xnand->last_read_page = -1; + /* Clear interrupt */ pl353_smc_clr_nand_int(); @@ -839,6 +856,12 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, pr_err("%s timed out\n", __func__); return; } + + if (command == NAND_CMD_READ0) + /* Store the read page address so that we can detect consecutive + * reads of the same page and only send one read command. + */ + xnand->last_read_page = page_addr; } /** @@ -1106,6 +1129,8 @@ static int pl353_nand_probe(struct platform_device *pdev) if (nand_chip->options & NAND_BUSWIDTH_16) pl353_smc_set_buswidth(PL353_SMC_MEM_WIDTH_16); + xnand->last_read_page = -1; + /* second phase scan */ if (nand_scan_tail(mtd)) { dev_err(&pdev->dev, "nand_scan_tail for NAND failed\n"); From 68163aca9a22ff40d160652a270b438530059739 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Mon, 22 Apr 2013 12:22:41 -0500 Subject: [PATCH 14/97] Xilinx: ARM: nand: Check read status when using on-die ECC When using on-die ECC, check the NAND status after READ0 operations for an ECC warning or error. Signed-off-by: Jeff Westfahl --- drivers/mtd/nand/pl353_nand.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index b174390fd59fd..d8181b490fbc8 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -65,6 +65,20 @@ static inline void pl353_nand_write32(void __iomem *addr, u32 val) { writel_relaxed((val), (addr)); } + /* + * READ0 command only, for checking read status. Note that the real command + * here is 0x00, but we can't differentiate between READ0 where we need to + * send a READSTART after the address bytes, or a READ0 by itself, after + * a read status command to check the on-die ECC status. The high bit is + * written into the unused end_cmd field, so we don't need to mask it off. + */ +#define NAND_CMD_READ0_ONLY 0x100 + +/* + * Status bits + */ +/* Micron rewrite-recommended */ +#define NAND_STATUS_RR 0x08 /** * struct pl353_nand_command_format - Defines NAND flash command format @@ -97,6 +111,7 @@ struct pl353_nand_info { unsigned long end_cmd_pending; unsigned long end_cmd; int last_read_page; + int ondie_ecc_enabled; }; /* @@ -104,6 +119,7 @@ struct pl353_nand_info { */ static const struct pl353_nand_command_format pl353_nand_commands[] = { {NAND_CMD_READ0, NAND_CMD_READSTART, 5, PL353_NAND_CMD_PHASE}, + {NAND_CMD_READ0_ONLY, NAND_CMD_NONE, 0, NAND_CMD_NONE}, {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, PL353_NAND_CMD_PHASE}, {NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE}, {NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE}, @@ -857,11 +873,28 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, return; } - if (command == NAND_CMD_READ0) + if (command == NAND_CMD_READ0) { + /* If using on-die ECC, we must check the NAND status for an + * ECC warning or error after reading a page. + */ + if (xnand->ondie_ecc_enabled) { + uint8_t status; + + pl353_nand_cmd_function(mtd, NAND_CMD_STATUS, -1, -1); + status = chip->read_byte(mtd); + pl353_nand_cmd_function(mtd, NAND_CMD_READ0_ONLY, -1, + -1); + if (status & NAND_STATUS_RR) + ++mtd->ecc_stats.corrected; + else if (status & NAND_STATUS_FAIL) + ++mtd->ecc_stats.failed; + } + /* Store the read page address so that we can detect consecutive * reads of the same page and only send one read command. */ xnand->last_read_page = page_addr; + } } /** From d0c7b042a75fde375a8368b363de44bfc1f8c9c9 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Mon, 22 Apr 2013 13:49:03 -0500 Subject: [PATCH 15/97] Xilinx: ARM: nand: Deassert CS when the chip is no longer in use In some cases, CS remains asserted to the NAND chip after an operation has completed. We should make sure to deassert CS when the chip is no longer in use. Refactored to avoid variable hiding. Signed-off-by: Jeff Westfahl --- drivers/mtd/nand/pl353_nand.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index d8181b490fbc8..38411c4c17c18 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -706,12 +706,25 @@ static int pl353_nand_read_page_swecc(struct mtd_info *mtd, * pl353_nand_select_chip - Select the flash device * @mtd: Pointer to the mtd info structure * @chip: Pointer to the NAND chip info structure - * - * This function is empty as the NAND controller handles chip select line - * internally based on the chip address passed in command and data phase. */ static void pl353_nand_select_chip(struct mtd_info *mtd, int chip) { + /* CS is automatically asserted when a command or data access is + * started. In this function we only need to deassert CS when the + * chip is no longer in use. Unfortunately, the only way we can + * do this is to read a byte of data from the NAND chip. + */ + if (-1 == chip) { + struct nand_chip *nand_chip; + unsigned long data_phase_addr; + + nand_chip = (struct nand_chip *)mtd->priv; + data_phase_addr = (unsigned long __force)nand_chip->IO_ADDR_R; + data_phase_addr |= PL353_NAND_CLEAR_CS; + nand_chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr; + + readb(nand_chip->IO_ADDR_R); + } return; } From d3d67cbd3488f350fb05d603e0d56fb0af2f979f Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Thu, 25 Sep 2014 15:18:43 -0500 Subject: [PATCH 16/97] mtd: nand: xilinx: Rename the pl353 NAND driver to match bootloader The Zynq static memory controller is based on ARM PL353. The following commit [3fa059cfa4b105f09752a4eb7480d122dd5e796b nand: pl353: Renamed zynq_nand driver as pl353_nand] renamed the driver to "pl353-nand" to match the hardware. This creates problems on shipping hardware due to a mismatch between what u-boot expects (via bootargs/mtdparts) and the kernel driver name. This commit reverts the NAND driver name to the old "xilinx_nand" in order to preserve compatibility. Signed-off-by: Gratian Crisan Acked-by: Joseph Hershberger Acked-by: Terry Wilcox Natinst-ReviewBoard-ID: 79256 --- drivers/mtd/nand/pl353_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index 38411c4c17c18..84ead572fc72e 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -30,7 +30,7 @@ #include #include -#define PL353_NAND_DRIVER_NAME "pl353-nand" +#define PL353_NAND_DRIVER_NAME "xilinx_nand" /* NAND flash driver defines */ #define PL353_NAND_CMD_PHASE 1 /* End command valid in command phase */ From 51c072cb05b8c1bd91a11412ba184932d63b80bf Mon Sep 17 00:00:00 2001 From: Brad Mouring Date: Tue, 21 Jun 2016 14:40:14 -0500 Subject: [PATCH 17/97] nand: pl353: Fix private data's use of mtd_info In ed4f85c03 (mtd: nand: embed an mtd_info structure into nand_chip), an mtd_info structure was embedded into the nand_chip struct since all drivers were doing the same thing. This was an attempt to simplify and streamline. In 862eba519 (mtd: nand: make use of mtd_to_nand() in NAND core code) this change was put into practice, changing the nand_core's mapping of mtd-to-nand to use the embedded mtd_info in the nand_chip struct. Update the pl353_nand driver to use this new embedded structure. Signed-off-by: Brad Mouring --- drivers/mtd/nand/pl353_nand.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index 84ead572fc72e..ca4a8b5f9d6cf 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -105,7 +105,6 @@ struct pl353_nand_command_format { */ struct pl353_nand_info { struct nand_chip chip; - struct mtd_info mtd; struct mtd_partition *parts; void __iomem *nand_base; unsigned long end_cmd_pending; @@ -718,7 +717,7 @@ static void pl353_nand_select_chip(struct mtd_info *mtd, int chip) struct nand_chip *nand_chip; unsigned long data_phase_addr; - nand_chip = (struct nand_chip *)mtd->priv; + nand_chip = mtd_to_nand(mtd); data_phase_addr = (unsigned long __force)nand_chip->IO_ADDR_R; data_phase_addr |= PL353_NAND_CLEAR_CS; nand_chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr; @@ -738,10 +737,10 @@ static void pl353_nand_select_chip(struct mtd_info *mtd, int chip) static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, int column, int page_addr) { - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); const struct pl353_nand_command_format *curr_cmd = NULL; struct pl353_nand_info *xnand = - container_of(mtd, struct pl353_nand_info, mtd); + container_of(mtd_to_nand(mtd), struct pl353_nand_info, chip); void __iomem *cmd_addr; unsigned long cmd_data = 0, end_cmd_valid = 0; unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i; @@ -919,7 +918,7 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, static void pl353_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { int i; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); unsigned long *ptr = (unsigned long *)buf; len >>= 2; @@ -937,7 +936,7 @@ static void pl353_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { int i; - struct nand_chip *chip = mtd->priv; + struct nand_chip *chip = mtd_to_nand(mtd); unsigned long *ptr = (unsigned long *)buf; len >>= 2; @@ -971,7 +970,7 @@ static int pl353_nand_device_ready(struct mtd_info *mtd) */ static int pl353_nand_detect_ondie_ecc(struct mtd_info *mtd) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); u8 maf_id, dev_id, i, get_feature; u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; @@ -1030,7 +1029,7 @@ static int pl353_nand_detect_ondie_ecc(struct mtd_info *mtd) */ static void pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *nand_chip = mtd_to_nand(mtd); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.read_oob = pl353_nand_read_oob; @@ -1133,11 +1132,10 @@ static int pl353_nand_probe(struct platform_device *pdev) return PTR_ERR(xnand->nand_base); /* Link the private data with the MTD structure */ - mtd = &xnand->mtd; nand_chip = &xnand->chip; + mtd = &xnand->chip.mtd; nand_chip->priv = xnand; - mtd->priv = nand_chip; mtd->owner = THIS_MODULE; mtd->name = PL353_NAND_DRIVER_NAME; @@ -1183,7 +1181,7 @@ static int pl353_nand_probe(struct platform_device *pdev) return -ENXIO; } - mtd_device_parse_register(&xnand->mtd, NULL, NULL, NULL, 0); + mtd_device_parse_register(&xnand->chip.mtd, NULL, NULL, NULL, 0); return 0; } @@ -1202,7 +1200,7 @@ static int pl353_nand_remove(struct platform_device *pdev) struct pl353_nand_info *xnand = platform_get_drvdata(pdev); /* Release resources, unregister device */ - nand_release(&xnand->mtd); + nand_release(&xnand->chip.mtd); /* kfree(NULL) is safe */ kfree(xnand->parts); From 325cb97c9feb0f75b922a515520e69f096968221 Mon Sep 17 00:00:00 2001 From: Haris Okanovic Date: Wed, 7 Sep 2016 11:16:52 -0500 Subject: [PATCH 18/97] pl353_nand: Add module params to disable subpage read and write Add `enable_subpage_read` and `enable_subpage_write` load-time options to toggle subpage read/write operations on pl353 chips. Both options are enabled by default, and may be toggled in the boot loader. Signed-off-by: Haris Okanovic Acked-by: Gratian Crisan Acked-by: Jeff Westfahl Natinst-CAR-ID: 599280 Natinst-ReviewBoard-ID: 151758 (cherry picked from commit 311a5711cfdbfa20e3f4ec2dbd429f96b9f76c2f) --- drivers/mtd/nand/pl353_nand.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index ca4a8b5f9d6cf..8c8ee10219a73 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -203,6 +203,14 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = mirror_pattern }; +static bool enable_subpage_read = 1; +module_param(enable_subpage_read, bool, 0444); +MODULE_PARM_DESC(enable_subpage_read, "Load-time parameter to toggle subpage reads on supported nand chips. Enabled by default."); + +static bool enable_subpage_write = 1; +module_param(enable_subpage_write, bool, 0444); +MODULE_PARM_DESC(enable_subpage_write, "Load-time parameter to toggle subpage writes on supported nand chips. Enabled by default."); + /** * pl353_nand_calculate_hwecc - Calculate Hardware ECC * @mtd: Pointer to the mtd_info structure @@ -1055,13 +1063,21 @@ static void pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) nand_chip->ecc.size = mtd->writesize; /* NAND with on-die ECC supports subpage reads */ - nand_chip->options |= NAND_SUBPAGE_READ; + if (enable_subpage_read) + nand_chip->options |= NAND_SUBPAGE_READ; + else + nand_chip->options &= ~(NAND_SUBPAGE_READ); /* NAND with on-die ECC may support subpage writes */ if (nand_chip->onfi_version) nand_chip->ecc.size /= nand_chip->onfi_params.programs_per_page; + if (enable_subpage_write) + nand_chip->options &= ~(NAND_NO_SUBPAGE_WRITE); + else + nand_chip->options |= NAND_NO_SUBPAGE_WRITE; + /* * On-Die ECC spare bytes offset 8 is used for ECC codes * Use the BBT pattern descriptors From 3bc908fcd844a6b4f97eb0c2848174a59e6fc1f9 Mon Sep 17 00:00:00 2001 From: Haris Okanovic Date: Mon, 12 Sep 2016 17:33:19 -0500 Subject: [PATCH 19/97] pl353_nand: Add dsb(st) (store-only data sync barrier) after reg writes Add dsb(st) [1] after writes to command register to ensure the chip receives them before ndelay()-ing to synchronize driver/chip state. The subsequent ndelay()s (after dsb(st)) gives the chip enough time to process "quick" commands (like RNDOUT) which don't change status flags or issue interrupts upon completion. They are assumed to complete at most 100ns after delivery on the bus. It's therefore critical to ensure they make it all the way down to the chip before the driver ndelay()s for on-chip processing. Otherwise, commands may get buffered in the interconnect between the CPU and chip while the driver waits. Subsequent read/write operations may then be delivered inside the on-chip processing window resulting in incorrect behavior. In particular, a READ0 (page select + col change), followed by RNDOUT (column change only), followed by data reads <1page in size results in sporadic one-byte data corruption, particularity when the bus is busy. Testing: No longer see a sporadic 1 byte corruption after RNDOUT by repeatedly reading the entire Linux file system after fs-cache drop for 48 hours. Verified RNDOUT requires the ndelay() by unsuccessfully attempting to remove it for that command. Doing so results in the same sporadic 1 byte corruption in the aforementioned read test. Ran fio [2] with random read/write+verify for 48 hours; no corruptions reported. Config: rw=randrw, size=100M, bs=5k, verify=sha256, numjobs=5 Hardware: National Instruments cRIO-9068 [3] Xilinx Zynq-7020 SoC MT29F8G08ADBDAH4 8GB NAND [1] http://infocenter.arm.com/help/topic/com.arm.doc.dui0489c/CIHGHHIE.html#id4692433 [2] http://linux.die.net/man/1/fio [3] https://sine.ni.com/nips/cds/view/p/lang/en/nid/211620 Signed-off-by: Haris Okanovic Signed-off-by: Brad Mouring Acked-by: Jeff Westfahl Natinst-CAR-ID: 599280 Natinst-ReviewBoard-ID: 152950 --- drivers/mtd/nand/pl353_nand.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index 8c8ee10219a73..a0facf7fff316 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -868,6 +868,12 @@ static void pl353_nand_cmd_function(struct mtd_info *mtd, unsigned int command, pl353_nand_write32(cmd_addr, cmd_data); + /* + * Ensure writes to the command register are observed by chip + * before proceeding to ndelay() and other reads/writes. + */ + dsb(st); + if (curr_cmd->end_cmd_valid) { xnand->end_cmd = curr_cmd->end_cmd; xnand->end_cmd_pending = 1; From b9327ab876c212ddb89497e692b94a52646031e9 Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Wed, 3 Feb 2016 14:14:46 -0600 Subject: [PATCH 20/97] HACK: ARM: zynq: established early fixed mapping for PL353 NAND region Haven't yet figured out why this is required...hack it. Signed-off-by: Josh Cartwright --- arch/arm/mach-zynq/common.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 15e8a321a713b..9848f69734c15 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -152,6 +152,13 @@ static struct map_desc zynq_cortex_a9_scu_map __initdata = { .type = MT_DEVICE, }; +static struct map_desc pl353_space __initdata = { + .length = SZ_16M, + .type = MT_DEVICE, + .pfn = __phys_to_pfn(0xE1000000), + .virtual = 0xE1000000, +}; + static void __init zynq_scu_map_io(void) { unsigned long base; @@ -163,6 +170,8 @@ static void __init zynq_scu_map_io(void) iotable_init(&zynq_cortex_a9_scu_map, 1); zynq_scu_base = (void __iomem *)base; BUG_ON(!zynq_scu_base); + + iotable_init(&pl353_space, 1); } /** From 105d0173a0fe270fa6a00a6002fb6d9891f7ecba Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Thu, 3 Aug 2017 14:30:57 -0500 Subject: [PATCH 21/97] mtd: nand: pl353: Convert nand_ecclayout structs to mtd_ooblayout_ops Commit aab616e31d1c ("mtd: kill the nand_ecclayout struct") removed the nand_ecclayout struct. Convert the pl353_nand driver to the new mtd_ooblayout_ops model. Fixes: 627a2ef8fb01 ("mtd: nand: pl353: add snapshot of driver from linux-xlnx tree") Signed-off-by: Gratian Crisan --- drivers/mtd/nand/pl353_nand.c | 99 +++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 34 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index a0facf7fff316..4593f8590aa99 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -143,40 +143,73 @@ static const struct pl353_nand_command_format pl353_nand_commands[] = { }; /* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = { - {.offset = 8, - . length = 8} } -}; -static struct nand_ecclayout nand_oob_64 = { - .eccbytes = 12, - .eccpos = { - 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63}, - .oobfree = { - {.offset = 2, - .length = 50} } -}; +static int pl353_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section) + return -ERANGE; -static struct nand_ecclayout ondie_nand_oob_64 = { - .eccbytes = 32, + if (mtd->oobsize == 64) { + oobregion->offset = 52; + oobregion->length = 12; + } else { + oobregion->offset = 0; + oobregion->length = 3; + } - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 24, 25, 26, 27, 28, 29, 30, 31, - 40, 41, 42, 43, 44, 45, 46, 47, - 56, 57, 58, 59, 60, 61, 62, 63 - }, + return 0; +} - .oobfree = { - { .offset = 4, .length = 4 }, - { .offset = 20, .length = 4 }, - { .offset = 36, .length = 4 }, - { .offset = 52, .length = 4 } +static int pl353_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section) + return -ERANGE; + + if (mtd->oobsize == 64) { + oobregion->offset = 2; + oobregion->length = 50; + } else { + oobregion->offset = 8; + oobregion->length = 8; } + + return 0; +} + +static const struct mtd_ooblayout_ops pl353_ooblayout_ops = { + .ecc = pl353_ooblayout_ecc, + .free = pl353_ooblayout_free, +}; + +static int pl353_ondie_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section > 3) + return -ERANGE; + + oobregion->length = 8; + oobregion->offset = 8 * (section * 2 + 1); + + return 0; +} + +static int pl353_ondie_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section > 3) + return -ERANGE; + + oobregion->length = 4; + oobregion->offset = 4 + section * 16; + + return 0; +} + +static const struct mtd_ooblayout_ops pl353_ondie_ooblayout_ops = { + .ecc = pl353_ondie_ooblayout_ecc, + .free = pl353_ondie_ooblayout_free, }; /* Generic flash bbt decriptors */ @@ -1061,7 +1094,6 @@ static void pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) * SMC controller */ nand_chip->ecc.bytes = 0; - nand_chip->ecc.layout = &ondie_nand_oob_64; nand_chip->ecc.read_page = pl353_nand_read_page_raw; nand_chip->ecc.read_subpage = pl353_nand_read_subpage_raw; nand_chip->ecc.write_page = pl353_nand_write_page_raw; @@ -1090,6 +1122,8 @@ static void pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) */ nand_chip->bbt_td = &bbt_main_descr; nand_chip->bbt_md = &bbt_mirror_descr; + + mtd_set_ooblayout(mtd, &pl353_ondie_ooblayout_ops); } else { /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ nand_chip->ecc.bytes = 3; @@ -1120,10 +1154,7 @@ static void pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) break; } - if (mtd->oobsize == 16) - nand_chip->ecc.layout = &nand_oob_16; - else if (mtd->oobsize == 64) - nand_chip->ecc.layout = &nand_oob_64; + mtd_set_ooblayout(mtd, &pl353_ooblayout_ops); } } From cbdf0fccfa293813a109c8442570ed0320b6fc25 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Thu, 3 Aug 2017 15:10:43 -0500 Subject: [PATCH 22/97] mtd: nand: pl353: Use mtd_ooblayout_xxx() helpers Commit 7f2b092c9eed ("mtd: nand: kill the ecc->layout field") removed direct access to the ecc layout field. Use instead the mtd_ooblayout_xxx() helper functions in places where the eccpos[] array was accessed directly. Fixes: 627a2ef8fb01 ("mtd: nand: pl353: add snapshot of driver from linux-xlnx tree") Signed-off-by: Gratian Crisan --- drivers/mtd/nand/pl353_nand.c | 52 +++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index 4593f8590aa99..9aab45c54f1cb 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -542,7 +542,8 @@ static int pl353_nand_write_page_hwecc(struct mtd_info *mtd, int eccsteps = chip->ecc.steps; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; + struct mtd_oob_region oobregion = { }; + int section = 0; unsigned long data_phase_addr; uint8_t *oob_ptr; @@ -563,8 +564,14 @@ static int pl353_nand_write_page_hwecc(struct mtd_info *mtd, p = buf; chip->ecc.calculate(mtd, p, &ecc_calc[0]); - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]); + for (i = 0; i < chip->ecc.total; i++) { + if (!oobregion.length) + mtd_ooblayout_ecc(mtd, section++, &oobregion); + + chip->oob_poi[oobregion.offset] = ~(ecc_calc[i]); + oobregion.length--; + oobregion.offset++; + } /* Clear ECC last bit */ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; @@ -604,14 +611,21 @@ static int pl353_nand_write_page_swecc(struct mtd_info *mtd, int eccsteps = chip->ecc.steps; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; + struct mtd_oob_region oobregion = { }; + int section = 0; /* Software ecc calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; + for (i = 0; i < chip->ecc.total; i++) { + if (!oobregion.length) + mtd_ooblayout_ecc(mtd, section++, &oobregion); + + chip->oob_poi[oobregion.offset] = ecc_calc[i]; + oobregion.length--; + oobregion.offset++; + } chip->ecc.write_page_raw(mtd, chip, buf, 1, page); @@ -641,7 +655,8 @@ static int pl353_nand_read_page_hwecc(struct mtd_info *mtd, uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; + struct mtd_oob_region oobregion = { }; + int section = 0; unsigned long data_phase_addr; uint8_t *oob_ptr; @@ -680,8 +695,14 @@ static int pl353_nand_read_page_hwecc(struct mtd_info *mtd, oob_ptr += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); chip->read_buf(mtd, oob_ptr, PL353_NAND_LAST_TRANSFER_LENGTH); - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = ~(chip->oob_poi[eccpos[i]]); + for (i = 0; i < chip->ecc.total; i++) { + if (!oobregion.length) + mtd_ooblayout_ecc(mtd, section++, &oobregion); + + ecc_code[i] = ~(chip->oob_poi[oobregion.offset]); + oobregion.length--; + oobregion.offset++; + } eccsteps = chip->ecc.steps; p = buf; @@ -717,15 +738,22 @@ static int pl353_nand_read_page_swecc(struct mtd_info *mtd, uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; + struct mtd_oob_region oobregion = { }; + int section = 0; chip->ecc.read_page_raw(mtd, chip, buf, page, 1); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; + for (i = 0; i < chip->ecc.total; i++) { + if (!oobregion.length) + mtd_ooblayout_ecc(mtd, section++, &oobregion); + + ecc_code[i] = chip->oob_poi[oobregion.offset]; + oobregion.length--; + oobregion.offset++; + } eccsteps = chip->ecc.steps; p = buf; From 792e13cf7fcf6514b9ae6d4db699439c4b57454f Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Mon, 5 Mar 2012 11:55:13 -0600 Subject: [PATCH 23/97] nizynqcpld: Add support for the NI Zynq CPLD The NI Zynq prototype board has a CPLD that provides various board-management capabilities. Signed-off-by: Josh Cartwright Signed-off-by: Jaeden Amero Acked-by: Jeff Westfahl Acked-by: Joe Hershberger [cvadrevu: Fixed trivial conflicts due to newer module] Signed-off-by: Chaitanya Vadrevu --- drivers/misc/Kconfig | 10 ++ drivers/misc/Makefile | 1 + drivers/misc/nizynqcpld.c | 222 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 drivers/misc/nizynqcpld.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 62ca3814ce43e..64ae506071e5c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -102,6 +102,16 @@ config IBMVMC To compile this driver as a module, choose M here: the module will be called ibmvmc. +config NIZYNQ_CPLD + tristate "National Instruments Zynq CPLD driver" + depends on I2C + help + If you say yes here, you get support for the CPLD features + on National Instruments Zynq-based targets. + + This driver can also be built as a module. If so, the module + will be called nizynqcpld.ko. + config PHANTOM tristate "Sensable PHANToM (PCI)" depends on PCI diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 59e6fe9a576b7..f80a181198c44 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_SMPRO_ERRMON) += smpro-errmon.o obj-$(CONFIG_SMPRO_MISC) += smpro-misc.o obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o obj-$(CONFIG_GEHC_ACHC) += gehc-achc.o +obj-$(CONFIG_NIZYNQ_CPLD) += nizynqcpld.o obj-$(CONFIG_HP_ILO) += hpilo.o obj-$(CONFIG_APDS9802ALS) += apds9802als.o obj-$(CONFIG_ISL29003) += isl29003.o diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c new file mode 100644 index 0000000000000..ac8eebb4683c2 --- /dev/null +++ b/drivers/misc/nizynqcpld.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2012 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include + + +#define NIZYNQCPLD_VERSION 0x00 +#define NIZYNQCPLD_PRODUCT 0x1D + +struct nizynqcpld_desc { + u8 supported_version; + u8 supported_product; +}; + +struct nizynqcpld { + struct device *dev; + struct nizynqcpld_desc *desc; + struct i2c_client *client; + struct mutex lock; +}; + +static int nizynqcpld_write(struct nizynqcpld *cpld, u8 reg, u8 data); +static int nizynqcpld_read(struct nizynqcpld *cpld, u8 reg, u8 *data); + +static inline void nizynqcpld_lock(struct nizynqcpld *cpld) +{ + mutex_lock(&cpld->lock); +} +static inline void nizynqcpld_unlock(struct nizynqcpld *cpld) +{ + mutex_unlock(&cpld->lock); +} + +static int nizynqcpld_write(struct nizynqcpld *cpld, u8 reg, u8 data) +{ + int err; + u8 tdata[2] = { reg, data }; + + /* write reg byte, then data */ + struct i2c_msg msg = { + .addr = cpld->client->addr, + .len = 2, + .buf = tdata, + }; + + err = i2c_transfer(cpld->client->adapter, &msg, 1); + + return err == 1 ? 0 : err; +} + +static int nizynqcpld_read(struct nizynqcpld *cpld, u8 reg, u8 *data) +{ + int err; + + /* First, write the CPLD register offset, then read the data. */ + struct i2c_msg msgs[] = { + { + .addr = cpld->client->addr, + .len = 1, + .buf = ®, + }, + { + .addr = cpld->client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = data, + }, + }; + + err = i2c_transfer(cpld->client->adapter, msgs, ARRAY_SIZE(msgs)); + + return err == ARRAY_SIZE(msgs) ? 0 : err; +} + +static struct nizynqcpld_desc nizynqcpld_descs[] = { + /* DosEquis and myRIO development CPLD */ + { + .supported_version = 3, + .supported_product = 0, + }, + /* DosEquis and myRIO development CPLD */ + { + .supported_version = 4, + .supported_product = 0, + }, + /* DosEquis and myRIO development CPLD */ + { + .supported_version = 5, + .supported_product = 0, + }, + /* DosEquis CPLD */ + { + .supported_version = 6, + .supported_product = 0, + }, + /* myRIO CPLD */ + { + .supported_version = 6, + .supported_product = 1, + }, +}; + +static int nizynqcpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct nizynqcpld_desc *desc; + struct nizynqcpld *cpld; + u8 version; + u8 product; + int err; + int i; + + cpld = kzalloc(sizeof(*cpld), GFP_KERNEL); + if (!cpld) { + err = -ENOMEM; + dev_err(&client->dev, "could not allocate private data.\n"); + goto err_cpld_alloc; + } + + cpld->dev = &client->dev; + cpld->client = client; + mutex_init(&cpld->lock); + + err = nizynqcpld_read(cpld, NIZYNQCPLD_VERSION, + &version); + if (err) { + dev_err(cpld->dev, "could not read version cpld version.\n"); + goto err_read_info; + } + + err = nizynqcpld_read(cpld, NIZYNQCPLD_PRODUCT, &product); + if (err) { + dev_err(cpld->dev, "could not read cpld product number.\n"); + goto err_read_info; + } + + for (i = 0, desc = NULL; i < ARRAY_SIZE(nizynqcpld_descs); i++) { + if (nizynqcpld_descs[i].supported_version == version && + nizynqcpld_descs[i].supported_product == product) { + desc = &nizynqcpld_descs[i]; + break; + } + } + + if (!desc) { + err = -ENODEV; + dev_err(cpld->dev, + "this driver does not support cpld with version %d and" + " product %d.\n", version, product); + goto err_no_version; + } + + cpld->desc = desc; + + i2c_set_clientdata(client, cpld); + + dev_info(&client->dev, + "%s NI Zynq-based target CPLD found.\n", + client->name); + + return 0; + +err_no_version: +err_read_info: + kfree(cpld); +err_cpld_alloc: + return err; +} + +static int nizynqcpld_remove(struct i2c_client *client) +{ + struct nizynqcpld *cpld = i2c_get_clientdata(client); + + kfree(cpld); + return 0; +} + +static const struct i2c_device_id nizynqcpld_ids[] = { + { .name = "nizynqcpld" }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, nizynqcpld_ids); + +static struct i2c_driver nizynqcpld_driver = { + .driver = { + .name = "nizynqcpld", + .owner = THIS_MODULE, + }, + .probe = nizynqcpld_probe, + .remove = nizynqcpld_remove, + .id_table = nizynqcpld_ids, +}; + +static int __init nizynqcpld_init(void) +{ + return i2c_add_driver(&nizynqcpld_driver); +} +module_init(nizynqcpld_init); + +static void __exit nizynqcpld_exit(void) +{ + i2c_del_driver(&nizynqcpld_driver); +} +module_exit(nizynqcpld_exit); + +MODULE_DESCRIPTION("Driver for CPLD on NI's Zynq RIO products"); +MODULE_AUTHOR("National Instruments"); +MODULE_LICENSE("GPL"); From 09c937cc1a993fa8713160a1f2ca20e3fd5af92f Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Mon, 5 Mar 2012 11:55:13 -0600 Subject: [PATCH 24/97] nizynqcpld: Add scratchpad read and write This provides a general purpose, raw interface to the CPLD's scratchpad. The scratchpad can be used to communicate between soft reboots of the target. Signed-off-by: Josh Cartwright --- drivers/misc/Kconfig | 2 +- drivers/misc/nizynqcpld.c | 135 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 64ae506071e5c..b1fb65d6b480d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -104,7 +104,7 @@ config IBMVMC config NIZYNQ_CPLD tristate "National Instruments Zynq CPLD driver" - depends on I2C + depends on I2C && SYSFS help If you say yes here, you get support for the CPLD features on National Instruments Zynq-based targets. diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index ac8eebb4683c2..e2e6b072986e8 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -21,9 +21,18 @@ #define NIZYNQCPLD_VERSION 0x00 #define NIZYNQCPLD_PRODUCT 0x1D +#define PROTO_SCRATCHPADSR 0xFE +#define PROTO_SCRATCHPADHR 0xFF + +#define DOSX_SCRATCHPADSR 0x1E +#define DOSX_SCRATCHPADHR 0x1F + struct nizynqcpld_desc { + const struct attribute **attrs; u8 supported_version; u8 supported_product; + u8 scratch_hr_addr; + u8 scratch_sr_addr; }; struct nizynqcpld { @@ -86,31 +95,147 @@ static int nizynqcpld_read(struct nizynqcpld *cpld, u8 reg, u8 *data) return err == ARRAY_SIZE(msgs) ? 0 : err; } +static inline ssize_t nizynqcpld_scratch_show(struct nizynqcpld *cpld, + struct device_attribute *attr, + char *buf, u8 reg_addr) +{ + u8 data; + int err; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, reg_addr, &data); + nizynqcpld_unlock(cpld); + + if (err) { + dev_err(cpld->dev, "Error reading scratch register state.\n"); + return err; + } + + return sprintf(buf, "%02x\n", data); +} + +static ssize_t nizynqcpld_scratchsr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_show(cpld, attr, buf, desc->scratch_sr_addr); +} + +static ssize_t nizynqcpld_scratchhr_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_show(cpld, attr, buf, desc->scratch_hr_addr); +} + +static inline ssize_t nizynqcpld_scratch_store(struct nizynqcpld *cpld, + struct device_attribute *attr, + const char *buf, size_t count, + u8 reg_addr) +{ + unsigned long tmp; + u8 data; + int err; + + err = kstrtoul(buf, 0, &tmp); + if (err) + return err; + + data = (u8) tmp; + + nizynqcpld_lock(cpld); + err = nizynqcpld_write(cpld, reg_addr, data); + nizynqcpld_unlock(cpld); + + if (err) { + dev_err(cpld->dev, + "Error writing to scratch register.\n"); + return err; + } + + return count; +} + +static ssize_t nizynqcpld_scratchsr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_store(cpld, attr, buf, count, + desc->scratch_sr_addr); +} + +static ssize_t nizynqcpld_scratchhr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_store(cpld, attr, buf, count, + desc->scratch_hr_addr); +} + +static DEVICE_ATTR(scratch_softreset, S_IRUSR|S_IWUSR, + nizynqcpld_scratchsr_show, nizynqcpld_scratchsr_store); +static DEVICE_ATTR(scratch_hardreset, S_IRUSR|S_IWUSR, + nizynqcpld_scratchhr_show, nizynqcpld_scratchhr_store); + +static const struct attribute *nizynqcpld_attrs[] = { + &dev_attr_scratch_softreset.attr, + &dev_attr_scratch_hardreset.attr, + NULL +}; + +static const struct attribute *dosequis6_attrs[] = { + &dev_attr_scratch_softreset.attr, + &dev_attr_scratch_hardreset.attr, + NULL +}; + static struct nizynqcpld_desc nizynqcpld_descs[] = { /* DosEquis and myRIO development CPLD */ { + .attrs = nizynqcpld_attrs, .supported_version = 3, .supported_product = 0, + .scratch_hr_addr = PROTO_SCRATCHPADHR, + .scratch_sr_addr = PROTO_SCRATCHPADSR, }, /* DosEquis and myRIO development CPLD */ { + .attrs = nizynqcpld_attrs, .supported_version = 4, .supported_product = 0, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, }, /* DosEquis and myRIO development CPLD */ { + .attrs = nizynqcpld_attrs, .supported_version = 5, .supported_product = 0, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, }, /* DosEquis CPLD */ { + .attrs = dosequis6_attrs, .supported_version = 6, .supported_product = 0, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, }, /* myRIO CPLD */ { + .attrs = dosequis6_attrs, .supported_version = 6, .supported_product = 1, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, }, }; @@ -166,6 +291,12 @@ static int nizynqcpld_probe(struct i2c_client *client, cpld->desc = desc; + err = sysfs_create_files(&cpld->dev->kobj, desc->attrs); + if (err) { + dev_err(cpld->dev, "could not register attrs for device.\n"); + goto err_sysfs_create_files; + } + i2c_set_clientdata(client, cpld); dev_info(&client->dev, @@ -174,6 +305,8 @@ static int nizynqcpld_probe(struct i2c_client *client, return 0; + sysfs_remove_files(&client->dev.kobj, desc->attrs); +err_sysfs_create_files: err_no_version: err_read_info: kfree(cpld); @@ -184,7 +317,9 @@ static int nizynqcpld_probe(struct i2c_client *client, static int nizynqcpld_remove(struct i2c_client *client) { struct nizynqcpld *cpld = i2c_get_clientdata(client); + struct nizynqcpld_desc *desc = cpld->desc; + sysfs_remove_files(&cpld->dev->kobj, desc->attrs); kfree(cpld); return 0; } From 056778e54de12ffdb63041abf6257f79fd205d25 Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Mon, 20 Aug 2012 18:43:12 -0500 Subject: [PATCH 25/97] nizynqcpld: Add 'bootmode' attribute This is a read/write attribute that will set the necessary bits in the scratch registers used to determine which mode the board boots into. Currently, valid modes are 'runtime', 'safemode', and 'recovery'. Signed-off-by: Josh Cartwright --- drivers/misc/nizynqcpld.c | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index e2e6b072986e8..24781cbf19ada 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -184,13 +184,81 @@ static DEVICE_ATTR(scratch_softreset, S_IRUSR|S_IWUSR, static DEVICE_ATTR(scratch_hardreset, S_IRUSR|S_IWUSR, nizynqcpld_scratchhr_show, nizynqcpld_scratchhr_store); +static const char * const bootmode_strings[] = { + "runtime", "safemode", "recovery", +}; + +static ssize_t nizynqcpld_bootmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + int err; + u8 tmp; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, desc->scratch_hr_addr, &tmp); + nizynqcpld_unlock(cpld); + + if (err) + return err; + + tmp &= 0x3; + if (tmp >= ARRAY_SIZE(bootmode_strings)) + return -EINVAL; + + return sprintf(buf, "%s\n", bootmode_strings[tmp]); +} + +static int nizynqcpld_set_bootmode(struct nizynqcpld *cpld, u8 mode) +{ + struct nizynqcpld_desc *desc = cpld->desc; + int err; + u8 tmp; + + nizynqcpld_lock(cpld); + + err = nizynqcpld_read(cpld, desc->scratch_hr_addr, &tmp); + if (err) + goto unlock_out; + + tmp &= ~0x3; + tmp |= mode; + + err = nizynqcpld_write(cpld, desc->scratch_hr_addr, tmp); + +unlock_out: + nizynqcpld_unlock(cpld); + return err; +} + +static ssize_t nizynqcpld_bootmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + u8 i; + + for (i = 0; i < ARRAY_SIZE(bootmode_strings); i++) + if (!strcmp(buf, bootmode_strings[i])) + return nizynqcpld_set_bootmode(cpld, i) ?: count; + + return -EINVAL; +} + +static DEVICE_ATTR(bootmode, S_IRUSR|S_IWUSR, nizynqcpld_bootmode_show, + nizynqcpld_bootmode_store); + static const struct attribute *nizynqcpld_attrs[] = { + &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, &dev_attr_scratch_hardreset.attr, NULL }; static const struct attribute *dosequis6_attrs[] = { + &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, &dev_attr_scratch_hardreset.attr, NULL From 089ef1b4ca5761671bc07e5efc76efcb647e0947 Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Mon, 5 Mar 2012 11:55:13 -0600 Subject: [PATCH 26/97] nizynqcpld: Add support for LEDs Signed-off-by: Josh Cartwright Signed-off-by: Scot Salmon Acked-by: Brad Mouring Acked-by: Josh Cartwright Natinst-ReviewBoard-ID: 36482 --- drivers/misc/Kconfig | 2 +- drivers/misc/nizynqcpld.c | 265 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+), 1 deletion(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b1fb65d6b480d..7f369157c4609 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -104,7 +104,7 @@ config IBMVMC config NIZYNQ_CPLD tristate "National Instruments Zynq CPLD driver" - depends on I2C && SYSFS + depends on I2C && SYSFS && LEDS_CLASS help If you say yes here, you get support for the CPLD features on National Instruments Zynq-based targets. diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 24781cbf19ada..4f5fce3cd72ab 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -12,6 +12,7 @@ * GNU General Public License for more details. */ #include +#include #include #include #include @@ -21,16 +22,48 @@ #define NIZYNQCPLD_VERSION 0x00 #define NIZYNQCPLD_PRODUCT 0x1D +#define PROTO_SWITCHANDLED 0x04 +#define PROTO_ETHERNETLED 0x05 #define PROTO_SCRATCHPADSR 0xFE #define PROTO_SCRATCHPADHR 0xFF +#define DOSX_STATUSLEDSHIFTBYTE1 0x05 +#define DOSX_STATUSLEDSHIFTBYTE0 0x06 +#define DOSX_LED 0x07 +#define DOSX_ETHERNETLED 0x08 #define DOSX_SCRATCHPADSR 0x1E #define DOSX_SCRATCHPADHR 0x1F +struct nizynqcpld_led_desc { + const char *name; + const char *default_trigger; + u8 addr; + u8 bit; + u8 pattern_lo_addr; + u8 pattern_hi_addr; + int max_brightness; +}; + +struct nizynqcpld; + +struct nizynqcpld_led { + struct nizynqcpld *cpld; + struct nizynqcpld_led_desc *desc; + unsigned on:1; + struct led_classdev cdev; + struct work_struct deferred_work; + u16 blink_pattern; +}; + +#define to_nizynqcpld_led(x) \ + container_of(x, struct nizynqcpld_led, cdev) + struct nizynqcpld_desc { const struct attribute **attrs; u8 supported_version; u8 supported_product; + struct nizynqcpld_led_desc *led_descs; + unsigned num_led_descs; u8 scratch_hr_addr; u8 scratch_sr_addr; }; @@ -38,6 +71,7 @@ struct nizynqcpld_desc { struct nizynqcpld { struct device *dev; struct nizynqcpld_desc *desc; + struct nizynqcpld_led *leds; struct i2c_client *client; struct mutex lock; }; @@ -54,6 +88,70 @@ static inline void nizynqcpld_unlock(struct nizynqcpld *cpld) mutex_unlock(&cpld->lock); } +/* Can't issue i2c transfers in set_brightness, because + * they can sleep */ +static void nizynqcpld_set_brightness_work(struct work_struct *work) +{ + struct nizynqcpld_led *led = container_of(work, struct nizynqcpld_led, + deferred_work); + struct nizynqcpld_led_desc *desc = led->desc; + struct nizynqcpld *cpld = led->cpld; + int err; + u8 tmp; + + nizynqcpld_lock(cpld); + + err = nizynqcpld_read(cpld, desc->addr, &tmp); + if (err) + goto unlock_out; + + tmp &= ~desc->bit; + if (led->on) + tmp |= desc->bit; + + nizynqcpld_write(cpld, desc->addr, tmp); + + if (desc->pattern_lo_addr && desc->pattern_hi_addr) { + /* spec says to write byte 1 first */ + nizynqcpld_write(cpld, desc->pattern_hi_addr, + led->blink_pattern >> 8); + nizynqcpld_write(cpld, desc->pattern_lo_addr, + led->blink_pattern & 0xff); + } + +unlock_out: + nizynqcpld_unlock(cpld); +} + +static void nizynqcpld_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct nizynqcpld_led *led = to_nizynqcpld_led(led_cdev); + led->on = !!brightness; + /* some LED's support a blink pattern instead of a variable brightness, + and blink_set isn't flexible enough for the supported patterns */ + led->blink_pattern = brightness; + schedule_work(&led->deferred_work); +} + +static enum led_brightness +nizynqcpld_led_get_brightness(struct led_classdev *led_cdev) +{ + struct nizynqcpld_led *led = to_nizynqcpld_led(led_cdev); + struct nizynqcpld_led_desc *desc = led->desc; + struct nizynqcpld *cpld = led->cpld; + u8 tmp; + + nizynqcpld_lock(cpld); + /* can't handle an error here, so, roll with it. */ + nizynqcpld_read(cpld, desc->addr, &tmp); + nizynqcpld_unlock(cpld); + + /* for the status LED, the blink pattern used for brightness on write + is write-only, so we just return on/off for all LED's */ + return tmp & desc->bit ? LED_FULL : 0; +} + static int nizynqcpld_write(struct nizynqcpld *cpld, u8 reg, u8 data) { int err; @@ -71,6 +169,49 @@ static int nizynqcpld_write(struct nizynqcpld *cpld, u8 reg, u8 data) return err == 1 ? 0 : err; } +static int nizynqcpld_led_register(struct nizynqcpld *cpld, + struct nizynqcpld_led_desc *desc, + struct nizynqcpld_led *led) +{ + int err; + u8 tmp; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, desc->addr, &tmp); + nizynqcpld_unlock(cpld); + + if (err) + goto err_out; + + led->cpld = cpld; + led->desc = desc; + led->on = !!(tmp & desc->bit); + INIT_WORK(&led->deferred_work, nizynqcpld_set_brightness_work); + + led->cdev.name = desc->name; + led->cdev.default_trigger = desc->default_trigger; + led->cdev.max_brightness = desc->max_brightness ? desc->max_brightness + : 1; + led->cdev.brightness_set = nizynqcpld_led_set_brightness; + led->cdev.brightness_get = nizynqcpld_led_get_brightness; + + err = led_classdev_register(cpld->dev, &led->cdev); + if (err) { + dev_err(cpld->dev, "error registering led.\n"); + goto err_led; + } + +err_led: +err_out: + return err; +} + +static void nizynqcpld_led_unregister(struct nizynqcpld_led *led) +{ + led_classdev_unregister(&led->cdev); +} + + static int nizynqcpld_read(struct nizynqcpld *cpld, u8 reg, u8 *data) { int err; @@ -264,12 +405,104 @@ static const struct attribute *dosequis6_attrs[] = { NULL }; +static struct nizynqcpld_led_desc proto_leds[] = { + { + .name = "nizynqcpld:user1:green", + .addr = PROTO_SWITCHANDLED, + .bit = 1 << 4, + }, + { + .name = "nizynqcpld:user1:yellow", + .addr = PROTO_SWITCHANDLED, + .bit = 1 << 3, + }, + { + .name = "nizynqcpld:status:yellow", + .addr = PROTO_SWITCHANDLED, + .bit = 1 << 2, + }, + { + .name = "nizynqcpld:eth1:green", + .addr = PROTO_ETHERNETLED, + .bit = 1 << 1, + .default_trigger = "e000b000:00:100Mb", + }, + { + .name = "nizynqcpld:eth1:yellow", + .addr = PROTO_ETHERNETLED, + .bit = 1 << 0, + .default_trigger = "e000b000:00:Gb", + }, +}; + +static struct nizynqcpld_led_desc dosx_leds[] = { + { + .name = "nizynqcpld:user1:green", + .addr = DOSX_LED, + .bit = 1 << 5, + }, + { + .name = "nizynqcpld:user1:yellow", + .addr = DOSX_LED, + .bit = 1 << 4, + }, + { + .name = "nizynqcpld:status:red", + .addr = DOSX_LED, + .bit = 1 << 3, + }, + { + .name = "nizynqcpld:status:yellow", + .addr = DOSX_LED, + .bit = 1 << 2, + .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, + .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, + .max_brightness = 0xffff, + }, + { + .name = "nizynqcpld:wifi:green", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 5, + }, + { + .name = "nizynqcpld:wifi:yellow", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 4, + }, + { + .name = "nizynqcpld:eth1:green", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 3, + .default_trigger = "e000b000:01:100Mb", + }, + { + .name = "nizynqcpld:eth1:yellow", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 2, + .default_trigger = "e000b000:01:Gb", + }, + { + .name = "nizynqcpld:eth0:green", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 1, + .default_trigger = "e000b000:00:100Mb", + }, + { + .name = "nizynqcpld:eth0:yellow", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 0, + .default_trigger = "e000b000:00:Gb", + }, +}; + static struct nizynqcpld_desc nizynqcpld_descs[] = { /* DosEquis and myRIO development CPLD */ { .attrs = nizynqcpld_attrs, .supported_version = 3, .supported_product = 0, + .led_descs = proto_leds, + .num_led_descs = ARRAY_SIZE(proto_leds), .scratch_hr_addr = PROTO_SCRATCHPADHR, .scratch_sr_addr = PROTO_SCRATCHPADSR, }, @@ -278,6 +511,8 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .attrs = nizynqcpld_attrs, .supported_version = 4, .supported_product = 0, + .led_descs = dosx_leds, + .num_led_descs = ARRAY_SIZE(dosx_leds), .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -286,6 +521,8 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .attrs = nizynqcpld_attrs, .supported_version = 5, .supported_product = 0, + .led_descs = dosx_leds, + .num_led_descs = ARRAY_SIZE(dosx_leds), .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -294,6 +531,8 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .attrs = dosequis6_attrs, .supported_version = 6, .supported_product = 0, + .led_descs = dosx_leds, + .num_led_descs = ARRAY_SIZE(dosx_leds), .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -302,6 +541,8 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .attrs = dosequis6_attrs, .supported_version = 6, .supported_product = 1, + .led_descs = dosx_leds, + .num_led_descs = ARRAY_SIZE(dosx_leds), .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -359,6 +600,21 @@ static int nizynqcpld_probe(struct i2c_client *client, cpld->desc = desc; + cpld->leds = kzalloc(sizeof(*cpld->leds) * desc->num_led_descs, + GFP_KERNEL); + if (!cpld->leds) { + err = -ENOMEM; + dev_err(cpld->dev, "could not allocate led state data\n"); + goto err_led_alloc; + } + + for (i = 0; i < desc->num_led_descs; i++) { + err = nizynqcpld_led_register(cpld, &desc->led_descs[i], + &cpld->leds[i]); + if (err) + goto err_led; + } + err = sysfs_create_files(&cpld->dev->kobj, desc->attrs); if (err) { dev_err(cpld->dev, "could not register attrs for device.\n"); @@ -375,6 +631,11 @@ static int nizynqcpld_probe(struct i2c_client *client, sysfs_remove_files(&client->dev.kobj, desc->attrs); err_sysfs_create_files: +err_led: + while (i--) + nizynqcpld_led_unregister(&cpld->leds[i]); + kfree(cpld->leds); +err_led_alloc: err_no_version: err_read_info: kfree(cpld); @@ -386,8 +647,12 @@ static int nizynqcpld_remove(struct i2c_client *client) { struct nizynqcpld *cpld = i2c_get_clientdata(client); struct nizynqcpld_desc *desc = cpld->desc; + int i; sysfs_remove_files(&cpld->dev->kobj, desc->attrs); + for (i = desc->num_led_descs - 1; i; --i) + nizynqcpld_led_unregister(&cpld->leds[i]); + kfree(cpld->leds); kfree(cpld); return 0; } From 1e4612bd67dce94705de53d4892a65174ea52c2e Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Mon, 5 Mar 2012 11:55:13 -0600 Subject: [PATCH 27/97] nizynqcpld: Add reboot support Use the SLCR to reboot the zynq if a reset function is not provided. Signed-off-by: Josh Cartwright Signed-off-by: Nathan Sullivan Acked-by: Jeff Westfahl Acked-by: Joe Hershberger Natinst-ReviewBoard-ID: 90458 --- drivers/misc/nizynqcpld.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 4f5fce3cd72ab..2f881f553b968 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -15,18 +15,20 @@ #include #include #include +#include #include #include - #define NIZYNQCPLD_VERSION 0x00 #define NIZYNQCPLD_PRODUCT 0x1D +#define PROTO_PROCESSORSTATE 0x01 #define PROTO_SWITCHANDLED 0x04 #define PROTO_ETHERNETLED 0x05 #define PROTO_SCRATCHPADSR 0xFE #define PROTO_SCRATCHPADHR 0xFF +#define DOSX_PROCESSORRESET 0x02 #define DOSX_STATUSLEDSHIFTBYTE1 0x05 #define DOSX_STATUSLEDSHIFTBYTE0 0x06 #define DOSX_LED 0x07 @@ -64,6 +66,7 @@ struct nizynqcpld_desc { u8 supported_product; struct nizynqcpld_led_desc *led_descs; unsigned num_led_descs; + u8 reboot_addr; u8 scratch_hr_addr; u8 scratch_sr_addr; }; @@ -74,6 +77,7 @@ struct nizynqcpld { struct nizynqcpld_led *leds; struct i2c_client *client; struct mutex lock; + struct ni_zynq_board_reset reset; }; static int nizynqcpld_write(struct nizynqcpld *cpld, u8 reg, u8 data); @@ -236,6 +240,14 @@ static int nizynqcpld_read(struct nizynqcpld *cpld, u8 reg, u8 *data) return err == ARRAY_SIZE(msgs) ? 0 : err; } +static void nizynqcpld_reset(struct ni_zynq_board_reset *reset) +{ + struct nizynqcpld *cpld = container_of(reset, struct nizynqcpld, reset); + struct nizynqcpld_desc *desc = cpld->desc; + + nizynqcpld_write(cpld, desc->reboot_addr, 0x80); +} + static inline ssize_t nizynqcpld_scratch_show(struct nizynqcpld *cpld, struct device_attribute *attr, char *buf, u8 reg_addr) @@ -503,6 +515,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_product = 0, .led_descs = proto_leds, .num_led_descs = ARRAY_SIZE(proto_leds), + .reboot_addr = PROTO_PROCESSORSTATE, .scratch_hr_addr = PROTO_SCRATCHPADHR, .scratch_sr_addr = PROTO_SCRATCHPADSR, }, @@ -513,6 +526,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_product = 0, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), + .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -523,6 +537,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_product = 0, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), + .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -533,6 +548,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_product = 0, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), + .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -543,6 +559,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_product = 1, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), + .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, }, @@ -621,6 +638,9 @@ static int nizynqcpld_probe(struct i2c_client *client, goto err_sysfs_create_files; } + cpld->reset.reset = nizynqcpld_reset; + ni_zynq_board_reset = &cpld->reset; + i2c_set_clientdata(client, cpld); dev_info(&client->dev, @@ -649,6 +669,8 @@ static int nizynqcpld_remove(struct i2c_client *client) struct nizynqcpld_desc *desc = cpld->desc; int i; + ni_zynq_board_reset = NULL; + sysfs_remove_files(&cpld->dev->kobj, desc->attrs); for (i = desc->num_led_descs - 1; i; --i) nizynqcpld_led_unregister(&cpld->leds[i]); From 017088254b524b1cb15f7e5a0429489f7a5c1cdc Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Mon, 20 Aug 2012 17:15:28 -0500 Subject: [PATCH 28/97] nizynqcpld: Add attributes to query switches This will expose the switches as sysfs attributes for consumption by the RT utilities VIs. Signed-off-by: Josh Cartwright --- drivers/misc/nizynqcpld.c | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 2f881f553b968..73e8d08f36d61 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -33,6 +33,7 @@ #define DOSX_STATUSLEDSHIFTBYTE0 0x06 #define DOSX_LED 0x07 #define DOSX_ETHERNETLED 0x08 +#define DOSX_DEBUGSWITCH 0x09 #define DOSX_SCRATCHPADSR 0x1E #define DOSX_SCRATCHPADHR 0x1F @@ -69,6 +70,7 @@ struct nizynqcpld_desc { u8 reboot_addr; u8 scratch_hr_addr; u8 scratch_sr_addr; + u8 switch_addr; }; struct nizynqcpld { @@ -337,6 +339,45 @@ static DEVICE_ATTR(scratch_softreset, S_IRUSR|S_IWUSR, static DEVICE_ATTR(scratch_hardreset, S_IRUSR|S_IWUSR, nizynqcpld_scratchhr_show, nizynqcpld_scratchhr_store); +struct switch_attribute { + struct device_attribute dev_attr; + u8 bit; +}; + +static inline ssize_t nizynqcpld_switch_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + struct switch_attribute *sa = + container_of(attr, struct switch_attribute, dev_attr); + int err; + u8 data; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, desc->switch_addr, &data); + nizynqcpld_unlock(cpld); + + if (err) { + dev_err(dev, "Error reading switch state.\n"); + return err; + } + + return sprintf(buf, "%u\n", !!(data & sa->bit)); +} + +#define SWITCH_ATTR(_name, _bit) \ + struct switch_attribute dev_attr_##_name = { \ + .bit = _bit, \ + .dev_attr = \ + __ATTR(_name, 0444, nizynqcpld_switch_show, NULL), \ + } + +static SWITCH_ATTR(console_out, 1 << 7); +static SWITCH_ATTR(ip_reset, 1 << 6); +static SWITCH_ATTR(safe_mode, 1 << 5); + static const char * const bootmode_strings[] = { "runtime", "safemode", "recovery", }; @@ -407,6 +448,9 @@ static const struct attribute *nizynqcpld_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, &dev_attr_scratch_hardreset.attr, + &dev_attr_console_out.dev_attr.attr, + &dev_attr_ip_reset.dev_attr.attr, + &dev_attr_safe_mode.dev_attr.attr, NULL }; @@ -414,6 +458,9 @@ static const struct attribute *dosequis6_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, &dev_attr_scratch_hardreset.attr, + &dev_attr_console_out.dev_attr.attr, + &dev_attr_ip_reset.dev_attr.attr, + &dev_attr_safe_mode.dev_attr.attr, NULL }; @@ -518,6 +565,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = PROTO_PROCESSORSTATE, .scratch_hr_addr = PROTO_SCRATCHPADHR, .scratch_sr_addr = PROTO_SCRATCHPADSR, + .switch_addr = PROTO_SWITCHANDLED, }, /* DosEquis and myRIO development CPLD */ { @@ -529,6 +577,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = DOSX_DEBUGSWITCH, }, /* DosEquis and myRIO development CPLD */ { @@ -540,6 +589,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = DOSX_DEBUGSWITCH, }, /* DosEquis CPLD */ { @@ -551,6 +601,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = DOSX_DEBUGSWITCH, }, /* myRIO CPLD */ { @@ -562,6 +613,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = DOSX_DEBUGSWITCH, }, }; From 78ff412405e75dbc9ccee973a9d4053bdab41871 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Tue, 9 Oct 2012 11:42:15 -0500 Subject: [PATCH 29/97] nizynqcpld: Add NI Watchdog support Add support for the Dos Equis CPLD watchdog, implementing the NI Watchdog ioctl interface with a misc device. Signed-off-by: Jeff Westfahl Signed-off-by: Scot Salmon Acked-by: Brad Mouring Acked-by: Josh Cartwright Natinst-ReviewBoard-ID: 36482 --- drivers/misc/nizynqcpld.c | 499 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 499 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 73e8d08f36d61..9db44e76f9718 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -11,12 +11,18 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include #include +#include #include +#include #include +#include #include #include +#include #include +#include #include #define NIZYNQCPLD_VERSION 0x00 @@ -34,9 +40,28 @@ #define DOSX_LED 0x07 #define DOSX_ETHERNETLED 0x08 #define DOSX_DEBUGSWITCH 0x09 +#define DOSX_WATCHDOGCONTROL 0x13 +#define DOSX_WATCHDOGCOUNTER2 0x14 +#define DOSX_WATCHDOGCOUNTER1 0x15 +#define DOSX_WATCHDOGCOUNTER0 0x16 +#define DOSX_WATCHDOGSEED2 0x17 +#define DOSX_WATCHDOGSEED1 0x18 +#define DOSX_WATCHDOGSEED0 0x19 #define DOSX_SCRATCHPADSR 0x1E #define DOSX_SCRATCHPADHR 0x1F +#define DOSX_WATCHDOGCONTROL_PROC_INTERRUPT 0x40 +#define DOSX_WATCHDOGCONTROL_PROC_RESET 0x20 +#define DOSX_WATCHDOGCONTROL_ENTER_USER_MODE 0x80 +#define DOSX_WATCHDOGCONTROL_PET 0x10 +#define DOSX_WATCHDOGCONTROL_RUNNING 0x08 +#define DOSX_WATCHDOGCONTROL_CAPTURECOUNTER 0x04 +#define DOSX_WATCHDOGCONTROL_RESET 0x02 +#define DOSX_WATCHDOGCONTROL_ALARM 0x01 + +#define DOSX_WATCHDOG_MAX_COUNTER 0x00FFFFFF +#define DOSX_WATCHDOG_COUNTER_BYTES 3 + struct nizynqcpld_led_desc { const char *name; const char *default_trigger; @@ -61,22 +86,37 @@ struct nizynqcpld_led { #define to_nizynqcpld_led(x) \ container_of(x, struct nizynqcpld_led, cdev) +struct nizynqcpld_watchdog_desc { + u32 watchdog_period_ns; +}; + +struct nizynqcpld_watchdog { + struct miscdevice misc_dev; + struct nizynqcpld_watchdog_desc *desc; + atomic_t available; + wait_queue_head_t irq_event; + bool expired; +}; + struct nizynqcpld_desc { const struct attribute **attrs; u8 supported_version; u8 supported_product; struct nizynqcpld_led_desc *led_descs; unsigned num_led_descs; + struct nizynqcpld_watchdog_desc *watchdog_desc; u8 reboot_addr; u8 scratch_hr_addr; u8 scratch_sr_addr; u8 switch_addr; + u8 watchdog_addr; }; struct nizynqcpld { struct device *dev; struct nizynqcpld_desc *desc; struct nizynqcpld_led *leds; + struct nizynqcpld_watchdog watchdog; struct i2c_client *client; struct mutex lock; struct ni_zynq_board_reset reset; @@ -454,6 +494,51 @@ static const struct attribute *nizynqcpld_attrs[] = { NULL }; +static ssize_t dosequiscpld_wdmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + int err; + u8 tmp; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, desc->watchdog_addr, &tmp); + nizynqcpld_unlock(cpld); + + if (err) + return err; + + /* you write a 1 to the bit to enter user mode, but it reads as a + 0 in user mode for backwards compatibility */ + tmp &= DOSX_WATCHDOGCONTROL_ENTER_USER_MODE; + return sprintf(buf, "%s\n", tmp ? "boot" : "user"); +} + +static ssize_t dosequiscpld_wdmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct nizynqcpld_desc *desc = cpld->desc; + int err; + + /* you can only switch boot->user */ + if (strcmp(buf, "user")) + return -EINVAL; + + nizynqcpld_lock(cpld); + err = nizynqcpld_write(cpld, desc->watchdog_addr, + DOSX_WATCHDOGCONTROL_ENTER_USER_MODE); + nizynqcpld_unlock(cpld); + + return err ?: count; +} + +static DEVICE_ATTR(watchdog_mode, S_IRUSR|S_IWUSR, dosequiscpld_wdmode_show, + dosequiscpld_wdmode_store); + static const struct attribute *dosequis6_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, @@ -461,9 +546,386 @@ static const struct attribute *dosequis6_attrs[] = { &dev_attr_console_out.dev_attr.attr, &dev_attr_ip_reset.dev_attr.attr, &dev_attr_safe_mode.dev_attr.attr, + &dev_attr_watchdog_mode.attr, NULL }; +/* + * CPLD Watchdog (only for dosequis) + */ +static int nizynqcpld_watchdog_counter_set(struct nizynqcpld *cpld, u32 counter) +{ + int err; + u8 data[DOSX_WATCHDOG_COUNTER_BYTES]; + + data[0] = ((0x00FF0000 & counter) >> 16); + data[1] = ((0x0000FF00 & counter) >> 8); + data[2] = (0x000000FF & counter); + + nizynqcpld_lock(cpld); + + err = i2c_smbus_write_i2c_block_data(cpld->client, + DOSX_WATCHDOGSEED2, + DOSX_WATCHDOG_COUNTER_BYTES, + data); + nizynqcpld_unlock(cpld); + if (err) + dev_err(cpld->dev, + "Error %d writing watchdog counter.\n", err); + return err; +} + +static int nizynqcpld_watchdog_check_action(u32 action) +{ + int err = 0; + + switch (action) { + case DOSX_WATCHDOGCONTROL_PROC_INTERRUPT: + case DOSX_WATCHDOGCONTROL_PROC_RESET: + break; + default: + err = -ENOTSUPP; + } + + return err; +} + +static int nizynqcpld_watchdog_add_action(struct nizynqcpld *cpld, u32 action) +{ + int err; + u8 action_mask; + u8 control; + + if (NIWATCHDOG_ACTION_INTERRUPT == action) + action_mask = DOSX_WATCHDOGCONTROL_PROC_INTERRUPT; + else if (NIWATCHDOG_ACTION_RESET == action) + action_mask = DOSX_WATCHDOGCONTROL_PROC_RESET; + else + return -ENOTSUPP; + + nizynqcpld_lock(cpld); + + err = nizynqcpld_read(cpld, DOSX_WATCHDOGCONTROL, &control); + + if (err) { + dev_err(cpld->dev, + "Error %d reading watchdog control.\n", err); + goto out_unlock; + } + control |= action_mask; + + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control); + + if (err) { + dev_err(cpld->dev, + "Error %d writing watchdog control.\n", err); + goto out_unlock; + } +out_unlock: + nizynqcpld_unlock(cpld); + return err; +} + +static int nizynqcpld_watchdog_start(struct nizynqcpld *cpld) +{ + int err; + u8 control; + + nizynqcpld_lock(cpld); + + cpld->watchdog.expired = false; + + err = nizynqcpld_read(cpld, DOSX_WATCHDOGCONTROL, &control); + if (err) { + dev_err(cpld->dev, + "Error %d reading watchdog control.\n", err); + goto out_unlock; + } + + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, + control | DOSX_WATCHDOGCONTROL_RESET); + if (err) { + dev_err(cpld->dev, + "Error %d writing watchdog control.\n", err); + goto out_unlock; + } + + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, + control | DOSX_WATCHDOGCONTROL_PET); + if (err) { + dev_err(cpld->dev, + "Error %d writing watchdog control.\n", err); + goto out_unlock; + } +out_unlock: + nizynqcpld_unlock(cpld); + return err; +} + +static int nizynqcpld_watchdog_pet(struct nizynqcpld *cpld, u32 *state) +{ + int err; + u8 control; + + nizynqcpld_lock(cpld); + + if (cpld->watchdog.expired) { + err = 0; + *state = NIWATCHDOG_STATE_EXPIRED; + } else { + err = nizynqcpld_read(cpld, DOSX_WATCHDOGCONTROL, &control); + if (err) { + dev_err(cpld->dev, + "Error %d reading watchdog control.\n", err); + goto out_unlock; + } + + control |= DOSX_WATCHDOGCONTROL_PET; + + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control); + if (err) { + dev_err(cpld->dev, + "Error %d writing watchdog control.\n", err); + goto out_unlock; + } + + *state = NIWATCHDOG_STATE_RUNNING; + } + +out_unlock: + nizynqcpld_unlock(cpld); + return err; +} + +static int nizynqcpld_watchdog_reset(struct nizynqcpld *cpld) +{ + int err; + + nizynqcpld_lock(cpld); + + cpld->watchdog.expired = false; + + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, + DOSX_WATCHDOGCONTROL_RESET); + + nizynqcpld_unlock(cpld); + + if (err) + dev_err(cpld->dev, + "Error %d writing watchdog control.\n", err); + return err; +} + +static int nizynqcpld_watchdog_counter_get(struct nizynqcpld *cpld, + u32 *counter) +{ + int err; + u8 control; + u8 data[DOSX_WATCHDOG_COUNTER_BYTES]; + + nizynqcpld_lock(cpld); + + err = nizynqcpld_read(cpld, DOSX_WATCHDOGCONTROL, &control); + + if (err) { + dev_err(cpld->dev, + "Error %d reading watchdog control.\n", err); + goto out_unlock; + } + + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, + control | DOSX_WATCHDOGCONTROL_CAPTURECOUNTER); + if (err) { + dev_err(cpld->dev, + "Error %d capturing watchdog counter.\n", err); + goto out_unlock; + } + + /* Returns the number of read bytes */ + err = i2c_smbus_read_i2c_block_data(cpld->client, + DOSX_WATCHDOGCOUNTER2, + DOSX_WATCHDOG_COUNTER_BYTES, + data); + if (DOSX_WATCHDOG_COUNTER_BYTES == err) + err = 0; + else { + dev_err(cpld->dev, + "Error %d reading watchdog counter.\n", err); + goto out_unlock; + } + + *counter = (data[0] << 16) | (data[1] << 8) | data[2]; + +out_unlock: + nizynqcpld_unlock(cpld); + return err; +} + +static irqreturn_t nizynqcpld_watchdog_irq(int irq, void *data) +{ + struct nizynqcpld *cpld = data; + irqreturn_t ret = IRQ_NONE; + u8 control; + int err; + + nizynqcpld_lock(cpld); + + err = nizynqcpld_read(cpld, DOSX_WATCHDOGCONTROL, &control); + + if (err) { + dev_err(cpld->dev, + "Error %d reading watchdog control.\n", err); + goto out_unlock; + } else if (!(DOSX_WATCHDOGCONTROL_ALARM & control)) { + dev_err(cpld->dev, + "Spurious watchdog interrupt, 0x%02X\n", control); + goto out_unlock; + } + + cpld->watchdog.expired = true; + + /* Acknowledge the interrupt. */ + control |= DOSX_WATCHDOGCONTROL_RESET; + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control); + + /* Signal the watchdog event. */ + wake_up_all(&cpld->watchdog.irq_event); + + ret = IRQ_HANDLED; + +out_unlock: + nizynqcpld_unlock(cpld); + return ret; +} + +static int nizynqcpld_watchdog_misc_open(struct inode *inode, + struct file *file) +{ + struct miscdevice *misc_dev = file->private_data; + struct nizynqcpld *cpld = container_of(misc_dev, struct nizynqcpld, + watchdog.misc_dev); + file->private_data = cpld; + + if (!atomic_dec_and_test(&cpld->watchdog.available)) { + atomic_inc(&cpld->watchdog.available); + return -EBUSY; + } + + return request_threaded_irq(cpld->client->irq, + NULL, nizynqcpld_watchdog_irq, + 0, NIWATCHDOG_NAME, cpld); +} + +static int nizynqcpld_watchdog_misc_release(struct inode *inode, + struct file *file) +{ + struct nizynqcpld *cpld = file->private_data; + free_irq(cpld->client->irq, cpld); + atomic_inc(&cpld->watchdog.available); + return 0; +} + +long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct nizynqcpld *cpld = file->private_data; + struct nizynqcpld_watchdog_desc *desc; + int err; + + desc = cpld->watchdog.desc; + + switch (cmd) { + case NIWATCHDOG_IOCTL_PERIOD_NS: { + __u32 period = desc->watchdog_period_ns; + err = copy_to_user((__u32 *)arg, &period, + sizeof(__u32)); + break; + } + case NIWATCHDOG_IOCTL_MAX_COUNTER: { + __u32 counter = DOSX_WATCHDOG_MAX_COUNTER; + err = copy_to_user((__u32 *)arg, &counter, + sizeof(__u32)); + break; + } + case NIWATCHDOG_IOCTL_COUNTER_SET: { + __u32 counter; + err = copy_from_user(&counter, (__u32 *)arg, + sizeof(__u32)); + if (!err) + err = nizynqcpld_watchdog_counter_set(cpld, counter); + break; + } + case NIWATCHDOG_IOCTL_CHECK_ACTION: { + __u32 action; + err = copy_from_user(&action, (__u32 *)arg, + sizeof(__u32)); + if (!err) + err = nizynqcpld_watchdog_check_action(action); + break; + } + case NIWATCHDOG_IOCTL_ADD_ACTION: { + __u32 action; + err = copy_from_user(&action, (__u32 *)arg, + sizeof(__u32)); + if (!err) + err = nizynqcpld_watchdog_add_action(cpld, action); + break; + } + case NIWATCHDOG_IOCTL_START: { + err = nizynqcpld_watchdog_start(cpld); + break; + } + case NIWATCHDOG_IOCTL_PET: { + __u32 state; + err = nizynqcpld_watchdog_pet(cpld, &state); + if (!err) + err = copy_to_user((__u32 *)arg, &state, + sizeof(__u32)); + break; + } + case NIWATCHDOG_IOCTL_RESET: { + err = nizynqcpld_watchdog_reset(cpld); + break; + } + case NIWATCHDOG_IOCTL_COUNTER_GET: { + __u32 counter; + err = nizynqcpld_watchdog_counter_get(cpld, &counter); + if (!err) { + err = copy_to_user((__u32 *)arg, &counter, + sizeof(__u32)); + } + break; + } + default: + err = -EINVAL; + break; + }; + + return err; +} + +unsigned int nizynqcpld_watchdog_misc_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct nizynqcpld *cpld = file->private_data; + unsigned int mask = 0; + + poll_wait(file, &cpld->watchdog.irq_event, wait); + nizynqcpld_lock(cpld); + if (cpld->watchdog.expired) + mask = POLLIN; + nizynqcpld_unlock(cpld); + return mask; +} + +static const struct file_operations nizynqcpld_watchdog_misc_fops = { + .owner = THIS_MODULE, + .open = nizynqcpld_watchdog_misc_open, + .release = nizynqcpld_watchdog_misc_release, + .unlocked_ioctl = nizynqcpld_watchdog_misc_ioctl, + .poll = nizynqcpld_watchdog_misc_poll, +}; + static struct nizynqcpld_led_desc proto_leds[] = { { .name = "nizynqcpld:user1:green", @@ -554,6 +1016,14 @@ static struct nizynqcpld_led_desc dosx_leds[] = { }, }; +static struct nizynqcpld_watchdog_desc dosxv4_watchdog_desc = { + .watchdog_period_ns = 24000, +}; + +static struct nizynqcpld_watchdog_desc dosxv5_watchdog_desc = { + .watchdog_period_ns = 30720, +}; + static struct nizynqcpld_desc nizynqcpld_descs[] = { /* DosEquis and myRIO development CPLD */ { @@ -572,6 +1042,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .attrs = nizynqcpld_attrs, .supported_version = 4, .supported_product = 0, + .watchdog_desc = &dosxv4_watchdog_desc, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), .reboot_addr = DOSX_PROCESSORRESET, @@ -584,6 +1055,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .attrs = nizynqcpld_attrs, .supported_version = 5, .supported_product = 0, + .watchdog_desc = &dosxv5_watchdog_desc, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), .reboot_addr = DOSX_PROCESSORRESET, @@ -596,24 +1068,28 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .attrs = dosequis6_attrs, .supported_version = 6, .supported_product = 0, + .watchdog_desc = &dosxv5_watchdog_desc, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, .switch_addr = DOSX_DEBUGSWITCH, + .watchdog_addr = DOSX_WATCHDOGCONTROL, }, /* myRIO CPLD */ { .attrs = dosequis6_attrs, .supported_version = 6, .supported_product = 1, + .watchdog_desc = &dosxv5_watchdog_desc, .led_descs = dosx_leds, .num_led_descs = ARRAY_SIZE(dosx_leds), .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, .switch_addr = DOSX_DEBUGSWITCH, + .watchdog_addr = DOSX_WATCHDOGCONTROL, }, }; @@ -690,6 +1166,25 @@ static int nizynqcpld_probe(struct i2c_client *client, goto err_sysfs_create_files; } + if (desc->watchdog_desc) { + struct nizynqcpld_watchdog *watchdog = &cpld->watchdog; + + watchdog->desc = desc->watchdog_desc; + atomic_set(&watchdog->available, 1); + init_waitqueue_head(&watchdog->irq_event); + watchdog->expired = false; + + watchdog->misc_dev.minor = MISC_DYNAMIC_MINOR; + watchdog->misc_dev.name = NIWATCHDOG_NAME; + watchdog->misc_dev.fops = &nizynqcpld_watchdog_misc_fops; + err = misc_register(&watchdog->misc_dev); + if (err) { + dev_err(cpld->dev, + "Couldn't register misc device\n"); + goto err_watchdog_register; + } + } + cpld->reset.reset = nizynqcpld_reset; ni_zynq_board_reset = &cpld->reset; @@ -701,6 +1196,7 @@ static int nizynqcpld_probe(struct i2c_client *client, return 0; +err_watchdog_register: sysfs_remove_files(&client->dev.kobj, desc->attrs); err_sysfs_create_files: err_led: @@ -723,6 +1219,9 @@ static int nizynqcpld_remove(struct i2c_client *client) ni_zynq_board_reset = NULL; + if (desc->watchdog_desc) + misc_deregister(&cpld->watchdog.misc_dev); + sysfs_remove_files(&cpld->dev->kobj, desc->attrs); for (i = desc->num_led_descs - 1; i; --i) nizynqcpld_led_unregister(&cpld->leds[i]); From 4a423ad3bdbbe1a8ebd448db8ac9ea3509aacb2b Mon Sep 17 00:00:00 2001 From: Ioan Cornea Date: Thu, 17 Oct 2013 14:47:41 +0300 Subject: [PATCH 30/97] nizynqcpld: Add support for wifi button on myRIO Signed-off-by: Ioan Cornea --- drivers/misc/nizynqcpld.c | 174 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 9db44e76f9718..ba8186d6d0a1d 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #define NIZYNQCPLD_VERSION 0x00 #define NIZYNQCPLD_PRODUCT 0x1D @@ -62,6 +64,13 @@ #define DOSX_WATCHDOG_MAX_COUNTER 0x00FFFFFF #define DOSX_WATCHDOG_COUNTER_BYTES 3 +#define MYRIO_WIFISWCTRL_ADDR 0x0A +#define MYRIO_WIFISWCTRL_STATE 0x01 +#define MYRIO_WIFISWCTRL_ENPUSHIRQ 0x08 +#define MYRIO_WIFISWCTRL_PUSHIRQ 0x80 +#define MYRIO_WIFISWCTRL_ENRELIRQ 0x04 +#define MYRIO_WIFISWCTRL_RELIRQ 0x40 + struct nizynqcpld_led_desc { const char *name; const char *default_trigger; @@ -98,6 +107,13 @@ struct nizynqcpld_watchdog { bool expired; }; +struct myrio_wifi_sw { + struct input_dev *idev; + struct work_struct deferred_work; + bool irq_registered; + int irq; +}; + struct nizynqcpld_desc { const struct attribute **attrs; u8 supported_version; @@ -110,6 +126,7 @@ struct nizynqcpld_desc { u8 scratch_sr_addr; u8 switch_addr; u8 watchdog_addr; + u8 wifi_sw_addr; }; struct nizynqcpld { @@ -120,6 +137,7 @@ struct nizynqcpld { struct i2c_client *client; struct mutex lock; struct ni_zynq_board_reset reset; + struct myrio_wifi_sw wifi_sw; }; static int nizynqcpld_write(struct nizynqcpld *cpld, u8 reg, u8 data); @@ -1090,9 +1108,158 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .scratch_sr_addr = DOSX_SCRATCHPADSR, .switch_addr = DOSX_DEBUGSWITCH, .watchdog_addr = DOSX_WATCHDOGCONTROL, + .wifi_sw_addr = MYRIO_WIFISWCTRL_ADDR, }, }; +static void wifi_sw_work_func(struct work_struct *work) +{ + struct myrio_wifi_sw *wifi_sw = + container_of(work, struct myrio_wifi_sw, deferred_work); + struct nizynqcpld *cpld = + container_of(wifi_sw, struct nizynqcpld, wifi_sw); + u8 data; + int err; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, cpld->desc->wifi_sw_addr, &data); + nizynqcpld_unlock(cpld); + + if (err) { + dev_err(&cpld->client->dev, + "error %d reading wifi_sw control register\n", err); + return; + } + + /* check the interrupt flags and clear them */ + if (data & (MYRIO_WIFISWCTRL_PUSHIRQ | MYRIO_WIFISWCTRL_RELIRQ)) { + nizynqcpld_lock(cpld); + err = nizynqcpld_write(cpld, cpld->desc->wifi_sw_addr, data); + nizynqcpld_unlock(cpld); + + if (err) { + dev_err(&cpld->client->dev, + "err %d clearing wifi_sw irq flag\n", err); + return; + } + } + + input_event(wifi_sw->idev, + EV_KEY, BTN_0, !!(data & MYRIO_WIFISWCTRL_STATE)); + input_sync(wifi_sw->idev); +} + +static irqreturn_t wifi_sw_hnd(int irq, void *irq_data) +{ + struct myrio_wifi_sw *wifi_sw = (struct myrio_wifi_sw *)irq_data; + schedule_work(&wifi_sw->deferred_work); + + return IRQ_HANDLED; +} + +static int wifi_sw_open(struct input_dev *dev) +{ + int err; + struct myrio_wifi_sw *wifi_sw = input_get_drvdata(dev); + struct nizynqcpld *cpld = + container_of(wifi_sw, struct nizynqcpld, wifi_sw); + + err = request_threaded_irq(wifi_sw->irq, + NULL, wifi_sw_hnd, 0, "wifi_sw", wifi_sw); + if (err) { + dev_err(&cpld->client->dev, + "error %d registering irq handle for wifi_sw\n", err); + } + + wifi_sw->irq_registered = !err; + return err; +} + +static void wifi_sw_close(struct input_dev *dev) +{ + struct myrio_wifi_sw *wifi_sw = input_get_drvdata(dev); + + if (wifi_sw->irq_registered) + free_irq(wifi_sw->irq, wifi_sw_hnd); +} + +static int myrio_wifi_sw_init(struct nizynqcpld *cpld) +{ + u8 data; + int err = 0; + struct input_dev *input; + + if (!cpld->desc->wifi_sw_addr) + goto wifi_sw_init_exit; + + INIT_WORK(&cpld->wifi_sw.deferred_work, wifi_sw_work_func); + cpld->wifi_sw.irq = irq_of_parse_and_map(cpld->client->dev.of_node, 1); + + /* ensure that the interrupt was mapped */ + if (!cpld->wifi_sw.irq) + goto wifi_sw_init_exit; + + /* enable interrupts */ + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, cpld->desc->wifi_sw_addr, &data); + + if (!err) { + data |= (MYRIO_WIFISWCTRL_ENPUSHIRQ | + MYRIO_WIFISWCTRL_ENRELIRQ); + err = nizynqcpld_write(cpld, cpld->desc->wifi_sw_addr, data); + } + nizynqcpld_unlock(cpld); + + if (err) { + dev_err(&cpld->client->dev, + "error %d enabling wifi_sw irq\n", err); + goto wifi_sw_init_exit; + } + + input = input_allocate_device(); + cpld->wifi_sw.idev = input; + + if (!input) { + dev_err(&cpld->client->dev, + "error %d allocating input device for wifi_sw\n", err); + goto wifi_sw_init_exit; + } + + input->name = "wifi_btn"; + input->phys = "wifi_btn/wifibtn"; + input->open = wifi_sw_open; + input->close = wifi_sw_close; + input_set_capability(input, EV_KEY, BTN_0); + input_set_drvdata(input, &cpld->wifi_sw); + + err = input_register_device(cpld->wifi_sw.idev); + + /* report initial state */ + wifi_sw_work_func(&cpld->wifi_sw.deferred_work); + + if (err) { + dev_err(&cpld->client->dev, + "error %d registering input device for wifi_sw\n", err); + goto wifi_sw_init_exit_register; + } + + return err; + +wifi_sw_init_exit_register: + input_free_device(cpld->wifi_sw.idev); + +wifi_sw_init_exit: + return err; +} + +static void myrio_wifi_sw_uninit(struct nizynqcpld *cpld) +{ + if (cpld->desc->wifi_sw_addr) { + input_unregister_device(cpld->wifi_sw.idev); + input_free_device(cpld->wifi_sw.idev); + } +} + static int nizynqcpld_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1160,6 +1327,9 @@ static int nizynqcpld_probe(struct i2c_client *client, goto err_led; } + /* don't care about errors */ + myrio_wifi_sw_init(cpld); + err = sysfs_create_files(&cpld->dev->kobj, desc->attrs); if (err) { dev_err(cpld->dev, "could not register attrs for device.\n"); @@ -1199,6 +1369,7 @@ static int nizynqcpld_probe(struct i2c_client *client, err_watchdog_register: sysfs_remove_files(&client->dev.kobj, desc->attrs); err_sysfs_create_files: + myrio_wifi_sw_uninit(cpld); err_led: while (i--) nizynqcpld_led_unregister(&cpld->leds[i]); @@ -1226,6 +1397,9 @@ static int nizynqcpld_remove(struct i2c_client *client) for (i = desc->num_led_descs - 1; i; --i) nizynqcpld_led_unregister(&cpld->leds[i]); kfree(cpld->leds); + + myrio_wifi_sw_uninit(cpld); + kfree(cpld); return 0; } From e7e9c27fdccb7bfc8d00cd7f5b6598740eb143b0 Mon Sep 17 00:00:00 2001 From: Keng Soon Cheah Date: Wed, 28 Aug 2013 12:20:20 +0800 Subject: [PATCH 31/97] nizynqcpld: Add cRIO-906[6,7] CPLD support cRIO-906[6,7] (Sol) CPLD requires new driver support since it has a new version number. Also, the red and yellow LEDs and wifi LEDs are not supported. Signed-off-by: Keng Soon Cheah --- drivers/misc/nizynqcpld.c | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index ba8186d6d0a1d..824cb638ed527 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1034,6 +1034,47 @@ static struct nizynqcpld_led_desc dosx_leds[] = { }, }; +static struct nizynqcpld_led_desc sol_leds[] = { + { + .name = "nizynqcpld:user1:green", + .addr = DOSX_LED, + .bit = 1 << 5, + }, + { + .name = "nizynqcpld:status:yellow", + .addr = DOSX_LED, + .bit = 1 << 2, + .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, + /* write byte 1 first */ + .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, + .max_brightness = 0xffff, + }, + { + .name = "nizynqcpld:eth1:green", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 3, + .default_trigger = "e000b000:01:100Mb", + }, + { + .name = "nizynqcpld:eth1:yellow", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 2, + .default_trigger = "e000b000:01:Gb", + }, + { + .name = "nizynqcpld:eth0:green", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 1, + .default_trigger = "e000b000:00:100Mb", + }, + { + .name = "nizynqcpld:eth0:yellow", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 0, + .default_trigger = "e000b000:00:Gb", + }, +}; + static struct nizynqcpld_watchdog_desc dosxv4_watchdog_desc = { .watchdog_period_ns = 24000, }; @@ -1110,6 +1151,20 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .watchdog_addr = DOSX_WATCHDOGCONTROL, .wifi_sw_addr = MYRIO_WIFISWCTRL_ADDR, }, + /* Sol CPLD */ + { + .attrs = dosequis6_attrs, + .supported_version = 1, + .supported_product = 3, + .watchdog_desc = &dosxv5_watchdog_desc, + .led_descs = sol_leds, + .num_led_descs = ARRAY_SIZE(sol_leds), + .reboot_addr = DOSX_PROCESSORRESET, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = DOSX_DEBUGSWITCH, + .watchdog_addr = DOSX_WATCHDOGCONTROL, + }, }; static void wifi_sw_work_func(struct work_struct *work) From b0b165bcb916e583862cbba03b055d210872e720 Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Thu, 17 Oct 2013 14:55:57 -0500 Subject: [PATCH 32/97] nizynqcpld: Add Tecate CPLD support Add support for Tecate sbRIO to the CPLD by adding it to the list of CPLDs. It uses Sol-style LEDs. Signed-off-by: Jaeden Amero --- drivers/misc/nizynqcpld.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 824cb638ed527..70f3a1ca0f8cc 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1151,6 +1151,20 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .watchdog_addr = DOSX_WATCHDOGCONTROL, .wifi_sw_addr = MYRIO_WIFISWCTRL_ADDR, }, + /* Tecate */ + { + .attrs = dosequis6_attrs, + .supported_version = 1, + .supported_product = 2, + .watchdog_desc = &dosxv5_watchdog_desc, + .led_descs = sol_leds, + .num_led_descs = ARRAY_SIZE(sol_leds), + .reboot_addr = DOSX_PROCESSORRESET, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = DOSX_DEBUGSWITCH, + .watchdog_addr = DOSX_WATCHDOGCONTROL, + }, /* Sol CPLD */ { .attrs = dosequis6_attrs, From a86301e1a5f85a71b07e3cc21b67a2669f2f469f Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 24 Jan 2014 17:11:54 -0600 Subject: [PATCH 33/97] nizynqcpld: clean up tecate LEDs The CPLD driver is not used to control link speed LEDs for eth1 on Tecate. Signed-off-by: Jeff Westfahl Acked-by: Jaeden Amero --- drivers/misc/nizynqcpld.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 70f3a1ca0f8cc..c22264f7f8027 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1075,6 +1075,35 @@ static struct nizynqcpld_led_desc sol_leds[] = { }, }; +static struct nizynqcpld_led_desc tecate_leds[] = { + { + .name = "nizynqcpld:user1:green", + .addr = DOSX_LED, + .bit = 1 << 5, + }, + { + .name = "nizynqcpld:status:yellow", + .addr = DOSX_LED, + .bit = 1 << 2, + .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, + /* write byte 1 first */ + .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, + .max_brightness = 0xffff, + }, + { + .name = "nizynqcpld:eth0:green", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 1, + .default_trigger = "e000b000:00:100Mb", + }, + { + .name = "nizynqcpld:eth0:yellow", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 0, + .default_trigger = "e000b000:00:Gb", + }, +}; + static struct nizynqcpld_watchdog_desc dosxv4_watchdog_desc = { .watchdog_period_ns = 24000, }; @@ -1157,8 +1186,8 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_version = 1, .supported_product = 2, .watchdog_desc = &dosxv5_watchdog_desc, - .led_descs = sol_leds, - .num_led_descs = ARRAY_SIZE(sol_leds), + .led_descs = tecate_leds, + .num_led_descs = ARRAY_SIZE(tecate_leds), .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, From ffcb5d549ca1cbba2eff0c3979cfeb79bdfe5279 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Thu, 20 Feb 2014 16:30:46 -0600 Subject: [PATCH 34/97] nizynqcpld: Use correct register to detect switches The safemode, ipreset, and consoleout switches were being read from the DebugSwitchReg, which only represents the jumpers and not the reset button. Also, on targets like myRIO and Sol, the bitfields in that register changed from 0xE0 to 0x07. The bitfields in the ProcessorMode register have never changed and represent the actual state used by the bootloader. Use it here too. Signed-off-by: Joe Hershberger --- drivers/misc/nizynqcpld.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index c22264f7f8027..88405beda978a 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -30,7 +30,7 @@ #define NIZYNQCPLD_VERSION 0x00 #define NIZYNQCPLD_PRODUCT 0x1D -#define PROTO_PROCESSORSTATE 0x01 +#define PROTO_PROCESSORMODE 0x01 #define PROTO_SWITCHANDLED 0x04 #define PROTO_ETHERNETLED 0x05 #define PROTO_SCRATCHPADSR 0xFE @@ -432,9 +432,9 @@ static inline ssize_t nizynqcpld_switch_show(struct device *dev, __ATTR(_name, 0444, nizynqcpld_switch_show, NULL), \ } -static SWITCH_ATTR(console_out, 1 << 7); -static SWITCH_ATTR(ip_reset, 1 << 6); -static SWITCH_ATTR(safe_mode, 1 << 5); +static SWITCH_ATTR(console_out, 1 << 2); +static SWITCH_ATTR(ip_reset, 1 << 1); +static SWITCH_ATTR(safe_mode, 1 << 0); static const char * const bootmode_strings[] = { "runtime", "safemode", "recovery", @@ -1120,10 +1120,10 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_product = 0, .led_descs = proto_leds, .num_led_descs = ARRAY_SIZE(proto_leds), - .reboot_addr = PROTO_PROCESSORSTATE, + .reboot_addr = PROTO_PROCESSORMODE, .scratch_hr_addr = PROTO_SCRATCHPADHR, .scratch_sr_addr = PROTO_SCRATCHPADSR, - .switch_addr = PROTO_SWITCHANDLED, + .switch_addr = PROTO_PROCESSORMODE, }, /* DosEquis and myRIO development CPLD */ { @@ -1136,7 +1136,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, - .switch_addr = DOSX_DEBUGSWITCH, + .switch_addr = PROTO_PROCESSORMODE, }, /* DosEquis and myRIO development CPLD */ { @@ -1149,7 +1149,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, - .switch_addr = DOSX_DEBUGSWITCH, + .switch_addr = PROTO_PROCESSORMODE, }, /* DosEquis CPLD */ { @@ -1162,7 +1162,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, - .switch_addr = DOSX_DEBUGSWITCH, + .switch_addr = PROTO_PROCESSORMODE, .watchdog_addr = DOSX_WATCHDOGCONTROL, }, /* myRIO CPLD */ @@ -1176,7 +1176,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, - .switch_addr = DOSX_DEBUGSWITCH, + .switch_addr = PROTO_PROCESSORMODE, .watchdog_addr = DOSX_WATCHDOGCONTROL, .wifi_sw_addr = MYRIO_WIFISWCTRL_ADDR, }, @@ -1191,7 +1191,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, - .switch_addr = DOSX_DEBUGSWITCH, + .switch_addr = PROTO_PROCESSORMODE, .watchdog_addr = DOSX_WATCHDOGCONTROL, }, /* Sol CPLD */ @@ -1205,7 +1205,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, - .switch_addr = DOSX_DEBUGSWITCH, + .switch_addr = PROTO_PROCESSORMODE, .watchdog_addr = DOSX_WATCHDOGCONTROL, }, }; From 2f7d35a0f16b8fd5049e34a09f421cbb7d263b66 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Thu, 20 Feb 2014 16:35:05 -0600 Subject: [PATCH 35/97] nizynqcpld: Add support for reading soft-reset state Expose this information to the scripts in Linux. Signed-off-by: Joe Hershberger --- drivers/misc/nizynqcpld.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 88405beda978a..416500d6e1110 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -432,6 +432,7 @@ static inline ssize_t nizynqcpld_switch_show(struct device *dev, __ATTR(_name, 0444, nizynqcpld_switch_show, NULL), \ } +static SWITCH_ATTR(soft_reset, 1 << 5); static SWITCH_ATTR(console_out, 1 << 2); static SWITCH_ATTR(ip_reset, 1 << 1); static SWITCH_ATTR(safe_mode, 1 << 0); @@ -506,6 +507,7 @@ static const struct attribute *nizynqcpld_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, &dev_attr_scratch_hardreset.attr, + &dev_attr_soft_reset.dev_attr.attr, &dev_attr_console_out.dev_attr.attr, &dev_attr_ip_reset.dev_attr.attr, &dev_attr_safe_mode.dev_attr.attr, @@ -561,6 +563,7 @@ static const struct attribute *dosequis6_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, &dev_attr_scratch_hardreset.attr, + &dev_attr_soft_reset.dev_attr.attr, &dev_attr_console_out.dev_attr.attr, &dev_attr_ip_reset.dev_attr.attr, &dev_attr_safe_mode.dev_attr.attr, From 69fd01609a462050ffbc11ed70abd981d52c58db Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Thu, 20 Feb 2014 17:18:33 -0600 Subject: [PATCH 36/97] nizynqcpld: Expose power status to user-mode Some customers care about the status of the backup power source on the chassis that support it (so far only Dos Equis). Signed-off-by: Joe Hershberger --- drivers/misc/nizynqcpld.c | 72 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 416500d6e1110..6e1569dddfc63 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -42,6 +42,7 @@ #define DOSX_LED 0x07 #define DOSX_ETHERNETLED 0x08 #define DOSX_DEBUGSWITCH 0x09 +#define DOSX_POWERSTATUS 0x0C #define DOSX_WATCHDOGCONTROL 0x13 #define DOSX_WATCHDOGCOUNTER2 0x14 #define DOSX_WATCHDOGCOUNTER1 0x15 @@ -503,6 +504,57 @@ static ssize_t nizynqcpld_bootmode_store(struct device *dev, static DEVICE_ATTR(bootmode, S_IRUSR|S_IWUSR, nizynqcpld_bootmode_show, nizynqcpld_bootmode_store); + +struct powerstatus_attribute { + struct device_attribute dev_attr; + u8 bit; +}; + +static inline ssize_t nizynqcpld_powerstatus_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + struct powerstatus_attribute *pa = + container_of(attr, struct powerstatus_attribute, dev_attr); + int err; + u8 data; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, DOSX_POWERSTATUS, &data); + nizynqcpld_unlock(cpld); + + if (err) { + dev_err(dev, "Error reading power status.\n"); + return err; + } + + return sprintf(buf, "%u\n", !!(data & pa->bit)); +} + +#define POWERSTATUS_ATTR(_name,_bit) \ + struct powerstatus_attribute dev_attr_##_name = { \ + .bit = _bit, \ + .dev_attr = \ + __ATTR(_name, 0444, nizynqcpld_powerstatus_show, NULL), \ + } + +static POWERSTATUS_ATTR(pwr_aux_valid, 1 << 4); +static POWERSTATUS_ATTR(pwr_primary_in_use, 1 << 0); + +static const struct attribute *nizynqcpld_pwr_attrs[] = { + &dev_attr_bootmode.attr, + &dev_attr_scratch_softreset.attr, + &dev_attr_scratch_hardreset.attr, + &dev_attr_soft_reset.dev_attr.attr, + &dev_attr_console_out.dev_attr.attr, + &dev_attr_ip_reset.dev_attr.attr, + &dev_attr_safe_mode.dev_attr.attr, + &dev_attr_pwr_aux_valid.dev_attr.attr, + &dev_attr_pwr_primary_in_use.dev_attr.attr, + NULL +}; + static const struct attribute *nizynqcpld_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, @@ -559,6 +611,20 @@ static ssize_t dosequiscpld_wdmode_store(struct device *dev, static DEVICE_ATTR(watchdog_mode, S_IRUSR|S_IWUSR, dosequiscpld_wdmode_show, dosequiscpld_wdmode_store); +static const struct attribute *dosequis6_pwr_attrs[] = { + &dev_attr_bootmode.attr, + &dev_attr_scratch_softreset.attr, + &dev_attr_scratch_hardreset.attr, + &dev_attr_soft_reset.dev_attr.attr, + &dev_attr_console_out.dev_attr.attr, + &dev_attr_ip_reset.dev_attr.attr, + &dev_attr_safe_mode.dev_attr.attr, + &dev_attr_watchdog_mode.attr, + &dev_attr_pwr_aux_valid.dev_attr.attr, + &dev_attr_pwr_primary_in_use.dev_attr.attr, + NULL +}; + static const struct attribute *dosequis6_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, @@ -1130,7 +1196,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { }, /* DosEquis and myRIO development CPLD */ { - .attrs = nizynqcpld_attrs, + .attrs = nizynqcpld_pwr_attrs, .supported_version = 4, .supported_product = 0, .watchdog_desc = &dosxv4_watchdog_desc, @@ -1143,7 +1209,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { }, /* DosEquis and myRIO development CPLD */ { - .attrs = nizynqcpld_attrs, + .attrs = nizynqcpld_pwr_attrs, .supported_version = 5, .supported_product = 0, .watchdog_desc = &dosxv5_watchdog_desc, @@ -1156,7 +1222,7 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { }, /* DosEquis CPLD */ { - .attrs = dosequis6_attrs, + .attrs = dosequis6_pwr_attrs, .supported_version = 6, .supported_product = 0, .watchdog_desc = &dosxv5_watchdog_desc, From 43e7fbb567cd68b5e4c44546507517778f7b881f Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Thu, 20 Feb 2014 18:02:43 -0600 Subject: [PATCH 37/97] nizynqcpld: Replace recovery boot mode with install We do not actually support recovery-mode, so replace that bit with install-mode The boot loader only checks that the first 2 bits == 0x1 for safe-mode. Otherwise it boots to runmode. Signed-off-by: Joe Hershberger --- drivers/misc/nizynqcpld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 6e1569dddfc63..ed33ecfb8f19a 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -439,7 +439,7 @@ static SWITCH_ATTR(ip_reset, 1 << 1); static SWITCH_ATTR(safe_mode, 1 << 0); static const char * const bootmode_strings[] = { - "runtime", "safemode", "recovery", + "runtime", "safemode", "install", }; static ssize_t nizynqcpld_bootmode_show(struct device *dev, From e5e8d724b679bafec4e2b2abe21a8062aec2f2fa Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Fri, 21 Feb 2014 00:57:36 -0600 Subject: [PATCH 38/97] nizynqcpld: Add attribute for reset source Safe-mode will need to know the reset source Signed-off-by: Joe Hershberger --- drivers/misc/nizynqcpld.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index ed33ecfb8f19a..9797814bcb2c7 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -37,6 +37,7 @@ #define PROTO_SCRATCHPADHR 0xFF #define DOSX_PROCESSORRESET 0x02 +#define DOSX_PROCRESETSOURCE 0x04 #define DOSX_STATUSLEDSHIFTBYTE1 0x05 #define DOSX_STATUSLEDSHIFTBYTE0 0x06 #define DOSX_LED 0x07 @@ -611,6 +612,38 @@ static ssize_t dosequiscpld_wdmode_store(struct device *dev, static DEVICE_ATTR(watchdog_mode, S_IRUSR|S_IWUSR, dosequiscpld_wdmode_show, dosequiscpld_wdmode_store); + +static const char * const resetsource_strings[] = { + "button", "processor", "fpga", "watchdog", "software", "softoff", +}; + +static ssize_t nizynqcpld_resetsource_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct nizynqcpld *cpld = dev_get_drvdata(dev); + int err; + u8 tmp; + int i; + + nizynqcpld_lock(cpld); + err = nizynqcpld_read(cpld, DOSX_PROCRESETSOURCE, &tmp); + nizynqcpld_unlock(cpld); + + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(resetsource_strings); i++) { + if ((1 << i) & tmp) + return sprintf(buf, "%s\n", resetsource_strings[i]); + } + + return sprintf(buf, "poweron\n"); +} + +static DEVICE_ATTR(reset_source, S_IRUSR, nizynqcpld_resetsource_show, NULL); + + static const struct attribute *dosequis6_pwr_attrs[] = { &dev_attr_bootmode.attr, &dev_attr_scratch_softreset.attr, @@ -620,6 +653,7 @@ static const struct attribute *dosequis6_pwr_attrs[] = { &dev_attr_ip_reset.dev_attr.attr, &dev_attr_safe_mode.dev_attr.attr, &dev_attr_watchdog_mode.attr, + &dev_attr_reset_source.attr, &dev_attr_pwr_aux_valid.dev_attr.attr, &dev_attr_pwr_primary_in_use.dev_attr.attr, NULL @@ -634,6 +668,7 @@ static const struct attribute *dosequis6_attrs[] = { &dev_attr_ip_reset.dev_attr.attr, &dev_attr_safe_mode.dev_attr.attr, &dev_attr_watchdog_mode.attr, + &dev_attr_reset_source.attr, NULL }; From 35292a7afc38a02150e87f244096e9c51a6e4781 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Mon, 24 Feb 2014 08:45:49 -0600 Subject: [PATCH 39/97] nizynqcpld: Change LED prefix to "nilrt" Signed-off-by: Jeff Westfahl Natinst-CAR-ID: 452296 --- drivers/misc/nizynqcpld.c | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 9797814bcb2c7..7463addd80fd5 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1050,28 +1050,28 @@ static const struct file_operations nizynqcpld_watchdog_misc_fops = { static struct nizynqcpld_led_desc proto_leds[] = { { - .name = "nizynqcpld:user1:green", + .name = "nilrt:user1:green", .addr = PROTO_SWITCHANDLED, .bit = 1 << 4, }, { - .name = "nizynqcpld:user1:yellow", + .name = "nilrt:user1:yellow", .addr = PROTO_SWITCHANDLED, .bit = 1 << 3, }, { - .name = "nizynqcpld:status:yellow", + .name = "nilrt:status:yellow", .addr = PROTO_SWITCHANDLED, .bit = 1 << 2, }, { - .name = "nizynqcpld:eth1:green", + .name = "nilrt:eth1:green", .addr = PROTO_ETHERNETLED, .bit = 1 << 1, .default_trigger = "e000b000:00:100Mb", }, { - .name = "nizynqcpld:eth1:yellow", + .name = "nilrt:eth1:yellow", .addr = PROTO_ETHERNETLED, .bit = 1 << 0, .default_trigger = "e000b000:00:Gb", @@ -1080,22 +1080,22 @@ static struct nizynqcpld_led_desc proto_leds[] = { static struct nizynqcpld_led_desc dosx_leds[] = { { - .name = "nizynqcpld:user1:green", + .name = "nilrt:user1:green", .addr = DOSX_LED, .bit = 1 << 5, }, { - .name = "nizynqcpld:user1:yellow", + .name = "nilrt:user1:yellow", .addr = DOSX_LED, .bit = 1 << 4, }, { - .name = "nizynqcpld:status:red", + .name = "nilrt:status:red", .addr = DOSX_LED, .bit = 1 << 3, }, { - .name = "nizynqcpld:status:yellow", + .name = "nilrt:status:yellow", .addr = DOSX_LED, .bit = 1 << 2, .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, @@ -1103,35 +1103,35 @@ static struct nizynqcpld_led_desc dosx_leds[] = { .max_brightness = 0xffff, }, { - .name = "nizynqcpld:wifi:green", + .name = "nilrt:wifi:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 5, }, { - .name = "nizynqcpld:wifi:yellow", + .name = "nilrt:wifi:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 4, }, { - .name = "nizynqcpld:eth1:green", + .name = "nilrt:eth1:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 3, .default_trigger = "e000b000:01:100Mb", }, { - .name = "nizynqcpld:eth1:yellow", + .name = "nilrt:eth1:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 2, .default_trigger = "e000b000:01:Gb", }, { - .name = "nizynqcpld:eth0:green", + .name = "nilrt:eth0:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, .default_trigger = "e000b000:00:100Mb", }, { - .name = "nizynqcpld:eth0:yellow", + .name = "nilrt:eth0:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, .default_trigger = "e000b000:00:Gb", @@ -1140,12 +1140,12 @@ static struct nizynqcpld_led_desc dosx_leds[] = { static struct nizynqcpld_led_desc sol_leds[] = { { - .name = "nizynqcpld:user1:green", + .name = "nilrt:user1:green", .addr = DOSX_LED, .bit = 1 << 5, }, { - .name = "nizynqcpld:status:yellow", + .name = "nilrt:status:yellow", .addr = DOSX_LED, .bit = 1 << 2, .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, @@ -1154,25 +1154,25 @@ static struct nizynqcpld_led_desc sol_leds[] = { .max_brightness = 0xffff, }, { - .name = "nizynqcpld:eth1:green", + .name = "nilrt:eth1:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 3, .default_trigger = "e000b000:01:100Mb", }, { - .name = "nizynqcpld:eth1:yellow", + .name = "nilrt:eth1:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 2, .default_trigger = "e000b000:01:Gb", }, { - .name = "nizynqcpld:eth0:green", + .name = "nilrt:eth0:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, .default_trigger = "e000b000:00:100Mb", }, { - .name = "nizynqcpld:eth0:yellow", + .name = "nilrt:eth0:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, .default_trigger = "e000b000:00:Gb", @@ -1181,12 +1181,12 @@ static struct nizynqcpld_led_desc sol_leds[] = { static struct nizynqcpld_led_desc tecate_leds[] = { { - .name = "nizynqcpld:user1:green", + .name = "nilrt:user1:green", .addr = DOSX_LED, .bit = 1 << 5, }, { - .name = "nizynqcpld:status:yellow", + .name = "nilrt:status:yellow", .addr = DOSX_LED, .bit = 1 << 2, .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, @@ -1195,13 +1195,13 @@ static struct nizynqcpld_led_desc tecate_leds[] = { .max_brightness = 0xffff, }, { - .name = "nizynqcpld:eth0:green", + .name = "nilrt:eth0:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, .default_trigger = "e000b000:00:100Mb", }, { - .name = "nizynqcpld:eth0:yellow", + .name = "nilrt:eth0:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, .default_trigger = "e000b000:00:Gb", From 0ee8473004fe9b396c64dc19c964cf4be5021452 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Tue, 25 Feb 2014 15:45:32 -0600 Subject: [PATCH 40/97] nizynqcpld: myRIO WiFi LEDs are poorly named The myRIO WiFi LEDs are poorly named. The names "green" and "yellow" don't correspond to the actual colors of the LEDs (blue and red), but color names don't really relate to how the LEDs are used. Functional names "primary" and "secondary" are most appropriate; rename them as such. Signed-off-by: Jeff Westfahl Natinst-CAR-ID: 454237 --- drivers/misc/nizynqcpld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 7463addd80fd5..a74c746b6639d 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1103,12 +1103,12 @@ static struct nizynqcpld_led_desc dosx_leds[] = { .max_brightness = 0xffff, }, { - .name = "nilrt:wifi:green", + .name = "nilrt:wifi:primary", .addr = DOSX_ETHERNETLED, .bit = 1 << 5, }, { - .name = "nilrt:wifi:yellow", + .name = "nilrt:wifi:secondary", .addr = DOSX_ETHERNETLED, .bit = 1 << 4, }, From 26751c6b9cb2cf042cc886f3b33c087f361bcf45 Mon Sep 17 00:00:00 2001 From: Chen Yee Chew Date: Tue, 25 Nov 2014 15:50:33 +0800 Subject: [PATCH 41/97] sbZynq: Add sbZynq to nizynq CPLD driver Signed-off-by: Chen Yee Chew Acked-by: Keng Soon Cheah Acked-by: Jaeden Amero Natinst-ReviewBoard-ID: 83857 --- drivers/misc/nizynqcpld.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index a74c746b6639d..dcfdff8331445 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1312,6 +1312,20 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .switch_addr = PROTO_PROCESSORMODE, .watchdog_addr = DOSX_WATCHDOGCONTROL, }, + /* sbZynq CPLD */ + { + .attrs = dosequis6_attrs, + .supported_version = 1, + .supported_product = 4, + .watchdog_desc = &dosxv5_watchdog_desc, + .led_descs = sol_leds, + .num_led_descs = ARRAY_SIZE(sol_leds), + .reboot_addr = DOSX_PROCESSORRESET, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = PROTO_PROCESSORMODE, + .watchdog_addr = DOSX_WATCHDOGCONTROL, + }, }; static void wifi_sw_work_func(struct work_struct *work) From 4e3f6202685a6cb6686809d4da560c313e9aebae Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Wed, 3 Dec 2014 15:27:55 -0600 Subject: [PATCH 42/97] nizynqcpld: Update LED triggers to match macb mdio name Change the default trigger names to match the name the cadence macb driver gives its mdio bus. Signed-off-by: Nathan Sullivan Acked-by: Jaeden Amero Acked-by: Ben Shelton Acked-by: Gratian Crisan Natinst-ReviewBoard-ID: 84557 --- drivers/misc/nizynqcpld.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index dcfdff8331445..a759bae049862 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1068,13 +1068,13 @@ static struct nizynqcpld_led_desc proto_leds[] = { .name = "nilrt:eth1:green", .addr = PROTO_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000:00:100Mb", + .default_trigger = "e000b000.etherne:00:100Mb", }, { .name = "nilrt:eth1:yellow", .addr = PROTO_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000:00:Gb", + .default_trigger = "e000b000.etherne:00:Gb", }, }; @@ -1116,25 +1116,25 @@ static struct nizynqcpld_led_desc dosx_leds[] = { .name = "nilrt:eth1:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 3, - .default_trigger = "e000b000:01:100Mb", + .default_trigger = "e000b000.etherne:01:100Mb", }, { .name = "nilrt:eth1:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 2, - .default_trigger = "e000b000:01:Gb", + .default_trigger = "e000b000.etherne:01:Gb", }, { .name = "nilrt:eth0:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000:00:100Mb", + .default_trigger = "e000b000.etherne:00:100Mb", }, { .name = "nilrt:eth0:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000:00:Gb", + .default_trigger = "e000b000.etherne:00:Gb", }, }; @@ -1157,25 +1157,25 @@ static struct nizynqcpld_led_desc sol_leds[] = { .name = "nilrt:eth1:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 3, - .default_trigger = "e000b000:01:100Mb", + .default_trigger = "e000b000.etherne:01:100Mb", }, { .name = "nilrt:eth1:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 2, - .default_trigger = "e000b000:01:Gb", + .default_trigger = "e000b000.etherne:01:Gb", }, { .name = "nilrt:eth0:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000:00:100Mb", + .default_trigger = "e000b000.etherne:00:100Mb", }, { .name = "nilrt:eth0:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000:00:Gb", + .default_trigger = "e000b000.etherne:00:Gb", }, }; @@ -1198,13 +1198,13 @@ static struct nizynqcpld_led_desc tecate_leds[] = { .name = "nilrt:eth0:green", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000:00:100Mb", + .default_trigger = "e000b000.etherne:00:100Mb", }, { .name = "nilrt:eth0:yellow", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000:00:Gb", + .default_trigger = "e000b000.etherne:00:Gb", }, }; From 15f06132b3947dbca573f3bfc7ae7b63a24c47da Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Thu, 26 Feb 2015 17:55:47 -0600 Subject: [PATCH 43/97] nizynqcpld: Strobe the watchdog control register The CPLD watchdog control register is a strobe register, full of a mix of read-only and write-only bits. Because it is a strobe register, this driver was in error doing read, modify, write when updating the watchdog control register. Some bad things happened because of the driver's misuse of this register. A specific example of a failure due to read, modify, write of the watchdog control register follows. Bit 7 of the watchdog control register is "Watchdog Mode". A value of 1 here means "Boot Mode". A value of 0 means "User Mode". Bit 4 ("Watchdog Pet") is a write only bit that pets the watchdog when set to 1. When attempting to pet the watchdog while the watchdog is in boot mode, the driver would do a read, see that bit 7 is set (indicating that the watchdog is in boot mode), or this value with bit 4 (0x10) to say "I want to pet the boot mode watch dog," and end up writing both bit 7 and bit 4 as 1. Writing a 1 to bit 7 means "I want the watchdog to enter user mode," so no petting occurs, despite the driver's intent to pet the watch dog and not to enter user mode. Signed-off-by: Jaeden Amero Reviewed-by: Ben Shelton Reviewed-by: Gratian Crisan Natinst-ReviewBoard-ID: 90484 Natinst-CAR-ID: 521301 Natinst-ReviewBoard-ID: 95393 --- drivers/misc/nizynqcpld.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index a759bae049862..dfac18e0211e9 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -63,6 +63,9 @@ #define DOSX_WATCHDOGCONTROL_RESET 0x02 #define DOSX_WATCHDOGCONTROL_ALARM 0x01 +#define DOSX_WATCHDOGCONTROL_RW_BITS \ + (DOSX_WATCHDOGCONTROL_PROC_INTERRUPT | DOSX_WATCHDOGCONTROL_PROC_RESET) + #define DOSX_WATCHDOG_MAX_COUNTER 0x00FFFFFF #define DOSX_WATCHDOG_COUNTER_BYTES 3 @@ -715,28 +718,18 @@ static int nizynqcpld_watchdog_check_action(u32 action) static int nizynqcpld_watchdog_add_action(struct nizynqcpld *cpld, u32 action) { int err; - u8 action_mask; - u8 control; + u8 action_bit; if (NIWATCHDOG_ACTION_INTERRUPT == action) - action_mask = DOSX_WATCHDOGCONTROL_PROC_INTERRUPT; + action_bit = DOSX_WATCHDOGCONTROL_PROC_INTERRUPT; else if (NIWATCHDOG_ACTION_RESET == action) - action_mask = DOSX_WATCHDOGCONTROL_PROC_RESET; + action_bit = DOSX_WATCHDOGCONTROL_PROC_RESET; else return -ENOTSUPP; nizynqcpld_lock(cpld); - err = nizynqcpld_read(cpld, DOSX_WATCHDOGCONTROL, &control); - - if (err) { - dev_err(cpld->dev, - "Error %d reading watchdog control.\n", err); - goto out_unlock; - } - control |= action_mask; - - err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control); + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, action_bit); if (err) { dev_err(cpld->dev, @@ -764,6 +757,9 @@ static int nizynqcpld_watchdog_start(struct nizynqcpld *cpld) goto out_unlock; } + /* Mask off all the read-only and write-only bits. */ + control &= DOSX_WATCHDOGCONTROL_RW_BITS; + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control | DOSX_WATCHDOGCONTROL_RESET); if (err) { @@ -802,6 +798,9 @@ static int nizynqcpld_watchdog_pet(struct nizynqcpld *cpld, u32 *state) goto out_unlock; } + /* Mask off all the read-only and write-only bits. */ + control &= DOSX_WATCHDOGCONTROL_RW_BITS; + control |= DOSX_WATCHDOGCONTROL_PET; err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control); @@ -855,6 +854,9 @@ static int nizynqcpld_watchdog_counter_get(struct nizynqcpld *cpld, goto out_unlock; } + /* Mask off all the read-only and write-only bits. */ + control &= DOSX_WATCHDOGCONTROL_RW_BITS; + err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control | DOSX_WATCHDOGCONTROL_CAPTURECOUNTER); if (err) { @@ -906,6 +908,9 @@ static irqreturn_t nizynqcpld_watchdog_irq(int irq, void *data) cpld->watchdog.expired = true; + /* Mask off all the read-only and write-only bits. */ + control &= DOSX_WATCHDOGCONTROL_RW_BITS; + /* Acknowledge the interrupt. */ control |= DOSX_WATCHDOGCONTROL_RESET; err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control); From f96bc63eb3c230ec1b91ab67f64f127e1b0b55f6 Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Fri, 6 Mar 2015 17:19:15 -0600 Subject: [PATCH 44/97] nizynqcpld: Remove THIS_MODULE We don't need it. Signed-off-by: Jaeden Amero Reviewed-by: Ben Shelton Reviewed-by: Josh Cartwright Natinst-ReviewBoard-ID: 91284 --- drivers/misc/nizynqcpld.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index dfac18e0211e9..a66fb618ff2f2 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1634,7 +1634,6 @@ MODULE_DEVICE_TABLE(i2c, nizynqcpld_ids); static struct i2c_driver nizynqcpld_driver = { .driver = { .name = "nizynqcpld", - .owner = THIS_MODULE, }, .probe = nizynqcpld_probe, .remove = nizynqcpld_remove, From 3ef61d59ee7243ce0403339136a74f11f058f5e3 Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Fri, 6 Mar 2015 17:19:29 -0600 Subject: [PATCH 45/97] nizynqcpld: Use module_i2c_driver macro Use the module_i2c_driver macro to register with the i2c driver instead of explicitly rewriting the code that the macro creates for us. This is cleaner, and clean is nice. Signed-off-by: Jaeden Amero Reviewed-by: Ben Shelton Reviewed-by: Josh Cartwright Natinst-ReviewBoard-ID: 91284 --- drivers/misc/nizynqcpld.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index a66fb618ff2f2..becc0eef2add0 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1640,17 +1640,7 @@ static struct i2c_driver nizynqcpld_driver = { .id_table = nizynqcpld_ids, }; -static int __init nizynqcpld_init(void) -{ - return i2c_add_driver(&nizynqcpld_driver); -} -module_init(nizynqcpld_init); - -static void __exit nizynqcpld_exit(void) -{ - i2c_del_driver(&nizynqcpld_driver); -} -module_exit(nizynqcpld_exit); +module_i2c_driver(nizynqcpld_driver); MODULE_DESCRIPTION("Driver for CPLD on NI's Zynq RIO products"); MODULE_AUTHOR("National Instruments"); From 731df7523bcb4aabfa4f63233882144a903e9ed3 Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Fri, 6 Mar 2015 11:24:25 -0600 Subject: [PATCH 46/97] nizynqcpld: Read LED information from device tree Instead of maintaining a table of board-specific LED information for each board, use device tree to store LED properties 'max-brightness', 'default-trigger', and 'label'. This allows boards to vary these properties without also requiring driver modifications. Signed-off-by: Jaeden Amero Reviewed-by: Ben Shelton Reviewed-by: Josh Cartwright Natinst-ReviewBoard-ID: 91284 Natinst-ReviewBoard-ID: 93389 --- drivers/misc/nizynqcpld.c | 160 +++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 55 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index becc0eef2add0..b3a4a82151fc9 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -77,13 +77,11 @@ #define MYRIO_WIFISWCTRL_RELIRQ 0x40 struct nizynqcpld_led_desc { - const char *name; - const char *default_trigger; + const char *of_node_name; u8 addr; u8 bit; u8 pattern_lo_addr; u8 pattern_hi_addr; - int max_brightness; }; struct nizynqcpld; @@ -136,6 +134,7 @@ struct nizynqcpld_desc { struct nizynqcpld { struct device *dev; + int irq; struct nizynqcpld_desc *desc; struct nizynqcpld_led *leds; struct nizynqcpld_watchdog watchdog; @@ -244,6 +243,8 @@ static int nizynqcpld_led_register(struct nizynqcpld *cpld, { int err; u8 tmp; + struct device_node *leds_node; + struct device_node *node; nizynqcpld_lock(cpld); err = nizynqcpld_read(cpld, desc->addr, &tmp); @@ -257,10 +258,33 @@ static int nizynqcpld_led_register(struct nizynqcpld *cpld, led->on = !!(tmp & desc->bit); INIT_WORK(&led->deferred_work, nizynqcpld_set_brightness_work); - led->cdev.name = desc->name; - led->cdev.default_trigger = desc->default_trigger; - led->cdev.max_brightness = desc->max_brightness ? desc->max_brightness - : 1; + /* Find the LEDs node. */ + leds_node = of_find_node_by_name(cpld->client->dev.of_node, + "leds"); + if (!leds_node) + return -ENOENT; + + /* For the current led, get the device node under 'leds'. */ + node = of_get_child_by_name(leds_node, desc->of_node_name); + if (!node) { + /* Don't register the LED if the LED is not specified in device + * tree. */ + err = -ENOENT; + goto err_out; + } + + /* Read the label from device tree. */ + led->cdev.name = of_get_property(node, "label", NULL) ? : node->name; + + /* Read the default trigger from device tree. */ + led->cdev.default_trigger = of_get_property(node, + "linux,default-trigger", NULL); + + /* Read the max brightness from device tree. */ + led->cdev.max_brightness = 1; /* Default to max of 1 */ + of_property_read_u32(node, "max-brightness", + &led->cdev.max_brightness); + led->cdev.brightness_set = nizynqcpld_led_set_brightness; led->cdev.brightness_get = nizynqcpld_led_get_brightness; @@ -271,6 +295,7 @@ static int nizynqcpld_led_register(struct nizynqcpld *cpld, } err_led: + of_node_put(node); err_out: return err; } @@ -931,15 +956,31 @@ static int nizynqcpld_watchdog_misc_open(struct inode *inode, struct miscdevice *misc_dev = file->private_data; struct nizynqcpld *cpld = container_of(misc_dev, struct nizynqcpld, watchdog.misc_dev); + struct device_node *watchdogs_node; + struct device_node *boot_watchdog_node; + file->private_data = cpld; + /* Find the watchdogs node. */ + watchdogs_node = of_find_node_by_name(cpld->client->dev.of_node, + "watchdogs"); + if (!watchdogs_node) + return -ENOENT; + + /* Get the boot watchdog node. */ + boot_watchdog_node = of_find_node_by_name(watchdogs_node, + "boot-watchdog"); + if (!boot_watchdog_node) + return -ENOENT; + if (!atomic_dec_and_test(&cpld->watchdog.available)) { atomic_inc(&cpld->watchdog.available); return -EBUSY; } - return request_threaded_irq(cpld->client->irq, - NULL, nizynqcpld_watchdog_irq, + cpld->irq = irq_of_parse_and_map(boot_watchdog_node, 0); + + return request_threaded_irq(cpld->irq, NULL, nizynqcpld_watchdog_irq, 0, NIWATCHDOG_NAME, cpld); } @@ -947,7 +988,7 @@ static int nizynqcpld_watchdog_misc_release(struct inode *inode, struct file *file) { struct nizynqcpld *cpld = file->private_data; - free_irq(cpld->client->irq, cpld); + free_irq(cpld->irq, cpld); atomic_inc(&cpld->watchdog.available); return 0; } @@ -1055,161 +1096,146 @@ static const struct file_operations nizynqcpld_watchdog_misc_fops = { static struct nizynqcpld_led_desc proto_leds[] = { { - .name = "nilrt:user1:green", + .of_node_name = "user1-0", .addr = PROTO_SWITCHANDLED, .bit = 1 << 4, }, { - .name = "nilrt:user1:yellow", + .of_node_name = "user1-1", .addr = PROTO_SWITCHANDLED, .bit = 1 << 3, }, { - .name = "nilrt:status:yellow", + .of_node_name = "status-0", .addr = PROTO_SWITCHANDLED, .bit = 1 << 2, }, { - .name = "nilrt:eth1:green", + .of_node_name = "eth1-0", .addr = PROTO_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000.etherne:00:100Mb", }, { - .name = "nilrt:eth1:yellow", + .of_node_name = "eth1-1", .addr = PROTO_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000.etherne:00:Gb", }, }; static struct nizynqcpld_led_desc dosx_leds[] = { { - .name = "nilrt:user1:green", + .of_node_name = "user1-0", .addr = DOSX_LED, .bit = 1 << 5, }, { - .name = "nilrt:user1:yellow", + .of_node_name = "user1-1", .addr = DOSX_LED, .bit = 1 << 4, }, { - .name = "nilrt:status:red", + .of_node_name = "status-0", .addr = DOSX_LED, .bit = 1 << 3, }, { - .name = "nilrt:status:yellow", + .of_node_name = "status-1", .addr = DOSX_LED, .bit = 1 << 2, .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, - .max_brightness = 0xffff, }, { - .name = "nilrt:wifi:primary", + .of_node_name = "wifi-0", .addr = DOSX_ETHERNETLED, .bit = 1 << 5, }, { - .name = "nilrt:wifi:secondary", + .of_node_name = "wifi-1", .addr = DOSX_ETHERNETLED, .bit = 1 << 4, }, { - .name = "nilrt:eth1:green", + .of_node_name = "eth1-0", .addr = DOSX_ETHERNETLED, .bit = 1 << 3, - .default_trigger = "e000b000.etherne:01:100Mb", }, { - .name = "nilrt:eth1:yellow", + .of_node_name = "eth1-1", .addr = DOSX_ETHERNETLED, .bit = 1 << 2, - .default_trigger = "e000b000.etherne:01:Gb", }, { - .name = "nilrt:eth0:green", + .of_node_name = "eth0-0", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000.etherne:00:100Mb", }, { - .name = "nilrt:eth0:yellow", + .of_node_name = "eth0-1", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000.etherne:00:Gb", }, }; static struct nizynqcpld_led_desc sol_leds[] = { { - .name = "nilrt:user1:green", + .of_node_name = "user1-0", .addr = DOSX_LED, .bit = 1 << 5, }, { - .name = "nilrt:status:yellow", + .of_node_name = "status-0", .addr = DOSX_LED, .bit = 1 << 2, .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, /* write byte 1 first */ .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, - .max_brightness = 0xffff, }, { - .name = "nilrt:eth1:green", + .of_node_name = "eth1-0", .addr = DOSX_ETHERNETLED, .bit = 1 << 3, - .default_trigger = "e000b000.etherne:01:100Mb", }, { - .name = "nilrt:eth1:yellow", + .of_node_name = "eth1-1", .addr = DOSX_ETHERNETLED, .bit = 1 << 2, - .default_trigger = "e000b000.etherne:01:Gb", }, { - .name = "nilrt:eth0:green", + .of_node_name = "eth0-0", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000.etherne:00:100Mb", }, { - .name = "nilrt:eth0:yellow", + .of_node_name = "eth0-1", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000.etherne:00:Gb", }, }; static struct nizynqcpld_led_desc tecate_leds[] = { { - .name = "nilrt:user1:green", + .of_node_name = "user1-0", .addr = DOSX_LED, .bit = 1 << 5, }, { - .name = "nilrt:status:yellow", + .of_node_name = "status-0", .addr = DOSX_LED, .bit = 1 << 2, .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, /* write byte 1 first */ .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, - .max_brightness = 0xffff, }, { - .name = "nilrt:eth0:green", + .of_node_name = "eth0-0", .addr = DOSX_ETHERNETLED, .bit = 1 << 1, - .default_trigger = "e000b000.etherne:00:100Mb", }, { - .name = "nilrt:eth0:yellow", + .of_node_name = "eth0-1", .addr = DOSX_ETHERNETLED, .bit = 1 << 0, - .default_trigger = "e000b000.etherne:00:Gb", }, }; @@ -1409,12 +1435,26 @@ static int myrio_wifi_sw_init(struct nizynqcpld *cpld) u8 data; int err = 0; struct input_dev *input; + struct device_node *switches_node; + struct device_node *wifi_switch_node; if (!cpld->desc->wifi_sw_addr) goto wifi_sw_init_exit; INIT_WORK(&cpld->wifi_sw.deferred_work, wifi_sw_work_func); - cpld->wifi_sw.irq = irq_of_parse_and_map(cpld->client->dev.of_node, 1); + + /* Find the switches node. */ + switches_node = of_find_node_by_name(cpld->client->dev.of_node, + "switches"); + if (!switches_node) + goto wifi_sw_init_exit; + + /* Find the WiFi switch node. */ + wifi_switch_node = of_find_node_by_name(switches_node, "wifi-switch"); + if (!wifi_switch_node) + goto wifi_sw_init_exit; + + cpld->wifi_sw.irq = irq_of_parse_and_map(wifi_switch_node, 0); /* ensure that the interrupt was mapped */ if (!cpld->wifi_sw.irq) @@ -1544,8 +1584,12 @@ static int nizynqcpld_probe(struct i2c_client *client, for (i = 0; i < desc->num_led_descs; i++) { err = nizynqcpld_led_register(cpld, &desc->led_descs[i], &cpld->leds[i]); + /* Skip LEDs that are missing from device tree, but continue + * adding other LEDs. */ if (err) - goto err_led; + dev_dbg(&client->dev, + "Omitting %s LED\n", + desc->led_descs[i].of_node_name); } /* don't care about errors */ @@ -1591,7 +1635,6 @@ static int nizynqcpld_probe(struct i2c_client *client, sysfs_remove_files(&client->dev.kobj, desc->attrs); err_sysfs_create_files: myrio_wifi_sw_uninit(cpld); -err_led: while (i--) nizynqcpld_led_unregister(&cpld->leds[i]); kfree(cpld->leds); @@ -1625,15 +1668,22 @@ static int nizynqcpld_remove(struct i2c_client *client) return 0; } +static const struct of_device_id nizynqcpld_dt_ids[] = { + { .compatible = "ni,cpld" }, + { } +}; +MODULE_DEVICE_TABLE(of, nizynqcpld_dt_ids); + static const struct i2c_device_id nizynqcpld_ids[] = { - { .name = "nizynqcpld" }, + { .name = "cpld" }, { }, }; MODULE_DEVICE_TABLE(i2c, nizynqcpld_ids); static struct i2c_driver nizynqcpld_driver = { .driver = { - .name = "nizynqcpld", + .name = "nicpld", + .of_match_table = nizynqcpld_dt_ids, }, .probe = nizynqcpld_probe, .remove = nizynqcpld_remove, From 9da604dcb15e5cd9f6d7a69c4b63206b038cec7a Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Fri, 6 Mar 2015 12:05:30 -0600 Subject: [PATCH 47/97] nizynqcpld: Remove tecate_leds Tecate isn't so special that it needs its own duplicate LED section. The only reason it needed one before was to avoid registering eth1 LEDs. Now that we specify LEDs via the device tree, any LEDs not present in the device tree will not get registered. The Tecate device tree doesn't specify LEDs that it doesn't have, so we'll still be avoiding registering eth1 LEDs even after removing tecate_leds. Signed-off-by: Jaeden Amero Reviewed-by: Ben Shelton Reviewed-by: Josh Cartwright Natinst-ReviewBoard-ID: 91284 --- drivers/misc/nizynqcpld.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index b3a4a82151fc9..92ca8116c62ad 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1213,32 +1213,6 @@ static struct nizynqcpld_led_desc sol_leds[] = { }, }; -static struct nizynqcpld_led_desc tecate_leds[] = { - { - .of_node_name = "user1-0", - .addr = DOSX_LED, - .bit = 1 << 5, - }, - { - .of_node_name = "status-0", - .addr = DOSX_LED, - .bit = 1 << 2, - .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, - /* write byte 1 first */ - .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, - }, - { - .of_node_name = "eth0-0", - .addr = DOSX_ETHERNETLED, - .bit = 1 << 1, - }, - { - .of_node_name = "eth0-1", - .addr = DOSX_ETHERNETLED, - .bit = 1 << 0, - }, -}; - static struct nizynqcpld_watchdog_desc dosxv4_watchdog_desc = { .watchdog_period_ns = 24000, }; @@ -1321,8 +1295,8 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .supported_version = 1, .supported_product = 2, .watchdog_desc = &dosxv5_watchdog_desc, - .led_descs = tecate_leds, - .num_led_descs = ARRAY_SIZE(tecate_leds), + .led_descs = sol_leds, + .num_led_descs = ARRAY_SIZE(sol_leds), .reboot_addr = DOSX_PROCESSORRESET, .scratch_hr_addr = DOSX_SCRATCHPADHR, .scratch_sr_addr = DOSX_SCRATCHPADSR, From a3f0dc5c7b4abbf79bca0bdad0ba2a0989f5750f Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Wed, 17 Feb 2016 10:08:26 -0600 Subject: [PATCH 48/97] nizynqcpld: Use oneshot interrupt flag Using the IRQF_ONESHOT flag keeps us from losing our handler entirely after a recent IRQ change in the RT patch, commit 62c6757fc4ef ("genirq: Handle force threading of interrupts with primary and thread handler"). While that commit caused our immediate problem, we should have been using this all along and were only saved by the fact that our interrupts are edge-triggered. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Josh Cartwright Natinst-CAR-ID: 568224 Natinst-CAR-ID: 572611 Natinst-ReviewBoard-ID: 127047 --- drivers/misc/nizynqcpld.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 92ca8116c62ad..f6a92267aad23 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -981,7 +981,7 @@ static int nizynqcpld_watchdog_misc_open(struct inode *inode, cpld->irq = irq_of_parse_and_map(boot_watchdog_node, 0); return request_threaded_irq(cpld->irq, NULL, nizynqcpld_watchdog_irq, - 0, NIWATCHDOG_NAME, cpld); + IRQF_ONESHOT, NIWATCHDOG_NAME, cpld); } static int nizynqcpld_watchdog_misc_release(struct inode *inode, @@ -1385,8 +1385,8 @@ static int wifi_sw_open(struct input_dev *dev) struct nizynqcpld *cpld = container_of(wifi_sw, struct nizynqcpld, wifi_sw); - err = request_threaded_irq(wifi_sw->irq, - NULL, wifi_sw_hnd, 0, "wifi_sw", wifi_sw); + err = request_threaded_irq(wifi_sw->irq, NULL, wifi_sw_hnd, + IRQF_ONESHOT, "wifi_sw", wifi_sw); if (err) { dev_err(&cpld->client->dev, "error %d registering irq handle for wifi_sw\n", err); From f35934e76ded17c757eea0892567bd54f70b80c0 Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Thu, 26 Feb 2015 10:28:19 -0600 Subject: [PATCH 49/97] nizynqcpld: make poll() and ioctl() functions static These functions are not used outside nizynqcpld. Mark them static. Reviewed-by: Jaeden Amero Reviewed-by: Gratian Crisan Reviewed-by: Brad Mouring Reviewed-by: Ben Shelton Signed-off-by: Josh Cartwright Natinst-ReviewBoard-ID: 90460 --- drivers/misc/nizynqcpld.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index f6a92267aad23..1ee4b6ceaaf42 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -993,6 +993,7 @@ static int nizynqcpld_watchdog_misc_release(struct inode *inode, return 0; } +static long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1072,6 +1073,7 @@ long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, return err; } +static unsigned int nizynqcpld_watchdog_misc_poll(struct file *file, struct poll_table_struct *wait) { From d499e5956d5c23d9e4dea7ed3c6c3f7cf9de0046 Mon Sep 17 00:00:00 2001 From: Josh Cartwright Date: Fri, 20 Mar 2015 10:40:15 -0500 Subject: [PATCH 50/97] nizynqcpld: use restart_handler mechanism for triggering restart The restart_handler mechanism is a much cleaner way to hook into the restart codepaths. Make the CPLD driver higher priority than the Zynq-provided SLCR reset mechanism to allow the CPLD to track the reason why the Zynq was reset. Signed-off-by: Josh Cartwright Reviewed-by: Ben Shelton Reviewed-by: Jaeden Amero Natinst-ReviewBoard-ID: 90458 --- drivers/misc/nizynqcpld.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 1ee4b6ceaaf42..6b47e92fc4f43 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -19,8 +19,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -140,7 +140,7 @@ struct nizynqcpld { struct nizynqcpld_watchdog watchdog; struct i2c_client *client; struct mutex lock; - struct ni_zynq_board_reset reset; + struct notifier_block restart_nb; struct myrio_wifi_sw wifi_sw; }; @@ -330,12 +330,15 @@ static int nizynqcpld_read(struct nizynqcpld *cpld, u8 reg, u8 *data) return err == ARRAY_SIZE(msgs) ? 0 : err; } -static void nizynqcpld_reset(struct ni_zynq_board_reset *reset) +static int nizynqcpld_restart(struct notifier_block *nb, + unsigned long action, void *data) { - struct nizynqcpld *cpld = container_of(reset, struct nizynqcpld, reset); + struct nizynqcpld *cpld = container_of(nb, struct nizynqcpld, + restart_nb); struct nizynqcpld_desc *desc = cpld->desc; nizynqcpld_write(cpld, desc->reboot_addr, 0x80); + return 0; } static inline ssize_t nizynqcpld_scratch_show(struct nizynqcpld *cpld, @@ -1596,8 +1599,9 @@ static int nizynqcpld_probe(struct i2c_client *client, } } - cpld->reset.reset = nizynqcpld_reset; - ni_zynq_board_reset = &cpld->reset; + cpld->restart_nb.notifier_call = nizynqcpld_restart; + cpld->restart_nb.priority = 255; + register_restart_handler(&cpld->restart_nb); i2c_set_clientdata(client, cpld); @@ -1628,7 +1632,7 @@ static int nizynqcpld_remove(struct i2c_client *client) struct nizynqcpld_desc *desc = cpld->desc; int i; - ni_zynq_board_reset = NULL; + unregister_restart_handler(&cpld->restart_nb); if (desc->watchdog_desc) misc_deregister(&cpld->watchdog.misc_dev); From b491d608122a9f16f11a888e2545cf129f46ae00 Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Fri, 6 Mar 2015 11:51:40 -0600 Subject: [PATCH 51/97] nizynqcpld: Document device tree bindings Document how nizynqcpld uses device tree, including the required and optional settings for the nizynqcpld node and its children nodes. Signed-off-by: Jaeden Amero Reviewed-by: Ben Shelton Reviewed-by: Josh Cartwright Natinst-ReviewBoard-ID: 91284 --- .../devicetree/bindings/misc/ni,cpld.txt | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/ni,cpld.txt diff --git a/Documentation/devicetree/bindings/misc/ni,cpld.txt b/Documentation/devicetree/bindings/misc/ni,cpld.txt new file mode 100644 index 0000000000000..a1abde6f5f0e9 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/ni,cpld.txt @@ -0,0 +1,156 @@ +National Instruments CPLD + +National Instruments (NI) boards often have CPLDs on them to handle +board-specific tasks like LED control, board switches and buttons, +power sequencing, and CPU-independent watchdogs. + +NI's CPLDs are connected over i2c. As such, 'nicpld' must be a child +of an i2c node. + +nicpld properties: +- compatible : (required) + Should be "ni,cpld" +- reg: (required) + Address of the CPLD on the i2c bus + +Required sub-nodes: +- watchdogs : A node containing sub-nodes describing watchdogs + +Optional sub-nodes: +- switches : A node containing sub-nodes describing switches +- leds : A node containing sub-nodes describing LEDs + + +Watchdogs Child Node +==================== + +Each watchdog controlled by the CPLD is represented as a sub-node of +the nicpld's 'watchdogs' node. Each sub-node of 'watchdogs' has the +following properties. + +Required properties: +- interrupts : Should be the CPLD watchdog interrupt specifier + +Optional properties: +- label: A name for the CPLD switch + + +Switches Child Node +=================== + +Each switch or button controlled by the CPLD is represented as a +sub-node of the nicpld's 'switches' node. Each sub-node of 'switches' +has the following properties. + +Required properties: +- interrupts : The CPLD switch interrupt specifier + + +LEDs Child Node +=============== + +Each LED controlled by the CPLD is represented as a sub-node of the +nicpld's 'leds' node. The name of each LED node corresponds to an +LED type. The "-0" or "-1" suffixes specify an LED element (single +color) within a multi-color LED. + +Possible LED types: +- user1-0 +- user1-1 +- status-0 +- status-1 +- temp-alert-0 +- wifi-0 +- wifi-1 +- eth0-0 +- eth0-1 +- eth1-0 +- eth1-1 + +Different CPLDs support different LED types. The set of LEDs that +various CPLDs support can be determined by examining their product +code. The product code for a CPLD can be determined by reading the +"NICPLD_PRODUCT" (0x1D) register of the CPLD over i2c. Below is a +list of which CPLDs support which LED types. + +CPLD Products 0x00 and 0x01 +--------------------------- +user1-0 +user1-1 +status-0 +status-1 +wifi-0 +wifi-1 +eth0-0 +eth0-1 +eth1-0 +eth1-1 + +CPLD Product 0x02 +----------------- +status-0 +temp-alert-0 +eth0-0 +eth0-1 +eth1-0 +eth1-1 + +CPLD Products 0x03 and 0x04 +--------------------------- +user1-0 +status-0 +eth0-0 +eth0-1 +eth1-0 +eth1-1 + + +LED sub-node properties: +- label : (optional) + see bindings/leds/common.txt +- max-brightness : (optional) + The number of possible special blinking patterns. Selecting a + brightness will pick the blink pattern. +- linux,default-trigger : (optional) + see bindings/leds/common.txt + +Example: + +nicpld@40 { + compatible = "ni,cpld"; + reg = <0x40>; + + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <24 0>; + }; + }; + + switches { + wifi-switch { + interrupt-parent = <&gpio>; + interrupts = <25 0>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + }; +}; From a1a62591ceb702e397a2a3b3500d48a028b64ce5 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Fri, 9 Dec 2016 10:41:20 -0600 Subject: [PATCH 52/97] nizynqcpld: Unblock poll() callers on highly-loaded systems On systems under high load, our IRQ handler hangs on I2C read because the I2C IRQ thread priority is lower than load priority. To work around this, we set watchdog.expired and wake up poll() callers before trying I2C communication. This does assume that we will never have spurious interrupts on this line, but since it's only driven by the CPLD we should never run into that case. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Tested-by: Ovidiu Vancea Acked-by: Julia Cartwright Natinst-CAR-ID: 577311 Natinst-ReviewBoard-ID: 168702 --- drivers/misc/nizynqcpld.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 6b47e92fc4f43..1a6497b42e8b6 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -922,6 +922,11 @@ static irqreturn_t nizynqcpld_watchdog_irq(int irq, void *data) nizynqcpld_lock(cpld); + cpld->watchdog.expired = true; + + /* Signal the watchdog event. */ + wake_up_all(&cpld->watchdog.irq_event); + err = nizynqcpld_read(cpld, DOSX_WATCHDOGCONTROL, &control); if (err) { @@ -934,8 +939,6 @@ static irqreturn_t nizynqcpld_watchdog_irq(int irq, void *data) goto out_unlock; } - cpld->watchdog.expired = true; - /* Mask off all the read-only and write-only bits. */ control &= DOSX_WATCHDOGCONTROL_RW_BITS; @@ -943,9 +946,6 @@ static irqreturn_t nizynqcpld_watchdog_irq(int irq, void *data) control |= DOSX_WATCHDOGCONTROL_RESET; err = nizynqcpld_write(cpld, DOSX_WATCHDOGCONTROL, control); - /* Signal the watchdog event. */ - wake_up_all(&cpld->watchdog.irq_event); - ret = IRQ_HANDLED; out_unlock: @@ -1081,14 +1081,10 @@ unsigned int nizynqcpld_watchdog_misc_poll(struct file *file, struct poll_table_struct *wait) { struct nizynqcpld *cpld = file->private_data; - unsigned int mask = 0; - poll_wait(file, &cpld->watchdog.irq_event, wait); - nizynqcpld_lock(cpld); - if (cpld->watchdog.expired) - mask = POLLIN; - nizynqcpld_unlock(cpld); - return mask; + if (READ_ONCE(cpld->watchdog.expired)) + return POLLIN; + return 0; } static const struct file_operations nizynqcpld_watchdog_misc_fops = { From c747da87629652de9eac041a40e5b190aab1a936 Mon Sep 17 00:00:00 2001 From: Xander Huff Date: Tue, 18 Oct 2016 11:23:31 -0500 Subject: [PATCH 53/97] nizynqcpld: Code style cleanup Fix checkpatch error/warnings: Prefer 'unsigned int' to bare use of 'unsigned' Block comments use a trailing */ on a separate line Missing a blank line after declarations Block comments use * on subsequent lines line over 80 characters space required after that ',' (ctx:VnV) Comparisons should place the constant on the right side of the test quoted string split across lines Prefer kcalloc over kzalloc with multiply Signed-off-by: Xander Huff Natinst-ReviewBoard-ID: 157395 --- drivers/misc/nizynqcpld.c | 57 ++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 1a6497b42e8b6..1a92c7c1c5e6c 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -122,7 +122,7 @@ struct nizynqcpld_desc { u8 supported_version; u8 supported_product; struct nizynqcpld_led_desc *led_descs; - unsigned num_led_descs; + unsigned int num_led_descs; struct nizynqcpld_watchdog_desc *watchdog_desc; u8 reboot_addr; u8 scratch_hr_addr; @@ -157,7 +157,8 @@ static inline void nizynqcpld_unlock(struct nizynqcpld *cpld) } /* Can't issue i2c transfers in set_brightness, because - * they can sleep */ + * they can sleep + */ static void nizynqcpld_set_brightness_work(struct work_struct *work) { struct nizynqcpld_led *led = container_of(work, struct nizynqcpld_led, @@ -195,9 +196,11 @@ static void nizynqcpld_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { struct nizynqcpld_led *led = to_nizynqcpld_led(led_cdev); + led->on = !!brightness; /* some LED's support a blink pattern instead of a variable brightness, - and blink_set isn't flexible enough for the supported patterns */ + * and blink_set isn't flexible enough for the supported patterns + */ led->blink_pattern = brightness; schedule_work(&led->deferred_work); } @@ -216,7 +219,8 @@ nizynqcpld_led_get_brightness(struct led_classdev *led_cdev) nizynqcpld_unlock(cpld); /* for the status LED, the blink pattern used for brightness on write - is write-only, so we just return on/off for all LED's */ + * is write-only, so we just return on/off for all LED's + */ return tmp & desc->bit ? LED_FULL : 0; } @@ -268,7 +272,8 @@ static int nizynqcpld_led_register(struct nizynqcpld *cpld, node = of_get_child_by_name(leds_node, desc->of_node_name); if (!node) { /* Don't register the LED if the LED is not specified in device - * tree. */ + * tree. + */ err = -ENOENT; goto err_out; } @@ -366,6 +371,7 @@ static ssize_t nizynqcpld_scratchsr_show(struct device *dev, { struct nizynqcpld *cpld = dev_get_drvdata(dev); struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_show(cpld, attr, buf, desc->scratch_sr_addr); } @@ -374,6 +380,7 @@ static ssize_t nizynqcpld_scratchhr_show( { struct nizynqcpld *cpld = dev_get_drvdata(dev); struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_show(cpld, attr, buf, desc->scratch_hr_addr); } @@ -411,6 +418,7 @@ static ssize_t nizynqcpld_scratchsr_store(struct device *dev, { struct nizynqcpld *cpld = dev_get_drvdata(dev); struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_store(cpld, attr, buf, count, desc->scratch_sr_addr); } @@ -421,6 +429,7 @@ static ssize_t nizynqcpld_scratchhr_store(struct device *dev, { struct nizynqcpld *cpld = dev_get_drvdata(dev); struct nizynqcpld_desc *desc = cpld->desc; + return nizynqcpld_scratch_store(cpld, attr, buf, count, desc->scratch_hr_addr); } @@ -564,11 +573,12 @@ static inline ssize_t nizynqcpld_powerstatus_show(struct device *dev, return sprintf(buf, "%u\n", !!(data & pa->bit)); } -#define POWERSTATUS_ATTR(_name,_bit) \ - struct powerstatus_attribute dev_attr_##_name = { \ - .bit = _bit, \ - .dev_attr = \ - __ATTR(_name, 0444, nizynqcpld_powerstatus_show, NULL), \ +#define POWERSTATUS_ATTR(_name, _bit) \ + struct powerstatus_attribute dev_attr_##_name = { \ + .bit = _bit, \ + .dev_attr = \ + __ATTR(_name, 0444, nizynqcpld_powerstatus_show, \ + NULL), \ } static POWERSTATUS_ATTR(pwr_aux_valid, 1 << 4); @@ -615,7 +625,8 @@ static ssize_t dosequiscpld_wdmode_show(struct device *dev, return err; /* you write a 1 to the bit to enter user mode, but it reads as a - 0 in user mode for backwards compatibility */ + * 0 in user mode for backwards compatibility + */ tmp &= DOSX_WATCHDOGCONTROL_ENTER_USER_MODE; return sprintf(buf, "%s\n", tmp ? "boot" : "user"); } @@ -748,9 +759,9 @@ static int nizynqcpld_watchdog_add_action(struct nizynqcpld *cpld, u32 action) int err; u8 action_bit; - if (NIWATCHDOG_ACTION_INTERRUPT == action) + if (action == NIWATCHDOG_ACTION_INTERRUPT) action_bit = DOSX_WATCHDOGCONTROL_PROC_INTERRUPT; - else if (NIWATCHDOG_ACTION_RESET == action) + else if (action == NIWATCHDOG_ACTION_RESET) action_bit = DOSX_WATCHDOGCONTROL_PROC_RESET; else return -ENOTSUPP; @@ -898,7 +909,7 @@ static int nizynqcpld_watchdog_counter_get(struct nizynqcpld *cpld, DOSX_WATCHDOGCOUNTER2, DOSX_WATCHDOG_COUNTER_BYTES, data); - if (DOSX_WATCHDOG_COUNTER_BYTES == err) + if (err == DOSX_WATCHDOG_COUNTER_BYTES) err = 0; else { dev_err(cpld->dev, @@ -991,6 +1002,7 @@ static int nizynqcpld_watchdog_misc_release(struct inode *inode, struct file *file) { struct nizynqcpld *cpld = file->private_data; + free_irq(cpld->irq, cpld); atomic_inc(&cpld->watchdog.available); return 0; @@ -1009,18 +1021,21 @@ long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case NIWATCHDOG_IOCTL_PERIOD_NS: { __u32 period = desc->watchdog_period_ns; + err = copy_to_user((__u32 *)arg, &period, sizeof(__u32)); break; } case NIWATCHDOG_IOCTL_MAX_COUNTER: { __u32 counter = DOSX_WATCHDOG_MAX_COUNTER; + err = copy_to_user((__u32 *)arg, &counter, sizeof(__u32)); break; } case NIWATCHDOG_IOCTL_COUNTER_SET: { __u32 counter; + err = copy_from_user(&counter, (__u32 *)arg, sizeof(__u32)); if (!err) @@ -1029,6 +1044,7 @@ long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, } case NIWATCHDOG_IOCTL_CHECK_ACTION: { __u32 action; + err = copy_from_user(&action, (__u32 *)arg, sizeof(__u32)); if (!err) @@ -1037,6 +1053,7 @@ long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, } case NIWATCHDOG_IOCTL_ADD_ACTION: { __u32 action; + err = copy_from_user(&action, (__u32 *)arg, sizeof(__u32)); if (!err) @@ -1049,6 +1066,7 @@ long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, } case NIWATCHDOG_IOCTL_PET: { __u32 state; + err = nizynqcpld_watchdog_pet(cpld, &state); if (!err) err = copy_to_user((__u32 *)arg, &state, @@ -1061,6 +1079,7 @@ long nizynqcpld_watchdog_misc_ioctl(struct file *file, unsigned int cmd, } case NIWATCHDOG_IOCTL_COUNTER_GET: { __u32 counter; + err = nizynqcpld_watchdog_counter_get(cpld, &counter); if (!err) { err = copy_to_user((__u32 *)arg, &counter, @@ -1374,6 +1393,7 @@ static void wifi_sw_work_func(struct work_struct *work) static irqreturn_t wifi_sw_hnd(int irq, void *irq_data) { struct myrio_wifi_sw *wifi_sw = (struct myrio_wifi_sw *)irq_data; + schedule_work(&wifi_sw->deferred_work); return IRQ_HANDLED; @@ -1541,14 +1561,14 @@ static int nizynqcpld_probe(struct i2c_client *client, if (!desc) { err = -ENODEV; dev_err(cpld->dev, - "this driver does not support cpld with version %d and" - " product %d.\n", version, product); + "this driver does not support cpld with version %d and product %d.\n", + version, product); goto err_no_version; } cpld->desc = desc; - cpld->leds = kzalloc(sizeof(*cpld->leds) * desc->num_led_descs, + cpld->leds = kcalloc(desc->num_led_descs, sizeof(*cpld->leds), GFP_KERNEL); if (!cpld->leds) { err = -ENOMEM; @@ -1560,7 +1580,8 @@ static int nizynqcpld_probe(struct i2c_client *client, err = nizynqcpld_led_register(cpld, &desc->led_descs[i], &cpld->leds[i]); /* Skip LEDs that are missing from device tree, but continue - * adding other LEDs. */ + * adding other LEDs. + */ if (err) dev_dbg(&client->dev, "Omitting %s LED\n", From 362f8fd6a87e8b7bdb959293fdbc7cb706b08f49 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Wed, 2 Aug 2017 08:12:52 -0500 Subject: [PATCH 54/97] nizynqcpld: Request IRQ on probe instead of miscdevice open Do what most sane drivers do and request our IRQ on probe rather than doing it every time someone opens our char device. This ensures that our thread exists at boot time, which means priority changes can be done in user mode. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Ovidiu Vancea Acked-by: Zach Brown Acked-by: Julia Cartwright Natinst-CAR-ID: 649766 Natinst-ReviewBoard-ID: 197577 --- drivers/misc/nizynqcpld.c | 47 +++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 1a92c7c1c5e6c..59278ebe8424c 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -970,32 +970,15 @@ static int nizynqcpld_watchdog_misc_open(struct inode *inode, struct miscdevice *misc_dev = file->private_data; struct nizynqcpld *cpld = container_of(misc_dev, struct nizynqcpld, watchdog.misc_dev); - struct device_node *watchdogs_node; - struct device_node *boot_watchdog_node; file->private_data = cpld; - /* Find the watchdogs node. */ - watchdogs_node = of_find_node_by_name(cpld->client->dev.of_node, - "watchdogs"); - if (!watchdogs_node) - return -ENOENT; - - /* Get the boot watchdog node. */ - boot_watchdog_node = of_find_node_by_name(watchdogs_node, - "boot-watchdog"); - if (!boot_watchdog_node) - return -ENOENT; - if (!atomic_dec_and_test(&cpld->watchdog.available)) { atomic_inc(&cpld->watchdog.available); return -EBUSY; } - cpld->irq = irq_of_parse_and_map(boot_watchdog_node, 0); - - return request_threaded_irq(cpld->irq, NULL, nizynqcpld_watchdog_irq, - IRQF_ONESHOT, NIWATCHDOG_NAME, cpld); + return 0; } static int nizynqcpld_watchdog_misc_release(struct inode *inode, @@ -1003,7 +986,6 @@ static int nizynqcpld_watchdog_misc_release(struct inode *inode, { struct nizynqcpld *cpld = file->private_data; - free_irq(cpld->irq, cpld); atomic_inc(&cpld->watchdog.available); return 0; } @@ -1599,12 +1581,39 @@ static int nizynqcpld_probe(struct i2c_client *client, if (desc->watchdog_desc) { struct nizynqcpld_watchdog *watchdog = &cpld->watchdog; + struct device_node *node; watchdog->desc = desc->watchdog_desc; atomic_set(&watchdog->available, 1); init_waitqueue_head(&watchdog->irq_event); watchdog->expired = false; + /* Find the watchdogs node. */ + node = of_find_node_by_name(cpld->client->dev.of_node, + "watchdogs"); + if (!node) { + err = -ENOENT; + goto err_watchdog_register; + } + + /* Get the boot watchdog node. */ + node = of_find_node_by_name(node, "boot-watchdog"); + if (!node) { + err = -ENOENT; + goto err_watchdog_register; + } + + cpld->irq = irq_of_parse_and_map(node, 0); + + err = devm_request_threaded_irq(&client->dev, cpld->irq, NULL, + nizynqcpld_watchdog_irq, + IRQF_ONESHOT, NIWATCHDOG_NAME, + cpld); + if (err) { + dev_err(cpld->dev, "failed to get irq\n"); + goto err_watchdog_register; + } + watchdog->misc_dev.minor = MISC_DYNAMIC_MINOR; watchdog->misc_dev.name = NIWATCHDOG_NAME; watchdog->misc_dev.fops = &nizynqcpld_watchdog_misc_fops; From c0ca407caf24eeaf48dff0cad149ae6d88274257 Mon Sep 17 00:00:00 2001 From: Adrian Papp Date: Wed, 22 Jan 2014 14:42:36 +0200 Subject: [PATCH 55/97] myRIO: fix argument passed to free_irq called in wifi_sw_close Signed-off-by: Adrian Papp Natinst-CAR-ID: 445041 --- drivers/misc/nizynqcpld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 59278ebe8424c..5627313f5bf0e 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1404,7 +1404,7 @@ static void wifi_sw_close(struct input_dev *dev) struct myrio_wifi_sw *wifi_sw = input_get_drvdata(dev); if (wifi_sw->irq_registered) - free_irq(wifi_sw->irq, wifi_sw_hnd); + free_irq(wifi_sw->irq, wifi_sw); } static int myrio_wifi_sw_init(struct nizynqcpld *cpld) From 006c2eb0502d18bd359ad0b514bba1fee6009f24 Mon Sep 17 00:00:00 2001 From: Jason VanFickell Date: Fri, 17 Jan 2014 13:02:14 -0600 Subject: [PATCH 56/97] myRIO: add inversion support to the LED driver Inversion support in the LED driver is needed for the WiFi LED feature. Signed-off-by: Jason VanFickell (joshc: use DEVICE_ATTR_RW() to declare inverted attribute) Signed-off-by: Josh Cartwright (Haris Okanovic: fixup squash: led_get_brightness function inverting led value) Signed-off-by: Zach Brown Signed-off-by: Brad Mouring Acked-by: Xander Huff Acked-by: James Minor Natinst-CAR-ID: 624268 Natinst-ReviewBoard-ID: 170771 --- drivers/leds/led-class.c | 34 ++++++++++++++++++++++++++++++++++ drivers/leds/led-core.c | 6 ++++++ include/linux/leds.h | 1 + 3 files changed, 41 insertions(+) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 6b9fa060c3a11..b5724e4c3bd48 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -84,6 +84,39 @@ static ssize_t max_brightness_show(struct device *dev, } static DEVICE_ATTR_RO(max_brightness); +static ssize_t inverted_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", led_cdev->inverted); +} + +static ssize_t inverted_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + u8 inverted; + int ret; + + ret = kstrtou8(buf, 10, &inverted); + if (ret < 0) + return ret; + + if (inverted > 1) + return -EINVAL; + + led_cdev->inverted = inverted; + + /* Note: The LED brightness is not immediately + * updated as a result of changing the inversion. + */ + + return size; +} + +static DEVICE_ATTR_RW(inverted); + #ifdef CONFIG_LEDS_TRIGGERS static const BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, 0); static const struct bin_attribute *const led_trigger_bin_attrs[] = { @@ -98,6 +131,7 @@ static const struct attribute_group led_trigger_group = { static struct attribute *led_class_attrs[] = { &dev_attr_brightness.attr, &dev_attr_max_brightness.attr, + &dev_attr_inverted.attr, NULL, }; diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 59473f286b31f..1e549f3bbf8ad 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -331,6 +331,9 @@ EXPORT_SYMBOL_GPL(led_set_brightness); void led_set_brightness_nopm(struct led_classdev *led_cdev, unsigned int value) { + if (led_cdev->inverted) + value = value ? LED_OFF : LED_FULL; + /* Use brightness_set op if available, it is guaranteed not to sleep */ if (!__led_set_brightness(led_cdev, value)) return; @@ -375,6 +378,9 @@ int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value) if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) return -EBUSY; + if (led_cdev->inverted) + value = value ? LED_OFF : LED_FULL; + led_cdev->brightness = min(value, led_cdev->max_brightness); if (led_cdev->flags & LED_SUSPENDED) diff --git a/include/linux/leds.h b/include/linux/leds.h index b16b803cc1ac5..f4c173f66153d 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -233,6 +233,7 @@ struct led_classdev { */ struct device *(*hw_control_get_device)(struct led_classdev *led_cdev); #endif + u8 inverted; #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED int brightness_hw_changed; From 815d3a1efe3e5a111071c74000792963b6e5a61c Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Tue, 29 Apr 2014 09:35:46 -0500 Subject: [PATCH 57/97] i2c: cadence: Support reading the bus number from the device tree When multiple I2C busses are present, we need a way to deterministically specify the bus number for each bus. Here we add support for reading a bus-id field from the device tree. We must use i2c_add_numbered_adapter when specifying a bus number. We use a default value of -1 if the bus number isn't specified in the device tree, which gives the same behavior as using i2c_add_adapter. Signed-off-by: Jeff Westfahl --- drivers/i2c/busses/i2c-cadence.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 0fb728ade92e4..c397e4c8cdab1 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -1530,6 +1530,15 @@ static int cdns_i2c_probe(struct platform_device *pdev) return irq; id->adap.owner = THIS_MODULE; + + /* + * A bus number of -1 means dynamically assign, default to that if + * bus-id isn't specified in the device tree. + */ + ret = of_property_read_u32(pdev->dev.of_node, "bus-id", &id->adap.nr); + if (ret) + id->adap.nr = -1; + id->adap.dev.of_node = pdev->dev.of_node; id->adap.algo = &cdns_i2c_algo; id->adap.timeout = CDNS_I2C_TIMEOUT; @@ -1597,7 +1606,7 @@ static int cdns_i2c_probe(struct platform_device *pdev) } cdns_i2c_init(id); - ret = i2c_add_adapter(&id->adap); + ret = i2c_add_numbered_adapter(&id->adap); if (ret < 0) goto err_clk_notifier_unregister; From f470fe4aac01bd0933d9da5158f56f7f826a94c1 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Thu, 29 Aug 2013 20:36:21 -0500 Subject: [PATCH 58/97] xiic: Read the bus number from the device tree This allows the controller to play nicely with other i2c controllers in the same device. Signed-off-by: Joe Hershberger --- drivers/i2c/busses/i2c-xiic.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 28015d77599d1..dcc0de48be3aa 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -1430,6 +1430,9 @@ static int xiic_i2c_probe(struct platform_device *pdev) int ret, irq; u8 i; u32 sr; +#ifdef CONFIG_OF + const unsigned int *prop; +#endif i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) @@ -1461,6 +1464,18 @@ static int xiic_i2c_probe(struct platform_device *pdev) snprintf(i2c->adap.name, sizeof(i2c->adap.name), DRIVER_NAME " %s", pdev->name); + /* a bus number of -1 means dynamically assign, default to that if + * bus-id isn't specified in the device tree + */ + i2c->adap.nr = -1; +#ifdef CONFIG_OF + prop = of_get_property(pdev->dev.of_node, "bus-id", NULL); + if (prop) + i2c->adap.nr = be32_to_cpup(prop); +#endif + + xiic_reinit(i2c); + mutex_init(&i2c->lock); spin_lock_init(&i2c->atomic_lock); @@ -1514,7 +1529,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) } /* add i2c adapter to i2c tree */ - ret = i2c_add_adapter(&i2c->adap); + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret) { xiic_deinit(i2c); goto err_pm_disable; From 8b11fb9020be5551da7e8fef3b39be7ab29cb2a1 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 16 Feb 2017 14:03:16 -0600 Subject: [PATCH 59/97] i2c: xiic: Handle devices that do not specify a clock With the addition of commit e9aacb08ff9d ("i2c: xiic: Implement power management") the xiic driver failed to load if a clock was not specified in the dts. This commit changes the behavior so that a clock does not need to be specified in order for the driver to function. [cvadrevu: Fixed trivial conflict] Signed-off-by: Chaitanya Vadrevu Fixes: e9aacb08ff9d ("i2c: xiic: Implement power management") Signed-off-by: Zach Brown Signed-off-by: Brad Mouring Acked-by: Kyle Roeschley Acked-by: Julia Cartwright Acked-by: Brandon Streiff Natinst-CAR-ID: 630351 Natinst-ReviewBoard-ID: 173828 --- drivers/i2c/busses/i2c-xiic.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index dcc0de48be3aa..2521012922ce8 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -1480,10 +1480,16 @@ static int xiic_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->atomic_lock); i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); - if (IS_ERR(i2c->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), - "failed to enable input clock.\n"); - + if (IS_ERR(i2c->clk)) { + if (PTR_ERR(i2c->clk) != -ENOENT) { + dev_err(&pdev->dev, + "error while finding input clock. %ld\n", + PTR_ERR(i2c->clk)); + return PTR_ERR(i2c->clk); + } + dev_err(&pdev->dev, "Optional input clock not found.\n"); + i2c->clk = NULL; + } i2c->dev = &pdev->dev; pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT); pm_runtime_use_autosuspend(i2c->dev); From 10b16d67fd11544348a756d5cff8545d0467a3b8 Mon Sep 17 00:00:00 2001 From: James Minor Date: Tue, 16 Aug 2016 16:27:21 -0500 Subject: [PATCH 60/97] Revert "irqchip/gic: Kill the xlate method" This reverts commit 18bd8847cdd4dac3276ae9973739c570ce37e0b7. When using CONFIG_GIC_LEGACY_IRQDOMAIN irq!=hwirq. Keep this translation around or else irqs will be mapped to the wrong hwirq. Natinst-ReviewBoard-ID: 149318 Natinst-CAR-ID: 599933 [cvadrevu: Fixed conflicts due to TODO] Signed-off-by: Chaitanya Vadrevu --- drivers/irqchip/irq-gic.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 1269ab8eb726a..18bbf16e5e171 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1078,6 +1078,30 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, return 0; } +static int gic_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type) +{ + unsigned long ret = 0; + + if (irq_domain_get_of_node(d) != controller) + return -EINVAL; + if (intsize < 3) + return -EINVAL; + + /* Get the interrupt number and add 16 to skip over SGIs */ + *out_hwirq = intspec[1] + 16; + + /* For SPIs, we need to add 16 more to get the GIC irq ID number */ + if (!intspec[0]) + *out_hwirq += 16; + + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return ret; +} + static int gic_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, @@ -1158,6 +1182,7 @@ static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = { .translate = gic_irq_domain_translate, .alloc = gic_irq_domain_alloc, .free = irq_domain_free_irqs_top, + .xlate = gic_irq_domain_xlate, }; static int gic_init_bases(struct gic_chip_data *gic, From 9d88ce66c576c5a02f346e854d877585a853a1b5 Mon Sep 17 00:00:00 2001 From: Hui Chun Ong Date: Sat, 8 Jul 2017 12:33:34 +0800 Subject: [PATCH 61/97] watchdog: nic7018_wdt: Add support for timeout interrupt Add interrupt handling for watchdog timeout. Interrupt control is done through sysfs "enable_interrupt" attribute. uevent is used to signal userspace when interrupt occurred as oppose to using poll due to no support in watchdog core. Signed-off-by: Hui Chun Ong Signed-off-by: Brad Mouring Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 195479 --- drivers/watchdog/nic7018_wdt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c index e66f4866f94ff..3daf3e773f1d1 100644 --- a/drivers/watchdog/nic7018_wdt.c +++ b/drivers/watchdog/nic7018_wdt.c @@ -416,6 +416,15 @@ static int nic7018_probe(struct platform_device *pdev) return ret; } + ret = devm_request_threaded_irq(dev, irq, NULL, + nic7018_thread_isr, + IRQF_ONESHOT, + KBUILD_MODNAME, wdt); + if (ret) { + dev_err(dev, "failed to register interrupt handler\n"); + return ret; + } + /* Unlock WDT register */ outb(UNLOCK, wdt->io_base + WDT_REG_LOCK); From 5128ee229d7cff662cb0c0797b257f1100d0a29f Mon Sep 17 00:00:00 2001 From: Wilson Lee Date: Tue, 19 Dec 2017 20:15:14 -0800 Subject: [PATCH 62/97] auxdisplay: sh1107: Sino Wealth SH1107 OLED driver Sino Wealth SH1107 OLED display driver are not supported at this moment. This commit is to add SH1107 driver to support SH1107 OLED driver. This driver will use i2c communication to transfer data to SH1107 IC. Cc: Miguel Ojeda Sandonis Cc: Greg Kroah-Hartman Signed-off-by: Wilson Lee Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 205126 Signed-off-by: Brad Mouring [cvadrevu: Fixed trivial conflicts due to newer module.] [cvadrevu: Kconfig: Changed --help-- to help] [cvadrevu: Updated sh1107_probe args and removed sh1107_remove to build on 6.18 kernel] Signed-off-by: Chaitanya Vadrevu --- drivers/auxdisplay/Kconfig | 13 ++ drivers/auxdisplay/Makefile | 1 + drivers/auxdisplay/sh1107.c | 309 ++++++++++++++++++++++++++++++++++++ drivers/auxdisplay/sh1107.h | 78 +++++++++ 4 files changed, 401 insertions(+) create mode 100644 drivers/auxdisplay/sh1107.c create mode 100644 drivers/auxdisplay/sh1107.h diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index bedc6133f970a..7d7deda52488c 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -422,6 +422,19 @@ config KS0108_DELAY If you compile this as a module, you can still override this value using the module parameters. +config SH1107 + tristate "SH1107 LCD Controller" + depends on I2C + help + If you have a LCD controlled by one or more sh1107 + controller, say Y. You will need also another more specific + driver for your LCD. + + To compile this as a module, choose M here: + the module will be called sh1107. + + If unsure, say N. + config CFAG12864B tristate "CFAG12864B LCD" depends on X86 diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile index f5c13ed1cd4f5..c75b396bb42b9 100644 --- a/drivers/auxdisplay/Makefile +++ b/drivers/auxdisplay/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_LINEDISP) += line-display.o obj-$(CONFIG_MAX6959) += max6959.o obj-$(CONFIG_PARPORT_PANEL) += panel.o obj-$(CONFIG_SEG_LED_GPIO) += seg-led-gpio.o +obj-$(CONFIG_SH1107) += sh1107.o diff --git a/drivers/auxdisplay/sh1107.c b/drivers/auxdisplay/sh1107.c new file mode 100644 index 0000000000000..352ef6f0e491e --- /dev/null +++ b/drivers/auxdisplay/sh1107.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2017 National Instruments Corp. + * + * Based on ks0108 driver (v0.1.0) + * Copyright (C) 2006 by Miguel Ojeda Sandonis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sh1107.h" + +#define SH1107_CMDBYTE 0x00 +#define SH1107_DATABYTE 0x40 + +#define SH1107_SET_DC_HI 0xAD +#define SH1107_SET_DC_LO 0x80 +#define SH1107_SET_DC_MASK 0x0F +#define SH1107_SET_VCOM 0xDB +#define SH1107_SET_PHASE_PERIOD 0xD9 +#define SH1107_SET_ENTIRE_DISP 0xA4 +#define SH1107_SET_DISP 0xAE +#define SH1107_SET_INVERT_DISP 0xA6 +#define SH1107_SET_DISP_CONTRAST 0x81 +#define SH1107_SET_SCANDIR 0xC0 +#define SH1107_SET_DISP_FREQ 0xD5 +#define SH1107_SET_MULTIPLEX_RATIO 0xA8 +#define SH1107_SET_MULTIPLEX_RATIO_MASK 0x7F +#define SH1107_SET_ADDR_MODE 0x20 +#define SH1107_SET_REMAP_SEG 0xA0 +#define SH1107_SET_STARTLINE 0xDC +#define SH1107_SET_STARTLINE_MASK 0x7F +#define SH1107_SET_COL_ADDR_LO 0x00 +#define SH1107_SET_COL_ADDR_HI 0x10 +#define SH1107_SET_COL_ADDR_LO_MASK 0x0F +#define SH1107_SET_COL_ADDR_HI_MASK 0x70 +#define SH1107_SET_PAGE 0xB0 +#define SH1107_SET_PAGE_MASK 0x0F +#define SH1107_SET_OFFSET 0xD3 +#define SH1107_SET_OFFSET_MASK 0x7F + +struct sh1107 { + struct device *dev; /* sh1107 device */ + struct i2c_client *client; +}; + +int sh1107_writedata(struct sh1107 *sh, unsigned char byte) +{ + unsigned char tdata[2] = { SH1107_DATABYTE, byte }; + int ret; + + /* write control byte, then data */ + struct i2c_msg msg = { + .addr = sh->client->addr, + .len = 2, + .buf = tdata, + }; + + ret = i2c_transfer(sh->client->adapter, &msg, 1); + + return ret == 1 ? 0 : ret; +} +EXPORT_SYMBOL_GPL(sh1107_writedata); + +int sh1107_writecontrol(struct sh1107 *sh, unsigned char byte) +{ + unsigned char tdata[2] = { SH1107_CMDBYTE, byte }; + int ret; + + /* write control byte, then data */ + struct i2c_msg msg = { + .addr = sh->client->addr, + .len = 2, + .buf = tdata, + }; + + ret = i2c_transfer(sh->client->adapter, &msg, 1); + + return ret == 1 ? 0 : ret; +} +EXPORT_SYMBOL_GPL(sh1107_writecontrol); + +int sh1107_dccontrol(struct sh1107 *sh, unsigned char value) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_DC_HI); + if (ret) + return ret; + + return sh1107_writecontrol(sh, SH1107_SET_DC_LO | + (value & SH1107_SET_DC_MASK)); +} +EXPORT_SYMBOL_GPL(sh1107_dccontrol); + +int sh1107_vcomcontrol(struct sh1107 *sh, unsigned char vcom) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_VCOM); + if (ret) + return ret; + + return sh1107_writecontrol(sh, vcom); +} +EXPORT_SYMBOL_GPL(sh1107_vcomcontrol); + +int sh1107_phaseperiod(struct sh1107 *sh, unsigned char period) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_PHASE_PERIOD); + if (ret) + return ret; + + return sh1107_writecontrol(sh, period); +} +EXPORT_SYMBOL_GPL(sh1107_phaseperiod); + +int sh1107_entiredisplaystate(struct sh1107 *sh, unsigned char state) +{ + return sh1107_writecontrol(sh, SH1107_SET_ENTIRE_DISP | + (state ? BIT(0) : 0)); +} +EXPORT_SYMBOL_GPL(sh1107_entiredisplaystate); + +int sh1107_displaystate(struct sh1107 *sh, unsigned char state) +{ + return sh1107_writecontrol(sh, SH1107_SET_DISP | + (state ? BIT(0) : 0)); +} +EXPORT_SYMBOL_GPL(sh1107_displaystate); + +int sh1107_displayinvert(struct sh1107 *sh, unsigned char invert) +{ + return sh1107_writecontrol(sh, SH1107_SET_INVERT_DISP | + (invert ? BIT(0) : 0)); +} +EXPORT_SYMBOL_GPL(sh1107_displayinvert); + +int sh1107_displaycontrast(struct sh1107 *sh, unsigned char contrast) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_DISP_CONTRAST); + if (ret) + return ret; + + return sh1107_writecontrol(sh, contrast); +} +EXPORT_SYMBOL_GPL(sh1107_displaycontrast); + +int sh1107_scandir(struct sh1107 *sh, unsigned char direction) +{ + return sh1107_writecontrol(sh, SH1107_SET_SCANDIR | + (direction ? BIT(3) : 0)); +} +EXPORT_SYMBOL_GPL(sh1107_scandir); + +int sh1107_displayfreq(struct sh1107 *sh, unsigned char frequency) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_DISP_FREQ); + if (ret) + return ret; + + return sh1107_writecontrol(sh, frequency); +} +EXPORT_SYMBOL_GPL(sh1107_displayfreq); + +int sh1107_multiplexratio(struct sh1107 *sh, unsigned char ratio) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_MULTIPLEX_RATIO); + if (ret) + return ret; + + return sh1107_writecontrol(sh, ratio & + SH1107_SET_MULTIPLEX_RATIO_MASK); +} +EXPORT_SYMBOL_GPL(sh1107_multiplexratio); + +int sh1107_addressingmode(struct sh1107 *sh, unsigned char memmode) +{ + return sh1107_writecontrol(sh, SH1107_SET_ADDR_MODE | + (memmode ? BIT(0) : 0)); +} +EXPORT_SYMBOL_GPL(sh1107_addressingmode); + +int sh1107_segremap(struct sh1107 *sh, unsigned char uprotation) +{ + return sh1107_writecontrol(sh, SH1107_SET_REMAP_SEG | + (uprotation ? BIT(0) : 0)); +} +EXPORT_SYMBOL_GPL(sh1107_segremap); + +int sh1107_startline(struct sh1107 *sh, unsigned char startline) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_STARTLINE); + if (ret) + return ret; + + return sh1107_writecontrol(sh, startline & SH1107_SET_STARTLINE_MASK); +} +EXPORT_SYMBOL_GPL(sh1107_startline); + +int sh1107_address(struct sh1107 *sh, unsigned char address) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_COL_ADDR_LO | + (address & SH1107_SET_COL_ADDR_LO_MASK)); + if (ret) + return ret; + + return sh1107_writecontrol(sh, SH1107_SET_COL_ADDR_HI | + ((address & SH1107_SET_COL_ADDR_HI_MASK) + >> 4)); +} +EXPORT_SYMBOL_GPL(sh1107_address); + +int sh1107_page(struct sh1107 *sh, unsigned char page) +{ + return sh1107_writecontrol(sh, SH1107_SET_PAGE | + (page & SH1107_SET_PAGE_MASK)); +} +EXPORT_SYMBOL_GPL(sh1107_page); + +int sh1107_offset(struct sh1107 *sh, unsigned char offset) +{ + int ret; + + ret = sh1107_writecontrol(sh, SH1107_SET_OFFSET); + if (ret) + return ret; + + return sh1107_writecontrol(sh, offset & SH1107_SET_OFFSET_MASK); +} +EXPORT_SYMBOL_GPL(sh1107_offset); + +static int sh1107_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct sh1107 *sh; + + sh = devm_kzalloc(dev, sizeof(*sh), GFP_KERNEL); + if (!sh) + return -ENOMEM; + + sh->dev = dev; + sh->client = client; + + /* Test write data into OLED module (RAM) */ + if (sh1107_writedata(sh, 0)) + return -ENODEV; + + dev_set_drvdata(dev, sh); + dev_info(dev, "%s OLED module found.\n", client->name); + + return devm_of_platform_populate(dev); +} + +static const struct of_device_id sh1107_dt_ids[] = { + { .compatible = "sinowealth,sh1107" }, + { }, +}; +MODULE_DEVICE_TABLE(of, sh1107_dt_ids); + +static const struct i2c_device_id sh1107_ids[] = { + { "sh1107", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, sh1107_ids); + +static struct i2c_driver sh1107_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = sh1107_dt_ids, + }, + .probe = sh1107_probe, + .id_table = sh1107_ids, +}; +module_i2c_driver(sh1107_driver); + +MODULE_DESCRIPTION("Driver for SH1107 LCD Driver"); +MODULE_AUTHOR("Wilson Lee "); +MODULE_LICENSE("GPL"); diff --git a/drivers/auxdisplay/sh1107.h b/drivers/auxdisplay/sh1107.h new file mode 100644 index 0000000000000..0e277a4923b76 --- /dev/null +++ b/drivers/auxdisplay/sh1107.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 National Instruments Corp. + * + * Based on ks0108 driver (v0.1.0) + * Copyright (C) 2006 by Miguel Ojeda Sandonis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _SH1107_H_ +#define _SH1107_H_ + +/* sh1107 device private data */ +struct sh1107; + +/* Write a byte to the data port */ +int sh1107_writedata(struct sh1107 *sh, unsigned char byte); + +/* Write a byte to the control port */ +int sh1107_writecontrol(struct sh1107 *sh, unsigned char byte); + +/* Set internal DC-DC control register (0..15) */ +int sh1107_dccontrol(struct sh1107 *sh, unsigned char value); + +/* Set controller VCOM level (0..255) */ +int sh1107_vcomcontrol(struct sh1107 *sh, unsigned char vcom); + +/* Set controller pre/dis-charge period (0..255) */ +int sh1107_phaseperiod(struct sh1107 *sh, unsigned char period); + +/* Set the forcibly turn entire display state (0..1) */ +int sh1107_entiredisplaystate(struct sh1107 *sh, unsigned char state); + +/* Set the controller current display state (0..1) */ +int sh1107_displaystate(struct sh1107 *sh, unsigned char state); + +/* Set invert display (0..1) */ +int sh1107_displayinvert(struct sh1107 *sh, unsigned char invert); + +/* Set display contrast level (0..255) */ +int sh1107_displaycontrast(struct sh1107 *sh, unsigned char contrast); + +/* Set the controller common output scan direction (0..1) */ +int sh1107_scandir(struct sh1107 *sh, unsigned char direction); + +/* Set the controller internal display clocks. (0..255) */ +int sh1107_displayfreq(struct sh1107 *sh, unsigned char frequency); + +/* Set the controller multiplex mode to any multiplex ratio (0..127) */ +int sh1107_multiplexratio(struct sh1107 *sh, unsigned char ratio); + +/* Set the controller memory addressing mode (0..1) */ +int sh1107_addressingmode(struct sh1107 *sh, unsigned char memmode); + +/* Set the controller segment remap (0..1) */ +int sh1107_segremap(struct sh1107 *sh, unsigned char uprotation); + +/* Set the controller current startline (0..127) */ +int sh1107_startline(struct sh1107 *sh, unsigned char startline); + +/* Set the controller current address (0..127) */ +int sh1107_address(struct sh1107 *sh, unsigned char address); + +/* Set the controller current page (0..15) */ +int sh1107_page(struct sh1107 *sh, unsigned char page); + +/* Set the controller offset (0..127) */ +int sh1107_offset(struct sh1107 *sh, unsigned char offset); + +#endif /* _SH1107_H_ */ From 1f311e7706be9c76411f72dd15183f4e110404d9 Mon Sep 17 00:00:00 2001 From: Wilson Lee Date: Tue, 19 Dec 2017 20:22:07 -0800 Subject: [PATCH 63/97] doc: auxdisplay: sh1107: Documentation of Sino Wealth SH1107 driver This commit is to add documentation for Sino Wealth SH1107 driver. This commit will provide the required parameters and example of enabling SH1107 in devicetree. Signed-off-by: Wilson Lee Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 205126 Signed-off-by: Brad Mouring --- .../devicetree/bindings/auxdisplay/sh1107.txt | 12 ++++++++++++ MAINTAINERS | 7 +++++++ 2 files changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/sh1107.txt diff --git a/Documentation/devicetree/bindings/auxdisplay/sh1107.txt b/Documentation/devicetree/bindings/auxdisplay/sh1107.txt new file mode 100644 index 0000000000000..fa288b0c67058 --- /dev/null +++ b/Documentation/devicetree/bindings/auxdisplay/sh1107.txt @@ -0,0 +1,12 @@ +Binding for Sinowealth OLED driver + +Required properties: + - compatible: Compatibility string. Must be "sinowealth,sh1107". + - reg : i2c address of Truly OLED module (0x3C or 0x3D) + +Example: + + oleddriver@3C { + compatible = "sinowealth,sh1107"; + reg = <0x3C>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 554e881b05bea..e8a39b7879eda 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23452,6 +23452,13 @@ S: Orphan F: drivers/media/platform/renesas/sh_vou.c F: include/media/drv-intf/sh_vou.h +SH1107 OLED CONTROLLER DRIVER +M: Wilson Lee +S: Maintained +F: Documentation/devicetree/bindings/auxdisplay/sh1107.txt +F: drivers/auxdisplay/sh1107.c +F: drivers/auxdisplay/sh1107.h + SI2157 MEDIA DRIVER L: linux-media@vger.kernel.org S: Orphan From 848a3be427ba95c3963f741917bb7307ae0bee74 Mon Sep 17 00:00:00 2001 From: Wilson Lee Date: Tue, 19 Dec 2017 20:28:21 -0800 Subject: [PATCH 64/97] auxdisplay: oel9m1027: Truly OEL9M1027 OLED module driver Truly OEL9M1027 OLED display module are not supported at this moment. This commit is to add driver to support Truly OEL9M1027 OLED module. This driver will interact with Sino Wealth SH1107 driver and provide a framebuffer to userspace (/dev/fbX) for user application to interact with OLED display. Cc: Miguel Ojeda Sandonis Cc: Greg Kroah-Hartman Signed-off-by: Wilson Lee Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 205126 Signed-off-by: Brad Mouring [cvadrevu: Fixed trivial conflicts due to newer module] [cvadrevu: Kconfig: Changed --help-- to help] [cvadrevu: Kconfig: Updated to use FB_SYSMEM_FOPS due to 27ad64eac10f ("fbdev: Rename FB_SYS_FOPS token to FB_SYSMEM_FOPS")] [cvadrevu: Update oel9m1027_remove args for 6.18 kernel] [cvadrevu: Remove FBINFO_FLAG_DEFAULT as per 8a4675ebbd30 ("fbdev: Remove FBINFO_FLAG_DEFAULT from framebuffer_alloc()'ed structs")] Signed-off-by: Chaitanya Vadrevu oel9m1027_core: Fix build. Not sure if changes are correct. TODO --- drivers/auxdisplay/Kconfig | 24 +++ drivers/auxdisplay/Makefile | 2 + drivers/auxdisplay/oel9m1027.h | 83 +++++++ drivers/auxdisplay/oel9m1027_core.c | 323 ++++++++++++++++++++++++++++ drivers/auxdisplay/oel9m1027_fb.c | 169 +++++++++++++++ 5 files changed, 601 insertions(+) create mode 100644 drivers/auxdisplay/oel9m1027.h create mode 100644 drivers/auxdisplay/oel9m1027_core.c create mode 100644 drivers/auxdisplay/oel9m1027_fb.c diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 7d7deda52488c..dc372cd227ad4 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -513,6 +513,30 @@ config HT16K33 Say yes here to add support for Holtek HT16K33, RAM mapping 16*8 LED controller driver with keyscan. +config OEL9M1027 + tristate "OEL9M1027 LCD" + depends on FB + depends on SH1107 + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYSMEM_FOPS + default n + help + If you have a Truly 64x128 2-color LCD, OEL9M1027 Series, + say Y. You also need the sh1107 LCD Controller driver. + + Depends on the framebuffer support. + + The LCD framebuffer driver can be attached to a console. + It will work fine. However, you can't attach it to the fbdev driver + of the xorg server. + + To compile this as a module, choose M here: + the modules will be called oel9m1027 and oel9m1027fb. + + If unsure, say N. + config MAX6959 tristate "Maxim MAX6958/6959 7-segment LED controller" depends on I2C diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile index c75b396bb42b9..c3e12065a2176 100644 --- a/drivers/auxdisplay/Makefile +++ b/drivers/auxdisplay/Makefile @@ -17,3 +17,5 @@ obj-$(CONFIG_MAX6959) += max6959.o obj-$(CONFIG_PARPORT_PANEL) += panel.o obj-$(CONFIG_SEG_LED_GPIO) += seg-led-gpio.o obj-$(CONFIG_SH1107) += sh1107.o +obj-$(CONFIG_OEL9M1027) += oel9m1027.o +oel9m1027-y += oel9m1027_core.o oel9m1027_fb.o diff --git a/drivers/auxdisplay/oel9m1027.h b/drivers/auxdisplay/oel9m1027.h new file mode 100644 index 0000000000000..ba8fa8caacb0e --- /dev/null +++ b/drivers/auxdisplay/oel9m1027.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 National Instruments Corp. + * + * Based on cfag12864b driver (v0.1.0) + * Copyright (C) 2006 by Miguel Ojeda Sandonis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _OEL9M1027_H_ +#define _OEL9M1027_H_ + +#define OEL9M1027_WIDTH (64) +#define OEL9M1027_HEIGHT (128) + +#define OEL9M1027_PAGES (16) +#define OEL9M1027_ADDRESSES (64) +#define OEL9M1027_ADDRESSES_OFFSET (32) +#define OEL9M1027_SIZE ((OEL9M1027_PAGES) * \ + (OEL9M1027_ADDRESSES)) + +#define OEL9M1027_DISPLAYON 1 +#define OEL9M1027_DISPLAYOFF 0 +#define OEL9M1027_DISPNORMAL 0 +#define OEL9M1027_DISPINVERT 1 + +/* + * Default parameter that recommended by Truly manufacturer. + * + * Don't change if you unsure. This value is sufficient by + * default. + */ +#define OEL9M1027_DEF_MULTIRATIO 0x3F +#define OEL9M1027_DEF_DISPFREQ 0xF1 +#define OEL9M1027_DEF_SCANDIR 0x00 +#define OEL9M1027_DEF_DISPOFFSET 0x60 +#define OEL9M1027_DEF_STARTLINE 0x20 +#define OEL9M1027_DEF_ADDRMODE 0x00 +#define OEL9M1027_DEF_CONTRAST 0xFF +#define OEL9M1027_DEF_SEGREMAP 0x00 +#define OEL9M1027_DEF_DCCONTROL 0x0A +#define OEL9M1027_DEF_PHASEPERIOD 0x22 +#define OEL9M1027_DEF_VCOMCONTROL 0x35 + +/* + * OEL9M1027 device private data + */ +struct oel9m1027 { + struct device *dev; /* oel9m1027 device */ + struct sh1107 *sh; /* sh1107 privdata */ + + struct fb_info *fb; /* oel9m1027 framebuffer info */ + unsigned char *framebuffer; + + unsigned char contrast; /* oled display contrast */ + + struct delayed_work dwork; /* oled update worker */ + struct mutex lock; +}; + +/* + * Register OEL9M1027 framebuffer device + * + * Returns 0 if registered successfully, + * or != 0 if failed to register. + */ +int oel9m1027fb_init(struct oel9m1027 *oled); + +/* + * Remove OEL9M1027 framebuffer device + */ +void oel9m1027fb_exit(struct oel9m1027 *oled); + +#endif /* _OEL9M1027_H_ */ + diff --git a/drivers/auxdisplay/oel9m1027_core.c b/drivers/auxdisplay/oel9m1027_core.c new file mode 100644 index 0000000000000..4f30c320a89e9 --- /dev/null +++ b/drivers/auxdisplay/oel9m1027_core.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2017 National Instruments Corp. + * + * Based on cfag12864b driver (v0.1.0) + * Copyright (C) 2006 by Miguel Ojeda Sandonis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sh1107.h" +#include "oel9m1027.h" + +/* + * OEL9M1027 Internal Commands + */ + +static int oel9m1027_clear(struct oel9m1027 *oled) +{ + unsigned char i, j; + int ret; + + mutex_lock(&oled->lock); + + for (i = 0; i < OEL9M1027_PAGES; i++) { + ret = sh1107_page(oled->sh, i); + if (ret) + goto fail; + + ret = sh1107_address(oled->sh, OEL9M1027_ADDRESSES_OFFSET); + if (ret) + goto fail; + + for (j = 0; j < OEL9M1027_ADDRESSES; j++) { + ret = sh1107_writedata(oled->sh, 0); + if (ret) + goto fail; + } + } + +fail: + mutex_unlock(&oled->lock); + return ret; +} + +static int oel9m1027_off(struct oel9m1027 *oled) +{ + int ret; + + mutex_lock(&oled->lock); + ret = sh1107_displaystate(oled->sh, OEL9M1027_DISPLAYOFF); + mutex_unlock(&oled->lock); + + return ret; +} + +static int oel9m1027_on(struct oel9m1027 *oled) +{ + int ret; + + mutex_lock(&oled->lock); + + ret = sh1107_multiplexratio(oled->sh, OEL9M1027_DEF_MULTIRATIO); + if (ret) + goto fail; + + ret = sh1107_displayfreq(oled->sh, OEL9M1027_DEF_DISPFREQ); + if (ret) + goto fail; + + ret = sh1107_scandir(oled->sh, OEL9M1027_DEF_SCANDIR); + if (ret) + goto fail; + + ret = sh1107_offset(oled->sh, OEL9M1027_DEF_DISPOFFSET); + if (ret) + goto fail; + + ret = sh1107_startline(oled->sh, OEL9M1027_DEF_STARTLINE); + if (ret) + goto fail; + + ret = sh1107_addressingmode(oled->sh, OEL9M1027_DEF_ADDRMODE); + if (ret) + goto fail; + + ret = sh1107_displaycontrast(oled->sh, oled->contrast); + if (ret) + goto fail; + + ret = sh1107_segremap(oled->sh, OEL9M1027_DEF_SEGREMAP); + if (ret) + goto fail; + + ret = sh1107_entiredisplaystate(oled->sh, OEL9M1027_DISPLAYOFF); + if (ret) + goto fail; + + ret = sh1107_displayinvert(oled->sh, OEL9M1027_DISPNORMAL); + if (ret) + goto fail; + + ret = sh1107_dccontrol(oled->sh, OEL9M1027_DEF_DCCONTROL); + if (ret) + goto fail; + + ret = sh1107_phaseperiod(oled->sh, OEL9M1027_DEF_PHASEPERIOD); + if (ret) + goto fail; + + ret = sh1107_vcomcontrol(oled->sh, OEL9M1027_DEF_VCOMCONTROL); + if (ret) + goto fail; + + ret = sh1107_displaystate(oled->sh, OEL9M1027_DISPLAYON); + if (ret) + goto fail; + +fail: + mutex_unlock(&oled->lock); + return ret; +} + +static void oel9m1027_update(struct work_struct *work) +{ + struct oel9m1027 *oled = container_of(to_delayed_work(work), + struct oel9m1027, + dwork); + unsigned short page, addr, bit; + unsigned char c_buff; + unsigned int pos; + int ret; + + mutex_lock(&oled->lock); + + for (page = 0; page < OEL9M1027_PAGES; page++) { + ret = sh1107_page(oled->sh, page); + if (ret) + goto fail; + + ret = sh1107_address(oled->sh, + OEL9M1027_ADDRESSES_OFFSET); + if (ret) + goto fail; + + for (addr = 0; addr < OEL9M1027_ADDRESSES; addr++) { + for (c_buff = 0, bit = 0; bit < 8; bit++) { + pos = addr / 8 + (page * 8 + bit) * + OEL9M1027_WIDTH / 8; + + if (oled->framebuffer[pos] & BIT(addr % 8)) + c_buff |= BIT(bit); + } + + ret = sh1107_writedata(oled->sh, c_buff); + if (ret) + goto fail; + } + } + + mutex_unlock(&oled->lock); + return; + +fail: + mutex_unlock(&oled->lock); + + /* Error occur, retry after 100ms */ + dev_warn(oled->dev, "ERROR: OLED update fail.\n"); + queue_delayed_work(system_wq, &oled->dwork, HZ / 10); +} + +static ssize_t oel9m1027_contrast_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct oel9m1027 *oled = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", oled->contrast); +} + +static ssize_t oel9m1027_contrast_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct oel9m1027 *oled = dev_get_drvdata(dev); + int ret; + + ret = kstrtou8(buf, 10, &oled->contrast); + if (ret) + return -EINVAL; + + /* Restart for new contrast setting to take effect */ + ret = oel9m1027_off(oled); + if (ret) + return ret; + + ret = oel9m1027_on(oled); + + return ret ? ret : count; +} + +static DEVICE_ATTR(contrast, 0644, oel9m1027_contrast_show, + oel9m1027_contrast_store); + +static int oel9m1027_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct oel9m1027 *oled; + int ret; + + oled = devm_kzalloc(dev, sizeof(*oled), GFP_KERNEL); + if (!oled) { + ret = -ENOMEM; + goto none; + } + + platform_set_drvdata(pdev, oled); + oled->dev = dev; + oled->sh = dev_get_drvdata(dev->parent); + mutex_init(&oled->lock); + oled->contrast = OEL9M1027_DEF_CONTRAST; + + ret = device_create_file(dev, &dev_attr_contrast); + if (ret) { + dev_warn(dev, "ERROR: OLED sysfs create fail.\n"); + goto mutexcreated; + } + + ret = oel9m1027_off(oled); + if (ret) { + dev_warn(dev, "ERROR: OLED switch off fail.\n"); + goto mutexcreated; + } + + ret = oel9m1027_clear(oled); + if (ret) { + dev_warn(dev, "ERROR: OLED buffer clear fail.\n"); + goto mutexcreated; + } + + ret = oel9m1027_on(oled); + if (ret) { + dev_err(dev, "ERROR: OLED switch on fail.\n"); + goto mutexcreated; + } + + INIT_DELAYED_WORK(&oled->dwork, oel9m1027_update); + + ret = oel9m1027fb_init(oled); + if (ret) { + dev_err(dev, "ERROR: can't initialize framebuffer\n"); + goto oledturnedon; + } + + return 0; + +oledturnedon: + oel9m1027_off(oled); + +mutexcreated: + mutex_destroy(&oled->lock); + +none: + return ret; +} + +static void oel9m1027_remove(struct platform_device *pdev) +{ + struct oel9m1027 *oled = platform_get_drvdata(pdev); + + oel9m1027fb_exit(oled); + flush_delayed_work(&oled->dwork); + cancel_delayed_work_sync(&oled->dwork); + oel9m1027_off(oled); + mutex_destroy(&oled->lock); +} + +static const struct of_device_id oel9m1027_of_match[] = { + { .compatible = "truly,oel9m1027" }, + { }, +}; +MODULE_DEVICE_TABLE(of, oel9m1027_of_match); + +static struct platform_driver oel9m1027_driver = { + .probe = oel9m1027_probe, + .remove = oel9m1027_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = oel9m1027_of_match, + }, +}; + +module_platform_driver(oel9m1027_driver); + +MODULE_DESCRIPTION("OEL9M1027 OLED driver"); +MODULE_AUTHOR("Wilson Lee "); +MODULE_LICENSE("GPL"); diff --git a/drivers/auxdisplay/oel9m1027_fb.c b/drivers/auxdisplay/oel9m1027_fb.c new file mode 100644 index 0000000000000..76f7bd5922e53 --- /dev/null +++ b/drivers/auxdisplay/oel9m1027_fb.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2017 National Instruments Corp. + * + * Based on cfag12864b driver (v0.1.0) + * Copyright (C) 2006 by Miguel Ojeda Sandonis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oel9m1027.h" + +static ssize_t oel9m1027fb_write(struct fb_info *fb, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct oel9m1027 *oled = dev_get_drvdata(fb->device); + ssize_t ret; + + ret = fb_sys_write(fb, buf, count, ppos); + if (ret < 0) + return ret; + + queue_delayed_work(system_wq, &oled->dwork, 0); + return ret; +} + +static void oel9m1027fb_fillrect(struct fb_info *fb, + const struct fb_fillrect *rect) +{ + struct oel9m1027 *oled = dev_get_drvdata(fb->device); + + sys_fillrect(fb, rect); + queue_delayed_work(system_wq, &oled->dwork, 0); +} + +static void oel9m1027fb_copyarea(struct fb_info *fb, + const struct fb_copyarea *area) +{ + struct oel9m1027 *oled = dev_get_drvdata(fb->device); + + sys_copyarea(fb, area); + queue_delayed_work(system_wq, &oled->dwork, 0); +} + +static void oel9m1027fb_imageblit(struct fb_info *fb, + const struct fb_image *image) +{ + struct oel9m1027 *oled = dev_get_drvdata(fb->device); + + sys_imageblit(fb, image); + queue_delayed_work(system_wq, &oled->dwork, 0); +} + +static const struct fb_fix_screeninfo oel9m1027fb_fix = { + .id = "oel9m1027", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_MONO10, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .line_length = OEL9M1027_WIDTH / 8, + .accel = FB_ACCEL_NONE, +}; + +static const struct fb_var_screeninfo oel9m1027fb_var = { + .xres = OEL9M1027_WIDTH, + .yres = OEL9M1027_HEIGHT, + .xres_virtual = OEL9M1027_WIDTH, + .yres_virtual = OEL9M1027_HEIGHT, + .bits_per_pixel = 1, + .red = { 0, 1, 0 }, + .green = { 0, 1, 0 }, + .blue = { 0, 1, 0 }, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_ops oel9m1027fb_ops = { + .owner = THIS_MODULE, + .fb_read = fb_sys_read, + .fb_write = oel9m1027fb_write, + .fb_fillrect = oel9m1027fb_fillrect, + .fb_copyarea = oel9m1027fb_copyarea, + .fb_imageblit = oel9m1027fb_imageblit, +}; + +int oel9m1027fb_init(struct oel9m1027 *oled) +{ + int ret; + struct fb_info *fb = framebuffer_alloc(0, oled->dev); + + if (!fb) { + ret = -EINVAL; + goto none; + } + + oled->framebuffer = vzalloc(sizeof(unsigned char) * + OEL9M1027_SIZE); + if (!oled->framebuffer) { + ret = -ENOMEM; + goto fbinfoalloced; + } + + fb->screen_base = (char __iomem *)oled->framebuffer; + fb->screen_size = OEL9M1027_SIZE; + fb->fbops = &oel9m1027fb_ops; + fb->fix = oel9m1027fb_fix; + fb->fix.smem_start = page_to_phys(vmalloc_to_page(oled->framebuffer)); + fb->fix.smem_len = sizeof(unsigned char) * OEL9M1027_SIZE; + fb->var = oel9m1027fb_var; + fb->pseudo_palette = NULL; + fb->par = NULL; + oled->fb = fb; + + if (register_framebuffer(fb) < 0) { + ret = -EINVAL; + goto fballoced; + } + + fb_info(fb, "%s framebuffer device\n", fb->fix.id); + + return 0; + +fballoced: + vfree(oled->framebuffer); + +fbinfoalloced: + framebuffer_release(fb); + +none: + return ret; +} + +void oel9m1027fb_exit(struct oel9m1027 *oled) +{ + unregister_framebuffer(oled->fb); + vfree(oled->framebuffer); + framebuffer_release(oled->fb); +} + +MODULE_DESCRIPTION("OEL9M1027 OLED frame buffer driver"); +MODULE_AUTHOR("Wilson Lee "); +MODULE_LICENSE("GPL"); From cf2fa1c687a83f2a17e80c8c70ced87bbba9a917 Mon Sep 17 00:00:00 2001 From: Wilson Lee Date: Tue, 19 Dec 2017 20:34:50 -0800 Subject: [PATCH 65/97] doc: auxdisplay: oel9m1027: Documentation of Truly OEL9M1027 driver This commit is to add document for describing Truly OEL9M1027 driver. This commit will specific the required parameter and example for enabling this driver in devicetree. Signed-off-by: Wilson Lee Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 205126 Signed-off-by: Brad Mouring [cvadrevu: Fixed trivial conflicts due to newer module] Signed-off-by: Chaitanya Vadrevu --- .../devicetree/bindings/auxdisplay/oel9m1027.txt | 15 +++++++++++++++ MAINTAINERS | 8 ++++++++ 2 files changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/auxdisplay/oel9m1027.txt diff --git a/Documentation/devicetree/bindings/auxdisplay/oel9m1027.txt b/Documentation/devicetree/bindings/auxdisplay/oel9m1027.txt new file mode 100644 index 0000000000000..ee0c1a59cadfc --- /dev/null +++ b/Documentation/devicetree/bindings/auxdisplay/oel9m1027.txt @@ -0,0 +1,15 @@ +Binding for OEL9M1027 OLED display module manufactured by Truly + +Required properties: + - compatible : Compatibility string. Must be "truly,oel9m1027". + +Example: + + oleddriver@3C { + compatible = "sinowealth,sh1107"; + reg = <0x3C>; + + oledmodule { + compatible = "truly,oel9m1027"; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e8a39b7879eda..6161a4507e4ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18763,6 +18763,14 @@ F: drivers/misc/ocxl/ F: include/misc/ocxl* F: include/uapi/misc/ocxl.h +OEL9M1027 TRULY OLED MODULE DRIVER +M: Wilson Lee +S: Maintained +F: Documentation/devicetree/bindings/auxdisplay/oel9m1027.txt +F: drivers/auxdisplay/oel9m1027.c +F: drivers/auxdisplay/oel9m1027fb.c +F: drivers/auxdisplay/oel9m1027.h + OMAP AUDIO SUPPORT M: Peter Ujfalusi M: Jarkko Nikula From 1566c31e44e0222fafa3385487e875ea2b8e484a Mon Sep 17 00:00:00 2001 From: Wilson Lee Date: Mon, 14 Aug 2017 20:22:29 -0700 Subject: [PATCH 66/97] nizynqcpld: Add NI ELVIS III/III+ CPLD support NI ELVIS III was introduced a WiFi LED for display WiFi status. Hence, it required new driver support for NI ELVIS III. Without the new driver support for NI ELVIS III, the CPLD WiFi LED will fail to function. Signed-off-by: Chen Yee Chew Signed-off-by: Wilson Lee Signed-off-by: Brad Mouring Acked-by: Joe Hershberger Acked-by: Chen Yee chew Natinst-ReviewBoard-ID: 206904 --- drivers/misc/nizynqcpld.c | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 5627313f5bf0e..d8734a00f0331 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -76,6 +76,8 @@ #define MYRIO_WIFISWCTRL_ENRELIRQ 0x04 #define MYRIO_WIFISWCTRL_RELIRQ 0x40 +#define ELVISIII_WIFILEDCTRL_ADDR 0x0A + struct nizynqcpld_led_desc { const char *of_node_name; u8 addr; @@ -1215,6 +1217,37 @@ static struct nizynqcpld_led_desc sol_leds[] = { }, }; +static struct nizynqcpld_led_desc elvisiii_leds[] = { + { + .of_node_name = "status-0", + .addr = DOSX_LED, + .bit = 1 << 2, + .pattern_lo_addr = DOSX_STATUSLEDSHIFTBYTE0, + /* write byte 1 first */ + .pattern_hi_addr = DOSX_STATUSLEDSHIFTBYTE1, + }, + { + .of_node_name = "eth0-0", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 1, + }, + { + .of_node_name = "eth0-1", + .addr = DOSX_ETHERNETLED, + .bit = 1 << 0, + }, + { + .of_node_name = "wifi-0", + .addr = ELVISIII_WIFILEDCTRL_ADDR, + .bit = 1 << 1, + }, + { + .of_node_name = "wifi-1", + .addr = ELVISIII_WIFILEDCTRL_ADDR, + .bit = 1 << 0, + }, +}; + static struct nizynqcpld_watchdog_desc dosxv4_watchdog_desc = { .watchdog_period_ns = 24000, }; @@ -1333,6 +1366,20 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .switch_addr = PROTO_PROCESSORMODE, .watchdog_addr = DOSX_WATCHDOGCONTROL, }, + /* ELVIS III CPLD */ + { + .attrs = dosequis6_attrs, + .supported_version = 1, + .supported_product = 6, + .watchdog_desc = &dosxv5_watchdog_desc, + .led_descs = elvisiii_leds, + .num_led_descs = ARRAY_SIZE(elvisiii_leds), + .reboot_addr = DOSX_PROCESSORRESET, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = PROTO_PROCESSORMODE, + .watchdog_addr = DOSX_WATCHDOGCONTROL, + }, }; static void wifi_sw_work_func(struct work_struct *work) From aa06138b70dca299f896cbf77fe0adeb5e45c04e Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 13 Feb 2014 08:12:00 -0600 Subject: [PATCH 67/97] driver core: add device_poll interface Add the device_poll interface to the driver core. This is a generic interface that any struct device can take advantage of to dynamically switch between using interrupts and polling. Many drivers can be easily modified to take advantage of this feature if desired. This interface is most likely to be used along with the RT patch. It has only been used thus far on Ethernet interfaces. Even with the standard RT change to threaded interrupts for all devices, some RT applications can be sensitive to even the minimal hardware interrupt that still occurs with threaded interrupt handlers. The device_poll interface can be used to completely eliminate all hardware interrupts for a device and the associated jitter. This is a standalone feature that should be submitted for review and possible inclusion in mainline, or maybe in the RT patch. Signed-off-by: Jeff Westfahl Signed-off-by: Nathan Sullivan Reviewed-by: Jaeden Amero Natinst-ReviewBoard-ID: 108252 [gratian: update for ae7e81c077d6 ("sched/headers: Prepare for new header dependencies before moving code to ")] Signed-off-by: Gratian Crisan [cvadrevu: Fixed trivial conflicts due to newer modules] Signed-off-by: Chaitanya Vadrevu --- drivers/base/Kconfig | 3 + drivers/base/Makefile | 1 + drivers/base/poll.c | 334 ++++++++++++++++++++++++++++++++++++ include/linux/device_poll.h | 111 ++++++++++++ 4 files changed, 449 insertions(+) create mode 100644 drivers/base/poll.c create mode 100644 include/linux/device_poll.h diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 1786d87b29e22..095e9b8d2e6fd 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -249,4 +249,7 @@ config FW_DEVLINK_SYNC_STATE_TIMEOUT command line option on every system/board your kernel is expected to work on. +config DEVICE_POLL + bool + endmenu diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 8074a10183dcb..34c5ee80ab1df 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_GENERIC_MSI_IRQ) += platform-msi.o obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o obj-$(CONFIG_ACPI) += physical_location.o +obj-$(CONFIG_DEVICE_POLL) += poll.o obj-y += test/ diff --git a/drivers/base/poll.c b/drivers/base/poll.c new file mode 100644 index 0000000000000..7e1fc58082a85 --- /dev/null +++ b/drivers/base/poll.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2014 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* sysfs attributes */ + +#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) + +/* get sysfs attributes */ + +ssize_t device_poll_get_interval(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + struct device_poll *device_poll = ea->var; + + return sprintf(buf, "%d\n", device_poll->interval); +} + +static ssize_t device_poll_get_policy(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + struct device_poll *device_poll = ea->var; + + switch (device_poll->policy) { + case SCHED_NORMAL: + return sprintf(buf, "SCHED_NORMAL (SCHED_OTHER)\n"); + case SCHED_FIFO: + return sprintf(buf, "SCHED_FIFO\n"); + case SCHED_RR: + return sprintf(buf, "SCHED_RR\n"); + case SCHED_BATCH: + return sprintf(buf, "SCHED_BATCH\n"); + case SCHED_IDLE: + return sprintf(buf, "SCHED_IDLE\n"); + default: + return sprintf(buf, "unknown\n"); + } +} + +static ssize_t device_poll_get_priority(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + struct device_poll *device_poll = ea->var; + + return sprintf(buf, "%d\n", device_poll->priority); +} + +/* set sysfs attributes */ + +static ssize_t device_poll_set_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + struct device_poll *device_poll = ea->var; + int interval; + int ret = 0; + + if (device_poll->use_capability && !capable(device_poll->capability)) + return -EPERM; + + if (kstrtoint(buf, 0, &interval) < 0) + return -EINVAL; + + device_poll->ops->lock(device_poll); + if (device_poll->interval != interval) { + device_poll->interval = interval; + + ret = device_poll->ops->reinit(device_poll); + } + device_poll->ops->unlock(device_poll); + + if (ret) + return ret; + + return size; +} + +static ssize_t device_poll_set_policy(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + struct device_poll *device_poll = ea->var; + char policy_str[16] = { 0 }; + int policy; + struct sched_param param; + + if (device_poll->use_capability && !capable(device_poll->capability)) + return -EPERM; + + if (sscanf(buf, "%15s", policy_str) != 1) + return -EINVAL; + + if ((strcmp(policy_str, "SCHED_NORMAL") == 0 || + (strcmp(policy_str, "SCHED_OTHER") == 0))) + policy = SCHED_NORMAL; + else if (strcmp(policy_str, "SCHED_FIFO") == 0) + policy = SCHED_FIFO; + else if (strcmp(policy_str, "SCHED_RR") == 0) + policy = SCHED_RR; + else if (strcmp(policy_str, "SCHED_BATCH") == 0) + policy = SCHED_BATCH; + else if (strcmp(policy_str, "SCHED_IDLE") == 0) + policy = SCHED_IDLE; + else + return -EINVAL; + + device_poll->ops->lock(device_poll); + if (device_poll->policy != policy) { + device_poll->policy = policy; + + if (device_poll->task) { + param.sched_priority = device_poll->priority; + sched_setscheduler(device_poll->task, + device_poll->policy, + ¶m); + } + } + device_poll->ops->unlock(device_poll); + + return size; +} + +static ssize_t device_poll_set_priority(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + struct device_poll *device_poll = ea->var; + int priority; + struct sched_param param; + + if (device_poll->use_capability && !capable(device_poll->capability)) + return -EPERM; + + if (kstrtoint(buf, 0, &priority) < 0) + return -EINVAL; + + device_poll->ops->lock(device_poll); + if (device_poll->priority != priority) { + device_poll->priority = priority; + + if (device_poll->task) { + param.sched_priority = device_poll->priority; + sched_setscheduler(device_poll->task, + device_poll->policy, + ¶m); + } + } + device_poll->ops->unlock(device_poll); + + return size; +} + +/* sysfs attributes */ + +static const DEVICE_ATTR(interval, S_IWUSR | S_IRUGO, + device_poll_get_interval, device_poll_set_interval); + +static const DEVICE_ATTR(policy, S_IWUSR | S_IRUGO, + device_poll_get_policy, device_poll_set_policy); + +static const DEVICE_ATTR(priority, S_IWUSR | S_IRUGO, + device_poll_get_priority, device_poll_set_priority); + +/* device_poll internal functions */ + +static int device_poll_thread(void *info) +{ + struct device_poll *device_poll = info; + int polling_interval; + int polling_interval_us; + struct sched_param param; + + polling_interval = device_poll->interval; + + /* If we got changed to interrupt mode before the polling thread + * started. + */ + if (unlikely(polling_interval <= 0)) { + while (!kthread_should_stop()) + usleep_range(1000, 1100); + return -EINTR; + } + + polling_interval_us = polling_interval * 1000; + + param.sched_priority = device_poll->priority; + sched_setscheduler(current, device_poll->policy, ¶m); + + while (!kthread_should_stop()) { + /* Ensure changes to device_poll->enabled made on other CPUs + * are seen here. + */ + smp_rmb(); + if (device_poll->enabled) + device_poll->ops->interrupt(device_poll); + + if (polling_interval < 20) + usleep_range(polling_interval_us, polling_interval_us + + 100); + else + msleep(polling_interval); + } + + return 0; +} + +/* device_poll external functions */ + +int device_poll_init(struct device_poll *device_poll) +{ + int ret; + + if (!device_poll || !device_poll->device || !device_poll->ops) + return -EINVAL; + + if (!device_poll->ops->reinit || !device_poll->ops->lock || + !device_poll->ops->unlock || !device_poll->ops->interrupt) + return -EINVAL; + + if (device_poll->use_capability && !cap_valid(device_poll->capability)) + return -EINVAL; + + device_poll->task = NULL; + device_poll->enabled = 0; + + device_poll->interval_attr.attr = dev_attr_interval; + device_poll->policy_attr.attr = dev_attr_policy; + device_poll->priority_attr.attr = dev_attr_priority; + + device_poll->interval_attr.var = device_poll; + device_poll->policy_attr.var = device_poll; + device_poll->priority_attr.var = device_poll; + + if (device_poll->use_capability) { + device_poll->interval_attr.attr.attr.mode |= + (S_IWUSR | S_IRUGO); + device_poll->policy_attr.attr.attr.mode |= + (S_IWUSR | S_IRUGO); + device_poll->priority_attr.attr.attr.mode |= + (S_IWUSR | S_IRUGO); + } + + sysfs_attr_init(&device_poll->interval_attr.attr.attr); + sysfs_attr_init(&device_poll->policy_attr.attr.attr); + sysfs_attr_init(&device_poll->priority_attr.attr.attr); + + device_poll->attrs[0] = &device_poll->interval_attr.attr.attr; + device_poll->attrs[1] = &device_poll->policy_attr.attr.attr; + device_poll->attrs[2] = &device_poll->priority_attr.attr.attr; + device_poll->attrs[3] = NULL; + + device_poll->attr_group.name = "device_poll"; + device_poll->attr_group.attrs = device_poll->attrs; + + ret = sysfs_create_group(&device_poll->device->kobj, + &device_poll->attr_group); + if (ret) + device_poll_exit(device_poll); + + return ret; +} +EXPORT_SYMBOL(device_poll_init); + +void device_poll_exit(struct device_poll *device_poll) +{ + if (!device_poll || !device_poll->device) + return; + + sysfs_remove_group(&device_poll->device->kobj, + &device_poll->attr_group); +} +EXPORT_SYMBOL(device_poll_exit); + +int device_poll_request_irq(struct device_poll *device_poll) +{ + int err; + + if (!device_poll) + return -EINVAL; + + /* If interrupts are enabled. */ + if (device_poll->interval <= 0) + return -ERANGE; + + /* Start up the polling thread. */ + device_poll->task = kthread_run(device_poll_thread, + device_poll, "poll/%s", + dev_name(device_poll->device)); + if (IS_ERR(device_poll->task)) { + err = PTR_ERR(device_poll->task); + device_poll->task = NULL; + dev_err(device_poll->device, + "Unable to create polling thread: %d\n", err); + return err; + } + + return 0; +} +EXPORT_SYMBOL(device_poll_request_irq); + +void device_poll_free_irq(struct device_poll *device_poll) +{ + if (device_poll_is_active(device_poll)) { + kthread_stop(device_poll->task); + device_poll->task = NULL; + } +} +EXPORT_SYMBOL(device_poll_free_irq); diff --git a/include/linux/device_poll.h b/include/linux/device_poll.h new file mode 100644 index 0000000000000..6236f11d2c089 --- /dev/null +++ b/include/linux/device_poll.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_DEVICE_POLL_H_ +#define _LINUX_DEVICE_POLL_H_ + +#ifdef CONFIG_DEVICE_POLL + +#include + +struct device_poll; + +struct device_poll_ops { + /* Reinitialize, if the mode changes. */ + int (*reinit)(struct device_poll *device_poll); + + /* Lock and unlock, for consistency when changing settings. */ + void (*lock)(struct device_poll *device_poll); + void (*unlock)(struct device_poll *device_poll); + + /* Polled interrupt handler. */ + void (*interrupt)(struct device_poll *device_poll); +}; + +struct device_poll { + /* The following must be initialized by the driver before calling + * device_poll_init. + */ + + /* The device for which we're polling. */ + struct device *device; + + /* Device operations. */ + struct device_poll_ops *ops; + + /* A capability can be specified to allow non-root users to modify + * the sysfs attributes. + */ + bool use_capability; + int capability; + + /* Polling interval in milliseconds. A value of 0 or less means + * use interrupts. + */ + int interval; + + /* Polling task policy and priority, such as SCHED_FIFO 10. */ + int policy; + int priority; + + /* The following are internal struct members and should not be touched + * by drivers. + */ + + struct task_struct *task; + int enabled; + + struct dev_ext_attribute interval_attr; + struct dev_ext_attribute policy_attr; + struct dev_ext_attribute priority_attr; + struct attribute *attrs[4]; + struct attribute_group attr_group; +}; + +int device_poll_init(struct device_poll *device_poll); +void device_poll_exit(struct device_poll *device_poll); + +int device_poll_request_irq(struct device_poll *device_poll); +void device_poll_free_irq(struct device_poll *device_poll); + +static inline int device_poll_is_active(struct device_poll *device_poll) +{ + return likely(device_poll) && (device_poll->task != NULL); +} + +static inline void device_poll_enable_irq(struct device_poll *device_poll) +{ + if (device_poll_is_active(device_poll)) { + device_poll->enabled = 1; + /* Ensure changes to device_poll->enabled are seen by the + * polling thread. + */ + smp_wmb(); + } +} + +static inline void device_poll_disable_irq(struct device_poll *device_poll) +{ + if (device_poll_is_active(device_poll)) { + device_poll->enabled = 0; + /* Ensure changes to device_poll->enabled are seen by the + * polling thread. + */ + smp_wmb(); + } +} + +#endif + +#endif /* _LINUX_DEVICE_POLL_H_ */ From 9af00874b28fbe7c5b2605ee1f2fac1d6010a4dd Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 13 Feb 2014 08:13:36 -0600 Subject: [PATCH 68/97] net: add device_poll functionality common to all net devices The device_poll feature is generic to any device. Most net devices should be able to use a set of common functionality to implement device_poll, such as CAP_NET_ADMIN and rtnl_lock. Add this common functionality for all net devices to use. This is a standalone feature that should be submitted for review and possible inclusion in mainline, or maybe in the RT patch. Signed-off-by: Jeff Westfahl Signed-off-by: Nathan Sullivan Reviewed-by: Jaeden Amero Natinst-ReviewBoard-ID: 108252 [cvadrevu: Fixed trivial conflicts due to newer modules] Signed-off-by: Chaitanya Vadrevu --- include/linux/netdev_poll.h | 26 +++++++++++++++ net/Kconfig | 3 ++ net/core/Makefile | 1 + net/core/dev_poll.c | 64 +++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 include/linux/netdev_poll.h create mode 100644 net/core/dev_poll.c diff --git a/include/linux/netdev_poll.h b/include/linux/netdev_poll.h new file mode 100644 index 0000000000000..3785454de3eea --- /dev/null +++ b/include/linux/netdev_poll.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_NETDEV_POLL_H_ +#define _LINUX_NETDEV_POLL_H_ + +#ifdef CONFIG_NETDEV_POLL + +#include + +int netdev_poll_init(struct device_poll *device_poll); + +#endif + +#endif /* _LINUX_NETDEV_POLL_H_ */ diff --git a/net/Kconfig b/net/Kconfig index 1d3f757d4b07e..de5ee34ac7c38 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -452,6 +452,9 @@ config LWTUNNEL tunnels like mpls. There is no netdevice associated with a light weight tunnel endpoint. Tunnel encapsulation parameters are stored with light weight tunnel state associated with fib routes. +config NETDEV_POLL + bool + select DEVICE_POLL config LWTUNNEL_BPF bool "Execute BPF program as route nexthop action" diff --git a/net/core/Makefile b/net/core/Makefile index 9ef2099c54263..5fd6c429cd5e2 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_NET_TEST) += net_test.o obj-$(CONFIG_NET_DEVMEM) += devmem.o obj-$(CONFIG_DEBUG_NET) += lock_debug.o obj-$(CONFIG_FAIL_SKB_REALLOC) += skb_fault_injection.o +obj-$(CONFIG_NETDEV_POLL) += dev_poll.o diff --git a/net/core/dev_poll.c b/net/core/dev_poll.c new file mode 100644 index 0000000000000..1f2d4559ddd52 --- /dev/null +++ b/net/core/dev_poll.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +/* netdev_poll internal functions */ + +static int netdev_poll_reinit(struct device_poll *device_poll) +{ + int ret = 0; + struct net_device *netdev = to_net_dev(device_poll->device); + + if (netif_running(netdev)) { + netdev->netdev_ops->ndo_stop(netdev); + ret = netdev->netdev_ops->ndo_open(netdev); + } + + return ret; +} + +static void netdev_poll_lock(struct device_poll *device_poll) +{ + rtnl_lock(); +} + +static void netdev_poll_unlock(struct device_poll *device_poll) +{ + rtnl_unlock(); +} + +/* netdev_poll external functions */ + +int netdev_poll_init(struct device_poll *device_poll) +{ + if (!device_poll || !device_poll->device || !device_poll->ops) + return -EINVAL; + + if (!device_poll->ops->reinit) + device_poll->ops->reinit = netdev_poll_reinit; + if (!device_poll->ops->lock) + device_poll->ops->lock = netdev_poll_lock; + if (!device_poll->ops->unlock) + device_poll->ops->unlock = netdev_poll_unlock; + + /* Allow changes from any process with CAP_NET_ADMIN. */ + device_poll->use_capability = 1; + device_poll->capability = CAP_NET_ADMIN; + + return device_poll_init(device_poll); +} +EXPORT_SYMBOL(netdev_poll_init); From 62235abfa8a4f1163bd1139f8d901bfb6e9e514e Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 13 Feb 2014 09:01:51 -0600 Subject: [PATCH 69/97] driver core: NI backwards compatibility for device_poll interface NI software shipped with an early implementation of the device_poll interface with differences from the current implementation. This commit provides a compatibility layer that allows this NI software to function. This is an internal patch that should never be submitted for inclusion upstream. Signed-off-by: Jeff Westfahl Signed-off-by: Nathan Sullivan Reviewed-by: Jaeden Amero Natinst-ReviewBoard-ID: 108252 --- drivers/base/Kconfig | 4 ++++ drivers/base/poll.c | 46 +++++++++++++++++++++++++++++++++++++ include/linux/device_poll.h | 5 ++++ 3 files changed, 55 insertions(+) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 095e9b8d2e6fd..b6aa7ca2485c0 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -252,4 +252,8 @@ config FW_DEVLINK_SYNC_STATE_TIMEOUT config DEVICE_POLL bool +config DEVICE_POLL_NI_COMPAT + bool + default y if DEVICE_POLL + endmenu diff --git a/drivers/base/poll.c b/drivers/base/poll.c index 7e1fc58082a85..27c480638b133 100644 --- a/drivers/base/poll.c +++ b/drivers/base/poll.c @@ -85,6 +85,14 @@ static ssize_t device_poll_set_interval(struct device *dev, if (kstrtoint(buf, 0, &interval) < 0) return -EINVAL; +#ifdef CONFIG_DEVICE_POLL_NI_COMPAT + /* For backwards compatibility with NI software. An interval of zero + * now indicates interrupt mode. Shipping NI software can get confused + * by this, so force 0 to -1. + */ + if (interval == 0) + interval = -1; +#endif device_poll->ops->lock(device_poll); if (device_poll->interval != interval) { device_poll->interval = interval; @@ -187,6 +195,14 @@ static const DEVICE_ATTR(policy, S_IWUSR | S_IRUGO, static const DEVICE_ATTR(priority, S_IWUSR | S_IRUGO, device_poll_get_priority, device_poll_set_priority); +#ifdef CONFIG_DEVICE_POLL_NI_COMPAT +/* For backwards compatibility with NI software. The interval attribute had a + * different name, and shipping NI software looks for this other name. + */ +static const DEVICE_ATTR(ni_polling_interval, S_IWUSR | S_IRUGO, + device_poll_get_interval, device_poll_set_interval); +#endif + /* device_poll internal functions */ static int device_poll_thread(void *info) @@ -283,6 +299,32 @@ int device_poll_init(struct device_poll *device_poll) if (ret) device_poll_exit(device_poll); +#ifdef CONFIG_DEVICE_POLL_NI_COMPAT + /* For backwards compatibility with NI software. */ + + /* An interval of zero now indicates interrupt mode. Shipping NI + * software can get confused by this, so force 0 to -1. + */ + if (device_poll->interval == 0) + device_poll->interval = -1; + + /* The interval attribute originally had a different name and location, + * and shipping NI software looks for this other name in this other + * location. + */ + device_poll->ni_interval_attr.attr = dev_attr_ni_polling_interval; + device_poll->ni_interval_attr.var = device_poll; + + if (device_poll->use_capability) + device_poll->ni_interval_attr.attr.attr.mode |= S_IWUGO; + + sysfs_attr_init(&device_poll->ni_interval_attr.attr.attr); + + ret = sysfs_create_file(&device_poll->device->kobj, + &device_poll->ni_interval_attr.attr.attr); + if (ret) + device_poll_exit(device_poll); +#endif return ret; } EXPORT_SYMBOL(device_poll_init); @@ -292,6 +334,10 @@ void device_poll_exit(struct device_poll *device_poll) if (!device_poll || !device_poll->device) return; +#ifdef CONFIG_DEVICE_POLL_NI_COMPAT + sysfs_remove_file(&device_poll->device->kobj, + &device_poll->ni_interval_attr.attr.attr); +#endif sysfs_remove_group(&device_poll->device->kobj, &device_poll->attr_group); } diff --git a/include/linux/device_poll.h b/include/linux/device_poll.h index 6236f11d2c089..633d36c78a37c 100644 --- a/include/linux/device_poll.h +++ b/include/linux/device_poll.h @@ -71,6 +71,11 @@ struct device_poll { struct dev_ext_attribute priority_attr; struct attribute *attrs[4]; struct attribute_group attr_group; + +#ifdef CONFIG_DEVICE_POLL_NI_COMPAT + /* For backwards compatibility with NI software. */ + struct dev_ext_attribute ni_interval_attr; +#endif }; int device_poll_init(struct device_poll *device_poll); From db6497215cb6b07794f254b01bf180a62d4f6dec Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Tue, 9 Dec 2014 11:18:32 -0600 Subject: [PATCH 70/97] macb: Handle FPGA reprogramming notifications Add support for taking Ethernet down and up when the FPGA is reloaded. Signed-off-by: Nathan Sullivan Acked-by: Jaeden Amero Acked-by: Ben Shelton Natinst-ReviewBoard-ID: 84654 Natinst-ReviewBoard-ID: 99911 Natinst-CAR-ID: 528734 Natinst-CAR-ID: 527188 (joshc: minor checkpatch cleanups) Signed-off-by: Josh Cartwright [cvadrevu: Fixed trivial merge conflicts] [cvadrevu: Make macb_fpga_notifier static to avoid build warning] Signed-off-by: Chaitanya Vadrevu macb_main: Add declaration for macb_fpga_notifier. TODO: fixup original commit later --- drivers/net/ethernet/cadence/macb.h | 5 ++ drivers/net/ethernet/cadence/macb_main.c | 91 ++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 0830c48973aa0..6c99417898860 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -1317,6 +1317,11 @@ struct macb { struct gem_stats gem; } hw_stats; +#ifdef CONFIG_FPGA_PERIPHERAL + struct notifier_block fpga_notifier; + bool fpga_down; +#endif + struct macb_or_gem_ops macbgem_ops; struct mii_bus *mii_bus; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 17d4a3e039458..e3d39f0d20cab 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -39,6 +39,12 @@ #include #include #include + +#ifdef CONFIG_FPGA_PERIPHERAL +#include +#include +#endif + #include "macb.h" /* This structure is only used for MACB on SiFive FU540 devices */ @@ -3076,6 +3082,15 @@ static int macb_open(struct net_device *dev) if (err < 0) return err; +#ifdef CONFIG_FPGA_PERIPHERAL + /* If we're being opened while the FPGA is being reprogrammed, we can + * just return. The interface will be brought up when the FPGA is back + * up. + */ + if (bp->fpga_down) + return 0; +#endif + /* RX buffers initialization */ macb_init_rx_buffer_size(bp, bufsz); @@ -3133,6 +3148,14 @@ static int macb_close(struct net_device *dev) unsigned long flags; unsigned int q; +#ifdef CONFIG_FPGA_PERIPHERAL + /* If we're being closed while the FPGA is being reprogrammed, the + * interface is already down. We can just return. + */ + if (bp->fpga_down) + return 0; +#endif + netif_tx_stop_all_queues(dev); for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { @@ -4436,6 +4459,60 @@ static const struct net_device_ops macb_netdev_ops = { .ndo_setup_tc = macb_setup_tc, }; +#ifdef CONFIG_FPGA_PERIPHERAL +static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + struct macb *bp = container_of(nb, struct macb, fpga_notifier); + + switch (val) { + case FPGA_PERIPHERAL_DOWN: + netdev_dbg(bp->dev, + "macb_fpga_notifier: going down\n"); + + /* Synchronize with macb_open/close. */ + rtnl_lock(); + if (!bp->fpga_down) { + /* If the interface has been opened. */ + if (netif_running(bp->dev)) + macb_close(bp->dev); + + bp->fpga_down = 1; + } + rtnl_unlock(); + break; + + case FPGA_PERIPHERAL_UP: + netdev_dbg(bp->dev, + "macb_fpga_notifier: coming up\n"); + + BUG_ON(!bp->fpga_down); + + /* Synchronize with macb_open/close. */ + rtnl_lock(); + + bp->fpga_down = 0; + + /* If the interface has been opened. */ + if (netif_running(bp->dev)) + macb_open(bp->dev); + + rtnl_unlock(); + break; + + case FPGA_PERIPHERAL_FAILED: + /* This interface is not coming back up. */ + break; + + default: + netdev_err(bp->dev, + "unsupported FPGA notifier value %lu\n", val); + break; + } + + return notifier_from_errno(0); +} +#endif + /* Configure peripheral capabilities according to device tree * and integration options used */ @@ -4617,6 +4694,14 @@ static int macb_init(struct platform_device *pdev) bp->tx_ring_size = DEFAULT_TX_RING_SIZE; bp->rx_ring_size = DEFAULT_RX_RING_SIZE; +#ifdef CONFIG_FPGA_PERIPHERAL + bp->fpga_notifier.notifier_call = macb_fpga_notifier; + + blocking_notifier_chain_register( + &fpgaperipheral_notifier_list, + &bp->fpga_notifier); +#endif + /* set the queue register mapping once for all: queue0 has a special * register mapping but we don't want to test the queue index then * compute the corresponding register offset at run time. @@ -5750,6 +5835,12 @@ static void macb_remove(struct platform_device *pdev) if (dev) { bp = netdev_priv(dev); + +#ifdef CONFIG_FPGA_PERIPHERAL + blocking_notifier_chain_unregister( + &fpgaperipheral_notifier_list, &bp->fpga_notifier); +#endif + unregister_netdev(dev); phy_exit(bp->sgmii_phy); mdiobus_unregister(bp->mii_bus); From d7c1ef40c1674e40720d7cc17d08feedba50e82f Mon Sep 17 00:00:00 2001 From: Mihai Neagu Date: Thu, 12 Mar 2015 18:53:00 +0200 Subject: [PATCH 71/97] HACK net/macb: Totally disable TX checksum offloading Since hardware checksumming is not supported, reset the TXCOEN bit in DMACFG. If unitialized, this bit causes checksum offloading to be left on in hardware, with software thinking it is off, and for a checksum offloading bug in hardware to cause small UDP packets (<= 2 bytes) to be sent with an incorrect checksum (0xffff). We can't fix this problem by zeroing the checksum field in outgoing UDPv4 packets as implemented by Jeff Westfahl or Xilinx in their xemacps driver because it breaks packet forwarding (where it is illegal to modify the checksum of forwarded packets with unknown validity). We don't yet know a way to fix this problem other than to not use hardware checksum offloading. This commit will need to be reworked before it is upstreamable. We just need a fix in the LabVIEW RT Linux kernel right now for release. Ideally, we'd continue to work with upstream to solve the problem, but this is an emergency and we need to test and ship right away. Signed-off-by: Mihai Neagu Signed-off-by: Jaeden Amero Reviewed-by: Ben Shelton Reviewed-by: Josh Cartwright Natinst-CAR-ID: 516373 Natinst-ReviewBoard-ID: 97988 (joshc: also hack up hw_features to never advertise hw csum support) Signed-off-by: Josh Cartwright --- drivers/net/ethernet/cadence/macb_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index e3d39f0d20cab..5128c08a7d614 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -2894,7 +2894,7 @@ static void macb_configure_dma(struct macb *bp) else dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */ - if (bp->dev->features & NETIF_F_HW_CSUM) + if (0 && bp->dev->features & NETIF_F_HW_CSUM) dmacfg |= GEM_BIT(TXCOEN); else dmacfg &= ~GEM_BIT(TXCOEN); @@ -4785,7 +4785,7 @@ static int macb_init(struct platform_device *pdev) dev->hw_features |= MACB_NETIF_LSO; /* Checksum offload is only available on gem with packet buffer */ - if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) + if (0 && macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; if (bp->caps & MACB_CAPS_SG_DISABLED) dev->hw_features &= ~NETIF_F_SG; From ca23b9e61aa03abe1d97963b4153b3c756c64528 Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Tue, 19 May 2015 13:37:07 -0500 Subject: [PATCH 72/97] net: macb: Disable phy interrupts during FPGA load Even when the PHY is stopped by macb_close, it still hangs on to its irq. Explicitly call phy_stop_interrupts to make sure the interrupt line is ignored while the FPGA is reloading to avoid interrupt storms from floating lines. Signed-off-by: Nathan Sullivan Reviewed-by: Ben Shelton Reviewed-by: Jaeden Amero Natinst-ReviewBoard-ID: 98279 --- drivers/net/ethernet/cadence/macb_main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 5128c08a7d614..2545ab90ac830 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4463,6 +4463,7 @@ static const struct net_device_ops macb_netdev_ops = { static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void *data) { struct macb *bp = container_of(nb, struct macb, fpga_notifier); + struct net_device *dev = bp->dev; switch (val) { case FPGA_PERIPHERAL_DOWN: @@ -4473,8 +4474,11 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void rtnl_lock(); if (!bp->fpga_down) { /* If the interface has been opened. */ - if (netif_running(bp->dev)) + if (netif_running(bp->dev)) { macb_close(bp->dev); + phy_stop_interrupts(dev->phydev); + phy_stop_machine(dev->phydev); + } bp->fpga_down = 1; } @@ -4493,8 +4497,11 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void bp->fpga_down = 0; /* If the interface has been opened. */ - if (netif_running(bp->dev)) + if (netif_running(bp->dev)) { + phy_start_machine(dev->phydev); + phy_start_interrupts(dev->phydev); macb_open(bp->dev); + } rtnl_unlock(); break; From e2aa3ee7b4aa7535d8a512ea41573cab77d4513a Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Thu, 4 Jan 2018 13:04:09 -0600 Subject: [PATCH 73/97] phy: add phy_stop_machine_nolink This function stops the PHY state machine, but without running the machine. Ever since 7ad813f20, phy_stop_machine runs it and brings the link down, which isn't always what you want. Signed-off-by: Nathan Sullivan Signed-off-by: Brad Mouring Acked-by: James Minor Natinst-ReviewBoard-ID: 214996 [cvadrevu: Fixed trivial conflicts with 59088b5a946: ("net: phy: avoid kernel warning dump when stopping an errored PHY") a3320bcf28e: ("net: phy: make phy_trigger_machine static")] Signed-off-by: Chaitanya Vadrevu --- drivers/net/phy/phy.c | 19 +++++++++++++++++++ include/linux/phy.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 02da4a203ddd4..8201ec5db7b78 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1347,6 +1347,25 @@ static void phy_error_precise(struct phy_device *phydev, phy_process_error(phydev); } +/** + * phy_stop_machine_nolink - stop the PHY state machine tracking + * @phydev: target phy_device struct + * + * Description: Stops the state machine timer, sets the state to UP + * (unless it wasn't up yet). This function must be called BEFORE + * phy_detach. Does not run the state machine to avoid taking the + * link down. + */ +void phy_stop_machine_nolink(struct phy_device *phydev) +{ + cancel_delayed_work_sync(&phydev->state_queue); + + mutex_lock(&phydev->lock); + if (phydev->state > PHY_UP && phydev->state != PHY_HALTED) + phydev->state = PHY_UP; + mutex_unlock(&phydev->lock); +} + /** * phy_error - enter ERROR state for this PHY device * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index 0bc00a4cceb24..6ad414f0bc712 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -2042,6 +2042,7 @@ void phy_trigger_machine(struct phy_device *phydev); void phy_mac_interrupt(struct phy_device *phydev); void phy_start_machine(struct phy_device *phydev); void phy_stop_machine(struct phy_device *phydev); +void phy_stop_machine_nolink(struct phy_device *phydev); void phy_ethtool_ksettings_get(struct phy_device *phydev, struct ethtool_link_ksettings *cmd); int phy_ethtool_ksettings_set(struct phy_device *phydev, From 85984ad0a27c3e6c5c39c6e09ea8b5e855671b47 Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Thu, 4 Jan 2018 13:06:46 -0600 Subject: [PATCH 74/97] macb: call phy_stop_machine_nolink Use this new function to avoid bringing the link down when an FPGA bitfile is loaded. This minimizes the time spent with no network afterwards. Signed-off-by: Nathan Sullivan Signed-off-by: Brad Mouring Acked-by: James Minor Natinst-ReviewBoard-ID: 214996 --- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 2545ab90ac830..6c8166ea5aed8 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4477,7 +4477,7 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void if (netif_running(bp->dev)) { macb_close(bp->dev); phy_stop_interrupts(dev->phydev); - phy_stop_machine(dev->phydev); + phy_stop_machine_nolink(dev->phydev); } bp->fpga_down = 1; From 99d2e0e9eb5cdfdc0320a6bc3ef4a3da3f07fca2 Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Tue, 30 Jan 2018 13:42:20 -0600 Subject: [PATCH 75/97] macb: deactivate queues in fpga notifier In order to synchronize macb_stop and macb_start_xmit, turn all the tx queues off before going down and back on again before going up during FPGA reloads. Not synchronizing these functions would result in a crash during the reload if frames are transmitted. Signed-off-by: Nathan Sullivan Signed-off-by: Brad Mouring Acked-by: Zach Brown Acked-by: James Minor Natinst-ReviewBoard-ID: 218609 Natinst-CAR-ID: 672398 --- drivers/net/ethernet/cadence/macb_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 6c8166ea5aed8..475defef6ecf0 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -42,6 +42,7 @@ #ifdef CONFIG_FPGA_PERIPHERAL #include +#include #include #endif @@ -4475,6 +4476,7 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void if (!bp->fpga_down) { /* If the interface has been opened. */ if (netif_running(bp->dev)) { + dev_deactivate(bp->dev); macb_close(bp->dev); phy_stop_interrupts(dev->phydev); phy_stop_machine_nolink(dev->phydev); @@ -4501,6 +4503,7 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void phy_start_machine(dev->phydev); phy_start_interrupts(dev->phydev); macb_open(bp->dev); + dev_activate(bp->dev); } rtnl_unlock(); From f1b97e2a357778c0f6a6595c1293e1c6d58fc1a0 Mon Sep 17 00:00:00 2001 From: James Minor Date: Mon, 2 Mar 2015 14:37:42 -0600 Subject: [PATCH 76/97] wl12xx: Disable uncalibrated channel 14 (not supported on LSR) NI uses a module from LSR that does not have calibration constants for channel 14. As such, channel 14 should never be used. This change is to retain parity with NI's shipped 3.2 kernel for purposes of compliance, so it should not be upstreamed. Signed-off-by: James Minor --- drivers/net/wireless/ti/wlcore/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index bdb06584d7e45..057bc2cec0690 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5933,7 +5933,6 @@ static struct ieee80211_channel wl1271_channels[] = { { .hw_value = 11, .center_freq = 2462, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 12, .center_freq = 2467, .max_power = WLCORE_MAX_TXPWR }, { .hw_value = 13, .center_freq = 2472, .max_power = WLCORE_MAX_TXPWR }, - { .hw_value = 14, .center_freq = 2484, .max_power = WLCORE_MAX_TXPWR }, }; /* can't be const, mac80211 writes to this */ From ce3e55c29cb051870ef320517ff4342a207d5f35 Mon Sep 17 00:00:00 2001 From: James Minor Date: Tue, 3 Mar 2015 12:20:11 -0600 Subject: [PATCH 77/97] wl12xx: Disallow channels above 11 until beacons are seen In order to prevent us from sending out anything on channels that are illegal in some countries, we wait until we see beacons from the AP before trying to connect on those channels. This change is to retain parity with NI's shipped 3.2 kernel for purposes of compliance, so it should not be upstreamed. Signed-off-by: Tim Ousley [reworked for 3.14 branch and for coding style ] Signed-off-by: James Minor --- drivers/net/wireless/ti/wlcore/main.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 057bc2cec0690..2bbd4797a0ce4 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -32,6 +32,8 @@ #define WL1271_BOOT_RETRIES 3 #define WL1271_WAKEUP_TIMEOUT 500 +#define MAX_GLOBAL_80211_ISM_CENTER_FREQ 2462 + static char *fwlog_param; static int fwlog_mem_blocks = -1; static int bug_on_recovery = -1; @@ -67,6 +69,9 @@ static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif) static void wl1271_reg_notify(struct wiphy *wiphy, struct regulatory_request *request) { + struct ieee80211_supported_band *band; + struct ieee80211_channel *ch; + int i; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct wl1271 *wl = hw->priv; @@ -74,6 +79,18 @@ static void wl1271_reg_notify(struct wiphy *wiphy, if (request) wl->dfs_region = request->dfs_region; + /* Never speak first on channels 12, 13, and 14 even if + * the user hints that it's OK + */ + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + for (i = 0; i < band->n_channels; i++) { + ch = &band->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + if (ch->center_freq > MAX_GLOBAL_80211_ISM_CENTER_FREQ) + ch->flags |= IEEE80211_CHAN_NO_IR; + } + wlcore_regdomain_config(wl); } From 464f640c3f36feb7d8bae989bcca99800fac6dd6 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Tue, 3 Mar 2015 12:20:11 -0600 Subject: [PATCH 78/97] wl12xx: Switch to using nl80211_band enum Commit 57fbcce37be7 ("cfg80211: remove enum ieee80211_band") upstream removed the ieee80211_band enum in favour of using the nl80211_band enum directly. Convert the TI wl12xx driver's use of ieee80211_band to nl80211_band enum. Fixes: ce3a405b2e61 ("wl12xx: Disallow channels above 11 until beacons are seen") Signed-off-by: Gratian Crisan --- drivers/net/wireless/ti/wlcore/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2bbd4797a0ce4..7ecd32672146a 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -82,7 +82,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy, /* Never speak first on channels 12, 13, and 14 even if * the user hints that it's OK */ - band = wiphy->bands[IEEE80211_BAND_2GHZ]; + band = wiphy->bands[NL80211_BAND_2GHZ]; for (i = 0; i < band->n_channels; i++) { ch = &band->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) From 057f2b75e9486cfce4138fb89364ba9966769663 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Thu, 31 Aug 2017 19:58:11 -0500 Subject: [PATCH 79/97] mmc: core: Wait for Vdd to settle on card power off The SD spec version 6.0 section 6.4.1.5 requires that Vdd must be lowered to less than 0.5V for a minimum of 1 ms when powering off a card. Increase our wait to 15 ms so that voltage has time to drain down to 0.5V. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: James Minor Acked-by: Brandon Streiff Natinst-ReviewBoard-ID: 203804 --- drivers/mmc/host/sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3d5e062b8cfd4..67f72d98fb824 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2416,6 +2416,9 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) else sdhci_set_power(host, ios->power_mode, ios->vdd); + if (ios->power_mode == MMC_POWER_OFF) + mdelay(15); + if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); From 01198e1641c645aab17411fa8190dbdf22a9073b Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Tue, 24 Apr 2018 08:27:03 -0500 Subject: [PATCH 80/97] mmc: sdhci: Disable SD card clock before changing parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the SD Host Controller Simplified Specification v4.20 §3.2.3, change the SD card clock parameters only after first disabling the external card clock. Doing this fixes a spurious clock pulse on Baytrail and Apollo Lake SD controllers which otherwise breaks voltage switching with a specific Swissbit SD card. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Tony Liechty Acked-by: Nathan Sullivan Natinst-ReviewBoard-ID: 236135 Natinst-CAR-ID: 694815 --- drivers/mmc/host/sdhci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 67f72d98fb824..16c1c539b2a6a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2066,10 +2066,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->mmc->actual_clock = 0; - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + if (clk & SDHCI_CLOCK_CARD_EN) + sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, + SDHCI_CLOCK_CONTROL); - if (clock == 0) + if (clock == 0) { + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); return; + } clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_enable_clk(host, clk); From 9dcb30b4db5659151d1e20aa973e233039f453d0 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Mon, 14 May 2018 13:58:17 -0500 Subject: [PATCH 81/97] mmc: sdhci: Add quirk for delay between clock disable and param change Some SD controllers require a delay between clearing SDHCI_CLOCK_CARD_EN and changing the SD clock dividers in order to avoid a runt clock pulse which can otherwise cause problems with some SD cards. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Tony Liechty Acked-by: Nathan Sullivan Natinst-ReviewBoard-ID: 236135 [cvadrevu: Fixed trivial conflicts due to new quirks] Signed-off-by: Chaitanya Vadrevu --- drivers/mmc/host/sdhci.c | 6 ++++++ drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 16c1c539b2a6a..e44e9d06c73a7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2071,6 +2071,12 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, SDHCI_CLOCK_CONTROL); + if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_CLK_DISABLE) { + spin_unlock_irq(&host->lock); + usleep_range(900, 1100); + spin_lock_irq(&host->lock); + } + if (clock == 0) { sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); return; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 3201d21af793a..9b595462deda7 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -536,6 +536,8 @@ struct sdhci_host { #define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18) /* Issue CMD and DATA reset together */ #define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19) +/* Controller requires delay between card clock disable and param change */ +#define SDHCI_QUIRK2_NEED_DELAY_AFTER_CLK_DISABLE (1<<20) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ From 3b91786a7ac29b16469c95209cea34879640872b Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Wed, 16 May 2018 16:45:01 -0500 Subject: [PATCH 82/97] mmc: sdhci: Add quirk work around double rescan On some SD host controllers, we can see two SD card insert interrupts when inserting a card. This causes mmc_rescan() to be called twice in quick succession and generate one or two SD card clock pulses, which can cause some SD cards to become unresponsive. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Tony Liechty Acked-by: Nathan Sullivan Natinst-ReviewBoard-ID: 236135 [gratian: fix conflict with fec796739740 ("mmc: sdhci: Factor out sdhci_enable_clk")] Signed-off-by: Gratian Crisan [cvadrevu: Fixed trivial conflicts due to new quirks] Signed-off-by: Chaitanya Vadrevu --- drivers/mmc/host/sdhci.c | 8 +++++++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e44e9d06c73a7..8fb66edb82a01 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2079,11 +2079,17 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) if (clock == 0) { sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - return; + goto out_delay; } clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_enable_clk(host, clk); +out_delay: + if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_CARD_INSERT_INTERRUPT) { + spin_unlock_irq(&host->lock); + usleep_range(4900, 5100); + spin_lock_irq(&host->lock); + } } EXPORT_SYMBOL_GPL(sdhci_set_clock); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 9b595462deda7..ad5fb71cd729c 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -538,6 +538,8 @@ struct sdhci_host { #define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19) /* Controller requires delay between card clock disable and param change */ #define SDHCI_QUIRK2_NEED_DELAY_AFTER_CLK_DISABLE (1<<20) +/* Controller may interrupt multiple times for card insert */ +#define SDHCI_QUIRK2_SPURIOUS_CARD_INSERT_INTERRUPT (1<<21) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ From 27a24888ec7f94afd0d8d4e387353b480f520c96 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Thu, 17 May 2018 11:25:47 -0500 Subject: [PATCH 83/97] mmc: sdhci-pci: Use two delay quirks for Baytrail SD With the Baytrail SD controllers on cRIO-905x, we can run into two conditions which cause functional problems with the NI-recommended microSD card. The first is a runt pulse after SD card clock disable, which is fixed by using SDHCI_QUIRK2_NEED_DELAY_AFTER_CLK_DISABLE to wait after disabling the clock. The second is receiving two SDHCI_INT_CARD_INSERT interrupts, which causes us to set up the card twice a make our recommended microSD card unresponsive. Work around this by using SDHCI_QUIRK2_SPURIOUS_CARD_INSERT_INTERRUPT. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Tony Liechty Acked-by: Nathan Sullivan Natinst-ReviewBoard-ID: 236135 Natinst-CAR-ID: 696865 Natinst-CAR-ID: 694815 --- drivers/mmc/host/sdhci-pci-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 47a0a738862b5..4419f0414bf1a 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1137,6 +1137,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) byt_needs_pwr_off(slot); + if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BYT_SD) + slot->host->quirks2 |= SDHCI_QUIRK2_NEED_DELAY_AFTER_CLK_DISABLE | + SDHCI_QUIRK2_SPURIOUS_CARD_INSERT_INTERRUPT; + return 0; } From c5cd0641a32fb9dba2b87f5c532cc66e0f0c0a53 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Wed, 11 Jul 2012 22:14:17 +0200 Subject: [PATCH 84/97] Marvell 88E151x PHY: Configure interrupt output By default, the interrupt output of the Marvell 88E1512 PHY is configured as an LED output, and is driven low. If we have a case where eth1 is brought up before eth0, this causes an interrupt storm, and Linux eventually gives up and disables the PHY interrupt line. Adding a probe function to the Marvell 88E1512 PHY driver and moving the interrupt output configuration there resolves this problem. [bm: Adjust for d2fa47d9dd5c5f82d78c4503cf33989f67e8aa64 'phy: marvell: Add ethtool statistics counters'] Signed-off-by: Jeff Westfahl Signed-off-by: Mihaly Varga Acked-by: Brad Mouring Acked-by: Ben Shelton Acked-by: Jaeden Amero Natinst-ReviewBoard-ID: 81627 [bm: Restore correct page on LED/irq config] Signed-off-by: Brad Mouring Acked-by: Jeff Westfahl Natinst-ReviewBoard-ID: 148255 [gratian: split LED pin setup from m88e151x_probe; fixes conflict with 0b04680fdae4 ("phy: marvell: Add support for temperature sensor")] Signed-off-by: Gratian Crisan [cvadrevu: Fixed trivial conflict with b697d9d38a5a5 ("net: phy: marvell: add SFP support for 88E1510")] [cvadrevu: Updated marvell_get_page to marvell_read_page due to 424ca4c55121 ("net: phy: marvell: fix paged access races")] Signed-off-by: Chaitanya Vadrevu --- drivers/net/phy/marvell.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index c248c90510ae5..35da758f64852 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -181,6 +181,8 @@ #define MII_88E3016_PHY_SPEC_CTRL 0x10 #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 #define MII_88E3016_AUTO_MDIX_CROSSOVER 0x0030 +#define MII_88E1512_LEDTimerControl_InterruptEnable 0x0080 + #define MII_88E1510_GEN_CTRL_REG_1 0x14 #define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK 0x7 @@ -3682,10 +3684,45 @@ static const struct sfp_upstream_ops m88e1510_sfp_ops = { .disconnect_phy = phy_sfp_disconnect_phy, }; +static int m88e151x_setup_interrupt_pin(struct phy_device *phydev) +{ + u32 led_timer_control; + int err, old_page; + + old_page = marvell_read_page(phydev); + if (old_page < 0) + return old_page; + + /* Enable the interrupt output. This is just a pin configuration, + * we're not actually enabling any interrupts here. But the default + * configuration causes our interrupt pin to be asserted. We need + * to stop that as early as possible. + */ + err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); + + if (err < 0) + return err; + + led_timer_control = phy_read(phydev, MII_88E1318S_PHY_LED_TCR); + led_timer_control |= MII_88E1512_LEDTimerControl_InterruptEnable; + + err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, led_timer_control); + if (err < 0) + return err; + + err = marvell_set_page(phydev, old_page); + + return err; +} + static int m88e1510_probe(struct phy_device *phydev) { int err; + err = m88e151x_setup_interrupt_pin(phydev); + if (err) + return err; + err = marvell_probe(phydev); if (err) return err; From 2447ccfd69f091958683b83ab4b7f5f1ec460037 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Tue, 20 Nov 2018 07:38:02 -0600 Subject: [PATCH 85/97] mmc: sdhci: Do not disable interrupts in sdhci_set_clock Upstream removed spin lock usage in the set_ios path with commit d1e4f74f911d ("mmc: sdhci: Do not use spin lock in set_ios paths"), which means that our calls to spin_(un)lock_irq() in sdhci_set_clock() now cause an error on boot if a card is not present or a crash if one is present. Remove these calls so we don't do that and to match upstream's change. Fixes: 815777e0a1fb2 ("mmc: sdhci: Add quirk for delay between clock disable and param change") Fixes: 30d2f458ba48f ("mmc: sdhci: Add quirk work around double rescan") Signed-off-by: Kyle Roeschley Acked-by: Gratian Crisan Acked-by: Brandon Streiff Natinst-ReviewBoard-ID: 264712 Natinst-CAR-ID: 720310 --- drivers/mmc/host/sdhci.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8fb66edb82a01..15f09f7795cfa 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2071,11 +2071,8 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, SDHCI_CLOCK_CONTROL); - if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_CLK_DISABLE) { - spin_unlock_irq(&host->lock); - usleep_range(900, 1100); - spin_lock_irq(&host->lock); - } + if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_CLK_DISABLE) + mdelay(1); if (clock == 0) { sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); @@ -2085,11 +2082,8 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_enable_clk(host, clk); out_delay: - if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_CARD_INSERT_INTERRUPT) { - spin_unlock_irq(&host->lock); - usleep_range(4900, 5100); - spin_lock_irq(&host->lock); - } + if (host->quirks2 & SDHCI_QUIRK2_SPURIOUS_CARD_INSERT_INTERRUPT) + mdelay(5); } EXPORT_SYMBOL_GPL(sdhci_set_clock); From e2e9feeb7d6af7e44f1f5a302fa787991c98034f Mon Sep 17 00:00:00 2001 From: Kim Khiam Lim Date: Tue, 26 Jan 2021 21:20:39 -0800 Subject: [PATCH 86/97] nizynqcpld: Add NI roboRIO 2.0 CPLD support NI roboRIO 2.0 has relocated the clock pin from 1.8V bank to 3.3V bank. Hence, it required to update both product and supported version to indicate the changes in HW. Signed-off-by: Kim Khiam Lim --- drivers/misc/nizynqcpld.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index d8734a00f0331..5db065365893e 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1380,6 +1380,20 @@ static struct nizynqcpld_desc nizynqcpld_descs[] = { .switch_addr = PROTO_PROCESSORMODE, .watchdog_addr = DOSX_WATCHDOGCONTROL, }, + /* roboRIO 2.0 CPLD */ + { + .attrs = dosequis6_attrs, + .supported_version = 1, + .supported_product = 7, + .watchdog_desc = &dosxv5_watchdog_desc, + .led_descs = dosx_leds, + .num_led_descs = ARRAY_SIZE(dosx_leds), + .reboot_addr = DOSX_PROCESSORRESET, + .scratch_hr_addr = DOSX_SCRATCHPADHR, + .scratch_sr_addr = DOSX_SCRATCHPADSR, + .switch_addr = PROTO_PROCESSORMODE, + .watchdog_addr = DOSX_WATCHDOGCONTROL, + }, }; static void wifi_sw_work_func(struct work_struct *work) From c44a9609070de6d41c71a4569c36a9206f7ce341 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Tue, 21 Jul 2026 18:02:45 -0500 Subject: [PATCH 87/97] ARM: dts: ni: Import Zynq device trees from Linux 4.14 Import the NI Zynq board device trees from the 4.14 kernel and add them to the Xilinx DTB build list. Signed-off-by: Chaitanya Vadrevu --- arch/arm/boot/dts/xilinx/Makefile | 26 +- arch/arm/boot/dts/xilinx/ni-762F.dts | 6 + arch/arm/boot/dts/xilinx/ni-76D3.dts | 6 + arch/arm/boot/dts/xilinx/ni-76D6.dts | 138 +++++++++++ arch/arm/boot/dts/xilinx/ni-76F2.dts | 195 +++++++++++++++ arch/arm/boot/dts/xilinx/ni-7740.dts | 6 + arch/arm/boot/dts/xilinx/ni-7741.dts | 6 + arch/arm/boot/dts/xilinx/ni-7742.dts | 6 + arch/arm/boot/dts/xilinx/ni-7743.dts | 6 + arch/arm/boot/dts/xilinx/ni-7744.dts | 6 + arch/arm/boot/dts/xilinx/ni-774C.dts | 6 + arch/arm/boot/dts/xilinx/ni-774E.dts | 6 + arch/arm/boot/dts/xilinx/ni-775E.dts | 153 ++++++++++++ arch/arm/boot/dts/xilinx/ni-77AC.dts | 6 + arch/arm/boot/dts/xilinx/ni-77B1.dts | 6 + arch/arm/boot/dts/xilinx/ni-77B2.dts | 6 + arch/arm/boot/dts/xilinx/ni-77D4.dts | 141 +++++++++++ arch/arm/boot/dts/xilinx/ni-77D5.dts | 257 ++++++++++++++++++++ arch/arm/boot/dts/xilinx/ni-77D6.dts | 243 ++++++++++++++++++ arch/arm/boot/dts/xilinx/ni-7885.dts | 52 ++++ arch/arm/boot/dts/xilinx/ni-7931.dts | 8 + arch/arm/boot/dts/xilinx/ni-7932.dts | 8 + arch/arm/boot/dts/xilinx/ni-7935.dts | 8 + arch/arm/boot/dts/xilinx/ni-793C.dts | 155 ++++++++++++ arch/arm/boot/dts/xilinx/ni-793x.dtsi | 101 ++++++++ arch/arm/boot/dts/xilinx/ni-7AAE.dts | 205 ++++++++++++++++ arch/arm/boot/dts/xilinx/ni-myrio.dtsi | 87 +++++++ arch/arm/boot/dts/xilinx/ni-solbetter.dtsi | 199 +++++++++++++++ arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi | 108 ++++++++ arch/arm/boot/dts/xilinx/ni-solgood.dtsi | 126 ++++++++++ 30 files changed, 2281 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/xilinx/ni-762F.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-76D3.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-76D6.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-76F2.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7740.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7741.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7742.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7743.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7744.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-774C.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-774E.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-775E.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-77AC.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-77B1.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-77B2.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-77D4.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-77D5.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-77D6.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7885.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7931.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7932.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-7935.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-793C.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-793x.dtsi create mode 100644 arch/arm/boot/dts/xilinx/ni-7AAE.dts create mode 100644 arch/arm/boot/dts/xilinx/ni-myrio.dtsi create mode 100644 arch/arm/boot/dts/xilinx/ni-solbetter.dtsi create mode 100644 arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi create mode 100644 arch/arm/boot/dts/xilinx/ni-solgood.dtsi diff --git a/arch/arm/boot/dts/xilinx/Makefile b/arch/arm/boot/dts/xilinx/Makefile index 9233e539b192b..be4b160debac0 100644 --- a/arch/arm/boot/dts/xilinx/Makefile +++ b/arch/arm/boot/dts/xilinx/Makefile @@ -14,4 +14,28 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \ zynq-zturn.dtb \ zynq-zturn-v5.dtb \ zynq-zybo.dtb \ - zynq-zybo-z7.dtb + zynq-zybo-z7.dtb \ + ni-7931.dtb \ + ni-7932.dtb \ + ni-7935.dtb \ + ni-762F.dtb \ + ni-76D3.dtb \ + ni-76D6.dtb \ + ni-76F2.dtb \ + ni-7740.dtb \ + ni-7741.dtb \ + ni-7742.dtb \ + ni-7743.dtb \ + ni-7744.dtb \ + ni-774C.dtb \ + ni-774E.dtb \ + ni-775E.dtb \ + ni-77AC.dtb \ + ni-77B1.dtb \ + ni-77B2.dtb \ + ni-77D4.dtb \ + ni-77D5.dtb \ + ni-77D6.dtb \ + ni-7885.dtb \ + ni-793C.dtb \ + ni-7AAE.dtb diff --git a/arch/arm/boot/dts/xilinx/ni-762F.dts b/arch/arm/boot/dts/xilinx/ni-762F.dts new file mode 100644 index 0000000000000..5e9b94dd530e9 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-762F.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-myrio.dtsi" + +/ { + model = "NI myRIO-1900"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-76D3.dts b/arch/arm/boot/dts/xilinx/ni-76D3.dts new file mode 100644 index 0000000000000..c5fcc1d079d23 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-76D3.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-myrio.dtsi" + +/ { + model = "NI myRIO-1950"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-76D6.dts b/arch/arm/boot/dts/xilinx/ni-76D6.dts new file mode 100644 index 0000000000000..22fd6b41cd3e4 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-76D6.dts @@ -0,0 +1,138 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI cRIO-9068"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <46 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + user1-1 { + label = "nilrt:user1:yellow"; + }; + status-0 { + label = "nilrt:status:red"; + }; + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:100Mbps"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "marvell,88e1512","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1, shared with phy1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* marvell,reg-init = + * + * reg-page = MII_MARVELL_LED_PAGE (3) + * reg = PHY_LED_CTRL (16) + * value = 0x1881 (LED[0] = on:link, blink:activity, off:no link) + */ + marvell,reg-init = <3 16 0 0x1881>; + }; + + phy1: phy@1 { + compatible = "marvell,88e1512","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO1, shared with phy0. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* marvell,reg-init = + * + * reg-page = MII_MARVELL_LED_PAGE (3) + * reg = PHY_LED_CTRL (16) + * value = 0x1881 (LED[0] = on:link, blink:activity, off:no link) + */ + marvell,reg-init = <3 16 0 0x1881>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 54 0>; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-485"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-76F2.dts b/arch/arm/boot/dts/xilinx/ni-76F2.dts new file mode 100644 index 0000000000000..ef161a68d0f68 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-76F2.dts @@ -0,0 +1,195 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI roboRIO"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + aliases { + spi0 = &spi0; + spi1 = &spi1; + }; + + leds { + compatible = "gpio-leds"; + wlan1 { + /* green */ + label = "nilrt:wifi:primary"; + gpios = <&gpio 55 0>; + }; + + wlan2 { + /* red */ + label = "nilrt:wifi:secondary"; + gpios = <&gpio 56 0>; + }; + }; + + amba@0 { + adc: adc@f8007100 { + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + /* Channel 0 maps to VPVN */ + channel@0 { + reg = <0>; + }; + /* Channel 1 maps to VAUX0 */ + channel@1 { + reg = <1>; + }; + /* Channel 2 maps to VAUX1 */ + channel@2 { + reg = <2>; + }; + /* Channel 3 maps to VAUX2 */ + channel@3 { + reg = <3>; + }; + /* Channel 4 maps to VAUX3 */ + channel@4 { + reg = <4>; + }; + /* Channel 5 maps to VAUX4 */ + channel@5 { + reg = <5>; + }; + /* Channel 9 maps to VAUX8 */ + channel@9 { + reg = <9>; + }; + /* Channel 10 maps to VAUX9 */ + channel@10 { + reg = <10>; + }; + /* Channel 11 maps to VAUX10 */ + channel@11 { + reg = <11>; + }; + /* Channel 12 maps to VAUX11 */ + channel@12 { + reg = <12>; + }; + }; + }; + + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + }; + }; + }; + + i2c1: i2c@e0005000 { + status = "okay"; + }; + + i2c2: i2c@81000000 { + status = "okay"; + }; + + spi0: spi@e0006000 { + status = "okay"; + num-cs = <7>; + is-decoded-cs = <1>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + spidev@1 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <1>; + }; + spidev@2 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <2>; + }; + spidev@3 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <3>; + }; + }; + + spi1: spi@e0007000 { + status = "okay"; + num-cs = <3>; + is-decoded-cs = <0>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <&gpio 54 0>, + <0>; + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "smsc,lan8720","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt pin is connected from PL pin to FPGA IRQ 3 */ + interrupts = <0 32 4>; + smsc,disable-energy-detect; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&uart0 { + status = "okay"; +}; + +&can0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7740.dts b/arch/arm/boot/dts/xilinx/ni-7740.dts new file mode 100644 index 0000000000000..8fa59d7c8dcd1 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7740.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-solgood.dtsi" + +/ { + model = "NI cRIO-9063"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7741.dts b/arch/arm/boot/dts/xilinx/ni-7741.dts new file mode 100644 index 0000000000000..c7f1e246456a7 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7741.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-solbetter.dtsi" + +/ { + model = "NI cRIO-9064"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7742.dts b/arch/arm/boot/dts/xilinx/ni-7742.dts new file mode 100644 index 0000000000000..88ca0b6450e83 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7742.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-solbetter.dtsi" + +/ { + model = "NI cRIO-9065"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7743.dts b/arch/arm/boot/dts/xilinx/ni-7743.dts new file mode 100644 index 0000000000000..95f70a8383b56 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7743.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-solgood.dtsi" + +/ { + model = "NI cRIO-9066"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7744.dts b/arch/arm/boot/dts/xilinx/ni-7744.dts new file mode 100644 index 0000000000000..9f5a652c20eae --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7744.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-solbetter.dtsi" + +/ { + model = "NI cRIO-9067"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-774C.dts b/arch/arm/boot/dts/xilinx/ni-774C.dts new file mode 100644 index 0000000000000..c80a63c642266 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-774C.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-solenetexp.dtsi" + +/ { + model = "NI 9147"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-774E.dts b/arch/arm/boot/dts/xilinx/ni-774E.dts new file mode 100644 index 0000000000000..1557e8c5f8b3e --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-774E.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-solenetexp.dtsi" + +/ { + model = "NI 9149"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-775E.dts b/arch/arm/boot/dts/xilinx/ni-775E.dts new file mode 100644 index 0000000000000..ed3f9c6e53953 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-775E.dts @@ -0,0 +1,153 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI sbRIO-9651"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + + /* No fpga_clk specified because we want our FPGA clock + * (fclk0) to always be 125 MHz. The bootloader sets + * fclk0 to 125 MHz and we just leave it like that. + */ + + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + emio-speed-gpios = <0>, + <&gpio 54 0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ + rxc-skew-ps = <0>; + }; +}; + +&gem1 { + status = "okay"; + + /* No fpga_clk specified because we want our FPGA clock (fclk0) to + * always be 125 MHz. The bootloader sets fclk0 to 125 MHz and we just + * leave it like that. + */ + + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + emio-speed-gpios = <&gpio 56 0>, + <&gpio 55 0>; + + phy1: phy@1 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO57. */ + interrupts = <57 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + }; +}; + +&sdhci0 { + status = "okay"; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart3 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart4 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart5 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&usb1 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk0 for eth0 and eth1, fclk1 for serial. */ + fclk-enable = <0x3>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-77AC.dts b/arch/arm/boot/dts/xilinx/ni-77AC.dts new file mode 100644 index 0000000000000..a2456ca3cbe36 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-77AC.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-793x.dtsi" + +/ { + model = "NI 7935R"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-77B1.dts b/arch/arm/boot/dts/xilinx/ni-77B1.dts new file mode 100644 index 0000000000000..b78d89e3e36d6 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-77B1.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-793x.dtsi" + +/ { + model = "NI 7931R"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-77B2.dts b/arch/arm/boot/dts/xilinx/ni-77B2.dts new file mode 100644 index 0000000000000..c9c371e7cc302 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-77B2.dts @@ -0,0 +1,6 @@ +/dts-v1/; +/include/ "ni-793x.dtsi" + +/ { + model = "NI 7932R"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-77D4.dts b/arch/arm/boot/dts/xilinx/ni-77D4.dts new file mode 100644 index 0000000000000..571e48d34449f --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-77D4.dts @@ -0,0 +1,141 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI sbRIO-9637"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO25. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; +}; + +&sdhci0 { + status = "okay"; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-77D5.dts b/arch/arm/boot/dts/xilinx/ni-77D5.dts new file mode 100644 index 0000000000000..0e983d48037b8 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-77D5.dts @@ -0,0 +1,257 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI sbRIO-9627"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:100Mbps"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO25, shared with phy1. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; + + phy1: phy@1 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO25, shared with phy0. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 55 0>; +}; + +&sdhci0 { + status = "okay"; +}; + +&sdhci1 { + status = "okay"; + force-sd-standard; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart3 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart4 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart5 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart6 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart7 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart8 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-77D6.dts b/arch/arm/boot/dts/xilinx/ni-77D6.dts new file mode 100644 index 0000000000000..c344069dec3c0 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-77D6.dts @@ -0,0 +1,243 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI sbRIO-9607"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:100Mbps"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO25, shared with phy1. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; + + phy1: phy@1 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO25, shared with phy0. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 55 0>; +}; + +&sdhci1 { + status = "okay"; + force-sd-standard; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart3 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart4 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart5 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart6 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7885.dts b/arch/arm/boot/dts/xilinx/ni-7885.dts new file mode 100644 index 0000000000000..661dc24a23baf --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7885.dts @@ -0,0 +1,52 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI ELVIS RIO CM"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + }; + }; + }; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7931.dts b/arch/arm/boot/dts/xilinx/ni-7931.dts new file mode 100644 index 0000000000000..6b1c1d8f57e59 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7931.dts @@ -0,0 +1,8 @@ +/dts-v1/; +/include/ "ni-793x.dtsi" + +/* NIDEVCODE 77B1 */ + +/ { + model = "NI-7931"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7932.dts b/arch/arm/boot/dts/xilinx/ni-7932.dts new file mode 100644 index 0000000000000..3010feed71f70 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7932.dts @@ -0,0 +1,8 @@ +/dts-v1/; +/include/ "ni-793x.dtsi" + +/* NIDEVCODE 77B2 */ + +/ { + model = "NI-7932"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7935.dts b/arch/arm/boot/dts/xilinx/ni-7935.dts new file mode 100644 index 0000000000000..00fb196b3d52a --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7935.dts @@ -0,0 +1,8 @@ +/dts-v1/; +/include/ "ni-793x.dtsi" + +/* NIDEVCODE 77AC */ + +/ { + model = "NI-7935"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-793C.dts b/arch/arm/boot/dts/xilinx/ni-793C.dts new file mode 100644 index 0000000000000..a2255627d113d --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-793C.dts @@ -0,0 +1,155 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI ELVIS III"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + wifi-0 { + label = "nilrt:wifi:primary"; + }; + wifi-1 { + label = "nilrt:wifi:secondary"; + }; + }; + }; + + oleddriver@3C { + compatible = "sinowealth,sh1107"; + reg = <0x3C>; + + oledmodule { + compatible = "truly,oel9m1027"; + }; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO25, shared with phy1. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; +}; + +&sdhci0 { + status = "okay"; + non-removable = <1>; + + wlan0: wlan@0 { + compatible = "atheros,ath6kl"; + status = "okay"; + atheros,board-id = ""; + atheros,region-code = ""; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; + emio-con-dio-multiplex-gpios = <0>, + <&gpio 56 0>; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-793x.dtsi b/arch/arm/boot/dts/xilinx/ni-793x.dtsi new file mode 100644 index 0000000000000..2317bdb927553 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-793x.dtsi @@ -0,0 +1,101 @@ +/include/ "ni-zynq.dtsi" + +/ { + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + + leds-ni793x@4020F000 { + compatible = "ni,led-793x"; + reg = <0x4020F000 4>; + user1 { + label = "nilrt:user1:green"; + }; + }; + + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + + /* No fpga_clk specified because we want our FPGA clock + * (fclk0) to always be 125 MHz. The bootloader sets + * fclk0 to 125 MHz and we just leave it like that. + */ + + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + emio-speed-gpios = <0>, + <&gpio 54 0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ + rxc-skew-ps = <0>; + }; +}; + +&sdhci0 { + status = "okay"; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&usb1 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk0 for eth0 and eth1, fclk1 for serial. */ + fclk-enable = <0x3>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-7AAE.dts b/arch/arm/boot/dts/xilinx/ni-7AAE.dts new file mode 100644 index 0000000000000..b01fb7f7b45c2 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-7AAE.dts @@ -0,0 +1,205 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/ { + model = "NI roboRIO 2.0"; + compatible = "ni,zynq", "xlnx,zynq-7000", "ni,artemis"; + + aliases { + spi0 = &spi0; + spi1 = &spi1; + }; + + leds { + compatible = "gpio-leds"; + wlan1 { + /* green */ + label = "nilrt:wifi:primary"; + gpios = <&gpio 55 0>; + }; + + wlan2 { + /* red */ + label = "nilrt:wifi:secondary"; + gpios = <&gpio 56 0>; + }; + }; + + amba@0 { + adc: adc@f8007100 { + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + /* Channel 0 maps to VPVN */ + channel@0 { + reg = <0>; + }; + /* Channel 1 maps to VAUX0 */ + channel@1 { + reg = <1>; + }; + /* Channel 2 maps to VAUX1 */ + channel@2 { + reg = <2>; + }; + /* Channel 3 maps to VAUX2 */ + channel@3 { + reg = <3>; + }; + /* Channel 4 maps to VAUX3 */ + channel@4 { + reg = <4>; + }; + /* Channel 5 maps to VAUX4 */ + channel@5 { + reg = <5>; + }; + /* Channel 9 maps to VAUX8 */ + channel@9 { + reg = <9>; + }; + /* Channel 10 maps to VAUX9 */ + channel@10 { + reg = <10>; + }; + /* Channel 11 maps to VAUX10 */ + channel@11 { + reg = <11>; + }; + /* Channel 12 maps to VAUX11 */ + channel@12 { + reg = <12>; + }; + }; + }; + + smcc@e000e000 { + nand@e1000000 { + status = "disabled"; + }; + }; + + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + }; + }; + }; + + i2c1: i2c@e0005000 { + status = "okay"; + }; + + i2c2: i2c@81000000 { + status = "okay"; + }; + + spi0: spi@e0006000 { + status = "okay"; + num-cs = <7>; + is-decoded-cs = <1>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + spidev@1 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <1>; + }; + spidev@2 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <2>; + }; + spidev@3 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <3>; + }; + }; + + spi1: spi@e0007000 { + status = "okay"; + num-cs = <3>; + is-decoded-cs = <0>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <&gpio 54 0>, + <0>; + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "smsc,lan8720","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt pin is connected from PL pin to FPGA IRQ 3 */ + interrupts = <0 32 4>; + smsc,disable-energy-detect; + }; +}; + +&sdhci1 { + status = "okay"; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&uart0 { + status = "okay"; +}; + +&can0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-myrio.dtsi b/arch/arm/boot/dts/xilinx/ni-myrio.dtsi new file mode 100644 index 0000000000000..18ec8c1394c50 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-myrio.dtsi @@ -0,0 +1,87 @@ +/include/ "ni-zynq.dtsi" + +/ { + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + switches { + wifi-switch { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + wifi-0 { + label = "nilrt:wifi:primary"; + }; + wifi-1 { + label = "nilrt:wifi:secondary"; + }; + }; + }; + }; + }; +}; + +&sdhci0 { + status = "okay"; + + /* We must force the SDHCI into test mode, so that it + * always pretends to have a card present. This is to + * work-around a hardware bug where TiWi WiFi does not + * have its CD line connected correctly. + */ + xlnx,fails-without-test-cd; + + non-removable = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + wl12xx: wl12xx@0 { + compatible = "ti,wl1271"; + reg = <2>; + interrupt-parent = <&gpio>; + interrupts = <15 0x4>; + ref-clock-frequency = <38400000>; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-solbetter.dtsi b/arch/arm/boot/dts/xilinx/ni-solbetter.dtsi new file mode 100644 index 0000000000000..2e6bb345da74b --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-solbetter.dtsi @@ -0,0 +1,199 @@ +/include/ "ni-zynq.dtsi" + +/ { + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:100Mbps"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:01:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; + + phy1: phy@1 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO1, shared with phy0. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 55 0>; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi b/arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi new file mode 100644 index 0000000000000..c81f7abb05376 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi @@ -0,0 +1,108 @@ +/include/ "ni-zynq.dtsi" + +/ { + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; diff --git a/arch/arm/boot/dts/xilinx/ni-solgood.dtsi b/arch/arm/boot/dts/xilinx/ni-solgood.dtsi new file mode 100644 index 0000000000000..d65b51a80aac4 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/ni-solgood.dtsi @@ -0,0 +1,126 @@ +/include/ "ni-zynq.dtsi" + +/ { + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:100Mbps"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.ethernet-ffffffff:00:1Gbps"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. + */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. + */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. + */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. + */ + txc-skew-ps = <1860>; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; From 7853e136ebbc0845902c9ba85d809e9935899ba7 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Tue, 21 Jul 2026 18:10:58 -0500 Subject: [PATCH 88/97] ARM: dts: ni: Remove unused dts These have been superceded by ni-.dts. Signed-off-by: Chaitanya Vadrevu --- arch/arm/boot/dts/xilinx/Makefile | 3 - arch/arm/boot/dts/xilinx/ni-7931.dts | 8 - arch/arm/boot/dts/xilinx/ni-7932.dts | 8 - arch/arm/boot/dts/xilinx/ni-7935.dts | 8 - arch/arm/boot/dts/xilinx/ni-793x.dts | 106 --------- arch/arm/boot/dts/xilinx/ni-dosequis.dts | 136 ------------ arch/arm/boot/dts/xilinx/ni-myrio.dts | 93 -------- arch/arm/boot/dts/xilinx/ni-roborio.dts | 191 ---------------- arch/arm/boot/dts/xilinx/ni-sbrio-9607.dts | 233 ------------------- arch/arm/boot/dts/xilinx/ni-sbrio-9627.dts | 247 --------------------- arch/arm/boot/dts/xilinx/ni-sbrio-9637.dts | 137 ------------ arch/arm/boot/dts/xilinx/ni-solbetter.dts | 191 ---------------- arch/arm/boot/dts/xilinx/ni-solenetexp.dts | 106 --------- arch/arm/boot/dts/xilinx/ni-solgood.dts | 124 ----------- arch/arm/boot/dts/xilinx/ni-tecate.dts | 153 ------------- 15 files changed, 1744 deletions(-) delete mode 100644 arch/arm/boot/dts/xilinx/ni-7931.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-7932.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-7935.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-793x.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-dosequis.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-myrio.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-roborio.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-sbrio-9607.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-sbrio-9627.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-sbrio-9637.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-solbetter.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-solenetexp.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-solgood.dts delete mode 100644 arch/arm/boot/dts/xilinx/ni-tecate.dts diff --git a/arch/arm/boot/dts/xilinx/Makefile b/arch/arm/boot/dts/xilinx/Makefile index be4b160debac0..f44bc06d62858 100644 --- a/arch/arm/boot/dts/xilinx/Makefile +++ b/arch/arm/boot/dts/xilinx/Makefile @@ -15,9 +15,6 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \ zynq-zturn-v5.dtb \ zynq-zybo.dtb \ zynq-zybo-z7.dtb \ - ni-7931.dtb \ - ni-7932.dtb \ - ni-7935.dtb \ ni-762F.dtb \ ni-76D3.dtb \ ni-76D6.dtb \ diff --git a/arch/arm/boot/dts/xilinx/ni-7931.dts b/arch/arm/boot/dts/xilinx/ni-7931.dts deleted file mode 100644 index 6b1c1d8f57e59..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-7931.dts +++ /dev/null @@ -1,8 +0,0 @@ -/dts-v1/; -/include/ "ni-793x.dtsi" - -/* NIDEVCODE 77B1 */ - -/ { - model = "NI-7931"; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-7932.dts b/arch/arm/boot/dts/xilinx/ni-7932.dts deleted file mode 100644 index 3010feed71f70..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-7932.dts +++ /dev/null @@ -1,8 +0,0 @@ -/dts-v1/; -/include/ "ni-793x.dtsi" - -/* NIDEVCODE 77B2 */ - -/ { - model = "NI-7932"; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-7935.dts b/arch/arm/boot/dts/xilinx/ni-7935.dts deleted file mode 100644 index 00fb196b3d52a..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-7935.dts +++ /dev/null @@ -1,8 +0,0 @@ -/dts-v1/; -/include/ "ni-793x.dtsi" - -/* NIDEVCODE 77AC */ - -/ { - model = "NI-7935"; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-793x.dts b/arch/arm/boot/dts/xilinx/ni-793x.dts deleted file mode 100644 index 74e373ccad154..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-793x.dts +++ /dev/null @@ -1,106 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 77AC */ -/* NIDEVCODE 77B2 */ -/* NIDEVCODE 77B1 */ - -/ { - model = "NI-793x"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - - leds-ni793x@4020F000 { - compatible = "ni,led-793x"; - reg = <0x4020F000 4>; - user1 { - label = "nilrt:user1:green"; - }; - }; - - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - - /* No fpga_clk specified because we want our FPGA clock - * (fclk0) to always be 125 MHz. The bootloader sets - * fclk0 to 125 MHz and we just leave it like that. */ - - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - #address-cells = <0x1>; - #size-cells = <0x0>; - - emio-speed-gpios = <0>, - <&gpio 54 0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO1. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ - rxc-skew-ps = <0>; - }; -}; - -&sdhci0 { - status = "okay"; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&usb0 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&usb1 { - status = "okay"; - dr_mode = "host"; -}; - -&clkc { - /* Enable fclk0 for eth0 and eth1, fclk1 for serial. */ - fclk-enable = <0x3>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-dosequis.dts b/arch/arm/boot/dts/xilinx/ni-dosequis.dts deleted file mode 100644 index ea43df8ff569a..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-dosequis.dts +++ /dev/null @@ -1,136 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 76D6 */ - -/ { - model = "NI Dos Equis"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <46 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - user1-0 { - label = "nilrt:user1:green"; - }; - user1-1 { - label = "nilrt:user1:yellow"; - }; - status-0 { - label = "nilrt:status:red"; - }; - status-1 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - wifi-0 { - label = "nilrt:wifi:primary"; - }; - wifi-1 { - label = "nilrt:wifi:secondary"; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - eth1-0 { - label = "nilrt:eth1:green"; - linux,default-trigger = - "e000b000.etherne:01:100Mb"; - }; - eth1-1 { - label = "nilrt:eth1:yellow"; - linux,default-trigger = - "e000b000.etherne:01:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "marvell,88e1512"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO1, shared with phy1. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - /* Page 3, Register 16, LED[2:0] Function - Control Register */ - leds = <0x1881>; - }; - - phy1: phy@1 { - compatible = "marvell,88e1512"; - device_type = "ethernet-phy"; - reg = <0x1>; - /* Interrupt on GPIO1, shared with phy0. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - /* Page 3, Register 16, LED[2:0] Function - Control Register */ - leds = <0x1881>; - }; -}; - -&gem1 { - status = "okay"; - clocks = <&clkc 31>, <&clkc 14>, <&clkc 15>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy1>; - phy-mode = "rgmii-id"; - cdns,no_mdio_bus; - emio-speed-gpios = <0>, - <&gpio 54 0>; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart1 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart2 { - status = "okay"; - transceiver = "RS-485"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-myrio.dts b/arch/arm/boot/dts/xilinx/ni-myrio.dts deleted file mode 100644 index cd944323a6cda..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-myrio.dts +++ /dev/null @@ -1,93 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 762F */ - -/ { - model = "NI myRIO"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - switches { - wifi-switch { - interrupt-parent = <&gpio>; - interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - status-1 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - wifi-0 { - label = "nilrt:wifi:primary"; - }; - wifi-1 { - label = "nilrt:wifi:secondary"; - }; - }; - }; - }; - }; -}; - -&sdhci0 { - status = "okay"; - - /* We must force the SDHCI into test mode, so that it - * always pretends to have a card present. This is to - * work-around a hardware bug where TiWi WiFi does not - * have its CD line connected correctly. */ - force-sd-cd-test-mode = <1>; - - non-removable = <1>; - - wl12xx: wl12xx@0 { - compatible = "ti,wilink6"; - interrupt-parent = <&gpio>; - interrupts = <15 0x4>; - clocks = <&refclock>; - clock-names = "refclock"; - - refclock: refclock { - compatible = "ti,wilink-clock"; - #clock-cells = <0>; - clock-frequency = <38400000>; - }; - }; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart1 { - status = "okay"; - transceiver = "RS-232"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&usb1 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-roborio.dts b/arch/arm/boot/dts/xilinx/ni-roborio.dts deleted file mode 100644 index d41d9ba1f3bbe..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-roborio.dts +++ /dev/null @@ -1,191 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 76F2 */ - -/ { - model = "NI roboRIO"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - aliases { - spi0 = &spi0; - spi1 = &spi1; - }; - - amba@0 { - adc: adc@f8007100 { - xlnx,channels { - #address-cells = <1>; - #size-cells = <0>; - /* Channel 0 maps to VPVN */ - channel@0 { - reg = <0>; - xlnx,extend-name = "vin_v"; - }; - /* Channel 1 maps to VAUX0 */ - channel@1 { - reg = <1>; - xlnx,extend-name = "vin_c"; - }; - /* Channel 2 maps to VAUX1 */ - channel@2 { - reg = <2>; - xlnx,extend-name = "user5v_v"; - }; - /* Channel 3 maps to VAUX2 */ - channel@3 { - reg = <3>; - xlnx,extend-name = "user5v_c"; - }; - /* Channel 4 maps to VAUX3 */ - channel@4 { - reg = <4>; - xlnx,extend-name = "user3v3_v"; - }; - /* Channel 5 maps to VAUX4 */ - channel@5 { - reg = <5>; - xlnx,extend-name = "user3v3_c"; - }; - /* Channel 9 maps to VAUX8 */ - channel@9 { - reg = <9>; - xlnx,extend-name = "user6v_c"; - }; - /* Channel 10 maps to VAUX9 */ - channel@10 { - reg = <10>; - xlnx,extend-name = "bist_ao_v"; - }; - /* Channel 11 maps to VAUX10 */ - channel@11 { - reg = <11>; - xlnx,extend-name = "bist_dio_v"; - }; - /* Channel 12 maps to VAUX11 */ - channel@12 { - reg = <12>; - xlnx,extend-name = "user6v_v"; - }; - }; - }; - - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - status-1 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - }; - }; - }; - - i2c1: i2c@e0005000 { - status = "okay"; - }; - - i2c2: i2c@81000000 { - status = "okay"; - }; - - spi0: spi@e0006000 { - status = "okay"; - num-cs = <7>; - is-decoded-cs = <1>; - speed-hz = <200000000>; - - spidev@0 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <0>; - }; - spidev@1 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <1>; - }; - spidev@2 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <2>; - }; - spidev@3 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <3>; - }; - }; - - spi1: spi@e0007000 { - status = "okay"; - num-cs = <3>; - is-decoded-cs = <0>; - speed-hz = <200000000>; - - spidev@0 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <0>; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - emio-speed-gpios = <&gpio 54 0>, - <0>; - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "smsc,lan8720"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt pin is connected from PL pin to FPGA IRQ 3 */ - interrupts = <0 32 4>; - }; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart1 { - status = "okay"; - transceiver = "RS-232"; -}; - -&uart0 { - status = "okay"; -}; - -&can0 { - status = "okay"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&usb1 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-sbrio-9607.dts b/arch/arm/boot/dts/xilinx/ni-sbrio-9607.dts deleted file mode 100644 index e582fca748bf3..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-sbrio-9607.dts +++ /dev/null @@ -1,233 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 77D6 */ - -/ { - model = "NI sbRIO-9607"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - user1-0 { - label = "nilrt:user1:green"; - }; - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - eth1-0 { - label = "nilrt:eth1:green"; - linux,default-trigger = - "e000b000.etherne:01:100Mb"; - }; - eth1-1 { - label = "nilrt:eth1:yellow"; - linux,default-trigger = - "e000b000.etherne:01:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - emio-speed-gpios = <0>, - <&gpio 54 0>; - - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO25, shared with phy1. */ - interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; - - phy1: phy@1 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x1>; - /* Interrupt on GPIO25, shared with phy0. */ - interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; -}; - -&gem1 { - status = "okay"; - clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy1>; - phy-mode = "rgmii-id"; - cdns,no_mdio_bus; - emio-speed-gpios = <0>, - <&gpio 55 0>; -}; - -&sdhci1 { - status = "okay"; - force-sd-standard; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart1 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart2 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart3 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart4 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart5 { - status = "okay"; - transceiver = "RS-485"; -}; - -&ni_uart6 { - status = "okay"; - transceiver = "RS-485"; -}; - -&can0 { - status = "okay"; -}; - -&can1 { - status = "okay"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&usb1 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-sbrio-9627.dts b/arch/arm/boot/dts/xilinx/ni-sbrio-9627.dts deleted file mode 100644 index 435a6169e0604..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-sbrio-9627.dts +++ /dev/null @@ -1,247 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 77D5 */ - -/ { - model = "NI sbRIO-9627"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - user1-0 { - label = "nilrt:user1:green"; - }; - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - eth1-0 { - label = "nilrt:eth1:green"; - linux,default-trigger = - "e000b000.etherne:01:100Mb"; - }; - eth1-1 { - label = "nilrt:eth1:yellow"; - linux,default-trigger = - "e000b000.etherne:01:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - emio-speed-gpios = <0>, - <&gpio 54 0>; - - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO25, shared with phy1. */ - interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; - - phy1: phy@1 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x1>; - /* Interrupt on GPIO25, shared with phy0. */ - interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; -}; - -&gem1 { - status = "okay"; - clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy1>; - phy-mode = "rgmii-id"; - cdns,no_mdio_bus; - emio-speed-gpios = <0>, - <&gpio 55 0>; -}; - -&sdhci0 { - status = "okay"; -}; - -&sdhci1 { - status = "okay"; - force-sd-standard; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart1 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart2 { - status = "okay"; - transceiver = "RS-485"; -}; - -&ni_uart3 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart4 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart5 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart6 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart7 { - status = "okay"; - transceiver = "RS-485"; -}; - -&ni_uart8 { - status = "okay"; - transceiver = "RS-485"; -}; - -&can0 { - status = "okay"; -}; - -&can1 { - status = "okay"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&usb1 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-sbrio-9637.dts b/arch/arm/boot/dts/xilinx/ni-sbrio-9637.dts deleted file mode 100644 index 7626db67b8073..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-sbrio-9637.dts +++ /dev/null @@ -1,137 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 77D4 */ - -/ { - model = "NI sbRIO-9637"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - user1-0 { - label = "nilrt:user1:green"; - }; - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - emio-speed-gpios = <0>, - <&gpio 54 0>; - - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO25. */ - interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; -}; - -&sdhci0 { - status = "okay"; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart1 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart2 { - status = "okay"; - transceiver = "RS-485"; -}; - -&can0 { - status = "okay"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-solbetter.dts b/arch/arm/boot/dts/xilinx/ni-solbetter.dts deleted file mode 100644 index b8315f0fe7506..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-solbetter.dts +++ /dev/null @@ -1,191 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 7744 */ - -/ { - model = "NI Sol"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - user1-0 { - label = "nilrt:user1:green"; - }; - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - eth1-0 { - label = "nilrt:eth1:green"; - linux,default-trigger = - "e000b000.etherne:01:100Mb"; - }; - eth1-1 { - label = "nilrt:eth1:yellow"; - linux,default-trigger = - "e000b000.etherne:01:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - - emio-speed-gpios = <0>, - <&gpio 54 0>; - - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO1. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; - - phy1: phy@1 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x1>; - /* Interrupt on GPIO1, shared with phy0. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; -}; - -&gem1 { - status = "okay"; - clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy1>; - phy-mode = "rgmii-id"; - cdns,no_mdio_bus; - emio-speed-gpios = <0>, - <&gpio 55 0>; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&usb1 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-solenetexp.dts b/arch/arm/boot/dts/xilinx/ni-solenetexp.dts deleted file mode 100644 index a495ca23e8861..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-solenetexp.dts +++ /dev/null @@ -1,106 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 774E */ - -/ { - model = "NI Sol"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - emio-speed-gpios = <0>, - <&gpio 54 0>; - - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO1. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; -}; - -&usb1 { - status = "okay"; - dr_mode = "peripheral"; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-solgood.dts b/arch/arm/boot/dts/xilinx/ni-solgood.dts deleted file mode 100644 index 4b25334247076..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-solgood.dts +++ /dev/null @@ -1,124 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 7743 */ - -/ { - model = "NI Sol"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - user1-0 { - label = "nilrt:user1:green"; - }; - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; - clock-names = "pclk", "hclk", "tx_clk"; - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - emio-speed-gpios = <0>, - <&gpio 54 0>; - - #address-cells = <0x1>; - #size-cells = <0x0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO1. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxdv-skew-ps = <720>; - - /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txen-skew-ps = <120>; - - /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 + 300 is 720 ps. */ - rxd0-skew-ps = <720>; - rxd1-skew-ps = <720>; - rxd2-skew-ps = <720>; - rxd3-skew-ps = <720>; - - /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ - /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 - * ps. 420 - 300 is 120 ps. */ - txd0-skew-ps = <120>; - txd1-skew-ps = <120>; - txd2-skew-ps = <120>; - txd3-skew-ps = <120>; - - /* Write value to MMD Address 2h, Register 8h */ - /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is - * 900 ps. 900 - 900 is 0 ps. */ - rxc-skew-ps = <0>; - /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ - /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is - * 960 ps. 900 + 960 is 1860 ps. */ - txc-skew-ps = <1860>; - }; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&usb0 { - status = "okay"; - dr_mode = "host"; -}; - -&usb1 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&clkc { - /* Enable fclk1 for serial. */ - fclk-enable = <0x2>; -}; diff --git a/arch/arm/boot/dts/xilinx/ni-tecate.dts b/arch/arm/boot/dts/xilinx/ni-tecate.dts deleted file mode 100644 index 15124e4b12cad..0000000000000 --- a/arch/arm/boot/dts/xilinx/ni-tecate.dts +++ /dev/null @@ -1,153 +0,0 @@ -/dts-v1/; -/include/ "ni-zynq.dtsi" - -/* NIDEVCODE 775E */ - -/ { - model = "NI Tecate"; - compatible = "ni,zynq", "xlnx,zynq-7000"; - - amba@0 { - i2c0: i2c@e0004000 { - nicpld@40 { - watchdogs { - boot-watchdog { - interrupt-parent = <&gpio>; - interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; - }; - }; - - leds { - status-0 { - label = "nilrt:status:yellow"; - max-brightness = <0xFFFF>; - }; - eth0-0 { - label = "nilrt:eth0:green"; - linux,default-trigger = - "e000b000.etherne:00:100Mb"; - }; - eth0-1 { - label = "nilrt:eth0:yellow"; - linux,default-trigger = - "e000b000.etherne:00:Gb"; - }; - }; - }; - - ds3231_rtc@68 { - status = "okay"; - }; - }; - }; -}; - -&gem0 { - status = "okay"; - - /* No fpga_clk specified because we want our FPGA clock - * (fclk0) to always be 125 MHz. The bootloader sets - * fclk0 to 125 MHz and we just leave it like that. */ - - phy-handle = <&phy0>; - phy-mode = "rgmii-id"; - #address-cells = <0x1>; - #size-cells = <0x0>; - - emio-speed-gpios = <0>, - <&gpio 54 0>; - - phy0: phy@0 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x0>; - /* Interrupt on GPIO1. */ - interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - - /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ - rxc-skew-ps = <0>; - }; -}; - -&gem1 { - status = "okay"; - - /* No fpga_clk specified because we want our FPGA clock (fclk0) to - * always be 125 MHz. The bootloader sets fclk0 to 125 MHz and we just - * leave it like that. */ - - phy-handle = <&phy1>; - phy-mode = "rgmii-id"; - #address-cells = <0x1>; - #size-cells = <0x0>; - - emio-speed-gpios = <&gpio 56 0>, - <&gpio 55 0>; - - phy1: phy@1 { - compatible = "micrel,KSZ9031"; - device_type = "ethernet-phy"; - reg = <0x1>; - /* Interrupt on GPIO57. */ - interrupts = <57 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; - }; -}; - -&sdhci0 { - status = "okay"; -}; - -&ni_uart0 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart1 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart2 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart3 { - status = "okay"; - transceiver = "RS-232"; -}; - -&ni_uart4 { - status = "okay"; - transceiver = "RS-485"; -}; - -&ni_uart5 { - status = "okay"; - transceiver = "RS-485"; -}; - -&can0 { - status = "okay"; -}; - -&can1 { - status = "okay"; -}; - -&usb0 { - status = "okay"; - dr_mode = "peripheral"; -}; - -&usb1 { - status = "okay"; - dr_mode = "host"; -}; - -&clkc { - /* Enable fclk0 for eth0 and eth1, fclk1 for serial. */ - fclk-enable = <0x3>; -}; From 1a13ba32227412a0615731602599f0a36b7672d5 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Tue, 21 Jul 2026 18:33:26 -0500 Subject: [PATCH 89/97] ARM: dts: ni: Adapt boards to the current Zynq hierarchy The NI device trees were copied from the 4.14 kernel and still reopen SoC nodes using their old names and hierarchy. The current Zynq device tree defines these nodes with labels and uses gpio0 for the GPIO controller. Convert the NI board files to extend the existing amba, I2C, SPI, and ADC nodes through label references. Update GPIO references from gpio to gpio0 and move the myRIO I2C and SPI configuration to the corresponding labeled nodes. This allows the NI Zynq device trees to compile against the current zynq-7000.dtsi. Signed-off-by: Chaitanya Vadrevu --- arch/arm/boot/dts/xilinx/ni-76D6.dts | 15 ++- arch/arm/boot/dts/xilinx/ni-76F2.dts | 106 +++++++++--------- arch/arm/boot/dts/xilinx/ni-775E.dts | 18 ++- arch/arm/boot/dts/xilinx/ni-77D4.dts | 12 +- arch/arm/boot/dts/xilinx/ni-77D5.dts | 16 ++- arch/arm/boot/dts/xilinx/ni-77D6.dts | 16 ++- arch/arm/boot/dts/xilinx/ni-7885.dts | 8 +- arch/arm/boot/dts/xilinx/ni-793C.dts | 14 +-- arch/arm/boot/dts/xilinx/ni-793x.dtsi | 27 +++-- arch/arm/boot/dts/xilinx/ni-7AAE.dts | 116 ++++++++++---------- arch/arm/boot/dts/xilinx/ni-myrio.dtsi | 12 +- arch/arm/boot/dts/xilinx/ni-solbetter.dtsi | 16 ++- arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi | 12 +- arch/arm/boot/dts/xilinx/ni-solgood.dtsi | 12 +- 14 files changed, 187 insertions(+), 213 deletions(-) diff --git a/arch/arm/boot/dts/xilinx/ni-76D6.dts b/arch/arm/boot/dts/xilinx/ni-76D6.dts index 22fd6b41cd3e4..1b4f69deff8ac 100644 --- a/arch/arm/boot/dts/xilinx/ni-76D6.dts +++ b/arch/arm/boot/dts/xilinx/ni-76D6.dts @@ -4,13 +4,14 @@ / { model = "NI cRIO-9068"; compatible = "ni,zynq", "xlnx,zynq-7000"; +}; + - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <46 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -55,8 +56,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -72,7 +71,7 @@ reg = <0x0>; /* Interrupt on GPIO1, shared with phy1. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* marvell,reg-init = * @@ -89,7 +88,7 @@ reg = <0x1>; /* Interrupt on GPIO1, shared with phy0. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* marvell,reg-init = * @@ -109,7 +108,7 @@ phy-mode = "rgmii-id"; cdns,no_mdio_bus; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; }; &ni_uart0 { diff --git a/arch/arm/boot/dts/xilinx/ni-76F2.dts b/arch/arm/boot/dts/xilinx/ni-76F2.dts index ef161a68d0f68..f7b640041f1f6 100644 --- a/arch/arm/boot/dts/xilinx/ni-76F2.dts +++ b/arch/arm/boot/dts/xilinx/ni-76F2.dts @@ -15,18 +15,18 @@ wlan1 { /* green */ label = "nilrt:wifi:primary"; - gpios = <&gpio 55 0>; + gpios = <&gpio0 55 0>; }; wlan2 { /* red */ label = "nilrt:wifi:secondary"; - gpios = <&gpio 56 0>; + gpios = <&gpio0 56 0>; }; }; +}; - amba@0 { - adc: adc@f8007100 { +&adc { xlnx,channels { #address-cells = <1>; #size-cells = <0>; @@ -71,13 +71,13 @@ reg = <12>; }; }; - }; +}; - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -89,56 +89,54 @@ }; }; }; - }; - - i2c1: i2c@e0005000 { - status = "okay"; - }; - - i2c2: i2c@81000000 { - status = "okay"; - }; +}; - spi0: spi@e0006000 { - status = "okay"; - num-cs = <7>; - is-decoded-cs = <1>; - speed-hz = <200000000>; +&i2c1 { + status = "okay"; +}; - spidev@0 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <0>; - }; - spidev@1 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <1>; - }; - spidev@2 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <2>; - }; - spidev@3 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <3>; - }; - }; +&i2c2 { + status = "okay"; +}; - spi1: spi@e0007000 { - status = "okay"; - num-cs = <3>; - is-decoded-cs = <0>; - speed-hz = <200000000>; +&spi0 { + status = "okay"; + num-cs = <7>; + is-decoded-cs = <1>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + spidev@1 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <1>; + }; + spidev@2 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <2>; + }; + spidev@3 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <3>; + }; +}; - spidev@0 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <0>; - }; - }; +&spi1 { + status = "okay"; + num-cs = <3>; + is-decoded-cs = <0>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; }; }; @@ -146,7 +144,7 @@ status = "okay"; phy-handle = <&phy0>; phy-mode = "rgmii-id"; - emio-speed-gpios = <&gpio 54 0>, + emio-speed-gpios = <&gpio0 54 0>, <0>; #address-cells = <0x1>; #size-cells = <0x0>; diff --git a/arch/arm/boot/dts/xilinx/ni-775E.dts b/arch/arm/boot/dts/xilinx/ni-775E.dts index ed3f9c6e53953..b5dc0d2db518f 100644 --- a/arch/arm/boot/dts/xilinx/ni-775E.dts +++ b/arch/arm/boot/dts/xilinx/ni-775E.dts @@ -4,13 +4,13 @@ / { model = "NI sbRIO-9651"; compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -36,8 +36,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -54,7 +52,7 @@ #size-cells = <0x0>; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; phy0: phy@0 { compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; @@ -62,7 +60,7 @@ reg = <0x0>; /* Interrupt on GPIO1. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ rxc-skew-ps = <0>; @@ -82,8 +80,8 @@ #address-cells = <0x1>; #size-cells = <0x0>; - emio-speed-gpios = <&gpio 56 0>, - <&gpio 55 0>; + emio-speed-gpios = <&gpio0 56 0>, + <&gpio0 55 0>; phy1: phy@1 { compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; @@ -91,7 +89,7 @@ reg = <0x1>; /* Interrupt on GPIO57. */ interrupts = <57 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; }; }; diff --git a/arch/arm/boot/dts/xilinx/ni-77D4.dts b/arch/arm/boot/dts/xilinx/ni-77D4.dts index 571e48d34449f..4c9e32788fa29 100644 --- a/arch/arm/boot/dts/xilinx/ni-77D4.dts +++ b/arch/arm/boot/dts/xilinx/ni-77D4.dts @@ -4,13 +4,13 @@ / { model = "NI sbRIO-9637"; compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -39,8 +39,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -50,7 +48,7 @@ phy-handle = <&phy0>; phy-mode = "rgmii-id"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; @@ -61,7 +59,7 @@ reg = <0x0>; /* Interrupt on GPIO25. */ interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 diff --git a/arch/arm/boot/dts/xilinx/ni-77D5.dts b/arch/arm/boot/dts/xilinx/ni-77D5.dts index 0e983d48037b8..9ac70682c992a 100644 --- a/arch/arm/boot/dts/xilinx/ni-77D5.dts +++ b/arch/arm/boot/dts/xilinx/ni-77D5.dts @@ -4,13 +4,13 @@ / { model = "NI sbRIO-9627"; compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -49,8 +49,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -60,7 +58,7 @@ phy-handle = <&phy0>; phy-mode = "rgmii-id"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; @@ -71,7 +69,7 @@ reg = <0x0>; /* Interrupt on GPIO25, shared with phy1. */ interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 @@ -122,7 +120,7 @@ reg = <0x1>; /* Interrupt on GPIO25, shared with phy0. */ interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 @@ -176,7 +174,7 @@ phy-mode = "rgmii-id"; cdns,no_mdio_bus; emio-speed-gpios = <0>, - <&gpio 55 0>; + <&gpio0 55 0>; }; &sdhci0 { diff --git a/arch/arm/boot/dts/xilinx/ni-77D6.dts b/arch/arm/boot/dts/xilinx/ni-77D6.dts index c344069dec3c0..1f9ba5e003eb5 100644 --- a/arch/arm/boot/dts/xilinx/ni-77D6.dts +++ b/arch/arm/boot/dts/xilinx/ni-77D6.dts @@ -4,13 +4,13 @@ / { model = "NI sbRIO-9607"; compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -49,8 +49,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -60,7 +58,7 @@ phy-handle = <&phy0>; phy-mode = "rgmii-id"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; @@ -71,7 +69,7 @@ reg = <0x0>; /* Interrupt on GPIO25, shared with phy1. */ interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 @@ -122,7 +120,7 @@ reg = <0x1>; /* Interrupt on GPIO25, shared with phy0. */ interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 @@ -176,7 +174,7 @@ phy-mode = "rgmii-id"; cdns,no_mdio_bus; emio-speed-gpios = <0>, - <&gpio 55 0>; + <&gpio0 55 0>; }; &sdhci1 { diff --git a/arch/arm/boot/dts/xilinx/ni-7885.dts b/arch/arm/boot/dts/xilinx/ni-7885.dts index 661dc24a23baf..5a5450c9c2513 100644 --- a/arch/arm/boot/dts/xilinx/ni-7885.dts +++ b/arch/arm/boot/dts/xilinx/ni-7885.dts @@ -4,13 +4,13 @@ / { model = "NI ELVIS RIO CM"; compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -22,8 +22,6 @@ }; }; }; - }; - }; }; &ni_uart0 { diff --git a/arch/arm/boot/dts/xilinx/ni-793C.dts b/arch/arm/boot/dts/xilinx/ni-793C.dts index a2255627d113d..cf6e8d3671622 100644 --- a/arch/arm/boot/dts/xilinx/ni-793C.dts +++ b/arch/arm/boot/dts/xilinx/ni-793C.dts @@ -4,13 +4,13 @@ / { model = "NI ELVIS III"; compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -47,8 +47,6 @@ compatible = "truly,oel9m1027"; }; }; - }; - }; }; &gem0 { @@ -58,7 +56,7 @@ phy-handle = <&phy0>; phy-mode = "rgmii-id"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; @@ -69,7 +67,7 @@ reg = <0x0>; /* Interrupt on GPIO25, shared with phy1. */ interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 @@ -131,7 +129,7 @@ status = "okay"; transceiver = "RS-232"; emio-con-dio-multiplex-gpios = <0>, - <&gpio 56 0>; + <&gpio0 56 0>; }; &ni_uart1 { diff --git a/arch/arm/boot/dts/xilinx/ni-793x.dtsi b/arch/arm/boot/dts/xilinx/ni-793x.dtsi index 2317bdb927553..e293300c0a5b7 100644 --- a/arch/arm/boot/dts/xilinx/ni-793x.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-793x.dtsi @@ -2,22 +2,23 @@ / { compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - - leds-ni793x@4020F000 { - compatible = "ni,led-793x"; - reg = <0x4020F000 4>; - user1 { - label = "nilrt:user1:green"; - }; +&amba { + leds-ni793x@4020F000 { + compatible = "ni,led-793x"; + reg = <0x4020F000 4>; + user1 { + label = "nilrt:user1:green"; }; + }; +}; - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -43,8 +44,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -61,7 +60,7 @@ #size-cells = <0x0>; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; phy0: phy@0 { compatible = "micrel,KSZ9031","ethernet-phy-ieee802.3-c22"; @@ -69,7 +68,7 @@ reg = <0x0>; /* Interrupt on GPIO1. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ rxc-skew-ps = <0>; diff --git a/arch/arm/boot/dts/xilinx/ni-7AAE.dts b/arch/arm/boot/dts/xilinx/ni-7AAE.dts index b01fb7f7b45c2..16c9ef28b38eb 100644 --- a/arch/arm/boot/dts/xilinx/ni-7AAE.dts +++ b/arch/arm/boot/dts/xilinx/ni-7AAE.dts @@ -15,18 +15,18 @@ wlan1 { /* green */ label = "nilrt:wifi:primary"; - gpios = <&gpio 55 0>; + gpios = <&gpio0 55 0>; }; wlan2 { /* red */ label = "nilrt:wifi:secondary"; - gpios = <&gpio 56 0>; + gpios = <&gpio0 56 0>; }; }; +}; - amba@0 { - adc: adc@f8007100 { +&adc { xlnx,channels { #address-cells = <1>; #size-cells = <0>; @@ -71,19 +71,19 @@ reg = <12>; }; }; - }; +}; - smcc@e000e000 { - nand@e1000000 { - status = "disabled"; - }; - }; +&smcc { + nand@e1000000 { + status = "disabled"; + }; +}; - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -95,56 +95,54 @@ }; }; }; - }; - - i2c1: i2c@e0005000 { - status = "okay"; - }; - - i2c2: i2c@81000000 { - status = "okay"; - }; +}; - spi0: spi@e0006000 { - status = "okay"; - num-cs = <7>; - is-decoded-cs = <1>; - speed-hz = <200000000>; +&i2c1 { + status = "okay"; +}; - spidev@0 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <0>; - }; - spidev@1 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <1>; - }; - spidev@2 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <2>; - }; - spidev@3 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <3>; - }; - }; +&i2c2 { + status = "okay"; +}; - spi1: spi@e0007000 { - status = "okay"; - num-cs = <3>; - is-decoded-cs = <0>; - speed-hz = <200000000>; +&spi0 { + status = "okay"; + num-cs = <7>; + is-decoded-cs = <1>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + spidev@1 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <1>; + }; + spidev@2 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <2>; + }; + spidev@3 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <3>; + }; +}; - spidev@0 { - compatible = "spidev"; - spi-max-frequency = <2000000>; - reg = <0>; - }; - }; +&spi1 { + status = "okay"; + num-cs = <3>; + is-decoded-cs = <0>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; }; }; @@ -152,7 +150,7 @@ status = "okay"; phy-handle = <&phy0>; phy-mode = "rgmii-id"; - emio-speed-gpios = <&gpio 54 0>, + emio-speed-gpios = <&gpio0 54 0>, <0>; #address-cells = <0x1>; #size-cells = <0x0>; diff --git a/arch/arm/boot/dts/xilinx/ni-myrio.dtsi b/arch/arm/boot/dts/xilinx/ni-myrio.dtsi index 18ec8c1394c50..5194a062545f1 100644 --- a/arch/arm/boot/dts/xilinx/ni-myrio.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-myrio.dtsi @@ -2,20 +2,20 @@ / { compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; switches { wifi-switch { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -33,8 +33,6 @@ }; }; }; - }; - }; }; &sdhci0 { @@ -55,7 +53,7 @@ wl12xx: wl12xx@0 { compatible = "ti,wl1271"; reg = <2>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <15 0x4>; ref-clock-frequency = <38400000>; }; diff --git a/arch/arm/boot/dts/xilinx/ni-solbetter.dtsi b/arch/arm/boot/dts/xilinx/ni-solbetter.dtsi index 2e6bb345da74b..a1801ff93774c 100644 --- a/arch/arm/boot/dts/xilinx/ni-solbetter.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-solbetter.dtsi @@ -2,13 +2,13 @@ / { compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -47,8 +47,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -59,7 +57,7 @@ phy-mode = "rgmii-id"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; @@ -70,7 +68,7 @@ reg = <0x0>; /* Interrupt on GPIO1. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 @@ -121,7 +119,7 @@ reg = <0x1>; /* Interrupt on GPIO1, shared with phy0. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 @@ -175,7 +173,7 @@ phy-mode = "rgmii-id"; cdns,no_mdio_bus; emio-speed-gpios = <0>, - <&gpio 55 0>; + <&gpio0 55 0>; }; &ni_uart0 { diff --git a/arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi b/arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi index c81f7abb05376..b027ea61c9db6 100644 --- a/arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-solenetexp.dtsi @@ -2,13 +2,13 @@ / { compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -34,8 +34,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -45,7 +43,7 @@ phy-handle = <&phy0>; phy-mode = "rgmii-id"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; @@ -56,7 +54,7 @@ reg = <0x0>; /* Interrupt on GPIO1. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 diff --git a/arch/arm/boot/dts/xilinx/ni-solgood.dtsi b/arch/arm/boot/dts/xilinx/ni-solgood.dtsi index d65b51a80aac4..c826eb54b8840 100644 --- a/arch/arm/boot/dts/xilinx/ni-solgood.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-solgood.dtsi @@ -2,13 +2,13 @@ / { compatible = "ni,zynq", "xlnx,zynq-7000"; +}; - amba@0 { - i2c0: i2c@e0004000 { +&i2c0 { nicpld@40 { watchdogs { boot-watchdog { - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; }; }; @@ -37,8 +37,6 @@ ds3231_rtc@68 { status = "okay"; }; - }; - }; }; &gem0 { @@ -48,7 +46,7 @@ phy-handle = <&phy0>; phy-mode = "rgmii-id"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; @@ -59,7 +57,7 @@ reg = <0x0>; /* Interrupt on GPIO1. */ interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; - interrupt-parent = <&gpio>; + interrupt-parent = <&gpio0>; /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 From ee9f4d6a039557d847daf04d9022e99910dbc666 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Fri, 17 Jul 2026 19:12:34 -0500 Subject: [PATCH 90/97] dts: ni: Define NAND child address format Set the address and size cells on the NAND controller so the nand@0 reg property is parsed correctly. Signed-off-by: Chaitanya Vadrevu --- arch/arm/boot/dts/xilinx/ni-zynq.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi index d694aedc9c5d6..0f31351765ad8 100644 --- a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi @@ -156,6 +156,8 @@ &nfc0 { status = "okay"; + #address-cells = <1>; + #size-cells = <0>; nand@0 { reg = <0>; From edfc218397f336083d1a2920ee87ecea4d0297b3 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Tue, 21 Jul 2026 15:22:03 -0500 Subject: [PATCH 91/97] dts: ni: Disable inaccessible CoreSight devices The CoreSight blocks are not accessible on NI Zynq targets. Reading their AMBA identification registers hangs the SoC before any driver binds. Disable the nodes to allow the system to boot. Signed-off-by: Chaitanya Vadrevu --- arch/arm/boot/dts/xilinx/ni-zynq.dtsi | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi index 0f31351765ad8..f8a4850c093e1 100644 --- a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi @@ -172,3 +172,34 @@ arm,dynamic-clock-gating = <0>; arm,standby-mode = <0>; }; + +/* + * The CoreSight debug/trace macrocells are not accessible on NI Zynq-based + * targets: reading their AMBA peripheral-ID registers (done unconditionally + * by the kernel as soon as the device is created, before any driver binds) + * hangs the SoC indefinitely. Disable them so of_platform_populate() never + * touches them. + */ +&{/replicator} { + status = "disabled"; +}; + +&{/axi/etb@f8801000} { + status = "disabled"; +}; + +&{/axi/tpiu@f8803000} { + status = "disabled"; +}; + +&{/axi/funnel@f8804000} { + status = "disabled"; +}; + +&{/axi/ptm@f889c000} { + status = "disabled"; +}; + +&{/axi/ptm@f889d000} { + status = "disabled"; +}; From f71dcdb3babe250e85a36353393010457eb6c862 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Fri, 17 Jul 2026 19:39:34 -0500 Subject: [PATCH 92/97] net: macb: Replace removed PHY interrupt helpers phy_start_interrupts, phy_stop_interrupts have been removed in newer kernel. Replace them with phy_request_interrupt, phy_free_interrupt. Signed-off-by: Chaitanya Vadrevu --- drivers/net/ethernet/cadence/macb_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 475defef6ecf0..5824f9bbbcf8c 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4478,7 +4478,8 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void if (netif_running(bp->dev)) { dev_deactivate(bp->dev); macb_close(bp->dev); - phy_stop_interrupts(dev->phydev); + if (phy_interrupt_is_valid(dev->phydev)) + phy_free_interrupt(dev->phydev); phy_stop_machine_nolink(dev->phydev); } @@ -4501,7 +4502,8 @@ static int macb_fpga_notifier(struct notifier_block *nb, unsigned long val, void /* If the interface has been opened. */ if (netif_running(bp->dev)) { phy_start_machine(dev->phydev); - phy_start_interrupts(dev->phydev); + if (phy_interrupt_is_valid(dev->phydev)) + phy_request_interrupt(dev->phydev); macb_open(bp->dev); dev_activate(bp->dev); } From 8969762f3fcd839c11a11a3dcaa35afa154a1312 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Tue, 21 Jul 2026 14:40:51 -0500 Subject: [PATCH 93/97] misc: nizynqcpld: Update I2C driver callbacks Drop the unused device ID argument from probe and change remove to return void, matching the current I2C driver callback signatures. Signed-off-by: Chaitanya Vadrevu --- drivers/misc/nizynqcpld.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/misc/nizynqcpld.c b/drivers/misc/nizynqcpld.c index 5db065365893e..ce990ac4a6c76 100644 --- a/drivers/misc/nizynqcpld.c +++ b/drivers/misc/nizynqcpld.c @@ -1559,8 +1559,7 @@ static void myrio_wifi_sw_uninit(struct nizynqcpld *cpld) } } -static int nizynqcpld_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int nizynqcpld_probe(struct i2c_client *client) { struct nizynqcpld_desc *desc; struct nizynqcpld *cpld; @@ -1713,7 +1712,7 @@ static int nizynqcpld_probe(struct i2c_client *client, return err; } -static int nizynqcpld_remove(struct i2c_client *client) +static void nizynqcpld_remove(struct i2c_client *client) { struct nizynqcpld *cpld = i2c_get_clientdata(client); struct nizynqcpld_desc *desc = cpld->desc; @@ -1732,7 +1731,6 @@ static int nizynqcpld_remove(struct i2c_client *client) myrio_wifi_sw_uninit(cpld); kfree(cpld); - return 0; } static const struct of_device_id nizynqcpld_dt_ids[] = { From 38e45fa07fe90ad0bbe619bbbe03079fda476d6a Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Tue, 21 Jul 2026 15:34:48 -0500 Subject: [PATCH 94/97] serial: 8250_ni: Map MMIO registers before probe-time access UPF_IOREMAP defers mapping the register resource until the serial port is started. The NI 16550 driver accesses registers during probe to determine FIFO sizes and configure the PMR, before the port has been started. Map the MMIO resource with devm_ioremap() during probe and assign the result to port->membase so these early register accesses use a valid mapping. Signed-off-by: Chaitanya Vadrevu --- drivers/tty/serial/8250/8250_ni.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c index b77dbcbdef303..e9975dfb93d3c 100644 --- a/drivers/tty/serial/8250/8250_ni.c +++ b/drivers/tty/serial/8250/8250_ni.c @@ -243,7 +243,19 @@ static int ni16550_get_regs(struct platform_device *pdev, port->iotype = UPIO_MEM; port->mapbase = regs->start; port->mapsize = resource_size(regs); - port->flags |= UPF_IOREMAP; + + /* + * Map the registers here (rather than relying on the generic + * UPF_IOREMAP deferred-mapping mechanism, which only ioremaps + * when the port is started) because this driver reads + * hardware registers (FIFO sizes, PMR, etc.) directly during + * probe(), before the port is ever started. + */ + port->membase = devm_ioremap(&pdev->dev, regs->start, + resource_size(regs)); + if (!port->membase) + return dev_err_probe(&pdev->dev, -ENOMEM, + "cannot map registers\n"); return 0; default: From b5701b6cc871eb323eb4f66077df5696e263ace4 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Mon, 27 Jul 2026 18:33:29 -0500 Subject: [PATCH 95/97] nati_zynq_defconfig: Refresh for Linux 6.18 Port remaining defconfig changes from 4.14 kernel. Refresh it against Linux 6.18 while retaining the features required by NI Zynq targets. Enable PREEMPT_RT, RCU callback offloading, NI platform drivers, and the networking, USB, storage, filesystem options, etc. Regenerate the defconfig to account for current symbols and dependencies. Signed-off-by: Chaitanya Vadrevu --- arch/arm/configs/nati_zynq_defconfig | 122 ++++++++++++++++++++------- 1 file changed, 92 insertions(+), 30 deletions(-) diff --git a/arch/arm/configs/nati_zynq_defconfig b/arch/arm/configs/nati_zynq_defconfig index 9f1004d03889a..b83624192e9f8 100644 --- a/arch/arm/configs/nati_zynq_defconfig +++ b/arch/arm/configs/nati_zynq_defconfig @@ -1,7 +1,13 @@ CONFIG_LOCALVERSION="-ni" CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_JIT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -10,13 +16,15 @@ CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSFS_SYSCALL=y +CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y +CONFIG_ARCH_VEXPRESS=y CONFIG_ARCH_ZYNQ=y CONFIG_ARM_ERRATA_754322=y CONFIG_ARM_ERRATA_764369=y CONFIG_ARM_ERRATA_775420=y CONFIG_SMP=y +CONFIG_PREEMPT_RT=y CONFIG_HIGHMEM=y CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" CONFIG_VFP=y @@ -24,14 +32,14 @@ CONFIG_NEON=y # CONFIG_SUSPEND is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPAT_BRK is not set # CONFIG_COMPACTION is not set -CONFIG_CMA=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=m CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y @@ -53,9 +61,11 @@ CONFIG_IP_PIMSM_V2=y CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m +CONFIG_IPV6=m CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_EVENTS=y @@ -74,6 +84,7 @@ CONFIG_NF_CT_NETLINK=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_CONNMARK=m CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LOG=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m @@ -107,19 +118,17 @@ CONFIG_NETFILTER_XT_MATCH_QUOTA=m CONFIG_NETFILTER_XT_MATCH_RATEEST=m CONFIG_NETFILTER_XT_MATCH_REALM=m CONFIG_NETFILTER_XT_MATCH_RECENT=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m CONFIG_NETFILTER_XT_MATCH_STATE=m CONFIG_NETFILTER_XT_MATCH_STATISTIC=m CONFIG_NETFILTER_XT_MATCH_STRING=m CONFIG_NETFILTER_XT_MATCH_TCPMSS=m CONFIG_NETFILTER_XT_MATCH_TIME=m CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_NF_REJECT_IPV4=m +CONFIG_NETFILTER_XT_TARGET_LED=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_TTL=m -CONFIG_NF_REJECT_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -129,6 +138,8 @@ CONFIG_IP6_NF_MATCH_HL=m CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_MH=m CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP_SCTP=m +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE=y CONFIG_L2TP=m CONFIG_L2TP_V3=y CONFIG_L2TP_IP=m @@ -136,6 +147,7 @@ CONFIG_L2TP_ETH=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_NET_SCHED=y +CONFIG_NET_SCH_NETEM=m CONFIG_CAN=y CONFIG_BT=m CONFIG_BT_HCIBTUSB=m @@ -149,6 +161,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_RESERVE_END=524288 CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -158,18 +171,28 @@ CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_PL35X=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_GLUEBI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_NI793X=y +CONFIG_NIZYNQ_CPLD=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_FPGA_PERIPHERAL=y CONFIG_SRAM=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT25=y -CONFIG_EEPROM_93CX6=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_MD=y +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m CONFIG_NETDEVICES=y +CONFIG_BONDING=m CONFIG_TUN=y CONFIG_MACB=y # CONFIG_NET_VENDOR_CIRRUS is not set @@ -182,7 +205,7 @@ CONFIG_MACB=y # CONFIG_NET_VENDOR_QUALCOMM is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set -# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_SMSC911X=m # CONFIG_NET_VENDOR_STMICRO is not set # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set @@ -190,6 +213,7 @@ CONFIG_MARVELL_PHY=y CONFIG_MICREL_PHY=y CONFIG_SMSC_PHY=y CONFIG_VITESSE_PHY=y +CONFIG_LED_TRIGGER_PHY=y CONFIG_MDIO_BITBANG=y CONFIG_PPP=m CONFIG_PPP_BSDCOMP=m @@ -197,6 +221,10 @@ CONFIG_PPP_DEFLATE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m CONFIG_USB_NET_DRIVERS=m +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m CONFIG_USB_RTL8152=m CONFIG_USB_USBNET=m CONFIG_USB_NET_CDC_EEM=m @@ -205,7 +233,18 @@ CONFIG_USB_NET_SMSC95XX=m CONFIG_USB_NET_PLUSB=m CONFIG_USB_NET_RNDIS_HOST=m CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_USB_NET_CH9200=m CONFIG_ATH9K=m +CONFIG_CARL9170=m +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m +CONFIG_ATH6KL_SILEX_FIRMWARE=y +CONFIG_AR5523=m +CONFIG_AT76C50X_USB=m +CONFIG_MT7601U=m CONFIG_RT2X00=m CONFIG_RT2500USB=m CONFIG_RT73USB=m @@ -213,55 +252,76 @@ CONFIG_RT2800USB=m CONFIG_RT2800USB_RT53XX=y CONFIG_RT2800USB_RT55XX=y CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RTL8187=m CONFIG_RTL8192CU=m CONFIG_WL12XX=m CONFIG_WLCORE_SDIO=m +CONFIG_ZD1211RW=m CONFIG_INPUT_SPARSEKMAP=y CONFIG_INPUT_EVDEV=y +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_8250=y # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=9 +CONFIG_SERIAL_8250_NI=y CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_XILINX_PS_UART=y CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y # CONFIG_HW_RANDOM is not set +CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_CADENCE=y CONFIG_I2C_XILINX=y CONFIG_SPI=y CONFIG_SPI_CADENCE=y CONFIG_SPI_SPIDEV=y -CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y CONFIG_GPIO_ZYNQ=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m +CONFIG_AUXDISPLAY=y +CONFIG_SH1107=m +CONFIG_OEL9M1027=m CONFIG_FB=y -CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_HIDRAW=y CONFIG_HID_MICROSOFT=m CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_EHCI_HCD=y -CONFIG_USB_ACM=m CONFIG_USB_STORAGE=m -CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA=m CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y -CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CONSOLE=y +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m CONFIG_USB_SERIAL_CP210X=m CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m CONFIG_USB_SERIAL_PL2303=m -CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_NOP_USB_XCEIV=m CONFIG_USB_ULPI=y -CONFIG_USB_GADGET=y -CONFIG_USB_ETH=y +CONFIG_USB_GADGET=m +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set CONFIG_USB_ETH_EEM=y CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_OF_ARASAN=y @@ -271,23 +331,30 @@ CONFIG_RTC_DRV_DS3232=y CONFIG_DMADEVICES=y CONFIG_PL330_DMA=y CONFIG_COMMON_CLK_SI570=y -CONFIG_ARM_GT_INITIAL_PRESCALER_VAL=2 CONFIG_MEMORY=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_SECURITY=y CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y # CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=m CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y CONFIG_UBIFS_FS=y CONFIG_SQUASHFS=m CONFIG_SQUASHFS_XATTR=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V4=m +CONFIG_NFS_V4_1=y CONFIG_CIFS=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y @@ -297,17 +364,12 @@ CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y # CONFIG_INTEGRITY is not set CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_CRC32C=y -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y +CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y -CONFIG_FRAME_WARN=1024 CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x0 +CONFIG_PANIC_TIMEOUT=30 CONFIG_RCU_CPU_STALL_TIMEOUT=60 From 20542ef6613408d6e4f36c20cd1696d508d2ea72 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Tue, 21 Jul 2026 19:42:29 -0500 Subject: [PATCH 96/97] nati*defconfig: Enable CONFIG_RCU_NOCB_CPU_DEFAULT_ALL Port this change from commit [1] for nati_x86_64_defconfig. NILRT is currently booted with `rcu_nocbs=all` kernel parameter set. Enable CONFIG_RCU_NOCB_CPU_DEFAULT_ALL which will allow us to remove the boot option in the future. Note that it is still possible to override this option using rcu_nocbs or nohz_full boot parameters. [1]: 4d93b1f ("nati_x86_64_defconfig: enable CONFIG_RCU_NOCB_CPU_DEFAULT_ALL") Signed-off-by: Chaitanya Vadrevu --- arch/arm/configs/nati_bluefin_defconfig | 1 + arch/arm/configs/nati_slsc_defconfig | 1 + arch/arm/configs/nati_zynq_defconfig | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm/configs/nati_bluefin_defconfig b/arch/arm/configs/nati_bluefin_defconfig index 5ab4320d36ebb..fb049f1d8af57 100644 --- a/arch/arm/configs/nati_bluefin_defconfig +++ b/arch/arm/configs/nati_bluefin_defconfig @@ -209,3 +209,4 @@ CONFIG_DYNAMIC_DEBUG=y CONFIG_FRAME_WARN=1024 CONFIG_MAGIC_SYSRQ=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y diff --git a/arch/arm/configs/nati_slsc_defconfig b/arch/arm/configs/nati_slsc_defconfig index 34d474f347025..d90943e290e35 100644 --- a/arch/arm/configs/nati_slsc_defconfig +++ b/arch/arm/configs/nati_slsc_defconfig @@ -223,3 +223,4 @@ CONFIG_DYNAMIC_DEBUG=y CONFIG_FRAME_WARN=1024 CONFIG_MAGIC_SYSRQ=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y diff --git a/arch/arm/configs/nati_zynq_defconfig b/arch/arm/configs/nati_zynq_defconfig index b83624192e9f8..40d1de56e1fde 100644 --- a/arch/arm/configs/nati_zynq_defconfig +++ b/arch/arm/configs/nati_zynq_defconfig @@ -373,3 +373,4 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x0 CONFIG_PANIC_TIMEOUT=30 CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y From cc2b6fcae196fcf5cdba8468b1228b61b7cfe513 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Fri, 17 Jul 2026 20:31:49 -0500 Subject: [PATCH 97/97] ni-pkg: Add NI FIT image packaging target Ported from 4.14 and updated to work on 6.18 kernel. Signed-off-by: Chaitanya Vadrevu --- .gitignore | 5 ++ Makefile | 2 +- scripts/Makefile.package | 9 +++ scripts/package/buildnipkg | 148 +++++++++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 scripts/package/buildnipkg diff --git a/.gitignore b/.gitignore index 86a1ba0d90353..64930994bd8ec 100644 --- a/.gitignore +++ b/.gitignore @@ -96,6 +96,11 @@ modules.order # /tar-install/ +# +# ni specific install directory +# +/ni-install/ + # # pacman files (make pacman-pkg) # diff --git a/Makefile b/Makefile index 7f5abef39fd38..36cc213411ffd 100644 --- a/Makefile +++ b/Makefile @@ -1592,7 +1592,7 @@ endif # CONFIG_MODULES CLEAN_FILES += vmlinux.symvers modules-only.symvers \ modules.builtin modules.builtin.modinfo modules.nsdeps \ modules.builtin.ranges vmlinux.o.map vmlinux.unstripped \ - compile_commands.json rust/test \ + compile_commands.json rust/test ni-install \ rust-project.json .vmlinux.objs .vmlinux.export.c \ .builtin-dtbs-list .builtin-dtbs.S diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 74bcb9e7f7a45..332e15b8dc115 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -189,6 +189,14 @@ tar-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar tar%-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar.% FORCE @: +# ni-pkg - generate an NI Zynq FIT image for all device models +# --------------------------------------------------------------------------- + +PHONY += ni-pkg +ni-pkg: FORCE + +$(Q)$(MAKE) -f $(srctree)/Makefile Image modules dtbs + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/package/buildnipkg + # perf-tar*-src-pkg - generate a source tarball with perf source # --------------------------------------------------------------------------- @@ -245,6 +253,7 @@ help: @echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball' @echo ' tarxz-pkg - Build the kernel as a xz compressed tarball' @echo ' tarzst-pkg - Build the kernel as a zstd compressed tarball' + @echo ' ni-pkg - Build the kernel and needed files for NI targets' @echo ' perf-tar-src-pkg - Build the perf source tarball with no compression' @echo ' perf-targz-src-pkg - Build the perf source tarball with gzip compression' @echo ' perf-tarbz2-src-pkg - Build the perf source tarball with bz2 compression' diff --git a/scripts/package/buildnipkg b/scripts/package/buildnipkg new file mode 100644 index 0000000000000..2999116012c80 --- /dev/null +++ b/scripts/package/buildnipkg @@ -0,0 +1,148 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +set -eu + +if [ "${ARCH:-}" != "arm" ]; then + echo "error: ni-pkg requires ARCH=arm" >&2 + exit 1 +fi + +mkimage="${MKIMAGE:-mkimage}" +if ! command -v "${mkimage}" >/dev/null 2>&1; then + echo "error: ${mkimage} is required to build the NI FIT image" >&2 + exit 1 +fi + +bootdir="${objtree}/ni-install/arm/boot" +kernel="${objtree}/arch/arm/boot/Image" +dtsdir="${objtree}/arch/arm/boot/dts/xilinx" + +rm -rf -- "${bootdir}" +mkdir -p -- "${bootdir}" + +cp -- "${kernel}" "${bootdir}/vmlinux" +gzip -f -9 "${bootdir}/vmlinux" + +cat > "${bootdir}/bootscript.txt" <<'EOF' + +if test ${DeviceCode} -eq 0x7AAE; then + setenv set_args 'setenv bootargs ${consoleparam} root=/dev/mmcblk0p3 rw ${usb_gadget_args} rcu_nocbs=all rootdelay=1 $othbootargs' +else + setenv set_args 'setenv bootargs ${consoleparam} $mtdparts ubi.mtd=boot-config ubi.mtd=root root=ubi1:rootfs rw rootfstype=ubifs kthreadd_pri=25 ksoftirqd_pri=8 irqthread_pri=15 ${usb_gadget_args} $othbootargs' +fi + +# cRIO-9068 doesn't have USB gadget, so skip it on that device +if test ${DeviceCode} != 0x76D6; then + usb_gadget_args="g_ether.idVendor=${USBVendorID} g_ether.idProduct=${USBProductID} g_ether.iProduct=\"${USBProduct} [${hostname}]\" g_ether.iSerialNumber=${serial#} g_ether.dev_addr=${usbgadgetethaddr} g_ether.bcdDevice=${USBDevice}" +fi + +if test -n \"$bootscriptenvrun\" ; then run bootscriptenvrun; fi + +silent_tmp=${silent} +setenv silent +echo "Booting LabVIEW RT (custom kernel)..." +setenv silent ${silent_tmp} + +run set_args +bootm ${loadaddr}#config_${DeviceCode} +EOF + +dtb_list="" +device_codes="" +for dtb_path in "${dtsdir}"/ni-*.dtb; do + [ -e "${dtb_path}" ] || continue + dtb_name=$(basename "${dtb_path}") + devcode=${dtb_name#ni-} + devcode=${devcode%.dtb} + cp -- "${dtb_path}" "${bootdir}/${dtb_name}" + dtb_list="${dtb_list} ${devcode}" + device_codes="${device_codes}0x${devcode} " +done + +if [ -z "${dtb_list}" ]; then + echo "error: no ni-*.dtb files found in ${dtsdir}" >&2 + exit 1 +fi + +timestamp=$(date +%F_%R) +cat > "${bootdir}/linux.its" <; + + images { + kernel@1 { + description = "Linux kernel"; + version = "populate-kernel-export-version"; + data = /incbin/("./vmlinux.gz"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + load = <0x00008000>; + entry = <0x00008000>; + hash@1 { + algo = "crc32"; + }; + }; +EOF + +for devcode in ${dtb_list}; do + cat >> "${bootdir}/linux.its" <> "${bootdir}/linux.its" <> "${bootdir}/linux.its" <> "${bootdir}/linux.its" <