summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--devmem-aspeed.c118
1 files 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 <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
+#include <pci/pci.h>
-#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;
OpenPOWER on IntegriCloud