diff options
-rw-r--r-- | arch/powerpc/platforms/powernv/opal-xscom.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c index 09a90d8897ba..4d99a8fd55ac 100644 --- a/arch/powerpc/platforms/powernv/opal-xscom.c +++ b/arch/powerpc/platforms/powernv/opal-xscom.c | |||
@@ -71,11 +71,33 @@ static int opal_xscom_err_xlate(int64_t rc) | |||
71 | } | 71 | } |
72 | } | 72 | } |
73 | 73 | ||
74 | static u64 opal_scom_unmangle(u64 reg) | ||
75 | { | ||
76 | /* | ||
77 | * XSCOM indirect addresses have the top bit set. Additionally | ||
78 | * the reset of the top 3 nibbles is always 0. | ||
79 | * | ||
80 | * Because the debugfs interface uses signed offsets and shifts | ||
81 | * the address left by 3, we basically cannot use the top 4 bits | ||
82 | * of the 64-bit address, and thus cannot use the indirect bit. | ||
83 | * | ||
84 | * To deal with that, we support the indirect bit being in bit | ||
85 | * 4 (IBM notation) instead of bit 0 in this API, we do the | ||
86 | * conversion here. To leave room for further xscom address | ||
87 | * expansion, we only clear out the top byte | ||
88 | * | ||
89 | */ | ||
90 | if (reg & (1ull << 59)) | ||
91 | reg = (reg & ~(0xffull << 56)) | (1ull << 63); | ||
92 | return reg; | ||
93 | } | ||
94 | |||
74 | static int opal_scom_read(scom_map_t map, u64 reg, u64 *value) | 95 | static int opal_scom_read(scom_map_t map, u64 reg, u64 *value) |
75 | { | 96 | { |
76 | struct opal_scom_map *m = map; | 97 | struct opal_scom_map *m = map; |
77 | int64_t rc; | 98 | int64_t rc; |
78 | 99 | ||
100 | reg = opal_scom_unmangle(reg); | ||
79 | rc = opal_xscom_read(m->chip, m->addr + reg, (uint64_t *)__pa(value)); | 101 | rc = opal_xscom_read(m->chip, m->addr + reg, (uint64_t *)__pa(value)); |
80 | return opal_xscom_err_xlate(rc); | 102 | return opal_xscom_err_xlate(rc); |
81 | } | 103 | } |
@@ -85,6 +107,7 @@ static int opal_scom_write(scom_map_t map, u64 reg, u64 value) | |||
85 | struct opal_scom_map *m = map; | 107 | struct opal_scom_map *m = map; |
86 | int64_t rc; | 108 | int64_t rc; |
87 | 109 | ||
110 | reg = opal_scom_unmangle(reg); | ||
88 | rc = opal_xscom_write(m->chip, m->addr + reg, value); | 111 | rc = opal_xscom_write(m->chip, m->addr + reg, value); |
89 | return opal_xscom_err_xlate(rc); | 112 | return opal_xscom_err_xlate(rc); |
90 | } | 113 | } |