[PATCH v6 17/19] i2c: thunderx: Add i2c driver for ThunderX SOC

2016-04-11 Thread Jan Glauber
The ThunderX SOC uses the same i2c block as the Octeon SOC.
The main difference is that on ThunderX the device is a PCI device
so device probing is done via PCI, interrupts are MSIX and the
clock is taken from device tree.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Kconfig |  10 ++
 drivers/i2c/busses/Makefile|   2 +
 drivers/i2c/busses/i2c-cavium.h|  17 ++-
 drivers/i2c/busses/i2c-thunderx-core.c | 269 +
 4 files changed, 295 insertions(+), 3 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index faa8e68..92d23de 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -953,6 +953,16 @@ config I2C_OCTEON
  This driver can also be built as a module.  If so, the module
  will be called i2c-octeon.
 
+config I2C_THUNDERX
+   tristate "Cavium ThunderX I2C bus support"
+   depends on 64BIT && PCI && !CAVIUM_OCTEON_SOC
+   help
+ Say yes if you want to support the I2C serial bus on Cavium
+ ThunderX SOC.
+
+ This driver can also be built as a module.  If so, the module
+ will be called i2c-thunderx.
+
 config I2C_XILINX
tristate "Xilinx I2C Controller"
depends on HAS_IOMEM
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 282f781..a32ff14 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -93,6 +93,8 @@ obj-$(CONFIG_I2C_VERSATILE)   += i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
 i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
 obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+i2c-thunderx-objs := i2c-cavium.o i2c-thunderx-core.o
+obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.h b/drivers/i2c/busses/i2c-cavium.h
index e17f2dc..d8d4e0b 100644
--- a/drivers/i2c/busses/i2c-cavium.h
+++ b/drivers/i2c/busses/i2c-cavium.h
@@ -8,9 +8,15 @@
 #include 
 
 /* Register offsets */
-#define SW_TWSI0x00
-#define TWSI_INT   0x10
-#define SW_TWSI_EXT0x18
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+   #define SW_TWSI 0x1000
+   #define TWSI_INT0x1010
+   #define SW_TWSI_EXT 0x1018
+#else
+   #define SW_TWSI 0x00
+   #define TWSI_INT0x10
+   #define SW_TWSI_EXT 0x18
+#endif
 
 /* Controller command patterns */
 #define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
@@ -92,6 +98,7 @@
 struct octeon_i2c {
wait_queue_head_t queue;
struct i2c_adapter adap;
+   struct clk *clk;
int irq;
int hlc_irq;/* For cn7890 only */
u32 twsi_freq;
@@ -107,6 +114,10 @@ struct octeon_i2c {
void (*hlc_int_dis)(struct octeon_i2c *);
atomic_t int_en_cnt;
atomic_t hlc_int_en_cnt;
+
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+   struct msix_entry i2c_msix;
+#endif
 };
 
 static inline void writeqflush(u64 val, void __iomem *addr)
diff --git a/drivers/i2c/busses/i2c-thunderx-core.c 
b/drivers/i2c/busses/i2c-thunderx-core.c
new file mode 100644
index 000..99006a4
--- /dev/null
+++ b/drivers/i2c/busses/i2c-thunderx-core.c
@@ -0,0 +1,269 @@
+/*
+ * Cavium ThunderX i2c driver.
+ *
+ * Copyright (C) 2015,2016 Cavium Inc.
+ * Authors: Fred Martin 
+ * Jan Glauber 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+#define DRV_NAME "i2c-thunderx"
+
+#define PCI_CFG_REG_BAR_NUM0
+#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012
+
+#define TWSI_DFL_RATE  10
+#define SYS_FREQ_DEFAULT   8
+
+#define TWSI_INT_ENA_W1C   0x1028
+#define TWSI_INT_ENA_W1S   0x1030
+
+/*
+ * Enable the CORE interrupt.
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void thunder_i2c_int_enable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_CORE_INT, i2c->twsi_base + TWSI_INT_ENA_W1S);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+/*
+ * Disable the CORE interrupt.
+ */
+static void thunder_i2c_int_disable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_CORE_INT, i2c->twsi_base + TWSI_INT_ENA_W1C);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+i2c->twsi_base + TWSI_INT_ENA_W1S);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+static void t

[PATCH v6 15/19] i2c: octeon: Rename driver to prepare for split

2016-04-11 Thread Jan Glauber
This is an intermediate commit in preparation of the driver split.
The module rename in this commit will be reverted in the next patch,
this is just done to make the series bisectible.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Makefile| 2 +-
 drivers/i2c/busses/{i2c-octeon.c => i2c-octeon-core.c} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename drivers/i2c/busses/{i2c-octeon.c => i2c-octeon-core.c} (100%)

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819..3405286 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,7 @@ obj-$(CONFIG_I2C_UNIPHIER)+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
-obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon-core.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-octeon.c 
b/drivers/i2c/busses/i2c-octeon-core.c
similarity index 100%
rename from drivers/i2c/busses/i2c-octeon.c
rename to drivers/i2c/busses/i2c-octeon-core.c
-- 
1.9.1



[PATCH v6 11/19] i2c: octeon: Flush TWSI writes with readback

2016-04-11 Thread Jan Glauber
From: Peter Swain 

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 21 +
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index fff1ac0..8d54fc9 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -127,6 +127,12 @@ struct octeon_i2c {
atomic_t hlc_int_en_cnt;
 };
 
+static void writeqflush(u64 val, void __iomem *addr)
+{
+   __raw_writeq(val, addr);
+   __raw_readq(addr);  /* wait for write to land */
+}
+
 /**
  * octeon_i2c_reg_write - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -197,8 +203,7 @@ static u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
  */
 static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
 {
-   __raw_writeq(data, i2c->twsi_base + TWSI_INT);
-   __raw_readq(i2c->twsi_base + TWSI_INT);
+   writeqflush(data, i2c->twsi_base + TWSI_INT);
 }
 
 /**
@@ -487,7 +492,7 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
else
cmd |= SW_TWSI_OP_7;
 
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
goto err;
@@ -541,10 +546,10 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
 
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
ext |= (u64) msgs[0].buf[j] << (8 * i);
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
}
 
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
goto err;
@@ -589,7 +594,7 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, 
struct i2c_msg *msgs
cmd |= (u64) msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -649,10 +654,10 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c 
*i2c, struct i2c_msg *msg
set_ext = true;
}
if (set_ext)
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
-- 
1.9.1



[PATCH v6 07/19] i2c: octeon: Use i2c recovery framework

2016-04-11 Thread Jan Glauber
Switch to the i2c bus recovery framework using generic SCL recovery.
If this fails try to reset the hardware. The recovery is triggered
during START on timeout of the interrupt or failure to reach
the START / repeated-START condition.

The START function is moved to xfer and while at it:
- removed xfer debug message (i2c core already provides debugging)
- removed length is zero check

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 178 +---
 1 file changed, 111 insertions(+), 67 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 483c8a3..88c9686 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -90,6 +90,8 @@
 #define TWSI_INT_CORE_EN   BIT_ULL(6)
 #define TWSI_INT_SDA_OVR   BIT_ULL(8)
 #define TWSI_INT_SCL_OVR   BIT_ULL(9)
+#define TWSI_INT_SDA   BIT_ULL(10)
+#define TWSI_INT_SCL   BIT_ULL(11)
 
 struct octeon_i2c {
wait_queue_head_t queue;
@@ -152,6 +154,18 @@ static u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 
eop_reg)
 #define octeon_i2c_stat_read(i2c)  \
octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
 
+
+/**
+ * octeon_i2c_write_int - read the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns the value of the register.
+ */
+static u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
+{
+   return __raw_readq(i2c->twsi_base + TWSI_INT);
+}
+
 /**
  * octeon_i2c_write_int - write the TWSI_INT register
  * @i2c: The struct octeon_i2c
@@ -182,33 +196,6 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
octeon_i2c_write_int(i2c, 0);
 }
 
-/**
- * octeon_i2c_unblock - unblock the bus
- * @i2c: The struct octeon_i2c
- *
- * If there was a reset while a device was driving 0 to bus, bus is blocked.
- * We toggle it free manually by some clock cycles and send a stop.
- */
-static void octeon_i2c_unblock(struct octeon_i2c *i2c)
-{
-   int i;
-
-   dev_dbg(i2c->dev, "%s\n", __func__);
-
-   for (i = 0; i < 9; i++) {
-   octeon_i2c_write_int(i2c, 0);
-   udelay(5);
-   octeon_i2c_write_int(i2c, TWSI_INT_SCL_OVR);
-   udelay(5);
-   }
-   /* hand-crank a STOP */
-   octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR);
-   udelay(5);
-   octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR);
-   udelay(5);
-   octeon_i2c_write_int(i2c, 0);
-}
-
 /* interrupt service routine */
 static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 {
@@ -369,6 +356,17 @@ static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
return -EIO;
 }
 
+static int octeon_i2c_recovery(struct octeon_i2c *i2c)
+{
+   int ret;
+
+   ret = i2c_recover_bus(>adap);
+   if (ret)
+   /* recover failed, try hardware re-init */
+   ret = octeon_i2c_init_lowlevel(i2c);
+   return ret;
+}
+
 /**
  * octeon_i2c_start - send START to the bus
  * @i2c: The struct octeon_i2c
@@ -377,34 +375,34 @@ static int octeon_i2c_init_lowlevel(struct octeon_i2c 
*i2c)
  */
 static int octeon_i2c_start(struct octeon_i2c *i2c)
 {
-   int result;
-   u8 data;
-
-   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
-
-   result = octeon_i2c_wait(i2c);
-   if (result) {
-   if (octeon_i2c_stat_read(i2c) == STAT_IDLE) {
-   /*
-* Controller refused to send start flag May
-* be a client is holding SDA low - let's try
-* to free it.
-*/
-   octeon_i2c_unblock(i2c);
-   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
-   result = octeon_i2c_wait(i2c);
+   int ret, retries = 2;
+   u8 stat;
+
+retry:
+   if (retries > 0) {
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
+   ret = octeon_i2c_wait(i2c);
+   if (ret) {
+   /* timeout error, try to recover */
+   ret = octeon_i2c_recovery(i2c);
+   if (ret)
+   return ret;
+   retries--;
+   goto retry;
}
-   if (result)
-   return result;
-   }
+   } else
+   return -EAGAIN;
 
-   data = octeon_i2c_stat_read(i2c);
-   if ((data != STAT_START) && (data != STAT_RSTART)) {
-   dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data);
-   return -EIO;
-   }
+   stat = octeon_i2c_stat_read(i2c);
+   if (stat == STAT_START || stat == STAT_REP_START)
+   /* START successful, bail out */
+   return 0;
 
-   return 0;
+   /* START failed, try t

[PATCH v6 08/19] i2c: octeon: Enable High-Level Controller

2016-04-11 Thread Jan Glauber
From: David Daney 

Use High-Level Controller (HLC) when possible. The HLC can read/write
up to 8 bytes and is completely optional. The most important difference
of the HLC is that it only requires one interrupt for a transfer
(up to 8 bytes) where the low-level read/write requires 2 interrupts
plus one interrupt per transferred byte. Since the interrupts are costly
using the HLC improves the performance. Also, the HLC provides improved error
handling.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 355 ++--
 1 file changed, 345 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 88c9686..0bb9f0b 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -29,13 +29,23 @@
 /* Register offsets */
 #define SW_TWSI0x00
 #define TWSI_INT   0x10
+#define SW_TWSI_EXT0x18
 
 /* Controller command patterns */
 #define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
+#define SW_TWSI_EIABIT_ULL(61) /* Extended internal address */
 #define SW_TWSI_R  BIT_ULL(56) /* Result or read bit */
+#define SW_TWSI_SOVR   BIT_ULL(55) /* Size override */
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_ADDR_SHIFT 40
+#define SW_TWSI_IA_SHIFT   32  /* Internal address */
 
 /* Controller opcode word (bits 60:57) */
 #define SW_TWSI_OP_SHIFT   57
+#define SW_TWSI_OP_7   (0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA(1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10  (2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA   (3ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_TWSI_CLK(4ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
 
@@ -48,7 +58,7 @@
 #define SW_TWSI_EOP_TWSI_RST   (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
 
 /* Controller command and status bits */
-#define TWSI_CTL_CE0x80
+#define TWSI_CTL_CE0x80/* High level controller enable */
 #define TWSI_CTL_ENAB  0x40/* Bus enable */
 #define TWSI_CTL_STA   0x20/* Master-mode start, HW clears when 
done */
 #define TWSI_CTL_STP   0x10/* Master-mode stop, HW clears when 
done */
@@ -87,6 +97,11 @@
 #define STAT_IDLE  0xF8
 
 /* TWSI_INT values */
+#define TWSI_INT_ST_INTBIT_ULL(0)
+#define TWSI_INT_TS_INTBIT_ULL(1)
+#define TWSI_INT_CORE_INT  BIT_ULL(2)
+#define TWSI_INT_ST_EN BIT_ULL(4)
+#define TWSI_INT_TS_EN BIT_ULL(5)
 #define TWSI_INT_CORE_EN   BIT_ULL(6)
 #define TWSI_INT_SDA_OVR   BIT_ULL(8)
 #define TWSI_INT_SCL_OVR   BIT_ULL(9)
@@ -101,6 +116,7 @@ struct octeon_i2c {
int sys_freq;
void __iomem *twsi_base;
struct device *dev;
+   bool hlc_enabled;
 };
 
 /**
@@ -196,6 +212,47 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
octeon_i2c_write_int(i2c, 0);
 }
 
+/*
+ * Cleanup low-level state & enable high-level controller.
+ */
+static void octeon_i2c_hlc_enable(struct octeon_i2c *i2c)
+{
+   int try = 0;
+   u64 val;
+
+   if (i2c->hlc_enabled)
+   return;
+   i2c->hlc_enabled = true;
+
+   while (1) {
+   val = octeon_i2c_ctl_read(i2c);
+   if (!(val & (TWSI_CTL_STA | TWSI_CTL_STP)));
+   break;
+
+   /* clear IFLG event */
+   if (val & TWSI_CTL_IFLG)
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+   if (try++ > 100) {
+   pr_err("%s: giving up\n", __func__);
+   break;
+   }
+
+   /* spin until any start/stop has finished */
+   udelay(10);
+   }
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_CE | TWSI_CTL_AAK | TWSI_CTL_ENAB);
+}
+
+static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+}
+
 /* interrupt service routine */
 static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 {
@@ -293,6 +350,253 @@ static int octeon_i2c_check_status(struct octeon_i2c 
*i2c, int final_read)
}
 }
 
+static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c)
+{
+   u64 val = __raw_readq(i2c->twsi_base + SW_TWSI);
+
+   return (val & SW_TWSI_V) == 0;
+}
+
+static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+   octeon_i2c_write_int(i2c, TWSI_INT_ST_EN);
+}
+
+static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
+{
+   /* clear ST/TS events, listen for neither */
+   octeon_i2c_write_int(i2c, TWSI_INT_ST

[PATCH v6 09/19] dt-bindings: i2c: Add Octeon cn78xx TWSI

2016-04-11 Thread Jan Glauber
Add compatible string for Cavium Octeon cn78XX SOCs TWSI.

Cc: Rob Herring 
Cc: Pawel Moll 
Cc: Mark Rutland 
Cc: Ian Campbell 
Cc: Kumar Gala 

Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 Documentation/devicetree/bindings/i2c/i2c-octeon.txt | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt 
b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
index dced82e..872d485 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
@@ -4,6 +4,12 @@
 
   Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
 
+  or
+
+  compatible: "cavium,octeon-7890-twsi"
+
+  Compatibility with cn78XX SOCs.
+
 - reg: The base address of the TWSI/I2C bus controller register bank.
 
 - #address-cells: Must be <1>.
-- 
1.9.1



[PATCH v6 16/19] i2c: octeon: Split the driver into two parts

2016-04-11 Thread Jan Glauber
Move common functionality into a separate file in preparation of the
re-use from the ThunderX i2c driver.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Makefile  |   3 +-
 drivers/i2c/busses/i2c-cavium.c  | 805 +
 drivers/i2c/busses/i2c-cavium.h  | 200 +++
 drivers/i2c/busses/i2c-octeon-core.c | 972 +--
 4 files changed, 1008 insertions(+), 972 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3405286..282f781 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,8 @@ obj-$(CONFIG_I2C_UNIPHIER)+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
-obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon-core.o
+i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
+obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.c b/drivers/i2c/busses/i2c-cavium.c
new file mode 100644
index 000..9f4edaa
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cavium.c
@@ -0,0 +1,805 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c)
+{
+   u64 val = __raw_readq(i2c->twsi_base + SW_TWSI);
+
+   return (val & SW_TWSI_V) == 0;
+}
+
+static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
+{
+   /* clear ST/TS events, listen for neither */
+   octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT);
+}
+
+/*
+ * Cleanup low-level state & enable high-level controller.
+ */
+static void octeon_i2c_hlc_enable(struct octeon_i2c *i2c)
+{
+   int try = 0;
+   u64 val;
+
+   if (i2c->hlc_enabled)
+   return;
+   i2c->hlc_enabled = true;
+
+   while (1) {
+   val = octeon_i2c_ctl_read(i2c);
+   if (!(val & (TWSI_CTL_STA | TWSI_CTL_STP)));
+   break;
+
+   /* clear IFLG event */
+   if (val & TWSI_CTL_IFLG)
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+   if (try++ > 100) {
+   pr_err("%s: giving up\n", __func__);
+   break;
+   }
+
+   /* spin until any start/stop has finished */
+   udelay(10);
+   }
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_CE | TWSI_CTL_AAK | TWSI_CTL_ENAB);
+}
+
+static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+}
+
+#define I2C_OCTEON_IFLG_WAIT 80/* microseconds */
+
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(I2C_OCTEON_IFLG_WAIT, 2 * I2C_OCTEON_IFLG_WAIT);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+   long time_left;
+   int first = 1;
+
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64(

[PATCH v6 13/19] i2c: octeon: Add workaround for broken irqs on CN3860

2016-04-11 Thread Jan Glauber
From: David Daney 

CN3860 does not interrupt the CPU when the i2c status changes. If
we get a timeout, and see the status has in fact changed, we know we
have this problem, and drop back to polling.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 55 +++--
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index bad49cf..bfaee37 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -119,6 +119,8 @@ struct octeon_i2c {
void __iomem *twsi_base;
struct device *dev;
bool hlc_enabled;
+   bool broken_irq_mode;
+   bool broken_irq_check;
void (*int_en)(struct octeon_i2c *);
void (*int_dis)(struct octeon_i2c *);
void (*hlc_int_en)(struct octeon_i2c *);
@@ -378,10 +380,33 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
long time_left;
int first = 1;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_test_iflg(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->int_en(i2c);
time_left = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
   i2c->adap.timeout);
i2c->int_dis(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_test_iflg(i2c)) {
+   dev_err(i2c->dev,
+   "broken irq connection detected, switching to polling 
mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -477,17 +502,40 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int time_left;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some cn38xx boards did not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_hlc_test_ready(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_hlc_test_ready(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->hlc_int_en(i2c);
time_left = wait_event_interruptible_timeout(i2c->queue,
octeon_i2c_hlc_test_ready(i2c),
i2c->adap.timeout);
i2c->hlc_int_dis(i2c);
-   if (!time_left) {
+   if (!time_left)
octeon_i2c_hlc_int_clear(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_hlc_test_ready(i2c)) {
+   dev_err(i2c->dev, "broken irq connection detected, switching to 
polling mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
+
+   if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
}
-
if (time_left < 0) {
dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
return time_left;
@@ -1143,6 +1191,9 @@ static int octeon_i2c_probe(struct platform_device *pdev)
goto out;
}
 
+   if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+   i2c->broken_irq_check = true;
+
result = octeon_i2c_init_lowlevel(i2c);
if (result) {
dev_err(i2c->dev, "init low level failed\n");
-- 
1.9.1



[PATCH v6 03/19] i2c: octeon: Rename [read|write]_sw to reg_[read|write]

2016-04-11 Thread Jan Glauber
octeon_i2c_read_sw -> octeon_i2c_reg_read
octeon_i2c_write_sw -> octeon_i2c_reg_write

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 52 -
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index f647667..43498a4 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -80,14 +80,14 @@ struct octeon_i2c {
 };
 
 /**
- * octeon_i2c_write_sw - write an I2C core register
+ * octeon_i2c_reg_write - write an I2C core register
  * @i2c: The struct octeon_i2c
  * @eop_reg: Register selector
  * @data: Value to be written
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+static void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
 {
u64 tmp;
 
@@ -98,7 +98,7 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 
eop_reg, u8 data)
 }
 
 /**
- * octeon_i2c_read_sw - read lower bits of an I2C core register
+ * octeon_i2c_reg_read - read lower bits of an I2C core register
  * @i2c: The struct octeon_i2c
  * @eop_reg: Register selector
  *
@@ -106,7 +106,7 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 
eop_reg, u8 data)
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
+static u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg)
 {
u64 tmp;
 
@@ -189,7 +189,7 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 
 static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 {
-   return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) 
!= 0;
+   return (octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) 
!= 0;
 }
 
 /**
@@ -252,8 +252,8 @@ static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
}
}
}
-   octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+   octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
 }
 
 static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
@@ -262,14 +262,14 @@ static int octeon_i2c_init_lowlevel(struct octeon_i2c 
*i2c)
int tries;
 
/* disable high level controller, enable bus access */
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
 
/* reset controller */
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0);
 
for (tries = 10; tries; tries--) {
udelay(1);
-   status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+   status = octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT);
if (status == STAT_IDLE)
return 0;
}
@@ -288,19 +288,19 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
int result;
u8 data;
 
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB | TWSI_CTL_STA);
 
result = octeon_i2c_wait(i2c);
if (result) {
-   if (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT) == 
STAT_IDLE) {
+   if (octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT) == 
STAT_IDLE) {
/*
 * Controller refused to send start flag May
 * be a client is holding SDA low - let's try
 * to free it.
 */
octeon_i2c_unblock(i2c);
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL,
TWSI_CTL_ENAB | TWSI_CTL_STA);
result = octeon_i2c_wait(i2c);
}
@@ -308,7 +308,7 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
return result;
}
 
-   data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+   data = octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT);
if ((data != STAT_START) && (data != STAT_RSTART)) {
dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data);
return -EIO;
@@ -320,7 +320,7 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
 /* send STOP to the bus */
 static void octeon_i2c_stop(struct octeon_i2c *i2c)
 {
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL,
 

[PATCH v6 02/19] i2c: octeon: Move set-clock and init-lowlevel upward

2016-04-11 Thread Jan Glauber
No functional change, just moving the functions upward in
preparation of improving the recovery.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 126 
 1 file changed, 63 insertions(+), 63 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index c4abf16..f647667 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -214,6 +214,69 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
return 0;
 }
 
+/* calculate and set clock divisors */
+static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
+{
+   int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+   int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 100;
+
+   for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+   /*
+* An mdiv value of less than 2 seems to not work well
+* with ds1337 RTCs, so we constrain it to larger values.
+*/
+   for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) 
{
+   /*
+* For given ndiv and mdiv values check the
+* two closest thp values.
+*/
+   tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+   tclk *= (1 << ndiv_idx);
+   thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+
+   for (inc = 0; inc <= 1; inc++) {
+   thp_idx = thp_base + inc;
+   if (thp_idx < 5 || thp_idx > 0xff)
+   continue;
+
+   foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+   foscl = foscl / (1 << ndiv_idx);
+   foscl = foscl / (mdiv_idx + 1) / 10;
+   diff = abs(foscl - i2c->twsi_freq);
+   if (diff < delta_hz) {
+   delta_hz = diff;
+   thp = thp_idx;
+   mdiv = mdiv_idx;
+   ndiv = ndiv_idx;
+   }
+   }
+   }
+   }
+   octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+}
+
+static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
+{
+   u8 status;
+   int tries;
+
+   /* disable high level controller, enable bus access */
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+   /* reset controller */
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+   for (tries = 10; tries; tries--) {
+   udelay(1);
+   status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+   if (status == STAT_IDLE)
+   return 0;
+   }
+   dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
+   return -EIO;
+}
+
 /**
  * octeon_i2c_start - send START to the bus
  * @i2c: The struct octeon_i2c
@@ -428,69 +491,6 @@ static struct i2c_adapter octeon_i2c_ops = {
.algo = _i2c_algo,
 };
 
-/* calculate and set clock divisors */
-static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
-{
-   int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
-   int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 100;
-
-   for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
-   /*
-* An mdiv value of less than 2 seems to not work well
-* with ds1337 RTCs, so we constrain it to larger values.
-*/
-   for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) 
{
-   /*
-* For given ndiv and mdiv values check the
-* two closest thp values.
-*/
-   tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
-   tclk *= (1 << ndiv_idx);
-   thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
-
-   for (inc = 0; inc <= 1; inc++) {
-   thp_idx = thp_base + inc;
-   if (thp_idx < 5 || thp_idx > 0xff)
-   continue;
-
-   foscl = i2c->sys_freq / (2 * (thp_idx + 1));
-   foscl = foscl / (1 << ndiv_idx);
-   foscl = foscl / (mdiv_idx + 1) / 10;
-   diff = abs(foscl - i2c->twsi_freq);
-   i

[PATCH v6 04/19] i2c: octeon: Introduce helper functions for register access

2016-04-11 Thread Jan Glauber
Add helper functions for control, data and status register access.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 56 +++--
 1 file changed, 31 insertions(+), 25 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 43498a4..b25c491 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -97,6 +97,11 @@ static void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 
eop_reg, u8 data)
} while ((tmp & SW_TWSI_V) != 0);
 }
 
+#define octeon_i2c_ctl_write(i2c, val) \
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val)
+#define octeon_i2c_data_write(i2c, val)
\
+   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val)
+
 /**
  * octeon_i2c_reg_read - read lower bits of an I2C core register
  * @i2c: The struct octeon_i2c
@@ -118,6 +123,13 @@ static u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 
eop_reg)
return tmp & 0xFF;
 }
 
+#define octeon_i2c_ctl_read(i2c)   \
+   octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL)
+#define octeon_i2c_data_read(i2c)  \
+   octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA)
+#define octeon_i2c_stat_read(i2c)  \
+   octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
+
 /**
  * octeon_i2c_write_int - write the TWSI_INT register
  * @i2c: The struct octeon_i2c
@@ -189,7 +201,7 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 
 static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 {
-   return (octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) 
!= 0;
+   return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG) != 0;
 }
 
 /**
@@ -262,14 +274,14 @@ static int octeon_i2c_init_lowlevel(struct octeon_i2c 
*i2c)
int tries;
 
/* disable high level controller, enable bus access */
-   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
 
/* reset controller */
octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0);
 
for (tries = 10; tries; tries--) {
udelay(1);
-   status = octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT);
+   status = octeon_i2c_stat_read(i2c);
if (status == STAT_IDLE)
return 0;
}
@@ -288,27 +300,25 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
int result;
u8 data;
 
-   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL,
-   TWSI_CTL_ENAB | TWSI_CTL_STA);
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
 
result = octeon_i2c_wait(i2c);
if (result) {
-   if (octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT) == 
STAT_IDLE) {
+   if (octeon_i2c_stat_read(i2c) == STAT_IDLE) {
/*
 * Controller refused to send start flag May
 * be a client is holding SDA low - let's try
 * to free it.
 */
octeon_i2c_unblock(i2c);
-   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL,
-   TWSI_CTL_ENAB | TWSI_CTL_STA);
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
result = octeon_i2c_wait(i2c);
}
if (result)
return result;
}
 
-   data = octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT);
+   data = octeon_i2c_stat_read(i2c);
if ((data != STAT_START) && (data != STAT_RSTART)) {
dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data);
return -EIO;
@@ -320,8 +330,7 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
 /* send STOP to the bus */
 static void octeon_i2c_stop(struct octeon_i2c *i2c)
 {
-   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL,
-   TWSI_CTL_ENAB | TWSI_CTL_STP);
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP);
 }
 
 /**
@@ -345,15 +354,15 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int 
target,
if (result)
return result;
 
-   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
-   octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+   octeon_i2c_data_write(i2c, target << 1);
+   octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
 
result = octeon_i2c_wait(i2c);
if (result)
return result;
 
for (i = 0; i < length; i++) {
-   tmp = octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT);
+   tmp = octeon_i2c_stat_read(i2c);
 

[PATCH v6 05/19] i2c: octeon: Remove superfluous check in octeon_i2c_test_iflg

2016-04-11 Thread Jan Glauber
Remove superfluous check and stray newline.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index b25c491..4275007 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -198,10 +198,9 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
-
 static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 {
-   return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG) != 0;
+   return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG);
 }
 
 /**
-- 
1.9.1



[PATCH v6 00/19] i2c-octeon and i2c-thunderx drivers

2016-04-11 Thread Jan Glauber
Hi Wolfram,

in the meantime I've converted the octeon driver to use the i2c
recovery framework. I thing this makes the code easier to follow.
I've also cleaned up some other aspects, like the register access
and fixed some bugs I found while going over the code again.


This series for the Octeon i2c driver is an attempt to upstream some
bug fixes and features that accumulated for some time.

On top of the Octeon changes a i2c driver for the ThunderX SOC is
added which uses the same functional block as the Octeon driver.

Patches are on top of 4.6-rc3 and were tested on OCTEON, OCTEON-78
and ThunderX.

Changes to v5:
- Switch to i2c recovery framework
- Clean-up register access, introduce new helper functions
- Fixed ready bit check in combined write
- Fixed IFLG clear in hlc_enable
- Removed complicated last phase logic, not needed when we send
  START for every message part

Changes to v4:
- Splitted the High-Level Controller patch into several patches
- Reworded some commit messages

Changes to v3:
- Added more functionality flags for SMBUS
- Removed both module parameters
- Make xfer return also other errors than EGAIN
- Return EPROTO on invalid SMBUS block length
- Use devm_ioremap_resource
- Added rename-only patch
- Removed kerneldoc patch from series
- Improved defines

Changes to v2:
- Split clenaup patch into several patches
- Strictly moved functional changes to later patches
- Fixed do-while checkpatch errors
- Moved defines to the patches that use them
- Use BIT_ULL macro
- Split ThunderX patch into 2 patches

Changes to v1:
- Fixed compile error on x86_64
- Disabled thunderx driver on MIPS
- Re-ordered some thunderx probe functions for readability
- Fix missing of_irq.h and i2c-smbus.h includes
- Use IS_ENABLED for CONFIG options

Jan

-

David Daney (3):
  i2c: octeon: Enable High-Level Controller
  i2c: octeon: Add support for cn78xx chips
  i2c: octeon: Add workaround for broken irqs on CN3860

Jan Glauber (14):
  i2c: octeon: Increase retry default and use fixed timeout value
  i2c: octeon: Move set-clock and init-lowlevel upward
  i2c: octeon: Rename [read|write]_sw to reg_[read|write]
  i2c: octeon: Introduce helper functions for register access
  i2c: octeon: Remove superfluous check in octeon_i2c_test_iflg
  i2c: octeon: Improve error status checking
  i2c: octeon: Use i2c recovery framework
  dt-bindings: i2c: Add Octeon cn78xx TWSI
  i2c: octeon: Move read function before write
  i2c: octeon: Rename driver to prepare for split
  i2c: octeon: Split the driver into two parts
  i2c: thunderx: Add i2c driver for ThunderX SOC
  i2c: octeon,thunderx: Move register offsets to struct
  i2c: thunderx: Add smbus alert support

Peter Swain (2):
  i2c: octeon: Flush TWSI writes with readback
  i2c: octeon: Faster operation when IFLG signals late

 .../devicetree/bindings/i2c/i2c-octeon.txt |   6 +
 drivers/i2c/busses/Kconfig |  10 +
 drivers/i2c/busses/Makefile|   3 +
 drivers/i2c/busses/i2c-cavium.c| 805 +
 drivers/i2c/busses/i2c-cavium.h| 218 ++
 drivers/i2c/busses/i2c-octeon-core.c   | 288 
 drivers/i2c/busses/i2c-octeon.c| 600 ---
 drivers/i2c/busses/i2c-thunderx-core.c | 308 
 8 files changed, 1638 insertions(+), 600 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

-- 
1.9.1



Re: [PATCH 2/4] arm64: pmu: add fallback probe table

2016-04-12 Thread Jan Glauber
On Fri, Apr 08, 2016 at 04:57:05PM -0500, Jeremy Linton wrote:
> From: Mark Salter 
> 
> In preparation for ACPI support, add a pmu_probe_info table to
> the arm_pmu_device_probe() call. This table gets used when
> probing in the absence of a devicetree node for PMU.
> 
> Signed-off-by: Mark Salter 
> Signed-off-by: Jeremy Linton 
> ---
>  arch/arm64/kernel/perf_event.c | 10 +-
>  include/linux/perf/arm_pmu.h   |  3 +++
>  2 files changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
> index f419a7c..8f12eac 100644
> --- a/arch/arm64/kernel/perf_event.c
> +++ b/arch/arm64/kernel/perf_event.c
> @@ -867,9 +867,17 @@ static const struct of_device_id 
> armv8_pmu_of_device_ids[] = {
>   {},
>  };
>  
> +static const struct pmu_probe_info armv8_pmu_probe_table[] = {
> + ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A53, armv8_a53_pmu_init),
> + ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A57, armv8_a57_pmu_init),
> + PMU_PROBE(0, 0, armv8_pmuv3_init), /* if all else fails... */
> + { /* sentinel value */ }
> +};
> +

Hi Jeremy,

with 4.6 ThunderX PMU support was added, so I think above table is
missing a line like:

ARMV8_PMU_PART_PROBE(CAVIUM_CPU_PART_THUNDERX, armv8_thunder_pmu_init)

Thanks,
Jan


Re: [PATCH 0/6 v4] arm64/perf: Add ACPI support

2016-04-15 Thread Jan Glauber
Hi Jeremy,

I've tested the patches on ThunderX and got perf running with ACPI,
so you can add my Tested-by if you like.

Thanks,
Jan

On Tue, Apr 12, 2016 at 03:21:05PM -0500, Jeremy Linton wrote:
> v3->v4:
> Correct build issues with ARM (!ARM64) kernels.
> Add ThunderX to list of PMU types.
> 
> v3:
> Enable ARM performance monitoring units on ACPI/arm64 machines.
> 
> This patch expands and reworks the patches published by Mark Salter
> in order to clean up a few of the previous review comments, as well as
> add support for newer CPUs and big/little configurations.
> 
> I've been testing this patch in concert with an assortment of ACPI
> patches to enable things like PCIe. Its been tested on juno, seattle
> and some xgene systems.
> 
> Thanks,
> 
> *** BLURB HERE ***
> 
> Jeremy Linton (3):
>   arm: arm64: Add routine to determine cpuid of other cpus
>   arm64: pmu: Add ACPI support for A72 and ThunderX
>   arm64: pmu: Detect multiple PMU types in an ACPI system
> 
> Mark Salter (3):
>   arm: pmu: Fix non-devicetree probing
>   arm64: pmu: add fallback probe table
>   arm64: pmu: Add support for probing with ACPI
> 
>  arch/arm/include/asm/cputype.h   |   4 +
>  arch/arm64/include/asm/cputype.h |   4 +
>  arch/arm64/kernel/perf_event.c   |  12 ++-
>  arch/arm64/kernel/smp.c  |   5 +
>  drivers/perf/Kconfig |   4 +
>  drivers/perf/Makefile|   1 +
>  drivers/perf/arm_pmu.c   |  51 --
>  drivers/perf/arm_pmu_acpi.c  | 213 
> +++
>  include/linux/perf/arm_pmu.h |  10 ++
>  9 files changed, 293 insertions(+), 11 deletions(-)
>  create mode 100644 drivers/perf/arm_pmu_acpi.c
> 
> -- 
> 2.4.3


[PATCH] arm64: Reduce verbosity on SMP CPU stop

2016-04-15 Thread Jan Glauber
When CPUs are stopped during an abnormal operation like panic
for each CPU a line is printed and the stack trace is dumped.

This information is only interesting for the aborting CPU
and on systems with many CPUs it only makes it harder to
debug if after the aborting CPU the log is flooded with data
about all other CPUs too.

Therefore remove the stack dump and printk of other CPUs
and only print a single line that the other CPUs are going to be
stopped.

Signed-off-by: Jan Glauber 
---
 arch/arm64/kernel/smp.c | 11 +++
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index b2d5f4e..e6c2eb1 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -770,14 +770,6 @@ static DEFINE_RAW_SPINLOCK(stop_lock);
  */
 static void ipi_cpu_stop(unsigned int cpu)
 {
-   if (system_state == SYSTEM_BOOTING ||
-   system_state == SYSTEM_RUNNING) {
-   raw_spin_lock(_lock);
-   pr_crit("CPU%u: stopping\n", cpu);
-   dump_stack();
-   raw_spin_unlock(_lock);
-   }
-
set_cpu_online(cpu, false);
 
local_irq_disable();
@@ -872,6 +864,9 @@ void smp_send_stop(void)
cpumask_copy(, cpu_online_mask);
cpumask_clear_cpu(smp_processor_id(), );
 
+   if (system_state == SYSTEM_BOOTING ||
+   system_state == SYSTEM_RUNNING)
+   pr_crit("SMP: stopping secondary CPUs\n");
smp_cross_call(, IPI_CPU_STOP);
}
 
-- 
1.9.1



[PATCH v2] arm64: Reduce verbosity on SMP CPU stop

2016-04-18 Thread Jan Glauber
On Fri, Apr 15, 2016 at 12:37:06PM +0100, Will Deacon wrote:
> You can remove stop_lock altogether now, right? I also wonder whether
> it would be worth printing out which CPUs are still online in the case where
> we fail to stop all the secondaries?

Sorry, I've been a bit offline. Yes, the stop_lock can also be removed. 

How about below patch that prints the CPU ids for all CPUs that failed
to stop?

Jan



When CPUs are stopped during an abnormal operation like panic
for each CPU a line is printed and the stack trace is dumped.

This information is only interesting for the aborting CPU
and on systems with many CPUs it only makes it harder to
debug if after the aborting CPU the log is flooded with data
about all other CPUs too.

Therefore remove the stack dump and printk of other CPUs
and only print a single line that the other CPUs are going to be
stopped and, in case any CPUs remain online list them.

Signed-off-by: Jan Glauber 
---
 arch/arm64/kernel/smp.c | 16 +---
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index b2d5f4e..29f4e37 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -763,21 +763,11 @@ void arch_irq_work_raise(void)
 }
 #endif
 
-static DEFINE_RAW_SPINLOCK(stop_lock);
-
 /*
  * ipi_cpu_stop - handle IPI from smp_send_stop()
  */
 static void ipi_cpu_stop(unsigned int cpu)
 {
-   if (system_state == SYSTEM_BOOTING ||
-   system_state == SYSTEM_RUNNING) {
-   raw_spin_lock(_lock);
-   pr_crit("CPU%u: stopping\n", cpu);
-   dump_stack();
-   raw_spin_unlock(_lock);
-   }
-
set_cpu_online(cpu, false);
 
local_irq_disable();
@@ -872,6 +862,9 @@ void smp_send_stop(void)
cpumask_copy(, cpu_online_mask);
cpumask_clear_cpu(smp_processor_id(), );
 
+   if (system_state == SYSTEM_BOOTING ||
+   system_state == SYSTEM_RUNNING)
+   pr_crit("SMP: stopping secondary CPUs\n");
smp_cross_call(, IPI_CPU_STOP);
}
 
@@ -881,7 +874,8 @@ void smp_send_stop(void)
udelay(1);
 
if (num_online_cpus() > 1)
-   pr_warning("SMP: failed to stop secondary CPUs\n");
+   pr_warning("SMP: failed to stop secondary CPUs %*pbl\n",
+  cpumask_pr_args(cpu_online_mask));
 }
 
 /*
-- 
1.9.1



Re: [PATCH v2 0/5] Cavium ThunderX uncore PMU support

2016-04-04 Thread Jan Glauber
Hi Mark,

can you have a look at these patches?

Thanks,
Jan

On Wed, Mar 09, 2016 at 05:21:02PM +0100, Jan Glauber wrote:
> This patch series provides access to various counters on the ThunderX SOC.
> 
> For details of the uncore implementation see patch #1.
> 
> Patches #2-5 add the various ThunderX specific PMUs.
> 
> As suggested I've put the files under drivers/perf/uncore. I would
> prefer this location over drivers/bus because not all of the uncore
> drivers are bus related.
> 
> Changes to v1:
> - Added NUMA support
> - Fixed CPU hotplug by pmu migration
> - Moved files to drivers/perf/uncore
> - Removed OCX FRC and LNE drivers, these will fit better into a edac driver
> - improved comments abount overflow interrupts
> - removed max device limit
> - trimmed include files
> 
> Feedback welcome!
> Jan
> 
> -
> 
> Jan Glauber (5):
>   arm64/perf: Basic uncore counter support for Cavium ThunderX
>   arm64/perf: Cavium ThunderX L2C TAD uncore support
>   arm64/perf: Cavium ThunderX L2C CBC uncore support
>   arm64/perf: Cavium ThunderX LMC uncore support
>   arm64/perf: Cavium ThunderX OCX TLK uncore support
> 
>  drivers/perf/Makefile   |   1 +
>  drivers/perf/uncore/Makefile|   5 +
>  drivers/perf/uncore/uncore_cavium.c | 314 +++
>  drivers/perf/uncore/uncore_cavium.h |  95 +
>  drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 237 +++
>  drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600 
> 
>  drivers/perf/uncore/uncore_cavium_lmc.c | 196 +
>  drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 380 ++
>  8 files changed, 1828 insertions(+)
>  create mode 100644 drivers/perf/uncore/Makefile
>  create mode 100644 drivers/perf/uncore/uncore_cavium.c
>  create mode 100644 drivers/perf/uncore/uncore_cavium.h
>  create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c
>  create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c
>  create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c
>  create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c
> 
> -- 
> 1.9.1


Re: [PATCH v4 03/14] i2c-octeon: Change adapter timeout and retry default values

2016-03-31 Thread Jan Glauber
On Wed, Mar 23, 2016 at 08:55:18PM +0100, Wolfram Sang wrote:
> On Fri, Mar 18, 2016 at 09:46:28AM +0100, Jan Glauber wrote:
> > Convert the adapter timeout to 2 ms instead of a fixed number of
> > jiffies and set retries to 10.
> 
> You describe what you change, but not why this is needed. Why 10
> retries? And shouldn't that be 20ms seeing the HZ/50 ?

The timeout value is not changed, i2c-octeon is bound to Octeon SOC
which has CONFIG_HZ=100. I would prefer to use an absolute value for
a timeout that should not change with the value of CONFIG_HZ.

For the retries, I'll change it to 5 which is what many i2c drivers
use. I thought the reason to use a non-zero value for retries might
be obvious, like "retry in case of a failed operation" ?!

With the updated driver I do not see retry attempts, but it might
not hurt the robustness of the driver to benefit from i2c core
retry logic, or am I missing something?

> Also, please use "i2c: octeon: " as prefix in the subject.

OK.

Thanks,
Jan

> Thanks,
> 
>Wolfram
> 
> > 
> > Signed-off-by: Jan Glauber 
> > ---
> >  drivers/i2c/busses/i2c-octeon.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-octeon.c 
> > b/drivers/i2c/busses/i2c-octeon.c
> > index 9240037..e616e4c 100644
> > --- a/drivers/i2c/busses/i2c-octeon.c
> > +++ b/drivers/i2c/busses/i2c-octeon.c
> > @@ -414,7 +414,6 @@ static struct i2c_adapter octeon_i2c_ops = {
> > .owner = THIS_MODULE,
> > .name = "OCTEON adapter",
> > .algo = _i2c_algo,
> > -   .timeout = HZ / 50,
> >  };
> >  
> >  /* calculate and set clock divisors */
> > @@ -541,6 +540,8 @@ static int octeon_i2c_probe(struct platform_device 
> > *pdev)
> > octeon_i2c_set_clock(i2c);
> >  
> > i2c->adap = octeon_i2c_ops;
> > +   i2c->adap.timeout = msecs_to_jiffies(2);
> > +   i2c->adap.retries = 10;
> > i2c->adap.dev.parent = >dev;
> > i2c->adap.dev.of_node = node;
> > i2c_set_adapdata(>adap, i2c);
> > -- 
> > 1.9.1
> > 




Re: [PATCH v4 05/14] i2c-octeon: Enable high-level controller and improve on bus contention

2016-03-31 Thread Jan Glauber
On Wed, Mar 23, 2016 at 09:32:15PM +0100, Wolfram Sang wrote:
> On Fri, Mar 18, 2016 at 09:46:30AM +0100, Jan Glauber wrote:
> > From: David Daney 
> > 
> > Use High Level Controller when possible.
> 
> Can you give me a one line description what this Controller is? I'd
> assume it can do simple write-then-read messages with less setup?

Of course, I'll add this to the patch description too.

The HLC can read/write up to 8 bytes and is completely optional. The most
important difference of the HLC is that it only requires one interrupt for
a transfer (up to 8 bytes) where the low-level read/write requires 2
interrupts plus one interrupt per transferred byte. Since the interrupts
are costly using the HLC improves the performance. Also, the HLC provides
improved error handling.

> > i2c-octeon was reacting badly to bus contention: when in
> > direct-access mode (for transfers > 8 bytes, which cannot use the
> > high-level controller) some !ACK or arbitration-loss states were
> > not causing the current transfer to be aborted, and the bus released.
> 
> So, what does this patch do? Enable HLC for transfers < 8 byte? And for
> all other transfers we still suffer from the same problem?

I think the patch description was misleading, which is my fault because
I merged several incremental patches into one.

The HLC is used when possible (up to 8 bytes). For bigger transfers
the handling is improved and special treatment is done for the first
and last part of a transfer.

> Such information should be here, too. It helps reviewing when I already
> have the big picture.
> 
> > There's one place in i2c protocol that !ACK is an acceptable
> > response: in the final byte of a read cycle.  In this case the
> > destination is not saying that the transfer failed, just that it
> > doesn't want more data.
> 
> Ehrm, no? For reads, the MASTER is saying it doesn't need any more data.
> And an I2C eeprom can legally NACK a write, e.g. when it is still
> processing the previous write. Also, NACK is a valid response after the
> address phase, meaning there is no device listening.
> 
> Does the implementation cover the above cases?
> 
> > This enables correct behavior of ACK on final byte of non-final read
> > msgs too.
> 
> The patch is huge and very hard to review. Maybe it needs to be split
> up. Brainstorming example: a) move functions like octeon_i2c_set_clock()
> upwards, b) change them if needed, c) implement HLC functions, d) add
> switching logic to use HLC or non-HLC functions...

I was reluctant to split the patch because of the high risk of breaking
the bi-sectability, but your proposal makes sense. I've seperated the
error handling changes from the HLC feature now (plus seperate
patches for the moved functions).

Thanks,
Jan

> But first we need to be clear on the big picture view.
> 
> Thanks,
> 
>Wolfram
> 




[PATCH v5 13/14] i2c: thunderx: Add i2c driver for ThunderX SOC

2016-03-31 Thread Jan Glauber
The ThunderX SOC uses the same i2c block as the Octeon SOC.
The main difference is that on ThunderX the device is a PCI device
so device probing is done via PCI, interrupts are MSIX and the
clock is taken from device tree.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Kconfig |  10 ++
 drivers/i2c/busses/Makefile|   2 +
 drivers/i2c/busses/i2c-cavium.h|  17 ++-
 drivers/i2c/busses/i2c-thunderx-core.c | 268 +
 4 files changed, 294 insertions(+), 3 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index faa8e68..92d23de 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -953,6 +953,16 @@ config I2C_OCTEON
  This driver can also be built as a module.  If so, the module
  will be called i2c-octeon.
 
+config I2C_THUNDERX
+   tristate "Cavium ThunderX I2C bus support"
+   depends on 64BIT && PCI && !CAVIUM_OCTEON_SOC
+   help
+ Say yes if you want to support the I2C serial bus on Cavium
+ ThunderX SOC.
+
+ This driver can also be built as a module.  If so, the module
+ will be called i2c-thunderx.
+
 config I2C_XILINX
tristate "Xilinx I2C Controller"
depends on HAS_IOMEM
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 282f781..a32ff14 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -93,6 +93,8 @@ obj-$(CONFIG_I2C_VERSATILE)   += i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
 i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
 obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+i2c-thunderx-objs := i2c-cavium.o i2c-thunderx-core.o
+obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.h b/drivers/i2c/busses/i2c-cavium.h
index 7f78bf0..31608c4 100644
--- a/drivers/i2c/busses/i2c-cavium.h
+++ b/drivers/i2c/busses/i2c-cavium.h
@@ -8,9 +8,15 @@
 #include 
 
 /* Register offsets */
-#define SW_TWSI0x00
-#define TWSI_INT   0x10
-#define SW_TWSI_EXT0x18
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+   #define SW_TWSI 0x1000
+   #define TWSI_INT0x1010
+   #define SW_TWSI_EXT 0x1018
+#else
+   #define SW_TWSI 0x00
+   #define TWSI_INT0x10
+   #define SW_TWSI_EXT 0x18
+#endif
 
 /* Controller command patterns */
 #define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
@@ -92,6 +98,7 @@
 struct octeon_i2c {
wait_queue_head_t queue;
struct i2c_adapter adap;
+   struct clk *clk;
int irq;
int hlc_irq;/* For cn7890 only */
u32 twsi_freq;
@@ -107,6 +114,10 @@ struct octeon_i2c {
void (*hlc_int_dis)(struct octeon_i2c *);
atomic_t int_en_cnt;
atomic_t hlc_int_en_cnt;
+
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+   struct msix_entry i2c_msix;
+#endif
 };
 
 static inline void writeqflush(u64 val, void __iomem *addr)
diff --git a/drivers/i2c/busses/i2c-thunderx-core.c 
b/drivers/i2c/busses/i2c-thunderx-core.c
new file mode 100644
index 000..2ce985b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-thunderx-core.c
@@ -0,0 +1,268 @@
+/*
+ * Cavium ThunderX i2c driver.
+ *
+ * Copyright (C) 2015,2016 Cavium Inc.
+ * Authors: Fred Martin 
+ * Jan Glauber 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+#define DRV_NAME "i2c-thunderx"
+
+#define PCI_CFG_REG_BAR_NUM0
+#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012
+
+#define TWSI_DFL_RATE  10
+#define SYS_FREQ_DEFAULT   8
+
+#define TWSI_INT_ENA_W1C   0x1028
+#define TWSI_INT_ENA_W1S   0x1030
+
+/*
+ * Enable the CORE interrupt.
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void thunder_i2c_int_enable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_CORE_INT, i2c->twsi_base + TWSI_INT_ENA_W1S);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+/*
+ * Disable the CORE interrupt.
+ */
+static void thunder_i2c_int_disable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_CORE_INT, i2c->twsi_base + TWSI_INT_ENA_W1C);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+i2c->twsi_base + TWSI_INT_ENA_W1S);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+static void t

[PATCH v5 11/14] i2c: octeon: Rename driver to prepare for split

2016-03-31 Thread Jan Glauber
This is just an intermediate commit in preparation of
the driver split. The module rename in this commit
will be reverted in the next patch, this is just done
to make the series bisectible.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Makefile| 2 +-
 drivers/i2c/busses/{i2c-octeon.c => i2c-octeon-core.c} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename drivers/i2c/busses/{i2c-octeon.c => i2c-octeon-core.c} (100%)

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819..3405286 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,7 @@ obj-$(CONFIG_I2C_UNIPHIER)+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
-obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon-core.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-octeon.c 
b/drivers/i2c/busses/i2c-octeon-core.c
similarity index 100%
rename from drivers/i2c/busses/i2c-octeon.c
rename to drivers/i2c/busses/i2c-octeon-core.c
-- 
1.9.1



[PATCH v5 04/14] i2c: octeon: Enable High-Level Controller

2016-03-31 Thread Jan Glauber
From: David Daney 

Use High-Level Controller (HLC) when possible. The HLC can read/write
up to 8 bytes and is completely optional. The most important difference
of the HLC is that it only requires one interrupt for a transfer
(up to 8 bytes) where the low-level read/write requires 2 interrupts plus
one interrupt per transferred byte. Since the interrupts are costly using
the HLC improves the performance. Also, the HLC provides improved error
handling.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 397 ++--
 1 file changed, 380 insertions(+), 17 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index a037245..bc0ed20 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -29,13 +29,23 @@
 /* Register offsets */
 #define SW_TWSI0x00
 #define TWSI_INT   0x10
+#define SW_TWSI_EXT0x18
 
 /* Controller command patterns */
 #define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
+#define SW_TWSI_EIABIT_ULL(61) /* Extended internal address */
 #define SW_TWSI_R  BIT_ULL(56) /* Result or read bit */
+#define SW_TWSI_SOVR   BIT_ULL(55) /* Size override */
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_ADDR_SHIFT 40
+#define SW_TWSI_IA_SHIFT   32  /* Internal address */
 
 /* Controller opcode word (bits 60:57) */
 #define SW_TWSI_OP_SHIFT   57
+#define SW_TWSI_OP_7   (0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA(1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10  (2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA   (3ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_TWSI_CLK(4ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
 
@@ -48,7 +58,7 @@
 #define SW_TWSI_EOP_TWSI_RST   (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
 
 /* Controller command and status bits */
-#define TWSI_CTL_CE0x80
+#define TWSI_CTL_CE0x80/* High level controller enable */
 #define TWSI_CTL_ENAB  0x40/* Bus enable */
 #define TWSI_CTL_STA   0x20/* Master-mode start, HW clears when 
done */
 #define TWSI_CTL_STP   0x10/* Master-mode stop, HW clears when 
done */
@@ -87,9 +97,16 @@
 #define STAT_IDLE  0xF8
 
 /* TWSI_INT values */
+#define TWSI_INT_ST_INTBIT_ULL(0)
+#define TWSI_INT_TS_INTBIT_ULL(1)
+#define TWSI_INT_CORE_INT  BIT_ULL(2)
+#define TWSI_INT_ST_EN BIT_ULL(4)
+#define TWSI_INT_TS_EN BIT_ULL(5)
 #define TWSI_INT_CORE_EN   BIT_ULL(6)
 #define TWSI_INT_SDA_OVR   BIT_ULL(8)
 #define TWSI_INT_SCL_OVR   BIT_ULL(9)
+#define TWSI_INT_SDA   BIT_ULL(10)
+#define TWSI_INT_SCL   BIT_ULL(11)
 
 struct octeon_i2c {
wait_queue_head_t queue;
@@ -99,6 +116,7 @@ struct octeon_i2c {
int sys_freq;
void __iomem *twsi_base;
struct device *dev;
+   bool hlc_enabled;
 };
 
 static int reset_how;
@@ -111,7 +129,7 @@ static int reset_how;
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u32 data)
 {
u64 tmp;
 
@@ -122,7 +140,7 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 
eop_reg, u8 data)
 }
 
 /**
- * octeon_i2c_read_sw - read lower bits of an I2C core register
+ * octeon_i2c_read_sw64 - read an I2C core register
  * @i2c: The struct octeon_i2c
  * @eop_reg: Register selector
  *
@@ -130,7 +148,7 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 
eop_reg, u8 data)
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
+static u64 octeon_i2c_read_sw64(struct octeon_i2c *i2c, u64 eop_reg)
 {
u64 tmp;
 
@@ -139,7 +157,21 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 
eop_reg)
tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
} while ((tmp & SW_TWSI_V) != 0);
 
-   return tmp & 0xFF;
+   return tmp;
+}
+
+/**
+ * octeon_i2c_read_sw - read lower bits of an I2C core register
+ * @i2c: The struct octeon_i2c
+ * @eop_reg: Register selector
+ *
+ * Returns the data.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
+{
+   return octeon_i2c_read_sw64(i2c, eop_reg) & 0xFF;
 }
 
 /**
@@ -172,6 +204,15 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
octeon_i2c_write_int(i2c, 0);
 }
 
+static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc

[PATCH v5 08/14] i2c: octeon: Faster operation when IFLG signals late

2016-03-31 Thread Jan Glauber
From: Peter Swain 

Some versions can deliver low-level twsi irq before twsi_ctl.iflg
is set, leading to timeout-driven i/o.
When an irq signals event, but woken task does not see the expected
twsi_ctl.iflg, re-check about 80uS later.

EEPROM reads on 100kHz i2c now measure ~5.2kB/s, about 1/2 what's
achievable, and much better than the worst-case 100 bytes/sec before.

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 44ce9d4..cc1fe51 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -342,6 +342,28 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
return (octeon_i2c_read_ctl(i2c) & TWSI_CTL_IFLG) != 0;
 }
 
+#define I2C_OCTEON_IFLG_WAIT 80/* microseconds */
+
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(I2C_OCTEON_IFLG_WAIT, 2 * I2C_OCTEON_IFLG_WAIT);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
 /**
  * octeon_i2c_wait - wait for the IFLG to be set
  * @i2c: The struct octeon_i2c
@@ -351,9 +373,10 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
long time_left;
+   int first = 1;
 
i2c->int_en(i2c);
-   time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
+   time_left = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
   i2c->adap.timeout);
i2c->int_dis(i2c);
if (!time_left) {
-- 
1.9.1



[PATCH v5 14/14] i2c: thunderx: Add smbus alert support

2016-03-31 Thread Jan Glauber
Add smbus alert interrupt support.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-cavium.h|  6 ++
 drivers/i2c/busses/i2c-thunderx-core.c | 35 ++
 2 files changed, 41 insertions(+)

diff --git a/drivers/i2c/busses/i2c-cavium.h b/drivers/i2c/busses/i2c-cavium.h
index 31608c4..f934624 100644
--- a/drivers/i2c/busses/i2c-cavium.h
+++ b/drivers/i2c/busses/i2c-cavium.h
@@ -3,6 +3,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -118,6 +119,11 @@ struct octeon_i2c {
 #if IS_ENABLED(CONFIG_I2C_THUNDERX)
struct msix_entry i2c_msix;
 #endif
+
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   struct i2c_smbus_alert_setup alert_data;
+   struct i2c_client *ara;
+#endif
 };
 
 static inline void writeqflush(u64 val, void __iomem *addr)
diff --git a/drivers/i2c/busses/i2c-thunderx-core.c 
b/drivers/i2c/busses/i2c-thunderx-core.c
index 2ce985b..339378a 100644
--- a/drivers/i2c/busses/i2c-thunderx-core.c
+++ b/drivers/i2c/busses/i2c-thunderx-core.c
@@ -9,9 +9,11 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "i2c-cavium.h"
@@ -108,6 +110,35 @@ static void thunder_i2c_clock_disable(struct device *dev, 
struct clk *clk)
devm_clk_put(dev, clk);
 }
 
+static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
+  struct device_node *node)
+{
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   u32 type;
+
+   i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
+   if (!i2c->alert_data.irq)
+   return -EINVAL;
+
+   type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
+   i2c->alert_data.alert_edge_triggered =
+   (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
+
+   i2c->ara = i2c_setup_smbus_alert(>adap, >alert_data);
+   if (!i2c->ara)
+   return -ENODEV;
+#endif
+   return 0;
+}
+
+static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
+{
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   if (i2c->ara)
+   i2c_unregister_device(i2c->ara);
+#endif
+}
+
 static void thunder_i2c_set_name(struct pci_dev *pdev, struct octeon_i2c *i2c,
 char *name)
 {
@@ -207,6 +238,9 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
goto out_irq;
}
 
+   ret = thunder_i2c_smbus_setup(i2c, node);
+   if (ret < 0)
+   dev_err(dev, "Failed to setup smbus alert\n");
dev_info(i2c->dev, "probed\n");
return 0;
 
@@ -237,6 +271,7 @@ static void thunder_i2c_remove_pci(struct pci_dev *pdev)
 
dev = i2c->dev;
thunder_i2c_clock_disable(dev, i2c->clk);
+   thunder_i2c_smbus_remove(i2c);
i2c_del_adapter(>adap);
devm_free_irq(dev, i2c->i2c_msix.vector, i2c);
pci_disable_msix(pdev);
-- 
1.9.1



[PATCH v5 12/14] i2c: octeon: Split the driver into two parts

2016-03-31 Thread Jan Glauber
Move common functionality into a separate file in preparation of the
re-use from the ThunderX i2c driver.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Makefile  |   3 +-
 drivers/i2c/busses/i2c-cavium.c  | 822 +
 drivers/i2c/busses/i2c-cavium.h  | 195 +++
 drivers/i2c/busses/i2c-octeon-core.c | 983 +--
 4 files changed, 1020 insertions(+), 983 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3405286..282f781 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,8 @@ obj-$(CONFIG_I2C_UNIPHIER)+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
-obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon-core.o
+i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
+obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.c b/drivers/i2c/busses/i2c-cavium.c
new file mode 100644
index 000..9ad1f23
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cavium.c
@@ -0,0 +1,822 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+static int reset_how;
+
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+}
+
+#define I2C_OCTEON_IFLG_WAIT 80/* microseconds */
+
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(I2C_OCTEON_IFLG_WAIT, 2 * I2C_OCTEON_IFLG_WAIT);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+   long time_left;
+   int first = 1;
+
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_test_iflg(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+   }
+
+   i2c->int_en(i2c);
+   time_left = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
+  i2c->adap.timeout);
+   i2c->int_dis(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_test_iflg(i2c)) {
+   dev_err(i2c->dev,
+   "broken irq connection detected, switching to polling 
mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
+   if (!time_left) {
+   dev_dbg(i2c->dev, "%s: timeout\n", __func__);
+   return -ETIMEDOUT;
+   }
+
+   return 0;
+}
+
+/*
+ * Cleanup low-level state & enable high-level.
+ * Returns -EAGAIN if low-level state could not be cleaned.
+ */
+static int octeon_i2c_enable_hlc(struct octeon_i2c *i2c)
+{
+   int try = 0, ret = 0;
+   u64 val;
+
+   if (i2c->hlc_enabled)
+   return 0;
+   i2c->

[PATCH v5 10/14] i2c: octeon: Move read function before write

2016-03-31 Thread Jan Glauber
Just sorting the functions to be consistent with the other
read/write variants.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 94 -
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 9621b66..95cd301 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -928,53 +928,6 @@ static int octeon_i2c_start(struct octeon_i2c *i2c, int 
first)
 }
 
 /**
- * octeon_i2c_write - send data to the bus via low-level controller
- * @i2c: The struct octeon_i2c
- * @target: Target address
- * @data: Pointer to the data to be sent
- * @length: Length of the data
- * @last: is last msg in combined operation?
- *
- * The address is sent over the bus, then the data.
- *
- * Returns 0 on success, otherwise a negative errno.
- */
-static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
-   const u8 *data, int length, int first, int last)
-{
-   int i, result;
-
-   result = octeon_i2c_start(i2c, first);
-   if (result)
-   return result;
-
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
-
-   result = octeon_i2c_wait(i2c);
-   if (result)
-   return result;
-
-   for (i = 0; i < length; i++) {
-   result = check_arb(i2c, false);
-   if (result)
-   return result;
-
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
-   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
-
-   result = octeon_i2c_wait(i2c);
-   if (result)
-   return result;
-   result = check_arb(i2c, false);
-   if (result)
-   return result;
-   }
-
-   return 0;
-}
-
-/**
  * octeon_i2c_read - receive data from the bus via low-level controller
  * @i2c: The struct octeon_i2c
  * @target: Target address
@@ -1040,6 +993,53 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int 
target, u8 *data,
 }
 
 /**
+ * octeon_i2c_write - send data to the bus via low-level controller
+ * @i2c: The struct octeon_i2c
+ * @target: Target address
+ * @data: Pointer to the data to be sent
+ * @length: Length of the data
+ * @last: is last msg in combined operation?
+ *
+ * The address is sent over the bus, then the data.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
+   const u8 *data, int length, int first, int last)
+{
+   int i, result;
+
+   result = octeon_i2c_start(i2c, first);
+   if (result)
+   return result;
+
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+   result = octeon_i2c_wait(i2c);
+   if (result)
+   return result;
+
+   for (i = 0; i < length; i++) {
+   result = check_arb(i2c, false);
+   if (result)
+   return result;
+
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+   result = octeon_i2c_wait(i2c);
+   if (result)
+   return result;
+   result = check_arb(i2c, false);
+   if (result)
+   return result;
+   }
+
+   return 0;
+}
+
+/**
  * octeon_i2c_xfer - The driver's master_xfer function
  * @adap: Pointer to the i2c_adapter structure
  * @msgs: Pointer to the messages to be processed
-- 
1.9.1



[PATCH v5 09/14] i2c: octeon: Add workaround for broken irqs on CN3860

2016-03-31 Thread Jan Glauber
From: David Daney 

CN3860 does not interrupt the CPU when the i2c status changes. If
we get a timeout, and see the status has in fact changed, we know we
have this problem, and drop back to polling.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 55 +++--
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index cc1fe51..9621b66 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -119,6 +119,8 @@ struct octeon_i2c {
void __iomem *twsi_base;
struct device *dev;
bool hlc_enabled;
+   bool broken_irq_mode;
+   bool broken_irq_check;
void (*int_en)(struct octeon_i2c *);
void (*int_dis)(struct octeon_i2c *);
void (*hlc_int_en)(struct octeon_i2c *);
@@ -375,10 +377,33 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
long time_left;
int first = 1;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_test_iflg(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->int_en(i2c);
time_left = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
   i2c->adap.timeout);
i2c->int_dis(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_test_iflg(i2c)) {
+   dev_err(i2c->dev,
+   "broken irq connection detected, switching to polling 
mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -512,17 +537,40 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int time_left;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some cn38xx boards did not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_hlc_test_ready(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_hlc_test_ready(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->hlc_int_en(i2c);
time_left = wait_event_interruptible_timeout(i2c->queue,
octeon_i2c_hlc_test_ready(i2c),
i2c->adap.timeout);
i2c->hlc_int_dis(i2c);
-   if (!time_left) {
+   if (!time_left)
octeon_i2c_hlc_int_clear(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_hlc_test_ready(i2c)) {
+   dev_err(i2c->dev, "broken irq connection detected, switching to 
polling mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
+
+   if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
}
-
if (time_left < 0) {
dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
return time_left;
@@ -1154,6 +1202,9 @@ static int octeon_i2c_probe(struct platform_device *pdev)
goto out;
}
 
+   if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+   i2c->broken_irq_check = true;
+
result = octeon_i2c_init_lowlevel(i2c);
if (result) {
dev_err(i2c->dev, "init low level failed\n");
-- 
1.9.1



[PATCH v5 05/14] dt-bindings: i2c: Add Octeon cn78xx TWSI

2016-03-31 Thread Jan Glauber
Add compatible string for Cavium Octeon cn78XX SOCs TWSI.

Cc: Rob Herring 
Cc: Pawel Moll 
Cc: Mark Rutland 
Cc: Ian Campbell 
Cc: Kumar Gala 

Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 Documentation/devicetree/bindings/i2c/i2c-octeon.txt | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt 
b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
index dced82e..872d485 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
@@ -4,6 +4,12 @@
 
   Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
 
+  or
+
+  compatible: "cavium,octeon-7890-twsi"
+
+  Compatibility with cn78XX SOCs.
+
 - reg: The base address of the TWSI/I2C bus controller register bank.
 
 - #address-cells: Must be <1>.
-- 
1.9.1



[PATCH v5 06/14] i2c: octeon: Add support for cn78xx chips

2016-03-31 Thread Jan Glauber
From: David Daney 

cn78xx has a different interrupt architecture, so we have to manage
the interrupts differently.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 131 
 1 file changed, 120 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index bc0ed20..bd5915d 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -11,6 +11,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -112,11 +113,18 @@ struct octeon_i2c {
wait_queue_head_t queue;
struct i2c_adapter adap;
int irq;
+   int hlc_irq;/* For cn7890 only */
u32 twsi_freq;
int sys_freq;
void __iomem *twsi_base;
struct device *dev;
bool hlc_enabled;
+   void (*int_en)(struct octeon_i2c *);
+   void (*int_dis)(struct octeon_i2c *);
+   void (*hlc_int_en)(struct octeon_i2c *);
+   void (*hlc_int_dis)(struct octeon_i2c *);
+   atomic_t int_en_cnt;
+   atomic_t hlc_int_en_cnt;
 };
 
 static int reset_how;
@@ -214,6 +222,58 @@ static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
 }
 
 /**
+ * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
+{
+   atomic_inc_return(>int_en_cnt);
+   enable_irq(i2c->irq);
+}
+
+static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+{
+   int count;
+
+   /*
+* The interrupt can be disabled in two places, but we only
+* want to make the disable_irq_nosync() call once, so keep
+* track with the atomic variable.
+*/
+   count = atomic_dec_if_positive(cnt);
+   if (count >= 0)
+   disable_irq_nosync(irq);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+{
+   __octeon_i2c_irq_disable(>int_en_cnt, i2c->irq);
+}
+
+/**
+ * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+{
+   atomic_inc_return(>hlc_int_en_cnt);
+   enable_irq(i2c->hlc_irq);
+}
+
+/* disable the ST interrupt */
+static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+{
+   __octeon_i2c_irq_disable(>hlc_int_en_cnt, i2c->hlc_irq);
+}
+
+/**
  * octeon_i2c_unblock - unblock the bus
  * @i2c: The struct octeon_i2c
  *
@@ -250,7 +310,18 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 {
struct octeon_i2c *i2c = dev_id;
 
-   octeon_i2c_int_disable(i2c);
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+/* HLC interrupt service routine */
+static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->hlc_int_dis(i2c);
wake_up(>queue);
 
return IRQ_HANDLED;
@@ -276,10 +347,10 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
long time_left;
 
-   octeon_i2c_int_enable(i2c);
+   i2c->int_en(i2c);
time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
   i2c->adap.timeout);
-   octeon_i2c_int_disable(i2c);
+   i2c->int_dis(i2c);
if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -413,11 +484,11 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int time_left;
 
-   octeon_i2c_hlc_int_enable(i2c);
+   i2c->hlc_int_en(i2c);
time_left = wait_event_interruptible_timeout(i2c->queue,
octeon_i2c_hlc_test_ready(i2c),
i2c->adap.timeout);
-   octeon_i2c_int_disable(i2c);
+   i2c->hlc_int_dis(i2c);
if (!time_left) {
octeon_i2c_hlc_int_clear(i2c);
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
@@ -969,14 +1040,26 @@ static struct i2c_adapter octeon_i2c_ops = {
 static int octeon_i2c_probe(struct platform_device *pdev)
 {
struct device_node *node = pdev->dev.of_node;
+   int irq, result = 0, hlc_irq = 0;
struct resource *res_mem;
struct octeon_i2c *i2c;
-   int irq, result = 0;
-
-   /* All adaptors have an irq.  */
-   irq = platform_get_irq(pdev, 0);
-   if (irq < 0)
-   return irq;
+   bool cn78xx_style;
+
+   cn78xx_style = of_device_is_c

[PATCH v5 07/14] i2c: octeon: Flush TWSI writes with readback

2016-03-31 Thread Jan Glauber
From: Peter Swain 

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 19 ---
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index bd5915d..44ce9d4 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -129,6 +129,12 @@ struct octeon_i2c {
 
 static int reset_how;
 
+static void writeqflush(u64 val, void __iomem *addr)
+{
+   __raw_writeq(val, addr);
+   __raw_readq(addr);  /* wait for write to land */
+}
+
 /**
  * octeon_i2c_write_sw - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -189,8 +195,7 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 
eop_reg)
  */
 static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
 {
-   __raw_writeq(data, i2c->twsi_base + TWSI_INT);
-   __raw_readq(i2c->twsi_base + TWSI_INT);
+   writeqflush(data, i2c->twsi_base + TWSI_INT);
 }
 
 /**
@@ -576,10 +581,10 @@ static int octeon_i2c_simple_write(struct octeon_i2c 
*i2c, struct i2c_msg *msgs)
 
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
ext |= (u64) msgs[0].buf[j] << (8 * i);
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
}
 
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -625,7 +630,7 @@ static int octeon_i2c_ia_read(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
cmd |= (u64) msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -685,10 +690,10 @@ static int octeon_i2c_ia_write(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
set_ext = true;
}
if (set_ext)
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
-- 
1.9.1



[PATCH v5 01/14] i2c: octeon: Increase retry default and use fixed timeout value

2016-03-31 Thread Jan Glauber
Convert the adapter timeout to 2 ms independently of depending on CONFIG_HZ.
CONFIG_HZ is 100 for MIPS Cavium-Octeon so the timeout value is not changed.

Also set retries to 5 to improve robustness.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 46fb6c4..c4abf16 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -426,7 +426,6 @@ static struct i2c_adapter octeon_i2c_ops = {
.owner = THIS_MODULE,
.name = "OCTEON adapter",
.algo = _i2c_algo,
-   .timeout = HZ / 50,
 };
 
 /* calculate and set clock divisors */
@@ -553,6 +552,8 @@ static int octeon_i2c_probe(struct platform_device *pdev)
octeon_i2c_set_clock(i2c);
 
i2c->adap = octeon_i2c_ops;
+   i2c->adap.timeout = msecs_to_jiffies(2);
+   i2c->adap.retries = 5;
i2c->adap.dev.parent = >dev;
i2c->adap.dev.of_node = node;
i2c_set_adapdata(>adap, i2c);
-- 
1.9.1



[PATCH v5 02/14] i2c: octeon: Move set-clock and init-lowlevel upward

2016-03-31 Thread Jan Glauber
No functional change, just moving the functions upward in
preparation of improving the recovery.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 126 
 1 file changed, 63 insertions(+), 63 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index c4abf16..f647667 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -214,6 +214,69 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
return 0;
 }
 
+/* calculate and set clock divisors */
+static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
+{
+   int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+   int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 100;
+
+   for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+   /*
+* An mdiv value of less than 2 seems to not work well
+* with ds1337 RTCs, so we constrain it to larger values.
+*/
+   for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) 
{
+   /*
+* For given ndiv and mdiv values check the
+* two closest thp values.
+*/
+   tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+   tclk *= (1 << ndiv_idx);
+   thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+
+   for (inc = 0; inc <= 1; inc++) {
+   thp_idx = thp_base + inc;
+   if (thp_idx < 5 || thp_idx > 0xff)
+   continue;
+
+   foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+   foscl = foscl / (1 << ndiv_idx);
+   foscl = foscl / (mdiv_idx + 1) / 10;
+   diff = abs(foscl - i2c->twsi_freq);
+   if (diff < delta_hz) {
+   delta_hz = diff;
+   thp = thp_idx;
+   mdiv = mdiv_idx;
+   ndiv = ndiv_idx;
+   }
+   }
+   }
+   }
+   octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+}
+
+static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
+{
+   u8 status;
+   int tries;
+
+   /* disable high level controller, enable bus access */
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+   /* reset controller */
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+   for (tries = 10; tries; tries--) {
+   udelay(1);
+   status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+   if (status == STAT_IDLE)
+   return 0;
+   }
+   dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
+   return -EIO;
+}
+
 /**
  * octeon_i2c_start - send START to the bus
  * @i2c: The struct octeon_i2c
@@ -428,69 +491,6 @@ static struct i2c_adapter octeon_i2c_ops = {
.algo = _i2c_algo,
 };
 
-/* calculate and set clock divisors */
-static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
-{
-   int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
-   int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 100;
-
-   for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
-   /*
-* An mdiv value of less than 2 seems to not work well
-* with ds1337 RTCs, so we constrain it to larger values.
-*/
-   for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) 
{
-   /*
-* For given ndiv and mdiv values check the
-* two closest thp values.
-*/
-   tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
-   tclk *= (1 << ndiv_idx);
-   thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
-
-   for (inc = 0; inc <= 1; inc++) {
-   thp_idx = thp_base + inc;
-   if (thp_idx < 5 || thp_idx > 0xff)
-   continue;
-
-   foscl = i2c->sys_freq / (2 * (thp_idx + 1));
-   foscl = foscl / (1 << ndiv_idx);
-   foscl = foscl / (mdiv_idx + 1) / 10;
-   diff = abs(foscl - i2c->twsi_freq);
-   i

[PATCH v5 03/14] i2c: octeon: Improve error handling

2016-03-31 Thread Jan Glauber
From: Peter Swain 

Consider more status codes and improve error handling.
Distinguish handling for first and last part of a message.

TODO: Convert to use the i2c recovery framework.

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 244 +---
 1 file changed, 178 insertions(+), 66 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index f647667..a037245 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -56,12 +56,34 @@
 #define TWSI_CTL_AAK   0x04/* Assert ACK */
 
 /* Some status values */
+#define STAT_ERROR 0x00
 #define STAT_START 0x08
 #define STAT_RSTART0x10
 #define STAT_TXADDR_ACK0x18
+#define STAT_TXADDR_NAK0x20
 #define STAT_TXDATA_ACK0x28
+#define STAT_TXDATA_NAK0x30
+#define STAT_LOST_ARB_38   0x38
 #define STAT_RXADDR_ACK0x40
+#define STAT_RXADDR_NAK0x48
 #define STAT_RXDATA_ACK0x50
+#define STAT_RXDATA_NAK0x58
+#define STAT_SLAVE_60  0x60
+#define STAT_LOST_ARB_68   0x68
+#define STAT_SLAVE_70  0x70
+#define STAT_LOST_ARB_78   0x78
+#define STAT_SLAVE_80  0x80
+#define STAT_SLAVE_88  0x88
+#define STAT_GENDATA_ACK   0x90
+#define STAT_GENDATA_NAK   0x98
+#define STAT_SLAVE_A0  0xA0
+#define STAT_SLAVE_A8  0xA8
+#define STAT_LOST_ARB_B0   0xB0
+#define STAT_SLAVE_LOST0xB8
+#define STAT_SLAVE_NAK 0xC0
+#define STAT_SLAVE_ACK 0xC8
+#define STAT_AD2W_ACK  0xD0
+#define STAT_AD2W_NAK  0xD8
 #define STAT_IDLE  0xF8
 
 /* TWSI_INT values */
@@ -79,6 +101,8 @@ struct octeon_i2c {
struct device *dev;
 };
 
+static int reset_how;
+
 /**
  * octeon_i2c_write_sw - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -186,7 +210,6 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
-
 static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 {
return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) 
!= 0;
@@ -214,6 +237,66 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
return 0;
 }
 
+static int octeon_i2c_lost_arb(u8 code, int final_read)
+{
+   switch (code) {
+   /* Arbitration lost */
+   case STAT_LOST_ARB_38:
+   case STAT_LOST_ARB_68:
+   case STAT_LOST_ARB_78:
+   case STAT_LOST_ARB_B0:
+   return -EAGAIN;
+
+   /* Being addressed as slave, should back off & listen */
+   case STAT_SLAVE_60:
+   case STAT_SLAVE_70:
+   case STAT_GENDATA_ACK:
+   case STAT_GENDATA_NAK:
+   return -EIO;
+
+   /* Core busy as slave */
+   case STAT_SLAVE_80:
+   case STAT_SLAVE_88:
+   case STAT_SLAVE_A0:
+   case STAT_SLAVE_A8:
+   case STAT_SLAVE_LOST:
+   case STAT_SLAVE_NAK:
+   case STAT_SLAVE_ACK:
+   return -EIO;
+
+   /* ACK allowed on pre-terminal bytes only */
+   case STAT_RXDATA_ACK:
+   if (!final_read)
+   return 0;
+   return -EAGAIN;
+
+   /* NAK allowed on terminal byte only */
+   case STAT_RXDATA_NAK:
+   if (final_read)
+   return 0;
+   return -EAGAIN;
+   case STAT_TXDATA_NAK:
+   case STAT_TXADDR_NAK:
+   case STAT_RXADDR_NAK:
+   case STAT_AD2W_NAK:
+   return -EAGAIN;
+   }
+   return 0;
+}
+
+static int check_arb(struct octeon_i2c *i2c, int final_read)
+{
+   return octeon_i2c_lost_arb(octeon_i2c_read_sw(i2c,
+   SW_TWSI_EOP_TWSI_STAT), final_read);
+}
+
+/* send STOP to the bus */
+static void octeon_i2c_stop(struct octeon_i2c *i2c)
+{
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+   TWSI_CTL_ENAB | TWSI_CTL_STP);
+}
+
 /* calculate and set clock divisors */
 static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
 {
@@ -277,71 +360,103 @@ static int octeon_i2c_init_lowlevel(struct octeon_i2c 
*i2c)
return -EIO;
 }
 
+/*
+ * TWSI state seems stuck. Not sure if it's TWSI-engine state or something
+ * else on bus. The initial _stop() is always harmless, it just resets state
+ * machine, does not _transmit_ STOP unless engine was active.
+ */
+static int start_unstick(struct octeon_i2c *i2c)
+{
+   octeon_i2c_stop(i2c);
+
+   /*
+* Response is escalated over successive calls,
+* as EAGAIN provokes retries from i2c/core.
+*/
+   switch (reset_how++ % 4) {
+   case 0:
+   /* just the stop above */
+   break;
+   case 1:
+   /*
+* Controller refused to send start flag. May be a
+* client is holding SDA low? L

[PATCH v5 00/14] i2c-octeon and i2c-thunderx drivers

2016-03-31 Thread Jan Glauber
This series for the Octeon i2c driver is an attempt to upstream some
bug fixes and features that accumulated for some time.

On top of the Octeon changes a i2c driver for the ThunderX SOC is
added which uses the same functional block as the Octeon driver.

Patches #1-9 are forward-ports of Octeon features and bugfixes.
Patches #10-12 prepare for the driver split.
Patches #13-14 add the ThunderX driver.

Patches are on top of 4.6-rc1 and were tested on OCTEON, OCTEON-78
and ThunderX.

Changes to v4:
- Splitted the High-Level Controller patch into several patches
- Reworded some commit messages

Changes to v3:
- Added more functionality flags for SMBUS
- Removed both module parameters
- Make xfer return also other errors than EGAIN
- Return EPROTO on invalid SMBUS block length
- Use devm_ioremap_resource
- Added rename-only patch
- Removed kerneldoc patch from series
- Improved defines

Changes to v2:
- Split clenaup patch into several patches
- Strictly moved functional changes to later patches
- Fixed do-while checkpatch errors
- Moved defines to the patches that use them
- Use BIT_ULL macro
- Split ThunderX patch into 2 patches

Changes to v1:
- Fixed compile error on x86_64
- Disabled thunderx driver on MIPS
- Re-ordered some thunderx probe functions for readability
- Fix missing of_irq.h and i2c-smbus.h includes
- Use IS_ENABLED for CONFIG options

Jan

-


David Daney (3):
  i2c: octeon: Enable High-Level Controller
  i2c: octeon: Add support for cn78xx chips
  i2c: octeon: Add workaround for broken irqs on CN3860

Jan Glauber (8):
  i2c: octeon: Increase retry default and use fixed timeout value
  i2c: octeon: Move set-clock and init-lowlevel upward
  dt-bindings: i2c: Add Octeon cn78xx TWSI
  i2c: octeon: Move read function before write
  i2c: octeon: Rename driver to prepare for split
  i2c: octeon: Split the driver into two parts
  i2c: thunderx: Add i2c driver for ThunderX SOC
  i2c: thunderx: Add smbus alert support

Peter Swain (3):
  i2c: octeon: Improve error handling
  i2c: octeon: Flush TWSI writes with readback
  i2c: octeon: Faster operation when IFLG signals late

 .../devicetree/bindings/i2c/i2c-octeon.txt |   6 +
 drivers/i2c/busses/Kconfig |  10 +
 drivers/i2c/busses/Makefile|   3 +
 drivers/i2c/busses/i2c-cavium.c| 822 +
 drivers/i2c/busses/i2c-cavium.h| 212 ++
 drivers/i2c/busses/i2c-octeon-core.c   | 283 +++
 drivers/i2c/busses/i2c-octeon.c| 600 ---
 drivers/i2c/busses/i2c-thunderx-core.c | 303 
 8 files changed, 1639 insertions(+), 600 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

-- 
1.9.1



[PATCH 4/6] spi: octeon: Move include file from arch/mips to drivers/spi

2016-07-23 Thread Jan Glauber
Move the register definitions to the drivers directory because they
are only used there.

Signed-off-by: Jan Glauber 
Tested-by: Steven J. Hill 
---
 .../cvmx-mpi-defs.h => drivers/spi/spi-cavium.h| 32 +-
 drivers/spi/spi-octeon.c   |  3 +-
 2 files changed, 3 insertions(+), 32 deletions(-)
 rename arch/mips/include/asm/octeon/cvmx-mpi-defs.h => 
drivers/spi/spi-cavium.h (84%)

diff --git a/arch/mips/include/asm/octeon/cvmx-mpi-defs.h 
b/drivers/spi/spi-cavium.h
similarity index 84%
rename from arch/mips/include/asm/octeon/cvmx-mpi-defs.h
rename to drivers/spi/spi-cavium.h
index 4615b10..d41dba5 100644
--- a/arch/mips/include/asm/octeon/cvmx-mpi-defs.h
+++ b/drivers/spi/spi-cavium.h
@@ -1,32 +1,4 @@
-/***license start***
- * Author: Cavium Networks
- *
- * Contact: supp...@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2012 Cavium Networks
- *
- * This file 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 file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***license end**/
-
-#ifndef __CVMX_MPI_DEFS_H__
-#define __CVMX_MPI_DEFS_H__
+/* MPI register descriptions */
 
 #define CVMX_MPI_CFG (CVMX_ADD_IO_SEG(0x000107001000ull))
 #define CVMX_MPI_DATX(offset) (CVMX_ADD_IO_SEG(0x000107001080ull) + 
((offset) & 15) * 8)
@@ -324,5 +296,3 @@ union cvmx_mpi_tx {
struct cvmx_mpi_tx_s cn66xx;
struct cvmx_mpi_tx_cn61xx cnf71xx;
 };
-
-#endif
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 209eddc..2180176 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -15,7 +15,8 @@
 #include 
 
 #include 
-#include 
+
+#include "spi-cavium.h"
 
 #define OCTEON_SPI_MAX_BYTES 9
 
-- 
2.9.0.rc0.21.g322



[PATCH 0/6] SPI ThunderX driver

2016-07-23 Thread Jan Glauber
Hi Mark,

This series adds support for SPI on Cavium's ThunderX (arm64). The SPI
hardware is the same as on MIPS Octeon, the only difference is that the
device appears as a PCI device. To avoid copy and paste of the Octeon
driver I've moved the common parts into a shared file.

Patches #1-5 prepare the Octeon driver for re-use.

Patch #6 adds the ThunderX driver.

The series was tested on MIPS (Edge Router PRO and cn71xx) and ThunderX.

Feedback welcome!

thanks,
Jan

Jan Glauber (5):
  spi: octeon: Store system clock freqency in struct octeon_spi
  spi: octeon: Put register offsets into a struct
  spi: octeon: Move include file from arch/mips to drivers/spi
  spi: octeon: Split driver into Octeon specific and common parts
  spi: octeon: Add thunderx driver

Steven J. Hill (1):
  spi: octeon: Convert driver to use readq()/writeq() functions

 drivers/spi/Kconfig|   7 +
 drivers/spi/Makefile   |   3 +
 drivers/spi/spi-cavium-octeon.c| 104 +
 drivers/spi/spi-cavium-thunderx.c  | 158 +
 drivers/spi/spi-cavium.c   | 151 
 .../cvmx-mpi-defs.h => drivers/spi/spi-cavium.h|  62 ++---
 drivers/spi/spi-octeon.c   | 255 -
 7 files changed, 456 insertions(+), 284 deletions(-)
 create mode 100644 drivers/spi/spi-cavium-octeon.c
 create mode 100644 drivers/spi/spi-cavium-thunderx.c
 create mode 100644 drivers/spi/spi-cavium.c
 rename arch/mips/include/asm/octeon/cvmx-mpi-defs.h => 
drivers/spi/spi-cavium.h (84%)
 delete mode 100644 drivers/spi/spi-octeon.c

-- 
2.9.0.rc0.21.g322



[PATCH 3/6] spi: octeon: Put register offsets into a struct

2016-07-23 Thread Jan Glauber
Instead of hard-coding the register offsets put them into a struct
and set them in the probe function.

Signed-off-by: Jan Glauber 
Tested-by: Steven J. Hill 
---
 drivers/spi/spi-octeon.c | 41 +++--
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index e722040..209eddc 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -17,22 +17,30 @@
 #include 
 #include 
 
-#define OCTEON_SPI_CFG 0
-#define OCTEON_SPI_STS 0x08
-#define OCTEON_SPI_TX 0x10
-#define OCTEON_SPI_DAT0 0x80
-
 #define OCTEON_SPI_MAX_BYTES 9
 
 #define OCTEON_SPI_MAX_CLOCK_HZ 1600
 
+struct octeon_spi_regs {
+   int config;
+   int status;
+   int tx;
+   int data;
+};
+
 struct octeon_spi {
void __iomem *register_base;
u64 last_cfg;
u64 cs_enax;
int sys_freq;
+   struct octeon_spi_regs regs;
 };
 
+#define OCTEON_SPI_CFG(x)  (x->regs.config)
+#define OCTEON_SPI_STS(x)  (x->regs.status)
+#define OCTEON_SPI_TX(x)   (x->regs.tx)
+#define OCTEON_SPI_DAT0(x) (x->regs.data)
+
 static void octeon_spi_wait_ready(struct octeon_spi *p)
 {
union cvmx_mpi_sts mpi_sts;
@@ -41,7 +49,7 @@ static void octeon_spi_wait_ready(struct octeon_spi *p)
do {
if (loops++)
__delay(500);
-   mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS);
+   mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS(p));
} while (mpi_sts.s.busy);
 }
 
@@ -83,7 +91,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
 
if (mpi_cfg.u64 != p->last_cfg) {
p->last_cfg = mpi_cfg.u64;
-   writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG);
+   writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG(p));
}
tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf;
@@ -95,19 +103,19 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
d = *tx_buf++;
else
d = 0;
-   writeq(d, p->register_base + OCTEON_SPI_DAT0 + (8 * i));
+   writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * 
i));
}
mpi_tx.u64 = 0;
mpi_tx.s.csid = spi->chip_select;
mpi_tx.s.leavecs = 1;
mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
-   writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX);
+   writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
 
octeon_spi_wait_ready(p);
if (rx_buf)
for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
-   u64 v = readq(p->register_base + 
OCTEON_SPI_DAT0 + (8 * i));
+   u64 v = readq(p->register_base + 
OCTEON_SPI_DAT0(p) + (8 * i));
*rx_buf++ = (u8)v;
}
len -= OCTEON_SPI_MAX_BYTES;
@@ -119,7 +127,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
d = *tx_buf++;
else
d = 0;
-   writeq(d, p->register_base + OCTEON_SPI_DAT0 + (8 * i));
+   writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
}
 
mpi_tx.u64 = 0;
@@ -130,12 +138,12 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mpi_tx.s.leavecs = !xfer->cs_change;
mpi_tx.s.txnum = tx_buf ? len : 0;
mpi_tx.s.totnum = len;
-   writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX);
+   writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
 
octeon_spi_wait_ready(p);
if (rx_buf)
for (i = 0; i < len; i++) {
-   u64 v = readq(p->register_base + OCTEON_SPI_DAT0 + (8 * 
i));
+   u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + 
(8 * i));
*rx_buf++ = (u8)v;
}
 
@@ -194,6 +202,11 @@ static int octeon_spi_probe(struct platform_device *pdev)
p->register_base = reg_base;
p->sys_freq = octeon_get_io_clock_rate();
 
+   p->regs.config = 0;
+   p->regs.status = 0x08;
+   p->regs.tx = 0x10;
+   p->regs.data = 0x80;
+
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
SPI_CPOL |
@@ -226,7 +239,7 @@ static int octeon_spi_remove(struct platform_device *pdev)
struct octeon_spi *p = spi_master_get_devdata(master);
 
/* Clear the CSENA* and put everything in a known state. */
-   writeq(0, p->register_base + OCTEON_SPI_CFG);
+   writeq(0, p->register_base + OCTEON_SPI_CFG(p));
 
return 0;
 }
-- 
2.9.0.rc0.21.g322



[PATCH 6/6] spi: octeon: Add thunderx driver

2016-07-23 Thread Jan Glauber
Add ThunderX SPI driver using the shared part from the Octeon
driver. The main difference of the ThunderX driver is that it
is a PCI device so probing is different. The system clock settings
can be specified in device tree.

Signed-off-by: Jan Glauber 
---
 drivers/spi/Kconfig   |   7 ++
 drivers/spi/Makefile  |   2 +
 drivers/spi/spi-cavium-thunderx.c | 158 ++
 drivers/spi/spi-cavium.h  |   3 +
 4 files changed, 170 insertions(+)
 create mode 100644 drivers/spi/spi-cavium-thunderx.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b931ec..db02ba7 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -630,6 +630,13 @@ config SPI_TEGRA20_SLINK
help
  SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
 
+config SPI_THUNDERX
+   tristate "Cavium ThunderX SPI controller"
+   depends on 64BIT && PCI && !CAVIUM_OCTEON_SOC
+   help
+ SPI host driver for the hardware found on Cavium ThunderX
+ SOCs.
+
 config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 185367e..133364b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -91,6 +91,8 @@ obj-$(CONFIG_SPI_TEGRA114)+= spi-tegra114.o
 obj-$(CONFIG_SPI_TEGRA20_SFLASH)   += spi-tegra20-sflash.o
 obj-$(CONFIG_SPI_TEGRA20_SLINK)+= spi-tegra20-slink.o
 obj-$(CONFIG_SPI_TLE62X0)  += spi-tle62x0.o
+spi-thunderx-objs  := spi-cavium.o spi-cavium-thunderx.o
+obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
 obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
 obj-$(CONFIG_SPI_XCOMM)+= spi-xcomm.o
diff --git a/drivers/spi/spi-cavium-thunderx.c 
b/drivers/spi/spi-cavium-thunderx.c
new file mode 100644
index 000..7eb9141
--- /dev/null
+++ b/drivers/spi/spi-cavium-thunderx.c
@@ -0,0 +1,158 @@
+/*
+ * Cavium ThunderX SPI driver.
+ *
+ * Copyright (C) 2016 Cavium Inc.
+ * Authors: Jan Glauber 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "spi-cavium.h"
+
+#define DRV_NAME "spi-thunderx"
+
+#define SYS_FREQ_DEFAULT   7
+
+static void thunderx_spi_clock_enable(struct device *dev, struct octeon_spi *p)
+{
+   int ret;
+
+   p->clk = devm_clk_get(dev, NULL);
+   if (IS_ERR(p->clk)) {
+   p->clk = NULL;
+   goto skip;
+   }
+
+   ret = clk_prepare_enable(p->clk);
+   if (ret)
+   goto skip;
+   p->sys_freq = clk_get_rate(p->clk);
+
+skip:
+   if (!p->sys_freq)
+   p->sys_freq = SYS_FREQ_DEFAULT;
+
+   dev_info(dev, "Set system clock to %u\n", p->sys_freq);
+}
+
+static void thunderx_spi_clock_disable(struct device *dev, struct clk *clk)
+{
+   if (!clk)
+   return;
+   clk_disable_unprepare(clk);
+   devm_clk_put(dev, clk);
+}
+
+static int thunderx_spi_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+   struct device *dev = >dev;
+   struct spi_master *master;
+   struct octeon_spi *p;
+   int ret = -ENOENT;
+
+   master = spi_alloc_master(dev, sizeof(struct octeon_spi));
+   if (!master)
+   return -ENOMEM;
+   p = spi_master_get_devdata(master);
+
+   ret = pci_enable_device(pdev);
+   if (ret) {
+   dev_err(dev, "Failed to enable PCI device\n");
+   goto out_free;
+   }
+
+   ret = pci_request_regions(pdev, DRV_NAME);
+   if (ret) {
+   dev_err(dev, "PCI request regions failed 0x%x\n", ret);
+   goto out_disable;
+   }
+
+   p->register_base = pci_ioremap_bar(pdev, 0);
+   if (!p->register_base) {
+   dev_err(dev, "Cannot map reg base\n");
+   ret = -EINVAL;
+   goto out_region;
+   }
+
+   p->regs.config = 0x1000;
+   p->regs.status = 0x1008;
+   p->regs.tx = 0x1010;
+   p->regs.data = 0x1080;
+
+   thunderx_spi_clock_enable(dev, p);
+
+   master->num_chipselect = 4;
+   master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
+   SPI_LSB_FIRST | SPI_3WIRE;
+   master->transfer_one_message = octeon_spi_transfer_one_message;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+   master->dev.of_node = pdev->dev.of_node;
+
+   pci_set_drvdata(pdev, master);
+   ret = devm_spi_register_master(dev, master);
+   if (ret) {
+   dev_err(>

[PATCH 2/6] spi: octeon: Store system clock freqency in struct octeon_spi

2016-07-23 Thread Jan Glauber
Storing the system clock frequency in struct octeon_spi avoids
calling the MIPS specific octeon_get_io_clock_rate() for every transfer.

Signed-off-by: Jan Glauber 
Tested-by: Steven J. Hill 
---
 drivers/spi/spi-octeon.c | 7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index b53ba53..e722040 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -30,6 +30,7 @@ struct octeon_spi {
void __iomem *register_base;
u64 last_cfg;
u64 cs_enax;
+   int sys_freq;
 };
 
 static void octeon_spi_wait_ready(struct octeon_spi *p)
@@ -53,7 +54,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
union cvmx_mpi_cfg mpi_cfg;
union cvmx_mpi_tx mpi_tx;
unsigned int clkdiv;
-   unsigned int speed_hz;
int mode;
bool cpha, cpol;
const u8 *tx_buf;
@@ -65,9 +65,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
cpha = mode & SPI_CPHA;
cpol = mode & SPI_CPOL;
 
-   speed_hz = xfer->speed_hz;
-
-   clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
+   clkdiv = p->sys_freq / (2 * xfer->speed_hz);
 
mpi_cfg.u64 = 0;
 
@@ -194,6 +192,7 @@ static int octeon_spi_probe(struct platform_device *pdev)
}
 
p->register_base = reg_base;
+   p->sys_freq = octeon_get_io_clock_rate();
 
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
-- 
2.9.0.rc0.21.g322



[PATCH 1/6] spi: octeon: Convert driver to use readq()/writeq() functions

2016-07-23 Thread Jan Glauber
From: "Steven J. Hill" 

Remove all calls to cvmx_read_csr()/cvmx_write_csr() and use
the portable readq()/writeq() functions.

Signed-off-by: Steven J. Hill 
Signed-off-by: Jan Glauber 
---
 drivers/spi/spi-octeon.c | 23 +++
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 3b17009..b53ba53 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -27,7 +27,7 @@
 #define OCTEON_SPI_MAX_CLOCK_HZ 1600
 
 struct octeon_spi {
-   u64 register_base;
+   void __iomem *register_base;
u64 last_cfg;
u64 cs_enax;
 };
@@ -40,7 +40,7 @@ static void octeon_spi_wait_ready(struct octeon_spi *p)
do {
if (loops++)
__delay(500);
-   mpi_sts.u64 = cvmx_read_csr(p->register_base + OCTEON_SPI_STS);
+   mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS);
} while (mpi_sts.s.busy);
 }
 
@@ -85,7 +85,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
 
if (mpi_cfg.u64 != p->last_cfg) {
p->last_cfg = mpi_cfg.u64;
-   cvmx_write_csr(p->register_base + OCTEON_SPI_CFG, mpi_cfg.u64);
+   writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG);
}
tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf;
@@ -97,19 +97,19 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
d = *tx_buf++;
else
d = 0;
-   cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 
* i), d);
+   writeq(d, p->register_base + OCTEON_SPI_DAT0 + (8 * i));
}
mpi_tx.u64 = 0;
mpi_tx.s.csid = spi->chip_select;
mpi_tx.s.leavecs = 1;
mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
-   cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64);
+   writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX);
 
octeon_spi_wait_ready(p);
if (rx_buf)
for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
-   u64 v = cvmx_read_csr(p->register_base + 
OCTEON_SPI_DAT0 + (8 * i));
+   u64 v = readq(p->register_base + 
OCTEON_SPI_DAT0 + (8 * i));
*rx_buf++ = (u8)v;
}
len -= OCTEON_SPI_MAX_BYTES;
@@ -121,7 +121,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
d = *tx_buf++;
else
d = 0;
-   cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
+   writeq(d, p->register_base + OCTEON_SPI_DAT0 + (8 * i));
}
 
mpi_tx.u64 = 0;
@@ -132,12 +132,12 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mpi_tx.s.leavecs = !xfer->cs_change;
mpi_tx.s.txnum = tx_buf ? len : 0;
mpi_tx.s.totnum = len;
-   cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64);
+   writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX);
 
octeon_spi_wait_ready(p);
if (rx_buf)
for (i = 0; i < len; i++) {
-   u64 v = cvmx_read_csr(p->register_base + 
OCTEON_SPI_DAT0 + (8 * i));
+   u64 v = readq(p->register_base + OCTEON_SPI_DAT0 + (8 * 
i));
*rx_buf++ = (u8)v;
}
 
@@ -193,7 +193,7 @@ static int octeon_spi_probe(struct platform_device *pdev)
goto fail;
}
 
-   p->register_base = (u64)reg_base;
+   p->register_base = reg_base;
 
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
@@ -225,10 +225,9 @@ static int octeon_spi_remove(struct platform_device *pdev)
 {
struct spi_master *master = platform_get_drvdata(pdev);
struct octeon_spi *p = spi_master_get_devdata(master);
-   u64 register_base = p->register_base;
 
/* Clear the CSENA* and put everything in a known state. */
-   cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0);
+   writeq(0, p->register_base + OCTEON_SPI_CFG);
 
return 0;
 }
-- 
2.9.0.rc0.21.g322



[PATCH 5/6] spi: octeon: Split driver into Octeon specific and common parts

2016-07-23 Thread Jan Glauber
Separate driver probing from SPI transfer functions.

Signed-off-by: Jan Glauber 
Tested-by: Steven J. Hill 
---
 drivers/spi/Makefile   |   1 +
 drivers/spi/spi-cavium-octeon.c| 104 +
 drivers/spi/{spi-octeon.c => spi-cavium.c} | 120 +
 drivers/spi/spi-cavium.h   |  31 
 4 files changed, 138 insertions(+), 118 deletions(-)
 create mode 100644 drivers/spi/spi-cavium-octeon.c
 rename drivers/spi/{spi-octeon.c => spi-cavium.c} (55%)

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3c74d00..185367e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_MT65XX)+= spi-mt65xx.o
 obj-$(CONFIG_SPI_MXS)  += spi-mxs.o
 obj-$(CONFIG_SPI_NUC900)   += spi-nuc900.o
 obj-$(CONFIG_SPI_OC_TINY)  += spi-oc-tiny.o
+spi-octeon-objs:= spi-cavium.o 
spi-cavium-octeon.o
 obj-$(CONFIG_SPI_OCTEON)   += spi-octeon.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)   += spi-omap-uwire.o
 obj-$(CONFIG_SPI_OMAP_100K)+= spi-omap-100k.o
diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c
new file mode 100644
index 000..ee4703e
--- /dev/null
+++ b/drivers/spi/spi-cavium-octeon.c
@@ -0,0 +1,104 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011, 2012 Cavium, Inc.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "spi-cavium.h"
+
+static int octeon_spi_probe(struct platform_device *pdev)
+{
+   struct resource *res_mem;
+   void __iomem *reg_base;
+   struct spi_master *master;
+   struct octeon_spi *p;
+   int err = -ENOENT;
+
+   master = spi_alloc_master(>dev, sizeof(struct octeon_spi));
+   if (!master)
+   return -ENOMEM;
+   p = spi_master_get_devdata(master);
+   platform_set_drvdata(pdev, master);
+
+   res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   reg_base = devm_ioremap_resource(>dev, res_mem);
+   if (IS_ERR(reg_base)) {
+   err = PTR_ERR(reg_base);
+   goto fail;
+   }
+
+   p->register_base = reg_base;
+   p->sys_freq = octeon_get_io_clock_rate();
+
+   p->regs.config = 0;
+   p->regs.status = 0x08;
+   p->regs.tx = 0x10;
+   p->regs.data = 0x80;
+
+   master->num_chipselect = 4;
+   master->mode_bits = SPI_CPHA |
+   SPI_CPOL |
+   SPI_CS_HIGH |
+   SPI_LSB_FIRST |
+   SPI_3WIRE;
+
+   master->transfer_one_message = octeon_spi_transfer_one_message;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+
+   master->dev.of_node = pdev->dev.of_node;
+   err = devm_spi_register_master(>dev, master);
+   if (err) {
+   dev_err(>dev, "register master failed: %d\n", err);
+   goto fail;
+   }
+
+   dev_info(>dev, "OCTEON SPI bus driver\n");
+
+   return 0;
+fail:
+   spi_master_put(master);
+   return err;
+}
+
+static int octeon_spi_remove(struct platform_device *pdev)
+{
+   struct spi_master *master = platform_get_drvdata(pdev);
+   struct octeon_spi *p = spi_master_get_devdata(master);
+
+   /* Clear the CSENA* and put everything in a known state. */
+   writeq(0, p->register_base + OCTEON_SPI_CFG(p));
+
+   return 0;
+}
+
+static const struct of_device_id octeon_spi_match[] = {
+   { .compatible = "cavium,octeon-3010-spi", },
+   {},
+};
+MODULE_DEVICE_TABLE(of, octeon_spi_match);
+
+static struct platform_driver octeon_spi_driver = {
+   .driver = {
+   .name   = "spi-octeon",
+   .of_match_table = octeon_spi_match,
+   },
+   .probe  = octeon_spi_probe,
+   .remove = octeon_spi_remove,
+};
+
+module_platform_driver(octeon_spi_driver);
+
+MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-cavium.c
similarity index 55%
rename from drivers/spi/spi-octeon.c
rename to drivers/spi/spi-cavium.c
index 2180176..5aaf215 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-cavium.c
@@ -6,42 +6,13 @@
  * Copyright (C) 2011, 2012 Cavium, Inc.
  */
 
-#include 
-#include 
 #include 
 #include 
 #include 
 #include 
-#include 
-
-#include 
 
 #include "spi-cavium.h"
 
-#define OCTEON_SPI_MAX_BYTES 9
-
-#define OCTEON_SPI_MAX_CLOC

Re: [PATCH v2] spi: octeon: Add thunderx driver

2016-07-28 Thread Jan Glauber
On Wed, Jul 27, 2016 at 07:08:24PM +0100, Mark Brown wrote:
> On Mon, Jul 25, 2016 at 07:56:22PM +0200, Jan Glauber wrote:
> > Add ThunderX SPI driver using the shared part from the Octeon
> > driver. The main difference of the ThunderX driver is that it
> > is a PCI device so probing is different. The system clock settings
> > can be specified in device tree.
> 
> Don't send individual patches in reply to the middle of threads, it
> makes it really confusing what's going on.  I now have multiple patches
> from you for this driver completely unthreaded in my inbox with no
> indication of ordering or anything.  Please resend anything that's
> pending as a proper patch series.

With multiple being exactly two. I thought it to be easier this way
around and the ordering to be obvious (if you use threading),
but of course I can resend the two patches as a new series.


[PATCH v2 0/2] SPI ThunderX driver

2016-07-28 Thread Jan Glauber
This series adds support for SPI on Cavium's ThunderX (arm64). The SPI
hardware is the same as on MIPS Octeon, the only difference is that the
device appears as a PCI device. To avoid copy and paste of the Octeon
driver I've moved the common parts into a shared file.

The series was tested on MIPS (Edge Router PRO and cn71xx) and ThunderX.

Changes to v1:
- Changed Kconfig depencency for ThunderX
- Merged clock setup functions with main probe/remove
- Fail if SPI DT entry misses clock reference
- Removed debug prints at end of probe
- Removed unneeded includes from spi-cavium.c
- Dropped merged patches

thanks,
Jan

--

Jan Glauber (2):
  spi: octeon: Split driver into Octeon specific and common parts
  spi: octeon: Add thunderx driver

 drivers/spi/Kconfig|   7 ++
 drivers/spi/Makefile   |   3 +
 drivers/spi/spi-cavium-octeon.c| 102 +
 drivers/spi/spi-cavium-thunderx.c  | 140 +
 drivers/spi/{spi-octeon.c => spi-cavium.c} | 122 +
 drivers/spi/spi-cavium.h   |  34 +++
 6 files changed, 288 insertions(+), 120 deletions(-)
 create mode 100644 drivers/spi/spi-cavium-octeon.c
 create mode 100644 drivers/spi/spi-cavium-thunderx.c
 rename drivers/spi/{spi-octeon.c => spi-cavium.c} (54%)

-- 
2.9.0.rc0.21.g322



[PATCH v2 2/2] spi: octeon: Add thunderx driver

2016-07-28 Thread Jan Glauber
Add ThunderX SPI driver using the shared part from the Octeon
driver. The main difference of the ThunderX driver is that it
is a PCI device so probing is different. The system clock settings
can be specified in device tree.

Signed-off-by: Jan Glauber 
---
 drivers/spi/Kconfig   |   7 ++
 drivers/spi/Makefile  |   2 +
 drivers/spi/spi-cavium-thunderx.c | 140 ++
 drivers/spi/spi-cavium.h  |   3 +
 4 files changed, 152 insertions(+)
 create mode 100644 drivers/spi/spi-cavium-thunderx.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b931ec..e0ee112 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -630,6 +630,13 @@ config SPI_TEGRA20_SLINK
help
  SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
 
+config SPI_THUNDERX
+   tristate "Cavium ThunderX SPI controller"
+   depends on (ARM64 || CONFIG_TEST) && 64BIT && PCI
+   help
+ SPI host driver for the hardware found on Cavium ThunderX
+ SOCs.
+
 config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 185367e..133364b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -91,6 +91,8 @@ obj-$(CONFIG_SPI_TEGRA114)+= spi-tegra114.o
 obj-$(CONFIG_SPI_TEGRA20_SFLASH)   += spi-tegra20-sflash.o
 obj-$(CONFIG_SPI_TEGRA20_SLINK)+= spi-tegra20-slink.o
 obj-$(CONFIG_SPI_TLE62X0)  += spi-tle62x0.o
+spi-thunderx-objs  := spi-cavium.o spi-cavium-thunderx.o
+obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
 obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
 obj-$(CONFIG_SPI_XCOMM)+= spi-xcomm.o
diff --git a/drivers/spi/spi-cavium-thunderx.c 
b/drivers/spi/spi-cavium-thunderx.c
new file mode 100644
index 000..28c3dcc
--- /dev/null
+++ b/drivers/spi/spi-cavium-thunderx.c
@@ -0,0 +1,140 @@
+/*
+ * Cavium ThunderX SPI driver.
+ *
+ * Copyright (C) 2016 Cavium Inc.
+ * Authors: Jan Glauber 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "spi-cavium.h"
+
+#define DRV_NAME "spi-thunderx"
+
+#define SYS_FREQ_DEFAULT 7 /* 700 Mhz */
+
+static int thunderx_spi_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+   struct device *dev = >dev;
+   struct spi_master *master;
+   struct octeon_spi *p;
+   int ret = -ENOENT;
+
+   master = spi_alloc_master(dev, sizeof(struct octeon_spi));
+   if (!master)
+   return -ENOMEM;
+   p = spi_master_get_devdata(master);
+
+   ret = pci_enable_device(pdev);
+   if (ret) {
+   dev_err(dev, "Failed to enable PCI device\n");
+   goto out_free;
+   }
+
+   ret = pci_request_regions(pdev, DRV_NAME);
+   if (ret) {
+   dev_err(dev, "PCI request regions failed 0x%x\n", ret);
+   goto out_disable;
+   }
+
+   p->register_base = pci_ioremap_bar(pdev, 0);
+   if (!p->register_base) {
+   dev_err(dev, "Cannot map reg base\n");
+   ret = -EINVAL;
+   goto out_region;
+   }
+
+   p->regs.config = 0x1000;
+   p->regs.status = 0x1008;
+   p->regs.tx = 0x1010;
+   p->regs.data = 0x1080;
+
+   p->clk = devm_clk_get(dev, NULL);
+   if (IS_ERR(p->clk))
+   goto out_unmap;
+
+   ret = clk_prepare_enable(p->clk);
+   if (ret)
+   goto out_clock_devm;
+
+   p->sys_freq = clk_get_rate(p->clk);
+   if (!p->sys_freq)
+   p->sys_freq = SYS_FREQ_DEFAULT;
+   dev_info(dev, "Set system clock to %u\n", p->sys_freq);
+
+   master->num_chipselect = 4;
+   master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
+   SPI_LSB_FIRST | SPI_3WIRE;
+   master->transfer_one_message = octeon_spi_transfer_one_message;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+   master->dev.of_node = pdev->dev.of_node;
+
+   pci_set_drvdata(pdev, master);
+   ret = devm_spi_register_master(dev, master);
+   if (ret) {
+   dev_err(>dev, "Register master failed: %d\n", ret);
+   goto out_clock;
+   }
+
+   return 0;
+
+out_clock:
+   clk_disable_unprepare(p->clk);
+out_clock_devm:
+   devm_clk_put(dev, p->clk);
+out_unmap:
+   iounmap(p->register_base);
+out_region:
+   pci_release_regions(pdev);
+out_disable:
+   pci_disable_device(pdev);
+out_fr

[PATCH v2 1/2] spi: octeon: Split driver into Octeon specific and common parts

2016-07-28 Thread Jan Glauber
Separate driver probing from SPI transfer functions.

Signed-off-by: Jan Glauber 
---
 drivers/spi/Makefile   |   1 +
 drivers/spi/spi-cavium-octeon.c| 102 
 drivers/spi/{spi-octeon.c => spi-cavium.c} | 122 +
 drivers/spi/spi-cavium.h   |  31 
 4 files changed, 136 insertions(+), 120 deletions(-)
 create mode 100644 drivers/spi/spi-cavium-octeon.c
 rename drivers/spi/{spi-octeon.c => spi-cavium.c} (54%)

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3c74d00..185367e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_MT65XX)+= spi-mt65xx.o
 obj-$(CONFIG_SPI_MXS)  += spi-mxs.o
 obj-$(CONFIG_SPI_NUC900)   += spi-nuc900.o
 obj-$(CONFIG_SPI_OC_TINY)  += spi-oc-tiny.o
+spi-octeon-objs:= spi-cavium.o 
spi-cavium-octeon.o
 obj-$(CONFIG_SPI_OCTEON)   += spi-octeon.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)   += spi-omap-uwire.o
 obj-$(CONFIG_SPI_OMAP_100K)+= spi-omap-100k.o
diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c
new file mode 100644
index 000..97310c1
--- /dev/null
+++ b/drivers/spi/spi-cavium-octeon.c
@@ -0,0 +1,102 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011, 2012 Cavium, Inc.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "spi-cavium.h"
+
+static int octeon_spi_probe(struct platform_device *pdev)
+{
+   struct resource *res_mem;
+   void __iomem *reg_base;
+   struct spi_master *master;
+   struct octeon_spi *p;
+   int err = -ENOENT;
+
+   master = spi_alloc_master(>dev, sizeof(struct octeon_spi));
+   if (!master)
+   return -ENOMEM;
+   p = spi_master_get_devdata(master);
+   platform_set_drvdata(pdev, master);
+
+   res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   reg_base = devm_ioremap_resource(>dev, res_mem);
+   if (IS_ERR(reg_base)) {
+   err = PTR_ERR(reg_base);
+   goto fail;
+   }
+
+   p->register_base = reg_base;
+   p->sys_freq = octeon_get_io_clock_rate();
+
+   p->regs.config = 0;
+   p->regs.status = 0x08;
+   p->regs.tx = 0x10;
+   p->regs.data = 0x80;
+
+   master->num_chipselect = 4;
+   master->mode_bits = SPI_CPHA |
+   SPI_CPOL |
+   SPI_CS_HIGH |
+   SPI_LSB_FIRST |
+   SPI_3WIRE;
+
+   master->transfer_one_message = octeon_spi_transfer_one_message;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+
+   master->dev.of_node = pdev->dev.of_node;
+   err = devm_spi_register_master(>dev, master);
+   if (err) {
+   dev_err(>dev, "register master failed: %d\n", err);
+   goto fail;
+   }
+
+   return 0;
+fail:
+   spi_master_put(master);
+   return err;
+}
+
+static int octeon_spi_remove(struct platform_device *pdev)
+{
+   struct spi_master *master = platform_get_drvdata(pdev);
+   struct octeon_spi *p = spi_master_get_devdata(master);
+
+   /* Clear the CSENA* and put everything in a known state. */
+   writeq(0, p->register_base + OCTEON_SPI_CFG(p));
+
+   return 0;
+}
+
+static const struct of_device_id octeon_spi_match[] = {
+   { .compatible = "cavium,octeon-3010-spi", },
+   {},
+};
+MODULE_DEVICE_TABLE(of, octeon_spi_match);
+
+static struct platform_driver octeon_spi_driver = {
+   .driver = {
+   .name   = "spi-octeon",
+   .of_match_table = octeon_spi_match,
+   },
+   .probe  = octeon_spi_probe,
+   .remove = octeon_spi_remove,
+};
+
+module_platform_driver(octeon_spi_driver);
+
+MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-cavium.c
similarity index 54%
rename from drivers/spi/spi-octeon.c
rename to drivers/spi/spi-cavium.c
index 2180176..8857e7d 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-cavium.c
@@ -6,42 +6,11 @@
  * Copyright (C) 2011, 2012 Cavium, Inc.
  */
 
-#include 
-#include 
 #include 
-#include 
 #include 
-#include 
-#include 
-
-#include 
 
 #include "spi-cavium.h"
 
-#define OCTEON_SPI_MAX_BYTES 9
-
-#define OCTEON_SPI_MAX_CLOCK_HZ 1600
-
-struct octeon_spi_regs {
-   int config;
-   int status;
-   int

Re: [PATCH 5/6] spi: octeon: Split driver into Octeon specific and common parts

2016-07-25 Thread Jan Glauber
On Sun, Jul 24, 2016 at 02:38:11PM -0400, Paul Gortmaker wrote:
> On Sat, Jul 23, 2016 at 6:42 AM, Jan Glauber  wrote:
> > Separate driver probing from SPI transfer functions.
> >
> > Signed-off-by: Jan Glauber 
> > Tested-by: Steven J. Hill 
> > ---
> >  drivers/spi/Makefile   |   1 +
> >  drivers/spi/spi-cavium-octeon.c| 104 +
> >  drivers/spi/{spi-octeon.c => spi-cavium.c} | 120 
> > +
> >  drivers/spi/spi-cavium.h   |  31 
> >  4 files changed, 138 insertions(+), 118 deletions(-)
> >  create mode 100644 drivers/spi/spi-cavium-octeon.c
> >  rename drivers/spi/{spi-octeon.c => spi-cavium.c} (55%)
> >
> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> > index 3c74d00..185367e 100644
> > --- a/drivers/spi/Makefile
> > +++ b/drivers/spi/Makefile
> > @@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_MT65XX)+= spi-mt65xx.o
> >  obj-$(CONFIG_SPI_MXS)  += spi-mxs.o
> >  obj-$(CONFIG_SPI_NUC900)   += spi-nuc900.o
> >  obj-$(CONFIG_SPI_OC_TINY)  += spi-oc-tiny.o
> > +spi-octeon-objs:= spi-cavium.o 
> > spi-cavium-octeon.o
> >  obj-$(CONFIG_SPI_OCTEON)   += spi-octeon.o
> >  obj-$(CONFIG_SPI_OMAP_UWIRE)   += spi-omap-uwire.o
> >  obj-$(CONFIG_SPI_OMAP_100K)+= spi-omap-100k.o
> > diff --git a/drivers/spi/spi-cavium-octeon.c 
> > b/drivers/spi/spi-cavium-octeon.c
> > new file mode 100644
> > index 000..ee4703e
> > --- /dev/null
> > +++ b/drivers/spi/spi-cavium-octeon.c
> > @@ -0,0 +1,104 @@
> > +/*
> > + * This file is subject to the terms and conditions of the GNU General 
> > Public
> > + * License.  See the file "COPYING" in the main directory of this archive
> > + * for more details.
> > + *
> > + * Copyright (C) 2011, 2012 Cavium, Inc.
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> 
> [...]
> 
> > +MODULE_DEVICE_TABLE(of, octeon_spi_match);
> > +
> > +static struct platform_driver octeon_spi_driver = {
> > +   .driver = {
> > +   .name   = "spi-octeon",
> > +   .of_match_table = octeon_spi_match,
> > +   },
> > +   .probe  = octeon
> _spi_probe,
> > +   .remove = octeon_spi_remove,
> > +};
> > +
> > +module_platform_driver(octeon_spi_driver);
> > +
> > +MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
> > +MODULE_AUTHOR("David Daney");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-cavium.c
> > similarity index 55%
> > rename from drivers/spi/spi-octeon.c
> > rename to drivers/spi/spi-cavium.c
> > index 2180176..5aaf215 100644
> > --- a/drivers/spi/spi-octeon.c
> > +++ b/drivers/spi/spi-cavium.c
> > @@ -6,42 +6,13 @@
> >   * Copyright (C) 2011, 2012 Cavium, Inc.
> >   */
> >
> > -#include 
> > -#include 
> >  #include 
> >  #include 
> 
> It almost looks like all the modular stuff got moved to the new file and
> maybe the above module.h isn't needed in the original file anymore?
> 
> Paul.
> --

Yes, that can be removed. Also io.h isn't needed there.

thanks,
Jan

> >  #include 
> >  #include 
> > -#include 
> > -
> > -#include 
> >
> >  #include "spi-cavium.h"
> 
> [...]


Re: [PATCH 5/6] spi: octeon: Split driver into Octeon specific and common parts

2016-07-25 Thread Jan Glauber
On Sun, Jul 24, 2016 at 09:54:16PM +0100, Mark Brown wrote:
> On Sat, Jul 23, 2016 at 12:42:54PM +0200, Jan Glauber wrote:
> 
> > +   dev_info(>dev, "OCTEON SPI bus driver\n");
> 
> This is just noise, remove it.

I'll remove these in both drivers.

Thanks,
Jan


Re: [PATCH 6/6] spi: octeon: Add thunderx driver

2016-07-25 Thread Jan Glauber
On Sun, Jul 24, 2016 at 10:04:52PM +0100, Mark Brown wrote:
> On Sat, Jul 23, 2016 at 12:42:55PM +0200, Jan Glauber wrote:
> 
> > +config SPI_THUNDERX
> > +   tristate "Cavium ThunderX SPI controller"
> > +   depends on 64BIT && PCI && !CAVIUM_OCTEON_SOC
> 
> This is a *weird* and most likely broken set of dependencies - why
> exclude this if we're on Octeon (or Octeon happens to have been enabled
> in a config)?

I agree that it looks weird, the reasoning is that we would like
to avoid making the driver depend on something like ARCH_THUNDER.

So I made the driver depend on the things it actually uses
(PCI for probing and 64BIT because of readq/writeq) and don't care if it
compiles on other platforms too (like x86).

That said, I can remove the !CAVIUM_OCTEON_SOC, it compiles without
errors on MIPS too. Would that be ok?

> > +static void thunderx_spi_clock_enable(struct device *dev, struct 
> > octeon_spi *p)
> > +{
> > +   int ret;
> > +
> > +   p->clk = devm_clk_get(dev, NULL);
> > +   if (IS_ERR(p->clk)) {
> > +   p->clk = NULL;
> > +   goto skip;
> > +   }
> 
> This is really not clever - we should be requesting clocks on probe, not
> only when we're trying to enable them, and using devm_ outside of probe
> paths is usually a warning sign too.  Now, this is actually called from
> probe so it works out fine but obviously it'd be better to improve the
> power management to only enable the clock when needed and at that point
> this function will be used and we'll fall into a bad pattern.
> 
> Given how tiny this function is and that we've not bothered splitting
> out any of the other resource acquisition it's probably better to just
> inline it into probe.

OK, I'll merge it into the probe function.

> > +   dev_info(>dev, "Cavium SPI bus driver probed\n");
> 
> Again, this is just adding noise to the boot log.
> 
> > +#define PCI_DEVICE_ID_THUNDERX_SPI  0xa00b
> > +
> > +static const struct pci_device_id thunderx_spi_pci_id_table[] = {
> > +   { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDERX_SPI) },
> > +   { 0, }
> > +};
> 
> The define for the device ID doesn't seem to be adding much here.

I find it more readable instead of PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa00b),
or did I miss your point?

thanks,
Jan


[PATCH v2] spi: octeon: Split driver into Octeon specific and common parts

2016-07-25 Thread Jan Glauber
Separate driver probing from SPI transfer functions.

Signed-off-by: Jan Glauber 
---
 drivers/spi/Makefile   |   1 +
 drivers/spi/spi-cavium-octeon.c| 102 
 drivers/spi/{spi-octeon.c => spi-cavium.c} | 122 +
 drivers/spi/spi-cavium.h   |  31 
 4 files changed, 136 insertions(+), 120 deletions(-)
 create mode 100644 drivers/spi/spi-cavium-octeon.c
 rename drivers/spi/{spi-octeon.c => spi-cavium.c} (54%)

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3c74d00..185367e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_MT65XX)+= spi-mt65xx.o
 obj-$(CONFIG_SPI_MXS)  += spi-mxs.o
 obj-$(CONFIG_SPI_NUC900)   += spi-nuc900.o
 obj-$(CONFIG_SPI_OC_TINY)  += spi-oc-tiny.o
+spi-octeon-objs:= spi-cavium.o 
spi-cavium-octeon.o
 obj-$(CONFIG_SPI_OCTEON)   += spi-octeon.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)   += spi-omap-uwire.o
 obj-$(CONFIG_SPI_OMAP_100K)+= spi-omap-100k.o
diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c
new file mode 100644
index 000..97310c1
--- /dev/null
+++ b/drivers/spi/spi-cavium-octeon.c
@@ -0,0 +1,102 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011, 2012 Cavium, Inc.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "spi-cavium.h"
+
+static int octeon_spi_probe(struct platform_device *pdev)
+{
+   struct resource *res_mem;
+   void __iomem *reg_base;
+   struct spi_master *master;
+   struct octeon_spi *p;
+   int err = -ENOENT;
+
+   master = spi_alloc_master(>dev, sizeof(struct octeon_spi));
+   if (!master)
+   return -ENOMEM;
+   p = spi_master_get_devdata(master);
+   platform_set_drvdata(pdev, master);
+
+   res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   reg_base = devm_ioremap_resource(>dev, res_mem);
+   if (IS_ERR(reg_base)) {
+   err = PTR_ERR(reg_base);
+   goto fail;
+   }
+
+   p->register_base = reg_base;
+   p->sys_freq = octeon_get_io_clock_rate();
+
+   p->regs.config = 0;
+   p->regs.status = 0x08;
+   p->regs.tx = 0x10;
+   p->regs.data = 0x80;
+
+   master->num_chipselect = 4;
+   master->mode_bits = SPI_CPHA |
+   SPI_CPOL |
+   SPI_CS_HIGH |
+   SPI_LSB_FIRST |
+   SPI_3WIRE;
+
+   master->transfer_one_message = octeon_spi_transfer_one_message;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+
+   master->dev.of_node = pdev->dev.of_node;
+   err = devm_spi_register_master(>dev, master);
+   if (err) {
+   dev_err(>dev, "register master failed: %d\n", err);
+   goto fail;
+   }
+
+   return 0;
+fail:
+   spi_master_put(master);
+   return err;
+}
+
+static int octeon_spi_remove(struct platform_device *pdev)
+{
+   struct spi_master *master = platform_get_drvdata(pdev);
+   struct octeon_spi *p = spi_master_get_devdata(master);
+
+   /* Clear the CSENA* and put everything in a known state. */
+   writeq(0, p->register_base + OCTEON_SPI_CFG(p));
+
+   return 0;
+}
+
+static const struct of_device_id octeon_spi_match[] = {
+   { .compatible = "cavium,octeon-3010-spi", },
+   {},
+};
+MODULE_DEVICE_TABLE(of, octeon_spi_match);
+
+static struct platform_driver octeon_spi_driver = {
+   .driver = {
+   .name   = "spi-octeon",
+   .of_match_table = octeon_spi_match,
+   },
+   .probe  = octeon_spi_probe,
+   .remove = octeon_spi_remove,
+};
+
+module_platform_driver(octeon_spi_driver);
+
+MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-cavium.c
similarity index 54%
rename from drivers/spi/spi-octeon.c
rename to drivers/spi/spi-cavium.c
index 2180176..8857e7d 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-cavium.c
@@ -6,42 +6,11 @@
  * Copyright (C) 2011, 2012 Cavium, Inc.
  */
 
-#include 
-#include 
 #include 
-#include 
 #include 
-#include 
-#include 
-
-#include 
 
 #include "spi-cavium.h"
 
-#define OCTEON_SPI_MAX_BYTES 9
-
-#define OCTEON_SPI_MAX_CLOCK_HZ 1600
-
-struct octeon_spi_regs {
-   int config;
-   int status;
-   int

[PATCH v2] spi: octeon: Add thunderx driver

2016-07-25 Thread Jan Glauber
Add ThunderX SPI driver using the shared part from the Octeon
driver. The main difference of the ThunderX driver is that it
is a PCI device so probing is different. The system clock settings
can be specified in device tree.

Signed-off-by: Jan Glauber 
---
 drivers/spi/Kconfig   |   7 ++
 drivers/spi/Makefile  |   2 +
 drivers/spi/spi-cavium-thunderx.c | 140 ++
 drivers/spi/spi-cavium.h  |   3 +
 4 files changed, 152 insertions(+)
 create mode 100644 drivers/spi/spi-cavium-thunderx.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b931ec..e0ee112 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -630,6 +630,13 @@ config SPI_TEGRA20_SLINK
help
  SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
 
+config SPI_THUNDERX
+   tristate "Cavium ThunderX SPI controller"
+   depends on (ARM64 || CONFIG_TEST) && 64BIT && PCI
+   help
+ SPI host driver for the hardware found on Cavium ThunderX
+ SOCs.
+
 config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 185367e..133364b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -91,6 +91,8 @@ obj-$(CONFIG_SPI_TEGRA114)+= spi-tegra114.o
 obj-$(CONFIG_SPI_TEGRA20_SFLASH)   += spi-tegra20-sflash.o
 obj-$(CONFIG_SPI_TEGRA20_SLINK)+= spi-tegra20-slink.o
 obj-$(CONFIG_SPI_TLE62X0)  += spi-tle62x0.o
+spi-thunderx-objs  := spi-cavium.o spi-cavium-thunderx.o
+obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
 obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
 obj-$(CONFIG_SPI_XCOMM)+= spi-xcomm.o
diff --git a/drivers/spi/spi-cavium-thunderx.c 
b/drivers/spi/spi-cavium-thunderx.c
new file mode 100644
index 000..28c3dcc
--- /dev/null
+++ b/drivers/spi/spi-cavium-thunderx.c
@@ -0,0 +1,140 @@
+/*
+ * Cavium ThunderX SPI driver.
+ *
+ * Copyright (C) 2016 Cavium Inc.
+ * Authors: Jan Glauber 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "spi-cavium.h"
+
+#define DRV_NAME "spi-thunderx"
+
+#define SYS_FREQ_DEFAULT 7 /* 700 Mhz */
+
+static int thunderx_spi_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+   struct device *dev = >dev;
+   struct spi_master *master;
+   struct octeon_spi *p;
+   int ret = -ENOENT;
+
+   master = spi_alloc_master(dev, sizeof(struct octeon_spi));
+   if (!master)
+   return -ENOMEM;
+   p = spi_master_get_devdata(master);
+
+   ret = pci_enable_device(pdev);
+   if (ret) {
+   dev_err(dev, "Failed to enable PCI device\n");
+   goto out_free;
+   }
+
+   ret = pci_request_regions(pdev, DRV_NAME);
+   if (ret) {
+   dev_err(dev, "PCI request regions failed 0x%x\n", ret);
+   goto out_disable;
+   }
+
+   p->register_base = pci_ioremap_bar(pdev, 0);
+   if (!p->register_base) {
+   dev_err(dev, "Cannot map reg base\n");
+   ret = -EINVAL;
+   goto out_region;
+   }
+
+   p->regs.config = 0x1000;
+   p->regs.status = 0x1008;
+   p->regs.tx = 0x1010;
+   p->regs.data = 0x1080;
+
+   p->clk = devm_clk_get(dev, NULL);
+   if (IS_ERR(p->clk))
+   goto out_unmap;
+
+   ret = clk_prepare_enable(p->clk);
+   if (ret)
+   goto out_clock_devm;
+
+   p->sys_freq = clk_get_rate(p->clk);
+   if (!p->sys_freq)
+   p->sys_freq = SYS_FREQ_DEFAULT;
+   dev_info(dev, "Set system clock to %u\n", p->sys_freq);
+
+   master->num_chipselect = 4;
+   master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
+   SPI_LSB_FIRST | SPI_3WIRE;
+   master->transfer_one_message = octeon_spi_transfer_one_message;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+   master->dev.of_node = pdev->dev.of_node;
+
+   pci_set_drvdata(pdev, master);
+   ret = devm_spi_register_master(dev, master);
+   if (ret) {
+   dev_err(>dev, "Register master failed: %d\n", ret);
+   goto out_clock;
+   }
+
+   return 0;
+
+out_clock:
+   clk_disable_unprepare(p->clk);
+out_clock_devm:
+   devm_clk_put(dev, p->clk);
+out_unmap:
+   iounmap(p->register_base);
+out_region:
+   pci_release_regions(pdev);
+out_disable:
+   pci_disable_device(pdev);
+out_fr

[PATCH] i2c: Prevent endless uevent loop with dev_dbg

2016-03-23 Thread Jan Glauber
After enabling CONFIG_I2C_DEBUG_CORE my system was broken
(no network, console login not possible). System log was
flooded with the this message:

 ...
[  608.052077] rtc-ds1307 0-0068: uevent
[  608.052500] rtc-ds1307 0-0068: uevent
[  608.052925] rtc-ds1307 0-0068: uevent
 ...

The culprit is the dev_dbg printk in the i2c uevent handler.
If this is activated (for instance by CONFIG_I2C_DEBUG_CORE)
it results in an endless loop with systemd-journald.

This happens if user-space scans the system log and reads the uevent
file to get information about a newly created device, which seems fair
use to me. Unfortunately reading the "uevent" file uses the same
function that runs for creating the uevent for a new device,
generating the next syslog entry.

Ideally user-space would implement a recursion detection and
after reading the same device file for the 1000th time call it a
day, but nevertheless I think we should avoid this problem by
removing the debug print completly or using another print variant.

The same problem seems to be reported here:
https://bugs.freedesktop.org/show_bug.cgi?id=76886

Signed-off-by: Jan Glauber 
---
 drivers/i2c/i2c-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 0f2f848..84165d9 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -539,7 +539,7 @@ static int i2c_device_uevent(struct device *dev, struct 
kobj_uevent_env *env)
if (add_uevent_var(env, "MODALIAS=%s%s",
   I2C_MODULE_PREFIX, client->name))
return -ENOMEM;
-   dev_dbg(dev, "uevent\n");
+   pr_debug("uevent: device: %s\n", dev_name(dev));
return 0;
 }
 
-- 
1.9.1



Re: [PATCH] i2c: Prevent endless uevent loop with dev_dbg

2016-03-23 Thread Jan Glauber
On Wed, Mar 23, 2016 at 05:50:33PM +0100, Wolfram Sang wrote:
> On Wed, Mar 23, 2016 at 04:50:47PM +0100, Jan Glauber wrote:
> > After enabling CONFIG_I2C_DEBUG_CORE my system was broken
> > (no network, console login not possible). System log was
> > flooded with the this message:
> > 
> >  ...
> > [  608.052077] rtc-ds1307 0-0068: uevent
> > [  608.052500] rtc-ds1307 0-0068: uevent
> > [  608.052925] rtc-ds1307 0-0068: uevent
> >  ...
> > 
> > The culprit is the dev_dbg printk in the i2c uevent handler.
> > If this is activated (for instance by CONFIG_I2C_DEBUG_CORE)
> > it results in an endless loop with systemd-journald.
> > 
> > This happens if user-space scans the system log and reads the uevent
> > file to get information about a newly created device, which seems fair
> > use to me. Unfortunately reading the "uevent" file uses the same
> > function that runs for creating the uevent for a new device,
> > generating the next syslog entry.
> > 
> > Ideally user-space would implement a recursion detection and
> > after reading the same device file for the 1000th time call it a
> > day, but nevertheless I think we should avoid this problem by
> > removing the debug print completly or using another print variant.
> 
> Thanks for pointing out this problem. I think this debug can go. I also
> think the function can be cleaned up some more. Can you test this patch?

Works for me!

Thanks, Jan

> Thanks,
> 
>Wolfram
> 
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index 0f2f8484e8ec1f..e584d88ee337f6 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -525,22 +525,16 @@ static int i2c_device_match(struct device *dev, struct 
> device_driver *drv)
>   return 0;
>  }
>  
> -
> -/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
>  static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
>  {
> - struct i2c_client   *client = to_i2c_client(dev);
> + struct i2c_client *client = to_i2c_client(dev);
>   int rc;
>  
>   rc = acpi_device_uevent_modalias(dev, env);
>   if (rc != -ENODEV)
>   return rc;
>  
> - if (add_uevent_var(env, "MODALIAS=%s%s",
> -I2C_MODULE_PREFIX, client->name))
> - return -ENOMEM;
> - dev_dbg(dev, "uevent\n");
> - return 0;
> + return add_uevent_var(env, "MODALIAS=%s%s", I2C_MODULE_PREFIX, 
> client->name);
>  }
>  
>  /* i2c bus recovery routines */
> 




Re: [PATCH v2 0/5] Cavium ThunderX uncore PMU support

2016-06-28 Thread Jan Glauber
On Tue, Jun 28, 2016 at 11:24:20AM +0100, Will Deacon wrote:
> Hi Jan,
> 
> On Wed, Mar 09, 2016 at 05:21:02PM +0100, Jan Glauber wrote:
> > This patch series provides access to various counters on the ThunderX SOC.
> > 
> > For details of the uncore implementation see patch #1.
> > 
> > Patches #2-5 add the various ThunderX specific PMUs.
> > 
> > As suggested I've put the files under drivers/perf/uncore. I would
> > prefer this location over drivers/bus because not all of the uncore
> > drivers are bus related.
> 
> What's the status of these patches? Were you planning to send a new
> version?
> 
> Will

Hi Will,

I was half-way through with addressing Mark's review comments when
got side-tracked.

The principle question these patches raised remains open though in my
opinion, how to determine the socket a device belongs to.

There is no first-class interface to ask a device or the firmware
which socket the device lives on.

The options I see are:
A) Using NUMA node information, depends on CONFIG_NUMA
B) Decoding the socket bits of the PCI BAR address
C) Using PCI topology information

A is what I tried, but I agree that depending on CONFIG_NUMA is not a good
solution. B would be easy but looks not very future-proof. So option C
is what is left...

thanks,
Jan


[PATCH v4 13/14] i2c-thunderx: Add i2c driver for ThunderX SOC

2016-03-18 Thread Jan Glauber
The ThunderX SOC uses the same i2c block as the Octeon SOC.
The main difference is that on ThunderX the device is a PCI device
so device probing is done via PCI, interrupts are MSIX and the
clock is taken from device tree.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Kconfig |  10 ++
 drivers/i2c/busses/Makefile|   2 +
 drivers/i2c/busses/i2c-cavium.h|  17 ++-
 drivers/i2c/busses/i2c-thunderx-core.c | 268 +
 4 files changed, 294 insertions(+), 3 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0299dfa..d1e7341 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -953,6 +953,16 @@ config I2C_OCTEON
  This driver can also be built as a module.  If so, the module
  will be called i2c-octeon.
 
+config I2C_THUNDERX
+   tristate "Cavium ThunderX I2C bus support"
+   depends on 64BIT && PCI && !CAVIUM_OCTEON_SOC
+   help
+ Say yes if you want to support the I2C serial bus on Cavium
+ ThunderX SOC.
+
+ This driver can also be built as a module.  If so, the module
+ will be called i2c-thunderx.
+
 config I2C_XILINX
tristate "Xilinx I2C Controller"
depends on HAS_IOMEM
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 282f781..a32ff14 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -93,6 +93,8 @@ obj-$(CONFIG_I2C_VERSATILE)   += i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
 i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
 obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+i2c-thunderx-objs := i2c-cavium.o i2c-thunderx-core.o
+obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.h b/drivers/i2c/busses/i2c-cavium.h
index 7f78bf0..31608c4 100644
--- a/drivers/i2c/busses/i2c-cavium.h
+++ b/drivers/i2c/busses/i2c-cavium.h
@@ -8,9 +8,15 @@
 #include 
 
 /* Register offsets */
-#define SW_TWSI0x00
-#define TWSI_INT   0x10
-#define SW_TWSI_EXT0x18
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+   #define SW_TWSI 0x1000
+   #define TWSI_INT0x1010
+   #define SW_TWSI_EXT 0x1018
+#else
+   #define SW_TWSI 0x00
+   #define TWSI_INT0x10
+   #define SW_TWSI_EXT 0x18
+#endif
 
 /* Controller command patterns */
 #define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
@@ -92,6 +98,7 @@
 struct octeon_i2c {
wait_queue_head_t queue;
struct i2c_adapter adap;
+   struct clk *clk;
int irq;
int hlc_irq;/* For cn7890 only */
u32 twsi_freq;
@@ -107,6 +114,10 @@ struct octeon_i2c {
void (*hlc_int_dis)(struct octeon_i2c *);
atomic_t int_en_cnt;
atomic_t hlc_int_en_cnt;
+
+#if IS_ENABLED(CONFIG_I2C_THUNDERX)
+   struct msix_entry i2c_msix;
+#endif
 };
 
 static inline void writeqflush(u64 val, void __iomem *addr)
diff --git a/drivers/i2c/busses/i2c-thunderx-core.c 
b/drivers/i2c/busses/i2c-thunderx-core.c
new file mode 100644
index 000..6168517
--- /dev/null
+++ b/drivers/i2c/busses/i2c-thunderx-core.c
@@ -0,0 +1,268 @@
+/*
+ * Cavium ThunderX i2c driver.
+ *
+ * Copyright (C) 2015,2016 Cavium Inc.
+ * Authors: Fred Martin 
+ * Jan Glauber 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+#define DRV_NAME "i2c-thunderx"
+
+#define PCI_CFG_REG_BAR_NUM0
+#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012
+
+#define TWSI_DFL_RATE  10
+#define SYS_FREQ_DEFAULT   8
+
+#define TWSI_INT_ENA_W1C   0x1028
+#define TWSI_INT_ENA_W1S   0x1030
+
+/*
+ * Enable the CORE interrupt.
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void thunder_i2c_int_enable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_CORE_INT, i2c->twsi_base + TWSI_INT_ENA_W1S);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+/*
+ * Disable the CORE interrupt.
+ */
+static void thunder_i2c_int_disable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_CORE_INT, i2c->twsi_base + TWSI_INT_ENA_W1C);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1C);
+}
+
+static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+   __raw_writeq(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
+i2c->twsi_base + TWSI_INT_ENA_W1S);
+   __raw_readq(i2c->twsi_base + TWSI_INT_ENA_W1S);
+}
+
+static void t

[PATCH v4 07/14] i2c-octeon: Add support for cn78xx chips

2016-03-18 Thread Jan Glauber
From: David Daney 

cn78xx has a different interrupt architecture, so we have to manage
the interrupts differently.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 131 
 1 file changed, 120 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 0e3611a..f409f8f 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -11,6 +11,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -112,11 +113,18 @@ struct octeon_i2c {
wait_queue_head_t queue;
struct i2c_adapter adap;
int irq;
+   int hlc_irq;/* For cn7890 only */
u32 twsi_freq;
int sys_freq;
void __iomem *twsi_base;
struct device *dev;
bool hlc_enabled;
+   void (*int_en)(struct octeon_i2c *);
+   void (*int_dis)(struct octeon_i2c *);
+   void (*hlc_int_en)(struct octeon_i2c *);
+   void (*hlc_int_dis)(struct octeon_i2c *);
+   atomic_t int_en_cnt;
+   atomic_t hlc_int_en_cnt;
 };
 
 static int reset_how;
@@ -214,6 +222,58 @@ static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
 }
 
 /**
+ * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
+{
+   atomic_inc_return(>int_en_cnt);
+   enable_irq(i2c->irq);
+}
+
+static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+{
+   int count;
+
+   /*
+* The interrupt can be disabled in two places, but we only
+* want to make the disable_irq_nosync() call once, so keep
+* track with the atomic variable.
+*/
+   count = atomic_dec_if_positive(cnt);
+   if (count >= 0)
+   disable_irq_nosync(irq);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+{
+   __octeon_i2c_irq_disable(>int_en_cnt, i2c->irq);
+}
+
+/**
+ * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+{
+   atomic_inc_return(>hlc_int_en_cnt);
+   enable_irq(i2c->hlc_irq);
+}
+
+/* disable the ST interrupt */
+static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+{
+   __octeon_i2c_irq_disable(>hlc_int_en_cnt, i2c->hlc_irq);
+}
+
+/**
  * octeon_i2c_unblock - unblock the bus
  * @i2c: The struct octeon_i2c
  *
@@ -250,7 +310,18 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 {
struct octeon_i2c *i2c = dev_id;
 
-   octeon_i2c_int_disable(i2c);
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+/* HLC interrupt service routine */
+static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->hlc_int_dis(i2c);
wake_up(>queue);
 
return IRQ_HANDLED;
@@ -276,10 +347,10 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
long time_left;
 
-   octeon_i2c_int_enable(i2c);
+   i2c->int_en(i2c);
time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
   i2c->adap.timeout);
-   octeon_i2c_int_disable(i2c);
+   i2c->int_dis(i2c);
if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -413,11 +484,11 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int time_left;
 
-   octeon_i2c_hlc_int_enable(i2c);
+   i2c->hlc_int_en(i2c);
time_left = wait_event_interruptible_timeout(i2c->queue,
octeon_i2c_hlc_test_ready(i2c),
i2c->adap.timeout);
-   octeon_i2c_int_disable(i2c);
+   i2c->hlc_int_dis(i2c);
if (!time_left) {
octeon_i2c_hlc_int_clear(i2c);
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
@@ -969,14 +1040,26 @@ static struct i2c_adapter octeon_i2c_ops = {
 static int octeon_i2c_probe(struct platform_device *pdev)
 {
struct device_node *node = pdev->dev.of_node;
+   int irq, result = 0, hlc_irq = 0;
struct resource *res_mem;
struct octeon_i2c *i2c;
-   int irq, result = 0;
-
-   /* All adaptors have an irq.  */
-   irq = platform_get_irq(pdev, 0);
-   if (irq < 0)
-   return irq;
+   bool cn78xx_style;
+
+   cn78xx_style = of_device_is_c

[PATCH v4 06/14] dt-bindings: i2c: Add Octeon cn78xx TWSI

2016-03-18 Thread Jan Glauber
Add compatible string for Cavium Octeon cn78XX SOCs TWSI.

Cc: Rob Herring 
Cc: Pawel Moll 
Cc: Mark Rutland 
Cc: Ian Campbell 
Cc: Kumar Gala 

Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 Documentation/devicetree/bindings/i2c/i2c-octeon.txt | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt 
b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
index dced82e..872d485 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
@@ -4,6 +4,12 @@
 
   Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
 
+  or
+
+  compatible: "cavium,octeon-7890-twsi"
+
+  Compatibility with cn78XX SOCs.
+
 - reg: The base address of the TWSI/I2C bus controller register bank.
 
 - #address-cells: Must be <1>.
-- 
1.9.1



[PATCH v4 00/14] i2c-octeon and i2c-thunderx drivers

2016-03-18 Thread Jan Glauber
This series for the Octeon i2c driver is an attempt to upstream some
bug fixes and features that accumulated for some time.

On top of the Octeon changes a i2c driver for the ThunderX SOC is
added which uses the same functional block as the Octeon driver.

Patches #1-2 are cleanups.
Patches #3-10 are forward-ports of Octeon features and bugfixes.
Patch #11-12 prepare for the driver split
Patches #13-14 add the ThunderX driver.

Patches are on top of 4.5 + i2c-octeon-kerneldoc-patch and were
tested on OCTEON, OCTEON-78 and ThunderX.

Changes to v3:
- added more functionality flags for SMBUS
- removed both module parameters
- make xfer return also other errors than EGAIN
- return EPROTO on invalid SMBUS block length
- use devm_ioremap_resource
- added rename-only patch
- removed kerneldoc patch from series
- improved defines

Changes to v2:
- Split clenaup patch into several patches
- Strictly moved functional changes to later patches
- Fixed do-while checkpatch errors
- Moved defines to the patches that use them
- Use BIT_ULL macro
- Split ThunderX patch into 2 patches

Changes to v1:
- Fixed compile error on x86_64
- Disabled thunderx driver on MIPS
- Re-ordered some thunderx probe functions for readability
- Fix missing of_irq.h and i2c-smbus.h includes
- Use IS_ENABLED for CONFIG options

Jan

-


David Daney (4):
  i2c-octeon: Support I2C_M_RECV_LEN
  i2c-octeon: Enable high-level controller and improve on bus contention
  i2c-octeon: Add support for cn78xx chips
  i2c-octeon: Add workaround for broken irqs on CN3860

Jan Glauber (8):
  i2c-octeon: Cleanup i2c-octeon driver
  i2c-octeon: Cleanup resource allocation code
  i2c-octeon: Change adapter timeout and retry default values
  dt-bindings: i2c: Add Octeon cn78xx TWSI
  i2c-octeon: Rename driver to prepare for split
  i2c-octeon: Split the driver into two parts
  i2c-thunderx: Add i2c driver for ThunderX SOC
  i2c-thunderx: Add smbus alert support

Peter Swain (2):
  i2c-octeon: Flush TWSI writes with readback
  i2c-octeon: Faster operation when IFLG signals late

 .../devicetree/bindings/i2c/i2c-octeon.txt |   6 +
 drivers/i2c/busses/Kconfig |  10 +
 drivers/i2c/busses/Makefile|   3 +
 drivers/i2c/busses/i2c-cavium.c| 822 +
 drivers/i2c/busses/i2c-cavium.h| 212 ++
 drivers/i2c/busses/i2c-octeon-core.c   | 283 +++
 drivers/i2c/busses/i2c-octeon.c| 622 
 drivers/i2c/busses/i2c-thunderx-core.c | 303 
 8 files changed, 1639 insertions(+), 622 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

-- 
1.9.1



[PATCH v4 12/14] i2c-octeon: Split the driver into two parts

2016-03-18 Thread Jan Glauber
Move common functionality into a separate file in preparation of the
re-use from the ThunderX i2c driver.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Makefile  |   3 +-
 drivers/i2c/busses/i2c-cavium.c  | 822 +
 drivers/i2c/busses/i2c-cavium.h  | 195 +++
 drivers/i2c/busses/i2c-octeon-core.c | 983 +--
 4 files changed, 1020 insertions(+), 983 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3405286..282f781 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,8 @@ obj-$(CONFIG_I2C_UNIPHIER)+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
-obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon-core.o
+i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
+obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.c b/drivers/i2c/busses/i2c-cavium.c
new file mode 100644
index 000..9ad1f23
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cavium.c
@@ -0,0 +1,822 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+static int reset_how;
+
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+}
+
+#define I2C_OCTEON_IFLG_WAIT 80/* microseconds */
+
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(I2C_OCTEON_IFLG_WAIT, 2 * I2C_OCTEON_IFLG_WAIT);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+   long time_left;
+   int first = 1;
+
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_test_iflg(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+   }
+
+   i2c->int_en(i2c);
+   time_left = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
+  i2c->adap.timeout);
+   i2c->int_dis(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_test_iflg(i2c)) {
+   dev_err(i2c->dev,
+   "broken irq connection detected, switching to polling 
mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
+   if (!time_left) {
+   dev_dbg(i2c->dev, "%s: timeout\n", __func__);
+   return -ETIMEDOUT;
+   }
+
+   return 0;
+}
+
+/*
+ * Cleanup low-level state & enable high-level.
+ * Returns -EAGAIN if low-level state could not be cleaned.
+ */
+static int octeon_i2c_enable_hlc(struct octeon_i2c *i2c)
+{
+   int try = 0, ret = 0;
+   u64 val;
+
+   if (i2c->hlc_enabled)
+   return 0;
+   i2c->

[PATCH v4 02/14] i2c-octeon: Cleanup resource allocation code

2016-03-18 Thread Jan Glauber
Remove resource values from struct i2c_octeon and use
devm_ioremap_resource helper.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 18 +++---
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 9787379..9240037 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -75,9 +75,7 @@ struct octeon_i2c {
int irq;
u32 twsi_freq;
int sys_freq;
-   resource_size_t twsi_phys;
void __iomem *twsi_base;
-   resource_size_t regsize;
struct device *dev;
 };
 
@@ -502,14 +500,11 @@ static int octeon_i2c_probe(struct platform_device *pdev)
i2c->dev = >dev;
 
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-   if (res_mem == NULL) {
-   dev_err(i2c->dev, "found no memory resource\n");
-   result = -ENXIO;
+   i2c->twsi_base = devm_ioremap_resource(>dev, res_mem);
+   if (IS_ERR(i2c->twsi_base)) {
+   result = PTR_ERR(i2c->twsi_base);
goto out;
}
-   i2c->twsi_phys = res_mem->start;
-   i2c->regsize = resource_size(res_mem);
 
/*
 * "clock-rate" is a legacy binding, the official binding is
@@ -526,13 +521,6 @@ static int octeon_i2c_probe(struct platform_device *pdev)
 
i2c->sys_freq = octeon_get_io_clock_rate();
 
-   if (!devm_request_mem_region(>dev, i2c->twsi_phys, i2c->regsize,
-res_mem->name)) {
-   dev_err(i2c->dev, "request_mem_region failed\n");
-   goto out;
-   }
-   i2c->twsi_base = devm_ioremap(>dev, i2c->twsi_phys, i2c->regsize);
-
init_waitqueue_head(>queue);
 
i2c->irq = irq;
-- 
1.9.1



[PATCH v4 08/14] i2c-octeon: Flush TWSI writes with readback

2016-03-18 Thread Jan Glauber
From: Peter Swain 

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 19 ---
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index f409f8f..aa676ce 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -129,6 +129,12 @@ struct octeon_i2c {
 
 static int reset_how;
 
+static void writeqflush(u64 val, void __iomem *addr)
+{
+   __raw_writeq(val, addr);
+   __raw_readq(addr);  /* wait for write to land */
+}
+
 /**
  * octeon_i2c_write_sw - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -189,8 +195,7 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 
eop_reg)
  */
 static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
 {
-   __raw_writeq(data, i2c->twsi_base + TWSI_INT);
-   __raw_readq(i2c->twsi_base + TWSI_INT);
+   writeqflush(data, i2c->twsi_base + TWSI_INT);
 }
 
 /**
@@ -576,10 +581,10 @@ static int octeon_i2c_simple_write(struct octeon_i2c 
*i2c, struct i2c_msg *msgs)
 
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
ext |= (u64) msgs[0].buf[j] << (8 * i);
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
}
 
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -625,7 +630,7 @@ static int octeon_i2c_ia_read(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
cmd |= (u64) msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -685,10 +690,10 @@ static int octeon_i2c_ia_write(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
set_ext = true;
}
if (set_ext)
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
-- 
1.9.1



[PATCH v4 01/14] i2c-octeon: Cleanup i2c-octeon driver

2016-03-18 Thread Jan Glauber
Cleanup only without functional change.

- removed DRV_VERSION
- defines: use defines instead of plain values,
  use BIT_ULL macro, add comments
- rename waitqueue return value to time_left
- sort local variables by length
- fix indentation and whitespace errors
- make function return void if the result is not used
  (octeon_i2c_stop, octeon_i2c_set_clock)
- remove debug code from octeon_i2c_stop
- renamed some functions for readability
- update copyright

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 190 ++--
 1 file changed, 84 insertions(+), 106 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 4a08418..9787379 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -2,7 +2,7 @@
  * (C) Copyright 2009-2010
  * Nokia Siemens Networks, michael.lawnick@nsn.com
  *
- * Portions Copyright (C) 2010, 2011 Cavium Networks, Inc.
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
  *
  * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
  *
@@ -26,39 +26,48 @@
 
 #define DRV_NAME "i2c-octeon"
 
-/* The previous out-of-tree version was implicitly version 1.0. */
-#define DRV_VERSION"2.0"
-
-/* register offsets */
-#define SW_TWSI 0x00
-#define TWSI_INT 0x10
+/* Register offsets */
+#define SW_TWSI0x00
+#define TWSI_INT   0x10
 
 /* Controller command patterns */
-#define SW_TWSI_V   0x8000ull
-#define SW_TWSI_EOP_TWSI_DATA   0x0C01ull
-#define SW_TWSI_EOP_TWSI_CTL0x0C02ull
-#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C03ull
-#define SW_TWSI_EOP_TWSI_STAT   0x0C03ull
-#define SW_TWSI_EOP_TWSI_RST0x0C07ull
-#define SW_TWSI_OP_TWSI_CLK 0x0800ull
-#define SW_TWSI_R   0x0100ull
+#define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
+#define SW_TWSI_R  BIT_ULL(56) /* Result or read bit */
+
+/* Controller opcode word (bits 60:57) */
+#define SW_TWSI_OP_SHIFT   57
+#define SW_TWSI_OP_TWSI_CLK(4ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
+
+/* Controller extended opcode word (bits 34:32) */
+#define SW_TWSI_EOP_SHIFT  32
+#define SW_TWSI_EOP_TWSI_DATA  (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CTL   (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CLKCTL(SW_TWSI_OP_EOP | 3ULL << 
SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_STAT  (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_RST   (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
 
 /* Controller command and status bits */
-#define TWSI_CTL_CE   0x80
-#define TWSI_CTL_ENAB 0x40
-#define TWSI_CTL_STA  0x20
-#define TWSI_CTL_STP  0x10
-#define TWSI_CTL_IFLG 0x08
-#define TWSI_CTL_AAK  0x04
+#define TWSI_CTL_CE0x80
+#define TWSI_CTL_ENAB  0x40/* Bus enable */
+#define TWSI_CTL_STA   0x20/* Master-mode start, HW clears when 
done */
+#define TWSI_CTL_STP   0x10/* Master-mode stop, HW clears when 
done */
+#define TWSI_CTL_IFLG  0x08/* HW event, SW writes 0 to ACK */
+#define TWSI_CTL_AAK   0x04/* Assert ACK */
 
 /* Some status values */
-#define STAT_START  0x08
-#define STAT_RSTART 0x10
-#define STAT_TXADDR_ACK 0x18
-#define STAT_TXDATA_ACK 0x28
-#define STAT_RXADDR_ACK 0x40
-#define STAT_RXDATA_ACK 0x50
-#define STAT_IDLE   0xF8
+#define STAT_START 0x08
+#define STAT_RSTART0x10
+#define STAT_TXADDR_ACK0x18
+#define STAT_TXDATA_ACK0x28
+#define STAT_RXADDR_ACK0x40
+#define STAT_RXDATA_ACK0x50
+#define STAT_IDLE  0xF8
+
+/* TWSI_INT values */
+#define TWSI_INT_CORE_EN   BIT_ULL(6)
+#define TWSI_INT_SDA_OVR   BIT_ULL(8)
+#define TWSI_INT_SCL_OVR   BIT_ULL(9)
 
 struct octeon_i2c {
wait_queue_head_t queue;
@@ -80,9 +89,7 @@ struct octeon_i2c {
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static void octeon_i2c_write_sw(struct octeon_i2c *i2c,
-   u64 eop_reg,
-   u8 data)
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
 {
u64 tmp;
 
@@ -93,7 +100,7 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c,
 }
 
 /**
- * octeon_i2c_read_sw - write an I2C core register
+ * octeon_i2c_read_sw - read lower bits of an I2C core register
  * @i2c: The struct octeon_i2c
  * @eop_reg: Register selector
  *
@@ -133,12 +140,13 @@ static void octeon_i2c_write_int(struct octeon_i2c *i2c, 
u64 data)
  */
 static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
 {
-   oct

[PATCH v4 10/14] i2c-octeon: Add workaround for broken irqs on CN3860

2016-03-19 Thread Jan Glauber
From: David Daney 

CN3860 does not interrupt the CPU when the i2c status changes. If
we get a timeout, and see the status has in fact changed, we know we
have this problem, and drop back to polling.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 55 +++--
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index d3a3e2e..444e8ed 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -119,6 +119,8 @@ struct octeon_i2c {
void __iomem *twsi_base;
struct device *dev;
bool hlc_enabled;
+   bool broken_irq_mode;
+   bool broken_irq_check;
void (*int_en)(struct octeon_i2c *);
void (*int_dis)(struct octeon_i2c *);
void (*hlc_int_en)(struct octeon_i2c *);
@@ -375,10 +377,33 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
long time_left;
int first = 1;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_test_iflg(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->int_en(i2c);
time_left = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
   i2c->adap.timeout);
i2c->int_dis(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_test_iflg(i2c)) {
+   dev_err(i2c->dev,
+   "broken irq connection detected, switching to polling 
mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -512,17 +537,40 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int time_left;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some cn38xx boards did not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_hlc_test_ready(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_hlc_test_ready(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->hlc_int_en(i2c);
time_left = wait_event_interruptible_timeout(i2c->queue,
octeon_i2c_hlc_test_ready(i2c),
i2c->adap.timeout);
i2c->hlc_int_dis(i2c);
-   if (!time_left) {
+   if (!time_left)
octeon_i2c_hlc_int_clear(i2c);
+
+   if (time_left <= 0 && i2c->broken_irq_check &&
+   octeon_i2c_hlc_test_ready(i2c)) {
+   dev_err(i2c->dev, "broken irq connection detected, switching to 
polling mode.\n");
+   i2c->broken_irq_mode = true;
+   return 0;
+   }
+
+   if (!time_left) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
}
-
if (time_left < 0) {
dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
return time_left;
@@ -1154,6 +1202,9 @@ static int octeon_i2c_probe(struct platform_device *pdev)
goto out;
}
 
+   if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+   i2c->broken_irq_check = true;
+
result = octeon_i2c_init_lowlevel(i2c);
if (result) {
dev_err(i2c->dev, "init low level failed\n");
-- 
1.9.1



[PATCH v4 09/14] i2c-octeon: Faster operation when IFLG signals late

2016-03-19 Thread Jan Glauber
From: Peter Swain 

Some versions can deliver low-level twsi irq before twsi_ctl.iflg
is set, leading to timeout-driven i/o.
When an irq signals event, but woken task does not see the expected
twsi_ctl.iflg, re-check about 80uS later.

EEPROM reads on 100kHz i2c now measure ~5.2kB/s, about 1/2 what's
achievable, and much better than the worst-case 100 bytes/sec before.

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index aa676ce..d3a3e2e 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -342,6 +342,28 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
return (octeon_i2c_read_ctl(i2c) & TWSI_CTL_IFLG) != 0;
 }
 
+#define I2C_OCTEON_IFLG_WAIT 80/* microseconds */
+
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(I2C_OCTEON_IFLG_WAIT, 2 * I2C_OCTEON_IFLG_WAIT);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
 /**
  * octeon_i2c_wait - wait for the IFLG to be set
  * @i2c: The struct octeon_i2c
@@ -351,9 +373,10 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
long time_left;
+   int first = 1;
 
i2c->int_en(i2c);
-   time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
+   time_left = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
   i2c->adap.timeout);
i2c->int_dis(i2c);
if (!time_left) {
-- 
1.9.1



[PATCH v4 14/14] i2c-thunderx: Add smbus alert support

2016-03-19 Thread Jan Glauber
Add smbus alert interrupt support.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-cavium.h|  6 ++
 drivers/i2c/busses/i2c-thunderx-core.c | 35 ++
 2 files changed, 41 insertions(+)

diff --git a/drivers/i2c/busses/i2c-cavium.h b/drivers/i2c/busses/i2c-cavium.h
index 31608c4..f934624 100644
--- a/drivers/i2c/busses/i2c-cavium.h
+++ b/drivers/i2c/busses/i2c-cavium.h
@@ -3,6 +3,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -118,6 +119,11 @@ struct octeon_i2c {
 #if IS_ENABLED(CONFIG_I2C_THUNDERX)
struct msix_entry i2c_msix;
 #endif
+
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   struct i2c_smbus_alert_setup alert_data;
+   struct i2c_client *ara;
+#endif
 };
 
 static inline void writeqflush(u64 val, void __iomem *addr)
diff --git a/drivers/i2c/busses/i2c-thunderx-core.c 
b/drivers/i2c/busses/i2c-thunderx-core.c
index 6168517..93bb64b 100644
--- a/drivers/i2c/busses/i2c-thunderx-core.c
+++ b/drivers/i2c/busses/i2c-thunderx-core.c
@@ -9,9 +9,11 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "i2c-cavium.h"
@@ -108,6 +110,35 @@ static void thunder_i2c_clock_disable(struct device *dev, 
struct clk *clk)
devm_clk_put(dev, clk);
 }
 
+static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
+  struct device_node *node)
+{
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   u32 type;
+
+   i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
+   if (!i2c->alert_data.irq)
+   return -EINVAL;
+
+   type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
+   i2c->alert_data.alert_edge_triggered =
+   (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
+
+   i2c->ara = i2c_setup_smbus_alert(>adap, >alert_data);
+   if (!i2c->ara)
+   return -ENODEV;
+#endif
+   return 0;
+}
+
+static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
+{
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   if (i2c->ara)
+   i2c_unregister_device(i2c->ara);
+#endif
+}
+
 static void thunder_i2c_set_name(struct pci_dev *pdev, struct octeon_i2c *i2c,
 char *name)
 {
@@ -207,6 +238,9 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
goto out_irq;
}
 
+   ret = thunder_i2c_smbus_setup(i2c, node);
+   if (ret < 0)
+   dev_err(dev, "Failed to setup smbus alert\n");
dev_info(i2c->dev, "probed\n");
return 0;
 
@@ -237,6 +271,7 @@ static void thunder_i2c_remove_pci(struct pci_dev *pdev)
 
dev = i2c->dev;
thunder_i2c_clock_disable(dev, i2c->clk);
+   thunder_i2c_smbus_remove(i2c);
i2c_del_adapter(>adap);
devm_free_irq(dev, i2c->i2c_msix.vector, i2c);
pci_disable_msix(pdev);
-- 
1.9.1



[PATCH v4 05/14] i2c-octeon: Enable high-level controller and improve on bus contention

2016-03-19 Thread Jan Glauber
From: David Daney 

Use High Level Controller when possible.

i2c-octeon was reacting badly to bus contention: when in
direct-access mode (for transfers > 8 bytes, which cannot use the
high-level controller) some !ACK or arbitration-loss states were
not causing the current transfer to be aborted, and the bus released.

There's one place in i2c protocol that !ACK is an acceptable
response: in the final byte of a read cycle.  In this case the
destination is not saying that the transfer failed, just that it
doesn't want more data.

This enables correct behavior of ACK on final byte of non-final read
msgs too.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 783 
 1 file changed, 629 insertions(+), 154 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index c21d102..0e3611a 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -29,13 +29,23 @@
 /* Register offsets */
 #define SW_TWSI0x00
 #define TWSI_INT   0x10
+#define SW_TWSI_EXT0x18
 
 /* Controller command patterns */
 #define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
+#define SW_TWSI_EIABIT_ULL(61) /* Extended internal address */
 #define SW_TWSI_R  BIT_ULL(56) /* Result or read bit */
+#define SW_TWSI_SOVR   BIT_ULL(55) /* Size override */
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_ADDR_SHIFT 40
+#define SW_TWSI_IA_SHIFT   32  /* Internal address */
 
 /* Controller opcode word (bits 60:57) */
 #define SW_TWSI_OP_SHIFT   57
+#define SW_TWSI_OP_7   (0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA(1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10  (2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA   (3ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_TWSI_CLK(4ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
 
@@ -48,7 +58,7 @@
 #define SW_TWSI_EOP_TWSI_RST   (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
 
 /* Controller command and status bits */
-#define TWSI_CTL_CE0x80
+#define TWSI_CTL_CE0x80/* High level controller enable */
 #define TWSI_CTL_ENAB  0x40/* Bus enable */
 #define TWSI_CTL_STA   0x20/* Master-mode start, HW clears when 
done */
 #define TWSI_CTL_STP   0x10/* Master-mode stop, HW clears when 
done */
@@ -56,18 +66,47 @@
 #define TWSI_CTL_AAK   0x04/* Assert ACK */
 
 /* Some status values */
+#define STAT_ERROR 0x00
 #define STAT_START 0x08
 #define STAT_RSTART0x10
 #define STAT_TXADDR_ACK0x18
+#define STAT_TXADDR_NAK0x20
 #define STAT_TXDATA_ACK0x28
+#define STAT_TXDATA_NAK0x30
+#define STAT_LOST_ARB_38   0x38
 #define STAT_RXADDR_ACK0x40
+#define STAT_RXADDR_NAK0x48
 #define STAT_RXDATA_ACK0x50
+#define STAT_RXDATA_NAK0x58
+#define STAT_SLAVE_60  0x60
+#define STAT_LOST_ARB_68   0x68
+#define STAT_SLAVE_70  0x70
+#define STAT_LOST_ARB_78   0x78
+#define STAT_SLAVE_80  0x80
+#define STAT_SLAVE_88  0x88
+#define STAT_GENDATA_ACK   0x90
+#define STAT_GENDATA_NAK   0x98
+#define STAT_SLAVE_A0  0xA0
+#define STAT_SLAVE_A8  0xA8
+#define STAT_LOST_ARB_B0   0xB0
+#define STAT_SLAVE_LOST0xB8
+#define STAT_SLAVE_NAK 0xC0
+#define STAT_SLAVE_ACK 0xC8
+#define STAT_AD2W_ACK  0xD0
+#define STAT_AD2W_NAK  0xD8
 #define STAT_IDLE  0xF8
 
 /* TWSI_INT values */
+#define TWSI_INT_ST_INTBIT_ULL(0)
+#define TWSI_INT_TS_INTBIT_ULL(1)
+#define TWSI_INT_CORE_INT  BIT_ULL(2)
+#define TWSI_INT_ST_EN BIT_ULL(4)
+#define TWSI_INT_TS_EN BIT_ULL(5)
 #define TWSI_INT_CORE_EN   BIT_ULL(6)
 #define TWSI_INT_SDA_OVR   BIT_ULL(8)
 #define TWSI_INT_SCL_OVR   BIT_ULL(9)
+#define TWSI_INT_SDA   BIT_ULL(10)
+#define TWSI_INT_SCL   BIT_ULL(11)
 
 struct octeon_i2c {
wait_queue_head_t queue;
@@ -77,8 +116,11 @@ struct octeon_i2c {
int sys_freq;
void __iomem *twsi_base;
struct device *dev;
+   bool hlc_enabled;
 };
 
+static int reset_how;
+
 /**
  * octeon_i2c_write_sw - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -87,7 +129,7 @@ struct octeon_i2c {
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u32 data)
 {
u64 tmp;
 
@@ -98,7 +140,7 @@ static void oc

[PATCH v4 03/14] i2c-octeon: Change adapter timeout and retry default values

2016-03-19 Thread Jan Glauber
Convert the adapter timeout to 2 ms instead of a fixed number of
jiffies and set retries to 10.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 9240037..e616e4c 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -414,7 +414,6 @@ static struct i2c_adapter octeon_i2c_ops = {
.owner = THIS_MODULE,
.name = "OCTEON adapter",
.algo = _i2c_algo,
-   .timeout = HZ / 50,
 };
 
 /* calculate and set clock divisors */
@@ -541,6 +540,8 @@ static int octeon_i2c_probe(struct platform_device *pdev)
octeon_i2c_set_clock(i2c);
 
i2c->adap = octeon_i2c_ops;
+   i2c->adap.timeout = msecs_to_jiffies(2);
+   i2c->adap.retries = 10;
i2c->adap.dev.parent = >dev;
i2c->adap.dev.of_node = node;
i2c_set_adapdata(>adap, i2c);
-- 
1.9.1



[PATCH v4 11/14] i2c-octeon: Rename driver to prepare for split

2016-03-19 Thread Jan Glauber
This is just an intermediate commit in preparation of
the driver split. The module rename in this commit
will be reverted in the next patch, this is just done
to make the series bisectible.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Makefile  |2 +-
 drivers/i2c/busses/i2c-octeon-core.c | 1264 ++
 drivers/i2c/busses/i2c-octeon.c  | 1264 --
 3 files changed, 1265 insertions(+), 1265 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819..3405286 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,7 @@ obj-$(CONFIG_I2C_UNIPHIER)+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
-obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon-core.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-octeon-core.c 
b/drivers/i2c/busses/i2c-octeon-core.c
new file mode 100644
index 000..444e8ed
--- /dev/null
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -0,0 +1,1264 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#define DRV_NAME "i2c-octeon"
+
+/* Register offsets */
+#define SW_TWSI0x00
+#define TWSI_INT   0x10
+#define SW_TWSI_EXT0x18
+
+/* Controller command patterns */
+#define SW_TWSI_V  BIT_ULL(63) /* Valid bit */
+#define SW_TWSI_EIABIT_ULL(61) /* Extended internal address */
+#define SW_TWSI_R  BIT_ULL(56) /* Result or read bit */
+#define SW_TWSI_SOVR   BIT_ULL(55) /* Size override */
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_ADDR_SHIFT 40
+#define SW_TWSI_IA_SHIFT   32  /* Internal address */
+
+/* Controller opcode word (bits 60:57) */
+#define SW_TWSI_OP_SHIFT   57
+#define SW_TWSI_OP_7   (0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA(1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10  (2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA   (3ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_TWSI_CLK(4ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
+
+/* Controller extended opcode word (bits 34:32) */
+#define SW_TWSI_EOP_SHIFT  32
+#define SW_TWSI_EOP_TWSI_DATA  (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CTL   (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_CLKCTL(SW_TWSI_OP_EOP | 3ULL << 
SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_STAT  (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT)
+#define SW_TWSI_EOP_TWSI_RST   (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
+
+/* Controller command and status bits */
+#define TWSI_CTL_CE0x80/* High level controller enable */
+#define TWSI_CTL_ENAB  0x40/* Bus enable */
+#define TWSI_CTL_STA   0x20/* Master-mode start, HW clears when 
done */
+#define TWSI_CTL_STP   0x10/* Master-mode stop, HW clears when 
done */
+#define TWSI_CTL_IFLG  0x08/* HW event, SW writes 0 to ACK */
+#define TWSI_CTL_AAK   0x04/* Assert ACK */
+
+/* Some status values */
+#define STAT_ERROR 0x00
+#define STAT_START 0x08
+#define STAT_RSTART0x10
+#define STAT_TXADDR_ACK0x18
+#define STAT_TXADDR_NAK0x20
+#define STAT_TXDATA_ACK0x28
+#define STAT_TXDATA_NAK0x30
+#define STAT_LOST_ARB_38   0x38
+#define STAT_RXADDR_ACK0x40
+#define STAT_RXADDR_NAK0x48
+#define STAT_RXDATA_ACK0x50
+#define STAT_RXDATA_NAK0x58
+#define STAT_SLAVE_60  0x60
+#define STAT_LOST_ARB_68   0x68
+#define STAT_SLAVE_70  0x70
+#define STAT_LOST_ARB_78   0x78
+#define STAT_SLAVE_80  0x80
+#define STAT_SLAVE_88  0x88
+#define STAT_GENDATA_ACK   0x90
+#define STAT_GENDATA_NAK   0x98
+#define STAT

[PATCH v4 04/14] i2c-octeon: Support I2C_M_RECV_LEN

2016-03-19 Thread Jan Glauber
From: David Daney 

If I2C_M_RECV_LEN is set consider the length byte.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 22 +-
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index e616e4c..c21d102 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -315,16 +315,17 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int 
target,
  * @i2c: The struct octeon_i2c
  * @target: Target address
  * @data: Pointer to the location to store the data
- * @length: Length of the data
+ * @rlength: Length of the data
+ * @recv_len: flag for length byte
  *
  * The address is sent over the bus, then the data is read.
  *
  * Returns 0 on success, otherwise a negative errno.
  */
 static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
-  u8 *data, int length)
+  u8 *data, u16 *rlength, bool recv_len)
 {
-   int i, result;
+   int i, result, length = *rlength;
u8 tmp;
 
if (length < 1)
@@ -363,7 +364,17 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int 
target,
return result;
 
data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
+   if (recv_len && i == 0) {
+   if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) {
+   dev_err(i2c->dev,
+   "%s: read len > I2C_SMBUS_BLOCK_MAX 
%d\n",
+   __func__, data[i]);
+   return -EPROTO;
+   }
+   length += data[i];
+   }
}
+   *rlength = length;
return 0;
 }
 
@@ -390,7 +401,7 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap, struct 
i2c_msg *msgs,
 pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD)
ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
- pmsg->len);
+ >len, pmsg->flags & 
I2C_M_RECV_LEN);
else
ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
   pmsg->len);
@@ -402,7 +413,8 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap, struct 
i2c_msg *msgs,
 
 static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
 {
-   return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+   return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+  I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
 }
 
 static const struct i2c_algorithm octeon_i2c_algo = {
-- 
1.9.1



[Resend PATCH 00/10] i2c-octeon and i2c-thunderx drivers

2016-02-29 Thread Jan Glauber
I'm resending both patch series as one since the thunderx driver
depends on the octeon driver patches. Also (subtly) dropping the RFC
in the hope of getting the patches reviewed.

This series for the Octeon i2c driver is an attempt to upstream some
bug fixes and features that accumulated for some time. I tried to
split the cleanup from the other patches and updated the patch
descriptions according to my humble i2c knowledge.

Patches are on top of 4.5-rc6 and were tested on OCTEON, OCTEON-78
and ThunderX.

Jan

--

David Daney (4):
  i2c-octeon: Support I2C_M_RECV_LEN
  i2c-octeon: Enable high-level controller and improve on bus contention
  i2c-octeon: Add support for cn78XX chips
  i2c-octeon: Add workaround for chips with broken irqs

Jan Glauber (4):
  i2c-octeon: Cleanup i2c-octeon driver
  dt-bindings: i2c: add Octeon cn78xx TWSI
  i2c: split i2c-octeon driver and add ThunderX support
  i2c: thunderx: add smbus support

Peter Swain (2):
  i2c-octeon: Flush TWSI writes with readback
  i2c-octeon: Faster operation when IFLG signals late

 .../devicetree/bindings/i2c/i2c-octeon.txt |   6 +
 drivers/i2c/busses/Kconfig |  10 +
 drivers/i2c/busses/Makefile|   3 +
 drivers/i2c/busses/i2c-cavium.c| 828 +
 drivers/i2c/busses/i2c-cavium.h| 191 +
 drivers/i2c/busses/i2c-octeon-core.c   | 302 
 drivers/i2c/busses/i2c-octeon.c| 633 
 drivers/i2c/busses/i2c-thunderx-core.c | 294 
 8 files changed, 1634 insertions(+), 633 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

-- 
1.9.1



[Resend PATCH 09/10] i2c: split i2c-octeon driver and add ThunderX support

2016-02-29 Thread Jan Glauber
The ThunderX SOC uses the same i2c block as the Octeon SOC.
The main difference is that on ThunderX the device is a PCI device
so device probing is done via PCI.

Split the current Octeon driver into an Octeon and a common part
and add the ThunderX support.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Kconfig |   10 +
 drivers/i2c/busses/Makefile|3 +
 drivers/i2c/busses/i2c-cavium.c|  828 +
 drivers/i2c/busses/i2c-cavium.h|  187 +
 drivers/i2c/busses/i2c-octeon-core.c   |  302 
 drivers/i2c/busses/i2c-octeon.c| 1283 
 drivers/i2c/busses/i2c-thunderx-core.c |  263 +++
 7 files changed, 1593 insertions(+), 1283 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7b0aa82..97614b3 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -952,6 +952,16 @@ config I2C_OCTEON
  This driver can also be built as a module.  If so, the module
  will be called i2c-octeon.
 
+config I2C_THUNDERX
+   tristate "Cavium ThunderX I2C bus support"
+   depends on 64BIT && PCI
+   help
+ Say yes if you want to support the I2C serial bus on Cavium
+ ThunderX SOC.
+
+ This driver can also be built as a module.  If so, the module
+ will be called i2c-thunderx.
+
 config I2C_XILINX
tristate "Xilinx I2C Controller"
depends on HAS_IOMEM
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819..a32ff14 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,10 @@ obj-$(CONFIG_I2C_UNIPHIER)   += i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
+i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
 obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+i2c-thunderx-objs := i2c-cavium.o i2c-thunderx-core.o
+obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.c b/drivers/i2c/busses/i2c-cavium.c
new file mode 100644
index 000..93d8c0f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cavium.c
@@ -0,0 +1,828 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+static int reset_how;
+
+/*
+ * On some hardware IFLG is not visible in TWSI_CTL until after low-level IRQ,
+ * so re-sample CTL a short time later to avoid stalls.
+ */
+static int irq_early_us = 80;
+module_param(irq_early_us, int, 0644);
+MODULE_PARM_DESC(irq_early_us, "Re-poll for IFLG after IRQ (us)");
+
+static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+}
+
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(irq_early_us, 2 * irq_early_us);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+   int first = 1;
+   long result;
+
+   if (i2c->broken_irq_mode) {
+  

[Resend PATCH 01/10] i2c-octeon: Cleanup i2c-octeon driver

2016-02-29 Thread Jan Glauber
Cleanup only without functional change.

Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 442 +---
 1 file changed, 230 insertions(+), 212 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 32914ab..1f14094 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -2,7 +2,7 @@
  * (C) Copyright 2009-2010
  * Nokia Siemens Networks, michael.lawnick@nsn.com
  *
- * Portions Copyright (C) 2010, 2011 Cavium Networks, Inc.
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
  *
  * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
  *
@@ -24,99 +24,154 @@
 
 #include 
 
-#define DRV_NAME "i2c-octeon"
+#define DRV_NAME   "i2c-octeon"
 
-/* The previous out-of-tree version was implicitly version 1.0. */
-#define DRV_VERSION"2.0"
+/* Register offsets */
+#define SW_TWSI0x00
+#define TWSI_INT   0x10
+#define SW_TWSI_EXT0x18
 
-/* register offsets */
-#define SW_TWSI 0x00
-#define TWSI_INT 0x10
+#define INT_ENA_ST 0x1
+#define INT_ENA_TS 0x2
+#define INT_ENA_CORE   0x4
 
 /* Controller command patterns */
-#define SW_TWSI_V   0x8000ull
-#define SW_TWSI_EOP_TWSI_DATA   0x0C01ull
-#define SW_TWSI_EOP_TWSI_CTL0x0C02ull
-#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C03ull
-#define SW_TWSI_EOP_TWSI_STAT   0x0C03ull
-#define SW_TWSI_EOP_TWSI_RST0x0C07ull
-#define SW_TWSI_OP_TWSI_CLK 0x0800ull
-#define SW_TWSI_R   0x0100ull
+#define SW_TWSI_V  (1ULL << 63)
+#define SW_TWSI_EIA(1ULL << 61)
+#define SW_TWSI_R  (1ULL << 56)
+#define SW_TWSI_SOVR   (1ULL << 55)
+#define SW_TWSI_OP_7   (0ULL << 57)
+#define SW_TWSI_OP_7_IA(1ULL << 57)
+#define SW_TWSI_OP_10  (2ULL << 57)
+#define SW_TWSI_OP_10_IA   (3ULL << 57)
+#define SW_TWSI_OP_TWSI_CLK(1ULL << 59)
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_A_SHIFT40
+#define SW_TWSI_IA_SHIFT   32
+#define SW_TWSI_EOP_TWSI_DATA  0x0C01ULL
+#define SW_TWSI_EOP_TWSI_CTL   0x0C02ULL
+#define SW_TWSI_EOP_TWSI_CLKCTL0x0C03ULL
+#define SW_TWSI_EOP_TWSI_STAT  0x0C03ULL
+#define SW_TWSI_EOP_TWSI_RST   0x0C07ULL
 
 /* Controller command and status bits */
-#define TWSI_CTL_CE   0x80
-#define TWSI_CTL_ENAB 0x40
-#define TWSI_CTL_STA  0x20
-#define TWSI_CTL_STP  0x10
-#define TWSI_CTL_IFLG 0x08
-#define TWSI_CTL_AAK  0x04
+#define TWSI_CTL_CE0x80/* High level controller enable */
+#define TWSI_CTL_ENAB  0x40/* Bus enable */
+#define TWSI_CTL_STA   0x20/* Master-mode start, HW clears when 
done */
+#define TWSI_CTL_STP   0x10/* Master-mode stop, HW clears when 
done */
+#define TWSI_CTL_IFLG  0x08/* HW event, SW writes 0 to ACK */
+#define TWSI_CTL_AAK   0x04/* Assert ACK */
 
 /* Some status values */
-#define STAT_START  0x08
-#define STAT_RSTART 0x10
-#define STAT_TXADDR_ACK 0x18
-#define STAT_TXDATA_ACK 0x28
-#define STAT_RXADDR_ACK 0x40
-#define STAT_RXDATA_ACK 0x50
-#define STAT_IDLE   0xF8
+#define STAT_ERROR 0x00
+#define STAT_START 0x08
+#define STAT_RSTART0x10
+#define STAT_TXADDR_ACK0x18
+#define STAT_TXADDR_NAK0x20
+#define STAT_TXDATA_ACK0x28
+#define STAT_TXDATA_NAK0x30
+#define STAT_LOST_ARB_38   0x38
+#define STAT_RXADDR_ACK0x40
+#define STAT_RXADDR_NAK0x48
+#define STAT_RXDATA_ACK0x50
+#define STAT_RXDATA_NAK0x58
+#define STAT_SLAVE_60  0x60
+#define STAT_LOST_ARB_68   0x68
+#define STAT_SLAVE_70  0x70
+#define STAT_LOST_ARB_78   0x78
+#define STAT_SLAVE_80  0x80
+#define STAT_SLAVE_88  0x88
+#define STAT_GENDATA_ACK   0x90
+#define STAT_GENDATA_NAK   0x98
+#define STAT_SLAVE_A0  0xA0
+#define STAT_SLAVE_A8  0xA8
+#define STAT_LOST_ARB_B0   0xB0
+#define STAT_SLAVE_LOST0xB8
+#define STAT_SLAVE_NAK 0xC0
+#define STAT_SLAVE_ACK 0xC8
+#define STAT_AD2W_ACK  0xD0
+#define STAT_AD2W_NAK  0xD8
+#define STAT_IDLE  0xF8
+
+/* TWSI_INT values */
+#define ST_INT 0x01
+#define TS_INT 0x02
+#define CORE_INT   0x04
+#define ST_EN  0x10
+#define TS_EN  0x20
+#define CORE_EN0x40
+#define SDA_OVR0x100
+#define SCL_OVR 

[Resend PATCH 02/10] i2c-octeon: Support I2C_M_RECV_LEN

2016-02-29 Thread Jan Glauber
From: David Daney 

If I2C_M_RECV_LEN is set consider the length byte.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 1f14094..fa4d439 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -392,13 +392,14 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int 
target,
  * @target: Target address
  * @data: Pointer to the location to store the data
  * @rlength: Length of the data
+ * @recv_len: flag for length byte
  *
  * The address is sent over the bus, then the data is read.
  *
  * Returns 0 on success, otherwise a negative errno.
  */
 static int octeon_i2c_read(struct octeon_i2c *i2c, int target, u8 *data,
-  u16 *rlength)
+  u16 *rlength, bool recv_len)
 {
int length = *rlength;
int i, result;
@@ -438,6 +439,15 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int 
target, u8 *data,
return result;
 
data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
+   if (recv_len && i == 0) {
+   if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) {
+   dev_err(i2c->dev,
+   "%s: read len > I2C_SMBUS_BLOCK_MAX 
%d\n",
+   __func__, data[i]);
+   return -EIO;
+   }
+   length += data[i];
+   }
}
*rlength = length;
return 0;
@@ -466,7 +476,8 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap, struct 
i2c_msg *msgs,
 pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD)
ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
- >len);
+ >len,
+ pmsg->flags & I2C_M_RECV_LEN);
else
ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
   pmsg->len);
-- 
1.9.1



[Resend PATCH 03/10] i2c-octeon: Enable high-level controller and improve on bus contention

2016-02-29 Thread Jan Glauber
From: David Daney 

Use High Level Controller when possible.

i2c-octeon was reacting badly to bus contention: when in
direct-access mode (for transfers > 8 bytes, which cannot use the
high-level controller) some !ACK or arbitration-loss states were
not causing the current transfer to be aborted, and the bus released.

There's one place in i2c protocol that !ACK is an acceptable
response: in the final byte of a read cycle.  In this case the
destination is not saying that the transfer failed, just that it
doesn't want more data.

This enables correct behavior of ACK on final byte of non-final read
msgs too.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 583 ++--
 1 file changed, 504 insertions(+), 79 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index fa4d439..d48456a 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -113,8 +113,15 @@ struct octeon_i2c {
int sys_freq;
void __iomem*twsi_base;
struct device   *dev;
+   boolhlc_enabled;
 };
 
+static int reset_how;
+
+static int timeout = 2;
+module_param(timeout, int, 0444);
+MODULE_PARM_DESC(timeout, "Low-level device timeout (ms)");
+
 /**
  * octeon_i2c_write_sw - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -123,7 +130,7 @@ struct octeon_i2c {
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u32 data)
 {
u64 tmp;
 
@@ -165,7 +172,7 @@ static u64 octeon_i2c_read_sw64(struct octeon_i2c *i2c, u64 
eop_reg)
  */
 static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
 {
-   return octeon_i2c_read_sw64(i2c, eop_reg);
+   return (u8) octeon_i2c_read_sw64(i2c, eop_reg);
 }
 
 /**
@@ -198,6 +205,15 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
octeon_i2c_write_int(i2c, TS_INT | ST_INT);
 }
 
+static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+}
+
 /**
  * bitbang_unblock - unblock the bus
  * @i2c: The struct octeon_i2c
@@ -207,13 +223,18 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
  */
 static void bitbang_unblock(struct octeon_i2c *i2c)
 {
-   int i;
+   int state, i;
 
+   octeon_i2c_disable_hlc(i2c);
dev_dbg(i2c->dev, "%s\n", __func__);
 
+   /* cycle 8+1 clocks with SDA high */
for (i = 0; i < 9; i++) {
octeon_i2c_write_int(i2c, 0);
udelay(5);
+   state = __raw_readq(i2c->twsi_base + TWSI_INT);
+   if (state & (SDA | SCL))
+   break;
octeon_i2c_write_int(i2c, SCL_OVR);
udelay(5);
}
@@ -236,10 +257,14 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
+static u64 octeon_i2c_read_ctl(struct octeon_i2c *i2c)
+{
+   return octeon_i2c_read_sw64(i2c, SW_TWSI_EOP_TWSI_CTL);
+}
+
 static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 {
-   return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL)
-   & TWSI_CTL_IFLG) != 0;
+   return (octeon_i2c_read_ctl(i2c) & TWSI_CTL_IFLG) != 0;
 }
 
 /**
@@ -263,76 +288,208 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
return 0;
 }
 
-/* send STOP to the bus */
-static void octeon_i2c_stop(struct octeon_i2c *i2c)
+/*
+ * Cleanup low-level state & enable high-level.
+ *
+ * Returns -EAGAIN if low-level state could not be cleaned
+ */
+static int octeon_i2c_enable_hlc(struct octeon_i2c *i2c)
 {
-   u8 data;
+   int try = 0, ret = 0;
+   u64 val;
+
+   if (i2c->hlc_enabled)
+   return 0;
+   else
+   i2c->hlc_enabled = true;
+
+   while (1) {
+   val = octeon_i2c_read_ctl(i2c) & (TWSI_CTL_STA | TWSI_CTL_STP);
+   if (!val)
+   break;
+
+   /* clear _IFLG event */
+   if (val & TWSI_CTL_IFLG)
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+   TWSI_CTL_ENAB);
+
+   if (try++ > 100) {
+   pr_err("%s: giving up\n", __func__);
+   ret = -EAGAIN;
+   break;
+   }
+
+   /* spin until any start/stop has finished */
+   udelay(10);
+   }
 
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
-   TWSI_CTL_ENAB | TWSI_CTL_STP);
+ 

[Resend PATCH 10/10] i2c: thunderx: add smbus support

2016-02-29 Thread Jan Glauber
Add smbus alert interrupt support.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-cavium.h|  4 
 drivers/i2c/busses/i2c-thunderx-core.c | 31 +++
 2 files changed, 35 insertions(+)

diff --git a/drivers/i2c/busses/i2c-cavium.h b/drivers/i2c/busses/i2c-cavium.h
index db80c0f..8357997 100644
--- a/drivers/i2c/busses/i2c-cavium.h
+++ b/drivers/i2c/busses/i2c-cavium.h
@@ -119,6 +119,10 @@ struct octeon_i2c {
 #ifdef CONFIG_ARCH_THUNDER
struct msix_entry   i2c_msix;
 #endif
+#ifdef CONFIG_I2C_SMBUS
+   struct i2c_smbus_alert_setup alert_data;
+   struct i2c_client   *ara;
+#endif
 };
 
 static inline void writeqflush(u64 val, void __iomem *addr)
diff --git a/drivers/i2c/busses/i2c-thunderx-core.c 
b/drivers/i2c/busses/i2c-thunderx-core.c
index 0a95891..396c8bc 100644
--- a/drivers/i2c/busses/i2c-thunderx-core.c
+++ b/drivers/i2c/busses/i2c-thunderx-core.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -104,6 +105,34 @@ static void thunder_i2c_clock_disable(struct device *dev, 
struct clk *clk)
devm_clk_put(dev, clk);
 }
 
+static void thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
+  struct device_node *node)
+{
+#ifdef CONFIG_I2C_SMBUS
+   u32 type;
+
+   i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
+   if (!i2c->alert_data.irq)
+   return;
+
+   type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
+   i2c->alert_data.alert_edge_triggered =
+   (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
+
+   i2c->ara = i2c_setup_smbus_alert(>adap, >alert_data);
+   if (!i2c->ara)
+   dev_err(dev, "Failed to setup smbalert\n");
+#endif
+}
+
+static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
+{
+#ifdef CONFIG_I2C_SMBUS
+   if (i2c->ara)
+   i2c_unregister_device(i2c->ara);
+#endif
+}
+
 static void thunder_i2c_set_name(struct pci_dev *pdev, struct octeon_i2c *i2c,
 char *name)
 {
@@ -202,6 +231,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
goto out_irq;
}
 
+   thunder_i2c_smbus_setup(i2c, node);
dev_info(i2c->dev, "probed\n");
return 0;
 
@@ -232,6 +262,7 @@ static void thunder_i2c_remove_pci(struct pci_dev *pdev)
 
dev = i2c->dev;
thunder_i2c_clock_disable(dev, i2c->clk);
+   thunder_i2c_smbus_remove(i2c);
i2c_del_adapter(>adap);
devm_free_irq(dev, i2c->i2c_msix.vector, i2c);
pci_disable_msix(pdev);
-- 
1.9.1



[Resend PATCH 06/10] i2c-octeon: Flush TWSI writes with readback

2016-02-29 Thread Jan Glauber
From: Peter Swain 

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 19 ---
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 0b28d8c..bb15a9c 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -130,6 +130,12 @@ static int timeout = 2;
 module_param(timeout, int, 0444);
 MODULE_PARM_DESC(timeout, "Low-level device timeout (ms)");
 
+static void writeqflush(u64 val, void __iomem *addr)
+{
+   __raw_writeq(val, addr);
+   __raw_readq(addr);  /* wait for write to land */
+}
+
 /**
  * octeon_i2c_write_sw - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -190,8 +196,7 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 
eop_reg)
  */
 static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
 {
-   __raw_writeq(data, i2c->twsi_base + TWSI_INT);
-   __raw_readq(i2c->twsi_base + TWSI_INT);
+   writeqflush(data, i2c->twsi_base + TWSI_INT);
 }
 
 /**
@@ -797,10 +802,10 @@ static int octeon_i2c_simple_write(struct octeon_i2c 
*i2c, struct i2c_msg *msgs)
 
for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
ext |= (u64) msgs[0].buf[j] << (8 * i);
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
}
 
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -846,7 +851,7 @@ static int octeon_i2c_ia_read(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
cmd |= (u64) msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -906,10 +911,10 @@ static int octeon_i2c_ia_write(struct octeon_i2c *i2c, 
struct i2c_msg *msgs)
set_ext = true;
}
if (set_ext)
-   __raw_writeq(ext, i2c->twsi_base + SW_TWSI_EXT);
+   writeqflush(ext, i2c->twsi_base + SW_TWSI_EXT);
 
octeon_i2c_hlc_int_clear(i2c);
-   __raw_writeq(cmd, i2c->twsi_base + SW_TWSI);
+   writeqflush(cmd, i2c->twsi_base + SW_TWSI);
 
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
-- 
1.9.1



[Resend PATCH 04/10] dt-bindings: i2c: add Octeon cn78xx TWSI

2016-02-29 Thread Jan Glauber
Add compatible string for Cavium Octeon cn78XX SOCs TWSI.

Cc: Rob Herring 
Cc: Pawel Moll 
Cc: Mark Rutland 
Cc: Ian Campbell 
Cc: Kumar Gala 

Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 Documentation/devicetree/bindings/i2c/i2c-octeon.txt | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt 
b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
index dced82e..872d485 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-octeon.txt
@@ -4,6 +4,12 @@
 
   Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
 
+  or
+
+  compatible: "cavium,octeon-7890-twsi"
+
+  Compatibility with cn78XX SOCs.
+
 - reg: The base address of the TWSI/I2C bus controller register bank.
 
 - #address-cells: Must be <1>.
-- 
1.9.1



[Resend PATCH 08/10] i2c-octeon: Add workaround for chips with broken irqs

2016-02-29 Thread Jan Glauber
From: David Daney 

CN3860 does not interrupt the CPU when the i2c status changes.  If
we get a timeout, and see the status has in fact changed, we know we
have this problem, and drop back to polling.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 46 +
 1 file changed, 46 insertions(+)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index e3552e5..3c2f848 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -115,6 +115,7 @@ struct octeon_i2c {
int sys_freq;
void __iomem*twsi_base;
struct device   *dev;
+   int broken_irq_mode;
boolhlc_enabled;
void(*int_en)   (struct octeon_i2c *);
void(*int_dis)  (struct octeon_i2c *);
@@ -382,10 +383,33 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
int first = 1;
long result;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_test_iflg(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->int_en(i2c);
result = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
i2c->adap.timeout);
i2c->int_dis(i2c);
+
+   if (result <= 0 && OCTEON_IS_MODEL(OCTEON_CN38XX) &&
+   octeon_i2c_test_iflg(i2c)) {
+   dev_err(i2c->dev,
+   "broken irq connection detected, switching to polling 
mode.\n");
+   i2c->broken_irq_mode = 1;
+   return 0;
+   }
if (!result) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -740,6 +764,21 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int result;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some cn38xx boards did not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_hlc_test_ready(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_hlc_test_ready(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->hlc_int_en(i2c);
result = wait_event_interruptible_timeout(i2c->queue,
octeon_i2c_hlc_test_ready(i2c), i2c->adap.timeout);
@@ -747,6 +786,13 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
if (!result)
octeon_i2c_hlc_int_clear(i2c);
 
+   if (result <= 0 && OCTEON_IS_MODEL(OCTEON_CN38XX) &&
+   octeon_i2c_hlc_test_ready(i2c)) {
+   dev_err(i2c->dev, "broken irq connection detected, switching to 
polling mode.\n");
+   i2c->broken_irq_mode = 1;
+   return 0;
+   }
+
if (result < 0) {
dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
return result;
-- 
1.9.1



[Resend PATCH 05/10] i2c-octeon: Add support for cn78XX chips

2016-02-29 Thread Jan Glauber
From: David Daney 

cn78XX has a different interrupt architecture, so we have to manage
the interrupts differently.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 156 ++--
 1 file changed, 136 insertions(+), 20 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index d48456a..0b28d8c 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -109,11 +110,18 @@ struct octeon_i2c {
wait_queue_head_t   queue;
struct i2c_adapter  adap;
int irq;
+   int hlc_irq;/* For cn7890 only */
u32 twsi_freq;
int sys_freq;
void __iomem*twsi_base;
struct device   *dev;
boolhlc_enabled;
+   void(*int_en)   (struct octeon_i2c *);
+   void(*int_dis)  (struct octeon_i2c *);
+   void(*hlc_int_en)   (struct octeon_i2c *);
+   void(*hlc_int_dis)  (struct octeon_i2c *);
+   atomic_tint_en_cnt;
+   atomic_thlc_int_en_cnt;
 };
 
 static int reset_how;
@@ -215,6 +223,58 @@ static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
 }
 
 /**
+ * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
+{
+   atomic_inc_return(>int_en_cnt);
+   enable_irq(i2c->irq);
+}
+
+static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+{
+   int count;
+
+   /*
+* The interrupt can be disabled in two places, but we only
+* want to make the disable_irq_nosync() call once, so keep
+* track with the atomic variable.
+*/
+   count = atomic_dec_if_positive(cnt);
+   if (count >= 0)
+   disable_irq_nosync(irq);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+{
+   __octeon_i2c_irq_disable(>int_en_cnt, i2c->irq);
+}
+
+/**
+ * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+{
+   atomic_inc_return(>hlc_int_en_cnt);
+   enable_irq(i2c->hlc_irq);
+}
+
+/* disable the ST interrupt */
+static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+{
+   __octeon_i2c_irq_disable(>hlc_int_en_cnt, i2c->hlc_irq);
+}
+
+/**
  * bitbang_unblock - unblock the bus
  * @i2c: The struct octeon_i2c
  *
@@ -251,7 +311,18 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 {
struct octeon_i2c *i2c = dev_id;
 
-   octeon_i2c_int_disable(i2c);
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+/* interrupt service routine */
+static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->hlc_int_dis(i2c);
wake_up(>queue);
 
return IRQ_HANDLED;
@@ -277,10 +348,10 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
long result;
 
-   octeon_i2c_int_enable(i2c);
+   i2c->int_en(i2c);
result = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
i2c->adap.timeout);
-   octeon_i2c_int_disable(i2c);
+   i2c->int_dis(i2c);
if (!result) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -300,8 +371,8 @@ static int octeon_i2c_enable_hlc(struct octeon_i2c *i2c)
 
if (i2c->hlc_enabled)
return 0;
-   else
-   i2c->hlc_enabled = true;
+
+   i2c->hlc_enabled = true;
 
while (1) {
val = octeon_i2c_read_ctl(i2c) & (TWSI_CTL_STA | TWSI_CTL_STP);
@@ -635,11 +706,10 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int result;
 
-   octeon_i2c_hlc_int_enable(i2c);
+   i2c->hlc_int_en(i2c);
result = wait_event_interruptible_timeout(i2c->queue,
- 
octeon_i2c_hlc_test_ready(i2c),
- i2c->adap.timeout);
-   octeon_i2c_int_disable(i2c);
+   octeon_i2c_hlc_test_ready(i2c), i2c->adap.timeout);
+   i2c->hlc_int_dis(i2c);
if (!result)
oc

[Resend PATCH 07/10] i2c-octeon: Faster operation when IFLG signals late

2016-02-29 Thread Jan Glauber
From: Peter Swain 

Some versions can deliver low-level twsi irq before twsi_ctl.iflg
is set, leading to timeout-driven i/o.
When an irq signals event, but woken task does not see the expected
twsi_ctl.iflg, re-check about 80uS later.

EEPROM reads on 100kHz i2c now measure ~5.2kB/s, about 1/2 what's
achievable, and much better than the worst-case 100 bytes/sec before.

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 31 ++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index bb15a9c..e3552e5 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -130,6 +130,14 @@ static int timeout = 2;
 module_param(timeout, int, 0444);
 MODULE_PARM_DESC(timeout, "Low-level device timeout (ms)");
 
+/*
+ * On some hardware IFLG is not visible in TWSI_CTL until after low-level IRQ,
+ * so re-sample CTL a short time later to avoid stalls.
+ */
+static int irq_early_us = 80;
+module_param(irq_early_us, int, 0644);
+MODULE_PARM_DESC(irq_early_us, "Re-poll for IFLG after IRQ (us)");
+
 static void writeqflush(u64 val, void __iomem *addr)
 {
__raw_writeq(val, addr);
@@ -343,6 +351,26 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
return (octeon_i2c_read_ctl(i2c) & TWSI_CTL_IFLG) != 0;
 }
 
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(irq_early_us, 2 * irq_early_us);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
 /**
  * octeon_i2c_wait - wait for the IFLG to be set
  * @i2c: The struct octeon_i2c
@@ -351,10 +379,11 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
  */
 static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
+   int first = 1;
long result;
 
i2c->int_en(i2c);
-   result = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
+   result = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
i2c->adap.timeout);
i2c->int_dis(i2c);
if (!result) {
-- 
1.9.1



Re: [PATCH v4 4/5] arm64/perf: Enable PMCR long cycle counter bit

2016-02-29 Thread Jan Glauber
On Mon, Feb 29, 2016 at 03:39:35PM +, Will Deacon wrote:
> Hi Jan,
> 
> I've queued this lot on my perf/updates branch, but I just noticed an
> oddity whilst dealing with some potential conflicts with the kvm tree.
> 
> On Thu, Feb 18, 2016 at 05:50:13PM +0100, Jan Glauber wrote:
> > With the long cycle counter bit (LC) disabled the cycle counter is not
> > working on ThunderX SOC (ThunderX only implements Aarch64).
> > Also, according to documentation LC == 0 is deprecated.
> > 
> > To keep the code simple the patch does not introduce 64 bit wide counter
> > functions. Instead writing the cycle counter always sets the upper
> > 32 bits so overflow interrupts are generated as before.
> > 
> > Original patch from Andrew Pinksi 
> > 
> > Signed-off-by: Jan Glauber 
> > ---
> >  arch/arm64/kernel/perf_event.c | 21 -
> >  1 file changed, 16 insertions(+), 5 deletions(-)
> > 
> > diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
> > index 0ed05f6..c68fa98 100644
> > --- a/arch/arm64/kernel/perf_event.c
> > +++ b/arch/arm64/kernel/perf_event.c
> > @@ -405,6 +405,7 @@ static const struct attribute_group 
> > *armv8_pmuv3_attr_groups[] = {
> >  #define ARMV8_PMCR_D   (1 << 3) /* CCNT counts every 64th cpu 
> > cycle */
> >  #define ARMV8_PMCR_X   (1 << 4) /* Export to ETM */
> >  #define ARMV8_PMCR_DP  (1 << 5) /* Disable CCNT if 
> > non-invasive debug*/
> > +#define ARMV8_PMCR_LC  (1 << 6) /* Overflow on 64 bit cycle 
> > counter */
> >  #defineARMV8_PMCR_N_SHIFT  11   /* Number of counters 
> > supported */
> >  #defineARMV8_PMCR_N_MASK   0x1f
> >  #defineARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
> 
> You haven't extended this mask to cover the LC bit, so it will be ignored
> by armv8pmu_pmcr_write afaict.

This is weird. I've double checked and I missed this mask. Annoying.
Nevertheless it works for me without the LC bit set.

> How did you test this? I can easily update the mask, but it would be
> good to know that it doesn't end up cause a breakage.
 
For testing I used:
- perf top and perf record & report
- looked at interrupt numbers in /proc/interrupts

Without the patch _no_ samples at all are recorded and the interrupt does
not occur. With the patch I get samples and see a reasonable number of
interrupts.

Extending the mask so the LC bit is covered would make sense, I'm going
to test this now.

Jan

> Will


Re: [PATCH v3 02/14] i2c-octeon: Cleanup i2c-octeon driver

2016-03-14 Thread Jan Glauber
On Sat, Mar 12, 2016 at 04:35:00PM +0100, Wolfram Sang wrote:
> On Mon, Mar 07, 2016 at 04:10:45PM +0100, Jan Glauber wrote:
> > Cleanup only without functional change.
> 
> I like most of the changes, but there are still some functional changes
> left.
> 
> > -static int octeon_i2c_stop(struct octeon_i2c *i2c)
> > +/* send STOP to the bus */
> > +static void octeon_i2c_stop(struct octeon_i2c *i2c)
> >  {
> > u8 data;
> >  
> > @@ -266,11 +259,8 @@ static int octeon_i2c_stop(struct octeon_i2c *i2c)
> >  
> > data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
> >  
> > -   if (data != STAT_IDLE) {
> > +   if (data != STAT_IDLE)
> > dev_err(i2c->dev, "%s: bad status(0x%x)\n", __func__, data);
> > -   return -EIO;
> > -   }
> > -   return 0;
> 
> Why this change? I don't know what SW_TWSI_EOP_TWSI_STAT tells, but this
> is surely not a cleanup.

It is no functional change because the return value of
octeon_i2c_stop() was ignored anyway. That said, the whole read-back of
the status and the dev_err looks like debug code to me and is removed
in a later patch anyway. I'll incoporate this in the cleanup,
so octeon_i2c_stop() will only do the write.

> > octeon_i2c_stop(i2c);
> >  
> > -   return (ret != 0) ? ret : num;
> > +   return ret ? -EAGAIN : num;
> 
> This is also not a cleanup and looks wrong. -EAGAIN is for lost
> arbitration only.

I agree, this looks like an over-simplification and drops
the EINVAL/ETIMEDOUT/EIO errors. I'll drop that completely.

> >  
> > -static struct of_device_id octeon_i2c_match[] = {
> > -   {
> > -   .compatible = "cavium,octeon-3860-twsi",
> > -   },
> > +static const struct of_device_id octeon_i2c_match[] = {
> > +   {   .compatible = "cavium,octeon-3860-twsi",},
> 
> Nit: I'd prefer no tabs within the curly braces.

Agreed.

thanks, Jan

> Thanks,
> 
>Wolfram
> 




Re: [PATCH v3 03/14] i2c-octeon: Cleanup resource allocation code

2016-03-14 Thread Jan Glauber
On Sat, Mar 12, 2016 at 04:37:15PM +0100, Wolfram Sang wrote:
> On Mon, Mar 07, 2016 at 04:10:46PM +0100, Jan Glauber wrote:
> > From: David Daney 
> > 
> > Use resource start and size directly.
> > 
> > Signed-off-by: David Daney 
> > Signed-off-by: Jan Glauber 
> 
> What about converting to devm_ioremap_resource()?
> 

Nice. I'll use that.


Re: [PATCH v3 05/14] i2c-octeon: Make adapter timeout tunable

2016-03-14 Thread Jan Glauber
On Sat, Mar 12, 2016 at 04:46:12PM +0100, Wolfram Sang wrote:
> On Mon, Mar 07, 2016 at 04:10:48PM +0100, Jan Glauber wrote:
> > From: Peter Swain 
> > 
> > Make the i2c adapter timeout a module parameter to allow upper-level
> > target device drivers to retry with their own logic before their own
> > timeouts abort operations.
> > 
> > For example, at24 eeprom driver retries for 25ms when -EAGAIN
> > indicates that an eeprom has gone unresponsive while committing
> > a newly written page (5ms on typical devices).
> > 
> > Signed-off-by: Peter Swain 
> > Signed-off-by: Jan Glauber 
> 
> i2c-dev has IOCTLs for timeout and retries. Can't you use those?
> 

Yes, with these IOCTLs we don't need to add a module parameter
so I'll drop that.


[PATCH v2 1/5] arm64/perf: Rename Cortex A57 events

2016-01-28 Thread Jan Glauber
The implemented Cortex A57 events are not A57 specific.
They are recommended by ARM and can be found on other
ARMv8 SOCs like Cavium ThunderX too. Therefore move
these events to the common PMUv3 table.

Signed-off-by: Jan Glauber 
---
 arch/arm64/kernel/perf_event.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index f7ab14c..32fe656 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -87,17 +87,17 @@
 #define ARMV8_PMUV3_PERFCTR_L2D_TLB0x2F
 #define ARMV8_PMUV3_PERFCTR_L21_TLB0x30
 
+/* Recommended events. */
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS_LD0x40
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS_ST0x41
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL_LD0x42
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL_ST0x43
+#define ARMV8_PMUV3_PERFCTR_DTLB_REFILL_LD 0x4C
+#define ARMV8_PMUV3_PERFCTR_DTLB_REFILL_ST 0x4D
+
 /* ARMv8 Cortex-A53 specific event types. */
 #define ARMV8_A53_PERFCTR_PREFETCH_LINEFILL0xC2
 
-/* ARMv8 Cortex-A57 and Cortex-A72 specific event types. */
-#define ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD  0x40
-#define ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST  0x41
-#define ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD  0x42
-#define ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST  0x43
-#define ARMV8_A57_PERFCTR_DTLB_REFILL_LD   0x4c
-#define ARMV8_A57_PERFCTR_DTLB_REFILL_ST   0x4d
-
 /* PMUv3 HW events mapping. */
 static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
PERF_MAP_ALL_UNSUPPORTED,
@@ -174,16 +174,16 @@ static const unsigned 
armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
  [PERF_COUNT_HW_CACHE_RESULT_MAX] 
= {
PERF_CACHE_MAP_ALL_UNSUPPORTED,
 
-   [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)]  = 
ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD,
-   [C(L1D)][C(OP_READ)][C(RESULT_MISS)]= 
ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD,
-   [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = 
ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST,
-   [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]   = 
ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST,
+   [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)]  = 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS_LD,
+   [C(L1D)][C(OP_READ)][C(RESULT_MISS)]= 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL_LD,
+   [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS_ST,
+   [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]   = 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL_ST,
 
[C(L1I)][C(OP_READ)][C(RESULT_ACCESS)]  = 
ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS,
[C(L1I)][C(OP_READ)][C(RESULT_MISS)]= 
ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL,
 
-   [C(DTLB)][C(OP_READ)][C(RESULT_MISS)]   = 
ARMV8_A57_PERFCTR_DTLB_REFILL_LD,
-   [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]  = 
ARMV8_A57_PERFCTR_DTLB_REFILL_ST,
+   [C(DTLB)][C(OP_READ)][C(RESULT_MISS)]   = 
ARMV8_PMUV3_PERFCTR_DTLB_REFILL_LD,
+   [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]  = 
ARMV8_PMUV3_PERFCTR_DTLB_REFILL_ST,
 
[C(ITLB)][C(OP_READ)][C(RESULT_MISS)]   = 
ARMV8_PMUV3_PERFCTR_ITLB_REFILL,
 
-- 
1.9.1



[PATCH v2 4/5] arm64/perf: Enable PMCR long cycle counter bit

2016-01-28 Thread Jan Glauber
With the long cycle counter bit (LC) disabled the cycle counter is not
working on ThunderX SOC (ThunderX only implements Aarch64).
Also, according to documentation LC == 0 is deprecated.

To keep the code simple the patch does not introduce 64 bit wide counter
functions. Instead writing the cycle counter always sets the upper
32 bits so overflow interrupts are generated as before.

Original patch from Andrew Pinksi 

Signed-off-by: Jan Glauber 
---
 arch/arm64/kernel/perf_event.c | 21 -
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index c038e4e..5e4275e 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -405,6 +405,7 @@ static const struct attribute_group 
*armv8_pmuv3_attr_groups[] = {
 #define ARMV8_PMCR_D   (1 << 3) /* CCNT counts every 64th cpu cycle */
 #define ARMV8_PMCR_X   (1 << 4) /* Export to ETM */
 #define ARMV8_PMCR_DP  (1 << 5) /* Disable CCNT if non-invasive debug*/
+#define ARMV8_PMCR_LC  (1 << 6) /* Overflow on 64 bit cycle counter */
 #defineARMV8_PMCR_N_SHIFT  11   /* Number of counters 
supported */
 #defineARMV8_PMCR_N_MASK   0x1f
 #defineARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
@@ -494,9 +495,16 @@ static inline void armv8pmu_write_counter(struct 
perf_event *event, u32 value)
if (!armv8pmu_counter_valid(cpu_pmu, idx))
pr_err("CPU%u writing wrong counter %d\n",
smp_processor_id(), idx);
-   else if (idx == ARMV8_IDX_CYCLE_COUNTER)
-   asm volatile("msr pmccntr_el0, %0" :: "r" (value));
-   else if (armv8pmu_select_counter(idx) == idx)
+   else if (idx == ARMV8_IDX_CYCLE_COUNTER) {
+   /*
+* Set the upper 32bits as this is a 64bit counter but we only
+* count using the lower 32bits and we want an interrupt when
+* it overflows.
+*/
+   u64 value64 = 0xULL | value;
+
+   asm volatile("msr pmccntr_el0, %0" :: "r" (value64));
+   } else if (armv8pmu_select_counter(idx) == idx)
asm volatile("msr pmxevcntr_el0, %0" :: "r" (value));
 }
 
@@ -768,8 +776,11 @@ static void armv8pmu_reset(void *info)
armv8pmu_disable_intens(idx);
}
 
-   /* Initialize & Reset PMNC: C and P bits. */
-   armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C);
+   /*
+* Initialize & Reset PMNC. Request overflow on 64 bit but
+* cheat in armv8pmu_write_counter().
+*/
+   armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C | ARMV8_PMCR_LC);
 }
 
 static int armv8_pmuv3_map_event(struct perf_event *event)
-- 
1.9.1



[PATCH v2 2/5] arm64/perf: Add Cavium ThunderX PMU support

2016-01-28 Thread Jan Glauber
Support PMU events on Caviums ThunderX SOC. ThunderX supports
some additional counters compared to the default ARMv8 PMUv3:

- branch instructions counter
- stall frontend & backend counters
- L1 dcache load & store counters
- L1 icache counters
- iTLB & dTLB counters
- L1 dcache & icache prefetch counters

Signed-off-by: Jan Glauber 
---
 arch/arm64/kernel/perf_event.c | 69 +-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 32fe656..c038e4e 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -94,10 +94,19 @@
 #define ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL_ST0x43
 #define ARMV8_PMUV3_PERFCTR_DTLB_REFILL_LD 0x4C
 #define ARMV8_PMUV3_PERFCTR_DTLB_REFILL_ST 0x4D
+#define ARMV8_PMUV3_PERFCTR_DTLB_ACCESS_LD 0x4E
+#define ARMV8_PMUV3_PERFCTR_DTLB_ACCESS_ST 0x4F
 
 /* ARMv8 Cortex-A53 specific event types. */
 #define ARMV8_A53_PERFCTR_PREFETCH_LINEFILL0xC2
 
+/* ARMv8 Cavium Thunder specific event types. */
+#define ARMV8_THUNDER_PERFCTR_L1_DCACHE_MISS_ST0xE9
+#define ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_ACCESS0xEA
+#define ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_MISS  0xEB
+#define ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_ACCESS0xEC
+#define ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_MISS  0xED
+
 /* PMUv3 HW events mapping. */
 static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
PERF_MAP_ALL_UNSUPPORTED,
@@ -131,6 +140,18 @@ static const unsigned 
armv8_a57_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_BUS_CYCLES]  = 
ARMV8_PMUV3_PERFCTR_BUS_CYCLES,
 };
 
+static const unsigned armv8_thunder_perf_map[PERF_COUNT_HW_MAX] = {
+   PERF_MAP_ALL_UNSUPPORTED,
+   [PERF_COUNT_HW_CPU_CYCLES]  = 
ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES,
+   [PERF_COUNT_HW_INSTRUCTIONS]= 
ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED,
+   [PERF_COUNT_HW_CACHE_REFERENCES]= 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS,
+   [PERF_COUNT_HW_CACHE_MISSES]= 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL,
+   [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV8_PMUV3_PERFCTR_PC_WRITE,
+   [PERF_COUNT_HW_BRANCH_MISSES]   = 
ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+   [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 
ARMV8_PMUV3_PERFCTR_STALL_FRONTEND,
+   [PERF_COUNT_HW_STALLED_CYCLES_BACKEND]  = 
ARMV8_PMUV3_PERFCTR_STALL_BACKEND,
+};
+
 static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]

[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
@@ -193,6 +214,36 @@ static const unsigned 
armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[C(BPU)][C(OP_WRITE)][C(RESULT_MISS)]   = 
ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
 };
 
+static const unsigned armv8_thunder_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+  [PERF_COUNT_HW_CACHE_OP_MAX]
+  
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+   PERF_CACHE_MAP_ALL_UNSUPPORTED,
+
+   [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)]  = 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS_LD,
+   [C(L1D)][C(OP_READ)][C(RESULT_MISS)]= 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL_LD,
+   [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = 
ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS_ST,
+   [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]   = 
ARMV8_THUNDER_PERFCTR_L1_DCACHE_MISS_ST,
+   [C(L1D)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = 
ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_ACCESS,
+   [C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = 
ARMV8_THUNDER_PERFCTR_L1_DCACHE_PREF_MISS,
+
+   [C(L1I)][C(OP_READ)][C(RESULT_ACCESS)]  = 
ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS,
+   [C(L1I)][C(OP_READ)][C(RESULT_MISS)]= 
ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL,
+   [C(L1I)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = 
ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_ACCESS,
+   [C(L1I)][C(OP_PREFETCH)][C(RESULT_MISS)] = 
ARMV8_THUNDER_PERFCTR_L1_ICACHE_PREF_MISS,
+
+   [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = 
ARMV8_PMUV3_PERFCTR_DTLB_ACCESS_LD,
+   [C(DTLB)][C(OP_READ)][C(RESULT_MISS)]   = 
ARMV8_PMUV3_PERFCTR_DTLB_REFILL_LD,
+   [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = 
ARMV8_PMUV3_PERFCTR_DTLB_ACCESS_ST,
+   [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]  = 
ARMV8_PMUV3_PERFCTR_DTLB_REFILL_ST,
+
+   [C(ITLB)][C(OP_READ)][C(RESULT_MISS)]   = 
ARMV8_PMUV3_PERFCTR_ITLB_REFILL,
+
+   [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)]  = 
ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED,
+   [C(BPU)][C(OP_READ)][C(RESULT_MISS)]= 
ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
+   [C(BPU)][C(OP_WRITE)]

[PATCH v2 5/5] arm64/perf: Extend event mask for ARMv8.1

2016-01-28 Thread Jan Glauber
ARMv8.1 increases the PMU event number space. Detect the
presence of this PMUv3 type and extend the event mask.

The event mask is moved to struct arm_pmu so different event masks
can exist, depending on the PMU type.

Signed-off-by: Jan Glauber 
---
 arch/arm64/kernel/perf_event.c | 33 +++--
 drivers/perf/arm_pmu.c |  5 +++--
 include/linux/perf/arm_pmu.h   |  4 ++--
 3 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5e4275e..78b24cb 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -419,7 +419,7 @@ static const struct attribute_group 
*armv8_pmuv3_attr_groups[] = {
 /*
  * PMXEVTYPER: Event selection reg
  */
-#defineARMV8_EVTYPE_MASK   0xc80003ff  /* Mask for writable 
bits */
+#defineARMV8_EVTYPE_FLT_MASK   0xc800  /* Writable filter bits 
*/
 #defineARMV8_EVTYPE_EVENT  0x3ff   /* Mask for EVENT bits 
*/
 
 /*
@@ -510,10 +510,8 @@ static inline void armv8pmu_write_counter(struct 
perf_event *event, u32 value)
 
 static inline void armv8pmu_write_evtype(int idx, u32 val)
 {
-   if (armv8pmu_select_counter(idx) == idx) {
-   val &= ARMV8_EVTYPE_MASK;
+   if (armv8pmu_select_counter(idx) == idx)
asm volatile("msr pmxevtyper_el0, %0" :: "r" (val));
-   }
 }
 
 static inline int armv8pmu_enable_counter(int idx)
@@ -570,6 +568,7 @@ static void armv8pmu_enable_event(struct perf_event *event)
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
+   u32 val;
 
/*
 * Enable counter and interrupt, and set the counter to count
@@ -585,7 +584,8 @@ static void armv8pmu_enable_event(struct perf_event *event)
/*
 * Set event (if destined for PMNx counters).
 */
-   armv8pmu_write_evtype(idx, hwc->config_base);
+   val = hwc->config_base & (ARMV8_EVTYPE_FLT_MASK | cpu_pmu->event_mask);
+   armv8pmu_write_evtype(idx, val);
 
/*
 * Enable interrupt for this counter
@@ -716,7 +716,7 @@ static int armv8pmu_get_event_idx(struct pmu_hw_events 
*cpuc,
int idx;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = >hw;
-   unsigned long evtype = hwc->config_base & ARMV8_EVTYPE_EVENT;
+   unsigned long evtype = hwc->config_base & cpu_pmu->event_mask;
 
/* Always place a cycle counter into the cycle counter. */
if (evtype == ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES) {
@@ -786,29 +786,25 @@ static void armv8pmu_reset(void *info)
 static int armv8_pmuv3_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _pmuv3_perf_map,
-   _pmuv3_perf_cache_map,
-   ARMV8_EVTYPE_EVENT);
+   _pmuv3_perf_cache_map);
 }
 
 static int armv8_a53_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a53_perf_map,
-   _a53_perf_cache_map,
-   ARMV8_EVTYPE_EVENT);
+   _a53_perf_cache_map);
 }
 
 static int armv8_a57_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a57_perf_map,
-   _a57_perf_cache_map,
-   ARMV8_EVTYPE_EVENT);
+   _a57_perf_cache_map);
 }
 
 static int armv8_thunder_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _thunder_perf_map,
-   _thunder_perf_cache_map,
-   ARMV8_EVTYPE_EVENT);
+   _thunder_perf_cache_map);
 }
 
 static void armv8pmu_read_num_pmnc_events(void *info)
@@ -831,6 +827,8 @@ static int armv8pmu_probe_num_events(struct arm_pmu 
*arm_pmu)
 
 static void armv8_pmu_init(struct arm_pmu *cpu_pmu)
 {
+   u64 id;
+
cpu_pmu->handle_irq = armv8pmu_handle_irq,
cpu_pmu->enable = armv8pmu_enable_event,
cpu_pmu->disable= armv8pmu_disable_event,
@@ -842,6 +840,13 @@ static void armv8_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->reset  = armv8pmu_reset,
cpu_pmu->max_period = (1LLU << 32) - 1,
cpu_pmu->set_event_filter   = armv8pmu_set_event_filter;
+
+   /* detect ARMv8.1 PMUv3 with extended event mask */
+   id = read_cpuid(ID_AA64DFR0_EL1);
+   if (((id >> 8) & 0xf) == 4)
+   cpu_pmu->event_mask = 0x;   /* ARMv8.1 extended events */
+   else
+   cpu_pmu->event_mask = ARMV8_EVTYPE_EVENT;
 }
 
 static int armv8_pmuv3_init(struct arm_pmu *cpu_

[PATCH v2 3/5] arm64: dts: Add Cavium ThunderX specific PMU

2016-01-28 Thread Jan Glauber
Add a compatible string for the Cavium ThunderX PMU.

Signed-off-by: Jan Glauber 
---
 Documentation/devicetree/bindings/arm/pmu.txt | 1 +
 arch/arm64/boot/dts/cavium/thunder-88xx.dtsi  | 5 +
 2 files changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/pmu.txt 
b/Documentation/devicetree/bindings/arm/pmu.txt
index 5651883..d3999a1 100644
--- a/Documentation/devicetree/bindings/arm/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/pmu.txt
@@ -25,6 +25,7 @@ Required properties:
"qcom,scorpion-pmu"
"qcom,scorpion-mp-pmu"
"qcom,krait-pmu"
+   "cavium,thunder-pmu"
 - interrupts : 1 combined interrupt or 1 per core. If the interrupt is a 
per-cpu
interrupt (PPI) then 1 interrupt should be specified.
 
diff --git a/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi 
b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
index 9cb7cf9..2eb9b22 100644
--- a/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
+++ b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
@@ -360,6 +360,11 @@
 <1 10 0xff01>;
};
 
+   pmu {
+   compatible = "cavium,thunder-pmu", "arm,armv8-pmuv3";
+   interrupts = <1 7 4>;
+   };
+
soc {
compatible = "simple-bus";
#address-cells = <2>;
-- 
1.9.1



[PATCH v2 0/5] Cavium ThunderX PMU support

2016-01-28 Thread Jan Glauber
Hi Mark & Will,

I'm resending the arm64 PMU patches. The only difference to the first
version is that I dropped the x on thunder in order to be consistent
with the existing device tree name.

Thanks,
Jan

Jan Glauber (5):
  arm64/perf: Rename Cortex A57 events
  arm64/perf: Add Cavium ThunderX PMU support
  arm64: dts: Add Cavium ThunderX specific PMU
  arm64/perf: Enable PMCR long cycle counter bit
  arm64/perf: Extend event mask for ARMv8.1

 Documentation/devicetree/bindings/arm/pmu.txt |   1 +
 arch/arm64/boot/dts/cavium/thunder-88xx.dtsi  |   5 +
 arch/arm64/kernel/perf_event.c| 145 --
 drivers/perf/arm_pmu.c|   5 +-
 include/linux/perf/arm_pmu.h  |   4 +-
 5 files changed, 125 insertions(+), 35 deletions(-)

-- 
1.9.1



[PATCH v2 5/5] arm64/perf: Extend event mask for ARMv8.1

2016-01-29 Thread Jan Glauber
ARMv8.1 increases the PMU event number space. Detect the
presence of this PMUv3 type and extend the event mask.

The event mask is moved to struct arm_pmu so different event masks
can exist, depending on the PMU type.

Signed-off-by: Jan Glauber 
---
 arch/arm/kernel/perf_event_v6.c |  6 --
 arch/arm/kernel/perf_event_v7.c | 29 +++--
 arch/arm/kernel/perf_event_xscale.c |  4 +++-
 arch/arm64/kernel/perf_event.c  | 33 +++--
 drivers/perf/arm_pmu.c  |  5 +++--
 include/linux/perf/arm_pmu.h|  4 ++--
 6 files changed, 50 insertions(+), 31 deletions(-)

diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index 09413e7..d6769f5 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -481,7 +481,7 @@ static void armv6mpcore_pmu_disable_event(struct perf_event 
*event)
 static int armv6_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _perf_map,
-   _perf_cache_map, 0xFF);
+   _perf_cache_map);
 }
 
 static void armv6pmu_init(struct arm_pmu *cpu_pmu)
@@ -494,6 +494,7 @@ static void armv6pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->get_event_idx  = armv6pmu_get_event_idx;
cpu_pmu->start  = armv6pmu_start;
cpu_pmu->stop   = armv6pmu_stop;
+   cpu_pmu->event_mask = 0xFF;
cpu_pmu->map_event  = armv6_map_event;
cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
@@ -531,7 +532,7 @@ static int armv6_1176_pmu_init(struct arm_pmu *cpu_pmu)
 static int armv6mpcore_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _perf_map,
-   _perf_cache_map, 0xFF);
+   _perf_cache_map);
 }
 
 static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
@@ -545,6 +546,7 @@ static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->get_event_idx  = armv6pmu_get_event_idx;
cpu_pmu->start  = armv6pmu_start;
cpu_pmu->stop   = armv6pmu_stop;
+   cpu_pmu->event_mask = 0xFF;
cpu_pmu->map_event  = armv6mpcore_map_event;
cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4152158..8aab098 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1042,7 +1042,7 @@ static int armv7pmu_get_event_idx(struct pmu_hw_events 
*cpuc,
int idx;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = >hw;
-   unsigned long evtype = hwc->config_base & ARMV7_EVTYPE_EVENT;
+   unsigned long evtype = hwc->config_base & cpu_pmu->event_mask;
 
/* Always place a cycle counter into the cycle counter. */
if (evtype == ARMV7_PERFCTR_CPU_CYCLES) {
@@ -1109,55 +1109,55 @@ static void armv7pmu_reset(void *info)
 static int armv7_a8_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a8_perf_map,
-   _a8_perf_cache_map, 0xFF);
+   _a8_perf_cache_map);
 }
 
 static int armv7_a9_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a9_perf_map,
-   _a9_perf_cache_map, 0xFF);
+   _a9_perf_cache_map);
 }
 
 static int armv7_a5_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a5_perf_map,
-   _a5_perf_cache_map, 0xFF);
+   _a5_perf_cache_map);
 }
 
 static int armv7_a15_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a15_perf_map,
-   _a15_perf_cache_map, 0xFF);
+   _a15_perf_cache_map);
 }
 
 static int armv7_a7_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a7_perf_map,
-   _a7_perf_cache_map, 0xFF);
+   _a7_perf_cache_map);
 }
 
 static int armv7_a12_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _a12_perf_map,
-   _a12_perf_cache_map, 0xFF);
+   _a12_perf_cache_map);
 }
 
 static int krait_map_event(struct perf_event *event)
 {
return armpmu_map_event(event, _perf_map,
-   _perf_cache_map, 0xF);
+   _perf_cache_map);
 }
 
 static int krait_map_event_no_branch(struct perf_event *event)
 {
return armpmu_map_event(event, _perf_map_no_branch,
-   _perf_cache_map, 0xF);
+   _

Re: [PATCH v2 5/5] arm64/perf: Extend event mask for ARMv8.1

2016-01-29 Thread Jan Glauber
On Fri, Jan 29, 2016 at 01:33:35AM +0800, kbuild test robot wrote:
> Hi Jan,
> 
> [auto build test ERROR on robh/for-next]
> [also build test ERROR on v4.5-rc1 next-20160128]
> [cannot apply to tip/perf/core]
> [if your patch is applied to the wrong git tree, please drop us a note to 
> help improving the system]
> 
> url:
> https://github.com/0day-ci/linux/commits/Jan-Glauber/Cavium-ThunderX-PMU-support/20160128-225855
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux for-next
> config: arm-corgi_defconfig (attached as .config)
> reproduce:
> wget 
> https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross
>  -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=arm 
> 
> All errors (new ones prefixed by >>):
> 
>arch/arm/kernel/perf_event_xscale.c: In function 'xscale_map_event':
> >> arch/arm/kernel/perf_event_xscale.c:360:9: error: too many arguments to 
> >> function 'armpmu_map_event'
>  return armpmu_map_event(event, _perf_map,
> ^

I forgot the arm32 parts of this patch. I'll resend this patch only, the
other patches don't touch arm32.

--Jan


[PATCH v2 07/10] i2c-octeon: Faster operation when IFLG signals late

2016-03-04 Thread Jan Glauber
From: Peter Swain 

Some versions can deliver low-level twsi irq before twsi_ctl.iflg
is set, leading to timeout-driven i/o.
When an irq signals event, but woken task does not see the expected
twsi_ctl.iflg, re-check about 80uS later.

EEPROM reads on 100kHz i2c now measure ~5.2kB/s, about 1/2 what's
achievable, and much better than the worst-case 100 bytes/sec before.

Signed-off-by: Peter Swain 
Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 31 ++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index bb15a9c..e3552e5 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -130,6 +130,14 @@ static int timeout = 2;
 module_param(timeout, int, 0444);
 MODULE_PARM_DESC(timeout, "Low-level device timeout (ms)");
 
+/*
+ * On some hardware IFLG is not visible in TWSI_CTL until after low-level IRQ,
+ * so re-sample CTL a short time later to avoid stalls.
+ */
+static int irq_early_us = 80;
+module_param(irq_early_us, int, 0644);
+MODULE_PARM_DESC(irq_early_us, "Re-poll for IFLG after IRQ (us)");
+
 static void writeqflush(u64 val, void __iomem *addr)
 {
__raw_writeq(val, addr);
@@ -343,6 +351,26 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
return (octeon_i2c_read_ctl(i2c) & TWSI_CTL_IFLG) != 0;
 }
 
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(irq_early_us, 2 * irq_early_us);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
 /**
  * octeon_i2c_wait - wait for the IFLG to be set
  * @i2c: The struct octeon_i2c
@@ -351,10 +379,11 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
  */
 static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
+   int first = 1;
long result;
 
i2c->int_en(i2c);
-   result = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
+   result = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
i2c->adap.timeout);
i2c->int_dis(i2c);
if (!result) {
-- 
1.9.1



[PATCH v2 00/10] i2c-octeon and i2c-thunderx drivers

2016-03-04 Thread Jan Glauber
This series for the Octeon i2c driver is an attempt to upstream some
bug fixes and features that accumulated for some time. I tried to
split the cleanup from the other patches and updated the patch
descriptions according to my humble i2c knowledge.
  
Patches are on top of 4.5-rc6 and were tested on OCTEON, OCTEON-78
and ThunderX.

Changes to v1:
- Fixed compile error on x86_64
- Disabled thunderx driver on MIPS
- Re-ordered some thunderx probe functions for readability
- Fix missing of_irq.h and i2c-smbus.h includes
- Use IS_ENABLED for CONFIG options

Comments welcome.

Thanks,
Jan

--

David Daney (4):
  i2c-octeon: Support I2C_M_RECV_LEN
  i2c-octeon: Enable high-level controller and improve on bus contention
  i2c-octeon: Add support for cn78XX chips
  i2c-octeon: Add workaround for chips with broken irqs

Jan Glauber (4):
  i2c-octeon: Cleanup i2c-octeon driver
  dt-bindings: i2c: add Octeon cn78xx TWSI
  i2c: split i2c-octeon driver and add ThunderX support
  i2c: thunderx: add smbus support

Peter Swain (2):
  i2c-octeon: Flush TWSI writes with readback
  i2c-octeon: Faster operation when IFLG signals late

 .../devicetree/bindings/i2c/i2c-octeon.txt |   6 +
 drivers/i2c/busses/Kconfig |  10 +
 drivers/i2c/busses/Makefile|   3 +
 drivers/i2c/busses/i2c-cavium.c| 828 +
 drivers/i2c/busses/i2c-cavium.h| 191 +
 drivers/i2c/busses/i2c-octeon-core.c   | 302 
 drivers/i2c/busses/i2c-octeon.c| 633 
 drivers/i2c/busses/i2c-thunderx-core.c | 301 
 8 files changed, 1641 insertions(+), 633 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

-- 
1.9.1



[PATCH v2 03/10] i2c-octeon: Enable high-level controller and improve on bus contention

2016-03-04 Thread Jan Glauber
From: David Daney 

Use High Level Controller when possible.

i2c-octeon was reacting badly to bus contention: when in
direct-access mode (for transfers > 8 bytes, which cannot use the
high-level controller) some !ACK or arbitration-loss states were
not causing the current transfer to be aborted, and the bus released.

There's one place in i2c protocol that !ACK is an acceptable
response: in the final byte of a read cycle.  In this case the
destination is not saying that the transfer failed, just that it
doesn't want more data.

This enables correct behavior of ACK on final byte of non-final read
msgs too.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 583 ++--
 1 file changed, 504 insertions(+), 79 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index fa4d439..d48456a 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -113,8 +113,15 @@ struct octeon_i2c {
int sys_freq;
void __iomem*twsi_base;
struct device   *dev;
+   boolhlc_enabled;
 };
 
+static int reset_how;
+
+static int timeout = 2;
+module_param(timeout, int, 0444);
+MODULE_PARM_DESC(timeout, "Low-level device timeout (ms)");
+
 /**
  * octeon_i2c_write_sw - write an I2C core register
  * @i2c: The struct octeon_i2c
@@ -123,7 +130,7 @@ struct octeon_i2c {
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u32 data)
 {
u64 tmp;
 
@@ -165,7 +172,7 @@ static u64 octeon_i2c_read_sw64(struct octeon_i2c *i2c, u64 
eop_reg)
  */
 static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
 {
-   return octeon_i2c_read_sw64(i2c, eop_reg);
+   return (u8) octeon_i2c_read_sw64(i2c, eop_reg);
 }
 
 /**
@@ -198,6 +205,15 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
octeon_i2c_write_int(i2c, TS_INT | ST_INT);
 }
 
+static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+}
+
 /**
  * bitbang_unblock - unblock the bus
  * @i2c: The struct octeon_i2c
@@ -207,13 +223,18 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
  */
 static void bitbang_unblock(struct octeon_i2c *i2c)
 {
-   int i;
+   int state, i;
 
+   octeon_i2c_disable_hlc(i2c);
dev_dbg(i2c->dev, "%s\n", __func__);
 
+   /* cycle 8+1 clocks with SDA high */
for (i = 0; i < 9; i++) {
octeon_i2c_write_int(i2c, 0);
udelay(5);
+   state = __raw_readq(i2c->twsi_base + TWSI_INT);
+   if (state & (SDA | SCL))
+   break;
octeon_i2c_write_int(i2c, SCL_OVR);
udelay(5);
}
@@ -236,10 +257,14 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
return IRQ_HANDLED;
 }
 
+static u64 octeon_i2c_read_ctl(struct octeon_i2c *i2c)
+{
+   return octeon_i2c_read_sw64(i2c, SW_TWSI_EOP_TWSI_CTL);
+}
+
 static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 {
-   return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL)
-   & TWSI_CTL_IFLG) != 0;
+   return (octeon_i2c_read_ctl(i2c) & TWSI_CTL_IFLG) != 0;
 }
 
 /**
@@ -263,76 +288,208 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
return 0;
 }
 
-/* send STOP to the bus */
-static void octeon_i2c_stop(struct octeon_i2c *i2c)
+/*
+ * Cleanup low-level state & enable high-level.
+ *
+ * Returns -EAGAIN if low-level state could not be cleaned
+ */
+static int octeon_i2c_enable_hlc(struct octeon_i2c *i2c)
 {
-   u8 data;
+   int try = 0, ret = 0;
+   u64 val;
+
+   if (i2c->hlc_enabled)
+   return 0;
+   else
+   i2c->hlc_enabled = true;
+
+   while (1) {
+   val = octeon_i2c_read_ctl(i2c) & (TWSI_CTL_STA | TWSI_CTL_STP);
+   if (!val)
+   break;
+
+   /* clear _IFLG event */
+   if (val & TWSI_CTL_IFLG)
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+   TWSI_CTL_ENAB);
+
+   if (try++ > 100) {
+   pr_err("%s: giving up\n", __func__);
+   ret = -EAGAIN;
+   break;
+   }
+
+   /* spin until any start/stop has finished */
+   udelay(10);
+   }
 
octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
-   TWSI_CTL_ENAB | TWSI_CTL_STP);
+ 

[PATCH v2 10/10] i2c: thunderx: add smbus support

2016-03-04 Thread Jan Glauber
Add smbus alert interrupt support.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-cavium.h|  6 ++
 drivers/i2c/busses/i2c-thunderx-core.c | 35 ++
 2 files changed, 41 insertions(+)

diff --git a/drivers/i2c/busses/i2c-cavium.h b/drivers/i2c/busses/i2c-cavium.h
index aadd4f5..062bc022 100644
--- a/drivers/i2c/busses/i2c-cavium.h
+++ b/drivers/i2c/busses/i2c-cavium.h
@@ -3,6 +3,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -117,6 +118,11 @@ struct octeon_i2c {
 #if IS_ENABLED(CONFIG_I2C_THUNDERX)
struct msix_entry   i2c_msix;
 #endif
+
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   struct i2c_smbus_alert_setup alert_data;
+   struct i2c_client   *ara;
+#endif
 };
 
 static inline void writeqflush(u64 val, void __iomem *addr)
diff --git a/drivers/i2c/busses/i2c-thunderx-core.c 
b/drivers/i2c/busses/i2c-thunderx-core.c
index e14838a..cdfadee 100644
--- a/drivers/i2c/busses/i2c-thunderx-core.c
+++ b/drivers/i2c/busses/i2c-thunderx-core.c
@@ -9,10 +9,12 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "i2c-cavium.h"
 
@@ -107,6 +109,35 @@ static void thunder_i2c_clock_disable(struct device *dev, 
struct clk *clk)
devm_clk_put(dev, clk);
 }
 
+static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
+  struct device_node *node)
+{
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   u32 type;
+
+   i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
+   if (!i2c->alert_data.irq)
+   return -EINVAL;
+
+   type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
+   i2c->alert_data.alert_edge_triggered =
+   (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
+
+   i2c->ara = i2c_setup_smbus_alert(>adap, >alert_data);
+   if (!i2c->ara)
+   return -ENODEV;
+#endif
+   return 0;
+}
+
+static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
+{
+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+   if (i2c->ara)
+   i2c_unregister_device(i2c->ara);
+#endif
+}
+
 static void thunder_i2c_set_name(struct pci_dev *pdev, struct octeon_i2c *i2c,
 char *name)
 {
@@ -205,6 +236,9 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
goto out_irq;
}
 
+   ret = thunder_i2c_smbus_setup(i2c, node);
+   if (ret < 0)
+   dev_err(dev, "Failed to setup smbus alert\n");
dev_info(i2c->dev, "probed\n");
return 0;
 
@@ -235,6 +269,7 @@ static void thunder_i2c_remove_pci(struct pci_dev *pdev)
 
dev = i2c->dev;
thunder_i2c_clock_disable(dev, i2c->clk);
+   thunder_i2c_smbus_remove(i2c);
i2c_del_adapter(>adap);
devm_free_irq(dev, i2c->i2c_msix.vector, i2c);
pci_disable_msix(pdev);
-- 
1.9.1



[PATCH v2 09/10] i2c: split i2c-octeon driver and add ThunderX support

2016-03-04 Thread Jan Glauber
The ThunderX SOC uses the same i2c block as the Octeon SOC.
The main difference is that on ThunderX the device is a PCI device
so device probing is done via PCI.

Split the current Octeon driver into an Octeon and a common part
and add the ThunderX support.

Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/Kconfig |   10 +
 drivers/i2c/busses/Makefile|3 +
 drivers/i2c/busses/i2c-cavium.c|  828 +
 drivers/i2c/busses/i2c-cavium.h|  185 +
 drivers/i2c/busses/i2c-octeon-core.c   |  302 
 drivers/i2c/busses/i2c-octeon.c| 1283 
 drivers/i2c/busses/i2c-thunderx-core.c |  266 +++
 7 files changed, 1594 insertions(+), 1283 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-cavium.c
 create mode 100644 drivers/i2c/busses/i2c-cavium.h
 create mode 100644 drivers/i2c/busses/i2c-octeon-core.c
 delete mode 100644 drivers/i2c/busses/i2c-octeon.c
 create mode 100644 drivers/i2c/busses/i2c-thunderx-core.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7b0aa82..6069401 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -952,6 +952,16 @@ config I2C_OCTEON
  This driver can also be built as a module.  If so, the module
  will be called i2c-octeon.
 
+config I2C_THUNDERX
+   tristate "Cavium ThunderX I2C bus support"
+   depends on 64BIT && PCI && !CAVIUM_OCTEON_SOC
+   help
+ Say yes if you want to support the I2C serial bus on Cavium
+ ThunderX SOC.
+
+ This driver can also be built as a module.  If so, the module
+ will be called i2c-thunderx.
+
 config I2C_XILINX
tristate "Xilinx I2C Controller"
depends on HAS_IOMEM
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819..a32ff14 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -91,7 +91,10 @@ obj-$(CONFIG_I2C_UNIPHIER)   += i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)   += i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)+= i2c-versatile.o
 obj-$(CONFIG_I2C_WMT)  += i2c-wmt.o
+i2c-octeon-objs := i2c-cavium.o i2c-octeon-core.o
 obj-$(CONFIG_I2C_OCTEON)   += i2c-octeon.o
+i2c-thunderx-objs := i2c-cavium.o i2c-thunderx-core.o
+obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
 obj-$(CONFIG_I2C_XILINX)   += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)  += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)   += i2c-xlp9xx.o
diff --git a/drivers/i2c/busses/i2c-cavium.c b/drivers/i2c/busses/i2c-cavium.c
new file mode 100644
index 000..93d8c0f
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cavium.c
@@ -0,0 +1,828 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick@nsn.com
+ *
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
+ *
+ * This file contains the shared part of the driver for the i2c adapter in
+ * Cavium Networks' OCTEON processors and ThunderX SOCs.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+
+#include "i2c-cavium.h"
+
+static int reset_how;
+
+/*
+ * On some hardware IFLG is not visible in TWSI_CTL until after low-level IRQ,
+ * so re-sample CTL a short time later to avoid stalls.
+ */
+static int irq_early_us = 80;
+module_param(irq_early_us, int, 0644);
+MODULE_PARM_DESC(irq_early_us, "Re-poll for IFLG after IRQ (us)");
+
+static void octeon_i2c_disable_hlc(struct octeon_i2c *i2c)
+{
+   if (!i2c->hlc_enabled)
+   return;
+
+   i2c->hlc_enabled = false;
+   octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+}
+
+/* interrupt service routine */
+irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+   struct octeon_i2c *i2c = dev_id;
+
+   i2c->int_dis(i2c);
+   wake_up(>queue);
+
+   return IRQ_HANDLED;
+}
+
+/*
+ * Wait-helper which addresses the delayed-IFLAG problem by re-polling for
+ * missing TWSI_CTL[IFLG] a few us later, when irq has signalled an event,
+ * but none found. Skip this re-poll on the first (non-wakeup) call.
+ */
+static int poll_iflg(struct octeon_i2c *i2c, int *first_p)
+{
+   int iflg = octeon_i2c_test_iflg(i2c);
+
+   if (iflg)
+   return 1;
+   if (*first_p)
+   *first_p = 0;
+   else {
+   usleep_range(irq_early_us, 2 * irq_early_us);
+   iflg = octeon_i2c_test_iflg(i2c);
+   }
+   return iflg;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+   int first = 1;
+   long result;
+
+   if (i2c->broken_irq_mod

[PATCH v2 08/10] i2c-octeon: Add workaround for chips with broken irqs

2016-03-04 Thread Jan Glauber
From: David Daney 

CN3860 does not interrupt the CPU when the i2c status changes.  If
we get a timeout, and see the status has in fact changed, we know we
have this problem, and drop back to polling.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 46 +
 1 file changed, 46 insertions(+)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index e3552e5..3c2f848 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -115,6 +115,7 @@ struct octeon_i2c {
int sys_freq;
void __iomem*twsi_base;
struct device   *dev;
+   int broken_irq_mode;
boolhlc_enabled;
void(*int_en)   (struct octeon_i2c *);
void(*int_dis)  (struct octeon_i2c *);
@@ -382,10 +383,33 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c)
int first = 1;
long result;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some chip revisions seem to not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_test_iflg(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->int_en(i2c);
result = wait_event_timeout(i2c->queue, poll_iflg(i2c, ),
i2c->adap.timeout);
i2c->int_dis(i2c);
+
+   if (result <= 0 && OCTEON_IS_MODEL(OCTEON_CN38XX) &&
+   octeon_i2c_test_iflg(i2c)) {
+   dev_err(i2c->dev,
+   "broken irq connection detected, switching to polling 
mode.\n");
+   i2c->broken_irq_mode = 1;
+   return 0;
+   }
if (!result) {
dev_dbg(i2c->dev, "%s: timeout\n", __func__);
return -ETIMEDOUT;
@@ -740,6 +764,21 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
int result;
 
+   if (i2c->broken_irq_mode) {
+   /*
+* Some cn38xx boards did not assert the irq in
+* the interrupt controller.  So we must poll for the
+* IFLG change.
+*/
+   u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+   while (!octeon_i2c_hlc_test_ready(i2c) &&
+  time_before64(get_jiffies_64(), end))
+   udelay(50);
+
+   return octeon_i2c_hlc_test_ready(i2c) ? 0 : -ETIMEDOUT;
+   }
+
i2c->hlc_int_en(i2c);
result = wait_event_interruptible_timeout(i2c->queue,
octeon_i2c_hlc_test_ready(i2c), i2c->adap.timeout);
@@ -747,6 +786,13 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
if (!result)
octeon_i2c_hlc_int_clear(i2c);
 
+   if (result <= 0 && OCTEON_IS_MODEL(OCTEON_CN38XX) &&
+   octeon_i2c_hlc_test_ready(i2c)) {
+   dev_err(i2c->dev, "broken irq connection detected, switching to 
polling mode.\n");
+   i2c->broken_irq_mode = 1;
+   return 0;
+   }
+
if (result < 0) {
dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
return result;
-- 
1.9.1



[PATCH v2 01/10] i2c-octeon: Cleanup i2c-octeon driver

2016-03-04 Thread Jan Glauber
Cleanup only without functional change.

Signed-off-by: Jan Glauber 
Acked-by: David Daney 
---
 drivers/i2c/busses/i2c-octeon.c | 442 +---
 1 file changed, 230 insertions(+), 212 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 32914ab..1f14094 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -2,7 +2,7 @@
  * (C) Copyright 2009-2010
  * Nokia Siemens Networks, michael.lawnick@nsn.com
  *
- * Portions Copyright (C) 2010, 2011 Cavium Networks, Inc.
+ * Portions Copyright (C) 2010 - 2016 Cavium, Inc.
  *
  * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
  *
@@ -24,99 +24,154 @@
 
 #include 
 
-#define DRV_NAME "i2c-octeon"
+#define DRV_NAME   "i2c-octeon"
 
-/* The previous out-of-tree version was implicitly version 1.0. */
-#define DRV_VERSION"2.0"
+/* Register offsets */
+#define SW_TWSI0x00
+#define TWSI_INT   0x10
+#define SW_TWSI_EXT0x18
 
-/* register offsets */
-#define SW_TWSI 0x00
-#define TWSI_INT 0x10
+#define INT_ENA_ST 0x1
+#define INT_ENA_TS 0x2
+#define INT_ENA_CORE   0x4
 
 /* Controller command patterns */
-#define SW_TWSI_V   0x8000ull
-#define SW_TWSI_EOP_TWSI_DATA   0x0C01ull
-#define SW_TWSI_EOP_TWSI_CTL0x0C02ull
-#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C03ull
-#define SW_TWSI_EOP_TWSI_STAT   0x0C03ull
-#define SW_TWSI_EOP_TWSI_RST0x0C07ull
-#define SW_TWSI_OP_TWSI_CLK 0x0800ull
-#define SW_TWSI_R   0x0100ull
+#define SW_TWSI_V  (1ULL << 63)
+#define SW_TWSI_EIA(1ULL << 61)
+#define SW_TWSI_R  (1ULL << 56)
+#define SW_TWSI_SOVR   (1ULL << 55)
+#define SW_TWSI_OP_7   (0ULL << 57)
+#define SW_TWSI_OP_7_IA(1ULL << 57)
+#define SW_TWSI_OP_10  (2ULL << 57)
+#define SW_TWSI_OP_10_IA   (3ULL << 57)
+#define SW_TWSI_OP_TWSI_CLK(1ULL << 59)
+#define SW_TWSI_SIZE_SHIFT 52
+#define SW_TWSI_A_SHIFT40
+#define SW_TWSI_IA_SHIFT   32
+#define SW_TWSI_EOP_TWSI_DATA  0x0C01ULL
+#define SW_TWSI_EOP_TWSI_CTL   0x0C02ULL
+#define SW_TWSI_EOP_TWSI_CLKCTL0x0C03ULL
+#define SW_TWSI_EOP_TWSI_STAT  0x0C03ULL
+#define SW_TWSI_EOP_TWSI_RST   0x0C07ULL
 
 /* Controller command and status bits */
-#define TWSI_CTL_CE   0x80
-#define TWSI_CTL_ENAB 0x40
-#define TWSI_CTL_STA  0x20
-#define TWSI_CTL_STP  0x10
-#define TWSI_CTL_IFLG 0x08
-#define TWSI_CTL_AAK  0x04
+#define TWSI_CTL_CE0x80/* High level controller enable */
+#define TWSI_CTL_ENAB  0x40/* Bus enable */
+#define TWSI_CTL_STA   0x20/* Master-mode start, HW clears when 
done */
+#define TWSI_CTL_STP   0x10/* Master-mode stop, HW clears when 
done */
+#define TWSI_CTL_IFLG  0x08/* HW event, SW writes 0 to ACK */
+#define TWSI_CTL_AAK   0x04/* Assert ACK */
 
 /* Some status values */
-#define STAT_START  0x08
-#define STAT_RSTART 0x10
-#define STAT_TXADDR_ACK 0x18
-#define STAT_TXDATA_ACK 0x28
-#define STAT_RXADDR_ACK 0x40
-#define STAT_RXDATA_ACK 0x50
-#define STAT_IDLE   0xF8
+#define STAT_ERROR 0x00
+#define STAT_START 0x08
+#define STAT_RSTART0x10
+#define STAT_TXADDR_ACK0x18
+#define STAT_TXADDR_NAK0x20
+#define STAT_TXDATA_ACK0x28
+#define STAT_TXDATA_NAK0x30
+#define STAT_LOST_ARB_38   0x38
+#define STAT_RXADDR_ACK0x40
+#define STAT_RXADDR_NAK0x48
+#define STAT_RXDATA_ACK0x50
+#define STAT_RXDATA_NAK0x58
+#define STAT_SLAVE_60  0x60
+#define STAT_LOST_ARB_68   0x68
+#define STAT_SLAVE_70  0x70
+#define STAT_LOST_ARB_78   0x78
+#define STAT_SLAVE_80  0x80
+#define STAT_SLAVE_88  0x88
+#define STAT_GENDATA_ACK   0x90
+#define STAT_GENDATA_NAK   0x98
+#define STAT_SLAVE_A0  0xA0
+#define STAT_SLAVE_A8  0xA8
+#define STAT_LOST_ARB_B0   0xB0
+#define STAT_SLAVE_LOST0xB8
+#define STAT_SLAVE_NAK 0xC0
+#define STAT_SLAVE_ACK 0xC8
+#define STAT_AD2W_ACK  0xD0
+#define STAT_AD2W_NAK  0xD8
+#define STAT_IDLE  0xF8
+
+/* TWSI_INT values */
+#define ST_INT 0x01
+#define TS_INT 0x02
+#define CORE_INT   0x04
+#define ST_EN  0x10
+#define TS_EN  0x20
+#define CORE_EN0x40
+#define SDA_OVR0x100
+#define SCL_OVR 

[PATCH v2 02/10] i2c-octeon: Support I2C_M_RECV_LEN

2016-03-04 Thread Jan Glauber
From: David Daney 

If I2C_M_RECV_LEN is set consider the length byte.

Signed-off-by: David Daney 
Signed-off-by: Jan Glauber 
---
 drivers/i2c/busses/i2c-octeon.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 1f14094..fa4d439 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -392,13 +392,14 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int 
target,
  * @target: Target address
  * @data: Pointer to the location to store the data
  * @rlength: Length of the data
+ * @recv_len: flag for length byte
  *
  * The address is sent over the bus, then the data is read.
  *
  * Returns 0 on success, otherwise a negative errno.
  */
 static int octeon_i2c_read(struct octeon_i2c *i2c, int target, u8 *data,
-  u16 *rlength)
+  u16 *rlength, bool recv_len)
 {
int length = *rlength;
int i, result;
@@ -438,6 +439,15 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int 
target, u8 *data,
return result;
 
data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
+   if (recv_len && i == 0) {
+   if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) {
+   dev_err(i2c->dev,
+   "%s: read len > I2C_SMBUS_BLOCK_MAX 
%d\n",
+   __func__, data[i]);
+   return -EIO;
+   }
+   length += data[i];
+   }
}
*rlength = length;
return 0;
@@ -466,7 +476,8 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap, struct 
i2c_msg *msgs,
 pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD)
ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
- >len);
+ >len,
+ pmsg->flags & I2C_M_RECV_LEN);
else
ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
   pmsg->len);
-- 
1.9.1



<    5   6   7   8   9   10   11   >