diff options
Diffstat (limited to 'roms/skiboot/external/lpc')
-rw-r--r-- | roms/skiboot/external/lpc/Makefile | 8 | ||||
-rw-r--r-- | roms/skiboot/external/lpc/lpc.c | 178 |
2 files changed, 186 insertions, 0 deletions
diff --git a/roms/skiboot/external/lpc/Makefile b/roms/skiboot/external/lpc/Makefile new file mode 100644 index 000000000..1c14945c8 --- /dev/null +++ b/roms/skiboot/external/lpc/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +all: lpc + +lpc: lpc.c + $(CC) -o $@ $^ + +clean: rm -rf *.[od] lpc diff --git a/roms/skiboot/external/lpc/lpc.c b/roms/skiboot/external/lpc/lpc.c new file mode 100644 index 000000000..112183705 --- /dev/null +++ b/roms/skiboot/external/lpc/lpc.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * LPC operations through debugfs interface + * + * Copyright 2014-2018 IBM Corp. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <byteswap.h> +#include <stdint.h> +#include <stdbool.h> +#include <getopt.h> +#include <limits.h> +#include <arpa/inet.h> +#include <assert.h> +#include <endian.h> +#include <byteswap.h> + +#define SYSFS_PREFIX "/sys/kernel/debug/powerpc/lpc" + +int main(int argc, char *argv[]) +{ + char path[256]; + char *dot; + char *eq; + int fd, size = 4; + bool do_write = false; + bool big_endian = false; + uint32_t addr, val; + ssize_t rc; + + if (argc < 3) { + printf("Usage: %s <space> <addr>[.lLwWbBd[,size]][=value]\n", argv[0]); + return 0; + } + + eq = strchr(argv[2], '='); + if (eq) { + do_write = true; + val = strtoul(eq + 1, NULL, 0); + *eq = 0; + } + dot = strchr(argv[2], '.'); + if (dot) { + *(dot++) = 0; + switch(*dot) { + case 'L': + big_endian = true; + case 'l': + break; + case 'W': + big_endian = true; + case 'w': + size = 2; + break; + case 'B': + big_endian = true; + case 'b': + size = 1; + break; + default: + fprintf(stderr, "Invalid size specifier\n"); + exit(1); + } + } + addr = strtoul(argv[2], NULL, 0); + + memset(path, 0, sizeof(path)); + snprintf(path, 255, SYSFS_PREFIX "/%s", argv[1]); + fd = open(path, O_RDWR); + if (fd < 0) { + perror("Failed to open sysfs file"); + exit(1); + } + + lseek(fd, addr, SEEK_SET); + if (do_write) { + uint8_t v8; + uint16_t v16; + uint32_t v32; + + switch(size) { + case 1: + val &= 0xff; + v8 = val; + rc = write(fd, &v8, 1); + if (rc != 1) { + perror("Failed to write to LPC"); + exit(1); + } + printf("[%s] W 0x%08x.%c=0x%02x\n", + argv[1], addr, big_endian ? 'B' : 'b', val); + break; + case 2: + val &= 0xffff; +#if __BYTE_ORDER == __LITTLE_ENDIAN + v16 = big_endian ? bswap_16(val) : val; +#else + v16 = big_endian ? val : bswap_16(val); +#endif + rc = write(fd, &v16, 2); + if (rc != 2) { + perror("Failed to write to LPC"); + exit(1); + } + printf("[%s] W 0x%08x.%c=0x%04x\n", + argv[1], addr, big_endian ? 'W' : 'w', val); + break; + default: +#if __BYTE_ORDER == __LITTLE_ENDIAN + v32 = big_endian ? bswap_32(val) : val; +#else + v32 = big_endian ? val : bswap_32(val); +#endif + rc = write(fd, &v32, 4); + if (rc != 4) { + perror("Failed to write to LPC"); + exit(1); + } + printf("[%s] W 0x%08x.%c=0x%08x\n", + argv[1], addr, big_endian ? 'L' : 'l', val); + break; + } + } else { + uint8_t v8; + uint16_t v16; + uint32_t v32; + + switch(size) { + case 1: + rc = read(fd, &v8, 1); + if (rc != 1) { + perror("Failed to read from LPC"); + exit(1); + } + printf("[%s] R 0x%08x.%c=0x%02x\n", argv[1], addr, + big_endian ? 'B' : 'b', v8); + break; + case 2: + rc = read(fd, &v16, 2); + if (rc != 2) { + perror("Failed to read from LPC"); + exit(1); + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + v16 = big_endian ? bswap_16(v16) : v16; +#else + v16 = big_endian ? v16 : bswap_16(v16); +#endif + printf("[%s] R 0x%08x.%c=0x%04x\n", argv[1], addr, + big_endian ? 'W' : 'w', v16); + break; + default: + rc = read(fd, &v32, 4); + if (rc != 4) { + perror("Failed to read from LPC"); + exit(1); + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + v32 = big_endian ? bswap_32(v32) : v32; +#else + v32 = big_endian ? v32 : bswap_32(v32); +#endif + printf("[%s] R 0x%08x.%c=0x%08x\n", argv[1], addr, + big_endian ? 'L' : 'l', v32); + break; + } + } + return 0; +} |