diff options
author | Alistair Popple <alistair@popple.id.au> | 2018-04-27 14:08:51 +1000 |
---|---|---|
committer | Alistair Popple <alistair@popple.id.au> | 2018-04-27 14:08:51 +1000 |
commit | ad058f045c4403346c92ddd9115397a939b44a79 (patch) | |
tree | 83659a06243db24d7d860c59af7d343bb02bd03a /libpdbg | |
parent | d74029ccdd3bb680e3753a07df4ff60c3e18aea2 (diff) | |
download | pdbg-ad058f045c4403346c92ddd9115397a939b44a79.tar.gz pdbg-ad058f045c4403346c92ddd9115397a939b44a79.zip |
libpdbg: Add support for getring on POWER9
Add basic support for a getring operation on POWER9.
Signed-off-by: Alistair Popple <alistair@popple.id.au>
Diffstat (limited to 'libpdbg')
-rw-r--r-- | libpdbg/chip.c | 12 | ||||
-rw-r--r-- | libpdbg/libpdbg.h | 2 | ||||
-rw-r--r-- | libpdbg/p9chip.c | 99 | ||||
-rw-r--r-- | libpdbg/target.c | 22 | ||||
-rw-r--r-- | libpdbg/target.h | 2 |
5 files changed, 133 insertions, 4 deletions
diff --git a/libpdbg/chip.c b/libpdbg/chip.c index 06ea4e9..79bc87d 100644 --- a/libpdbg/chip.c +++ b/libpdbg/chip.c @@ -272,3 +272,15 @@ int ram_getmem(struct pdbg_target *thread, uint64_t addr, uint64_t *value) *value = results[3]; return 0; } + +/* + * Read the given ring from the given chiplet. Result must be large enough to hold ring_len bits. + */ +int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]) +{ + struct chiplet *chiplet; + + assert(!strcmp(chiplet_target->class, "chiplet")); + chiplet = target_to_chiplet(chiplet_target); + return chiplet->getring(chiplet, ring_addr, ring_len, result); +} diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h index 15537b8..f843816 100644 --- a/libpdbg/libpdbg.h +++ b/libpdbg/libpdbg.h @@ -78,6 +78,7 @@ int fsi_write(struct pdbg_target *target, uint32_t addr, uint32_t val); int pib_read(struct pdbg_target *target, uint64_t addr, uint64_t *val); int pib_write(struct pdbg_target *target, uint64_t addr, uint64_t val); +int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data); int ram_putmsr(struct pdbg_target *target, uint64_t val); int ram_putnia(struct pdbg_target *target, uint64_t val); @@ -92,6 +93,7 @@ int ram_step_thread(struct pdbg_target *target, int steps); int ram_stop_thread(struct pdbg_target *target); int ram_sreset_thread(struct pdbg_target *target); uint64_t thread_status(struct pdbg_target *target); +int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]); #define THREAD_STATUS_DISABLED PPC_BIT(0) #define THREAD_STATUS_ACTIVE PPC_BIT(63) diff --git a/libpdbg/p9chip.c b/libpdbg/p9chip.c index 41f694e..380cb59 100644 --- a/libpdbg/p9chip.c +++ b/libpdbg/p9chip.c @@ -35,11 +35,34 @@ #define P9_SPR_MODE 0x10a84 #define P9_SCR0_REG 0x10a86 +#define CHIPLET_CTRL0_WOR 0x10 +#define CHIPLET_CTRL0_CLEAR 0x20 +#define CHIPLET_CTRL0_CTRL_CC_ABIST_MUXSEL_DC PPC_BIT(0) +#define CHIPLET_CTRL0_TC_UNIT_SYNCCLK_MUXSEL_DC PPC_BIT(1) +#define CHIPLET_CTRL0_CTRL_CC_FLUSHMODE_INH_DC PPC_BIT(2) + +#define CHIPLET_CTRL1_WOR 0x11 +#define CHIPLET_CTRL1_TC_VITL_REGION_FENCE PPC_BIT(3) + +#define CHIPLET_STAT0 0x100 +#define CHIPLET_STAT0_CC_CTRL_OPCG_DONE_DC PPC_BIT(8) + +#define CHIPLET_SCAN_REGION_TYPE 0x30005 +#define CHIPLET_CLK_REGION 0x30006 +#define CHIPLET_CLK_REGION_CLOCK_CMD PPC_BITMASK(0, 1) +#define CHIPLET_CLK_REGION_CLOCK_CMD_STOP 0x2 +#define CHIPLET_CLK_REGION_SLAVE_MODE PPC_BIT(2) +#define CHIPLET_CLK_REGION_MASTER_MODE PPC_BIT(3) +#define CHIPLET_CLK_REGION_REGIONS PPC_BITMASK(4, 14) +#define CHIPLET_CLK_REGION_SEL_THOLD PPC_BITMASK(48, 50) + /* PCB Slave Registers */ -#define NET_CTRL0 0xf0040 -#define NET_CTRL0_CHIPLET_ENABLE PPC_BIT(0) -#define PPM_GPMMR 0xf0100 -#define PPM_SPWKUP_OTR 0xf010a +#define NET_CTRL0 0xf0040 +#define NET_CTRL0_CHIPLET_ENABLE PPC_BIT(0) +#define NET_CTRL0_FENCE_EN PPC_BIT(18) +#define NET_CTRL0_WOR 0xf0042 +#define PPM_GPMMR 0xf0100 +#define PPM_SPWKUP_OTR 0xf010a #define SPECIAL_WKUP_DONE PPC_BIT(1) #define RAS_STATUS_TIMEOUT 100 @@ -215,6 +238,73 @@ struct thread p9_thread = { }; DECLARE_HW_UNIT(p9_thread); +#define HEADER_CHECK_DATA ((uint64_t) 0xc0ffee03 << 32) + +static int p9_chiplet_getring(struct chiplet *chiplet, uint64_t ring_addr, int64_t ring_len, uint32_t result[]) +{ + uint64_t scan_type_addr; + uint64_t scan_data_addr; + uint64_t scan_header_addr; + uint64_t scan_type_data; + uint64_t set_pulse = 1; + uint64_t bits = 32; + uint64_t data; + + /* We skip the first word in the results so we can write it later as it + * should contain the header read out at the end */ + int i = 0; + + scan_type_addr = (ring_addr & 0x7fff0000) | 0x7; + scan_data_addr = (scan_type_addr & 0xffff0000) | 0x8000; + scan_header_addr = scan_data_addr & 0xffffe000; + + scan_type_data = (ring_addr & 0xfff0) << 13; + scan_type_data |= 0x800 >> (ring_addr & 0xf); + scan_type_data <<= 32; + + pib_write(&chiplet->target, scan_type_addr, scan_type_data); + pib_write(&chiplet->target, scan_header_addr, HEADER_CHECK_DATA); + + /* The final 32 bit read is the header which we do at the end */ + ring_len -= 32; + i = 1; + + while (ring_len > 0) { + ring_len -= bits; + if (set_pulse) { + scan_data_addr |= 0x4000; + set_pulse = 0; + } else + scan_data_addr &= ~0x4000ULL; + + scan_data_addr &= ~0xffull; + scan_data_addr |= bits; + pib_read(&chiplet->target, scan_data_addr, &data); + + /* Discard lower 32 bits */ + /* TODO: We always read 64-bits from the ring on P9 so we could + * optimise here by reading 64-bits at a time, but I'm not + * confident I've figured that out and 32-bits is what Hostboot + * does and seems to work. */ + data >>= 32; + + /* Left-align data */ + data <<= 32 - bits; + result[i++] = data; + if (ring_len > 0 && (ring_len < bits)) + bits = ring_len; + } + + pib_read(&chiplet->target, scan_header_addr | 0x20, &data); + data &= 0xffffffff00000000; + result[0] = data >> 32; + if (data != HEADER_CHECK_DATA) + printf("WARNING: Header check failed. Make sure you specified the right ring length!\n" + "Ring data is probably corrupt now.\n"); + + return 0; +} + static int p9_core_probe(struct pdbg_target *target) { int i = 0; @@ -271,5 +361,6 @@ struct chiplet p9_chiplet = { .class = "chiplet", .probe = p9_chiplet_probe, }, + .getring = p9_chiplet_getring, }; DECLARE_HW_UNIT(p9_chiplet); diff --git a/libpdbg/target.c b/libpdbg/target.c index 7e42b58..704d7d5 100644 --- a/libpdbg/target.c +++ b/libpdbg/target.c @@ -139,6 +139,28 @@ int pib_write(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data) return rc; } +/* Wait for a SCOM register addr to match value & mask == data */ +int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data) +{ + struct pib *pib; + uint64_t tmp; + int rc; + + pib_dt = get_class_target_addr(pib_dt, "pib", &addr); + pib = target_to_pib(pib_dt); + + do { + if (addr & PPC_BIT(0)) + rc = pib_indirect_read(pib, addr, &tmp); + else + rc = pib->read(pib, addr, &tmp); + if (rc) + return rc; + } while ((tmp & mask) != data); + + return 0; +} + int opb_read(struct pdbg_target *opb_dt, uint32_t addr, uint32_t *data) { struct opb *opb; diff --git a/libpdbg/target.h b/libpdbg/target.h index dc91d68..eba26cb 100644 --- a/libpdbg/target.h +++ b/libpdbg/target.h @@ -157,5 +157,7 @@ struct thread { /* Place holder for chiplets which we just want translation for */ struct chiplet { struct pdbg_target target; + int (*getring)(struct chiplet *, uint64_t, int64_t, uint32_t[]); }; +#define target_to_chiplet(x) container_of(x, struct chiplet, target) #endif |