summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2017-08-16 16:40:45 +1000
committerAlistair Popple <alistair@popple.id.au>2017-08-16 16:40:45 +1000
commit8c083c3c59e9ef208059ed512fd7fd2ab745ffd1 (patch)
tree99ebd1f4d7919a58747739c87e44f0891a40b10c
parent0bf4a14b4c9765ca3ddb4256bbfdc529d7f9bb95 (diff)
downloadpdbg-8c083c3c59e9ef208059ed512fd7fd2ab745ffd1.tar.gz
pdbg-8c083c3c59e9ef208059ed512fd7fd2ab745ffd1.zip
Add indirect SCOM access
Allows access to scom addresses with IBM bit 0 set (ie. indirect scom addresses). Signed-off-by: Alistair Popple <alistair@popple.id.au>
-rw-r--r--libpdbg/target.c91
1 files changed, 87 insertions, 4 deletions
diff --git a/libpdbg/target.c b/libpdbg/target.c
index aa446b1..ebf41bb 100644
--- a/libpdbg/target.c
+++ b/libpdbg/target.c
@@ -4,8 +4,10 @@
#include <ccan/list/list.h>
#include <libfdt/libfdt.h>
+#include "bitutils.h"
#include "target.h"
#include "device.h"
+#include "operations.h"
#undef PR_DEBUG
#define PR_DEBUG(...)
@@ -33,6 +35,83 @@ static struct dt_node *get_class_target_addr(struct dt_node *dn, const char *nam
return dn;
}
+/* The indirect access code was largely stolen from hw/xscom.c in skiboot */
+#define PIB_IND_MAX_RETRIES 10
+#define PIB_IND_READ PPC_BIT(0)
+#define PIB_IND_ADDR PPC_BITMASK(12, 31)
+#define PIB_IND_DATA PPC_BITMASK(48, 63)
+
+#define PIB_DATA_IND_COMPLETE PPC_BIT(32)
+#define PIB_DATA_IND_ERR PPC_BITMASK(33, 35)
+#define PIB_DATA_IND_DATA PPC_BITMASK(48, 63)
+
+static int pib_indirect_read(struct pib *pib, uint64_t addr, uint64_t *data)
+{
+ uint64_t indirect_addr;
+ int retries;
+
+ if ((addr >> 60) & 1) {
+ PR_ERROR("Indirect form 1 not supported\n");
+ return -1;
+ }
+
+ indirect_addr = addr & 0x7fffffff;
+ *data = PIB_IND_READ | (addr & PIB_IND_ADDR);
+ CHECK_ERR(pib->write(pib, indirect_addr, *data));
+
+ /* Wait for completion */
+ for (retries = 0; retries < PIB_IND_MAX_RETRIES; retries++) {
+ CHECK_ERR(pib->read(pib, indirect_addr, data));
+
+ if ((*data & PIB_DATA_IND_COMPLETE) &&
+ ((*data & PIB_DATA_IND_ERR) == 0)) {
+ *data = *data & PIB_DATA_IND_DATA;
+ break;
+ }
+
+ if ((*data & PIB_DATA_IND_COMPLETE) ||
+ (retries >= PIB_IND_MAX_RETRIES)) {
+ PR_ERROR("Error reading indirect register");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int pib_indirect_write(struct pib *pib, uint64_t addr, uint64_t data)
+{
+ uint64_t indirect_addr;
+ int retries;
+
+ if ((addr >> 60) & 1) {
+ PR_ERROR("Indirect form 1 not supported\n");
+ return -1;
+ }
+
+ indirect_addr = addr & 0x7fffffff;
+ data &= PIB_IND_DATA;
+ data |= addr & PIB_IND_ADDR;
+ CHECK_ERR(pib->write(pib, indirect_addr, data));
+
+ /* Wait for completion */
+ for (retries = 0; retries < PIB_IND_MAX_RETRIES; retries++) {
+ CHECK_ERR(pib->read(pib, indirect_addr, &data));
+
+ if ((data & PIB_DATA_IND_COMPLETE) &&
+ ((data & PIB_DATA_IND_ERR) == 0))
+ break;
+
+ if ((data & PIB_DATA_IND_COMPLETE) ||
+ (retries >= PIB_IND_MAX_RETRIES)) {
+ PR_ERROR("Error writing indirect register");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
int pib_read(struct target *pib_dt, uint64_t addr, uint64_t *data)
{
struct pib *pib;
@@ -42,8 +121,10 @@ int pib_read(struct target *pib_dt, uint64_t addr, uint64_t *data)
dn = get_class_target_addr(dn, "pib", &addr);
pib_dt = dn->target;
pib = target_to_pib(pib_dt);
- rc = pib->read(pib, addr, data);
-// printf("pib_read 0x%016llx = 0x%016llx\n", addr, *data);
+ if (addr & PPC_BIT(0))
+ rc = pib_indirect_read(pib, addr, data);
+ else
+ rc = pib->read(pib, addr, data);
return rc;
}
@@ -56,8 +137,10 @@ int pib_write(struct target *pib_dt, uint64_t addr, uint64_t data)
dn = get_class_target_addr(dn, "pib", &addr);
pib_dt = dn->target;
pib = target_to_pib(pib_dt);
- rc = pib->write(pib, addr, data);
-// printf("pib_write 0x%016llx = 0x%016llx\n", addr, data);
+ if (addr & PPC_BIT(0))
+ rc = pib_indirect_write(pib, addr, data);
+ else
+ rc = pib->write(pib, addr, data);
return rc;
}
OpenPOWER on IntegriCloud