* [PATCH v5 20/23] drivers/fsi/gpio: Add tracepoints for GPIO master
From: Christopher Bostic @ 2017-04-05 2:06 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Jeremy Kerr, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r, Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Add trace points for key GPIO operations of the GPIO based FSI
master.
Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
drivers/fsi/fsi-master-gpio.c | 9 +++++
include/trace/events/fsi_master_gpio.h | 68 ++++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+)
create mode 100644 include/trace/events/fsi_master_gpio.h
diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c
index 9fedfaf..5d9e0b0 100644
--- a/drivers/fsi/fsi-master-gpio.c
+++ b/drivers/fsi/fsi-master-gpio.c
@@ -61,6 +61,9 @@ struct fsi_master_gpio {
struct gpio_desc *gpio_mux; /* Mux control */
};
+#define CREATE_TRACE_POINTS
+#include <trace/events/fsi_master_gpio.h>
+
#define to_fsi_master_gpio(m) container_of(m, struct fsi_master_gpio, master)
struct fsi_gpio_msg {
@@ -128,6 +131,8 @@ static void serial_in(struct fsi_master_gpio *master, struct fsi_gpio_msg *msg,
msg->msg |= ~in_bit & 0x1; /* Data is negative active */
}
msg->bits += num_bits;
+
+ trace_fsi_master_gpio_in(master, num_bits, msg->msg);
}
static void serial_out(struct fsi_master_gpio *master,
@@ -139,6 +144,8 @@ static void serial_out(struct fsi_master_gpio *master,
uint64_t last_bit = ~0;
int next_bit;
+ trace_fsi_master_gpio_out(master, cmd->bits, cmd->msg);
+
if (!cmd->bits) {
dev_warn(master->dev, "trying to output 0 bits\n");
return;
@@ -464,6 +471,8 @@ static int fsi_master_gpio_break(struct fsi_master *_master, int link)
if (link != 0)
return -ENODEV;
+ trace_fsi_master_gpio_break(master);
+
set_sda_output(master, 1);
sda_out(master, 1);
clock_toggle(master, FSI_PRE_BREAK_CLOCKS);
diff --git a/include/trace/events/fsi_master_gpio.h b/include/trace/events/fsi_master_gpio.h
new file mode 100644
index 0000000..11b36c1
--- /dev/null
+++ b/include/trace/events/fsi_master_gpio.h
@@ -0,0 +1,68 @@
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM fsi_master_gpio
+
+#if !defined(_TRACE_FSI_MASTER_GPIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FSI_MASTER_GPIO_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(fsi_master_gpio_in,
+ TP_PROTO(const struct fsi_master_gpio *master, int bits, uint64_t msg),
+ TP_ARGS(master, bits, msg),
+ TP_STRUCT__entry(
+ __field(int, master_idx)
+ __field(int, bits)
+ __field(uint64_t, msg)
+ ),
+ TP_fast_assign(
+ __entry->master_idx = master->master.idx;
+ __entry->bits = bits;
+ __entry->msg = msg & ((1ull<<bits) - 1);
+ ),
+ TP_printk("fsi-gpio%d => %0*llx[%d]",
+ __entry->master_idx,
+ (__entry->bits + 3) / 4,
+ __entry->msg,
+ __entry->bits
+ )
+);
+
+TRACE_EVENT(fsi_master_gpio_out,
+ TP_PROTO(const struct fsi_master_gpio *master, int bits, uint64_t msg),
+ TP_ARGS(master, bits, msg),
+ TP_STRUCT__entry(
+ __field(int, master_idx)
+ __field(int, bits)
+ __field(uint64_t, msg)
+ ),
+ TP_fast_assign(
+ __entry->master_idx = master->master.idx;
+ __entry->bits = bits;
+ __entry->msg = msg & ((1ull<<bits) - 1);
+ ),
+ TP_printk("fsi-gpio%d <= %0*llx[%d]",
+ __entry->master_idx,
+ (__entry->bits + 3) / 4,
+ __entry->msg,
+ __entry->bits
+ )
+);
+
+TRACE_EVENT(fsi_master_gpio_break,
+ TP_PROTO(const struct fsi_master_gpio *master),
+ TP_ARGS(master),
+ TP_STRUCT__entry(
+ __field(int, master_idx)
+ ),
+ TP_fast_assign(
+ __entry->master_idx = master->master.idx;
+ ),
+ TP_printk("fsi-gpio%d ----break---",
+ __entry->master_idx
+ )
+);
+
+#endif /* _TRACE_FSI_MASTER_GPIO_H */
+
+#include <trace/define_trace.h>
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 19/23] drivers/fsi: Add GPIO based FSI master
From: Christopher Bostic @ 2017-04-05 2:06 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Chris Bostic, joel, linux-kernel, andrew, alistair, benh,
Edward A . James, Jeremy Kerr
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Chris Bostic <cbostic@linux.vnet.ibm.com>
Implement a FSI master using GPIO. Will generate FSI protocol for
read and write commands to particular addresses. Sends master command
and waits for and decodes a slave response.
Includes changes from Edward A. James <eajames@us.ibm.com> and Jeremy
Kerr <jk@ozlabs.org>.
Signed-off-by: Edward A. James <eajames@us.ibm.com>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
drivers/fsi/Kconfig | 11 +
drivers/fsi/Makefile | 1 +
drivers/fsi/fsi-master-gpio.c | 610 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 622 insertions(+)
create mode 100644 drivers/fsi/fsi-master-gpio.c
diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
index 04c1a0e..9cf8345 100644
--- a/drivers/fsi/Kconfig
+++ b/drivers/fsi/Kconfig
@@ -9,4 +9,15 @@ config FSI
---help---
FSI - the FRU Support Interface - is a simple bus for low-level
access to POWER-based hardware.
+
+if FSI
+
+config FSI_MASTER_GPIO
+ tristate "GPIO-based FSI master"
+ depends on FSI && GPIOLIB
+ ---help---
+ This option enables a FSI master driver using GPIO lines.
+
+endif
+
endmenu
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
index db0e5e7..ed28ac0 100644
--- a/drivers/fsi/Makefile
+++ b/drivers/fsi/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_FSI) += fsi-core.o
+obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c
new file mode 100644
index 0000000..9fedfaf
--- /dev/null
+++ b/drivers/fsi/fsi-master-gpio.c
@@ -0,0 +1,610 @@
+/*
+ * A FSI master controller, using a simple GPIO bit-banging interface
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fsi.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "fsi-master.h"
+
+#define FSI_GPIO_STD_DLY 1 /* Standard pin delay in nS */
+#define FSI_ECHO_DELAY_CLOCKS 16 /* Number clocks for echo delay */
+#define FSI_PRE_BREAK_CLOCKS 50 /* Number clocks to prep for break */
+#define FSI_BREAK_CLOCKS 256 /* Number of clocks to issue break */
+#define FSI_POST_BREAK_CLOCKS 16000 /* Number clocks to set up cfam */
+#define FSI_INIT_CLOCKS 5000 /* Clock out any old data */
+#define FSI_GPIO_STD_DELAY 10 /* Standard GPIO delay in nS */
+ /* todo: adjust down as low as */
+ /* possible or eliminate */
+#define FSI_GPIO_CMD_DPOLL 0x2
+#define FSI_GPIO_CMD_TERM 0x3f
+#define FSI_GPIO_CMD_ABS_AR 0x4
+
+#define FSI_GPIO_DPOLL_CLOCKS 100 /* < 21 will cause slave to hang */
+
+/* Bus errors */
+#define FSI_GPIO_ERR_BUSY 1 /* Slave stuck in busy state */
+#define FSI_GPIO_RESP_ERRA 2 /* Any (misc) Error */
+#define FSI_GPIO_RESP_ERRC 3 /* Slave reports master CRC error */
+#define FSI_GPIO_MTOE 4 /* Master time out error */
+#define FSI_GPIO_CRC_INVAL 5 /* Master reports slave CRC error */
+
+/* Normal slave responses */
+#define FSI_GPIO_RESP_BUSY 1
+#define FSI_GPIO_RESP_ACK 0
+#define FSI_GPIO_RESP_ACKD 4
+
+#define FSI_GPIO_MAX_BUSY 100
+#define FSI_GPIO_MTOE_COUNT 1000
+#define FSI_GPIO_DRAIN_BITS 20
+#define FSI_GPIO_CRC_SIZE 4
+#define FSI_GPIO_MSG_ID_SIZE 2
+#define FSI_GPIO_MSG_RESPID_SIZE 2
+#define FSI_GPIO_PRIME_SLAVE_CLOCKS 100
+
+static DEFINE_SPINLOCK(fsi_gpio_cmd_lock); /* lock around fsi commands */
+
+struct fsi_master_gpio {
+ struct fsi_master master;
+ struct device *dev;
+ struct gpio_desc *gpio_clk;
+ struct gpio_desc *gpio_data;
+ struct gpio_desc *gpio_trans; /* Voltage translator */
+ struct gpio_desc *gpio_enable; /* FSI enable */
+ struct gpio_desc *gpio_mux; /* Mux control */
+};
+
+#define to_fsi_master_gpio(m) container_of(m, struct fsi_master_gpio, master)
+
+struct fsi_gpio_msg {
+ uint64_t msg;
+ uint8_t bits;
+};
+
+static void clock_toggle(struct fsi_master_gpio *master, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ ndelay(FSI_GPIO_STD_DLY);
+ gpiod_set_value(master->gpio_clk, 0);
+ ndelay(FSI_GPIO_STD_DLY);
+ gpiod_set_value(master->gpio_clk, 1);
+ }
+}
+
+static int sda_in(struct fsi_master_gpio *master)
+{
+ int in;
+
+ ndelay(FSI_GPIO_STD_DLY);
+ in = gpiod_get_value(master->gpio_data);
+ return in ? 1 : 0;
+}
+
+static void sda_out(struct fsi_master_gpio *master, int value)
+{
+ gpiod_set_value(master->gpio_data, value);
+}
+
+static void set_sda_input(struct fsi_master_gpio *master)
+{
+ gpiod_direction_input(master->gpio_data);
+ if (master->gpio_trans)
+ gpiod_set_value(master->gpio_trans, 0);
+}
+
+static void set_sda_output(struct fsi_master_gpio *master, int value)
+{
+ if (master->gpio_trans)
+ gpiod_set_value(master->gpio_trans, 1);
+ gpiod_direction_output(master->gpio_data, value);
+}
+
+static void clock_zeros(struct fsi_master_gpio *master, int count)
+{
+ set_sda_output(master, 1);
+ clock_toggle(master, count);
+}
+
+static void serial_in(struct fsi_master_gpio *master, struct fsi_gpio_msg *msg,
+ uint8_t num_bits)
+{
+ uint8_t bit, in_bit;
+
+ set_sda_input(master);
+
+ for (bit = 0; bit < num_bits; bit++) {
+ clock_toggle(master, 1);
+ in_bit = sda_in(master);
+ msg->msg <<= 1;
+ msg->msg |= ~in_bit & 0x1; /* Data is negative active */
+ }
+ msg->bits += num_bits;
+}
+
+static void serial_out(struct fsi_master_gpio *master,
+ const struct fsi_gpio_msg *cmd)
+{
+ uint8_t bit;
+ uint64_t msg = ~cmd->msg; /* Data is negative active */
+ uint64_t sda_mask = 0x1ULL << (cmd->bits - 1);
+ uint64_t last_bit = ~0;
+ int next_bit;
+
+ if (!cmd->bits) {
+ dev_warn(master->dev, "trying to output 0 bits\n");
+ return;
+ }
+ set_sda_output(master, 0);
+
+ /* Send the start bit */
+ sda_out(master, 0);
+ clock_toggle(master, 1);
+
+ /* Send the message */
+ for (bit = 0; bit < cmd->bits; bit++) {
+ next_bit = (msg & sda_mask) >> (cmd->bits - 1);
+ if (last_bit ^ next_bit) {
+ sda_out(master, next_bit);
+ last_bit = next_bit;
+ }
+ clock_toggle(master, 1);
+ msg <<= 1;
+ }
+}
+
+static void msg_push_bits(struct fsi_gpio_msg *msg, uint64_t data, int bits)
+{
+ msg->msg <<= bits;
+ msg->msg |= data & ((1ull << bits) - 1);
+ msg->bits += bits;
+}
+
+static void msg_push_crc(struct fsi_gpio_msg *msg)
+{
+ uint8_t crc;
+ int top;
+
+ top = msg->bits & 0x3;
+
+ /* start bit, and any non-aligned top bits */
+ crc = fsi_crc4(0,
+ 1 << top | msg->msg >> (msg->bits - top),
+ top + 1);
+
+ /* aligned bits */
+ crc = fsi_crc4(crc, msg->msg, msg->bits - top);
+
+ msg_push_bits(msg, crc, 4);
+}
+
+static void build_abs_ar_command(struct fsi_gpio_msg *cmd,
+ uint8_t id, uint32_t addr, size_t size, const void *data)
+{
+ bool write = !!data;
+ uint8_t ds;
+ int i;
+
+ cmd->bits = 0;
+ cmd->msg = 0;
+
+ msg_push_bits(cmd, id, 2);
+ msg_push_bits(cmd, FSI_GPIO_CMD_ABS_AR, 3);
+ msg_push_bits(cmd, write ? 0 : 1, 1);
+
+ /*
+ * The read/write size is encoded in the lower bits of the address
+ * (as it must be naturally-aligned), and the following ds bit.
+ *
+ * size addr:1 addr:0 ds
+ * 1 x x 0
+ * 2 x 0 1
+ * 4 0 1 1
+ *
+ */
+ ds = size > 1 ? 1 : 0;
+ addr &= ~(size - 1);
+ if (size == 4)
+ addr |= 1;
+
+ msg_push_bits(cmd, addr & ((1 << 21) - 1), 21);
+ msg_push_bits(cmd, ds, 1);
+ for (i = 0; write && i < size; i++)
+ msg_push_bits(cmd, ((uint8_t *)data)[i], 8);
+
+ msg_push_crc(cmd);
+}
+
+static void build_dpoll_command(struct fsi_gpio_msg *cmd, uint8_t slave_id)
+{
+ cmd->bits = 0;
+ cmd->msg = 0;
+
+ msg_push_bits(cmd, slave_id, 2);
+ msg_push_bits(cmd, FSI_GPIO_CMD_DPOLL, 3);
+ msg_push_crc(cmd);
+}
+
+static void echo_delay(struct fsi_master_gpio *master)
+{
+ set_sda_output(master, 1);
+ clock_toggle(master, FSI_ECHO_DELAY_CLOCKS);
+}
+
+static void build_term_command(struct fsi_gpio_msg *cmd, uint8_t slave_id)
+{
+ cmd->bits = 0;
+ cmd->msg = 0;
+
+ msg_push_bits(cmd, slave_id, 2);
+ msg_push_bits(cmd, FSI_GPIO_CMD_TERM, 6);
+ msg_push_crc(cmd);
+}
+
+/*
+ * Store information on master errors so handler can detect and clean
+ * up the bus
+ */
+static void fsi_master_gpio_error(struct fsi_master_gpio *master, int error)
+{
+
+}
+
+static int read_one_response(struct fsi_master_gpio *master,
+ uint8_t data_size, struct fsi_gpio_msg *msgp, uint8_t *tagp)
+{
+ struct fsi_gpio_msg msg;
+ uint8_t id, tag;
+ uint32_t crc;
+ int i;
+
+ /* wait for the start bit */
+ for (i = 0; i < FSI_GPIO_MTOE_COUNT; i++) {
+ msg.bits = 0;
+ msg.msg = 0;
+ serial_in(master, &msg, 1);
+ if (msg.msg)
+ break;
+ }
+ if (i >= FSI_GPIO_MTOE_COUNT) {
+ dev_dbg(master->dev,
+ "Master time out waiting for response\n");
+ fsi_master_gpio_error(master, FSI_GPIO_MTOE);
+ return -EIO;
+ }
+
+ msg.bits = 0;
+ msg.msg = 0;
+
+ /* Read slave ID & response tag */
+ serial_in(master, &msg, 4);
+
+ id = (msg.msg >> FSI_GPIO_MSG_RESPID_SIZE) & 0x3;
+ tag = msg.msg & 0x3;
+
+ /* if we have an ACK, and we're expecting data, clock the
+ * data in too
+ */
+ if (tag == FSI_GPIO_RESP_ACK && data_size)
+ serial_in(master, &msg, data_size * 8);
+
+ /* read CRC */
+ serial_in(master, &msg, FSI_GPIO_CRC_SIZE);
+
+ /* we have a whole message now; check CRC */
+ crc = fsi_crc4(0, 1, 1);
+ crc = fsi_crc4(crc, msg.msg, msg.bits);
+ if (crc) {
+ dev_dbg(master->dev, "ERR response CRC\n");
+ fsi_master_gpio_error(master, FSI_GPIO_CRC_INVAL);
+ return -EIO;
+ }
+
+ if (msgp)
+ *msgp = msg;
+ if (tagp)
+ *tagp = tag;
+
+ return 0;
+}
+
+static int issue_term(struct fsi_master_gpio *master, uint8_t slave)
+{
+ struct fsi_gpio_msg cmd;
+ uint8_t tag;
+ int rc;
+
+ build_term_command(&cmd, slave);
+ serial_out(master, &cmd);
+ echo_delay(master);
+
+ rc = read_one_response(master, 0, NULL, &tag);
+ if (rc) {
+ dev_err(master->dev,
+ "TERM failed; lost communication with slave\n");
+ return -EIO;
+ } else if (tag != FSI_GPIO_RESP_ACK) {
+ dev_err(master->dev, "TERM failed; response %d\n", tag);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int poll_for_response(struct fsi_master_gpio *master,
+ uint8_t slave, uint8_t size, void *data)
+{
+ struct fsi_gpio_msg response, cmd;
+ int busy_count = 0, rc, i;
+ uint8_t tag;
+
+retry:
+ rc = read_one_response(master, size, &response, &tag);
+ if (rc)
+ return rc;
+
+ switch (tag) {
+ case FSI_GPIO_RESP_ACK:
+ if (size && data) {
+ uint64_t val = response.msg;
+ /* clear crc & mask */
+ val >>= 4;
+ val &= (1ull << (size * 8)) - 1;
+
+ for (i = 0; i < size; i++) {
+ ((uint8_t *)data)[size-i-1] =
+ val & 0xff;
+ val >>= 8;
+ }
+ }
+ break;
+ case FSI_GPIO_RESP_BUSY:
+ /*
+ * Its necessary to clock slave before issuing
+ * d-poll, not indicated in the hardware protocol
+ * spec. < 20 clocks causes slave to hang, 21 ok.
+ */
+ clock_zeros(master, FSI_GPIO_DPOLL_CLOCKS);
+ if (busy_count++ < FSI_GPIO_MAX_BUSY) {
+ build_dpoll_command(&cmd, slave);
+ serial_out(master, &cmd);
+ echo_delay(master);
+ goto retry;
+ }
+ dev_warn(master->dev,
+ "ERR slave is stuck in busy state, issuing TERM\n");
+ issue_term(master, slave);
+ rc = -EIO;
+ break;
+
+ case FSI_GPIO_RESP_ERRA:
+ case FSI_GPIO_RESP_ERRC:
+ dev_dbg(master->dev, "ERR%c received: 0x%x\n",
+ tag == FSI_GPIO_RESP_ERRA ? 'A' : 'C',
+ (int)response.msg);
+ fsi_master_gpio_error(master, response.msg);
+ rc = -EIO;
+ break;
+ }
+
+ /* Clock the slave enough to be ready for next operation */
+ clock_zeros(master, FSI_GPIO_PRIME_SLAVE_CLOCKS);
+ return rc;
+}
+
+static int fsi_master_gpio_xfer(struct fsi_master_gpio *master, uint8_t slave,
+ struct fsi_gpio_msg *cmd, size_t resp_len, void *resp)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&fsi_gpio_cmd_lock, flags);
+ serial_out(master, cmd);
+ echo_delay(master);
+ rc = poll_for_response(master, slave, resp_len, resp);
+ spin_unlock_irqrestore(&fsi_gpio_cmd_lock, flags);
+
+ return rc;
+}
+
+static int fsi_master_gpio_read(struct fsi_master *_master, int link,
+ uint8_t id, uint32_t addr, void *val, size_t size)
+{
+ struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
+ struct fsi_gpio_msg cmd;
+
+ if (link != 0)
+ return -ENODEV;
+
+ build_abs_ar_command(&cmd, id, addr, size, NULL);
+ return fsi_master_gpio_xfer(master, id, &cmd, size, val);
+}
+
+static int fsi_master_gpio_write(struct fsi_master *_master, int link,
+ uint8_t id, uint32_t addr, const void *val, size_t size)
+{
+ struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
+ struct fsi_gpio_msg cmd;
+
+ if (link != 0)
+ return -ENODEV;
+
+ build_abs_ar_command(&cmd, id, addr, size, val);
+ return fsi_master_gpio_xfer(master, id, &cmd, 0, NULL);
+}
+
+static int fsi_master_gpio_term(struct fsi_master *_master,
+ int link, uint8_t id)
+{
+ struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
+ struct fsi_gpio_msg cmd;
+
+ if (link != 0)
+ return -ENODEV;
+
+ build_term_command(&cmd, id);
+ return fsi_master_gpio_xfer(master, id, &cmd, 0, NULL);
+}
+
+/*
+ * Issue a break command on link
+ */
+static int fsi_master_gpio_break(struct fsi_master *_master, int link)
+{
+ struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
+
+ if (link != 0)
+ return -ENODEV;
+
+ set_sda_output(master, 1);
+ sda_out(master, 1);
+ clock_toggle(master, FSI_PRE_BREAK_CLOCKS);
+ sda_out(master, 0);
+ clock_toggle(master, FSI_BREAK_CLOCKS);
+ echo_delay(master);
+ sda_out(master, 1);
+ clock_toggle(master, FSI_POST_BREAK_CLOCKS);
+
+ /* Wait for logic reset to take effect */
+ udelay(200);
+
+ return 0;
+}
+
+static void fsi_master_gpio_init(struct fsi_master_gpio *master)
+{
+ if (master->gpio_mux)
+ gpiod_direction_output(master->gpio_mux, 1);
+ if (master->gpio_trans)
+ gpiod_direction_output(master->gpio_trans, 1);
+ if (master->gpio_enable)
+ gpiod_direction_output(master->gpio_enable, 1);
+ gpiod_direction_output(master->gpio_clk, 1);
+ gpiod_direction_output(master->gpio_data, 1);
+
+ /* todo: evaluate if clocks can be reduced */
+ clock_zeros(master, FSI_INIT_CLOCKS);
+}
+
+static int fsi_master_gpio_link_enable(struct fsi_master *_master, int link)
+{
+ struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
+
+ if (link != 0)
+ return -ENODEV;
+ if (master->gpio_enable)
+ gpiod_set_value(master->gpio_enable, 1);
+
+ return 0;
+}
+
+static void fsi_master_gpio_release(struct device *dev)
+{
+}
+
+static int fsi_master_gpio_probe(struct platform_device *pdev)
+{
+ struct fsi_master_gpio *master;
+ struct gpio_desc *gpio;
+
+ master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return -ENOMEM;
+
+ master->dev = &pdev->dev;
+ master->master.dev.parent = master->dev;
+ master->master.dev.release = fsi_master_gpio_release;
+
+ gpio = devm_gpiod_get(&pdev->dev, "clock", 0);
+ if (IS_ERR(gpio)) {
+ dev_err(&pdev->dev, "failed to get clock gpio\n");
+ return PTR_ERR(gpio);
+ }
+ master->gpio_clk = gpio;
+
+ gpio = devm_gpiod_get(&pdev->dev, "data", 0);
+ if (IS_ERR(gpio)) {
+ dev_err(&pdev->dev, "failed to get data gpio\n");
+ return PTR_ERR(gpio);
+ }
+ master->gpio_data = gpio;
+
+ /* Optional GPIOs */
+ gpio = devm_gpiod_get_optional(&pdev->dev, "trans", 0);
+ if (IS_ERR(gpio)) {
+ dev_err(&pdev->dev, "failed to get trans gpio\n");
+ return PTR_ERR(gpio);
+ }
+ master->gpio_trans = gpio;
+
+ gpio = devm_gpiod_get_optional(&pdev->dev, "enable", 0);
+ if (IS_ERR(gpio)) {
+ dev_err(&pdev->dev, "failed to get enable gpio\n");
+ return PTR_ERR(gpio);
+ }
+ master->gpio_enable = gpio;
+
+ gpio = devm_gpiod_get_optional(&pdev->dev, "mux", 0);
+ if (IS_ERR(gpio)) {
+ dev_err(&pdev->dev, "failed to get mux gpio\n");
+ return PTR_ERR(gpio);
+ }
+ master->gpio_mux = gpio;
+
+ master->master.n_links = 1;
+ master->master.read = fsi_master_gpio_read;
+ master->master.write = fsi_master_gpio_write;
+ master->master.term = fsi_master_gpio_term;
+ master->master.send_break = fsi_master_gpio_break;
+ master->master.link_enable = fsi_master_gpio_link_enable;
+ platform_set_drvdata(pdev, master);
+
+ fsi_master_gpio_init(master);
+
+ fsi_master_register(&master->master);
+
+ return 0;
+}
+
+
+static int fsi_master_gpio_remove(struct platform_device *pdev)
+{
+ struct fsi_master_gpio *master = platform_get_drvdata(pdev);
+
+ devm_gpiod_put(&pdev->dev, master->gpio_clk);
+ devm_gpiod_put(&pdev->dev, master->gpio_data);
+ if (master->gpio_trans)
+ devm_gpiod_put(&pdev->dev, master->gpio_trans);
+ if (master->gpio_enable)
+ devm_gpiod_put(&pdev->dev, master->gpio_enable);
+ if (master->gpio_mux)
+ devm_gpiod_put(&pdev->dev, master->gpio_mux);
+ fsi_master_unregister(&master->master);
+
+ return 0;
+}
+
+static const struct of_device_id fsi_master_gpio_match[] = {
+ { .compatible = "fsi-master-gpio" },
+ { },
+};
+
+static struct platform_driver fsi_master_gpio_driver = {
+ .driver = {
+ .name = "fsi-master-gpio",
+ .of_match_table = fsi_master_gpio_match,
+ },
+ .probe = fsi_master_gpio_probe,
+ .remove = fsi_master_gpio_remove,
+};
+
+module_platform_driver(fsi_master_gpio_driver);
+MODULE_LICENSE("GPL");
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 18/23] drivers/fsi: Document FSI master sysfs files in ABI
From: Christopher Bostic @ 2017-04-05 2:06 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Chris Bostic, joel, linux-kernel, andrew, alistair, benh
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Chris Bostic <cbostic@linux.vnet.ibm.com>
Add info for sysfs scan file in Documentaiton ABI/testing
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
---
Documentation/ABI/testing/sysfs-bus-fsi | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-bus-fsi
diff --git a/Documentation/ABI/testing/sysfs-bus-fsi b/Documentation/ABI/testing/sysfs-bus-fsi
new file mode 100644
index 0000000..dfcbc1b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-fsi
@@ -0,0 +1,6 @@
+What: /sys/bus/platform/devices/fsi-master/scan
+KernelVersion: 4.9
+Contact: cbostic@us.ibm.com
+Description:
+ Initiates a FSI master scan for all connected
+ slave devices on its links.
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 17/23] drivers/fsi: Add error handling for slave communication errors
From: Christopher Bostic @ 2017-04-05 2:06 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Jeremy Kerr, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r, Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
This change implements error handling in the FSI core, by cleaning up
and retrying failed operations, using the SISC, TERM and BREAK
facilities.
Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
drivers/fsi/fsi-core.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 114 insertions(+), 7 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 09becec..747d0e3 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -44,7 +44,9 @@
/*
* FSI slave engine control register offsets
*/
-#define FSI_SMODE 0x0 /* R/W: Mode register */
+#define FSI_SMODE 0x0 /* R/W: Mode register */
+#define FSI_SISC 0x8 /* R/W: Interrupt condition */
+#define FSI_SSTAT 0x14 /* R : Slave status */
/*
* SMODE fields
@@ -75,10 +77,14 @@ struct fsi_slave {
#define to_fsi_master(d) container_of(d, struct fsi_master, dev)
#define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
+static const int slave_retries = 2;
+static int discard_errors;
+
static int fsi_master_read(struct fsi_master *master, int link,
uint8_t slave_id, uint32_t addr, void *val, size_t size);
static int fsi_master_write(struct fsi_master *master, int link,
uint8_t slave_id, uint32_t addr, const void *val, size_t size);
+static int fsi_master_break(struct fsi_master *master, int link);
/* FSI endpoint-device support */
@@ -180,32 +186,131 @@ static int fsi_slave_calc_addr(struct fsi_slave *slave, uint32_t *addrp,
return 0;
}
+int fsi_slave_report_and_clear_errors(struct fsi_slave *slave)
+{
+ struct fsi_master *master = slave->master;
+ uint32_t irq, stat;
+ int rc, link;
+ uint8_t id;
+
+ link = slave->link;
+ id = slave->id;
+
+ rc = fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
+ &irq, sizeof(irq));
+ if (rc)
+ return rc;
+
+ rc = fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SSTAT,
+ &stat, sizeof(stat));
+ if (rc)
+ return rc;
+
+ dev_info(&slave->dev, "status: 0x%08x, sisc: 0x%08x\n",
+ be32_to_cpu(stat), be32_to_cpu(irq));
+
+ /* clear interrupts */
+ return fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
+ &irq, sizeof(irq));
+}
+
+static int fsi_slave_set_smode(struct fsi_master *master, int link, int id);
+
+int fsi_slave_handle_error(struct fsi_slave *slave, bool write, uint32_t addr,
+ size_t size)
+{
+ struct fsi_master *master = slave->master;
+ int rc, link;
+ uint32_t reg;
+ uint8_t id;
+
+ if (discard_errors)
+ return -1;
+
+ link = slave->link;
+ id = slave->id;
+
+ dev_dbg(&slave->dev, "handling error on %s to 0x%08x[%zd]",
+ write ? "write" : "read", addr, size);
+
+ /* try a simple clear of error conditions, which may fail if we've lost
+ * communication with the slave
+ */
+ rc = fsi_slave_report_and_clear_errors(slave);
+ if (!rc)
+ return 0;
+
+ /* send a TERM and retry */
+ if (master->term) {
+ rc = master->term(master, link, id);
+ if (!rc) {
+ rc = fsi_master_read(master, link, id, 0,
+ ®, sizeof(reg));
+ if (!rc)
+ rc = fsi_slave_report_and_clear_errors(slave);
+ if (!rc)
+ return 0;
+ }
+ }
+
+ /* getting serious, reset the slave via BREAK */
+ rc = fsi_master_break(master, link);
+ if (rc)
+ return rc;
+
+ rc = fsi_slave_set_smode(master, link, id);
+ if (rc)
+ return rc;
+
+ return fsi_slave_report_and_clear_errors(slave);
+}
+
int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
void *val, size_t size)
{
uint8_t id = slave->id;
- int rc;
+ int rc, err_rc, i;
rc = fsi_slave_calc_addr(slave, &addr, &id);
if (rc)
return rc;
- return fsi_master_read(slave->master, slave->link, id,
- addr, val, size);
+ for (i = 0; i < slave_retries; i++) {
+ rc = fsi_master_read(slave->master, slave->link,
+ id, addr, val, size);
+ if (!rc)
+ break;
+
+ err_rc = fsi_slave_handle_error(slave, false, addr, size);
+ if (err_rc)
+ break;
+ }
+
+ return rc;
}
int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
const void *val, size_t size)
{
uint8_t id = slave->id;
- int rc;
+ int rc, err_rc, i;
rc = fsi_slave_calc_addr(slave, &addr, &id);
if (rc)
return rc;
- return fsi_master_write(slave->master, slave->link, id,
- addr, val, size);
+ for (i = 0; i < slave_retries; i++) {
+ rc = fsi_master_write(slave->master, slave->link,
+ id, addr, val, size);
+ if (!rc)
+ break;
+
+ err_rc = fsi_slave_handle_error(slave, true, addr, size);
+ if (err_rc)
+ break;
+ }
+
+ return rc;
}
extern int fsi_slave_claim_range(struct fsi_slave *slave,
@@ -765,3 +870,5 @@ static void fsi_exit(void)
module_init(fsi_init);
module_exit(fsi_exit);
+module_param(discard_errors, int, 0664);
+MODULE_PARM_DESC(discard_errors, "Don't invoke error handling on bus accesses");
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 16/23] drivers/fsi: Add tracepoints for low-level operations
From: Christopher Bostic @ 2017-04-05 2:06 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Jeremy Kerr, joel, linux-kernel, andrew, alistair, benh,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
---
drivers/fsi/fsi-core.c | 27 +++++++---
include/trace/events/fsi.h | 127 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 148 insertions(+), 6 deletions(-)
create mode 100644 include/trace/events/fsi.h
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index f7e55e7..09becec 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -21,6 +21,9 @@
#include "fsi-master.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/fsi.h>
+
#define FSI_SLAVE_CONF_NEXT_MASK 0x80000000
#define FSI_SLAVE_CONF_SLOTS_MASK 0x00ff0000
#define FSI_SLAVE_CONF_SLOTS_SHIFT 16
@@ -541,11 +544,16 @@ static int fsi_master_read(struct fsi_master *master, int link,
{
int rc;
+ trace_fsi_master_read(master, link, slave_id, addr, size);
+
rc = fsi_check_access(addr, size);
- if (rc)
- return rc;
+ if (!rc)
+ rc = master->read(master, link, slave_id, addr, val, size);
+
+ trace_fsi_master_rw_result(master, link, slave_id, addr, size,
+ false, val, rc);
- return master->read(master, link, slave_id, addr, val, size);
+ return rc;
}
static int fsi_master_write(struct fsi_master *master, int link,
@@ -553,11 +561,16 @@ static int fsi_master_write(struct fsi_master *master, int link,
{
int rc;
+ trace_fsi_master_write(master, link, slave_id, addr, size, val);
+
rc = fsi_check_access(addr, size);
- if (rc)
- return rc;
+ if (!rc)
+ rc = master->write(master, link, slave_id, addr, val, size);
- return master->write(master, link, slave_id, addr, val, size);
+ trace_fsi_master_rw_result(master, link, slave_id, addr, size,
+ true, val, rc);
+
+ return rc;
}
static int fsi_master_link_enable(struct fsi_master *master, int link)
@@ -573,6 +586,8 @@ static int fsi_master_link_enable(struct fsi_master *master, int link)
*/
static int fsi_master_break(struct fsi_master *master, int link)
{
+ trace_fsi_master_break(master, link);
+
if (master->send_break)
return master->send_break(master, link);
diff --git a/include/trace/events/fsi.h b/include/trace/events/fsi.h
new file mode 100644
index 0000000..ac74a30
--- /dev/null
+++ b/include/trace/events/fsi.h
@@ -0,0 +1,127 @@
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM fsi
+
+#if !defined(_TRACE_FSI_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FSI_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(fsi_master_read,
+ TP_PROTO(const struct fsi_master *master, int link, int id,
+ uint32_t addr, size_t size),
+ TP_ARGS(master, link, id, addr, size),
+ TP_STRUCT__entry(
+ __field(int, master_idx)
+ __field(int, link)
+ __field(int, id)
+ __field(__u32, addr)
+ __field(size_t, size)
+ ),
+ TP_fast_assign(
+ __entry->master_idx = master->idx;
+ __entry->link = link;
+ __entry->id = id;
+ __entry->addr = addr;
+ __entry->size = size;
+ ),
+ TP_printk("fsi%d:%02d:%02d %08x[%zd]",
+ __entry->master_idx,
+ __entry->link,
+ __entry->id,
+ __entry->addr,
+ __entry->size
+ )
+);
+
+TRACE_EVENT(fsi_master_write,
+ TP_PROTO(const struct fsi_master *master, int link, int id,
+ uint32_t addr, size_t size, const void *data),
+ TP_ARGS(master, link, id, addr, size, data),
+ TP_STRUCT__entry(
+ __field(int, master_idx)
+ __field(int, link)
+ __field(int, id)
+ __field(__u32, addr)
+ __field(size_t, size)
+ __field(__u32, data)
+ ),
+ TP_fast_assign(
+ __entry->master_idx = master->idx;
+ __entry->link = link;
+ __entry->id = id;
+ __entry->addr = addr;
+ __entry->size = size;
+ __entry->data = 0;
+ memcpy(&__entry->data, data, size);
+ ),
+ TP_printk("fsi%d:%02d:%02d %08x[%zd] <= {%*ph}",
+ __entry->master_idx,
+ __entry->link,
+ __entry->id,
+ __entry->addr,
+ __entry->size,
+ __entry->size, &__entry->data
+ )
+);
+
+TRACE_EVENT(fsi_master_rw_result,
+ TP_PROTO(const struct fsi_master *master, int link, int id,
+ uint32_t addr, size_t size,
+ bool write, const void *data, int ret),
+ TP_ARGS(master, link, id, addr, size, write, data, ret),
+ TP_STRUCT__entry(
+ __field(int, master_idx)
+ __field(int, link)
+ __field(int, id)
+ __field(__u32, addr)
+ __field(size_t, size)
+ __field(bool, write)
+ __field(__u32, data)
+ __field(int, ret)
+ ),
+ TP_fast_assign(
+ __entry->master_idx = master->idx;
+ __entry->link = link;
+ __entry->id = id;
+ __entry->addr = addr;
+ __entry->size = size;
+ __entry->write = write;
+ __entry->data = 0;
+ __entry->ret = ret;
+ if (__entry->write || !__entry->ret)
+ memcpy(&__entry->data, data, size);
+ ),
+ TP_printk("fsi%d:%02d:%02d %08x[%zd] %s {%*ph} ret %d",
+ __entry->master_idx,
+ __entry->link,
+ __entry->id,
+ __entry->addr,
+ __entry->size,
+ __entry->write ? "<=" : "=>",
+ __entry->size, &__entry->data,
+ __entry->ret
+ )
+);
+
+TRACE_EVENT(fsi_master_break,
+ TP_PROTO(const struct fsi_master *master, int link),
+ TP_ARGS(master, link),
+ TP_STRUCT__entry(
+ __field(int, master_idx)
+ __field(int, link)
+ ),
+ TP_fast_assign(
+ __entry->master_idx = master->idx;
+ __entry->link = link;
+ ),
+ TP_printk("fsi%d:%d",
+ __entry->master_idx,
+ __entry->link
+ )
+);
+
+
+#endif /* _TRACE_FSI_H */
+
+#include <trace/define_trace.h>
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 15/23] drivers/fsi: expose direct-access slave API
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Jeremy Kerr, joel, linux-kernel, andrew, alistair, benh,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Jeremy Kerr <jk@ozlabs.org>
Allow drivers to access the slave address ranges.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
---
drivers/fsi/fsi-core.c | 26 ++++++++++++++++++++------
include/linux/fsi.h | 12 ++++++++++++
2 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index f0f0556..f7e55e7 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -76,10 +76,6 @@ static int fsi_master_read(struct fsi_master *master, int link,
uint8_t slave_id, uint32_t addr, void *val, size_t size);
static int fsi_master_write(struct fsi_master *master, int link,
uint8_t slave_id, uint32_t addr, const void *val, size_t size);
-static int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
- void *val, size_t size);
-static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
- const void *val, size_t size);
/* FSI endpoint-device support */
@@ -181,7 +177,7 @@ static int fsi_slave_calc_addr(struct fsi_slave *slave, uint32_t *addrp,
return 0;
}
-static int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
+int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
void *val, size_t size)
{
uint8_t id = slave->id;
@@ -195,7 +191,7 @@ static int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
addr, val, size);
}
-static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
+int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
const void *val, size_t size)
{
uint8_t id = slave->id;
@@ -209,6 +205,24 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
addr, val, size);
}
+extern int fsi_slave_claim_range(struct fsi_slave *slave,
+ uint32_t addr, uint32_t size)
+{
+ if (addr + size < addr)
+ return -EINVAL;
+
+ if (addr + size > slave->size)
+ return -EINVAL;
+
+ /* todo: check for overlapping claims */
+ return 0;
+}
+
+extern void fsi_slave_release_range(struct fsi_slave *slave,
+ uint32_t addr, uint32_t size)
+{
+}
+
static int fsi_slave_scan(struct fsi_slave *slave)
{
uint32_t engine_addr;
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
index 34f1e9a..141fd38 100644
--- a/include/linux/fsi.h
+++ b/include/linux/fsi.h
@@ -66,6 +66,18 @@ struct fsi_driver {
module_driver(__fsi_driver, fsi_driver_register, \
fsi_driver_unregister)
+/* direct slave API */
+extern int fsi_slave_claim_range(struct fsi_slave *slave,
+ uint32_t addr, uint32_t size);
+extern void fsi_slave_release_range(struct fsi_slave *slave,
+ uint32_t addr, uint32_t size);
+extern int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
+ void *val, size_t size);
+extern int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
+ const void *val, size_t size);
+
+
+
extern struct bus_type fsi_bus_type;
#endif /* LINUX_FSI_H */
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 14/23] drivers/fsi: Add sysfs files for FSI master & slave accesses
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Jeremy Kerr, joel, linux-kernel, andrew, alistair, benh,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Jeremy Kerr <jk@ozlabs.org>
This change adds a 'raw' file for reads & writes, and a 'term' file for
the TERM command, and a 'break' file for issuing a BREAK.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
---
drivers/fsi/fsi-core.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 4359e26..f0f0556 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -294,6 +294,95 @@ static int fsi_slave_scan(struct fsi_slave *slave)
return 0;
}
+static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
+ size_t total_len, read_len;
+ int rc;
+
+ if (off < 0)
+ return -EINVAL;
+
+ if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
+ return -EINVAL;
+
+ for (total_len = 0; total_len < count; total_len += read_len) {
+ read_len = min_t(size_t, count, 4);
+ read_len -= off & 0x3;
+
+ rc = fsi_slave_read(slave, off, buf + total_len, read_len);
+ if (rc)
+ return rc;
+
+ off += read_len;
+ }
+
+ return count;
+}
+
+static ssize_t fsi_slave_sysfs_raw_write(struct file *file,
+ struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
+ size_t total_len, write_len;
+ int rc;
+
+ if (off < 0)
+ return -EINVAL;
+
+ if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
+ return -EINVAL;
+
+ for (total_len = 0; total_len < count; total_len += write_len) {
+ write_len = min_t(size_t, count, 4);
+ write_len -= off & 0x3;
+
+ rc = fsi_slave_write(slave, off, buf + total_len, write_len);
+ if (rc)
+ return rc;
+
+ off += write_len;
+ }
+
+ return count;
+}
+
+static struct bin_attribute fsi_slave_raw_attr = {
+ .attr = {
+ .name = "raw",
+ .mode = 0600,
+ },
+ .size = 0,
+ .read = fsi_slave_sysfs_raw_read,
+ .write = fsi_slave_sysfs_raw_write,
+};
+
+static ssize_t fsi_slave_sysfs_term_write(struct file *file,
+ struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
+ struct fsi_master *master = slave->master;
+
+ if (!master->term)
+ return -ENODEV;
+
+ master->term(master, slave->link, slave->id);
+ return count;
+}
+
+static struct bin_attribute fsi_slave_term_attr = {
+ .attr = {
+ .name = "term",
+ .mode = 0200,
+ },
+ .size = 0,
+ .write = fsi_slave_sysfs_term_write,
+};
+
/* Encode slave local bus echo delay */
static inline uint32_t fsi_smode_echodly(int x)
{
@@ -409,6 +498,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
return rc;
}
+ rc = device_create_bin_file(&slave->dev, &fsi_slave_raw_attr);
+ if (rc)
+ dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
+
+ rc = device_create_bin_file(&slave->dev, &fsi_slave_term_attr);
+ if (rc)
+ dev_warn(&slave->dev, "failed to create term attr: %d\n", rc);
+
fsi_slave_scan(slave);
return 0;
}
@@ -523,6 +620,18 @@ static ssize_t master_rescan_store(struct device *dev,
static DEVICE_ATTR(rescan, 0200, NULL, master_rescan_store);
+static ssize_t master_break_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct fsi_master *master = to_fsi_master(dev);
+
+ fsi_master_break(master, 0);
+
+ return count;
+}
+
+static DEVICE_ATTR(break, 0200, NULL, master_break_store);
+
int fsi_master_register(struct fsi_master *master)
{
int rc;
@@ -546,6 +655,13 @@ int fsi_master_register(struct fsi_master *master)
return rc;
}
+ rc = device_create_file(&master->dev, &dev_attr_break);
+ if (rc) {
+ device_unregister(&master->dev);
+ ida_simple_remove(&master_ida, master->idx);
+ return rc;
+ }
+
fsi_master_scan(master);
return 0;
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 13/23] drivers/fsi: Add client driver register utilities
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Chris Bostic, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Add driver_register and driver_unregister wrappers for FSI.
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
---
drivers/fsi/fsi-core.c | 17 +++++++++++++++++
include/linux/fsi.h | 12 ++++++++++++
2 files changed, 29 insertions(+)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 75d2a88..4359e26 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -585,6 +585,23 @@ static int fsi_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
+int fsi_driver_register(struct fsi_driver *fsi_drv)
+{
+ if (!fsi_drv)
+ return -EINVAL;
+ if (!fsi_drv->id_table)
+ return -EINVAL;
+
+ return driver_register(&fsi_drv->drv);
+}
+EXPORT_SYMBOL_GPL(fsi_driver_register);
+
+void fsi_driver_unregister(struct fsi_driver *fsi_drv)
+{
+ driver_unregister(&fsi_drv->drv);
+}
+EXPORT_SYMBOL_GPL(fsi_driver_unregister);
+
struct bus_type fsi_bus_type = {
.name = "fsi",
.match = fsi_bus_match,
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
index 66bce48..34f1e9a 100644
--- a/include/linux/fsi.h
+++ b/include/linux/fsi.h
@@ -54,6 +54,18 @@ struct fsi_driver {
#define to_fsi_dev(devp) container_of(devp, struct fsi_device, dev)
#define to_fsi_drv(drvp) container_of(drvp, struct fsi_driver, drv)
+extern int fsi_driver_register(struct fsi_driver *fsi_drv);
+extern void fsi_driver_unregister(struct fsi_driver *fsi_drv);
+
+/* module_fsi_driver() - Helper macro for drivers that don't do
+ * anything special in module init/exit. This eliminates a lot of
+ * boilerplate. Each module may only use this macro once, and
+ * calling it replaces module_init() and module_exit()
+ */
+#define module_fsi_driver(__fsi_driver) \
+ module_driver(__fsi_driver, fsi_driver_register, \
+ fsi_driver_unregister)
+
extern struct bus_type fsi_bus_type;
#endif /* LINUX_FSI_H */
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 12/23] drivers/fsi: Add documentation for GPIO bindings
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Chris Bostic, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Add fsi master gpio device tree binding documentation
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/fsi/fsi-master-gpio.txt | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt
diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt b/Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt
new file mode 100644
index 0000000..a767259
--- /dev/null
+++ b/Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt
@@ -0,0 +1,24 @@
+Device-tree bindings for gpio-based FSI master driver
+-----------------------------------------------------
+
+Required properties:
+ - compatible = "fsi-master-gpio";
+ - clock-gpios = <gpio-descriptor>; : GPIO for FSI clock
+ - data-gpios = <gpio-descriptor>; : GPIO for FSI data signal
+
+Optional properties:
+ - enable-gpios = <gpio-descriptor>; : GPIO for enable signal
+ - trans-gpios = <gpio-descriptor>; : GPIO for voltage translator enable
+ - mux-gpios = <gpio-descriptor>; : GPIO for pin multiplexing with other
+ functions (eg, external FSI masters)
+
+Examples:
+
+ fsi-master {
+ compatible = "fsi-master-gpio", "fsi-master";
+ clock-gpios = <&gpio 0>;
+ data-gpios = <&gpio 1>;
+ enable-gpios = <&gpio 2>;
+ trans-gpios = <&gpio 3>;
+ mux-gpios = <&gpio 4>;
+ }
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 11/23] drivers/fsi: Add master unscan
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Chris Bostic, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Allow a master to undo a previous scan. Should a master scan a bus
twice it will need to ensure it doesn't double register any
previously detected device.
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
---
drivers/fsi/fsi-core.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 4da0b030..75d2a88 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -69,6 +69,7 @@ struct fsi_slave {
uint32_t size; /* size of slave address space */
};
+#define to_fsi_master(d) container_of(d, struct fsi_master, dev)
#define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
static int fsi_master_read(struct fsi_master *master, int link,
@@ -491,6 +492,37 @@ static int fsi_master_scan(struct fsi_master *master)
return 0;
}
+static int __fsi_slave_remove_device(struct device *dev, void *arg)
+{
+ device_unregister(dev);
+ return 0;
+}
+
+static int __fsi_master_remove_slave(struct device *dev, void *arg)
+{
+ device_for_each_child(dev, NULL, __fsi_slave_remove_device);
+ device_unregister(dev);
+ return 0;
+}
+
+static void fsi_master_unscan(struct fsi_master *master)
+{
+ device_for_each_child(&master->dev, NULL, __fsi_master_remove_slave);
+}
+
+static ssize_t master_rescan_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct fsi_master *master = to_fsi_master(dev);
+
+ fsi_master_unscan(master);
+ fsi_master_scan(master);
+
+ return count;
+}
+
+static DEVICE_ATTR(rescan, 0200, NULL, master_rescan_store);
+
int fsi_master_register(struct fsi_master *master)
{
int rc;
@@ -507,7 +539,15 @@ int fsi_master_register(struct fsi_master *master)
return rc;
}
+ rc = device_create_file(&master->dev, &dev_attr_rescan);
+ if (rc) {
+ device_unregister(&master->dev);
+ ida_simple_remove(&master_ida, master->idx);
+ return rc;
+ }
+
fsi_master_scan(master);
+
return 0;
}
EXPORT_SYMBOL_GPL(fsi_master_register);
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 10/23] drivers/fsi: Add device read/write/peek API
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Jeremy Kerr, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r, Edward A . James,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
This change introduces the fsi device API: simple read, write and peek
accessors for the devices' address spaces.
Includes contributions from Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
and Edward A. James <eajames-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>.
Signed-off-by: Edward A. James <eajames-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
---
drivers/fsi/fsi-core.c | 33 +++++++++++++++++++++++++++++++++
include/linux/fsi.h | 7 ++++++-
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index a8faa89..4da0b030 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -32,6 +32,8 @@
#define FSI_SLAVE_CONF_CRC_MASK 0x0000000f
#define FSI_SLAVE_CONF_DATA_BITS 28
+#define FSI_PEEK_BASE 0x410
+
static const int engine_page_size = 0x400;
#define FSI_SLAVE_BASE 0x800
@@ -73,9 +75,40 @@ static int fsi_master_read(struct fsi_master *master, int link,
uint8_t slave_id, uint32_t addr, void *val, size_t size);
static int fsi_master_write(struct fsi_master *master, int link,
uint8_t slave_id, uint32_t addr, const void *val, size_t size);
+static int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
+ void *val, size_t size);
+static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
+ const void *val, size_t size);
/* FSI endpoint-device support */
+int fsi_device_read(struct fsi_device *dev, uint32_t addr, void *val,
+ size_t size)
+{
+ if (addr > dev->size || size > dev->size || addr > dev->size - size)
+ return -EINVAL;
+
+ return fsi_slave_read(dev->slave, dev->addr + addr, val, size);
+}
+EXPORT_SYMBOL_GPL(fsi_device_read);
+
+int fsi_device_write(struct fsi_device *dev, uint32_t addr, const void *val,
+ size_t size)
+{
+ if (addr > dev->size || size > dev->size || addr > dev->size - size)
+ return -EINVAL;
+
+ return fsi_slave_write(dev->slave, dev->addr + addr, val, size);
+}
+EXPORT_SYMBOL_GPL(fsi_device_write);
+
+int fsi_device_peek(struct fsi_device *dev, void *val)
+{
+ uint32_t addr = FSI_PEEK_BASE + ((dev->unit - 2) * sizeof(uint32_t));
+
+ return fsi_slave_read(dev->slave, addr, val, sizeof(uint32_t));
+}
+
static void fsi_device_release(struct device *_device)
{
struct fsi_device *device = to_fsi_dev(_device);
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
index efa55ba..66bce48 100644
--- a/include/linux/fsi.h
+++ b/include/linux/fsi.h
@@ -27,6 +27,12 @@ struct fsi_device {
uint32_t size;
};
+extern int fsi_device_read(struct fsi_device *dev, uint32_t addr,
+ void *val, size_t size);
+extern int fsi_device_write(struct fsi_device *dev, uint32_t addr,
+ const void *val, size_t size);
+extern int fsi_device_peek(struct fsi_device *dev, void *val);
+
struct fsi_device_id {
u8 engine_type;
u8 version;
@@ -40,7 +46,6 @@ struct fsi_device_id {
#define FSI_DEVICE_VERSIONED(t, v) \
.engine_type = (t), .version = (v),
-
struct fsi_driver {
struct device_driver drv;
const struct fsi_device_id *id_table;
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 09/23] drivers/fsi: scan slaves & register devices
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Jeremy Kerr, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r, Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Now that we have fsi_slave devices, scan each for endpoints, and
register them on the fsi bus.
Includes contributions from Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
---
drivers/fsi/fsi-core.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++--
include/linux/fsi.h | 4 ++
2 files changed, 128 insertions(+), 3 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index b7b138b..a8faa89 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -21,6 +21,19 @@
#include "fsi-master.h"
+#define FSI_SLAVE_CONF_NEXT_MASK 0x80000000
+#define FSI_SLAVE_CONF_SLOTS_MASK 0x00ff0000
+#define FSI_SLAVE_CONF_SLOTS_SHIFT 16
+#define FSI_SLAVE_CONF_VERSION_MASK 0x0000f000
+#define FSI_SLAVE_CONF_VERSION_SHIFT 12
+#define FSI_SLAVE_CONF_TYPE_MASK 0x00000ff0
+#define FSI_SLAVE_CONF_TYPE_SHIFT 4
+#define FSI_SLAVE_CONF_CRC_SHIFT 4
+#define FSI_SLAVE_CONF_CRC_MASK 0x0000000f
+#define FSI_SLAVE_CONF_DATA_BITS 28
+
+static const int engine_page_size = 0x400;
+
#define FSI_SLAVE_BASE 0x800
/*
@@ -61,6 +74,30 @@ static int fsi_master_read(struct fsi_master *master, int link,
static int fsi_master_write(struct fsi_master *master, int link,
uint8_t slave_id, uint32_t addr, const void *val, size_t size);
+/* FSI endpoint-device support */
+
+static void fsi_device_release(struct device *_device)
+{
+ struct fsi_device *device = to_fsi_dev(_device);
+
+ kfree(device);
+}
+
+static struct fsi_device *fsi_create_device(struct fsi_slave *slave)
+{
+ struct fsi_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->dev.parent = &slave->dev;
+ dev->dev.bus = &fsi_bus_type;
+ dev->dev.release = fsi_device_release;
+
+ return dev;
+}
+
/* crc helpers */
static const uint8_t crc4_tab[] = {
0x0, 0x7, 0xe, 0x9, 0xb, 0xc, 0x5, 0x2,
@@ -138,6 +175,91 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
addr, val, size);
}
+static int fsi_slave_scan(struct fsi_slave *slave)
+{
+ uint32_t engine_addr;
+ uint32_t conf;
+ int rc, i;
+
+ /*
+ * scan engines
+ *
+ * We keep the peek mode and slave engines for the core; so start
+ * at the third slot in the configuration table. We also need to
+ * skip the chip ID entry at the start of the address space.
+ */
+ engine_addr = engine_page_size * 3;
+ for (i = 2; i < engine_page_size / sizeof(uint32_t); i++) {
+ uint8_t slots, version, type, crc;
+ struct fsi_device *dev;
+
+ rc = fsi_slave_read(slave, (i + 1) * sizeof(conf),
+ &conf, sizeof(conf));
+ if (rc) {
+ dev_warn(&slave->dev,
+ "error reading slave registers\n");
+ return -1;
+ }
+ conf = be32_to_cpu(conf);
+
+ crc = fsi_crc4(0, conf, 32);
+ if (crc) {
+ dev_warn(&slave->dev,
+ "crc error in slave register at 0x%04x\n",
+ i);
+ return -1;
+ }
+
+ slots = (conf & FSI_SLAVE_CONF_SLOTS_MASK)
+ >> FSI_SLAVE_CONF_SLOTS_SHIFT;
+ version = (conf & FSI_SLAVE_CONF_VERSION_MASK)
+ >> FSI_SLAVE_CONF_VERSION_SHIFT;
+ type = (conf & FSI_SLAVE_CONF_TYPE_MASK)
+ >> FSI_SLAVE_CONF_TYPE_SHIFT;
+
+ /*
+ * Unused address areas are marked by a zero type value; this
+ * skips the defined address areas
+ */
+ if (type != 0 && slots != 0) {
+
+ /* create device */
+ dev = fsi_create_device(slave);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->slave = slave;
+ dev->engine_type = type;
+ dev->version = version;
+ dev->unit = i;
+ dev->addr = engine_addr;
+ dev->size = slots * engine_page_size;
+
+ dev_info(&slave->dev,
+ "engine[%i]: type %x, version %x, addr %x size %x\n",
+ dev->unit, dev->engine_type, version,
+ dev->addr, dev->size);
+
+ dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x",
+ slave->master->idx, slave->link,
+ slave->id, i - 2);
+
+ rc = device_register(&dev->dev);
+ if (rc) {
+ dev_warn(&slave->dev, "add failed: %d\n", rc);
+ put_device(&dev->dev);
+ }
+ }
+
+ engine_addr += slots * engine_page_size;
+
+ if (!(conf & FSI_SLAVE_CONF_NEXT_MASK))
+ break;
+ }
+
+ return 0;
+}
+
/* Encode slave local bus echo delay */
static inline uint32_t fsi_smode_echodly(int x)
{
@@ -253,9 +375,8 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
return rc;
}
- /* todo: perform engine scan */
-
- return rc;
+ fsi_slave_scan(slave);
+ return 0;
}
/* FSI master support */
diff --git a/include/linux/fsi.h b/include/linux/fsi.h
index 273cbf6..efa55ba 100644
--- a/include/linux/fsi.h
+++ b/include/linux/fsi.h
@@ -21,6 +21,10 @@ struct fsi_device {
struct device dev;
u8 engine_type;
u8 version;
+ u8 unit;
+ struct fsi_slave *slave;
+ uint32_t addr;
+ uint32_t size;
};
struct fsi_device_id {
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 08/23] drivers/fsi: Set slave SMODE to init communication
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Chris Bostic, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r, Jeremy Kerr
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Set CFAM to appropriate ID so that the controlling master can manage
link memory ranges. Add slave engine register definitions.
Includes changes from Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>.
Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
---
drivers/fsi/fsi-core.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index c705ca2..b7b138b 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -21,6 +21,27 @@
#include "fsi-master.h"
+#define FSI_SLAVE_BASE 0x800
+
+/*
+ * FSI slave engine control register offsets
+ */
+#define FSI_SMODE 0x0 /* R/W: Mode register */
+
+/*
+ * SMODE fields
+ */
+#define FSI_SMODE_WSC 0x80000000 /* Warm start done */
+#define FSI_SMODE_ECRC 0x20000000 /* Hw CRC check */
+#define FSI_SMODE_SID_SHIFT 24 /* ID shift */
+#define FSI_SMODE_SID_MASK 3 /* ID Mask */
+#define FSI_SMODE_ED_SHIFT 20 /* Echo delay shift */
+#define FSI_SMODE_ED_MASK 0xf /* Echo delay mask */
+#define FSI_SMODE_SD_SHIFT 16 /* Send delay shift */
+#define FSI_SMODE_SD_MASK 0xf /* Send delay mask */
+#define FSI_SMODE_LBCRR_SHIFT 8 /* Clk ratio shift */
+#define FSI_SMODE_LBCRR_MASK 0xf /* Clk ratio mask */
+
#define FSI_SLAVE_SIZE_23b 0x800000
static DEFINE_IDA(master_ida);
@@ -117,6 +138,52 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
addr, val, size);
}
+/* Encode slave local bus echo delay */
+static inline uint32_t fsi_smode_echodly(int x)
+{
+ return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
+}
+
+/* Encode slave local bus send delay */
+static inline uint32_t fsi_smode_senddly(int x)
+{
+ return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
+}
+
+/* Encode slave local bus clock rate ratio */
+static inline uint32_t fsi_smode_lbcrr(int x)
+{
+ return (x & FSI_SMODE_LBCRR_MASK) << FSI_SMODE_LBCRR_SHIFT;
+}
+
+/* Encode slave ID */
+static inline uint32_t fsi_smode_sid(int x)
+{
+ return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
+}
+
+static const uint32_t fsi_slave_smode(int id)
+{
+ return FSI_SMODE_WSC | FSI_SMODE_ECRC
+ | fsi_smode_sid(id)
+ | fsi_smode_echodly(0xf) | fsi_smode_senddly(0xf)
+ | fsi_smode_lbcrr(0x8);
+}
+
+static int fsi_slave_set_smode(struct fsi_master *master, int link, int id)
+{
+ uint32_t smode;
+
+ /* set our smode register with the slave ID field to 0; this enables
+ * extended slave addressing
+ */
+ smode = fsi_slave_smode(id);
+ smode = cpu_to_be32(smode);
+
+ return fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SMODE,
+ &smode, sizeof(smode));
+}
+
static void fsi_slave_release(struct device *dev)
{
struct fsi_slave *slave = to_fsi_slave(dev);
@@ -155,6 +222,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
dev_info(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
chip_id, master->idx, link, id);
+ rc = fsi_slave_set_smode(master, link, id);
+ if (rc) {
+ dev_warn(&master->dev,
+ "can't set smode on slave:%02x:%02x %d\n",
+ link, id, rc);
+ return -ENODEV;
+ }
+
/* We can communicate with a slave; create the slave device and
* register.
*/
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 07/23] drivers/fsi: Implement slave initialisation
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Jeremy Kerr, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r, Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Implement fsi_slave_init: if we can read a chip ID, create fsi_slave
devices and register with the driver core.
Includes changes from Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>.
Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
---
drivers/fsi/fsi-core.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 6e1cfdf..c705ca2 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -17,9 +17,12 @@
#include <linux/fsi.h>
#include <linux/idr.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include "fsi-master.h"
+#define FSI_SLAVE_SIZE_23b 0x800000
+
static DEFINE_IDA(master_ida);
struct fsi_slave {
@@ -114,11 +117,70 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
addr, val, size);
}
+static void fsi_slave_release(struct device *dev)
+{
+ struct fsi_slave *slave = to_fsi_slave(dev);
+
+ kfree(slave);
+}
+
static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
{
- /* todo: initialise slave device, perform engine scan */
+ struct fsi_slave *slave;
+ uint32_t chip_id;
+ uint8_t crc;
+ int rc;
+
+ /* Currently, we only support single slaves on a link, and use the
+ * full 23-bit address range
+ */
+ if (id != 0)
+ return -EINVAL;
+
+ rc = fsi_master_read(master, link, id, 0, &chip_id, sizeof(chip_id));
+ if (rc) {
+ dev_warn(&master->dev, "can't read slave %02x:%02x %d\n",
+ link, id, rc);
+ return -ENODEV;
+ }
+ chip_id = be32_to_cpu(chip_id);
+
+ crc = fsi_crc4(0, chip_id, 32);
+ if (crc) {
+ dev_warn(&master->dev, "slave %02x:%02x invalid chip id CRC!\n",
+ link, id);
+ return -EIO;
+ }
+
+ dev_info(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
+ chip_id, master->idx, link, id);
+
+ /* We can communicate with a slave; create the slave device and
+ * register.
+ */
+ slave = kzalloc(sizeof(*slave), GFP_KERNEL);
+ if (!slave)
+ return -ENOMEM;
+
+ slave->master = master;
+ slave->dev.parent = &master->dev;
+ slave->dev.release = fsi_slave_release;
+ slave->link = link;
+ slave->id = id;
+ slave->size = FSI_SLAVE_SIZE_23b;
+
+ dev_set_name(&slave->dev, "slave@%02x:%02x", link, id);
+ rc = device_register(&slave->dev);
+ if (rc < 0) {
+ dev_warn(&master->dev, "failed to create slave device: %d\n",
+ rc);
+ put_device(&slave->dev);
+ return rc;
+ }
+
+ /* todo: perform engine scan */
- return -ENODEV;
+ return rc;
}
/* FSI master support */
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 06/23] drivers/fsi: Set up links for slave communication
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Chris Bostic, joel, linux-kernel, andrew, alistair, benh
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Chris Bostic <cbostic@linux.vnet.ibm.com>
Enable each link and send a break command, and try to detect a slave by
reading from the SMODE register.
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
drivers/fsi/fsi-core.c | 37 +++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 32698ed..6e1cfdf 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -157,12 +157,45 @@ static int fsi_master_write(struct fsi_master *master, int link,
return master->write(master, link, slave_id, addr, val, size);
}
+static int fsi_master_link_enable(struct fsi_master *master, int link)
+{
+ if (master->link_enable)
+ return master->link_enable(master, link);
+
+ return 0;
+}
+
+/*
+ * Issue a break command on this link
+ */
+static int fsi_master_break(struct fsi_master *master, int link)
+{
+ if (master->send_break)
+ return master->send_break(master, link);
+
+ return 0;
+}
+
static int fsi_master_scan(struct fsi_master *master)
{
- int link;
+ int link, rc;
+
+ for (link = 0; link < master->n_links; link++) {
+ rc = fsi_master_link_enable(master, link);
+ if (rc) {
+ dev_dbg(&master->dev,
+ "enable link %d failed: %d\n", link, rc);
+ continue;
+ }
+ rc = fsi_master_break(master, link);
+ if (rc) {
+ dev_dbg(&master->dev,
+ "break to link %d failed: %d\n", link, rc);
+ continue;
+ }
- for (link = 0; link < master->n_links; link++)
fsi_slave_init(master, link, 0);
+ }
return 0;
}
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 05/23] drivers/fsi: Add slave & master read/write APIs
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Jeremy Kerr, joel, linux-kernel, andrew, alistair, benh,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Jeremy Kerr <jk@ozlabs.org>
Introduce functions to perform reads/writes on the slave address space;
these simply pass the request on the slave's master with the correct
link and slave ID.
We implement these on top of similar helpers for the master.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
---
drivers/fsi/fsi-core.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 4bbca95..32698ed 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -32,6 +32,11 @@ struct fsi_slave {
#define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
+static int fsi_master_read(struct fsi_master *master, int link,
+ uint8_t slave_id, uint32_t addr, void *val, size_t size);
+static int fsi_master_write(struct fsi_master *master, int link,
+ uint8_t slave_id, uint32_t addr, const void *val, size_t size);
+
/* crc helpers */
static const uint8_t crc4_tab[] = {
0x0, 0x7, 0xe, 0x9, 0xb, 0xc, 0x5, 0x2,
@@ -57,6 +62,58 @@ uint8_t fsi_crc4(uint8_t c, uint64_t x, int bits)
EXPORT_SYMBOL_GPL(fsi_crc4);
/* FSI slave support */
+static int fsi_slave_calc_addr(struct fsi_slave *slave, uint32_t *addrp,
+ uint8_t *idp)
+{
+ uint32_t addr = *addrp;
+ uint8_t id = *idp;
+
+ if (addr > slave->size)
+ return -EINVAL;
+
+ /* For 23 bit addressing, we encode the extra two bits in the slave
+ * id (and the slave's actual ID needs to be 0).
+ */
+ if (addr > 0x1fffff) {
+ if (slave->id != 0)
+ return -EINVAL;
+ id = (addr >> 21) & 0x3;
+ addr &= 0x1fffff;
+ }
+
+ *addrp = addr;
+ *idp = id;
+ return 0;
+}
+
+static int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
+ void *val, size_t size)
+{
+ uint8_t id = slave->id;
+ int rc;
+
+ rc = fsi_slave_calc_addr(slave, &addr, &id);
+ if (rc)
+ return rc;
+
+ return fsi_master_read(slave->master, slave->link, id,
+ addr, val, size);
+}
+
+static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
+ const void *val, size_t size)
+{
+ uint8_t id = slave->id;
+ int rc;
+
+ rc = fsi_slave_calc_addr(slave, &addr, &id);
+ if (rc)
+ return rc;
+
+ return fsi_master_write(slave->master, slave->link, id,
+ addr, val, size);
+}
+
static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
{
/* todo: initialise slave device, perform engine scan */
@@ -65,6 +122,41 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
}
/* FSI master support */
+static int fsi_check_access(uint32_t addr, size_t size)
+{
+ if (size != 1 && size != 2 && size != 4)
+ return -EINVAL;
+
+ if ((addr & 0x3) != (size & 0x3))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int fsi_master_read(struct fsi_master *master, int link,
+ uint8_t slave_id, uint32_t addr, void *val, size_t size)
+{
+ int rc;
+
+ rc = fsi_check_access(addr, size);
+ if (rc)
+ return rc;
+
+ return master->read(master, link, slave_id, addr, val, size);
+}
+
+static int fsi_master_write(struct fsi_master *master, int link,
+ uint8_t slave_id, uint32_t addr, const void *val, size_t size)
+{
+ int rc;
+
+ rc = fsi_check_access(addr, size);
+ if (rc)
+ return rc;
+
+ return master->write(master, link, slave_id, addr, val, size);
+}
+
static int fsi_master_scan(struct fsi_master *master)
{
int link;
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 04/23] drivers/fsi: Add crc4 helpers
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Jeremy Kerr, joel, linux-kernel, andrew, alistair, benh,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Jeremy Kerr <jk@ozlabs.org>
Add some helpers for the crc checks for the slave configuration table.
This works 4-bits-at-a-time, using a simple table approach.
We will need this in the FSI core code, as well as any master
implementations that need to calculate CRCs in software.
We add this to the fsi code (rather than lib/), as we need a specific
polynomial for FSI CRCs.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
drivers/fsi/fsi-core.c | 24 ++++++++++++++++++++++++
drivers/fsi/fsi-master.h | 21 +++++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index e90d45d..4bbca95 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -32,6 +32,30 @@ struct fsi_slave {
#define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
+/* crc helpers */
+static const uint8_t crc4_tab[] = {
+ 0x0, 0x7, 0xe, 0x9, 0xb, 0xc, 0x5, 0x2,
+ 0x1, 0x6, 0xf, 0x8, 0xa, 0xd, 0x4, 0x3,
+};
+
+uint8_t fsi_crc4(uint8_t c, uint64_t x, int bits)
+{
+ int i;
+
+ /* Align to 4-bits */
+ bits = (bits + 3) & ~0x3;
+
+ /* mask off anything above the top bit */
+ x &= (1ull << bits) - 1;
+
+ /* Calculate crc4 over four-bit nibbles, starting at the MSbit */
+ for (i = bits - 4; i >= 0; i -= 4)
+ c = crc4_tab[c ^ ((x >> i) & 0xf)];
+
+ return c;
+}
+EXPORT_SYMBOL_GPL(fsi_crc4);
+
/* FSI slave support */
static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
{
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index 7764b00..d6a4885 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -38,4 +38,25 @@ struct fsi_master {
extern int fsi_master_register(struct fsi_master *master);
extern void fsi_master_unregister(struct fsi_master *master);
+/**
+ * crc4 helper: Given a starting crc4 state @c, calculate the crc4 vaue of @x,
+ * which is @bits in length. This may be required by master implementations
+ * that do not provide their own hardware checksums.
+ *
+ * The crc4 is performed on 4-bit chunks (which is all we need for FSI
+ * calculations). Typically, we'll want a starting state of 0:
+ *
+ * c = fsi_crc4(0, msg, len);
+ *
+ * To crc4 a message that includes a single start bit, initialise crc4 state
+ * with:
+ *
+ * c = fsi_crc4(0, 1, 1);
+ *
+ * Then update with message data:
+ *
+ * c = fsi_crc4(c, msg, len);
+ */
+uint8_t fsi_crc4(uint8_t c, uint64_t x, int bits);
+
#endif /* DRIVERS_FSI_MASTER_H */
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 03/23] drivers/fsi: Add empty master scan
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Jeremy Kerr, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r, Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
From: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
When a new fsi master is added, we will need to scan its links, and
slaves attached to those links. This change introduces a little shell to
iterate the links, which we will populate with the actual slave scan in
a later change.
Signed-off-by: Jeremy Kerr <jk-mnsaURCQ41sdnm+yROfE0A@public.gmane.org>
Signed-off-by: Chris Bostic <cbostic-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Signed-off-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
---
drivers/fsi/fsi-core.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 2f19509..e90d45d 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -32,7 +32,25 @@ struct fsi_slave {
#define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
+/* FSI slave support */
+static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
+{
+ /* todo: initialise slave device, perform engine scan */
+
+ return -ENODEV;
+}
+
/* FSI master support */
+static int fsi_master_scan(struct fsi_master *master)
+{
+ int link;
+
+ for (link = 0; link < master->n_links; link++)
+ fsi_slave_init(master, link, 0);
+
+ return 0;
+}
+
int fsi_master_register(struct fsi_master *master)
{
int rc;
@@ -44,10 +62,13 @@ int fsi_master_register(struct fsi_master *master)
dev_set_name(&master->dev, "fsi%d", master->idx);
rc = device_register(&master->dev);
- if (rc)
+ if (rc) {
ida_simple_remove(&master_ida, master->idx);
+ return rc;
+ }
- return rc;
+ fsi_master_scan(master);
+ return 0;
}
EXPORT_SYMBOL_GPL(fsi_master_register);
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v5 02/23] drivers/fsi: Add slave definition
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Jeremy Kerr, joel, linux-kernel, andrew, alistair, benh,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Jeremy Kerr <jk@ozlabs.org>
Add the initial fsi slave device, which is private to the core code.
This will be a child of the master, and parent to endpoint devices.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
drivers/fsi/fsi-core.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index ca02913..2f19509 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -22,6 +22,16 @@
static DEFINE_IDA(master_ida);
+struct fsi_slave {
+ struct device dev;
+ struct fsi_master *master;
+ int id;
+ int link;
+ uint32_t size; /* size of slave address space */
+};
+
+#define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
+
/* FSI master support */
int fsi_master_register(struct fsi_master *master)
{
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 01/23] drivers/fsi: Add fsi master definition
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt, mark.rutland, linux, rostedt, mingo, gregkh, devicetree,
linux-arm-kernel
Cc: Jeremy Kerr, joel, linux-kernel, andrew, alistair, benh,
Chris Bostic
In-Reply-To: <20170405020607.79939-1-cbostic@linux.vnet.ibm.com>
From: Jeremy Kerr <jk@ozlabs.org>
Add a `struct fsi_master` to represent a FSI master controller.
FSI master drivers register one of these structs to provide
device-specific of the standard operations: read/write/term/break and
link control.
Includes changes from Edward A. James <eajames@us.ibm.com> & Jeremy Kerr
<jk@ozlabs.org>.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
drivers/fsi/fsi-core.c | 35 +++++++++++++++++++++++++++++++++++
drivers/fsi/fsi-master.h | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+)
create mode 100644 drivers/fsi/fsi-master.h
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 3d55bd5..ca02913 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -15,8 +15,43 @@
#include <linux/device.h>
#include <linux/fsi.h>
+#include <linux/idr.h>
#include <linux/module.h>
+#include "fsi-master.h"
+
+static DEFINE_IDA(master_ida);
+
+/* FSI master support */
+int fsi_master_register(struct fsi_master *master)
+{
+ int rc;
+
+ if (!master)
+ return -EINVAL;
+
+ master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL);
+ dev_set_name(&master->dev, "fsi%d", master->idx);
+
+ rc = device_register(&master->dev);
+ if (rc)
+ ida_simple_remove(&master_ida, master->idx);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(fsi_master_register);
+
+void fsi_master_unregister(struct fsi_master *master)
+{
+ if (master->idx >= 0) {
+ ida_simple_remove(&master_ida, master->idx);
+ master->idx = -1;
+ }
+
+ device_unregister(&master->dev);
+}
+EXPORT_SYMBOL_GPL(fsi_master_unregister);
+
/* FSI core & Linux bus type definitions */
static int fsi_bus_match(struct device *dev, struct device_driver *drv)
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
new file mode 100644
index 0000000..7764b00
--- /dev/null
+++ b/drivers/fsi/fsi-master.h
@@ -0,0 +1,41 @@
+/*
+ * FSI master definitions. These comprise the core <--> master interface,
+ * to allow the core to interact with the (hardware-specific) masters.
+ *
+ * Copyright (C) IBM Corporation 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DRIVERS_FSI_MASTER_H
+#define DRIVERS_FSI_MASTER_H
+
+#include <linux/device.h>
+
+struct fsi_master {
+ struct device dev;
+ int idx;
+ int n_links;
+ int flags;
+ int (*read)(struct fsi_master *, int link, uint8_t id,
+ uint32_t addr, void *val, size_t size);
+ int (*write)(struct fsi_master *, int link, uint8_t id,
+ uint32_t addr, const void *val, size_t size);
+ int (*term)(struct fsi_master *, int link, uint8_t id);
+ int (*send_break)(struct fsi_master *, int link);
+ int (*link_enable)(struct fsi_master *, int link);
+};
+
+#define dev_to_fsi_master(d) container_of(d, struct fsi_master, dev)
+
+extern int fsi_master_register(struct fsi_master *master);
+extern void fsi_master_unregister(struct fsi_master *master);
+
+#endif /* DRIVERS_FSI_MASTER_H */
--
1.8.2.2
^ permalink raw reply related
* [PATCH v5 00/23] FSI device driver implementation
From: Christopher Bostic @ 2017-04-05 2:05 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, rostedt-nx8X9YLhiw1AfugRpC6u6w,
mingo-H+wXaHxf7aLQT0dZR+AlfA,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Christopher Bostic, joel-U3u1mxZcP9KHXe+LvDLADg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, andrew-zrmu5oMJ5Fs,
alistair-Y4h6yKqj69EXC2x5gXVKYQ,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r
Implementation of the IBM 'Flexible Support Interface' (FSI) bus device
driver. FSI is a high fan out serial bus consisting of a clock and a serial
data line capable of running at speeds up to 166 MHz.
This set provides the basic framework to add FSI extensions to the
Linux bus and device models. Master specific implementations are
defined to utilize the core FSI function.
In Linux, we have a core FSI "bus type", along with drivers for FSI
masters and engines.
The FSI master drivers expose a read/write interface to the bus address
space. The master drivers are under drivers/fsi/fsi-master-*.c.
The core handles probing and discovery of slaves and slave
engines, using those read/write interfaces. It is responsible for
creating the endpoint Linux devices corresponding to the discovered
engines on each slave.
Slave engines are identified by an 'engine' type, and an optional
version. Engine, a.k.a. client, drivers are matched and bound to these
engines during discovery.
This patch set does not include extended FSI function such as:
* Cascaded master support
* Application layer hot plug notification
* Application layer FSI bus status interface
Common FSI terminology:
* Master
Controller of the FSI bus. Only the master is allowed to control the
clock line and is the initiator of all transactions on a bus.
* Slave
The receiver or target of a master initiated transaction. The slave
cannot initiate communications on a bus and must respond to any
master requests for data.
* CFAM
Stands for Common Field replaceable unit Access Macro. A CFAM is an
ASIC residing in any device requiring FSI communications. CFAMs
consist of an array of hardware 'engines' used for various purposes.
I2C masters, UARTs, General Purpose IO hardware are common types of
these engines.
* Configuration Space / Table
A table contained at the beginning of each CFAM address space.
This table lists information such as the CFAM's ID, which engine types
and versions it has available, as well as its addressing range.
* FSI Engine driver
A device driver that registers with the FSI core so that it can access
devices it owns on an FSI bus.
* Hub
An FSI master that connects to an upstream 'primary' master allowing
high fanout of target devices.
----
Changes in v5:
- Remove explicit kfree of struct fsi_master in fsi_master_gpio.
- Remove Palmetto and Romulus dts device tree file udates for FSI gpio
master
Changes in v4:
- endianness: the _read() and _write() APIs are now all *bus endian*,
so will be the same on all platforms (the previous fsi patches
exposed as (BMC/FSP) CPU endian, which is variable).
- device tree: Remove the "ibm," prefix for the fsi core and GPIO
master compatibility strings, as they're not describing
IBM-specific
- device model: Create separate struct devices for each FSI
master, which fits better with the Linux device model, and allows
addition of sysfs attributes that are implemented by the fsi core
- sysfs: there are now sysfs facilities for break and term. Raw
file supports reads and writes of arbitrary sizes.
- GPIO master: split the xfer() logic out a little, so that the
response handling & DPOLL retry mechanism is more obvious
- GPIO master: simplifications for message construction
- GPIO master: fixes for some CRC calculations
- GPIO master: issue TERM in response to DPOLL busy-loops
- Error handling: rather than handle errors on (potentially) an entire
cascaded read or write, the error handling is now down on a per-slave
basis, where we try to reestablish communication in a more "gradual"
manner, rather than sending a break immediately. May need to add a
hook to percolate error recovery up to a slave's master but no need
seen for that at present.
- Hub master: this is now implemented as a fsi engine driver, as the
fsi_slave_{read,write}() functions are exported (and the port count
is available in the hMFSI configuration register)
This means we need fewer special-cases in the fsi core.
- Tracepoints: Add tracepoints for FSI core read & write, and another
set for low-level GPIO in/out operations.
Changes in v3:
- Patch set contained an invalid 18/18 test patch not
meant for community review, corrected.
Changes in v2:
- Change from atomic global for master number to ida simple
interface.
- Add valid pointer checks on register and unregister utils.
- Move CRC calculation utilities out of driver to lib path.
- Clean up white space issues.
- Remove added list management of master devices and use
instead the device_for_each_child method available in the
bus.
- Add new patch to document FSI bus functionality.
- Add new patch documenting FSI gpio master.
- Rearrage patch set to have documentation earlier than code
implementing it.
- Document all compatible strings used in device tree bindings.
- Elaborate documentation definition of FSI GPIO master.
- Describe in more detail what each GPIO FSI master pin is for.
- Re-order compatible strings in example binding so that most
specific device comes first.
- Indicate proper activation order of all FSI GPIO master pins.
- Fix an unmatched '>' bracket in the example for binding.
- Bracket each element of the example bindings individually.
- Add new patch documenting sysfs-bus-fsi attributes.
- Merge FSI GPIO master init into probe function.
- Set pin initial values at time of pin request.
- Assign value of master->master.dev at probe time.
- Use get_optional interface for all optional GPIO pins.
Chris Bostic (9):
drivers/fsi: Set up links for slave communication
drivers/fsi: Set slave SMODE to init communication
drivers/fsi: Add master unscan
drivers/fsi: Add documentation for GPIO bindings
drivers/fsi: Add client driver register utilities
drivers/fsi: Document FSI master sysfs files in ABI
drivers/fsi: Add GPIO based FSI master
drivers/fsi: Add SCOM FSI client device driver
drivers/fsi: Add hub master support
Jeremy Kerr (14):
drivers/fsi: Add fsi master definition
drivers/fsi: Add slave definition
drivers/fsi: Add empty master scan
drivers/fsi: Add crc4 helpers
drivers/fsi: Add slave & master read/write APIs
drivers/fsi: Implement slave initialisation
drivers/fsi: scan slaves & register devices
drivers/fsi: Add device read/write/peek API
drivers/fsi: Add sysfs files for FSI master & slave accesses
drivers/fsi: expose direct-access slave API
drivers/fsi: Add tracepoints for low-level operations
drivers/fsi: Add error handling for slave communication errors
drivers/fsi/gpio: Add tracepoints for GPIO master
drivers/fsi: Use asynchronous slave mode
Documentation/ABI/testing/sysfs-bus-fsi | 6 +
.../devicetree/bindings/fsi/fsi-master-gpio.txt | 24 +
drivers/fsi/Kconfig | 26 +
drivers/fsi/Makefile | 3 +
drivers/fsi/fsi-core.c | 835 +++++++++++++++++++++
drivers/fsi/fsi-master-gpio.c | 620 +++++++++++++++
drivers/fsi/fsi-master-hub.c | 327 ++++++++
drivers/fsi/fsi-master.h | 64 ++
drivers/fsi/fsi-scom.c | 263 +++++++
include/linux/fsi.h | 35 +-
include/trace/events/fsi.h | 127 ++++
include/trace/events/fsi_master_gpio.h | 68 ++
12 files changed, 2397 insertions(+), 1 deletion(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-fsi
create mode 100644 Documentation/devicetree/bindings/fsi/fsi-master-gpio.txt
create mode 100644 drivers/fsi/fsi-master-gpio.c
create mode 100644 drivers/fsi/fsi-master-hub.c
create mode 100644 drivers/fsi/fsi-master.h
create mode 100644 drivers/fsi/fsi-scom.c
create mode 100644 include/trace/events/fsi.h
create mode 100644 include/trace/events/fsi_master_gpio.h
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2] clk/axs10x: introduce AXS10X pll driver
From: Stephen Boyd @ 2017-04-05 1:35 UTC (permalink / raw)
To: Vlad Zakharov
Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Jose Abreu, Michael Turquette,
Mark Rutland, Rob Herring
In-Reply-To: <1487682670-4164-1-git-send-email-vzakhar-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
On 02/21, Vlad Zakharov wrote:
> diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> new file mode 100644
> index 0000000..5706246
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> @@ -0,0 +1,28 @@
> +Binding for the AXS10X Generic PLL clock
> +
> +This binding uses the common clock binding[1].
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> +
> +Required properties:
> +- compatible: should be "snps,axs10x-<name>-pll-clock"
> + "snps,axs10x-arc-pll-clock"
> + "snps,axs10x-pgu-pll-clock"
> +- reg: should always contain 2 pairs address - length: first for PLL config
> +registers and second for corresponding LOCK CGU register.
> +- clocks: shall be the input parent clock phandle for the PLL.
> +- #clock-cells: from common clock binding; Should always be set to 0.
> +
> +Example:
> + input-clk: input-clk {
> + clock-frequency = <33333333>;
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + };
> +
> + core-clk: core-clk@80 {
> + compatible = "snps,axs10x-arc-pll-clock";
> + reg = <0x80 0x10 0x100 0x10>;
Can you add the braces around register pairs in the example?
Makes it clearer with a quick glance.
> + #clock-cells = <0>;
> + clocks = <&input-clk>;
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3960e7f..5805833 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11910,6 +11910,12 @@ F: arch/arc/plat-axs10x
> F: arch/arc/boot/dts/ax*
> F: Documentation/devicetree/bindings/arc/axs10*
>
> +SYNOPSYS ARC SDP clock driver
This also includes the existing driver there. Jose can ack this?
> +M: Vlad Zakharov <vzakhar-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
> +S: Supported
> +F: drivers/clk/axs10x/*
> +F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> +
> SYSTEM CONFIGURATION (SYSCON)
> M: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> M: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
> diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile
> index 01996b8..d747dea 100644
> --- a/drivers/clk/axs10x/Makefile
> +++ b/drivers/clk/axs10x/Makefile
> @@ -1 +1,2 @@
> obj-y += i2s_pll_clock.o
> +obj-y += pll_clock.o
> diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c
> new file mode 100644
> index 0000000..784a0a2
> --- /dev/null
> +++ b/drivers/clk/axs10x/pll_clock.c
> @@ -0,0 +1,384 @@
> +/*
> + * Synopsys AXS10X SDP Generic PLL clock driver
> + *
> + * Copyright (C) 2017 Synopsys
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/device.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +
> +/* PLL registers addresses */
> +#define PLL_REG_IDIV 0x0
> +#define PLL_REG_FBDIV 0x4
> +#define PLL_REG_ODIV 0x8
> +
> +/*
> + * Bit fields of the PLL IDIV/FBDIV/ODIV registers:
> + * ________________________________________________________________________
> + * |31 15| 14 | 13 | 12 |11 6|5 0|
> + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--|
> + * |____________________|__________|________|______|____________|___________|
> + *
> + * Following macros detirmine the way of access to these registers
s/detirmine/determine/
> + * They should be set up only using the macros.
> + * reg should be and uint32_t variable.
s/and/an/?
> + */
> +
> +#define PLL_REG_GET_LOW(reg) \
> + (((reg) & (0x3F << 0)) >> 0)
> +#define PLL_REG_GET_HIGH(reg) \
> + (((reg) & (0x3F << 6)) >> 6)
> +#define PLL_REG_GET_EDGE(reg) \
> + (((reg) & (BIT(12))) ? 1 : 0)
> +#define PLL_REG_GET_BYPASS(reg) \
> + (((reg) & (BIT(13))) ? 1 : 0)
> +#define PLL_REG_GET_NOUPD(reg) \
> + (((reg) & (BIT(14))) ? 1 : 0)
> +#define PLL_REG_GET_PAD(reg) \
> + (((reg) & (0x1FFFF << 15)) >> 15)
> +
> +#define PLL_REG_SET_LOW(reg, value) \
> + { reg |= (((value) & 0x3F) << 0); }
> +#define PLL_REG_SET_HIGH(reg, value) \
> + { reg |= (((value) & 0x3F) << 6); }
> +#define PLL_REG_SET_EDGE(reg, value) \
> + { reg |= (((value) & 0x01) << 12); }
> +#define PLL_REG_SET_BYPASS(reg, value) \
> + { reg |= (((value) & 0x01) << 13); }
> +#define PLL_REG_SET_NOUPD(reg, value) \
> + { reg |= (((value) & 0x01) << 14); }
> +#define PLL_REG_SET_PAD(reg, value) \
> + { reg |= (((value) & 0x1FFFF) << 15); }
> +
> +#define PLL_LOCK 0x1
> +#define PLL_MAX_LOCK_TIME 100 /* 100 us */
> +
> +struct pll_cfg {
> + u32 rate;
> + u32 idiv;
> + u32 fbdiv;
> + u32 odiv;
> +};
> +
> +struct pll_of_table {
> + unsigned long prate;
> + struct pll_cfg *pll_cfg_table;
const?
> +};
> +
> +struct pll_of_data {
> + struct pll_of_table *pll_table;
> +};
Why the structure for another structure pointer? Just use
pll_of_table for now?
> +
> +static struct pll_of_data pgu_pll_data = {
const?
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 27000000,
Can this be another clk in the framework instead of hardcoding
the parent rate?
> + .pll_cfg_table = (struct pll_cfg []){
> + { 25200000, 1, 84, 90 },
> + { 50000000, 1, 100, 54 },
> + { 74250000, 1, 44, 16 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
There's only ever one, so I'm confused why we're making a list.
> + },
> +};
> +
> +static struct pll_of_data arc_pll_data = {
const?
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 33333333,
> + .pll_cfg_table = (struct pll_cfg []){
> + { 33333333, 1, 1, 1 },
> + { 50000000, 1, 30, 20 },
> + { 75000000, 2, 45, 10 },
> + { 90000000, 2, 54, 10 },
> + { 100000000, 1, 30, 10 },
> + { 125000000, 2, 45, 6 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
> + },
> +};
> +
> +struct pll_clk {
> + void __iomem *base;
> + void __iomem *lock;
> + const struct pll_of_data *pll_data;
> + struct clk_hw hw;
> + struct device *dev;
> +};
> +
> +static inline void pll_write(struct pll_clk *clk, unsigned int reg,
> + unsigned int val)
> +{
> + iowrite32(val, clk->base + reg);
> +}
> +
> +static inline u32 pll_read(struct pll_clk *clk,
> + unsigned int reg)
reg can go on the same line as clk?
> +{
> + return ioread32(clk->base + reg);
> +}
> +
> +static inline struct pll_clk *to_pll_clk(struct clk_hw *hw)
> +{
> + return container_of(hw, struct pll_clk, hw);
> +}
> +
> +static inline u32 div_get_value(unsigned int reg)
> +{
> + if (PLL_REG_GET_BYPASS(reg))
> + return 1;
> +
> + return (PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg));
Useless parenthesis.
> +}
> +
> +static inline u32 encode_div(unsigned int id, int upd)
> +{
> + uint32_t div = 0;
> +
> + PLL_REG_SET_LOW(div, (id%2 == 0) ? id >> 1 : (id >> 1) + 1);
> + PLL_REG_SET_HIGH(div, id >> 1);
> + PLL_REG_SET_EDGE(div, id%2);
> + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0);
> + PLL_REG_SET_NOUPD(div, !upd);
> +
> + return div;
> +}
> +
> +static const struct pll_cfg *pll_get_cfg(unsigned long prate,
> + const struct pll_of_table *pll_table)
> +{
> + int i;
> +
> + for (i = 0; pll_table[i].prate != 0; i++)
> + if (pll_table[i].prate == prate)
> + return pll_table[i].pll_cfg_table;
> +
> + return NULL;
> +}
> +
> +static unsigned long pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + u64 rate;
> + u32 idiv, fbdiv, odiv;
> + struct pll_clk *clk = to_pll_clk(hw);
> +
> + idiv = div_get_value(pll_read(clk, PLL_REG_IDIV));
> + fbdiv = div_get_value(pll_read(clk, PLL_REG_FBDIV));
> + odiv = div_get_value(pll_read(clk, PLL_REG_ODIV));
> +
> + rate = (u64)parent_rate * fbdiv;
> + do_div(rate, idiv * odiv);
> +
> + return (unsigned long)rate;
Useless cast?
> +}
> +
> +static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + int i;
> + long best_rate;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(*prate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate);
> + return -EINVAL;
> + }
> +
> + if (pll_cfg[0].rate == 0)
> + return -EINVAL;
> +
> + best_rate = pll_cfg[0].rate;
> +
> + for (i = 1; pll_cfg[i].rate != 0; i++) {
> + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
> + best_rate = pll_cfg[i].rate;
> + }
> +
> + return best_rate;
> +}
> +
> +static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + int i;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(parent_rate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate);
> + return -EINVAL;
> + }
> +
> + for (i = 0; pll_cfg[i].rate != 0; i++) {
> + if (pll_cfg[i].rate == rate) {
> + pll_write(clk, PLL_REG_IDIV,
> + encode_div(pll_cfg[i].idiv, 0));
> + pll_write(clk, PLL_REG_FBDIV,
> + encode_div(pll_cfg[i].fbdiv, 0));
> + pll_write(clk, PLL_REG_ODIV,
> + encode_div(pll_cfg[i].odiv, 1));
> +
> + /*
> + * Wait until CGU relocks.
> + * If after timeout CGU is unlocked yet return error
> + */
> + udelay(PLL_MAX_LOCK_TIME);
> + if (ioread32(clk->lock) & PLL_LOCK)
> + return 0;
> + else
> + return -ETIMEDOUT;
Can just be a return without the else part.
> + }
> + }
> +
> + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
> + parent_rate);
> + return -EINVAL;
> +}
> +
> +static const struct clk_ops pll_ops = {
> + .recalc_rate = pll_recalc_rate,
> + .round_rate = pll_round_rate,
> + .set_rate = pll_set_rate,
> +};
> +
> +static int pll_clk_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct resource *mem;
> + struct clk_init_data init = { };
> +
> + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return -ENOMEM;
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + pll_clk->base = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->base))
> + return PTR_ERR(pll_clk->base);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + pll_clk->lock = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->lock))
> + return PTR_ERR(pll_clk->base);
> +
> + init.name = dev->of_node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(dev->of_node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> + pll_clk->hw.init = &init;
> + pll_clk->dev = dev;
> + pll_clk->pll_data = of_device_get_match_data(dev);
> +
> + if (!pll_clk->pll_data) {
> + dev_err(dev, "No OF match data provided\n");
> + return -EINVAL;
> + }
> +
> + clk = devm_clk_register(dev, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + dev_err(dev, "failed to register %s clock (%ld)\n",
> + init.name, PTR_ERR(clk));
> + return PTR_ERR(clk);
> + }
> +
> + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk);
> +}
> +
> +static int pll_clk_remove(struct platform_device *pdev)
> +{
> + of_clk_del_provider(pdev->dev.of_node);
> + return 0;
> +}
> +
> +static void __init of_pll_clk_setup(struct device_node *node)
> +{
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct clk_init_data init = { };
> +
> + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return;
> +
> + pll_clk->base = of_iomap(node, 0);
> + if (!pll_clk->base) {
> + pr_err("failed to map pll div registers\n");
> + iounmap(pll_clk->base);
> + return;
> + }
> +
> + pll_clk->lock = of_iomap(node, 1);
> + if (!pll_clk->lock) {
> + pr_err("failed to map pll lock register\n");
> + iounmap(pll_clk->lock);
> + return;
> + }
> +
> + init.name = node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = parent_name ? 1 : 0;
> + pll_clk->hw.init = &init;
> + pll_clk->pll_data = &arc_pll_data;
> +
> + clk = clk_register(NULL, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + pr_err("failed to register %s clock (%ld)\n",
> + node->name, PTR_ERR(clk));
> + kfree(pll_clk);
> + return;
> + }
> +
> + of_clk_add_provider(node, of_clk_src_simple_get, clk);
Can you please use the clk_hw based provider and clk registration
functions?
> +}
> +
> +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup);
Does this need to be CLK_OF_DECLARE_DRIVER? I mean does the
driver need to probe and also have this of declare happen? Is the
PLL special and needs to be used for the timers?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 19/23] drivers/fsi: Add GPIO based FSI master
From: Christopher Bostic @ 2017-04-05 1:24 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Joel Stanley
Cc: Rob Herring, Mark Rutland, Russell King,
rostedt-nx8X9YLhiw1AfugRpC6u6w, mingo-H+wXaHxf7aLQT0dZR+AlfA,
Greg KH, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Linux Kernel Mailing List, Andrew Jeffery, Alistair Popple,
Edward A . James, Jeremy Kerr
In-Reply-To: <1491344360.4166.68.camel-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
On 4/4/17 5:19 PM, Benjamin Herrenschmidt wrote:
> On Tue, 2017-04-04 at 12:32 -0500, Christopher Bostic wrote:
>> Agreed that there is room for improvement. I intend to look further
>> into your suggestions from here and our private conversation on the
>> matter and make changes as appropriate. I have an open issue to track
>> this. As it exists in this patch reads/writes from master to slave
>> fundamentally work.
> My understanding is they "seem to work if you get lucky with the timing
> and fall apart under load". Or did I hear wrong ?
>
>> Given the pervasiveness and time to fully evaluate
>> and test any protocol updates I intend address this in the near future
>> with a separate follow on patch.
> Please try the simple change I proposed in my email. It's a 4 or 5
> lines change max to your clock_toggle function and how it's called in
> send and receive. It should be trivial to check if things still "seem
> to work" to begin with.
>
> Do you have some kind of test mechanism that hammers the FSI
> continuously ? Such as doing a series of putmemproc/getmemproc &
> checking the values ?
>
> Then you can run that while hammering the LPC bus and generally putting
> the BMC under load and you'll quickly see if it's reliable or not.
Hi Ben,
I do now have a mechanism that puts the bus under heavy load. I'll look
into your changes tomorrow.
Thanks,
Chris
>
> Cheers,
> Ben.
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V10 00/12] IOMMU probe deferral support
From: Rob Herring @ 2017-04-05 1:23 UTC (permalink / raw)
To: Sricharan R
Cc: Robin Murphy, Will Deacon, Joerg Roedel, Lorenzo Pieralisi,
Linux IOMMU, linux-arm-kernel@lists.infradead.org, linux-arm-msm,
Marek Szyprowski, bhelgaas@google.com, linux-pci@vger.kernel.org,
linux-acpi@vger.kernel.org, Tomasz Nowicki, Hanjun Guo,
Sinan Kaya, Frank Rowand, devicetree@vger.kernel.org,
linux-kernel
In-Reply-To: <1491301105-5274-1-git-send-email-sricharan@codeaurora.org>
On Tue, Apr 4, 2017 at 5:18 AM, Sricharan R <sricharan@codeaurora.org> wrote:
> This series calls the dma ops configuration for the devices
> at a generic place so that it works for all busses.
> The dma_configure_ops for a device is now called during
> the device_attach callback just before the probe of the
> bus/driver is called. Similarly dma_deconfigure is called during
> device/driver_detach path.
For patches 3, 4, 6, 7, 8:
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 1/2] extcon: cros-ec: Add extcon-cros-ec driver to support display out.
From: Chanwoo Choi @ 2017-04-05 1:21 UTC (permalink / raw)
To: Enric Balletbo i Serra, MyungJoo Ham, Rob Herring
Cc: Lee Jones, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Benson Leung
In-Reply-To: <58B7C9BF.1040708-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Hi Enric,
On 2017년 03월 02일 16:29, Chanwoo Choi wrote:
> Hi,
>
> On 2017년 03월 01일 20:19, Enric Balletbo i Serra wrote:
>> From: Benson Leung <bleung-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>>
>> This is the driver for the USB Type C cable detection mechanism
>> built into the ChromeOS Embedded Controller on systems that
>> have USB Type-C ports.
>>
>> At present, this allows for the presence of display out, but in
>> future, it may also be used to notify host and device type cables
>> and the presence of power.
>>
>> Signed-off-by: Benson Leung <bleung-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
>> ---
>> Changes since v1:
>> Requested by Chanwoo Choi
>> - Rename files changing _ for -
>> - Remove the unneeded blank line on bottom of header.
>> - Remove kobject.h and cros_ec_commands.h includes.
>> - Remove the debug message as is not necessary.
>> - Use the tab for indentation instead of space for if sentence.
>> - Define each variable on different lines when the variables should be
>> initialized.
>> - Remove EXTCON_USB and EXTCON_USB_HOST as are not really used for now.
>> - Add one blank line to split out between state and property setting.
>> - Add the author information (header and module)
>>
>> Enric Balletbo
>> - As Rob suggested to rename the compatible name to something indicating that
>> is USB Type C related I also renamed the file names, extcon-cros-ec ->
>> extcon-usbc-cros-ec, I think it's more clear.
>>
>> drivers/extcon/Kconfig | 7 +
>> drivers/extcon/Makefile | 1 +
>> drivers/extcon/extcon-usbc-cros-ec.c | 415 +++++++++++++++++++++++++++++++++++
>> include/linux/mfd/cros_ec_commands.h | 75 +++++++
>> 4 files changed, 498 insertions(+)
>> create mode 100644 drivers/extcon/extcon-usbc-cros-ec.c
>>
>
> Looks good to me.
> Acked-by: Chanwoo Choi <cw00.chio-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>
> I think this patch should be handled with patches[1].
> [1] https://lkml.org/lkml/2017/2/14/655
>
> I think that one maintainer among following subsystems
> (mfd, chrome h/w platform, rtc and extcon)
> will apply their git repository, and then one maintainer
> will send the pull request of immutable branch for these patches.
>
As I mentioned, these patch should be handled with related patches[1].
[1] https://lkml.org/lkml/2017/2/14/655
So, I can't apply these patch on extcon git because there is a merge conflict
and we should handle these patches with immutable branch between subsystem maintainer.
The v4.11-rc5 was released, if you want to apply this patch to the v4.12-rc1,
please take care of these patches.
--
Best Regards,
Chanwoo Choi
Samsung Electronics
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox