254 lines
8.8 KiB
C
254 lines
8.8 KiB
C
/* Copyright 2013-2014 IBM Corp.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
* implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef __XSCOM_H
|
|
#define __XSCOM_H
|
|
|
|
#include <stdint.h>
|
|
#include <processor.h>
|
|
#include <cpu.h>
|
|
|
|
/*
|
|
* SCOM "partID" definitions:
|
|
*
|
|
* All Ids are 32-bits long, top nibble is reserved for the
|
|
* 'type' field:
|
|
* 0x0 = Processor Chip
|
|
* 0x8 = Memory Buffer (Centaur) Chip
|
|
* 0x4 = EX/Core Chiplet
|
|
*
|
|
* Processor Chip = Logical Fabric Id = PIR>>7
|
|
* 0b0000.0000.0000.0000.0000.0000.00NN.NCCC
|
|
* N=Node, C=Chip
|
|
* Centaur Chip = Associated Processor Chip with memory channel
|
|
* appended and flag set
|
|
* 0b1000.0000.0000.0000.0000.00NN.NCCC.MMMM
|
|
* N=Node, C=Chip, M=Memory Channel
|
|
* Processor EX/Core chiplet = PIR >> 3 with flag set.
|
|
* On P8:
|
|
* 0b0100.0000.0000.0000.0000.00NN.NCCC.PPPP
|
|
* On P9:
|
|
* 0b0100.0000.0000.0000.0000.0NNN.CCCP.PPPP
|
|
* N=Node, C=Chip, P=Processor core
|
|
*/
|
|
|
|
/*
|
|
* SCOM Address definition extracted from HWPs for documentation
|
|
* purposes
|
|
*
|
|
* "Normal" (legacy) format
|
|
*
|
|
* 111111 11112222 22222233 33333333 44444444 44555555 55556666
|
|
* 01234567 89012345 67890123 45678901 23456789 01234567 89012345 67890123
|
|
* -------- -------- -------- -------- -------- -------- -------- --------
|
|
* 00000000 00000000 00000000 00000000 0MCCCCCC ????PPPP 00LLLLLL LLLLLLLL
|
|
* || | |
|
|
* || | `-> Local Address*
|
|
* || |
|
|
* || `-> Port
|
|
* ||
|
|
* |`-> Chiplet ID**
|
|
* |
|
|
* `-> Multicast bit
|
|
*
|
|
* * Local address is composed of "00" + 4-bit ring + 10-bit ID
|
|
* The 10-bit ID is usually 4-bit sat_id and 6-bit reg_id
|
|
*
|
|
* ** Chiplet ID turns into multicast operation type and group number
|
|
* if the multicast bit is set
|
|
*
|
|
* "Indirect" format
|
|
*
|
|
*
|
|
* 111111 11112222 22222233 33333333 44444444 44555555 55556666
|
|
* 01234567 89012345 67890123 45678901 23456789 01234567 89012345 67890123
|
|
* -------- -------- -------- -------- -------- -------- -------- --------
|
|
* 10000000 0000IIII IIIIIGGG GGGLLLLL 0MCCCCCC ????PPPP 00LLLLLL LLLLLLLL
|
|
* | | | || | |
|
|
* | | | || | `-> Local Address*
|
|
* | | | || |
|
|
* | | | || `-> Port
|
|
* | | | ||
|
|
* | | | |`-> Chiplet ID**
|
|
* | | | |
|
|
* | | | `-> Multicast bit
|
|
* | | |
|
|
* | | `-> Lane ID
|
|
* | |
|
|
* | `-> RX or TX Group ID
|
|
* |
|
|
* `-> Indirect Register Address
|
|
*
|
|
* * Local address is composed of "00" + 4-bit ring + 4-bit sat_id + "111111"
|
|
*
|
|
* ** Chiplet ID turns into multicast operation type and group number
|
|
* if the multicast bit is set
|
|
*/
|
|
|
|
/*
|
|
* Generate a local address from a given ring/satellite/offset
|
|
* combination:
|
|
*
|
|
* Ring Satellite offset
|
|
* +---------+---------+-------------+
|
|
* | 4 | 4 | 6 |
|
|
* +---------+---------+-------------+
|
|
*/
|
|
#define XSCOM_SAT(_r, _s, _o) \
|
|
(((_r) << 10) | ((_s) << 6) | (_o))
|
|
|
|
/*
|
|
* Additional useful definitions for P8
|
|
*/
|
|
#define P8_EX_PCB_SLAVE_BASE 0x100F0000
|
|
|
|
#define XSCOM_ADDR_P8_EX_SLAVE(core, offset) \
|
|
(P8_EX_PCB_SLAVE_BASE | (((core) & 0xF) << 24) | ((offset) & 0xFFFF))
|
|
|
|
#define XSCOM_ADDR_P8_EX(core, addr) \
|
|
((((core) & 0xF) << 24) | (addr))
|
|
|
|
/*
|
|
* Additional useful definitions for P9
|
|
*/
|
|
|
|
/* An EQ is a quad (also named an EP) */
|
|
#define XSCOM_ADDR_P9_EP(core, addr) \
|
|
(((((core) & 0x1c) + 0x40) << 22) | (addr))
|
|
#define XSCOM_ADDR_P9_EP_SLAVE(core, addr) \
|
|
XSCOM_ADDR_P9_EP(core, (addr) | 0xf0000)
|
|
|
|
/* An EX is a pair of cores. They are accessed via their corresponding EQs
|
|
* with bit 0x400 indicating which of the 2 EX to address
|
|
*/
|
|
#define XSCOM_ADDR_P9_EX(core, addr) \
|
|
(XSCOM_ADDR_P9_EP(core, addr | (((core) & 2) << 9)))
|
|
|
|
/* An EC is an individual core and has its own XSCOM addressing */
|
|
#define XSCOM_ADDR_P9_EC(core, addr) \
|
|
(((((core) & 0x1F) + 0x20) << 24) | (addr))
|
|
#define XSCOM_ADDR_P9_EC_SLAVE(core, addr) \
|
|
XSCOM_ADDR_P9_EC(core, (addr) | 0xf0000)
|
|
|
|
/* Power 9 EC slave per-core power mgt slave registers */
|
|
#define EC_PPM_SPECIAL_WKUP_OTR 0x010A
|
|
#define EC_PPM_SPECIAL_WKUP_FSP 0x010B
|
|
#define EC_PPM_SPECIAL_WKUP_OCC 0x010C
|
|
#define EC_PPM_SPECIAL_WKUP_HYP 0x010D
|
|
|
|
/************* XXXX Move these P8 only registers elswhere !!! ****************/
|
|
|
|
/* Per core power mgt registers */
|
|
#define PM_OHA_MODE_REG 0x1002000D
|
|
#define L2_FIR_ACTION1 0x10012807
|
|
|
|
/* EX slave per-core power mgt slave regisers */
|
|
#define EX_PM_GP0 0x0100
|
|
#define EX_PM_GP1 0x0103
|
|
#define EX_PM_CLEAR_GP1 0x0104 /* AND SCOM */
|
|
#define EX_PM_SET_GP1 0x0105 /* OR SCOM */
|
|
#define EX_PM_SPECIAL_WAKEUP_FSP 0x010B
|
|
#define EX_PM_SPECIAL_WAKEUP_OCC 0x010C
|
|
#define EX_PM_SPECIAL_WAKEUP_PHYP 0x010D
|
|
#define EX_PM_IDLE_STATE_HISTORY_PHYP 0x0110
|
|
#define EX_PM_IDLE_STATE_HISTORY_FSP 0x0111
|
|
#define EX_PM_IDLE_STATE_HISTORY_OCC 0x0112
|
|
#define EX_PM_IDLE_STATE_HISTORY_PERF 0x0113
|
|
#define EX_PM_CORE_PFET_VRET 0x0130
|
|
#define EX_PM_CORE_ECO_VRET 0x0150
|
|
#define EX_PM_PPMSR 0x0153
|
|
#define EX_PM_PPMCR 0x0159
|
|
|
|
/* Power mgt bits in GP0 */
|
|
#define EX_PM_GP0_SPECIAL_WAKEUP_DONE PPC_BIT(31)
|
|
|
|
/* Power mgt settings in GP1 */
|
|
#define EX_PM_SETUP_GP1_FAST_SLEEP 0xD800000000000000ULL
|
|
#define EX_PM_SETUP_GP1_DEEP_SLEEP 0x2400000000000000ULL
|
|
#define EX_PM_SETUP_GP1_FAST_SLEEP_DEEP_WINKLE 0xC400000000000000ULL
|
|
#define EX_PM_GP1_SLEEP_WINKLE_MASK 0xFC00000000000000ULL
|
|
#define EX_PM_SETUP_GP1_PM_SPR_OVERRIDE_EN 0x0010000000000000ULL
|
|
#define EX_PM_SETUP_GP1_DPLL_FREQ_OVERRIDE_EN 0x0020000000000000ULL
|
|
|
|
/* Fields in history regs */
|
|
#define EX_PM_IDLE_ST_HIST_PM_STATE_MASK PPC_BITMASK(0, 2)
|
|
#define EX_PM_IDLE_ST_HIST_PM_STATE_LSH PPC_BITLSHIFT(2)
|
|
|
|
/***************************************************************************/
|
|
|
|
/* Definitions relating to indirect XSCOMs shared with centaur */
|
|
#define XSCOM_ADDR_IND_FLAG PPC_BIT(0)
|
|
#define XSCOM_ADDR_IND_ADDR PPC_BITMASK(12,31)
|
|
#define XSCOM_ADDR_IND_DATA PPC_BITMASK(48,63)
|
|
|
|
#define XSCOM_DATA_IND_READ PPC_BIT(0)
|
|
#define XSCOM_DATA_IND_COMPLETE PPC_BIT(32)
|
|
#define XSCOM_DATA_IND_ERR PPC_BITMASK(33,35)
|
|
#define XSCOM_DATA_IND_DATA PPC_BITMASK(48,63)
|
|
#define XSCOM_DATA_IND_FORM1_DATA PPC_BITMASK(12,63)
|
|
|
|
/* HB folks say: try 10 time for now */
|
|
#define XSCOM_IND_MAX_RETRIES 10
|
|
|
|
/* Max number of retries when XSCOM remains busy */
|
|
#define XSCOM_BUSY_MAX_RETRIES 3000
|
|
|
|
/* Max number of retries for xscom clearing recovery. */
|
|
#define XSCOM_CLEAR_MAX_RETRIES 10
|
|
|
|
/* Retry count after which to reset XSCOM, if still busy */
|
|
#define XSCOM_BUSY_RESET_THRESHOLD 1000
|
|
|
|
/*
|
|
* Error handling:
|
|
*
|
|
* Error codes TBD, 0 = success
|
|
*/
|
|
|
|
/* Use only in select places where multiple SCOMs are time/latency sensitive */
|
|
extern void _xscom_lock(void);
|
|
extern int _xscom_read(uint32_t partid, uint64_t pcb_addr, uint64_t *val, bool take_lock);
|
|
extern int _xscom_write(uint32_t partid, uint64_t pcb_addr, uint64_t val, bool take_lock);
|
|
extern void _xscom_unlock(void);
|
|
|
|
|
|
/* Targeted SCOM access */
|
|
static inline int xscom_read(uint32_t partid, uint64_t pcb_addr, uint64_t *val)
|
|
{
|
|
return _xscom_read(partid, pcb_addr, val, true);
|
|
}
|
|
static inline int xscom_write(uint32_t partid, uint64_t pcb_addr, uint64_t val) {
|
|
return _xscom_write(partid, pcb_addr, val, true);
|
|
}
|
|
extern int xscom_write_mask(uint32_t partid, uint64_t pcb_addr, uint64_t val, uint64_t mask);
|
|
|
|
/* This chip SCOM access */
|
|
extern int xscom_readme(uint64_t pcb_addr, uint64_t *val);
|
|
extern int xscom_writeme(uint64_t pcb_addr, uint64_t val);
|
|
extern void xscom_init(void);
|
|
|
|
/* Mark XSCOM lock as being in console path */
|
|
extern void xscom_used_by_console(void);
|
|
|
|
/* Returns true if XSCOM can be used. Typically this returns false if
|
|
* the current CPU holds the XSCOM lock (to avoid re-entrancy from error path).
|
|
*/
|
|
extern bool xscom_ok(void);
|
|
|
|
extern int64_t xscom_read_cfam_chipid(uint32_t partid, uint32_t *chip_id);
|
|
extern int64_t xscom_trigger_xstop(void);
|
|
|
|
#endif /* __XSCOM_H */
|