| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| |
| #ifndef CPU_PPC64_SCOM_H |
| #define CPU_PPC64_SCOM_H |
| |
| #include <arch/byteorder.h> // PPC_BIT(), PPC_BITMASK() |
| |
| // 32b SCOM address: |
| // |
| // 8 7 6 5 4 3 2 1 |
| // |
| // | | | | | 1 1| |1 1 1 1| |1 1 1 1| |2 2 2 2| |2 2 2 2| |2 2 3 3| |
| // |0 1 2 3| |4 5 6 7| |8 9 0 1| |2 3 4 5| |6 7 8 9| |0 1 2 3| |4 5 6 7| |8 9 0 1| |
| // {A}{ B } { C } { D }{ E }{ F } |
| // |
| // A - Is multiCast if bit 1 = 0x1 |
| // B - Contains Chiplet ID (6 bits) [2:7] |
| // C - Contains Port Number (4 bits) [12:15] |
| // D - Ring (4 bits) [18:21] |
| // E - Sat ID (4 bits) [22:25] |
| // F - Sat Offset (6 bits) [26:31] |
| // |
| // For 64b SCOM address all of the fields are shifted 32b to the right: |
| // A - Is multiCast if bit 33 = 0x1 |
| // B - Contains Chiplet ID (6 bits) [34:39] |
| // C - Contains Port Number (4 bits) [44:47] |
| // D - Ring (4 bits) [50:53] |
| // E - Sat ID (4 bits) [54:57] |
| // F - Sat Offset (6 bits) [58:63] |
| // Higher bits specify indirect address |
| |
| #define XSCOM_ADDR_IND_FLAG PPC_BIT(0) |
| |
| #ifndef __ASSEMBLER__ |
| #include <types.h> |
| #include <arch/io.h> |
| |
| // TODO: these are probably specific to POWER9 |
| typedef enum { |
| PIB_CHIPLET_ID = 0x00, ///< PIB chiplet |
| PERV_CHIPLET_ID = 0x01, ///< TP chiplet |
| N0_CHIPLET_ID = 0x02, ///< Nest0 (North) chiplet |
| N1_CHIPLET_ID = 0x03, ///< Nest1 (East) chiplet |
| N2_CHIPLET_ID = 0x04, ///< Nest2 (South) chiplet |
| N3_CHIPLET_ID = 0x05, ///< Nest3 (West) chiplet |
| XB_CHIPLET_ID = 0x06, ///< XBus chiplet |
| MC01_CHIPLET_ID = 0x07, ///< MC01 (West) chiplet |
| MC23_CHIPLET_ID = 0x08, ///< MC23 (East) chiplet |
| OB0_CHIPLET_ID = 0x09, ///< OBus0 chiplet |
| OB1_CHIPLET_ID = 0x0A, ///< OBus1 chiplet (Cumulus only) |
| OB2_CHIPLET_ID = 0x0B, ///< OBus2 chiplet (Cumulus only) |
| OB3_CHIPLET_ID = 0x0C, ///< OBus3 chiplet |
| PCI0_CHIPLET_ID = 0x0D, ///< PCIe0 chiplet |
| PCI1_CHIPLET_ID = 0x0E, ///< PCIe1 chiplet |
| PCI2_CHIPLET_ID = 0x0F, ///< PCIe2 chiplet |
| EP00_CHIPLET_ID = 0x10, ///< Quad0 chiplet (EX0/1) |
| EP01_CHIPLET_ID = 0x11, ///< Quad1 chiplet (EX2/3) |
| EP02_CHIPLET_ID = 0x12, ///< Quad2 chiplet (EX4/5) |
| EP03_CHIPLET_ID = 0x13, ///< Quad3 chiplet (EX6/7) |
| EP04_CHIPLET_ID = 0x14, ///< Quad4 chiplet (EX8/9) |
| EP05_CHIPLET_ID = 0x15, ///< Quad5 chiplet (EX10/11) |
| EC00_CHIPLET_ID = 0x20, ///< Core0 chiplet (Quad0, EX0, C0) |
| EC01_CHIPLET_ID = 0x21, ///< Core1 chiplet (Quad0, EX0, C1) |
| EC02_CHIPLET_ID = 0x22, ///< Core2 chiplet (Quad0, EX1, C0) |
| EC03_CHIPLET_ID = 0x23, ///< Core3 chiplet (Quad0, EX1, C1) |
| EC04_CHIPLET_ID = 0x24, ///< Core4 chiplet (Quad1, EX2, C0) |
| EC05_CHIPLET_ID = 0x25, ///< Core5 chiplet (Quad1, EX2, C1) |
| EC06_CHIPLET_ID = 0x26, ///< Core6 chiplet (Quad1, EX3, C0) |
| EC07_CHIPLET_ID = 0x27, ///< Core7 chiplet (Quad1, EX3, C1) |
| EC08_CHIPLET_ID = 0x28, ///< Core8 chiplet (Quad2, EX4, C0) |
| EC09_CHIPLET_ID = 0x29, ///< Core9 chiplet (Quad2, EX4, C1) |
| EC10_CHIPLET_ID = 0x2A, ///< Core10 chiplet (Quad2, EX5, C0) |
| EC11_CHIPLET_ID = 0x2B, ///< Core11 chiplet (Quad2, EX5, C1) |
| EC12_CHIPLET_ID = 0x2C, ///< Core12 chiplet (Quad3, EX6, C0) |
| EC13_CHIPLET_ID = 0x2D, ///< Core13 chiplet (Quad3, EX6, C1) |
| EC14_CHIPLET_ID = 0x2E, ///< Core14 chiplet (Quad3, EX7, C0) |
| EC15_CHIPLET_ID = 0x2F, ///< Core15 chiplet (Quad3, EX7, C1) |
| EC16_CHIPLET_ID = 0x30, ///< Core16 chiplet (Quad4, EX8, C0) |
| EC17_CHIPLET_ID = 0x31, ///< Core17 chiplet (Quad4, EX8, C1) |
| EC18_CHIPLET_ID = 0x32, ///< Core18 chiplet (Quad4, EX9, C0) |
| EC19_CHIPLET_ID = 0x33, ///< Core19 chiplet (Quad4, EX9, C1) |
| EC20_CHIPLET_ID = 0x34, ///< Core20 chiplet (Quad5, EX10, C0) |
| EC21_CHIPLET_ID = 0x35, ///< Core21 chiplet (Quad5, EX10, C1) |
| EC22_CHIPLET_ID = 0x36, ///< Core22 chiplet (Quad5, EX11, C0) |
| EC23_CHIPLET_ID = 0x37 ///< Core23 chiplet (Quad5, EX11, C1) |
| } chiplet_id_t; |
| |
| uint64_t read_scom_direct(uint64_t reg_address); |
| void write_scom_direct(uint64_t reg_address, uint64_t data); |
| |
| uint64_t read_scom_indirect(uint64_t reg_address); |
| void write_scom_indirect(uint64_t reg_address, uint64_t data); |
| |
| static inline void write_scom(uint64_t addr, uint64_t data) |
| { |
| if (addr & XSCOM_ADDR_IND_FLAG) |
| write_scom_indirect(addr, data); |
| else |
| write_scom_direct(addr, data); |
| } |
| |
| static inline uint64_t read_scom(uint64_t addr) |
| { |
| if (addr & XSCOM_ADDR_IND_FLAG) |
| return read_scom_indirect(addr); |
| else |
| return read_scom_direct(addr); |
| } |
| |
| static inline void scom_and_or(uint64_t addr, uint64_t and, uint64_t or) |
| { |
| uint64_t data = read_scom(addr); |
| write_scom(addr, (data & and) | or); |
| } |
| |
| static inline void scom_and(uint64_t addr, uint64_t and) |
| { |
| scom_and_or(addr, and, 0); |
| } |
| |
| static inline void scom_or(uint64_t addr, uint64_t or) |
| { |
| scom_and_or(addr, ~0, or); |
| } |
| |
| static inline void write_scom_for_chiplet(chiplet_id_t chiplet, uint64_t addr, uint64_t data) |
| { |
| addr &= ~PPC_BITMASK(34, 39); |
| addr |= ((chiplet & 0x3F) << 24); |
| write_scom(addr, data); |
| } |
| |
| static inline uint64_t read_scom_for_chiplet(chiplet_id_t chiplet, uint64_t addr) |
| { |
| addr &= ~PPC_BITMASK(34, 39); |
| addr |= ((chiplet & 0x3F) << 24); |
| return read_scom(addr); |
| } |
| |
| static inline void scom_and_or_for_chiplet(chiplet_id_t chiplet, uint64_t addr, |
| uint64_t and, uint64_t or) |
| { |
| uint64_t data = read_scom_for_chiplet(chiplet, addr); |
| write_scom_for_chiplet(chiplet, addr, (data & and) | or); |
| } |
| |
| static inline void scom_and_for_chiplet(chiplet_id_t chiplet, uint64_t addr, uint64_t and) |
| { |
| scom_and_or_for_chiplet(chiplet, addr, and, 0); |
| } |
| |
| static inline void scom_or_for_chiplet(chiplet_id_t chiplet, uint64_t addr, uint64_t or) |
| { |
| scom_and_or_for_chiplet(chiplet, addr, ~0, or); |
| } |
| |
| #endif /* __ASSEMBLER__ */ |
| #endif /* CPU_PPC64_SCOM_H */ |