aboutsummaryrefslogtreecommitdiff
path: root/include/pau.h
blob: be8ed26a3e109b984f5daabca4e438e14f5d4a07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* 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 <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 {
	uint64_t		addr;
	uint64_t		size;
	uint64_t		cfg;
};

struct pau_dev {
	enum pau_dev_type	type;
	uint32_t		index;
	struct dt_node		*dn;

	struct pau_bar		ntl_bar;
	struct pau_bar		genid_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;
	uint64_t		xscom_base;

	/* Global MMIO window (all PAU regs) */
	uint64_t		regs[2];
	bool			mmio_access;

	struct lock		lock;

	uint32_t		links;
	struct pau_dev		devices[PAU_LINKS_OPENCAPI_PER_PAU];
};

#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;
}

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;
}

/*
 * 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);
}

#endif /* __PAU_H */