[PATCH linux v3 16/18] drivers/fsi: Set up CFAMs for communication
christopher.lee.bostic at gmail.com
christopher.lee.bostic at gmail.com
Wed Oct 12 08:40:01 AEDT 2016
From: Chris Bostic <cbostic at us.ibm.com>
Issue break command to reset CFAM logic and set ID as appropriate
for a particular master type. Begin definition of the slave
engine register set and accessors.
V3 - Remove definition of BREAK command from fsi-master.h
- Remove definitions of fsi_master_fake for set_smode and
break
- Remove master->set_smode master dependent function and
moved to a generic base master set_smode.
- Add fsi_master_link_enable with master type dependencies
Signed-off-by: Chris Bostic <cbostic at us.ibm.com>
---
drivers/fsi/fsi-core.c | 75 +++++++++++++++++++++++++++++++++++++++++--
drivers/fsi/fsi-master-fake.c | 2 ++
drivers/fsi/fsi-master-gpio.c | 33 +++++++++++++++++++
drivers/fsi/fsi-master.h | 2 ++
drivers/fsi/fsi-slave.h | 62 +++++++++++++++++++++++++++++++++++
5 files changed, 171 insertions(+), 3 deletions(-)
create mode 100644 drivers/fsi/fsi-slave.h
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 0da8cf0..c5e7441 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -22,6 +22,7 @@
#include "fsi-master.h"
#include "fsi-cfam.h"
+#include "fsi-slave.h"
#define FSI_N_SLAVES 4
@@ -224,13 +225,66 @@ static void fsi_slave_release(struct device *dev)
kfree(slave);
}
+/*
+ * Issue a break commad on this link
+ */
+static int fsi_master_break(struct fsi_master *master, int link)
+{
+ int rc = 0;
+
+ if (master->send_break)
+ rc = master->send_break(master, link);
+
+ return rc;
+}
+
+static void set_smode_defaults(struct fsi_master *master, uint32_t *smode)
+{
+ *smode = FSI_SMODE_WSC | FSI_SMODE_ECRC
+ | fsi_smode_echodly(0xf) | fsi_smode_senddly(0xf)
+ | fsi_smode_lbcrr(1) | fsi_smode_sid(0);
+}
+
+static int fsi_master_set_smode(struct fsi_master *master, int link)
+{
+ uint32_t smode;
+ int rc;
+
+ set_smode_defaults(master, &smode);
+ rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SMODE,
+ &smode, sizeof(smode));
+
+ return rc;
+}
+
static int fsi_slave_init(struct fsi_master *master,
int link, uint8_t slave_id)
{
- struct fsi_slave *slave;
+ struct fsi_slave *slave = NULL;
uint32_t chip_id;
int rc;
+ /*
+ * todo: Due to CFAM hardware issues related to BREAK commands we're
+ * limited to only one CFAM per link. Once hardware fixes are available
+ * this restriction can be removed.
+ */
+ if (slave_id > 0)
+ return 0;
+
+ rc = fsi_master_break(master, link);
+ if (rc) {
+ dev_warn(master->dev, "no slave detected at %02x:%02x\n",
+ link, slave_id);
+ return -ENODEV;
+ }
+
+ rc = fsi_master_set_smode(master, link);
+ if (rc) {
+ dev_warn(master->dev, "failed to set smode id, rc:%d\n", rc);
+ return -ENODEV;
+ }
+
rc = master->read(master, link, slave_id, 0, &chip_id, sizeof(chip_id));
if (rc) {
dev_warn(master->dev, "can't read slave %02x:%02x: %d\n",
@@ -273,13 +327,28 @@ static int fsi_slave_init(struct fsi_master *master,
/* FSI master support */
+static int fsi_master_link_enable(struct fsi_master *master, int link)
+{
+ int rc;
+
+ if (master->link_enable)
+ rc = master->link_enable(master, link);
+
+ return rc;
+}
+
static int fsi_master_scan(struct fsi_master *master)
{
- int link, slave_id;
+ int link, slave_id, rc;
+
+ for (link = 0; link < master->n_links; link++) {
+ rc = fsi_master_link_enable(master, link);
+ if (rc)
+ continue;
- for (link = 0; link < master->n_links; link++)
for (slave_id = 0; slave_id < FSI_N_SLAVES; slave_id++)
fsi_slave_init(master, link, slave_id);
+ }
return 0;
diff --git a/drivers/fsi/fsi-master-fake.c b/drivers/fsi/fsi-master-fake.c
index ec1ed5e..c7ad631 100644
--- a/drivers/fsi/fsi-master-fake.c
+++ b/drivers/fsi/fsi-master-fake.c
@@ -63,6 +63,8 @@ static int fsi_master_fake_probe(struct platform_device *pdev)
master->n_links = 1;
master->read = fsi_master_fake_read;
master->write = fsi_master_fake_write;
+ master->send_break = NULL;
+ master->link_enable = NULL;
return fsi_master_register(master);
}
diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c
index 5c3d5cd..166370a 100644
--- a/drivers/fsi/fsi-master-gpio.c
+++ b/drivers/fsi/fsi-master-gpio.c
@@ -7,6 +7,8 @@
#include <linux/module.h>
#include "fsi-master.h"
+#include "fsi-cfam.h"
+#include "fsi-slave.h"
struct fsi_master_gpio {
struct fsi_master master;
@@ -50,6 +52,35 @@ static int fsi_master_gpio_write(struct fsi_master *_master, int link,
return 0;
}
+/*
+ * 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;
+
+ /* todo: send the break pattern over gpio */
+ (void)master;
+
+ return 0;
+}
+
+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;
+
+ /* todo: set the enable pin */
+ (void)master;
+
+ return 0;
+}
+
static int fsi_master_gpio_probe(struct platform_device *pdev)
{
struct fsi_master_gpio *master;
@@ -71,6 +102,8 @@ static int fsi_master_gpio_probe(struct platform_device *pdev)
master->master.read = fsi_master_gpio_read;
master->master.write = fsi_master_gpio_write;
+ master->master.send_break = fsi_master_gpio_break;
+ master->master.link_enable = fsi_master_gpio_link_enable;
return fsi_master_register(&master->master);
}
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index e75a810..94a0671 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -29,6 +29,8 @@ struct fsi_master {
int (*write)(struct fsi_master *, int link,
uint8_t slave, uint32_t addr,
const void *val, size_t size);
+ int (*send_break)(struct fsi_master *, int link);
+ int (*link_enable)(struct fsi_master *, int link);
};
extern int fsi_master_register(struct fsi_master *master);
diff --git a/drivers/fsi/fsi-slave.h b/drivers/fsi/fsi-slave.h
new file mode 100644
index 0000000..ea7a760
--- /dev/null
+++ b/drivers/fsi/fsi-slave.h
@@ -0,0 +1,62 @@
+/*
+ * FSI slave engine definitions.
+ *
+ * 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_SLAVE_H
+#define DRIVERS_FSI_SLAVE_H
+
+/*
+ * FSI slave engine control register offsets
+ */
+#define FSI_SMODE 0x0 /* R/W: Mode register */
+
+/*
+ * SMODE fields
+ */
+#define FSI_SMODE_WSC 0x80000000 /* Warm start completed */
+#define FSI_SMODE_ECRC 0x20000000 /* Enable hardware 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 /* Clock rate ratio shift */
+#define FSI_SMODE_LBCRR_MASK 0xf /* Clock rate ratio mask */
+
+/* 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;
+}
+
+#endif /* DRIVERS_FSI_SLAVE_H */
--
1.8.2.2
More information about the openbmc
mailing list