From c2ef9e55120a453878e9e912270f852f7e071174 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Wed, 7 Sep 2016 23:25:28 -0500 Subject: Enable read/write of AST2400 registers --- devmem-aspeed.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 21 deletions(-) diff --git a/devmem-aspeed.c b/devmem-aspeed.c index 4831b12..6034dcd 100644 --- a/devmem-aspeed.c +++ b/devmem-aspeed.c @@ -1,7 +1,9 @@ /* * devmem2.c: Simple program to read/write from/to any location in memory. * - * Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * Copyright (C) 2000 Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * Copyright (C) 2009 Carl-Daniel Hailfinger + * Copyright (C) 2016 Raptor Engineering, LLC * * * This software has been developed for the LART computing board @@ -48,18 +50,71 @@ #include #include #include +#include -#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ +#define FATAL do { pci_cleanup(pacc);; fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0) -#define MAP_SIZE 4096UL -#define MAP_MASK (MAP_SIZE - 1) +#define MAP_SIZE (128 * 1024) +#define MAP_MASK (MAP_SIZE - 1) +#define ASPEED_P2A_OFFSET 0x10000 + +struct pci_access *pacc; +uintptr_t aspeed_bar_offset = 0; +void *aspeed_bar = NULL; + +struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device) +{ + struct pci_dev *temp; + struct pci_filter filter; + + pci_filter_init(NULL, &filter); + filter.vendor = vendor; + filter.device = device; + + for (temp = pacc->devices; temp; temp = temp->next) + if (pci_filter_match(&filter, temp)) + return temp; + + return NULL; +} + +void sync_primitive(void) +{ +#if defined(__PPC__) || defined(__PPC64__) + asm("eieio" : : : "memory"); +#endif +} + +static int ast2400_set_a2b_bridge_dest_address(uintptr_t address) +{ + aspeed_bar_offset = address & 0xffff; + + *((volatile uint32_t *)(aspeed_bar + 0xf000)) = 0x0; + sync_primitive(); + *((volatile uint32_t *)(aspeed_bar + 0xf004)) = address & 0xffff0000; + sync_primitive(); + *((volatile uint32_t *)(aspeed_bar + 0xf000)) = 0x1; + sync_primitive(); + + return 0; +} + +static int ast2400_disable_a2b_bridge(void) +{ + *((volatile uint32_t *)(aspeed_bar + 0xf000)) = 0x0; + sync_primitive(); + + return 0; +} int main(int argc, char **argv) { int fd; - void *map_base, *virt_addr; - unsigned long read_result, writeval; - off_t target; + void *bar_addr = NULL; + void *virt_addr; + uint32_t read_result, writeval; + uintptr_t target; + struct pci_dev* aspeed_dev = NULL; int access_type = 'w'; if(argc < 2) { @@ -76,28 +131,45 @@ int main(int argc, char **argv) { access_type = tolower(argv[2][0]); } + pacc = pci_alloc(); + pci_init(pacc); + pci_scan_bus(pacc); + + aspeed_dev = pci_dev_find(0x1a03, 0x2000); + if (!aspeed_dev) FATAL; + + bar_addr = (void *)(aspeed_dev->base_addr[1] & PCI_BASE_ADDRESS_MEM_MASK); + printf("Detected ASPEED MMIO base address: 0x%p.\n", bar_addr); + fflush(stdout); + + bar_addr += ASPEED_P2A_OFFSET; + printf("ASPEED P2A base address: 0x%p.\n", bar_addr); + if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL; printf("/dev/mem opened.\n"); fflush(stdout); /* Map one page */ - map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK); - if(map_base == (void *) -1) FATAL; - printf("Memory mapped at address %p.\n", map_base); + aspeed_bar = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (uintptr_t)bar_addr); + if(aspeed_bar == (void *) -1) FATAL; + printf("Memory mapped at address %p.\n", aspeed_bar); fflush(stdout); - virt_addr = map_base + (target & MAP_MASK); + ast2400_set_a2b_bridge_dest_address(target); + + virt_addr = aspeed_bar + (aspeed_bar_offset & MAP_MASK); switch(access_type) { case 'b': - read_result = *((unsigned char *) virt_addr); + read_result = *((volatile uint8_t *) virt_addr); break; case 'h': - read_result = *((unsigned short *) virt_addr); + read_result = *((volatile uint16_t *) virt_addr); break; case 'w': - read_result = *((unsigned long *) virt_addr); + read_result = *((volatile uint32_t *) virt_addr); break; default: + ast2400_disable_a2b_bridge(); fprintf(stderr, "Illegal data type '%c'.\n", access_type); exit(2); } @@ -108,23 +180,27 @@ int main(int argc, char **argv) { writeval = strtoul(argv[3], 0, 0); switch(access_type) { case 'b': - *((unsigned char *) virt_addr) = writeval; - read_result = *((unsigned char *) virt_addr); + *((volatile uint8_t *) virt_addr) = writeval; + sync_primitive(); + read_result = *((volatile uint8_t *) virt_addr); break; case 'h': - *((unsigned short *) virt_addr) = writeval; - read_result = *((unsigned short *) virt_addr); + *((volatile uint16_t *) virt_addr) = writeval; + sync_primitive(); + read_result = *((volatile uint16_t *) virt_addr); break; case 'w': - *((unsigned long *) virt_addr) = writeval; - read_result = *((unsigned long *) virt_addr); + *((volatile uint32_t *) virt_addr) = writeval; + sync_primitive(); + read_result = *((volatile uint32_t *) virt_addr); break; } printf("Written 0x%X; readback 0x%X\n", writeval, read_result); fflush(stdout); } - if(munmap(map_base, MAP_SIZE) == -1) FATAL; + ast2400_disable_a2b_bridge(); + if(munmap(aspeed_bar, MAP_SIZE) == -1) FATAL; close(fd); return 0; -- cgit v1.2.1