diff options
Diffstat (limited to 'meta-phosphor/common/recipes-kernel')
14 files changed, 2 insertions, 4697 deletions
diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc.inc b/meta-phosphor/common/recipes-kernel/linux/linux-obmc.inc index fe07680c0..78da46967 100644 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc.inc +++ b/meta-phosphor/common/recipes-kernel/linux/linux-obmc.inc @@ -10,18 +10,6 @@ KSRC ?= "git://github.com/openbmc/linux;protocol=git;branch=${KBRANCH}" SRC_URI = "${KSRC}" SRC_URI += "file://phosphor-gpio-keys.scc" SRC_URI += "file://phosphor-gpio-keys.cfg" -SRC_URI += "file://0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch" -SRC_URI += "file://linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch" -SRC_URI += "file://linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch" -SRC_URI += "file://linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch" -SRC_URI += "file://linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch" -SRC_URI += "file://linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch" -SRC_URI += "file://linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch" -SRC_URI += "file://linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch" -SRC_URI += "file://linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch" -SRC_URI += "file://0001-arm-dts-aspeed-Add-FSI-devices.patch" -SRC_URI += "file://0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch" -SRC_URI += "file://v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch" LINUX_VERSION_EXTENSION ?= "-${SRCREV}" diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-arm-dts-aspeed-Add-FSI-devices.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-arm-dts-aspeed-Add-FSI-devices.patch deleted file mode 100644 index 3b49685c8..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-arm-dts-aspeed-Add-FSI-devices.patch +++ /dev/null @@ -1,507 +0,0 @@ -From e45cd4677a36eb759537f59c5f5bcf46b91728b3 Mon Sep 17 00:00:00 2001 -From: "Edward A. James" <eajames@us.ibm.com> -Date: Mon, 15 May 2017 11:02:48 -0500 -Subject: [PATCH linux dev-4.10] arm: dts: aspeed: Add FSI devices - -using Jeremy's new bindings - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts | 75 ++++++++++ - arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts | 181 +++++++++++++++++++++++ - arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts | 181 +++++++++++++++++++++++ - 3 files changed, 437 insertions(+) - -diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts -index b4faa1d..6f23ce3 100644 ---- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts -+++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts -@@ -85,12 +85,87 @@ - - gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; -+ #address-cells = <2>; -+ #size-cells = <0>; - - clock-gpios = <&gpio ASPEED_GPIO(A, 4) GPIO_ACTIVE_HIGH>; - data-gpios = <&gpio ASPEED_GPIO(A, 5) GPIO_ACTIVE_HIGH>; - mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>; - enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; - trans-gpios = <&gpio ASPEED_GPIO(H, 6) GPIO_ACTIVE_HIGH>; -+ -+ cfam@0,0 { -+ reg = <0 0>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ i2c-master@1800 { -+ compatible = "ibm,fsi-i2c-master"; -+ reg = <0x1800 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ port = <0>; -+ }; -+ -+ port@1 { -+ port = <1>; -+ }; -+ -+ port@2 { -+ port = <2>; -+ }; -+ -+ port@3 { -+ port = <3>; -+ }; -+ -+ port@4 { -+ port = <4>; -+ }; -+ -+ port@5 { -+ port = <5>; -+ }; -+ -+ port@6 { -+ port = <6>; -+ }; -+ -+ port@7 { -+ port = <7>; -+ }; -+ -+ port@8 { -+ port = <8>; -+ }; -+ -+ port@9 { -+ port = <9>; -+ }; -+ -+ port@10 { -+ port = <10>; -+ }; -+ -+ port@11 { -+ port = <11>; -+ }; -+ -+ port@12 { -+ port = <12>; -+ }; -+ -+ port@13 { -+ port = <13>; -+ }; -+ -+ port@14 { -+ port = <14>; -+ }; -+ }; -+ }; - }; - }; - -diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts -index f20aaf4..5d83a76 100644 ---- a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts -+++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts -@@ -65,6 +65,8 @@ - - gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; -+ #address-cells = <2>; -+ #size-cells = <0>; - - status = "okay"; - -@@ -73,6 +75,185 @@ - mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>; - enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; - trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>; -+ -+ cfam@0,0 { -+ reg = <0 0>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ i2c-master@1800 { -+ compatible = "ibm,fsi-i2c-master"; -+ reg = <0x1800 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ port = <0>; -+ }; -+ -+ port@1 { -+ port = <1>; -+ }; -+ -+ port@2 { -+ port = <2>; -+ }; -+ -+ port@3 { -+ port = <3>; -+ }; -+ -+ port@4 { -+ port = <4>; -+ }; -+ -+ port@5 { -+ port = <5>; -+ }; -+ -+ port@6 { -+ port = <6>; -+ }; -+ -+ port@7 { -+ port = <7>; -+ }; -+ -+ port@8 { -+ port = <8>; -+ }; -+ -+ port@9 { -+ port = <9>; -+ }; -+ -+ port@10 { -+ port = <10>; -+ }; -+ -+ port@11 { -+ port = <11>; -+ }; -+ -+ port@12 { -+ port = <12>; -+ }; -+ -+ port@13 { -+ port = <13>; -+ }; -+ -+ port@14 { -+ port = <14>; -+ }; -+ }; -+ -+ sbefifo@2400 { -+ compatible = "ibm,p9-sbefifo"; -+ reg = <0x2400 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ occ@1 { -+ compatible = "ibm,p9-occ"; -+ reg = <1>; -+ }; -+ }; -+ -+ hub@3400 { -+ compatible = "fsi-master-hub"; -+ reg = <0x3400 0x400>; -+ #address-cells = <2>; -+ #size-cells = <0>; -+ -+ cfam@1,0 { -+ reg = <1 0>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ i2c-master@1800 { -+ compatible = -+ "ibm,fsi-i2c-master"; -+ reg = <0x1800 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ port = <0>; -+ }; -+ -+ port@1 { -+ port = <1>; -+ }; -+ -+ port@2 { -+ port = <2>; -+ }; -+ -+ port@3 { -+ port = <3>; -+ }; -+ -+ port@4 { -+ port = <4>; -+ }; -+ -+ port@5 { -+ port = <5>; -+ }; -+ -+ port@6 { -+ port = <6>; -+ }; -+ -+ port@7 { -+ port = <7>; -+ }; -+ -+ port@8 { -+ port = <8>; -+ }; -+ -+ port@9 { -+ port = <9>; -+ }; -+ -+ port@10 { -+ port = <10>; -+ }; -+ -+ port@11 { -+ port = <11>; -+ }; -+ -+ port@12 { -+ port = <12>; -+ }; -+ -+ port@13 { -+ port = <13>; -+ }; -+ -+ port@14 { -+ port = <14>; -+ }; -+ }; -+ -+ sbefifo@2400 { -+ compatible = "ibm,p9-sbefifo"; -+ reg = <0x2400 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ occ@2 { -+ compatible = -+ "ibm,p9-occ"; -+ reg = <2>; -+ }; -+ }; -+ }; -+ }; -+ }; - }; - - iio-hwmon { -diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts -index b5c4c0f..6f36e56 100644 ---- a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts -+++ b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts -@@ -77,6 +77,8 @@ - - gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; -+ #address-cells = <2>; -+ #size-cells = <0>; - - status = "okay"; - -@@ -85,6 +87,185 @@ - trans-gpios = <&gpio ASPEED_GPIO(O, 6) GPIO_ACTIVE_HIGH>; - enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; - mux-gpios = <&gpio ASPEED_GPIO(P, 6) GPIO_ACTIVE_HIGH>; -+ -+ cfam@0,0 { -+ reg = <0 0>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ i2c-master@1800 { -+ compatible = "ibm,fsi-i2c-master"; -+ reg = <0x1800 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ port = <0>; -+ }; -+ -+ port@1 { -+ port = <1>; -+ }; -+ -+ port@2 { -+ port = <2>; -+ }; -+ -+ port@3 { -+ port = <3>; -+ }; -+ -+ port@4 { -+ port = <4>; -+ }; -+ -+ port@5 { -+ port = <5>; -+ }; -+ -+ port@6 { -+ port = <6>; -+ }; -+ -+ port@7 { -+ port = <7>; -+ }; -+ -+ port@8 { -+ port = <8>; -+ }; -+ -+ port@9 { -+ port = <9>; -+ }; -+ -+ port@10 { -+ port = <10>; -+ }; -+ -+ port@11 { -+ port = <11>; -+ }; -+ -+ port@12 { -+ port = <12>; -+ }; -+ -+ port@13 { -+ port = <13>; -+ }; -+ -+ port@14 { -+ port = <14>; -+ }; -+ }; -+ -+ sbefifo@2400 { -+ compatible = "ibm,p9-sbefifo"; -+ reg = <0x2400 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ occ@1 { -+ compatible = "ibm,p9-occ"; -+ reg = <1>; -+ }; -+ }; -+ -+ hub@3400 { -+ compatible = "fsi-master-hub"; -+ reg = <0x3400 0x400>; -+ #address-cells = <2>; -+ #size-cells = <0>; -+ -+ cfam@1,0 { -+ reg = <1 0>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ i2c-master@1800 { -+ compatible = -+ "ibm,fsi-i2c-master"; -+ reg = <0x1800 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ port = <0>; -+ }; -+ -+ port@1 { -+ port = <1>; -+ }; -+ -+ port@2 { -+ port = <2>; -+ }; -+ -+ port@3 { -+ port = <3>; -+ }; -+ -+ port@4 { -+ port = <4>; -+ }; -+ -+ port@5 { -+ port = <5>; -+ }; -+ -+ port@6 { -+ port = <6>; -+ }; -+ -+ port@7 { -+ port = <7>; -+ }; -+ -+ port@8 { -+ port = <8>; -+ }; -+ -+ port@9 { -+ port = <9>; -+ }; -+ -+ port@10 { -+ port = <10>; -+ }; -+ -+ port@11 { -+ port = <11>; -+ }; -+ -+ port@12 { -+ port = <12>; -+ }; -+ -+ port@13 { -+ port = <13>; -+ }; -+ -+ port@14 { -+ port = <14>; -+ }; -+ }; -+ -+ sbefifo@2400 { -+ compatible = "ibm,p9-sbefifo"; -+ reg = <0x2400 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ occ@2 { -+ compatible = -+ "ibm,p9-occ"; -+ reg = <2>; -+ }; -+ }; -+ }; -+ }; -+ }; - }; - - iio-hwmon { --- -1.8.3.1 - diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch deleted file mode 100644 index 6fdfe93cd..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch +++ /dev/null @@ -1,236 +0,0 @@ -From 8f10daa0cc99ce286b9a2f249f1fa0a245d4fc03 Mon Sep 17 00:00:00 2001 -From: "Edward A. James" <eajames@us.ibm.com> -Date: Wed, 17 May 2017 09:46:19 -0500 -Subject: [PATCH] fsi: Match fsi slaves & engines to available device tree - nodes - -This change populates device tree nodes for scanned FSI slaves and -engines. If the master populates ->of_node of the FSI master device, -we'll look for matching slaves, and under those slaves we'll look for -matching engines. - -This means that FSI drivers will have their ->of_node pointer populated -if there's a corresponding DT node, which they can use for further -device discover. - -Presence of device tree nodes is optional, and only required for -fsi device drivers that need extra properties, or subordinate devices, -to be enumerated. - -Signed-off-by: Jeremy Kerr <jk@ozlabs.org> -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/fsi/fsi-core.c | 99 +++++++++++++++++++++++++++++++++++++++++++ - drivers/fsi/fsi-master-gpio.c | 4 ++ - drivers/fsi/fsi-master-hub.c | 4 ++ - 3 files changed, 107 insertions(+) - -diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c -index 7ca5b74..71e3af9 100644 ---- a/drivers/fsi/fsi-core.c -+++ b/drivers/fsi/fsi-core.c -@@ -17,6 +17,7 @@ - #include <linux/fsi.h> - #include <linux/idr.h> - #include <linux/module.h> -+#include <linux/of.h> - #include <linux/slab.h> - - #include "fsi-master.h" -@@ -125,6 +126,7 @@ static void fsi_device_release(struct device *_device) - { - struct fsi_device *device = to_fsi_dev(_device); - -+ of_node_put(device->dev.of_node); - kfree(device); - } - -@@ -337,6 +339,57 @@ extern void fsi_slave_release_range(struct fsi_slave *slave, - { - } - -+static bool fsi_device_node_matches(struct device *dev, struct device_node *np, -+ uint32_t addr, uint32_t size) -+{ -+ unsigned int len, na, ns; -+ const __be32 *prop; -+ uint32_t psize; -+ -+ na = of_n_addr_cells(np); -+ ns = of_n_size_cells(np); -+ -+ if (na != 1 || ns != 1) -+ return false; -+ -+ prop = of_get_property(np, "reg", &len); -+ if (!prop || len != 8) -+ return false; -+ -+ if (of_read_number(prop, 1) != addr) -+ return false; -+ -+ psize = of_read_number(prop + 1, 1); -+ if (psize != size) { -+ dev_warn(dev, -+ "node %s matches probed address, but not size (got 0x%x, expected 0x%x)", -+ of_node_full_name(np), psize, size); -+ } -+ -+ return true; -+} -+ -+/* Find a matching node for the slave engine at @address, using @size bytes -+ * of space. Returns NULL if not found, or a matching node with refcount -+ * already incremented. -+ */ -+static struct device_node *fsi_device_find_of_node(struct fsi_device *dev) -+{ -+ struct device_node *parent, *np; -+ -+ parent = dev_of_node(&dev->slave->dev); -+ if (!parent) -+ return NULL; -+ -+ for_each_child_of_node(parent, np) { -+ if (fsi_device_node_matches(&dev->dev, np, -+ dev->addr, dev->size)) -+ return np; -+ } -+ -+ return NULL; -+} -+ - static int fsi_slave_scan(struct fsi_slave *slave) - { - uint32_t engine_addr; -@@ -405,6 +458,7 @@ static int fsi_slave_scan(struct fsi_slave *slave) - dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x", - slave->master->idx, slave->link, - slave->id, i - 2); -+ dev->dev.of_node = fsi_device_find_of_node(dev); - - rc = device_register(&dev->dev); - if (rc) { -@@ -561,9 +615,53 @@ static void fsi_slave_release(struct device *dev) - { - struct fsi_slave *slave = to_fsi_slave(dev); - -+ of_node_put(dev->of_node); - kfree(slave); - } - -+static bool fsi_slave_node_matches(struct device_node *np, -+ int link, uint8_t id) -+{ -+ unsigned int len, na, ns; -+ const __be32 *prop; -+ -+ na = of_n_addr_cells(np); -+ ns = of_n_size_cells(np); -+ -+ /* Ensure we have the correct format for addresses and sizes in -+ * reg properties -+ */ -+ if (na != 2 || ns != 0) -+ return false; -+ -+ prop = of_get_property(np, "reg", &len); -+ if (!prop || len != 8) -+ return false; -+ -+ return (of_read_number(prop, 1) == link) && -+ (of_read_number(prop + 1, 1) == id); -+} -+ -+/* Find a matching node for the slave at (link, id). Returns NULL if none -+ * found, or a matching node with refcount already incremented. -+ */ -+static struct device_node *fsi_slave_find_of_node(struct fsi_master *master, -+ int link, uint8_t id) -+{ -+ struct device_node *parent, *np; -+ -+ parent = dev_of_node(&master->dev); -+ if (!parent) -+ return NULL; -+ -+ for_each_child_of_node(parent, np) { -+ if (fsi_slave_node_matches(np, link, id)) -+ return np; -+ } -+ -+ return NULL; -+} -+ - static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id) - { - uint32_t chip_id, llmode; -@@ -626,6 +724,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id) - - slave->master = master; - slave->dev.parent = &master->dev; -+ slave->dev.of_node = fsi_slave_find_of_node(master, link, id); - slave->dev.release = fsi_slave_release; - slave->link = link; - slave->id = id; -diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c -index ef209ef..2a6a812 100644 ---- a/drivers/fsi/fsi-master-gpio.c -+++ b/drivers/fsi/fsi-master-gpio.c -@@ -5,6 +5,7 @@ - #include <linux/platform_device.h> - #include <linux/gpio/consumer.h> - #include <linux/module.h> -+#include <linux/of.h> - #include <linux/delay.h> - #include <linux/fsi.h> - #include <linux/device.h> -@@ -529,6 +530,7 @@ static int fsi_master_gpio_probe(struct platform_device *pdev) - - master->dev = &pdev->dev; - master->master.dev.parent = master->dev; -+ master->master.dev.of_node = of_node_get(dev_of_node(master->dev)); - master->master.dev.release = fsi_master_gpio_release; - - gpio = devm_gpiod_get(&pdev->dev, "clock", 0); -@@ -598,6 +600,8 @@ static int fsi_master_gpio_remove(struct platform_device *pdev) - devm_gpiod_put(&pdev->dev, master->gpio_mux); - fsi_master_unregister(&master->master); - -+ of_node_put(master->master.dev.of_node); -+ - return 0; - } - -diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c -index 133b9bf..3223a67 100644 ---- a/drivers/fsi/fsi-master-hub.c -+++ b/drivers/fsi/fsi-master-hub.c -@@ -16,6 +16,7 @@ - #include <linux/delay.h> - #include <linux/fsi.h> - #include <linux/module.h> -+#include <linux/of.h> - #include <linux/slab.h> - - #include "fsi-master.h" -@@ -274,6 +275,7 @@ static int hub_master_probe(struct device *dev) - - hub->master.dev.parent = dev; - hub->master.dev.release = hub_master_release; -+ hub->master.dev.of_node = of_node_get(dev_of_node(dev)); - - hub->master.n_links = links; - hub->master.read = hub_master_read; -@@ -302,6 +304,8 @@ static int hub_master_remove(struct device *dev) - - fsi_master_unregister(&hub->master); - fsi_slave_release_range(hub->upstream->slave, hub->addr, hub->size); -+ of_node_put(hub->master.dev.of_node); -+ - return 0; - } - --- -1.8.3.1 - diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch deleted file mode 100644 index 8ade1be61..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-hwmon-Add-support-for-MAX31785-intelligent-fan-contr.patch +++ /dev/null @@ -1,821 +0,0 @@ -From b3991e27b26930ef46206dad17715d8ac2f38a4e Mon Sep 17 00:00:00 2001 -From: Timothy Pearson <tpearson@raptorengineering.com> -Date: Tue, 11 Oct 2016 09:35:51 -0500 -Subject: [PATCH] hwmon: Add support for MAX31785 intelligent fan controller - -Add a basic driver for the MAX31785, focusing on the fan control -features but ignoring the temperature and voltage monitoring -features of the device. - -This driver supports all fan control modes and tachometer / PWM -readback where applicable. - -Signed-off-by: Timothy Pearson <tpearson@raptorengineering.com> -Signed-off-by: Joel Stanley <joel@jms.id.au> ---- - Documentation/hwmon/max31785 | 36 +++ - drivers/hwmon/Kconfig | 10 + - drivers/hwmon/Makefile | 1 + - drivers/hwmon/max31785.c | 714 +++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 761 insertions(+) - create mode 100644 Documentation/hwmon/max31785 - create mode 100644 drivers/hwmon/max31785.c - -diff --git a/Documentation/hwmon/max31785 b/Documentation/hwmon/max31785 -new file mode 100644 -index 0000000..0911d20 ---- /dev/null -+++ b/Documentation/hwmon/max31785 -@@ -0,0 +1,36 @@ -+Kernel driver max31785 -+====================== -+ -+Supported chips: -+ * Maxim MAX31785 -+ Prefix: 'max31785' -+ Addresses scanned: 0x52 0x53 0x54 0x55 -+ Datasheet: http://pdfserv.maximintegrated.com/en/ds/MAX31785.pdf -+ -+Author: Timothy Pearson <tpearson@raptorengineering.com> -+ -+ -+Description -+----------- -+ -+This driver implements support for the Maxim MAX31785 chip. -+ -+The MAX31785 controls the speeds of up to six fans using six independent -+PWM outputs. The desired fan speeds (or PWM duty cycles) are written -+through the I2C interface. The outputs drive "4-wire" fans directly, -+or can be used to modulate the fan's power terminals using an external -+pass transistor. -+ -+Tachometer inputs monitor fan tachometer logic outputs for precise (+/-1%) -+monitoring and control of fan RPM as well as detection of fan failure. -+ -+ -+Sysfs entries -+------------- -+ -+fan[1-6]_input RO fan tachometer speed in RPM -+fan[1-6]_fault RO fan experienced fault -+fan[1-6]_pulses RW tachometer pulses per fan revolution -+fan[1-6]_target RW desired fan speed in RPM -+pwm[1-6]_enable RW pwm mode, 0=disabled, 1=pwm, 2=rpm, 3=automatic -+pwm[1-6] RW fan target duty cycle (0-255) -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 190d270..136605d 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -886,6 +886,16 @@ config SENSORS_MAX6697 - This driver can also be built as a module. If so, the module - will be called max6697. - -+config SENSORS_MAX31785 -+ tristate "Maxim MAX31785 sensor chip" -+ depends on I2C -+ help -+ If you say yes here you get support for 6-Channel PWM-Output -+ Fan RPM Controller. -+ -+ This driver can also be built as a module. If so, the module -+ will be called max31785. -+ - config SENSORS_MAX31790 - tristate "Maxim MAX31790 sensor chip" - depends on I2C -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index d2cb7e8..e8ba5c6 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -119,6 +119,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o - obj-$(CONFIG_SENSORS_MAX6642) += max6642.o - obj-$(CONFIG_SENSORS_MAX6650) += max6650.o - obj-$(CONFIG_SENSORS_MAX6697) += max6697.o -+obj-$(CONFIG_SENSORS_MAX31785) += max31785.o - obj-$(CONFIG_SENSORS_MAX31790) += max31790.o - obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o - obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o -diff --git a/drivers/hwmon/max31785.c b/drivers/hwmon/max31785.c -new file mode 100644 -index 0000000..fb7b3f0 ---- /dev/null -+++ b/drivers/hwmon/max31785.c -@@ -0,0 +1,714 @@ -+/* -+ * max31785.c - Part of lm_sensors, Linux kernel modules for hardware -+ * monitoring. -+ * -+ * (C) 2016 Raptor Engineering, LLC -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/err.h> -+#include <linux/hwmon.h> -+#include <linux/hwmon-sysfs.h> -+#include <linux/i2c.h> -+#include <linux/init.h> -+#include <linux/jiffies.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+ -+/* MAX31785 device IDs */ -+#define MAX31785_MFR_ID 0x4d -+#define MAX31785_MFR_MODEL 0x53 -+ -+/* MAX31785 registers */ -+#define MAX31785_REG_PAGE 0x00 -+#define MAX31785_PAGE_FAN_CONFIG(ch) (0x00 + (ch)) -+#define MAX31785_REG_FAN_CONFIG_1_2 0x3a -+#define MAX31785_REG_FAN_COMMAND_1 0x3b -+#define MAX31785_REG_STATUS_FANS_1_2 0x81 -+#define MAX31785_REG_FAN_SPEED_1 0x90 -+#define MAX31785_REG_MFR_ID 0x99 -+#define MAX31785_REG_MFR_MODEL 0x9a -+#define MAX31785_REG_MFR_FAN_CONFIG 0xf1 -+#define MAX31785_REG_READ_FAN_PWM 0xf3 -+ -+/* Fan Config register bits */ -+#define MAX31785_FAN_CFG_PWM_ENABLE 0x80 -+#define MAX31785_FAN_CFG_CONTROL_MODE_RPM 0x40 -+#define MAX31785_FAN_CFG_PULSE_MASK 0x30 -+#define MAX31785_FAN_CFG_PULSE_SHIFT 4 -+#define MAX31785_FAN_CFG_PULSE_OFFSET 1 -+ -+/* Fan Status register bits */ -+#define MAX31785_FAN_STATUS_FAULT_MASK 0x80 -+ -+/* Fan Command constants */ -+#define MAX31785_FAN_COMMAND_PWM_RATIO 40 -+ -+#define NR_CHANNEL 6 -+ -+/* Addresses to scan */ -+static const unsigned short normal_i2c[] = { 0x52, 0x53, 0x54, 0x55, -+ I2C_CLIENT_END }; -+ -+/* -+ * Client data (each client gets its own) -+ */ -+struct max31785_data { -+ struct i2c_client *client; -+ struct mutex device_lock; -+ bool valid; /* zero until following fields are valid */ -+ unsigned long last_updated; /* in jiffies */ -+ -+ /* register values */ -+ u8 fan_config[NR_CHANNEL]; -+ u16 fan_command[NR_CHANNEL]; -+ u8 mfr_fan_config[NR_CHANNEL]; -+ u8 fault_status[NR_CHANNEL]; -+ u16 tach_rpm[NR_CHANNEL]; -+ u16 pwm[NR_CHANNEL]; -+}; -+ -+static int max31785_set_page(struct i2c_client *client, -+ u8 page) -+{ -+ return i2c_smbus_write_byte_data(client, -+ MAX31785_REG_PAGE, -+ page); -+} -+ -+static int max31785_read_fan_data(struct i2c_client *client, -+ u8 fan, u8 reg, u8 byte_mode) -+{ -+ int rv; -+ -+ rv = max31785_set_page(client, MAX31785_PAGE_FAN_CONFIG(fan)); -+ if (rv < 0) -+ return rv; -+ -+ if (byte_mode) -+ rv = i2c_smbus_read_byte_data(client, reg); -+ else -+ rv = i2c_smbus_read_word_data(client, reg); -+ -+ return rv; -+} -+ -+static int max31785_write_fan_data(struct i2c_client *client, -+ u8 fan, u8 reg, u16 data, -+ u8 byte_mode) -+{ -+ int err; -+ -+ err = max31785_set_page(client, MAX31785_PAGE_FAN_CONFIG(fan)); -+ if (err < 0) -+ return err; -+ -+ if (byte_mode) -+ err = i2c_smbus_write_byte_data(client, reg, data); -+ else -+ err = i2c_smbus_write_word_data(client, reg, data); -+ -+ if (err < 0) -+ return err; -+ -+ return 0; -+} -+ -+static bool is_automatic_control_mode(struct max31785_data *data, -+ int index) -+{ -+ if (data->fan_command[index] > 0x7fff) -+ return true; -+ else -+ return false; -+} -+ -+static struct max31785_data *max31785_update_device(struct device *dev) -+{ -+ struct max31785_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ struct max31785_data *ret = data; -+ int i; -+ int rv; -+ -+ mutex_lock(&data->device_lock); -+ -+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { -+ for (i = 0; i < NR_CHANNEL; i++) { -+ rv = max31785_read_fan_data(client, i, -+ MAX31785_REG_STATUS_FANS_1_2, 1); -+ if (rv < 0) -+ goto abort; -+ data->fault_status[i] = rv; -+ -+ rv = max31785_read_fan_data(client, i, -+ MAX31785_REG_FAN_SPEED_1, 0); -+ if (rv < 0) -+ goto abort; -+ data->tach_rpm[i] = rv; -+ -+ if ((data->fan_config[i] -+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM) -+ || is_automatic_control_mode(data, i)) { -+ rv = max31785_read_fan_data(client, i, -+ MAX31785_REG_READ_FAN_PWM, 0); -+ if (rv < 0) -+ goto abort; -+ data->pwm[i] = rv; -+ } -+ -+ if (!is_automatic_control_mode(data, i)) { -+ /* Poke watchdog for manual fan control */ -+ rv = max31785_write_fan_data(client, -+ i, MAX31785_REG_FAN_COMMAND_1, -+ data->fan_command[i], 0); -+ if (rv < 0) -+ goto abort; -+ } -+ } -+ -+ data->last_updated = jiffies; -+ data->valid = true; -+ } -+ goto done; -+ -+abort: -+ data->valid = false; -+ ret = ERR_PTR(rv); -+ -+done: -+ mutex_unlock(&data->device_lock); -+ -+ return ret; -+} -+ -+static ssize_t get_fan(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = max31785_update_device(dev); -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ return sprintf(buf, "%d\n", data->tach_rpm[attr->index]); -+} -+ -+static ssize_t get_fan_target(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = max31785_update_device(dev); -+ int rpm; -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ if (data->fan_config[attr->index] -+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM) -+ rpm = data->fan_command[attr->index]; -+ else -+ rpm = data->fan_command[attr->index] -+ / MAX31785_FAN_COMMAND_PWM_RATIO; -+ -+ return sprintf(buf, "%d\n", rpm); -+} -+ -+static ssize_t set_fan_target(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ unsigned long rpm; -+ int err; -+ -+ err = kstrtoul(buf, 10, &rpm); -+ if (err) -+ return err; -+ -+ if (rpm > 0x7fff) -+ return -EINVAL; -+ -+ mutex_lock(&data->device_lock); -+ -+ /* Write new RPM value */ -+ data->fan_command[attr->index] = rpm; -+ err = max31785_write_fan_data(client, attr->index, -+ MAX31785_REG_FAN_COMMAND_1, -+ data->fan_command[attr->index], 0); -+ -+ mutex_unlock(&data->device_lock); -+ -+ if (err < 0) -+ return err; -+ -+ return count; -+} -+ -+static ssize_t get_fan_pulses(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = max31785_update_device(dev); -+ int pulses; -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ pulses = ((data->fan_config[attr->index] & MAX31785_FAN_CFG_PULSE_MASK) -+ >> MAX31785_FAN_CFG_PULSE_SHIFT) -+ + MAX31785_FAN_CFG_PULSE_OFFSET; -+ -+ return sprintf(buf, "%d\n", pulses); -+} -+ -+static ssize_t set_fan_pulses(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ unsigned long pulses; -+ int err; -+ -+ err = kstrtoul(buf, 10, &pulses); -+ if (err) -+ return err; -+ -+ if (pulses > 4) -+ return -EINVAL; -+ -+ data->fan_config[attr->index] &= MAX31785_FAN_CFG_PULSE_MASK; -+ data->fan_config[attr->index] |= -+ ((pulses - MAX31785_FAN_CFG_PULSE_OFFSET) -+ << MAX31785_FAN_CFG_PULSE_SHIFT); -+ -+ mutex_lock(&data->device_lock); -+ -+ /* Write new pulse value */ -+ data->fan_command[attr->index] = pulses; -+ err = max31785_write_fan_data(client, attr->index, -+ MAX31785_REG_FAN_CONFIG_1_2, -+ data->fan_config[attr->index], 1); -+ -+ mutex_unlock(&data->device_lock); -+ -+ if (err < 0) -+ return err; -+ -+ return count; -+} -+ -+static ssize_t get_pwm(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = max31785_update_device(dev); -+ int pwm; -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ if ((data->fan_config[attr->index] -+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM) -+ || is_automatic_control_mode(data, attr->index)) -+ pwm = data->pwm[attr->index] / 100; -+ else -+ pwm = data->fan_command[attr->index] -+ / MAX31785_FAN_COMMAND_PWM_RATIO; -+ -+ return sprintf(buf, "%d\n", pwm); -+} -+ -+static ssize_t set_pwm(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ unsigned long pwm; -+ int err; -+ -+ err = kstrtoul(buf, 10, &pwm); -+ if (err) -+ return err; -+ -+ if (pwm > 255) -+ return -EINVAL; -+ -+ mutex_lock(&data->device_lock); -+ -+ /* Write new PWM value */ -+ data->fan_command[attr->index] = pwm * MAX31785_FAN_COMMAND_PWM_RATIO; -+ err = max31785_write_fan_data(client, attr->index, -+ MAX31785_REG_FAN_COMMAND_1, -+ data->fan_command[attr->index], 0); -+ -+ mutex_unlock(&data->device_lock); -+ -+ if (err < 0) -+ return err; -+ -+ return count; -+} -+ -+static ssize_t get_pwm_enable(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = max31785_update_device(dev); -+ int mode; -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ if (!(data->fan_config[attr->index] & MAX31785_FAN_CFG_PWM_ENABLE)) -+ mode = 0; -+ else if (is_automatic_control_mode(data, attr->index)) -+ mode = 3; -+ else if (data->fan_config[attr->index] -+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM) -+ mode = 2; -+ else -+ mode = 1; -+ -+ return sprintf(buf, "%d\n", mode); -+} -+ -+static ssize_t set_pwm_enable(struct device *dev, -+ struct device_attribute *devattr, -+ const char *buf, size_t count) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = dev_get_drvdata(dev); -+ struct i2c_client *client = data->client; -+ unsigned long mode; -+ int err; -+ -+ err = kstrtoul(buf, 10, &mode); -+ if (err) -+ return err; -+ -+ switch (mode) { -+ case 0: -+ data->fan_config[attr->index] = -+ data->fan_config[attr->index] -+ & ~MAX31785_FAN_CFG_PWM_ENABLE; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ data->fan_config[attr->index] = -+ data->fan_config[attr->index] -+ | MAX31785_FAN_CFG_PWM_ENABLE; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ switch (mode) { -+ case 0: -+ break; -+ case 1: -+ data->fan_config[attr->index] = -+ data->fan_config[attr->index] -+ & ~MAX31785_FAN_CFG_CONTROL_MODE_RPM; -+ break; -+ case 2: -+ data->fan_config[attr->index] = -+ data->fan_config[attr->index] -+ | MAX31785_FAN_CFG_CONTROL_MODE_RPM; -+ break; -+ case 3: -+ data->fan_command[attr->index] = 0xffff; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ mutex_lock(&data->device_lock); -+ -+ err = max31785_write_fan_data(client, attr->index, -+ MAX31785_REG_FAN_CONFIG_1_2, -+ data->fan_config[attr->index], 1); -+ -+ if (err < 0) -+ goto abort; -+ -+ err = max31785_write_fan_data(client, attr->index, -+ MAX31785_REG_FAN_COMMAND_1, -+ data->fan_command[attr->index], 0); -+ -+abort: -+ mutex_unlock(&data->device_lock); -+ -+ if (err < 0) -+ return err; -+ -+ return count; -+} -+ -+static ssize_t get_fan_fault(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct max31785_data *data = max31785_update_device(dev); -+ int fault; -+ -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ fault = !!(data->fault_status[attr->index] -+ & MAX31785_FAN_STATUS_FAULT_MASK); -+ -+ return sprintf(buf, "%d\n", fault); -+} -+ -+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); -+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); -+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); -+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3); -+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, get_fan, NULL, 4); -+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, get_fan, NULL, 5); -+ -+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_fault, NULL, 0); -+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, get_fan_fault, NULL, 1); -+static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, get_fan_fault, NULL, 2); -+static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, get_fan_fault, NULL, 3); -+static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, get_fan_fault, NULL, 4); -+static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, get_fan_fault, NULL, 5); -+ -+static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, -+ get_fan_target, set_fan_target, 0); -+static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, -+ get_fan_target, set_fan_target, 1); -+static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, -+ get_fan_target, set_fan_target, 2); -+static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, -+ get_fan_target, set_fan_target, 3); -+static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO, -+ get_fan_target, set_fan_target, 4); -+static SENSOR_DEVICE_ATTR(fan6_target, S_IWUSR | S_IRUGO, -+ get_fan_target, set_fan_target, 5); -+ -+static SENSOR_DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, -+ get_fan_pulses, set_fan_pulses, 0); -+static SENSOR_DEVICE_ATTR(fan2_pulses, S_IWUSR | S_IRUGO, -+ get_fan_pulses, set_fan_pulses, 1); -+static SENSOR_DEVICE_ATTR(fan3_pulses, S_IWUSR | S_IRUGO, -+ get_fan_pulses, set_fan_pulses, 2); -+static SENSOR_DEVICE_ATTR(fan4_pulses, S_IWUSR | S_IRUGO, -+ get_fan_pulses, set_fan_pulses, 3); -+static SENSOR_DEVICE_ATTR(fan5_pulses, S_IWUSR | S_IRUGO, -+ get_fan_pulses, set_fan_pulses, 4); -+static SENSOR_DEVICE_ATTR(fan6_pulses, S_IWUSR | S_IRUGO, -+ get_fan_pulses, set_fan_pulses, 5); -+ -+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 0); -+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 1); -+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 2); -+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 3); -+static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 4); -+static SENSOR_DEVICE_ATTR(pwm6, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 5); -+ -+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, -+ get_pwm_enable, set_pwm_enable, 0); -+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, -+ get_pwm_enable, set_pwm_enable, 1); -+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, -+ get_pwm_enable, set_pwm_enable, 2); -+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, -+ get_pwm_enable, set_pwm_enable, 3); -+static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, -+ get_pwm_enable, set_pwm_enable, 4); -+static SENSOR_DEVICE_ATTR(pwm6_enable, S_IWUSR | S_IRUGO, -+ get_pwm_enable, set_pwm_enable, 5); -+ -+static struct attribute *max31785_attrs[] = { -+ &sensor_dev_attr_fan1_input.dev_attr.attr, -+ &sensor_dev_attr_fan2_input.dev_attr.attr, -+ &sensor_dev_attr_fan3_input.dev_attr.attr, -+ &sensor_dev_attr_fan4_input.dev_attr.attr, -+ &sensor_dev_attr_fan5_input.dev_attr.attr, -+ &sensor_dev_attr_fan6_input.dev_attr.attr, -+ -+ &sensor_dev_attr_fan1_fault.dev_attr.attr, -+ &sensor_dev_attr_fan2_fault.dev_attr.attr, -+ &sensor_dev_attr_fan3_fault.dev_attr.attr, -+ &sensor_dev_attr_fan4_fault.dev_attr.attr, -+ &sensor_dev_attr_fan5_fault.dev_attr.attr, -+ &sensor_dev_attr_fan6_fault.dev_attr.attr, -+ -+ &sensor_dev_attr_fan1_target.dev_attr.attr, -+ &sensor_dev_attr_fan2_target.dev_attr.attr, -+ &sensor_dev_attr_fan3_target.dev_attr.attr, -+ &sensor_dev_attr_fan4_target.dev_attr.attr, -+ &sensor_dev_attr_fan5_target.dev_attr.attr, -+ &sensor_dev_attr_fan6_target.dev_attr.attr, -+ -+ &sensor_dev_attr_fan1_pulses.dev_attr.attr, -+ &sensor_dev_attr_fan2_pulses.dev_attr.attr, -+ &sensor_dev_attr_fan3_pulses.dev_attr.attr, -+ &sensor_dev_attr_fan4_pulses.dev_attr.attr, -+ &sensor_dev_attr_fan5_pulses.dev_attr.attr, -+ &sensor_dev_attr_fan6_pulses.dev_attr.attr, -+ -+ &sensor_dev_attr_pwm1.dev_attr.attr, -+ &sensor_dev_attr_pwm2.dev_attr.attr, -+ &sensor_dev_attr_pwm3.dev_attr.attr, -+ &sensor_dev_attr_pwm4.dev_attr.attr, -+ &sensor_dev_attr_pwm5.dev_attr.attr, -+ &sensor_dev_attr_pwm6.dev_attr.attr, -+ -+ &sensor_dev_attr_pwm1_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm2_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm3_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm4_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm5_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm6_enable.dev_attr.attr, -+ NULL -+}; -+ -+static umode_t max31785_attrs_visible(struct kobject *kobj, -+ struct attribute *a, int n) -+{ -+ return a->mode; -+} -+ -+static const struct attribute_group max31785_group = { -+ .attrs = max31785_attrs, -+ .is_visible = max31785_attrs_visible, -+}; -+__ATTRIBUTE_GROUPS(max31785); -+ -+static int max31785_init_client(struct i2c_client *client, -+ struct max31785_data *data) -+{ -+ int i, rv; -+ -+ for (i = 0; i < NR_CHANNEL; i++) { -+ rv = max31785_read_fan_data(client, i, -+ MAX31785_REG_FAN_CONFIG_1_2, 1); -+ if (rv < 0) -+ return rv; -+ data->fan_config[i] = rv; -+ -+ rv = max31785_read_fan_data(client, i, -+ MAX31785_REG_FAN_COMMAND_1, 0); -+ if (rv < 0) -+ return rv; -+ data->fan_command[i] = rv; -+ -+ rv = max31785_read_fan_data(client, i, -+ MAX31785_REG_MFR_FAN_CONFIG, 1); -+ if (rv < 0) -+ return rv; -+ data->mfr_fan_config[i] = rv; -+ -+ if (!((data->fan_config[i] -+ & MAX31785_FAN_CFG_CONTROL_MODE_RPM) -+ || is_automatic_control_mode(data, i))) { -+ data->pwm[i] = 0; -+ } -+ } -+ -+ return rv; -+} -+ -+/* Return 0 if detection is successful, -ENODEV otherwise */ -+static int max31785_detect(struct i2c_client *client, -+ struct i2c_board_info *info) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ int rv; -+ -+ if (!i2c_check_functionality(adapter, -+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) -+ return -ENODEV; -+ -+ /* Probe manufacturer / model registers */ -+ rv = i2c_smbus_read_byte_data(client, MAX31785_REG_MFR_ID); -+ if (rv < 0) -+ return -ENODEV; -+ if (rv != MAX31785_MFR_ID) -+ return -ENODEV; -+ -+ rv = i2c_smbus_read_byte_data(client, MAX31785_REG_MFR_MODEL); -+ if (rv < 0) -+ return -ENODEV; -+ if (rv != MAX31785_MFR_MODEL) -+ return -ENODEV; -+ -+ strlcpy(info->type, "max31785", I2C_NAME_SIZE); -+ -+ return 0; -+} -+ -+static int max31785_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ struct device *dev = &client->dev; -+ struct max31785_data *data; -+ struct device *hwmon_dev; -+ int err; -+ -+ if (!i2c_check_functionality(adapter, -+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) -+ return -ENODEV; -+ -+ data = devm_kzalloc(dev, sizeof(struct max31785_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->client = client; -+ mutex_init(&data->device_lock); -+ -+ /* -+ * Initialize the max31785 chip -+ */ -+ err = max31785_init_client(client, data); -+ if (err) -+ return err; -+ -+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, -+ client->name, data, max31785_groups); -+ -+ return PTR_ERR_OR_ZERO(hwmon_dev); -+} -+ -+static const struct i2c_device_id max31785_id[] = { -+ { "max31785", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, max31785_id); -+ -+static struct i2c_driver max31785_driver = { -+ .class = I2C_CLASS_HWMON, -+ .probe = max31785_probe, -+ .driver = { -+ .name = "max31785", -+ }, -+ .id_table = max31785_id, -+ .detect = max31785_detect, -+ .address_list = normal_i2c, -+}; -+ -+module_i2c_driver(max31785_driver); -+ -+MODULE_AUTHOR("Timothy Pearson <tpearson@raptorengineering.com>"); -+MODULE_DESCRIPTION("MAX31785 sensor driver"); -+MODULE_LICENSE("GPL"); --- -1.8.3.1 - diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch deleted file mode 100644 index 70a11f265..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-1-3-drivers-fsi-sbefifo-Add-in-kernel-API.patch +++ /dev/null @@ -1,338 +0,0 @@ -From patchwork Fri May 12 19:38:18 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux,dev-4.10,1/3] drivers: fsi: sbefifo: Add in-kernel API -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 761836 -Message-Id: <1494617900-32369-2-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, bradleyb@fuzziesquirrel.com, - cbostic@linux.vnet.ibm.com -Date: Fri, 12 May 2017 14:38:18 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -Add exported functions to the SBEFIFO driver to open/write/read/close -from within the kernel. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/fsi/fsi-sbefifo.c | 161 +++++++++++++++++++++++++++++++++++--------- - include/linux/fsi-sbefifo.h | 30 +++++++++ - 2 files changed, 161 insertions(+), 30 deletions(-) - create mode 100644 include/linux/fsi-sbefifo.h - -diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c -index b49aec2..56e6331 100644 ---- a/drivers/fsi/fsi-sbefifo.c -+++ b/drivers/fsi/fsi-sbefifo.c -@@ -15,9 +15,12 @@ - #include <linux/errno.h> - #include <linux/idr.h> - #include <linux/fsi.h> -+#include <linux/fsi-sbefifo.h> - #include <linux/list.h> - #include <linux/miscdevice.h> - #include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_platform.h> - #include <linux/poll.h> - #include <linux/sched.h> - #include <linux/slab.h> -@@ -82,6 +85,7 @@ struct sbefifo_client { - struct list_head xfrs; - struct sbefifo *dev; - struct kref kref; -+ unsigned long f_flags; - }; - - static struct list_head sbefifo_fifos; -@@ -506,6 +510,7 @@ static int sbefifo_open(struct inode *inode, struct file *file) - return -ENOMEM; - - file->private_data = client; -+ client->f_flags = file->f_flags; - - return 0; - } -@@ -530,24 +535,18 @@ static unsigned int sbefifo_poll(struct file *file, poll_table *wait) - return mask; - } - --static ssize_t sbefifo_read(struct file *file, char __user *buf, -- size_t len, loff_t *offset) -+static ssize_t sbefifo_read_common(struct sbefifo_client *client, -+ char __user *ubuf, char *kbuf, size_t len) - { -- struct sbefifo_client *client = file->private_data; - struct sbefifo *sbefifo = client->dev; - struct sbefifo_xfr *xfr; -- ssize_t ret = 0; - size_t n; -- -- WARN_ON(*offset); -- -- if (!access_ok(VERIFY_WRITE, buf, len)) -- return -EFAULT; -+ ssize_t ret = 0; - - if ((len >> 2) << 2 != len) - return -EINVAL; - -- if ((file->f_flags & O_NONBLOCK) && !sbefifo_xfr_rsp_pending(client)) -+ if ((client->f_flags & O_NONBLOCK) && !sbefifo_xfr_rsp_pending(client)) - return -EAGAIN; - - sbefifo_get_client(client); -@@ -566,10 +565,13 @@ static ssize_t sbefifo_read(struct file *file, char __user *buf, - - n = min_t(size_t, n, len); - -- if (copy_to_user(buf, READ_ONCE(client->rbuf.rpos), n)) { -- sbefifo_put_client(client); -- return -EFAULT; -- } -+ if (ubuf) { -+ if (copy_to_user(ubuf, READ_ONCE(client->rbuf.rpos), n)) { -+ sbefifo_put_client(client); -+ return -EFAULT; -+ } -+ } else -+ memcpy(kbuf, READ_ONCE(client->rbuf.rpos), n); - - if (sbefifo_buf_readnb(&client->rbuf, n)) { - xfr = sbefifo_client_next_xfr(client); -@@ -592,20 +594,28 @@ static ssize_t sbefifo_read(struct file *file, char __user *buf, - return n; - } - --static ssize_t sbefifo_write(struct file *file, const char __user *buf, -+static ssize_t sbefifo_read(struct file *file, char __user *buf, - size_t len, loff_t *offset) - { - struct sbefifo_client *client = file->private_data; -- struct sbefifo *sbefifo = client->dev; -- struct sbefifo_xfr *xfr; -- ssize_t ret = 0; -- size_t n; - - WARN_ON(*offset); - -- if (!access_ok(VERIFY_READ, buf, len)) -+ if (!access_ok(VERIFY_WRITE, buf, len)) - return -EFAULT; - -+ return sbefifo_read_common(client, buf, NULL, len); -+} -+ -+static ssize_t sbefifo_write_common(struct sbefifo_client *client, -+ const char __user *ubuf, const char *kbuf, -+ size_t len) -+{ -+ struct sbefifo *sbefifo = client->dev; -+ struct sbefifo_xfr *xfr; -+ ssize_t ret = 0; -+ size_t n; -+ - if ((len >> 2) << 2 != len) - return -EINVAL; - -@@ -617,7 +627,7 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf, - spin_lock_irq(&sbefifo->lock); - xfr = sbefifo_next_xfr(sbefifo); - -- if ((file->f_flags & O_NONBLOCK) && xfr && n < len) { -+ if ((client->f_flags & O_NONBLOCK) && xfr && n < len) { - spin_unlock_irq(&sbefifo->lock); - return -EAGAIN; - } -@@ -657,18 +667,25 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf, - - n = min_t(size_t, n, len); - -- if (copy_from_user(READ_ONCE(client->wbuf.wpos), buf, n)) { -- set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags); -- sbefifo_get(sbefifo); -- if (mod_timer(&sbefifo->poll_timer, jiffies)) -- sbefifo_put(sbefifo); -- sbefifo_put_client(client); -- return -EFAULT; -+ if (ubuf) { -+ if (copy_from_user(READ_ONCE(client->wbuf.wpos), ubuf, -+ n)) { -+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags); -+ sbefifo_get(sbefifo); -+ if (mod_timer(&sbefifo->poll_timer, jiffies)) -+ sbefifo_put(sbefifo); -+ sbefifo_put_client(client); -+ return -EFAULT; -+ } -+ -+ ubuf += n; -+ } else { -+ memcpy(READ_ONCE(client->wbuf.wpos), kbuf, n); -+ kbuf += n; - } - - sbefifo_buf_wrotenb(&client->wbuf, n); - len -= n; -- buf += n; - ret += n; - - /* -@@ -685,6 +702,19 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf, - return ret; - } - -+static ssize_t sbefifo_write(struct file *file, const char __user *buf, -+ size_t len, loff_t *offset) -+{ -+ struct sbefifo_client *client = file->private_data; -+ -+ WARN_ON(*offset); -+ -+ if (!access_ok(VERIFY_READ, buf, len)) -+ return -EFAULT; -+ -+ return sbefifo_write_common(client, buf, NULL, len); -+} -+ - static int sbefifo_release(struct inode *inode, struct file *file) - { - struct sbefifo_client *client = file->private_data; -@@ -704,12 +734,68 @@ static int sbefifo_release(struct inode *inode, struct file *file) - .release = sbefifo_release, - }; - -+struct sbefifo_client *sbefifo_drv_open(struct device *dev, -+ unsigned long flags) -+{ -+ struct sbefifo_client *client = NULL; -+ struct sbefifo *sbefifo; -+ struct fsi_device *fsi_dev = to_fsi_dev(dev); -+ -+ list_for_each_entry(sbefifo, &sbefifo_fifos, link) { -+ if (sbefifo->fsi_dev != fsi_dev) -+ continue; -+ -+ client = sbefifo_new_client(sbefifo); -+ if (client) -+ client->f_flags = flags; -+ } -+ -+ return client; -+} -+EXPORT_SYMBOL_GPL(sbefifo_drv_open); -+ -+int sbefifo_drv_read(struct sbefifo_client *client, char *buf, size_t len) -+{ -+ return sbefifo_read_common(client, NULL, buf, len); -+} -+EXPORT_SYMBOL_GPL(sbefifo_drv_read); -+ -+int sbefifo_drv_write(struct sbefifo_client *client, const char *buf, -+ size_t len) -+{ -+ return sbefifo_write_common(client, NULL, buf, len); -+} -+EXPORT_SYMBOL_GPL(sbefifo_drv_write); -+ -+void sbefifo_drv_release(struct sbefifo_client *client) -+{ -+ if (!client) -+ return; -+ -+ sbefifo_put_client(client); -+} -+EXPORT_SYMBOL_GPL(sbefifo_drv_release); -+ -+static int sbefifo_unregister_child(struct device *dev, void *data) -+{ -+ struct platform_device *child = to_platform_device(dev); -+ -+ of_device_unregister(child); -+ if (dev->of_node) -+ of_node_clear_flag(dev->of_node, OF_POPULATED); -+ -+ return 0; -+} -+ - static int sbefifo_probe(struct device *dev) - { - struct fsi_device *fsi_dev = to_fsi_dev(dev); - struct sbefifo *sbefifo; -+ struct device_node *np; -+ struct platform_device *child; -+ char child_name[32]; - u32 sts; -- int ret; -+ int ret, child_idx = 0; - - dev_info(dev, "Found sbefifo device\n"); - sbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL); -@@ -750,6 +836,18 @@ static int sbefifo_probe(struct device *dev) - init_waitqueue_head(&sbefifo->wait); - INIT_LIST_HEAD(&sbefifo->xfrs); - -+ if (dev->of_node) { -+ /* create platform devs for dts child nodes (occ, etc) */ -+ for_each_child_of_node(dev->of_node, np) { -+ snprintf(child_name, sizeof(child_name), "%s-dev%d", -+ sbefifo->name, child_idx++); -+ child = of_platform_device_create(np, child_name, dev); -+ if (!child) -+ dev_warn(&sbefifo->fsi_dev->dev, -+ "failed to create child node dev\n"); -+ } -+ } -+ - /* This bit of silicon doesn't offer any interrupts... */ - setup_timer(&sbefifo->poll_timer, sbefifo_poll_timer, - (unsigned long)sbefifo); -@@ -767,6 +865,9 @@ static int sbefifo_remove(struct device *dev) - list_for_each_entry_safe(sbefifo, sbefifo_tmp, &sbefifo_fifos, link) { - if (sbefifo->fsi_dev != fsi_dev) - continue; -+ -+ device_for_each_child(dev, NULL, sbefifo_unregister_child); -+ - misc_deregister(&sbefifo->mdev); - list_del(&sbefifo->link); - ida_simple_remove(&sbefifo_ida, sbefifo->idx); -diff --git a/include/linux/fsi-sbefifo.h b/include/linux/fsi-sbefifo.h -new file mode 100644 -index 0000000..1b46c63 ---- /dev/null -+++ b/include/linux/fsi-sbefifo.h -@@ -0,0 +1,30 @@ -+/* -+ * SBEFIFO FSI Client device driver -+ * -+ * Copyright (C) IBM Corporation 2017 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __FSI_SBEFIFO_H__ -+#define __FSI_SBEFIFO_H__ -+ -+struct device; -+struct sbefifo_client; -+ -+extern struct sbefifo_client *sbefifo_drv_open(struct device *dev, -+ unsigned long flags); -+extern int sbefifo_drv_read(struct sbefifo_client *client, char *buf, -+ size_t len); -+extern int sbefifo_drv_write(struct sbefifo_client *client, const char *buf, -+ size_t len); -+extern void sbefifo_drv_release(struct sbefifo_client *client); -+ -+#endif /* __FSI_SBEFIFO_H__ */ diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch deleted file mode 100644 index 5c53dadc4..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-2-3-drivers-fsi-sbefifo-Add-OCC-driver.patch +++ /dev/null @@ -1,694 +0,0 @@ -From patchwork Fri May 12 19:38:19 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux,dev-4.10,2/3] drivers: fsi: sbefifo: Add OCC driver -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 761838 -Message-Id: <1494617900-32369-3-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, bradleyb@fuzziesquirrel.com, - cbostic@linux.vnet.ibm.com -Date: Fri, 12 May 2017 14:38:19 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -This driver provides an atomic communications channel between the OCC on -the POWER9 processor and a service processor (a BMC). The driver is -dependent on the FSI SBEIFO driver to get hardware access to the OCC -SRAM. - -The format of the communication is a command followed by a response. -Since the command and response must be performed atomically, the driver -will perform this operations asynchronously. In this way, a write -operation starts the command, and a read will gather the response data -once it is complete. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/fsi/Kconfig | 9 + - drivers/fsi/Makefile | 1 + - drivers/fsi/occ.c | 625 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 635 insertions(+) - create mode 100644 drivers/fsi/occ.c - -diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig -index 39527fa..f3d8593 100644 ---- a/drivers/fsi/Kconfig -+++ b/drivers/fsi/Kconfig -@@ -36,6 +36,15 @@ config FSI_SBEFIFO - ---help--- - This option enables an FSI based SBEFIFO device driver. - -+if FSI_SBEFIFO -+ -+config OCCFIFO -+ tristate "OCC SBEFIFO client device driver" -+ ---help--- -+ This option enables an SBEFIFO based OCC device driver. -+ -+endif -+ - endif - - endmenu -diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile -index 851182e..336d9d5 100644 ---- a/drivers/fsi/Makefile -+++ b/drivers/fsi/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o - obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o - obj-$(CONFIG_FSI_SCOM) += fsi-scom.o - obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o -+obj-$(CONFIG_OCCFIFO) += occ.o -diff --git a/drivers/fsi/occ.c b/drivers/fsi/occ.c -new file mode 100644 -index 0000000..74272c8 ---- /dev/null -+++ b/drivers/fsi/occ.c -@@ -0,0 +1,625 @@ -+/* -+ * Copyright 2017 IBM 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. -+ */ -+ -+#include <asm/unaligned.h> -+#include <linux/device.h> -+#include <linux/err.h> -+#include <linux/fsi-sbefifo.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/wait.h> -+#include <linux/workqueue.h> -+ -+#define OCC_SRAM_BYTES 4096 -+#define OCC_CMD_DATA_BYTES 4090 -+#define OCC_RESP_DATA_BYTES 4089 -+ -+struct occ { -+ struct device *sbefifo; -+ char name[32]; -+ int idx; -+ struct miscdevice mdev; -+ struct list_head xfrs; -+ spinlock_t list_lock; -+ spinlock_t occ_lock; -+ struct work_struct work; -+}; -+ -+#define to_occ(x) container_of((x), struct occ, mdev) -+ -+struct occ_command { -+ u8 seq_no; -+ u8 cmd_type; -+ u16 data_length; -+ u8 data[OCC_CMD_DATA_BYTES]; -+ u16 checksum; -+}; -+ -+struct occ_response { -+ u8 seq_no; -+ u8 cmd_type; -+ u8 return_status; -+ u16 data_length; -+ u8 data[OCC_RESP_DATA_BYTES]; -+ u16 checksum; -+}; -+ -+struct occ_xfr; -+ -+enum { -+ CLIENT_NONBLOCKING, -+}; -+ -+struct occ_client { -+ struct occ *occ; -+ struct occ_xfr *xfr; -+ spinlock_t lock; -+ wait_queue_head_t wait; -+ size_t read_offset; -+ unsigned long flags; -+}; -+ -+enum { -+ XFR_IN_PROGRESS, -+ XFR_COMPLETE, -+ XFR_CANCELED, -+ XFR_WAITING, -+}; -+ -+struct occ_xfr { -+ struct list_head link; -+ struct occ_client *client; -+ int rc; -+ u8 buf[OCC_SRAM_BYTES]; -+ size_t cmd_data_length; -+ size_t resp_data_length; -+ unsigned long flags; -+}; -+ -+static struct workqueue_struct *occ_wq; -+ -+static DEFINE_IDA(occ_ida); -+ -+static void occ_enqueue_xfr(struct occ_xfr *xfr) -+{ -+ int empty; -+ struct occ *occ = xfr->client->occ; -+ -+ spin_lock_irq(&occ->list_lock); -+ empty = list_empty(&occ->xfrs); -+ list_add_tail(&xfr->link, &occ->xfrs); -+ spin_unlock(&occ->list_lock); -+ -+ if (empty) -+ queue_work(occ_wq, &occ->work); -+} -+ -+static int occ_open(struct inode *inode, struct file *file) -+{ -+ struct occ_client *client; -+ struct miscdevice *mdev = file->private_data; -+ struct occ *occ = to_occ(mdev); -+ -+ client = kzalloc(sizeof(*client), GFP_KERNEL); -+ if (!client) -+ return -ENOMEM; -+ -+ client->occ = occ; -+ spin_lock_init(&client->lock); -+ init_waitqueue_head(&client->wait); -+ -+ if (file->f_flags & O_NONBLOCK) -+ set_bit(CLIENT_NONBLOCKING, &client->flags); -+ -+ file->private_data = client; -+ -+ return 0; -+} -+ -+static ssize_t occ_read(struct file *file, char __user *buf, size_t len, -+ loff_t *offset) -+{ -+ int rc; -+ size_t bytes; -+ struct occ_xfr *xfr; -+ struct occ_client *client = file->private_data; -+ -+ if (!access_ok(VERIFY_WRITE, buf, len)) -+ return -EFAULT; -+ -+ if (len > OCC_SRAM_BYTES) -+ return -EINVAL; -+ -+ spin_lock_irq(&client->lock); -+ if (!client->xfr) { -+ /* we just finished reading all data, return 0 */ -+ if (client->read_offset) { -+ rc = 0; -+ client->read_offset = 0; -+ } else -+ rc = -ENOMSG; -+ -+ goto done; -+ } -+ -+ xfr = client->xfr; -+ -+ if (!test_bit(XFR_COMPLETE, &xfr->flags)) { -+ if (client->flags & CLIENT_NONBLOCKING) { -+ rc = -ERESTARTSYS; -+ goto done; -+ } -+ -+ set_bit(XFR_WAITING, &xfr->flags); -+ spin_unlock(&client->lock); -+ -+ rc = wait_event_interruptible(client->wait, -+ test_bit(XFR_COMPLETE, &xfr->flags) || -+ test_bit(XFR_CANCELED, &xfr->flags)); -+ -+ spin_lock_irq(&client->lock); -+ if (test_bit(XFR_CANCELED, &xfr->flags)) { -+ kfree(xfr); -+ spin_unlock(&client->lock); -+ kfree(client); -+ return -EBADFD; -+ } -+ -+ clear_bit(XFR_WAITING, &xfr->flags); -+ if (!test_bit(XFR_COMPLETE, &xfr->flags)) { -+ rc = -EINTR; -+ goto done; -+ } -+ } -+ -+ if (xfr->rc) { -+ rc = xfr->rc; -+ goto done; -+ } -+ -+ bytes = min(len, xfr->resp_data_length - client->read_offset); -+ if (copy_to_user(buf, &xfr->buf[client->read_offset], bytes)) { -+ rc = -EFAULT; -+ goto done; -+ } -+ -+ client->read_offset += bytes; -+ -+ /* xfr done */ -+ if (client->read_offset == xfr->resp_data_length) { -+ kfree(xfr); -+ client->xfr = NULL; -+ } -+ -+ rc = bytes; -+ -+done: -+ spin_unlock(&client->lock); -+ return rc; -+} -+ -+static ssize_t occ_write(struct file *file, const char __user *buf, -+ size_t len, loff_t *offset) -+{ -+ int rc; -+ struct occ_xfr *xfr; -+ struct occ_client *client = file->private_data; -+ -+ if (!access_ok(VERIFY_READ, buf, len)) -+ return -EFAULT; -+ -+ if (len > OCC_SRAM_BYTES) -+ return -EINVAL; -+ -+ spin_lock_irq(&client->lock); -+ if (client->xfr) { -+ rc = -EDEADLK; -+ goto done; -+ } -+ -+ xfr = kzalloc(sizeof(*xfr), GFP_KERNEL); -+ if (!xfr) { -+ rc = -ENOMEM; -+ goto done; -+ } -+ -+ if (copy_from_user(xfr->buf, buf, len)) { -+ kfree(xfr); -+ rc = -EFAULT; -+ goto done; -+ } -+ -+ xfr->client = client; -+ xfr->cmd_data_length = len; -+ client->xfr = xfr; -+ client->read_offset = 0; -+ -+ occ_enqueue_xfr(xfr); -+ -+ rc = len; -+ -+done: -+ spin_unlock(&client->lock); -+ return rc; -+} -+ -+static int occ_release(struct inode *inode, struct file *file) -+{ -+ struct occ_xfr *xfr; -+ struct occ_client *client = file->private_data; -+ struct occ *occ = client->occ; -+ -+ spin_lock_irq(&client->lock); -+ xfr = client->xfr; -+ if (!xfr) { -+ spin_unlock(&client->lock); -+ kfree(client); -+ return 0; -+ } -+ -+ spin_lock_irq(&occ->list_lock); -+ set_bit(XFR_CANCELED, &xfr->flags); -+ if (!test_bit(XFR_IN_PROGRESS, &xfr->flags)) { -+ /* already deleted from list if complete */ -+ if (!test_bit(XFR_COMPLETE, &xfr->flags)) -+ list_del(&xfr->link); -+ -+ spin_unlock(&occ->list_lock); -+ -+ if (test_bit(XFR_WAITING, &xfr->flags)) { -+ /* blocking read; let reader clean up */ -+ wake_up_interruptible(&client->wait); -+ spin_unlock(&client->lock); -+ return 0; -+ } -+ -+ kfree(xfr); -+ spin_unlock(&client->lock); -+ kfree(client); -+ return 0; -+ } -+ -+ /* operation is in progress; let worker clean up*/ -+ spin_unlock(&occ->list_lock); -+ spin_unlock(&client->lock); -+ return 0; -+} -+ -+static const struct file_operations occ_fops = { -+ .owner = THIS_MODULE, -+ .open = occ_open, -+ .read = occ_read, -+ .write = occ_write, -+ .release = occ_release, -+}; -+ -+static int occ_getscom(struct device *sbefifo, u32 address, u8 *data) -+{ -+ int rc; -+ u32 buf[4]; -+ struct sbefifo_client *client; -+ const size_t len = sizeof(buf); -+ -+ buf[0] = cpu_to_be32(0x4); -+ buf[1] = cpu_to_be32(0xa201); -+ buf[2] = 0; -+ buf[3] = cpu_to_be32(address); -+ -+ client = sbefifo_drv_open(sbefifo, 0); -+ if (!client) -+ return -ENODEV; -+ -+ rc = sbefifo_drv_write(client, (const char *)buf, len); -+ if (rc < 0) -+ goto done; -+ else if (rc != len) { -+ rc = -EMSGSIZE; -+ goto done; -+ } -+ -+ rc = sbefifo_drv_read(client, (char *)buf, len); -+ if (rc < 0) -+ goto done; -+ else if (rc != len) { -+ rc = -EMSGSIZE; -+ goto done; -+ } -+ -+ /* check for good response */ -+ if ((be32_to_cpu(buf[2]) >> 16) != 0xC0DE) { -+ rc = -EFAULT; -+ goto done; -+ } -+ -+ rc = 0; -+ -+ memcpy(data, buf, sizeof(u64)); -+ -+done: -+ sbefifo_drv_release(client); -+ return rc; -+} -+ -+static int occ_putscom(struct device *sbefifo, u32 address, u8 *data) -+{ -+ int rc; -+ u32 buf[6]; -+ struct sbefifo_client *client; -+ const size_t len = sizeof(buf); -+ -+ buf[0] = cpu_to_be32(0x6); -+ buf[1] = cpu_to_be32(0xa202); -+ buf[2] = 0; -+ buf[3] = cpu_to_be32(address); -+ memcpy(&buf[4], data, sizeof(u64)); -+ -+ client = sbefifo_drv_open(sbefifo, 0); -+ if (!client) -+ return -ENODEV; -+ -+ rc = sbefifo_drv_write(client, (const char *)buf, len); -+ if (rc < 0) -+ goto done; -+ else if (rc != len) { -+ rc = -EMSGSIZE; -+ goto done; -+ } -+ -+ rc = 0; -+ -+ /* ignore response */ -+ sbefifo_drv_read(client, (char *)buf, len); -+ -+done: -+ sbefifo_drv_release(client); -+ return rc; -+} -+ -+static int occ_putscom_u32(struct device *sbefifo, u32 address, u32 data0, -+ u32 data1) -+{ -+ u8 buf[8]; -+ u32 raw_data0 = cpu_to_be32(data0), raw_data1 = cpu_to_be32(data1); -+ -+ memcpy(buf, &raw_data0, 4); -+ memcpy(buf + 4, &raw_data1, 4); -+ -+ return occ_putscom(sbefifo, address, buf); -+} -+ -+static void occ_worker(struct work_struct *work) -+{ -+ int i, empty, canceled, waiting, rc; -+ u16 resp_data_length; -+ struct occ *occ = container_of(work, struct occ, work); -+ struct device *sbefifo = occ->sbefifo; -+ struct occ_client *client; -+ struct occ_xfr *xfr; -+ struct occ_response *resp; -+ -+again: -+ spin_lock_irq(&occ->list_lock); -+ xfr = list_first_entry(&occ->xfrs, struct occ_xfr, link); -+ if (!xfr) { -+ spin_unlock(&occ->list_lock); -+ return; -+ } -+ -+ set_bit(XFR_IN_PROGRESS, &xfr->flags); -+ spin_unlock(&occ->list_lock); -+ -+ resp = (struct occ_response *)xfr->buf; -+ -+ spin_lock_irq(&occ->occ_lock); -+ -+ /* set address reg to occ sram command buffer */ -+ rc = occ_putscom_u32(sbefifo, 0x6D050, 0xFFFBE000, 0); -+ if (rc) -+ goto done; -+ -+ /* write cmd data */ -+ for (i = 0; i < xfr->cmd_data_length; i += 8) { -+ rc = occ_putscom(sbefifo, 0x6D055, &xfr->buf[i]); -+ if (rc) -+ goto done; -+ } -+ -+ /* trigger attention */ -+ rc = occ_putscom_u32(sbefifo, 0x6D035, 0x20010000, 0); -+ if (rc) -+ goto done; -+ -+ /* set address reg to occ sram response buffer */ -+ rc = occ_putscom_u32(sbefifo, 0x6D050, 0xFFFBF000, 0); -+ if (rc) -+ goto done; -+ -+ rc = occ_getscom(sbefifo, 0x6D055, xfr->buf); -+ if (rc) -+ goto done; -+ -+ xfr->resp_data_length += 8; -+ -+ resp_data_length = be16_to_cpu(get_unaligned(&resp->data_length)); -+ if (resp_data_length > OCC_RESP_DATA_BYTES) { -+ rc = -EFAULT; -+ goto done; -+ } -+ -+ /* already read 3 bytes of resp data, but also need 2 bytes chksum */ -+ for (i = 8; i < resp_data_length + 7; i += 8) { -+ rc = occ_getscom(sbefifo, 0x6D055, &xfr->buf[i]); -+ if (rc) -+ goto done; -+ -+ xfr->resp_data_length += 8; -+ } -+ -+ /* no errors, got all data */ -+ xfr->resp_data_length = resp_data_length + 7; -+ -+done: -+ spin_unlock(&occ->occ_lock); -+ -+ xfr->rc = rc; -+ client = xfr->client; -+ -+ /* lock client to prevent race with read() */ -+ spin_lock_irq(&client->lock); -+ set_bit(XFR_COMPLETE, &xfr->flags); -+ waiting = test_bit(XFR_WAITING, &xfr->flags); -+ spin_unlock(&client->lock); -+ -+ spin_lock_irq(&occ->list_lock); -+ clear_bit(XFR_IN_PROGRESS, &xfr->flags); -+ list_del(&xfr->link); -+ empty = list_empty(&occ->xfrs); -+ canceled = test_bit(XFR_CANCELED, &xfr->flags); -+ spin_unlock(&occ->list_lock); -+ -+ if (waiting) -+ wake_up_interruptible(&client->wait); -+ else if (canceled) { -+ kfree(xfr); -+ kfree(xfr->client); -+ } -+ -+ if (!empty) -+ goto again; -+} -+ -+static int occ_probe(struct platform_device *pdev) -+{ -+ int rc; -+ u32 reg; -+ struct occ *occ; -+ struct device *dev = &pdev->dev; -+ -+ dev_info(dev, "Found occ device\n"); -+ occ = devm_kzalloc(dev, sizeof(*occ), GFP_KERNEL); -+ if (!occ) -+ return -ENOMEM; -+ -+ occ->sbefifo = dev->parent; -+ INIT_LIST_HEAD(&occ->xfrs); -+ spin_lock_init(&occ->list_lock); -+ spin_lock_init(&occ->occ_lock); -+ INIT_WORK(&occ->work, occ_worker); -+ -+ if (dev->of_node) { -+ rc = of_property_read_u32(dev->of_node, "reg", ®); -+ if (!rc) { -+ /* make sure we don't have a duplicate from dts */ -+ occ->idx = ida_simple_get(&occ_ida, reg, reg + 1, -+ GFP_KERNEL); -+ if (occ->idx < 0) -+ occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, -+ GFP_KERNEL); -+ } else -+ occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, -+ GFP_KERNEL); -+ } else -+ occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, GFP_KERNEL); -+ -+ snprintf(occ->name, sizeof(occ->name), "occ%d", occ->idx); -+ occ->mdev.fops = &occ_fops; -+ occ->mdev.minor = MISC_DYNAMIC_MINOR; -+ occ->mdev.name = occ->name; -+ occ->mdev.parent = dev; -+ -+ rc = misc_register(&occ->mdev); -+ if (rc) { -+ dev_err(dev, "failed to register miscdevice\n"); -+ return rc; -+ } -+ -+ platform_set_drvdata(pdev, occ); -+ -+ return 0; -+} -+ -+static int occ_remove(struct platform_device *pdev) -+{ -+ struct occ_xfr *xfr, *tmp; -+ struct occ *occ = platform_get_drvdata(pdev); -+ struct occ_client *client; -+ -+ misc_deregister(&occ->mdev); -+ -+ spin_lock_irq(&occ->list_lock); -+ list_for_each_entry_safe(xfr, tmp, &occ->xfrs, link) { -+ client = xfr->client; -+ set_bit(XFR_CANCELED, &xfr->flags); -+ -+ if (!test_bit(XFR_IN_PROGRESS, &xfr->flags)) { -+ list_del(&xfr->link); -+ -+ spin_lock_irq(&client->lock); -+ if (test_bit(XFR_WAITING, &xfr->flags)) { -+ wake_up_interruptible(&client->wait); -+ spin_unlock(&client->lock); -+ } else { -+ kfree(xfr); -+ spin_unlock(&client->lock); -+ kfree(client); -+ } -+ } -+ } -+ spin_unlock(&occ->list_lock); -+ -+ flush_work(&occ->work); -+ -+ ida_simple_remove(&occ_ida, occ->idx); -+ -+ return 0; -+} -+ -+static const struct of_device_id occ_match[] = { -+ { .compatible = "ibm,p9-occ" }, -+ { }, -+}; -+ -+static struct platform_driver occ_driver = { -+ .driver = { -+ .name = "occ", -+ .of_match_table = occ_match, -+ }, -+ .probe = occ_probe, -+ .remove = occ_remove, -+}; -+ -+static int occ_init(void) -+{ -+ occ_wq = create_singlethread_workqueue("occ"); -+ if (!occ_wq) -+ return -ENOMEM; -+ -+ return platform_driver_register(&occ_driver); -+} -+ -+static void occ_exit(void) -+{ -+ destroy_workqueue(occ_wq); -+ -+ platform_driver_unregister(&occ_driver); -+} -+ -+module_init(occ_init); -+module_exit(occ_exit); -+ -+MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>"); -+MODULE_DESCRIPTION("BMC P9 OCC driver"); -+MODULE_LICENSE("GPL"); -+ diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch deleted file mode 100644 index b29e0e933..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-drivers-fsi-Add-FSI-SBEFIFO-driver.patch +++ /dev/null @@ -1,899 +0,0 @@ -From patchwork Thu May 11 02:52:53 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux,dev-4.10] drivers: fsi: Add FSI SBEFIFO driver -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 760920 -Message-Id: <1494471173-6077-1-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, bradleyb@fuzziesquirrel.com -Date: Wed, 10 May 2017 21:52:53 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -IBM POWER9 processors contain some embedded hardware and software bits -collectively referred to as the self boot engine (SBE). One role of -the SBE is to act as a proxy that provides access to the registers of -the POWER chip from other (embedded) systems. - -The POWER9 chip contains a hardware frontend for communicating with -the SBE from remote systems called the SBEFIFO. The SBEFIFO logic -is contained within an FSI CFAM (see Documentation/fsi) and as such -the driver implements an FSI bus device. - -The SBE expects to communicate using a defined wire protocol; however, -the driver knows nothing of the protocol and only provides raw access -to the fifo device to userspace applications wishing to communicate with -the SBE using the wire protocol. - -The SBEFIFO consists of two hardware fifos. The upstream fifo is used -by the driver to transfer data to the SBE on the POWER chip, from the -system hosting the driver. The downstream fifo is used by the driver to -transfer data from the SBE on the power chip to the system hosting the -driver. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> -Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com> ---- - drivers/fsi/Kconfig | 5 + - drivers/fsi/Makefile | 1 + - drivers/fsi/fsi-sbefifo.c | 824 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 830 insertions(+) - create mode 100644 drivers/fsi/fsi-sbefifo.c - -diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig -index fc031ac..39527fa 100644 ---- a/drivers/fsi/Kconfig -+++ b/drivers/fsi/Kconfig -@@ -31,6 +31,11 @@ config FSI_SCOM - ---help--- - This option enables an FSI based SCOM device driver. - -+config FSI_SBEFIFO -+ tristate "SBEFIFO FSI client device driver" -+ ---help--- -+ This option enables an FSI based SBEFIFO device driver. -+ - endif - - endmenu -diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile -index 65eb99d..851182e 100644 ---- a/drivers/fsi/Makefile -+++ b/drivers/fsi/Makefile -@@ -3,3 +3,4 @@ obj-$(CONFIG_FSI) += fsi-core.o - obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o - obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o - obj-$(CONFIG_FSI_SCOM) += fsi-scom.o -+obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o -diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c -new file mode 100644 -index 0000000..b49aec2 ---- /dev/null -+++ b/drivers/fsi/fsi-sbefifo.c -@@ -0,0 +1,824 @@ -+/* -+ * Copyright (C) IBM Corporation 2017 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/delay.h> -+#include <linux/errno.h> -+#include <linux/idr.h> -+#include <linux/fsi.h> -+#include <linux/list.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/poll.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/timer.h> -+#include <linux/uaccess.h> -+ -+/* -+ * The SBEFIFO is a pipe-like FSI device for communicating with -+ * the self boot engine on POWER processors. -+ */ -+ -+#define DEVICE_NAME "sbefifo" -+#define FSI_ENGID_SBE 0x22 -+#define SBEFIFO_BUF_CNT 32 -+ -+#define SBEFIFO_UP 0x00 /* Up register offset */ -+#define SBEFIFO_DWN 0x40 /* Down register offset */ -+ -+#define SBEFIFO_STS 0x04 -+#define SBEFIFO_EMPTY BIT(20) -+#define SBEFIFO_EOT_RAISE 0x08 -+#define SBEFIFO_EOT_MAGIC 0xffffffff -+#define SBEFIFO_EOT_ACK 0x14 -+ -+struct sbefifo { -+ struct timer_list poll_timer; -+ struct fsi_device *fsi_dev; -+ struct miscdevice mdev; -+ wait_queue_head_t wait; -+ struct list_head link; -+ struct list_head xfrs; -+ struct kref kref; -+ spinlock_t lock; -+ char name[32]; -+ int idx; -+ int rc; -+}; -+ -+struct sbefifo_buf { -+ u32 buf[SBEFIFO_BUF_CNT]; -+ unsigned long flags; -+#define SBEFIFO_BUF_FULL 1 -+ u32 *rpos; -+ u32 *wpos; -+}; -+ -+struct sbefifo_xfr { -+ struct sbefifo_buf *rbuf; -+ struct sbefifo_buf *wbuf; -+ struct list_head client; -+ struct list_head xfrs; -+ unsigned long flags; -+#define SBEFIFO_XFR_WRITE_DONE 1 -+#define SBEFIFO_XFR_RESP_PENDING 2 -+#define SBEFIFO_XFR_COMPLETE 3 -+#define SBEFIFO_XFR_CANCEL 4 -+}; -+ -+struct sbefifo_client { -+ struct sbefifo_buf rbuf; -+ struct sbefifo_buf wbuf; -+ struct list_head xfrs; -+ struct sbefifo *dev; -+ struct kref kref; -+}; -+ -+static struct list_head sbefifo_fifos; -+ -+static DEFINE_IDA(sbefifo_ida); -+ -+static int sbefifo_inw(struct sbefifo *sbefifo, int reg, u32 *word) -+{ -+ int rc; -+ u32 raw_word; -+ -+ rc = fsi_device_read(sbefifo->fsi_dev, reg, &raw_word, -+ sizeof(raw_word)); -+ if (rc) -+ return rc; -+ -+ *word = be32_to_cpu(raw_word); -+ return 0; -+} -+ -+static int sbefifo_outw(struct sbefifo *sbefifo, int reg, u32 word) -+{ -+ u32 raw_word = cpu_to_be32(word); -+ -+ return fsi_device_write(sbefifo->fsi_dev, reg, &raw_word, -+ sizeof(raw_word)); -+} -+ -+static int sbefifo_readw(struct sbefifo *sbefifo, u32 *word) -+{ -+ return fsi_device_read(sbefifo->fsi_dev, SBEFIFO_DWN, word, -+ sizeof(*word)); -+} -+ -+static int sbefifo_writew(struct sbefifo *sbefifo, u32 word) -+{ -+ return fsi_device_write(sbefifo->fsi_dev, SBEFIFO_UP, &word, -+ sizeof(word)); -+} -+ -+static int sbefifo_ack_eot(struct sbefifo *sbefifo) -+{ -+ u32 discard; -+ int ret; -+ -+ /* Discard the EOT word. */ -+ ret = sbefifo_readw(sbefifo, &discard); -+ if (ret) -+ return ret; -+ -+ return sbefifo_outw(sbefifo, SBEFIFO_DWN | SBEFIFO_EOT_ACK, -+ SBEFIFO_EOT_MAGIC); -+} -+ -+static size_t sbefifo_dev_nwreadable(u32 sts) -+{ -+ static const u32 FIFO_NTRY_CNT_MSK = 0x000f0000; -+ static const unsigned int FIFO_NTRY_CNT_SHIFT = 16; -+ -+ return (sts & FIFO_NTRY_CNT_MSK) >> FIFO_NTRY_CNT_SHIFT; -+} -+ -+static size_t sbefifo_dev_nwwriteable(u32 sts) -+{ -+ static const size_t FIFO_DEPTH = 8; -+ -+ return FIFO_DEPTH - sbefifo_dev_nwreadable(sts); -+} -+ -+static void sbefifo_buf_init(struct sbefifo_buf *buf) -+{ -+ WRITE_ONCE(buf->rpos, buf->buf); -+ WRITE_ONCE(buf->wpos, buf->buf); -+} -+ -+static size_t sbefifo_buf_nbreadable(struct sbefifo_buf *buf) -+{ -+ size_t n; -+ u32 *rpos = READ_ONCE(buf->rpos); -+ u32 *wpos = READ_ONCE(buf->wpos); -+ -+ if (test_bit(SBEFIFO_BUF_FULL, &buf->flags)) -+ n = SBEFIFO_BUF_CNT; -+ else if (rpos <= wpos) -+ n = wpos - rpos; -+ else -+ n = (buf->buf + SBEFIFO_BUF_CNT) - rpos; -+ -+ return n << 2; -+} -+ -+static size_t sbefifo_buf_nbwriteable(struct sbefifo_buf *buf) -+{ -+ size_t n; -+ u32 *rpos = READ_ONCE(buf->rpos); -+ u32 *wpos = READ_ONCE(buf->wpos); -+ -+ if (test_bit(SBEFIFO_BUF_FULL, &buf->flags)) -+ n = 0; -+ else if (wpos < rpos) -+ n = rpos - wpos; -+ else -+ n = (buf->buf + SBEFIFO_BUF_CNT) - wpos; -+ -+ return n << 2; -+} -+ -+/* -+ * Update pointers and flags after doing a buffer read. Return true if the -+ * buffer is now empty; -+ */ -+static bool sbefifo_buf_readnb(struct sbefifo_buf *buf, size_t n) -+{ -+ u32 *rpos = READ_ONCE(buf->rpos); -+ u32 *wpos = READ_ONCE(buf->wpos); -+ -+ if (n) -+ clear_bit(SBEFIFO_BUF_FULL, &buf->flags); -+ -+ rpos += (n >> 2); -+ if (rpos == buf->buf + SBEFIFO_BUF_CNT) -+ rpos = buf->buf; -+ -+ WRITE_ONCE(buf->rpos, rpos); -+ return rpos == wpos; -+} -+ -+/* -+ * Update pointers and flags after doing a buffer write. Return true if the -+ * buffer is now full. -+ */ -+static bool sbefifo_buf_wrotenb(struct sbefifo_buf *buf, size_t n) -+{ -+ u32 *rpos = READ_ONCE(buf->rpos); -+ u32 *wpos = READ_ONCE(buf->wpos); -+ -+ wpos += (n >> 2); -+ if (wpos == buf->buf + SBEFIFO_BUF_CNT) -+ wpos = buf->buf; -+ if (wpos == rpos) -+ set_bit(SBEFIFO_BUF_FULL, &buf->flags); -+ -+ WRITE_ONCE(buf->wpos, wpos); -+ return rpos == wpos; -+} -+ -+static void sbefifo_free(struct kref *kref) -+{ -+ struct sbefifo *sbefifo; -+ -+ sbefifo = container_of(kref, struct sbefifo, kref); -+ kfree(sbefifo); -+} -+ -+static void sbefifo_get(struct sbefifo *sbefifo) -+{ -+ kref_get(&sbefifo->kref); -+} -+ -+static void sbefifo_put(struct sbefifo *sbefifo) -+{ -+ kref_put(&sbefifo->kref, sbefifo_free); -+} -+ -+static struct sbefifo_xfr *sbefifo_enq_xfr(struct sbefifo_client *client) -+{ -+ struct sbefifo *sbefifo = client->dev; -+ struct sbefifo_xfr *xfr; -+ -+ xfr = kzalloc(sizeof(*xfr), GFP_KERNEL); -+ if (!xfr) -+ return NULL; -+ -+ xfr->rbuf = &client->rbuf; -+ xfr->wbuf = &client->wbuf; -+ list_add_tail(&xfr->xfrs, &sbefifo->xfrs); -+ list_add_tail(&xfr->client, &client->xfrs); -+ -+ return xfr; -+} -+ -+static struct sbefifo_xfr *sbefifo_client_next_xfr( -+ struct sbefifo_client *client) -+{ -+ if (list_empty(&client->xfrs)) -+ return NULL; -+ -+ return container_of(client->xfrs.next, struct sbefifo_xfr, -+ client); -+} -+ -+static bool sbefifo_xfr_rsp_pending(struct sbefifo_client *client) -+{ -+ struct sbefifo_xfr *xfr; -+ -+ xfr = sbefifo_client_next_xfr(client); -+ if (xfr && test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags)) -+ return true; -+ -+ return false; -+} -+ -+static struct sbefifo_client *sbefifo_new_client(struct sbefifo *sbefifo) -+{ -+ struct sbefifo_client *client; -+ -+ client = kzalloc(sizeof(*client), GFP_KERNEL); -+ if (!client) -+ return NULL; -+ -+ kref_init(&client->kref); -+ client->dev = sbefifo; -+ sbefifo_buf_init(&client->rbuf); -+ sbefifo_buf_init(&client->wbuf); -+ INIT_LIST_HEAD(&client->xfrs); -+ -+ sbefifo_get(sbefifo); -+ -+ return client; -+} -+ -+static void sbefifo_client_release(struct kref *kref) -+{ -+ struct sbefifo_client *client; -+ struct sbefifo_xfr *xfr; -+ -+ client = container_of(kref, struct sbefifo_client, kref); -+ list_for_each_entry(xfr, &client->xfrs, client) { -+ /* -+ * The client left with pending or running xfrs. -+ * Cancel them. -+ */ -+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags); -+ sbefifo_get(client->dev); -+ if (mod_timer(&client->dev->poll_timer, jiffies)) -+ sbefifo_put(client->dev); -+ } -+ -+ sbefifo_put(client->dev); -+ kfree(client); -+} -+ -+static void sbefifo_get_client(struct sbefifo_client *client) -+{ -+ kref_get(&client->kref); -+} -+ -+static void sbefifo_put_client(struct sbefifo_client *client) -+{ -+ kref_put(&client->kref, sbefifo_client_release); -+} -+ -+static struct sbefifo_xfr *sbefifo_next_xfr(struct sbefifo *sbefifo) -+{ -+ struct sbefifo_xfr *xfr, *tmp; -+ -+ list_for_each_entry_safe(xfr, tmp, &sbefifo->xfrs, xfrs) { -+ if (unlikely(test_bit(SBEFIFO_XFR_CANCEL, &xfr->flags))) { -+ /* Discard cancelled transfers. */ -+ list_del(&xfr->xfrs); -+ kfree(xfr); -+ continue; -+ } -+ return xfr; -+ } -+ -+ return NULL; -+} -+ -+static void sbefifo_poll_timer(unsigned long data) -+{ -+ static const unsigned long EOT_MASK = 0x000000ff; -+ struct sbefifo *sbefifo = (void *)data; -+ struct sbefifo_buf *rbuf, *wbuf; -+ struct sbefifo_xfr *xfr = NULL; -+ struct sbefifo_buf drain; -+ size_t devn, bufn; -+ int eot = 0; -+ int ret = 0; -+ u32 sts; -+ int i; -+ -+ spin_lock(&sbefifo->lock); -+ xfr = list_first_entry_or_null(&sbefifo->xfrs, struct sbefifo_xfr, -+ xfrs); -+ if (!xfr) -+ goto out_unlock; -+ -+ rbuf = xfr->rbuf; -+ wbuf = xfr->wbuf; -+ -+ if (unlikely(test_bit(SBEFIFO_XFR_CANCEL, &xfr->flags))) { -+ /* The client left. */ -+ rbuf = &drain; -+ wbuf = &drain; -+ sbefifo_buf_init(&drain); -+ if (!test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags)) -+ set_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags); -+ } -+ -+ /* Drain the write buffer. */ -+ while ((bufn = sbefifo_buf_nbreadable(wbuf))) { -+ ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, -+ &sts); -+ if (ret) -+ goto out; -+ -+ devn = sbefifo_dev_nwwriteable(sts); -+ if (devn == 0) { -+ /* No open slot for write. Reschedule. */ -+ sbefifo->poll_timer.expires = jiffies + -+ msecs_to_jiffies(500); -+ add_timer(&sbefifo->poll_timer); -+ goto out_unlock; -+ } -+ -+ devn = min_t(size_t, devn, bufn >> 2); -+ for (i = 0; i < devn; i++) { -+ ret = sbefifo_writew(sbefifo, *wbuf->rpos); -+ if (ret) -+ goto out; -+ -+ sbefifo_buf_readnb(wbuf, 1 << 2); -+ } -+ } -+ -+ /* Send EOT if the writer is finished. */ -+ if (test_and_clear_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags)) { -+ ret = sbefifo_outw(sbefifo, -+ SBEFIFO_UP | SBEFIFO_EOT_RAISE, -+ SBEFIFO_EOT_MAGIC); -+ if (ret) -+ goto out; -+ -+ /* Inform reschedules that the writer is finished. */ -+ set_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags); -+ } -+ -+ /* Nothing left to do if the writer is not finished. */ -+ if (!test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags)) -+ goto out; -+ -+ /* Fill the read buffer. */ -+ while ((bufn = sbefifo_buf_nbwriteable(rbuf))) { -+ ret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &sts); -+ if (ret) -+ goto out; -+ -+ devn = sbefifo_dev_nwreadable(sts); -+ if (devn == 0) { -+ /* No data yet. Reschedule. */ -+ sbefifo->poll_timer.expires = jiffies + -+ msecs_to_jiffies(500); -+ add_timer(&sbefifo->poll_timer); -+ goto out_unlock; -+ } -+ -+ /* Fill. The EOT word is discarded. */ -+ devn = min_t(size_t, devn, bufn >> 2); -+ eot = (sts & EOT_MASK) != 0; -+ if (eot) -+ devn--; -+ -+ for (i = 0; i < devn; i++) { -+ ret = sbefifo_readw(sbefifo, rbuf->wpos); -+ if (ret) -+ goto out; -+ -+ if (likely(!test_bit(SBEFIFO_XFR_CANCEL, &xfr->flags))) -+ sbefifo_buf_wrotenb(rbuf, 1 << 2); -+ } -+ -+ if (eot) { -+ ret = sbefifo_ack_eot(sbefifo); -+ if (ret) -+ goto out; -+ -+ set_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags); -+ list_del(&xfr->xfrs); -+ if (unlikely(test_bit(SBEFIFO_XFR_CANCEL, -+ &xfr->flags))) -+ kfree(xfr); -+ break; -+ } -+ } -+ -+out: -+ if (unlikely(ret)) { -+ sbefifo->rc = ret; -+ dev_err(&sbefifo->fsi_dev->dev, -+ "Fatal bus access failure: %d\n", ret); -+ list_for_each_entry(xfr, &sbefifo->xfrs, xfrs) -+ kfree(xfr); -+ INIT_LIST_HEAD(&sbefifo->xfrs); -+ -+ } else if (eot && sbefifo_next_xfr(sbefifo)) { -+ sbefifo_get(sbefifo); -+ sbefifo->poll_timer.expires = jiffies; -+ add_timer(&sbefifo->poll_timer); -+ } -+ -+ sbefifo_put(sbefifo); -+ wake_up(&sbefifo->wait); -+ -+out_unlock: -+ spin_unlock(&sbefifo->lock); -+} -+ -+static int sbefifo_open(struct inode *inode, struct file *file) -+{ -+ struct sbefifo *sbefifo = container_of(file->private_data, -+ struct sbefifo, mdev); -+ struct sbefifo_client *client; -+ int ret; -+ -+ ret = READ_ONCE(sbefifo->rc); -+ if (ret) -+ return ret; -+ -+ client = sbefifo_new_client(sbefifo); -+ if (!client) -+ return -ENOMEM; -+ -+ file->private_data = client; -+ -+ return 0; -+} -+ -+static unsigned int sbefifo_poll(struct file *file, poll_table *wait) -+{ -+ struct sbefifo_client *client = file->private_data; -+ struct sbefifo *sbefifo = client->dev; -+ unsigned int mask = 0; -+ -+ poll_wait(file, &sbefifo->wait, wait); -+ -+ if (READ_ONCE(sbefifo->rc)) -+ mask |= POLLERR; -+ -+ if (sbefifo_buf_nbreadable(&client->rbuf)) -+ mask |= POLLIN; -+ -+ if (sbefifo_buf_nbwriteable(&client->wbuf)) -+ mask |= POLLOUT; -+ -+ return mask; -+} -+ -+static ssize_t sbefifo_read(struct file *file, char __user *buf, -+ size_t len, loff_t *offset) -+{ -+ struct sbefifo_client *client = file->private_data; -+ struct sbefifo *sbefifo = client->dev; -+ struct sbefifo_xfr *xfr; -+ ssize_t ret = 0; -+ size_t n; -+ -+ WARN_ON(*offset); -+ -+ if (!access_ok(VERIFY_WRITE, buf, len)) -+ return -EFAULT; -+ -+ if ((len >> 2) << 2 != len) -+ return -EINVAL; -+ -+ if ((file->f_flags & O_NONBLOCK) && !sbefifo_xfr_rsp_pending(client)) -+ return -EAGAIN; -+ -+ sbefifo_get_client(client); -+ if (wait_event_interruptible(sbefifo->wait, -+ (ret = READ_ONCE(sbefifo->rc)) || -+ (n = sbefifo_buf_nbreadable( -+ &client->rbuf)))) { -+ sbefifo_put_client(client); -+ return -ERESTARTSYS; -+ } -+ if (ret) { -+ INIT_LIST_HEAD(&client->xfrs); -+ sbefifo_put_client(client); -+ return ret; -+ } -+ -+ n = min_t(size_t, n, len); -+ -+ if (copy_to_user(buf, READ_ONCE(client->rbuf.rpos), n)) { -+ sbefifo_put_client(client); -+ return -EFAULT; -+ } -+ -+ if (sbefifo_buf_readnb(&client->rbuf, n)) { -+ xfr = sbefifo_client_next_xfr(client); -+ if (!test_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags)) { -+ /* -+ * Fill the read buffer back up. -+ */ -+ sbefifo_get(sbefifo); -+ if (mod_timer(&client->dev->poll_timer, jiffies)) -+ sbefifo_put(sbefifo); -+ } else { -+ kfree(xfr); -+ list_del(&xfr->client); -+ wake_up(&sbefifo->wait); -+ } -+ } -+ -+ sbefifo_put_client(client); -+ -+ return n; -+} -+ -+static ssize_t sbefifo_write(struct file *file, const char __user *buf, -+ size_t len, loff_t *offset) -+{ -+ struct sbefifo_client *client = file->private_data; -+ struct sbefifo *sbefifo = client->dev; -+ struct sbefifo_xfr *xfr; -+ ssize_t ret = 0; -+ size_t n; -+ -+ WARN_ON(*offset); -+ -+ if (!access_ok(VERIFY_READ, buf, len)) -+ return -EFAULT; -+ -+ if ((len >> 2) << 2 != len) -+ return -EINVAL; -+ -+ if (!len) -+ return 0; -+ -+ n = sbefifo_buf_nbwriteable(&client->wbuf); -+ -+ spin_lock_irq(&sbefifo->lock); -+ xfr = sbefifo_next_xfr(sbefifo); -+ -+ if ((file->f_flags & O_NONBLOCK) && xfr && n < len) { -+ spin_unlock_irq(&sbefifo->lock); -+ return -EAGAIN; -+ } -+ -+ xfr = sbefifo_enq_xfr(client); -+ if (!xfr) { -+ spin_unlock_irq(&sbefifo->lock); -+ return -ENOMEM; -+ } -+ spin_unlock_irq(&sbefifo->lock); -+ -+ sbefifo_get_client(client); -+ -+ /* -+ * Partial writes are not really allowed in that EOT is sent exactly -+ * once per write. -+ */ -+ while (len) { -+ if (wait_event_interruptible(sbefifo->wait, -+ READ_ONCE(sbefifo->rc) || -+ (sbefifo_client_next_xfr(client) == xfr && -+ (n = sbefifo_buf_nbwriteable( -+ &client->wbuf))))) { -+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags); -+ sbefifo_get(sbefifo); -+ if (mod_timer(&sbefifo->poll_timer, jiffies)) -+ sbefifo_put(sbefifo); -+ -+ sbefifo_put_client(client); -+ return -ERESTARTSYS; -+ } -+ if (sbefifo->rc) { -+ INIT_LIST_HEAD(&client->xfrs); -+ sbefifo_put_client(client); -+ return sbefifo->rc; -+ } -+ -+ n = min_t(size_t, n, len); -+ -+ if (copy_from_user(READ_ONCE(client->wbuf.wpos), buf, n)) { -+ set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags); -+ sbefifo_get(sbefifo); -+ if (mod_timer(&sbefifo->poll_timer, jiffies)) -+ sbefifo_put(sbefifo); -+ sbefifo_put_client(client); -+ return -EFAULT; -+ } -+ -+ sbefifo_buf_wrotenb(&client->wbuf, n); -+ len -= n; -+ buf += n; -+ ret += n; -+ -+ /* -+ * Drain the write buffer. -+ */ -+ sbefifo_get(sbefifo); -+ if (mod_timer(&client->dev->poll_timer, jiffies)) -+ sbefifo_put(sbefifo); -+ } -+ -+ set_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags); -+ sbefifo_put_client(client); -+ -+ return ret; -+} -+ -+static int sbefifo_release(struct inode *inode, struct file *file) -+{ -+ struct sbefifo_client *client = file->private_data; -+ struct sbefifo *sbefifo = client->dev; -+ -+ sbefifo_put_client(client); -+ -+ return READ_ONCE(sbefifo->rc); -+} -+ -+static const struct file_operations sbefifo_fops = { -+ .owner = THIS_MODULE, -+ .open = sbefifo_open, -+ .read = sbefifo_read, -+ .write = sbefifo_write, -+ .poll = sbefifo_poll, -+ .release = sbefifo_release, -+}; -+ -+static int sbefifo_probe(struct device *dev) -+{ -+ struct fsi_device *fsi_dev = to_fsi_dev(dev); -+ struct sbefifo *sbefifo; -+ u32 sts; -+ int ret; -+ -+ dev_info(dev, "Found sbefifo device\n"); -+ sbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL); -+ if (!sbefifo) -+ return -ENOMEM; -+ -+ sbefifo->fsi_dev = fsi_dev; -+ -+ ret = sbefifo_inw(sbefifo, -+ SBEFIFO_UP | SBEFIFO_STS, &sts); -+ if (ret) -+ return ret; -+ if (!(sts & SBEFIFO_EMPTY)) { -+ dev_err(&sbefifo->fsi_dev->dev, -+ "Found data in upstream fifo\n"); -+ return -EIO; -+ } -+ -+ ret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &sts); -+ if (ret) -+ return ret; -+ if (!(sts & SBEFIFO_EMPTY)) { -+ dev_err(&sbefifo->fsi_dev->dev, -+ "Found data in downstream fifo\n"); -+ return -EIO; -+ } -+ -+ sbefifo->mdev.minor = MISC_DYNAMIC_MINOR; -+ sbefifo->mdev.fops = &sbefifo_fops; -+ sbefifo->mdev.name = sbefifo->name; -+ sbefifo->mdev.parent = dev; -+ spin_lock_init(&sbefifo->lock); -+ kref_init(&sbefifo->kref); -+ -+ sbefifo->idx = ida_simple_get(&sbefifo_ida, 1, INT_MAX, GFP_KERNEL); -+ snprintf(sbefifo->name, sizeof(sbefifo->name), "sbefifo%d", -+ sbefifo->idx); -+ init_waitqueue_head(&sbefifo->wait); -+ INIT_LIST_HEAD(&sbefifo->xfrs); -+ -+ /* This bit of silicon doesn't offer any interrupts... */ -+ setup_timer(&sbefifo->poll_timer, sbefifo_poll_timer, -+ (unsigned long)sbefifo); -+ -+ list_add(&sbefifo->link, &sbefifo_fifos); -+ return misc_register(&sbefifo->mdev); -+} -+ -+static int sbefifo_remove(struct device *dev) -+{ -+ struct fsi_device *fsi_dev = to_fsi_dev(dev); -+ struct sbefifo *sbefifo, *sbefifo_tmp; -+ struct sbefifo_xfr *xfr; -+ -+ list_for_each_entry_safe(sbefifo, sbefifo_tmp, &sbefifo_fifos, link) { -+ if (sbefifo->fsi_dev != fsi_dev) -+ continue; -+ misc_deregister(&sbefifo->mdev); -+ list_del(&sbefifo->link); -+ ida_simple_remove(&sbefifo_ida, sbefifo->idx); -+ -+ if (del_timer_sync(&sbefifo->poll_timer)) -+ sbefifo_put(sbefifo); -+ -+ spin_lock(&sbefifo->lock); -+ list_for_each_entry(xfr, &sbefifo->xfrs, xfrs) -+ kfree(xfr); -+ spin_unlock(&sbefifo->lock); -+ -+ WRITE_ONCE(sbefifo->rc, -ENODEV); -+ -+ wake_up(&sbefifo->wait); -+ sbefifo_put(sbefifo); -+ } -+ -+ return 0; -+} -+ -+static struct fsi_device_id sbefifo_ids[] = { -+ { -+ .engine_type = FSI_ENGID_SBE, -+ .version = FSI_VERSION_ANY, -+ }, -+ { 0 } -+}; -+ -+static struct fsi_driver sbefifo_drv = { -+ .id_table = sbefifo_ids, -+ .drv = { -+ .name = DEVICE_NAME, -+ .bus = &fsi_bus_type, -+ .probe = sbefifo_probe, -+ .remove = sbefifo_remove, -+ } -+}; -+ -+static int sbefifo_init(void) -+{ -+ INIT_LIST_HEAD(&sbefifo_fifos); -+ return fsi_driver_register(&sbefifo_drv); -+} -+ -+static void sbefifo_exit(void) -+{ -+ fsi_driver_unregister(&sbefifo_drv); -+} -+ -+module_init(sbefifo_init); -+module_exit(sbefifo_exit); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Brad Bishop <bradleyb@fuzziesquirrel.com>"); -+MODULE_DESCRIPTION("Linux device interface to the POWER self boot engine"); diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch deleted file mode 100644 index f38a6a49a..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-1-6-drivers-i2c-Add-FSI-attached-I2C-master-algorithm.patch +++ /dev/null @@ -1,326 +0,0 @@ -From patchwork Wed May 10 15:52:37 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux, dev-4.10, v2, - 1/6] drivers: i2c: Add FSI-attached I2C master algorithm -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 760697 -Message-Id: <1494431562-25101-2-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com -Date: Wed, 10 May 2017 10:52:37 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -Initial startup code for the I2C algorithm to drive the I2C master -located on POWER CPUs over FSI bus. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/Makefile | 2 +- - drivers/i2c/busses/Kconfig | 11 ++ - drivers/i2c/busses/Makefile | 1 + - drivers/i2c/busses/i2c-fsi.c | 245 +++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 258 insertions(+), 1 deletion(-) - create mode 100644 drivers/i2c/busses/i2c-fsi.c - -diff --git a/drivers/Makefile b/drivers/Makefile -index 67ce51d..278f109 100644 ---- a/drivers/Makefile -+++ b/drivers/Makefile -@@ -105,6 +105,7 @@ obj-$(CONFIG_SERIO) += input/serio/ - obj-$(CONFIG_GAMEPORT) += input/gameport/ - obj-$(CONFIG_INPUT) += input/ - obj-$(CONFIG_RTC_LIB) += rtc/ -+obj-$(CONFIG_FSI) += fsi/ - obj-y += i2c/ media/ - obj-$(CONFIG_PPS) += pps/ - obj-y += ptp/ -@@ -173,4 +174,3 @@ obj-$(CONFIG_STM) += hwtracing/stm/ - obj-$(CONFIG_ANDROID) += android/ - obj-$(CONFIG_NVMEM) += nvmem/ - obj-$(CONFIG_FPGA) += fpga/ --obj-$(CONFIG_FSI) += fsi/ -diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index 7e34901d..0c714e0 100644 ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -1245,4 +1245,15 @@ config I2C_OPAL - This driver can also be built as a module. If so, the module will be - called as i2c-opal. - -+config I2C_FSI -+ tristate "FSI I2C driver" -+ depends on FSI -+ help -+ Driver for FSI bus attached I2C masters. These are I2C masters that -+ are connected to the system over a FSI bus, instead of the more -+ common PCI or MMIO interface. -+ -+ This driver can also be built as a module. If so, the module will be -+ called as i2c-fsi. -+ - endmenu -diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile -index 5798b4e..547773b 100644 ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -124,5 +124,6 @@ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o - obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o - obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o - obj-$(CONFIG_SCx200_ACB) += scx200_acb.o -+obj-$(CONFIG_I2C_FSI) += i2c-fsi.o - - ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG -diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c -new file mode 100644 -index 0000000..3c1087d ---- /dev/null -+++ b/drivers/i2c/busses/i2c-fsi.c -@@ -0,0 +1,245 @@ -+/* -+ * Copyright 2017 IBM Corporation -+ * -+ * Eddie James <eajames@us.ibm.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <linux/fsi.h> -+#include <linux/i2c.h> -+#include <linux/jiffies.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/sched.h> -+#include <linux/semaphore.h> -+#include <linux/wait.h> -+ -+#define FSI_ENGID_I2C_FSI 0x7 -+ -+/* Find left shift from first set bit in m */ -+#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1ULL) -+ -+/* Extract field m from v */ -+#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m)) -+ -+/* Set field m of v to val */ -+#define SETFIELD(m, v, val) \ -+ (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m))) -+ -+#define I2C_DEFAULT_CLK_DIV 6 -+ -+/* i2c registers */ -+#define I2C_FSI_FIFO 0x00 -+#define I2C_FSI_CMD 0x04 -+#define I2C_FSI_MODE 0x08 -+#define I2C_FSI_WATER_MARK 0x0C -+#define I2C_FSI_INT_MASK 0x10 -+#define I2C_FSI_INT_COND 0x14 -+#define I2C_FSI_OR_INT_MASK 0x14 -+#define I2C_FSI_INTS 0x18 -+#define I2C_FSI_AND_INT_MASK 0x18 -+#define I2C_FSI_STAT 0x1C -+#define I2C_FSI_RESET_I2C 0x1C -+#define I2C_FSI_ESTAT 0x20 -+#define I2C_FSI_RESET_ERR 0x20 -+#define I2C_FSI_RESID_LEN 0x24 -+#define I2C_FSI_SET_SCL 0x24 -+#define I2C_FSI_PORT_BUSY 0x28 -+#define I2C_FSI_RESET_SCL 0x2C -+#define I2C_FSI_SET_SDA 0x30 -+#define I2C_FSI_RESET_SDA 0x34 -+ -+/* cmd register */ -+#define I2C_CMD_WITH_START 0x80000000 -+#define I2C_CMD_WITH_ADDR 0x40000000 -+#define I2C_CMD_RD_CONT 0x20000000 -+#define I2C_CMD_WITH_STOP 0x10000000 -+#define I2C_CMD_FORCELAUNCH 0x08000000 -+#define I2C_CMD_ADDR 0x00fe0000 -+#define I2C_CMD_READ 0x00010000 -+#define I2C_CMD_LEN 0x0000ffff -+ -+/* mode register */ -+#define I2C_MODE_CLKDIV 0xffff0000 -+#define I2C_MODE_PORT 0x0000fc00 -+#define I2C_MODE_ENHANCED 0x00000008 -+#define I2C_MODE_DIAG 0x00000004 -+#define I2C_MODE_PACE_ALLOW 0x00000002 -+#define I2C_MODE_WRAP 0x00000001 -+ -+/* watermark register */ -+#define I2C_WATERMARK_HI 0x0000f000 -+#define I2C_WATERMARK_LO 0x000000f0 -+ -+#define I2C_FIFO_HI_LVL 4 -+#define I2C_FIFO_LO_LVL 4 -+ -+/* interrupt register */ -+#define I2C_INT_INV_CMD 0x00008000 -+#define I2C_INT_PARITY 0x00004000 -+#define I2C_INT_BE_OVERRUN 0x00002000 -+#define I2C_INT_BE_ACCESS 0x00001000 -+#define I2C_INT_LOST_ARB 0x00000800 -+#define I2C_INT_NACK 0x00000400 -+#define I2C_INT_DAT_REQ 0x00000200 -+#define I2C_INT_CMD_COMP 0x00000100 -+#define I2C_INT_STOP_ERR 0x00000080 -+#define I2C_INT_BUSY 0x00000040 -+#define I2C_INT_IDLE 0x00000020 -+ -+#define I2C_INT_ENABLE 0x0000ff80 -+#define I2C_INT_ERR 0x0000fcc0 -+ -+/* status register */ -+#define I2C_STAT_INV_CMD 0x80000000 -+#define I2C_STAT_PARITY 0x40000000 -+#define I2C_STAT_BE_OVERRUN 0x20000000 -+#define I2C_STAT_BE_ACCESS 0x10000000 -+#define I2C_STAT_LOST_ARB 0x08000000 -+#define I2C_STAT_NACK 0x04000000 -+#define I2C_STAT_DAT_REQ 0x02000000 -+#define I2C_STAT_CMD_COMP 0x01000000 -+#define I2C_STAT_STOP_ERR 0x00800000 -+#define I2C_STAT_MAX_PORT 0x000f0000 -+#define I2C_STAT_ANY_INT 0x00008000 -+#define I2C_STAT_SCL_IN 0x00000800 -+#define I2C_STAT_SDA_IN 0x00000400 -+#define I2C_STAT_PORT_BUSY 0x00000200 -+#define I2C_STAT_SELF_BUSY 0x00000100 -+#define I2C_STAT_FIFO_COUNT 0x000000ff -+ -+#define I2C_STAT_ERR 0xfc800000 -+#define I2C_STAT_ANY_RESP 0xff800000 -+ -+/* extended status register */ -+#define I2C_ESTAT_FIFO_SZ 0xff000000 -+#define I2C_ESTAT_SCL_IN_SY 0x00008000 -+#define I2C_ESTAT_SDA_IN_SY 0x00004000 -+#define I2C_ESTAT_S_SCL 0x00002000 -+#define I2C_ESTAT_S_SDA 0x00001000 -+#define I2C_ESTAT_M_SCL 0x00000800 -+#define I2C_ESTAT_M_SDA 0x00000400 -+#define I2C_ESTAT_HI_WATER 0x00000200 -+#define I2C_ESTAT_LO_WATER 0x00000100 -+#define I2C_ESTAT_PORT_BUSY 0x00000080 -+#define I2C_ESTAT_SELF_BUSY 0x00000040 -+#define I2C_ESTAT_VERSION 0x0000001f -+ -+struct fsi_i2c_master { -+ struct fsi_device *fsi; -+ u8 fifo_size; -+}; -+ -+static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg, -+ u32 *data) -+{ -+ int rc; -+ u32 raw_data; -+ -+ rc = fsi_device_read(fsi, reg, &raw_data, sizeof(raw_data)); -+ if (rc) -+ return rc; -+ -+ *data = be32_to_cpu(raw_data); -+ -+ return 0; -+} -+ -+static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg, -+ u32 *data) -+{ -+ u32 raw_data = cpu_to_be32(*data); -+ -+ return fsi_device_write(fsi, reg, &raw_data, sizeof(raw_data)); -+} -+ -+static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c) -+{ -+ int rc; -+ u32 mode = I2C_MODE_ENHANCED, extended_status, watermark = 0; -+ u32 interrupt = 0; -+ -+ /* since we use polling, disable interrupts */ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_INT_MASK, &interrupt); -+ if (rc) -+ return rc; -+ -+ mode = SETFIELD(I2C_MODE_CLKDIV, mode, I2C_DEFAULT_CLK_DIV); -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &extended_status); -+ if (rc) -+ return rc; -+ -+ i2c->fifo_size = GETFIELD(I2C_ESTAT_FIFO_SZ, extended_status); -+ watermark = SETFIELD(I2C_WATERMARK_HI, watermark, -+ i2c->fifo_size - I2C_FIFO_HI_LVL); -+ watermark = SETFIELD(I2C_WATERMARK_LO, watermark, -+ I2C_FIFO_LO_LVL); -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_WATER_MARK, &watermark); -+ -+ return rc; -+} -+ -+static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, -+ int num) -+{ -+ return -ENOSYS; -+} -+ -+static u32 fsi_i2c_functionality(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_10BIT_ADDR; -+} -+ -+static const struct i2c_algorithm fsi_i2c_algorithm = { -+ .master_xfer = fsi_i2c_xfer, -+ .functionality = fsi_i2c_functionality, -+}; -+ -+static int fsi_i2c_probe(struct device *dev) -+{ -+ struct fsi_i2c_master *i2c; -+ int rc; -+ -+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); -+ if (!i2c) -+ return -ENOMEM; -+ -+ i2c->fsi = to_fsi_dev(dev); -+ -+ rc = fsi_i2c_dev_init(i2c); -+ if (rc) -+ return rc; -+ -+ dev_set_drvdata(dev, i2c); -+ -+ return 0; -+} -+ -+static const struct fsi_device_id fsi_i2c_ids[] = { -+ { FSI_ENGID_I2C_FSI, FSI_VERSION_ANY }, -+ { 0 } -+}; -+ -+static struct fsi_driver fsi_i2c_driver = { -+ .id_table = fsi_i2c_ids, -+ .drv = { -+ .name = "i2c_master_fsi", -+ .bus = &fsi_bus_type, -+ .probe = fsi_i2c_probe, -+ }, -+}; -+ -+module_fsi_driver(fsi_i2c_driver); -+ -+MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>"); -+MODULE_DESCRIPTION("FSI attached I2C master"); -+MODULE_LICENSE("GPL"); diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch deleted file mode 100644 index 20f66bfa7..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-2-6-drivers-i2c-Add-port-structure-to-FSI-algorithm.patch +++ /dev/null @@ -1,194 +0,0 @@ -From patchwork Wed May 10 15:52:38 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux, dev-4.10, v2, - 2/6] drivers: i2c: Add port structure to FSI algorithm -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 760696 -Message-Id: <1494431562-25101-3-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com -Date: Wed, 10 May 2017 10:52:38 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -Add and initialize I2C adapters for each port on the FSI-attached I2C -master. Ports are defined in the devicetree. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/i2c/busses/i2c-fsi.c | 113 ++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 112 insertions(+), 1 deletion(-) - -diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c -index 3c1087d..cdebc99 100644 ---- a/drivers/i2c/busses/i2c-fsi.c -+++ b/drivers/i2c/busses/i2c-fsi.c -@@ -30,6 +30,7 @@ - #define SETFIELD(m, v, val) \ - (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m))) - -+#define I2C_MASTER_NR_OFFSET 100 - #define I2C_DEFAULT_CLK_DIV 6 - - /* i2c registers */ -@@ -131,9 +132,21 @@ - - struct fsi_i2c_master { - struct fsi_device *fsi; -+ int idx; - u8 fifo_size; -+ struct list_head ports; -+ struct ida ida; - }; - -+struct fsi_i2c_port { -+ struct list_head list; -+ struct i2c_adapter adapter; -+ struct fsi_i2c_master *master; -+ u16 port; -+}; -+ -+static DEFINE_IDA(fsi_i2c_ida); -+ - static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg, - u32 *data) - { -@@ -188,9 +201,44 @@ static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c) - return rc; - } - -+static int fsi_i2c_set_port(struct fsi_i2c_port *port) -+{ -+ int rc; -+ struct fsi_device *fsi = port->master->fsi; -+ u32 mode, dummy = 0; -+ u16 old_port; -+ -+ rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode); -+ if (rc) -+ return rc; -+ -+ old_port = GETFIELD(I2C_MODE_PORT, mode); -+ -+ if (old_port != port->port) { -+ mode = SETFIELD(I2C_MODE_PORT, mode, port->port); -+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode); -+ if (rc) -+ return rc; -+ -+ /* reset engine when port is changed */ -+ rc = fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy); -+ if (rc) -+ return rc; -+ } -+ -+ return rc; -+} -+ - static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) - { -+ int rc; -+ struct fsi_i2c_port *port = adap->algo_data; -+ -+ rc = fsi_i2c_set_port(port); -+ if (rc) -+ return rc; -+ - return -ENOSYS; - } - -@@ -207,13 +255,59 @@ static u32 fsi_i2c_functionality(struct i2c_adapter *adap) - static int fsi_i2c_probe(struct device *dev) - { - struct fsi_i2c_master *i2c; -- int rc; -+ struct fsi_i2c_port *port; -+ struct device_node *np; -+ int rc, idx; -+ u32 port_no; - - i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) - return -ENOMEM; - - i2c->fsi = to_fsi_dev(dev); -+ i2c->idx = ida_simple_get(&fsi_i2c_ida, 1, INT_MAX, GFP_KERNEL); -+ ida_init(&i2c->ida); -+ INIT_LIST_HEAD(&i2c->ports); -+ -+ if (dev->of_node) { -+ /* add adapter for each i2c port of the master */ -+ for_each_child_of_node(dev->of_node, np) { -+ rc = of_property_read_u32(np, "port", &port_no); -+ if (rc || port_no > 0xFFFF) -+ continue; -+ -+ /* make sure we don't overlap index with a buggy dts */ -+ idx = ida_simple_get(&i2c->ida, port_no, -+ port_no + 1, GFP_KERNEL); -+ if (idx < 0) -+ continue; -+ -+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); -+ if (!port) -+ return -ENOMEM; -+ -+ port->master = i2c; -+ port->port = (u16)port_no; -+ -+ port->adapter.owner = THIS_MODULE; -+ port->adapter.dev.parent = dev; -+ port->adapter.algo = &fsi_i2c_algorithm; -+ port->adapter.algo_data = port; -+ /* number ports uniquely */ -+ port->adapter.nr = (i2c->idx * I2C_MASTER_NR_OFFSET) + -+ port_no; -+ -+ snprintf(port->adapter.name, -+ sizeof(port->adapter.name), -+ "fsi_i2c-%u", port_no); -+ -+ rc = i2c_add_numbered_adapter(&port->adapter); -+ if (rc < 0) -+ return rc; -+ -+ list_add(&port->list, &i2c->ports); -+ } -+ } - - rc = fsi_i2c_dev_init(i2c); - if (rc) -@@ -224,6 +318,22 @@ static int fsi_i2c_probe(struct device *dev) - return 0; - } - -+static int fsi_i2c_remove(struct device *dev) -+{ -+ struct fsi_i2c_master *i2c = dev_get_drvdata(dev); -+ struct fsi_i2c_port *port; -+ -+ list_for_each_entry(port, &i2c->ports, list) { -+ i2c_del_adapter(&port->adapter); -+ } -+ -+ ida_destroy(&i2c->ida); -+ -+ ida_simple_remove(&fsi_i2c_ida, i2c->idx); -+ -+ return 0; -+} -+ - static const struct fsi_device_id fsi_i2c_ids[] = { - { FSI_ENGID_I2C_FSI, FSI_VERSION_ANY }, - { 0 } -@@ -235,6 +345,7 @@ static int fsi_i2c_probe(struct device *dev) - .name = "i2c_master_fsi", - .bus = &fsi_bus_type, - .probe = fsi_i2c_probe, -+ .remove = fsi_i2c_remove, - }, - }; - diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch deleted file mode 100644 index 50410ffc8..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-3-6-drivers-i2c-Add-transfer-implementation-for-FSI-algorithm.patch +++ /dev/null @@ -1,243 +0,0 @@ -From patchwork Wed May 10 15:52:39 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux, dev-4.10, v2, - 3/6] drivers: i2c: Add transfer implementation for FSI algorithm -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 760702 -Message-Id: <1494431562-25101-4-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com -Date: Wed, 10 May 2017 10:52:39 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -Execute I2C transfers from the FSI-attached I2C master. Use polling -instead of interrupts as we have no hardware IRQ over FSI. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/i2c/busses/i2c-fsi.c | 193 ++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 191 insertions(+), 2 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c -index cdebc99..f690b16 100644 ---- a/drivers/i2c/busses/i2c-fsi.c -+++ b/drivers/i2c/busses/i2c-fsi.c -@@ -143,6 +143,7 @@ struct fsi_i2c_port { - struct i2c_adapter adapter; - struct fsi_i2c_master *master; - u16 port; -+ u16 xfrd; - }; - - static DEFINE_IDA(fsi_i2c_ida); -@@ -229,17 +230,205 @@ static int fsi_i2c_set_port(struct fsi_i2c_port *port) - return rc; - } - -+static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg, -+ bool stop) -+{ -+ int rc; -+ struct fsi_i2c_master *i2c = port->master; -+ u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR; -+ -+ port->xfrd = 0; -+ -+ if (msg->flags & I2C_M_RD) -+ cmd |= I2C_CMD_READ; -+ -+ if (stop || msg->flags & I2C_M_STOP) -+ cmd |= I2C_CMD_WITH_STOP; -+ -+ cmd = SETFIELD(I2C_CMD_ADDR, cmd, msg->addr >> 1); -+ cmd = SETFIELD(I2C_CMD_LEN, cmd, msg->len); -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd); -+ -+ return rc; -+} -+ -+static int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, -+ u8 fifo_count) -+{ -+ int write; -+ int rc = 0; -+ struct fsi_i2c_master *i2c = port->master; -+ int bytes_to_write = i2c->fifo_size - fifo_count; -+ int bytes_remaining = msg->len - port->xfrd; -+ -+ if (bytes_to_write > bytes_remaining) -+ bytes_to_write = bytes_remaining; -+ -+ while (bytes_to_write > 0) { -+ write = bytes_to_write; -+ /* fsi limited to max 4 byte aligned ops */ -+ if (bytes_to_write > 4) -+ write = 4; -+ else if (write == 3) -+ write = 2; -+ -+ rc = fsi_device_write(i2c->fsi, I2C_FSI_FIFO, -+ &msg->buf[port->xfrd], write); -+ if (rc) -+ return rc; -+ -+ port->xfrd += write; -+ bytes_to_write -= write; -+ } -+ -+ return rc; -+} -+ -+static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, -+ u8 fifo_count) -+{ -+ int read; -+ int rc = 0; -+ struct fsi_i2c_master *i2c = port->master; -+ int xfr_remaining = msg->len - port->xfrd; -+ u32 dummy; -+ -+ while (fifo_count) { -+ read = fifo_count; -+ /* fsi limited to max 4 byte aligned ops */ -+ if (fifo_count > 4) -+ read = 4; -+ else if (read == 3) -+ read = 2; -+ -+ if (xfr_remaining) { -+ if (xfr_remaining < read) -+ read = xfr_remaining; -+ -+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, -+ &msg->buf[port->xfrd], read); -+ if (rc) -+ return rc; -+ -+ port->xfrd += read; -+ xfr_remaining -= read; -+ } else { -+ /* no more buffer but data in fifo, need to clear it */ -+ rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, &dummy, -+ read); -+ if (rc) -+ return rc; -+ } -+ -+ fifo_count -= read; -+ } -+ -+ return rc; -+} -+ -+static int fsi_i2c_handle_status(struct fsi_i2c_port *port, -+ struct i2c_msg *msg, u32 status) -+{ -+ int rc; -+ u8 fifo_count; -+ struct fsi_i2c_master *i2c = port->master; -+ u32 dummy = 0; -+ -+ if (status & I2C_STAT_ERR) { -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); -+ if (rc) -+ return rc; -+ -+ if (status & I2C_STAT_NACK) -+ return -EFAULT; -+ -+ return -EIO; -+ } -+ -+ if (status & I2C_STAT_DAT_REQ) { -+ fifo_count = GETFIELD(I2C_STAT_FIFO_COUNT, status); -+ -+ if (msg->flags & I2C_M_RD) -+ rc = fsi_i2c_read_fifo(port, msg, fifo_count); -+ else -+ rc = fsi_i2c_write_fifo(port, msg, fifo_count); -+ -+ return rc; -+ } -+ -+ if (status & I2C_STAT_CMD_COMP) { -+ if (port->xfrd < msg->len) -+ rc = -ENODATA; -+ else -+ rc = msg->len; -+ } -+ -+ return rc; -+} -+ -+static int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg, -+ unsigned long timeout) -+{ -+ const unsigned long local_timeout = 2; /* jiffies */ -+ u32 status = 0; -+ int rc; -+ -+ do { -+ rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT, -+ &status); -+ if (rc) -+ return rc; -+ -+ if (status & I2C_STAT_ANY_RESP) { -+ rc = fsi_i2c_handle_status(port, msg, status); -+ if (rc < 0) -+ return rc; -+ -+ /* cmd complete and all data xfrd */ -+ if (rc == msg->len) -+ return 0; -+ -+ /* need to xfr more data, but maybe don't need wait */ -+ continue; -+ } -+ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(local_timeout); -+ timeout = (timeout < local_timeout) ? 0 : -+ timeout - local_timeout; -+ } while (timeout); -+ -+ return -ETIME; -+} -+ - static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) - { -- int rc; -+ int i, rc; -+ unsigned long start_time; - struct fsi_i2c_port *port = adap->algo_data; -+ struct i2c_msg *msg; - - rc = fsi_i2c_set_port(port); - if (rc) - return rc; - -- return -ENOSYS; -+ for (i = 0; i < num; ++i) { -+ msg = msgs + i; -+ start_time = jiffies; -+ -+ rc = fsi_i2c_start(port, msg, i == num - 1); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_wait(port, msg, -+ adap->timeout - (jiffies - start_time)); -+ if (rc) -+ return rc; -+ } -+ -+ return 0; - } - - static u32 fsi_i2c_functionality(struct i2c_adapter *adap) diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch deleted file mode 100644 index e649d628f..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-4-6-drivers-i2c-Add-I2C-master-locking-to-FSI-algorithm.patch +++ /dev/null @@ -1,112 +0,0 @@ -From patchwork Wed May 10 15:52:40 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux, dev-4.10, v2, - 4/6] drivers: i2c: Add I2C master locking to FSI algorithm -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 760699 -Message-Id: <1494431562-25101-5-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com -Date: Wed, 10 May 2017 10:52:40 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -Since there are many ports per master, each with it's own adapter and -chardev, we need some locking to prevent xfers from changing the master -state while other xfers are in progress. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/i2c/busses/i2c-fsi.c | 41 +++++++++++++++++++++++++++++++++++++---- - 1 file changed, 37 insertions(+), 4 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c -index f690b16..d757aee 100644 ---- a/drivers/i2c/busses/i2c-fsi.c -+++ b/drivers/i2c/busses/i2c-fsi.c -@@ -136,6 +136,8 @@ struct fsi_i2c_master { - u8 fifo_size; - struct list_head ports; - struct ida ida; -+ wait_queue_head_t wait; -+ struct semaphore lock; - }; - - struct fsi_i2c_port { -@@ -171,6 +173,29 @@ static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg, - return fsi_device_write(fsi, reg, &raw_data, sizeof(raw_data)); - } - -+static int fsi_i2c_lock_master(struct fsi_i2c_master *i2c, int timeout) -+{ -+ int rc; -+ -+ rc = down_trylock(&i2c->lock); -+ if (!rc) -+ return 0; -+ -+ rc = wait_event_interruptible_timeout(i2c->wait, -+ !down_trylock(&i2c->lock), -+ timeout); -+ if (rc > 0) -+ return 0; -+ -+ return -EBUSY; -+} -+ -+static void fsi_i2c_unlock_master(struct fsi_i2c_master *i2c) -+{ -+ up(&i2c->lock); -+ wake_up(&i2c->wait); -+} -+ - static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c) - { - int rc; -@@ -410,25 +435,31 @@ static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - struct fsi_i2c_port *port = adap->algo_data; - struct i2c_msg *msg; - -- rc = fsi_i2c_set_port(port); -+ rc = fsi_i2c_lock_master(port->master, adap->timeout); - if (rc) - return rc; - -+ rc = fsi_i2c_set_port(port); -+ if (rc) -+ goto unlock; -+ - for (i = 0; i < num; ++i) { - msg = msgs + i; - start_time = jiffies; - - rc = fsi_i2c_start(port, msg, i == num - 1); - if (rc) -- return rc; -+ goto unlock; - - rc = fsi_i2c_wait(port, msg, - adap->timeout - (jiffies - start_time)); - if (rc) -- return rc; -+ goto unlock; - } - -- return 0; -+unlock: -+ fsi_i2c_unlock_master(port->master); -+ return rc; - } - - static u32 fsi_i2c_functionality(struct i2c_adapter *adap) -@@ -453,6 +484,8 @@ static int fsi_i2c_probe(struct device *dev) - if (!i2c) - return -ENOMEM; - -+ init_waitqueue_head(&i2c->wait); -+ sema_init(&i2c->lock, 1); - i2c->fsi = to_fsi_dev(dev); - i2c->idx = ida_simple_get(&fsi_i2c_ida, 1, INT_MAX, GFP_KERNEL); - ida_init(&i2c->ida); diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch deleted file mode 100644 index f9fc75d4a..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/linux-dev-4.10-v2-5-6-drivers-i2c-Add-bus-recovery-for-FSI-algorithm.patch +++ /dev/null @@ -1,117 +0,0 @@ -From patchwork Wed May 10 15:52:41 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [linux, dev-4.10, v2, - 5/6] drivers: i2c: Add bus recovery for FSI algorithm -From: eajames@linux.vnet.ibm.com -X-Patchwork-Id: 760701 -Message-Id: <1494431562-25101-6-git-send-email-eajames@linux.vnet.ibm.com> -To: openbmc@lists.ozlabs.org -Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com -Date: Wed, 10 May 2017 10:52:41 -0500 - -From: "Edward A. James" <eajames@us.ibm.com> - -Bus recovery should reset the engine and force block the bus 9 times -to recover most situations. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - drivers/i2c/busses/i2c-fsi.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 76 insertions(+) - -diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c -index d757aee..4689479 100644 ---- a/drivers/i2c/busses/i2c-fsi.c -+++ b/drivers/i2c/busses/i2c-fsi.c -@@ -467,6 +467,80 @@ static u32 fsi_i2c_functionality(struct i2c_adapter *adap) - return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_10BIT_ADDR; - } - -+static int fsi_i2c_low_level_recover_bus(struct fsi_i2c_master *i2c) -+{ -+ int i, rc; -+ u32 mode, dummy = 0; -+ -+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); -+ if (rc) -+ return rc; -+ -+ mode |= I2C_MODE_DIAG; -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); -+ if (rc) -+ return rc; -+ -+ for (i = 0; i < 9; ++i) { -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); -+ if (rc) -+ return rc; -+ } -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); -+ if (rc) -+ return rc; -+ -+ mode &= ~I2C_MODE_DIAG; -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); -+ -+ return rc; -+} -+ -+static int fsi_i2c_recover_bus(struct i2c_adapter *adap) -+{ -+ int rc; -+ u32 dummy = 0; -+ struct fsi_i2c_port *port = adap->algo_data; -+ struct fsi_i2c_master *i2c = port->master; -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_dev_init(i2c); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_low_level_recover_bus(i2c); -+ if (rc) -+ return rc; -+ -+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); -+ -+ return rc; -+} -+ -+static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = { -+ .recover_bus = fsi_i2c_recover_bus, -+}; -+ - static const struct i2c_algorithm fsi_i2c_algorithm = { - .master_xfer = fsi_i2c_xfer, - .functionality = fsi_i2c_functionality, -@@ -514,6 +588,8 @@ static int fsi_i2c_probe(struct device *dev) - port->adapter.owner = THIS_MODULE; - port->adapter.dev.parent = dev; - port->adapter.algo = &fsi_i2c_algorithm; -+ port->adapter.bus_recovery_info = -+ &fsi_i2c_bus_recovery_info; - port->adapter.algo_data = port; - /* number ports uniquely */ - port->adapter.nr = (i2c->idx * I2C_MASTER_NR_OFFSET) + diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch deleted file mode 100644 index 01644c517..000000000 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc/v2-0001-arm-dts-aspeed-Add-missing-clock-sources-for-barr.patch +++ /dev/null @@ -1,196 +0,0 @@ -From af9bc81e2158c326552c013d6591f533b69286e3 Mon Sep 17 00:00:00 2001 -From: "Edward A. James" <eajames@us.ibm.com> -Date: Thu, 25 May 2017 09:59:09 -0500 -Subject: [PATCH linux dev-4.10 v2] arm: dts: aspeed: Add missing clock sources - for barreleye - -Reorganize flash controllers into the ast2400 config. Barreleye wasn't -booting with the new aspeed-smc driver. - -Signed-off-by: Edward A. James <eajames@us.ibm.com> ---- - arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts | 44 ++++++++-------------- - arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts | 52 ++++++++------------------ - arch/arm/boot/dts/aspeed-g4.dtsi | 34 +++++++++++++++++ - 3 files changed, 66 insertions(+), 64 deletions(-) - -diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts b/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts -index be1f2d1..7a616bb 100644 ---- a/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts -+++ b/arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts -@@ -31,34 +31,6 @@ - }; - }; - -- ahb { -- bmc_pnor: fmc@1e620000 { -- reg = < 0x1e620000 0x94 -- 0x20000000 0x02000000 >; -- #address-cells = <1>; -- #size-cells = <0>; -- compatible = "aspeed,ast2400-fmc"; -- flash@0 { -- reg = < 0 >; -- compatible = "jedec,spi-nor" ; --#include "aspeed-bmc-opp-flash-layout.dtsi" -- }; -- }; -- -- host_pnor: spi@1e630000 { -- reg = < 0x1e630000 0x18 -- 0x30000000 0x02000000 >; -- #address-cells = <1>; -- #size-cells = <0>; -- compatible = "aspeed,ast2400-spi"; -- flash@0 { -- reg = < 0 >; -- compatible = "jedec,spi-nor" ; -- label = "pnor"; -- }; -- }; -- }; -- - leds { - compatible = "gpio-leds"; - -@@ -76,6 +48,22 @@ - }; - }; - -+&bmc_pnor { -+ status = "okay"; -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+#include "aspeed-bmc-opp-flash-layout.dtsi" -+ }; -+}; -+ -+&host_pnor { -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ }; -+}; -+ - &pinctrl { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_flbusy_default &pinctrl_flwp_default -diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts -index b4faa1d..e55abe6 100644 ---- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts -+++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts -@@ -47,42 +47,6 @@ - }; - }; - -- ahb { -- bmc_pnor: fmc@1e620000 { -- reg = < 0x1e620000 0x94 -- 0x20000000 0x02000000 >; -- #address-cells = <1>; -- #size-cells = <0>; -- compatible = "aspeed,ast2400-fmc"; -- aspeed,fmc-has-dma; -- interrupts = <19>; -- clocks = <&clk_ahb>; -- clock-names = "ahb"; -- flash@0 { -- reg = < 0 >; -- compatible = "jedec,spi-nor" ; -- m25p,fast-read; --#include "aspeed-bmc-opp-flash-layout.dtsi" -- }; -- }; -- -- host_pnor: spi@1e630000 { -- reg = < 0x1e630000 0x18 -- 0x30000000 0x02000000 >; -- #address-cells = <1>; -- #size-cells = <0>; -- compatible = "aspeed,ast2400-spi"; -- clocks = <&clk_ahb>; -- clock-names = "ahb"; -- flash { -- reg = < 0 >; -- compatible = "jedec,spi-nor" ; -- label = "pnor"; -- m25p,fast-read; -- }; -- }; -- }; -- - gpio-fsi { - compatible = "fsi-master-gpio", "fsi-master"; - -@@ -94,6 +58,22 @@ - }; - }; - -+&bmc_pnor { -+ status = "okay"; -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+#include "aspeed-bmc-opp-flash-layout.dtsi" -+ }; -+}; -+ -+&host_pnor { -+ flash@0 { -+ status = "okay"; -+ m25p,fast-read; -+ }; -+}; -+ - &pinctrl { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_flbusy_default &pinctrl_flwp_default -diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index d8827d5..9fb7889 100644 ---- a/arch/arm/boot/dts/aspeed-g4.dtsi -+++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -44,6 +44,40 @@ - #size-cells = <1>; - ranges; - -+ bmc_pnor: fmc@1e620000 { -+ reg = < 0x1e620000 0x94 -+ 0x20000000 0x02000000 >; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "aspeed,ast2400-fmc"; -+ status = "disabled"; -+ aspeed,fmc-has-dma; -+ interrupts = <19>; -+ clocks = <&clk_ahb>; -+ clock-names = "ahb"; -+ flash@0 { -+ reg = < 0 >; -+ compatible = "jedec,spi-nor" ; -+ status = "disabled"; -+ }; -+ }; -+ -+ host_pnor: spi@1e630000 { -+ reg = < 0x1e630000 0x18 -+ 0x30000000 0x02000000 >; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "aspeed,ast2400-spi"; -+ status = "disabled"; -+ clocks = <&clk_ahb>; -+ clock-names = "ahb"; -+ flash@0 { -+ reg = < 0 >; -+ compatible = "jedec,spi-nor" ; -+ status = "disabled"; -+ }; -+ }; -+ - vic: interrupt-controller@1e6c0080 { - compatible = "aspeed,ast2400-vic"; - interrupt-controller; --- -1.8.3.1 - diff --git a/meta-phosphor/common/recipes-kernel/linux/linux-obmc_4.10.bb b/meta-phosphor/common/recipes-kernel/linux/linux-obmc_4.10.bb index 3a0dd9a64..5b2cabd63 100644 --- a/meta-phosphor/common/recipes-kernel/linux/linux-obmc_4.10.bb +++ b/meta-phosphor/common/recipes-kernel/linux/linux-obmc_4.10.bb @@ -1,6 +1,6 @@ KBRANCH ?= "dev-4.10" -LINUX_VERSION ?= "4.10.5" +LINUX_VERSION ?= "4.10.17" -SRCREV="8736136e756ec127de0bbe2c7e2de683204d4512" +SRCREV="c694e47cbc1efc2bc181b2ac7137dfda04f974c2" require linux-obmc.inc |