summaryrefslogtreecommitdiff
path: root/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch')
-rw-r--r--meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch236
1 files changed, 236 insertions, 0 deletions
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
new file mode 100644
index 000000000..6fdfe93cd
--- /dev/null
+++ b/meta-phosphor/common/recipes-kernel/linux/linux-obmc/0001-fsi-Match-fsi-slaves-engines-to-available-device-tre.patch
@@ -0,0 +1,236 @@
+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
+