| /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| * Copyright 2021 IBM Corp. |
| */ |
| |
| #ifndef __PAU_H |
| #define __PAU_H |
| |
| #include <io.h> |
| #include <pci.h> |
| #include <xscom.h> |
| #include <phb4.h> |
| #include <pau-regs.h> |
| |
| #define PAU_NBR 6 |
| #define PAU_LINKS_OPENCAPI_PER_PAU 2 |
| |
| enum pau_dev_type { |
| PAU_DEV_TYPE_UNKNOWN = 0, |
| PAU_DEV_TYPE_OPENCAPI, |
| PAU_DEV_TYPE_ANY = INT_MAX |
| }; |
| |
| /* Used to expose a hardware BAR (or logical slice of it) outside skiboot */ |
| struct pau_bar { |
| bool enable; |
| uint64_t addr; |
| uint64_t size; |
| uint64_t cfg; |
| }; |
| |
| struct phy_proc_state { |
| struct lock lock; /* protect any change to this structure */ |
| unsigned long timeout; |
| uint16_t step; |
| }; |
| |
| struct pau_dev { |
| enum pau_dev_type type; |
| uint32_t index; |
| struct dt_node *dn; |
| struct phb phb; |
| uint32_t status; |
| unsigned long train_start; |
| unsigned long train_timeout; |
| |
| struct pau_bar ntl_bar; |
| struct pau_bar genid_bar; |
| struct pau_bar memory_bar; |
| |
| /* Associated I2C information */ |
| uint8_t i2c_bus_id; |
| |
| /* Associated PHY information */ |
| uint32_t pau_unit; /* 0,3,4,5,6,7 */ |
| uint32_t odl_index; |
| uint32_t op_unit; /* 0 -> 7 */ |
| uint32_t phy_lane_mask; |
| |
| struct pau *pau; |
| }; |
| |
| struct pau { |
| uint32_t index; |
| struct dt_node *dt_node; |
| uint32_t chip_id; |
| uint32_t op_chiplet; /* from pervasive: 0x10 -> 0x13 */ |
| uint64_t xscom_base; |
| |
| /* Global MMIO window (all PAU regs) */ |
| uint64_t regs[2]; |
| bool mmio_access; |
| |
| uint32_t irq_base; |
| struct lock lock; |
| |
| uint32_t links; |
| struct pau_dev devices[PAU_LINKS_OPENCAPI_PER_PAU]; |
| struct phy_proc_state procedure_state; |
| }; |
| |
| #define PAUDBG(pau, fmt, a...) PAULOG(PR_DEBUG, pau, fmt, ##a) |
| #define PAUINF(pau, fmt, a...) PAULOG(PR_INFO, pau, fmt, ##a) |
| #define PAUERR(pau, fmt, a...) PAULOG(PR_ERR, pau, fmt, ##a) |
| |
| #define PAUDEVDBG(dev, fmt, a...) PAUDEVLOG(PR_DEBUG, dev, fmt, ##a) |
| #define PAUDEVINF(dev, fmt, a...) PAUDEVLOG(PR_INFO, dev, fmt, ##a) |
| #define PAUDEVERR(dev, fmt, a...) PAUDEVLOG(PR_ERR, dev, fmt, ##a) |
| |
| #define PAULOG(l, pau, fmt, a...) \ |
| prlog(l, "PAU[%d:%d]: " fmt, (pau)->chip_id, (pau)->index, ##a) |
| |
| #define PAUDEVLOG(l, dev, fmt, a...) \ |
| prlog(l, "PAU[%d:%d:%d]: " fmt, \ |
| (dev)->pau->chip_id, \ |
| (dev)->pau->index, \ |
| (dev)->index, ##a) |
| |
| |
| /* pau-scope index of the link */ |
| static inline uint32_t pau_dev_index(struct pau_dev *dev, int links) |
| { |
| return dev->pau->index * links + dev->index; |
| } |
| |
| static inline struct pau_dev *pau_phb_to_opencapi_dev(struct phb *phb) |
| { |
| assert(phb->phb_type == phb_type_pau_opencapi); |
| return container_of(phb, struct pau_dev, phb); |
| } |
| |
| struct pau_dev *pau_next_dev(struct pau *pau, struct pau_dev *dev, |
| enum pau_dev_type type); |
| |
| #define pau_for_each_dev_type(dev, pau, type) \ |
| for (dev = NULL; (dev = pau_next_dev(pau, dev, type));) |
| |
| #define pau_for_each_opencapi_dev(dev, pau) \ |
| pau_for_each_dev_type(dev, pau, PAU_DEV_TYPE_OPENCAPI) |
| |
| #define pau_for_each_dev(dev, pau) \ |
| pau_for_each_dev_type(dev, pau, PAU_DEV_TYPE_ANY) |
| |
| #define PAU_PHB_INDEX_BASE 6 /* immediately after real PHBs */ |
| static inline int pau_get_phb_index(unsigned int pau_index, |
| unsigned int link_index) |
| { |
| return PAU_PHB_INDEX_BASE + pau_index * 2 + link_index; |
| } |
| |
| static inline int pau_get_opal_id(unsigned int chip_id, unsigned int index) |
| { |
| return phb4_get_opal_id(chip_id, index); |
| } |
| |
| /* |
| * We use the indirect method because it uses the same addresses as |
| * the MMIO offsets (PAU RING) |
| */ |
| static inline void pau_scom_sel(struct pau *pau, uint64_t reg, |
| uint64_t size) |
| { |
| uint64_t val; |
| |
| val = SETFIELD(PAU_MISC_DA_ADDR, 0ull, reg); |
| val = SETFIELD(PAU_MISC_DA_LEN, val, size); |
| xscom_write(pau->chip_id, |
| pau->xscom_base + PAU_MISC_SCOM_IND_SCOM_ADDR, |
| val); |
| } |
| |
| static inline void pau_scom_write(struct pau *pau, uint64_t reg, |
| uint64_t size, |
| uint64_t val) |
| { |
| pau_scom_sel(pau, reg, size); |
| xscom_write(pau->chip_id, |
| pau->xscom_base + PAU_MISC_SCOM_IND_SCOM_DATA, |
| val); |
| } |
| |
| static inline uint64_t pau_scom_read(struct pau *pau, uint64_t reg, |
| uint64_t size) |
| { |
| uint64_t val; |
| |
| pau_scom_sel(pau, reg, size); |
| xscom_read(pau->chip_id, |
| pau->xscom_base + PAU_MISC_SCOM_IND_SCOM_DATA, |
| &val); |
| |
| return val; |
| } |
| |
| static inline void pau_write(struct pau *pau, uint64_t reg, |
| uint64_t val) |
| { |
| void *mmio = (void *)pau->regs[0]; |
| |
| if (pau->mmio_access) |
| out_be64(mmio + reg, val); |
| else |
| pau_scom_write(pau, reg, PAU_MISC_DA_LEN_8B, val); |
| |
| /* CQ_SM writes should be mirrored in all four blocks */ |
| if (PAU_REG_BLOCK(reg) != PAU_BLOCK_CQ_SM(0)) |
| return; |
| |
| for (uint32_t i = 1; i < 4; i++) |
| pau_write(pau, PAU_BLOCK_CQ_SM(i) + PAU_REG_OFFSET(reg), |
| val); |
| } |
| |
| static inline uint64_t pau_read(struct pau *pau, uint64_t reg) |
| { |
| void *mmio = (void *)pau->regs[0]; |
| |
| if (pau->mmio_access) |
| return in_be64(mmio + reg); |
| |
| return pau_scom_read(pau, reg, PAU_MISC_DA_LEN_8B); |
| } |
| |
| void pau_opencapi_dump_scoms(struct pau *pau); |
| int64_t pau_opencapi_map_atsd_lpar(struct phb *phb, uint64_t __unused bdf, |
| uint64_t lparid, uint64_t __unused lpcr); |
| int64_t pau_opencapi_spa_setup(struct phb *phb, uint32_t __unused bdfn, |
| uint64_t addr, uint64_t PE_mask); |
| int64_t pau_opencapi_spa_clear_cache(struct phb *phb, |
| uint32_t __unused bdfn, |
| uint64_t PE_handle); |
| int64_t pau_opencapi_tl_set(struct phb *phb, uint32_t __unused bdfn, |
| long capabilities, char *rate_buf); |
| int64_t pau_opencapi_mem_alloc(struct phb *phb, uint32_t __unused bdfn, |
| uint64_t size, uint64_t *bar); |
| int64_t pau_opencapi_mem_release(struct phb *phb, uint32_t __unused bdfn); |
| |
| /* PHY */ |
| int pau_dev_phy_reset(struct pau_dev *dev); |
| |
| #endif /* __PAU_H */ |