diff options
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | libpdbg/backend.h | 3 | ||||
| -rw-r--r-- | libpdbg/i2c.c | 174 | ||||
| -rw-r--r-- | libpdbg/scom.c | 13 | ||||
| -rw-r--r-- | src/main.c | 61 |
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) @@ -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) { |

