[Pdbg] [PATCH 3/3] libpdbg: Add i2c get and put for i2c masters on the PIB
Rashmica Gupta
rashmica.g at gmail.com
Mon Apr 15 11:14:14 AEST 2019
This enables the basic i2c functions from the host.
Signed-off-by: Rashmica Gupta <rashmica.g at gmail.com>
---
libpdbg/i2cm.c | 183 +++++++++++++++++++++++++++++++++++++++++++++--
libpdbg/target.h | 2 +
p9-host.dts.m4 | 28 ++++++++
3 files changed, 208 insertions(+), 5 deletions(-)
diff --git a/libpdbg/i2cm.c b/libpdbg/i2cm.c
index 2022122..67fc5c6 100644
--- a/libpdbg/i2cm.c
+++ b/libpdbg/i2cm.c
@@ -33,7 +33,11 @@
#include <dirent.h>
-/* I2C common registers */
+/*
+ * I2C common registers
+ * - use as is on CFAM
+ * - use with I2C_PIB_OFFSET on PIB
+ */
#define I2C_FIFO_REG 0x0
#define I2C_CMD_REG 0x1
#define I2C_MODE_REG 0x2
@@ -47,11 +51,13 @@
#define I2C_RESIDUAL_REG 0x9
#define I2C_PORT_BUSY_REG 0xA
+/* I2C PIB only */
#define I2C_PIB_OFFSET 0x4
#define I2C_PIB_ENGINE_0 0x0000
#define I2C_PIB_ENGINE_1 0x1000
#define I2C_PIB_ENGINE_2 0x2000
#define I2C_PIB_ENGINE_3 0x3000
+#define I2C_PIB_FIFO4_REG 0x12
/* I2C command register bits */
#define I2C_CMD_WITH_START PPC_BIT32(0)
@@ -131,13 +137,24 @@
static int _i2cm_reg_write(struct i2cm *i2cm, uint32_t addr, uint32_t data)
{
- CHECK_ERR(fsi_write(&i2cm->target, addr, data));
+ if (i2cm->host)
+ /* pib addr space is 64 bits and i2cm only uses top 32 bits */
+ CHECK_ERR(pib_write(&i2cm->target, addr + I2C_PIB_OFFSET, (uint64_t)data << 32));
+ else
+ CHECK_ERR(fsi_write(&i2cm->target, addr, data));
return 0;
}
static int _i2cm_reg_read(struct i2cm *i2cm, uint32_t addr, uint32_t *data)
{
- CHECK_ERR(fsi_read(&i2cm->target, addr, data));
+ uint64_t d = (uint64_t)*data;
+
+ if (i2cm->host) {
+ CHECK_ERR(pib_read(&i2cm->target, addr + I2C_PIB_OFFSET, &d));
+ *data = d >> 32;
+ } else {
+ CHECK_ERR(fsi_read(&i2cm->target, addr, data));
+ }
return 0;
}
@@ -277,7 +294,10 @@ static int i2c_fifo_write(struct i2cm *i2cm, uint32_t *data, uint16_t size)
continue;
PR_INFO("\twriting: %x to FIFO\n", data[bytes_written / 4]);
- rc = _i2cm_reg_write(i2cm, I2C_FIFO_REG, data[bytes_written / 4]);
+ if (i2cm->host)
+ rc = _i2cm_reg_write(i2cm, I2C_PIB_FIFO4_REG - I2C_PIB_OFFSET , data[bytes_written / 4]);
+ else
+ rc = _i2cm_reg_write(i2cm, I2C_FIFO_REG, data[bytes_written / 4]);
if (rc)
return bytes_written;
bytes_written += 4;
@@ -308,9 +328,14 @@ static int i2c_fifo_read(struct i2cm *i2cm, uint32_t *data, uint16_t size)
if (!bytes_to_read)
continue;
- rc = _i2cm_reg_read(i2cm, I2C_FIFO_REG, &tmp);
+ if (i2cm->host)
+ rc = _i2cm_reg_read(i2cm, I2C_PIB_FIFO4_REG -I2C_PIB_OFFSET, &tmp);
+ else
+ rc = _i2cm_reg_read(i2cm, I2C_FIFO_REG, &tmp);
+
if (rc)
return bytes_read;
+
memcpy(data + (bytes_read / 4), &tmp, 4);
PR_INFO(" %x \n", data[bytes_read / 4]);
bytes_read += 4;
@@ -435,9 +460,157 @@ static struct i2cm i2c_fsi = {
},
.read = i2c_get,
.write = i2c_put,
+ .host = false
};
DECLARE_HW_UNIT(i2c_fsi);
+
+/////////////////////////////////////////////////////////////////////////////
+#define I2C_ATOMIC_LOCK_REG 0x3ff
+#define OCC_BASE 0x00000000006C08A
+#define OCC_CLEAR 0x00000000006C08B
+#define OCC_SET 0x00000000006C08C
+
+
+#define OCC_LOCKED_ENGINE_1 PPC_BIT(17)
+#define OCC_LOCKED_ENGINE_2 PPC_BIT(19)
+#define OCC_LOCKED_ENGINE_3 PPC_BIT(21)
+#define I2CM_DT_TO_ID(x) ((x>>12) & 0xf)
+static int i2cm_locked_by_occ(int id, uint64_t occ_base)
+{
+ uint64_t mask;
+ switch (id)
+ {
+ case 1:
+ mask = OCC_LOCKED_ENGINE_1;
+ break;
+ case 2:
+ mask = OCC_LOCKED_ENGINE_2;
+ break;
+ case 3:
+ mask = OCC_LOCKED_ENGINE_3;
+ break;
+ default:
+ mask = 0;
+ break;
+ }
+ return !!(mask & occ_base);
+}
+
+static int pib_i2c_get(struct i2cm *i2cm, uint32_t addr, uint16_t size, uint8_t *d)
+{
+ uint64_t data = 0;
+ uint64_t bit;
+ struct pdbg_target *p;
+
+ pdbg_for_each_class_target("pib", p) {
+ if (pdbg_target_probe(p) == PDBG_TARGET_ENABLED)
+ break;
+ }
+
+ if (!p) {
+ fprintf(stderr, "No PIB found\n");
+ return 0;
+ }
+ bit = PPC_BIT(16 + (i2cm->id - 1) * 2);
+ pib_read(p, OCC_BASE, &data);
+
+ if( !i2cm_locked_by_occ(i2cm->id, data)) {
+ /* lock i2cm */
+ pib_write(p, OCC_SET, bit);
+ pib_read(p, OCC_BASE, &data);
+
+ i2c_get(i2cm, addr, size, d);
+
+ /* unlock i2cm */
+ pib_read(p, OCC_BASE, &data);
+ pib_read(p, OCC_CLEAR, &data);
+ pib_write(p, OCC_CLEAR, bit);
+ pib_read(p, OCC_BASE, &data);
+ } else {
+ PR_INFO("I2C: de%d: occflags = 0x%16" PRIx64 "(locks = %x:%x:%x)\n",
+ i2cm->id, (u64) data, (u16) GETFIELD(PPC_BITMASK(16, 17), data),
+ (u16) GETFIELD(PPC_BITMASK(18, 19), data),
+ (u16) GETFIELD(PPC_BITMASK(20, 21), data));
+ PR_INFO("I2C master %x is locked by OCC :( \n", i2cm->id);
+ }
+
+ return 0;
+}
+static int pib_i2c_put(struct i2cm *i2cm, uint32_t addr, uint16_t size, uint8_t *d)
+{
+ uint64_t data = 0;
+ uint64_t bit;
+ struct pdbg_target *p;
+
+ pdbg_for_each_class_target("pib", p) {
+ if (pdbg_target_probe(p) == PDBG_TARGET_ENABLED)
+ break;
+ }
+
+ if (!p) {
+ fprintf(stderr, "No PIB found\n");
+ return 0;
+ }
+ bit = PPC_BIT(16 + (i2cm->id - 1) * 2);
+ pib_read(p, OCC_BASE, &data);
+
+ if( !i2cm_locked_by_occ(i2cm->id, data)) {
+ /* lock i2cm */
+ pib_write(p, OCC_SET, bit);
+ pib_read(p, OCC_BASE, &data);
+
+ i2c_put(i2cm, addr, size, d);
+
+ /* unlock i2cm */
+ pib_read(p, OCC_BASE, &data);
+ pib_read(p, OCC_CLEAR, &data);
+ pib_write(p, OCC_CLEAR, bit);
+ pib_read(p, OCC_BASE, &data);
+ } else {
+ PR_INFO("I2C: de%d: occflags = 0x%16" PRIx64 "(locks = %x:%x:%x)\n",
+ i2cm->id, (u64) data, (u16) GETFIELD(PPC_BITMASK(16, 17), data),
+ (u16) GETFIELD(PPC_BITMASK(18, 19), data),
+ (u16) GETFIELD(PPC_BITMASK(20, 21), data));
+ PR_INFO("I2C master %x is locked by OCC :( \n", i2cm->id);
+ }
+ return 0;
+}
+
+int host_i2cm_target_probe(struct pdbg_target *target)
+{
+ int dt_id = pdbg_target_address(target, NULL);
+ int id = I2CM_DT_TO_ID(dt_id);
+ printf("###############\n");
+ struct i2cm *i2cm = target_to_i2cm(target);
+ i2cm->id = id;
+ /*
+ * 1 0x800000000000
+ * 2 0x200000000000
+ * 3 0x080000000000
+ * */
+
+
+ #define FSI_SET_PIB_RESET_REG 0x07
+
+ // CHECK_ERR(fsi_write(target, FSI_SET_PIB_RESET_REG, 1));
+
+
+ return 0;
+}
+
+static struct i2cm i2c_pib = {
+ .target = {
+ .name = "PIB I2C Master",
+ .compatible = "ibm,power9-i2cm",
+ .class = "i2cm",
+ .probe = i2cm_target_probe,
+ },
+ .read = pib_i2c_get,
+ .write = pib_i2c_put,
+ .host = true,
+};
+DECLARE_HW_UNIT(i2c_pib);
/////////////////////////////////////////////////////////////////////////////
#ifndef DISABLE_I2CLIB
diff --git a/libpdbg/target.h b/libpdbg/target.h
index 8b53a0e..6e5f369 100644
--- a/libpdbg/target.h
+++ b/libpdbg/target.h
@@ -144,6 +144,8 @@ struct i2cm {
int (*write)(struct i2cm *, uint32_t, uint16_t, uint8_t *);
uint8_t port;
int i2c_fd;
+ bool host;
+ int id;
};
#define target_to_i2cm(x) container_of(x, struct i2cm, target)
diff --git a/p9-host.dts.m4 b/p9-host.dts.m4
index 52973ff..2d8b18b 100644
--- a/p9-host.dts.m4
+++ b/p9-host.dts.m4
@@ -12,6 +12,19 @@
reg = <0x0>;
index = <0x0>;
include(p9-pib.dts.m4)dnl
+
+ i2cm at a1000 {
+ reg = <0x0 0xa1000 0x400>;
+ compatible = "ibm,power9-i2cm";
+ };
+ i2cm at a2000 {
+ reg = <0x0 0xa2000 0x400>;
+ compatible = "ibm,power9-i2cm";
+ };
+ i2cm at a3000 {
+ reg = <0x0 0xa3000 0x400>;
+ compatible = "ibm,power9-i2cm";
+ };
};
pib at 8 {
@@ -21,5 +34,20 @@
reg = <0x8>;
index = <0x8>;
include(p9-pib.dts.m4)dnl
+
+ i2cm at a1000 {
+ reg = <0x0 0xa1000 0x400>;
+ compatible = "ibm,power9-i2cm";
+ };
+ i2cm at a2000 {
+ reg = <0x0 0xa2000 0x400>;
+ compatible = "ibm,power9-i2cm";
+ };
+ i2cm at a3000 {
+ reg = <0x0 0xa3000 0x400>;
+ compatible = "ibm,power9-i2cm";
+ };
+
+
};
};
--
2.17.2
More information about the Pdbg
mailing list