summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--libpdbg/backend.h3
-rw-r--r--libpdbg/i2c.c174
-rw-r--r--libpdbg/scom.c13
-rw-r--r--src/main.c61
5 files changed, 247 insertions, 5 deletions
diff --git a/Makefile.am b/Makefile.am
index eced4f6..f8b2317 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,5 +11,6 @@ pdbg_CFLAGS = -I$(top_srcdir)/libpdbg
libpdbg_a_SOURCES = \
libpdbg/adu.c \
libpdbg/bmcfsi.c \
+ libpdbg/i2c.c \
libpdbg/ram.c \
libpdbg/scom.c
diff --git a/libpdbg/backend.h b/libpdbg/backend.h
index 7d9414c..76ad82d 100644
--- a/libpdbg/backend.h
+++ b/libpdbg/backend.h
@@ -22,4 +22,7 @@
/* backend initialisation */
struct scom_backend *fsi_init(void);
+/* i2c backend initialisation */
+struct scom_backend *i2c_init(char *bus, int addr);
+
#endif
diff --git a/libpdbg/i2c.c b/libpdbg/i2c.c
new file mode 100644
index 0000000..07a1dd1
--- /dev/null
+++ b/libpdbg/i2c.c
@@ -0,0 +1,174 @@
+/* Copyright 2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/i2c-dev.h>
+
+#include "bitutils.h"
+#include "operations.h"
+
+struct i2c_data {
+ int addr;
+ int fd;
+};
+
+static int i2c_set_addr(int fd, int addr)
+{
+ if (ioctl(fd, I2C_SLAVE, addr) < 0) {
+ PR_ERROR("Unable to set i2c slave address\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int i2c_getcfam(struct scom_backend *backend, int processor_id,
+ uint32_t *value, uint32_t addr)
+{
+ PR_ERROR("TODO: cfam access not supported with i2c backend\n");
+
+ return -1;
+}
+
+static int i2c_putcfam(struct scom_backend *backend, int processor_id,
+ uint32_t value, uint32_t addr)
+{
+ PR_ERROR("TODO: cfam access not supported with i2c backend\n");
+
+ return -1;
+}
+
+static int i2c_set_scom_addr(struct i2c_data *i2c_data, uint32_t addr)
+{
+ uint8_t data[4];
+
+ addr <<= 1;
+ data[3] = GETFIELD(PPC_BITMASK32(0, 7), addr);
+ data[2] = GETFIELD(PPC_BITMASK32(8, 15), addr);
+ data[1] = GETFIELD(PPC_BITMASK32(16, 23), addr);
+ data[0] = GETFIELD(PPC_BITMASK32(23, 31), addr);
+ if (write(i2c_data->fd, data, sizeof(data)) != 4) {
+ PR_ERROR("Error writing address bytes\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int i2c_getscom(struct scom_backend *backend, int processor_id,
+ uint64_t *value, uint32_t addr)
+{
+ struct i2c_data *i2c_data = backend->priv;
+ uint8_t data[8];
+
+ if (processor_id) {
+ PR_ERROR("TODO: secondary processor access not supported with i2c backend\n");
+ return -1;
+ }
+
+ CHECK_ERR(i2c_set_scom_addr(i2c_data, addr));
+
+ if (read(i2c_data->fd, &data, sizeof(data)) != 8) {
+ PR_ERROR("Error reading data\n");
+ return -1;
+ }
+
+ *value = *((uint64_t *) data);
+
+ return 0;
+}
+
+static int i2c_putscom(struct scom_backend *backend, int processor_id,
+ uint64_t value, uint32_t addr)
+{
+ struct i2c_data *i2c_data = backend->priv;
+ uint8_t data[12];
+
+ if (processor_id) {
+ PR_ERROR("TODO: secondary processor access not supported with i2c backend\n");
+ return -1;
+ }
+
+ /* Setup scom address */
+ addr <<= 1;
+ data[3] = GETFIELD(PPC_BITMASK32(0, 7), addr);
+ data[2] = GETFIELD(PPC_BITMASK32(8, 15), addr);
+ data[1] = GETFIELD(PPC_BITMASK32(16, 23), addr);
+ data[0] = GETFIELD(PPC_BITMASK32(23, 31), addr);
+
+ /* Add data value */
+ data[11] = GETFIELD(PPC_BITMASK(0, 7), value);
+ data[10] = GETFIELD(PPC_BITMASK(8, 15), value);
+ data[9] = GETFIELD(PPC_BITMASK(16, 23), value);
+ data[8] = GETFIELD(PPC_BITMASK(23, 31), value);
+ data[7] = GETFIELD(PPC_BITMASK(32, 39), value);
+ data[6] = GETFIELD(PPC_BITMASK(40, 47), value);
+ data[5] = GETFIELD(PPC_BITMASK(48, 55), value);
+ data[4] = GETFIELD(PPC_BITMASK(56, 63), value);
+
+ /* Write value */
+ if (write(i2c_data->fd, data, sizeof(data)) != 12) {
+ PR_ERROR("Error writing data bytes\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void i2c_destroy(struct scom_backend *backend)
+{
+ struct i2c_data *i2c_data = backend->priv;
+
+ close(i2c_data->fd);
+ free(backend->priv);
+}
+
+/*
+ * Initialise a i2c backend on the given bus at the given bus address.
+ */
+struct scom_backend *i2c_init(char *bus, int addr)
+{
+ struct scom_backend *backend;
+ struct i2c_data *i2c_data;
+
+ backend = malloc(sizeof(*backend));
+ i2c_data = malloc(sizeof(*i2c_data));
+ if (!backend || !i2c_data)
+ exit(1);
+
+ i2c_data->addr = addr;
+ i2c_data->fd = open(bus, O_RDWR);
+ if (i2c_data->fd < 0) {
+ perror("Error opening bus");
+ exit(1);
+ }
+
+ if (i2c_set_addr(i2c_data->fd, addr) < 0)
+ exit(1);
+
+ backend->getscom = i2c_getscom;
+ backend->putscom = i2c_putscom;
+ backend->getcfam = i2c_getcfam;
+ backend->putcfam = i2c_putcfam;
+ backend->destroy = i2c_destroy;
+ backend->priv = i2c_data;
+
+ return backend;
+}
diff --git a/libpdbg/scom.c b/libpdbg/scom.c
index 162f3e4..ec93962 100644
--- a/libpdbg/scom.c
+++ b/libpdbg/scom.c
@@ -25,7 +25,18 @@ struct scom_backend *backend = NULL;
#define FSI_SET_PIB_RESET_REG 0x1007
#define FSI_SET_PIB_RESET PPC_BIT32(0)
-int backend_init(int processor_id)
+int backend_i2c_init(char *bus, int addr)
+{
+ backend = i2c_init(bus, addr);
+ if (!backend)
+ return -1;
+
+ backend->processor_id = 0;
+
+ return 0;
+}
+
+int backend_fsi_init(int processor_id)
{
backend = fsi_init();
if (!backend)
diff --git a/src/main.c b/src/main.c
index d779ed9..e8b733e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -44,6 +44,12 @@ static int processor = 0;
static int chip = 0;
static int thread = 0;
+enum backend { FSI, I2C };
+static enum backend backend = I2C;
+
+static char const *device_node = "/dev/i2c4";
+static int i2c_addr = 0x50;
+
static void print_usage(char *pname)
{
printf("Usage: %s [options] command ...\n\n", pname);
@@ -51,6 +57,18 @@ static void print_usage(char *pname)
printf("\t-p, --processor=processor-id\n");
printf("\t-c, --chip=chiplet-id\n");
printf("\t-t, --thread=thread\n");
+ printf("\t-b, --backend=backend\n");
+ printf("\t\tfsi:\tAn experimental backend that uses\n");
+ printf("\t\t\tbit-banging to access the host processor\n");
+ printf("\t\t\tvia the FSI bus.\n");
+ printf("\t\ti2c:\tThe default backend which goes via I2C.\n");
+ printf("\t-d, --device=backend device node\n");
+ printf("\t\tDevice node used by the backend to access the bus.\n");
+ printf("\t\tNot used by the FSI backend and defaults to /dev/i2c4\n");
+ printf("\t\tfor the I2C backend.\n");
+ printf("\t-a, --address=backend device address\n");
+ printf("\t\tDevice address to use for the backend. Not used by FSI\n");
+ printf("\t\tand defaults to 0x50 for I2C\n");
printf("\t-h, --help\n");
printf("\n");
printf(" Commands:\n");
@@ -119,11 +137,14 @@ static bool parse_options(int argc, char *argv[])
{"processor", required_argument, NULL, 'p'},
{"chip", required_argument, NULL, 'c'},
{"thread", required_argument, NULL, 't'},
+ {"backend", required_argument, NULL, 'b'},
+ {"device", required_argument, NULL, 'd'},
+ {"address", required_argument, NULL, 'a'},
{"help", no_argument, NULL, 'h'},
};
do {
- c = getopt_long(argc, argv, "-p:c:t:h", long_opts, &oidx);
+ c = getopt_long(argc, argv, "-p:c:t:b:d:a:h", long_opts, &oidx);
switch(c) {
case 1:
/* Positional argument */
@@ -156,6 +177,27 @@ static bool parse_options(int argc, char *argv[])
opt_error = errno;
break;
+ case 'b':
+ opt_error = false;
+ if (strcmp(optarg, "fsi") == 0)
+ backend = FSI;
+ else if (strcmp(optarg, "i2c") == 0)
+ backend = I2C;
+ else
+ opt_error = true;
+ break;
+
+ case 'd':
+ opt_error = false;
+ device_node = optarg;
+ break;
+
+ case 'a':
+ errno = 0;
+ i2c_addr = strtoull(optarg, NULL, 0);
+ opt_error = errno;
+ break;
+
case 'h':
opt_error = true;
break;
@@ -245,9 +287,20 @@ int main(int argc, char *argv[])
if (parse_options(argc, argv))
return 1;
- if (backend_init(processor)) {
- PR_ERROR("Unable to initialise backend\n");
- return 1;
+ switch (backend) {
+ case I2C:
+ if (backend_i2c_init(device_node, i2c_addr)) {
+ PR_ERROR("Unable to I2C initialise backend\n");
+ return 1;
+ }
+ break;
+
+ case FSI:
+ if (backend_fsi_init(processor)) {
+ PR_ERROR("Unable to FSI initialise backend\n");
+ return 1;
+ }
+ break;
}
switch(cmd) {
OpenPOWER on IntegriCloud