[PATCH linux dev-4.7 v2 2/7] drivers/fsi: Initialize hub master
Christopher Bostic
cbostic at linux.vnet.ibm.com
Wed Feb 22 08:50:27 AEDT 2017
Initialize the hub master control registers. Set up clock delays,
error handling behavior, toggle link enables.
Signed-off-by: Christopher Bostic <cbostic at linux.vnet.ibm.com>
---
Changes in V2:
- Add some description of what a hub master is and how it differs
from a cascaded master.
---
drivers/fsi/fsi-core.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++-
drivers/fsi/fsi-master.h | 57 +++++++++++++++++++++++
2 files changed, 172 insertions(+), 1 deletion(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 646bb43..4199188 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
+#include <linux/delay.h>
#include "fsi-master.h"
@@ -216,11 +217,124 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
slave->id, addr, val, size);
}
-static int hub_master_init(struct fsi_master_hub *hub)
+/*
+ * FSI hub master support
+ *
+ * A hub master increases the number of potential target devices that the
+ * primary FSI master can access. For each link a primary master supports
+ * each of those links can in turn be chained to a hub master with multiple
+ * hub links of its own. Hubs differ from cascaded masters (cMFSI) in the
+ * total addressable range per link -hubs having address ranges that are much
+ * larger.
+ */
+int hub_master_read(struct fsi_master *master, int linkno, uint8_t slave,
+ uint32_t addr, void *val, size_t size)
+{
+ return 0;
+}
+
+int hub_master_write(struct fsi_master *master, int linkno, uint8_t slave,
+ uint32_t addr, const void *val, size_t size)
{
return 0;
}
+int hub_master_break(struct fsi_master *master, int linkno)
+{
+ return 0;
+}
+
+int hub_master_link_enable(struct fsi_master *master, int linkno)
+{
+ return 0;
+}
+
+static int hub_master_init(struct fsi_master_hub *hub)
+{
+ int rc;
+ uint32_t mver;
+ struct fsi_master *master = &hub->master;
+
+ master->read = hub_master_read;
+ master->write = hub_master_write;
+ master->send_break = hub_master_break;
+ master->link_enable = hub_master_link_enable;
+
+ /* Initialize the MFSI (hub master) engine */
+ rc = fsi_slave_read(hub->slave, hub->control_regs + FSI_MVER, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ mver = FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
+ | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE;
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MRESP0, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ mver = FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM;
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MECTRL, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ mver = FSI_MMODE_EIP | FSI_MMODE_ECRC | FSI_MMODE_EPC
+ | fsi_mmode_crs0(1) | fsi_mmode_crs1(1)
+ | FSI_MMODE_P8_TO_LSB;
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MMODE, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ mver = 0xffff0000;
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MDLYR, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ mver = ~0;
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MSENP0, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ /* Leave enabled long enough for master logic to set up */
+ udelay(1000);
+
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MCENP0, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ rc = fsi_slave_read(hub->slave, hub->control_regs + FSI_MAEB, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ mver = FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK;
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MRESP0, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ rc = fsi_slave_read(hub->slave, hub->control_regs + FSI_MLEVP0, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ /* Reset the master bridge */
+ mver = FSI_MRESB_RST_GEN;
+ rc = fsi_slave_write(hub->slave, hub->control_regs + FSI_MRESB0, &mver,
+ sizeof(mver));
+ if (rc)
+ return rc;
+
+ mver = FSI_MRESB_RST_ERR;
+ return fsi_slave_write(hub->slave, hub->control_regs + FSI_MRESB0,
+ &mver, sizeof(mver));
+}
+
static int fsi_slave_scan(struct fsi_slave *slave)
{
uint32_t engine_addr;
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index 3737404..4a3176b 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -19,6 +19,52 @@
#include <linux/device.h>
+/* Control Registers */
+#define FSI_MMODE 0x0 /* R/W: mode */
+#define FSI_MDLYR 0x4 /* R/W: delay */
+#define FSI_MCRSP 0x8 /* R/W: clock rate */
+#define FSI_MENP0 0x10 /* R/W: enable */
+#define FSI_MLEVP0 0x18 /* R: plug detect */
+#define FSI_MSENP0 0x18 /* S: Set enable */
+#define FSI_MCENP0 0x20 /* C: Clear enable */
+#define FSI_MAEB 0x70 /* R: Error address */
+#define FSI_MVER 0x74 /* R: master version/type */
+#define FSI_MRESP0 0xd0 /* W: Port reset */
+#define FSI_MESRB0 0x1d0 /* R: Master error status */
+#define FSI_MRESB0 0x1d0 /* W: Reset bridge */
+#define FSI_MECTRL 0x2e0 /* W: Error control */
+
+/* MMODE: Mode control */
+#define FSI_MMODE_EIP 0x80000000 /* Enable interrupt polling */
+#define FSI_MMODE_ECRC 0x40000000 /* Enable error recovery */
+#define FSI_MMODE_EPC 0x10000000 /* Enable parity checking */
+#define FSI_MMODE_P8_TO_LSB 0x00000010 /* Timeout value LSB */
+ /* Rolf Fritz Nov 20, 2013: */
+ /* MSB=1, LSB=0 is 0.8 ms */
+ /* MSB=0, LSB=1 is 0.9 ms */
+#define FSI_MMODE_CRS0SHFT 18 /* Clk rate selection 0 shift */
+#define FSI_MMODE_CRS0MASK 0x3ff /* Clk rate selection 0 mask */
+#define FSI_MMODE_CRS1SHFT 8 /* Clk rate selection 1 shift */
+#define FSI_MMODE_CRS1MASK 0x3ff /* Clk rate selection 1 mask */
+
+/* MRESB: Reset brindge */
+#define FSI_MRESB_RST_GEN 0x80000000 /* General reset */
+#define FSI_MRESB_RST_ERR 0x40000000 /* Error Reset */
+
+/* MRESB: Reset port */
+#define FSI_MRESP_RST_ALL_MASTER 0x20000000 /* Reset all FSI masters */
+#define FSI_MRESP_RST_ALL_LINK 0x10000000 /* Reset all FSI port contr. */
+#define FSI_MRESP_RST_MCR 0x08000000 /* Reset FSI master reg. */
+#define FSI_MRESP_RST_PYE 0x04000000 /* Reset FSI parity error */
+#define FSI_MRESP_RST_ALL 0xfc000000 /* Reset any error */
+
+/* MECTRL: Error control */
+#define FSI_MECTRL_EOAE 0x8000 /* Enable machine check when */
+ /* master 0 in error */
+#define FSI_MECTRL_P8_AUTO_TERM 0x4000 /* Auto terminate */
+
+#define L_MSB_MASK(x) (0x80000000 >> (x))
+
struct fsi_master {
struct list_head my_slaves;
bool slave_list;
@@ -61,4 +107,15 @@ extern int fsi_master_start_ipoll(struct fsi_master *master);
*/
uint8_t fsi_crc4(uint8_t c, uint64_t x, int bits);
+/* mmode encoders */
+static inline u32 fsi_mmode_crs0(u32 x)
+{
+ return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;
+}
+
+static inline u32 fsi_mmode_crs1(u32 x)
+{
+ return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;
+}
+
#endif /* DRIVERS_FSI_MASTER_H */
--
1.8.2.2
More information about the openbmc
mailing list