1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Uclass for Primary-to-sideband bus, used to access various peripherals
4  *
5  * Copyright 2019 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #define LOG_CATEGORY UCLASS_P2SB
10 
11 #include <dm.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <mapmem.h>
15 #include <p2sb.h>
16 #include <spl.h>
17 #include <asm/io.h>
18 #include <dm/uclass-internal.h>
19 
20 #define PCR_COMMON_IOSF_1_0	1
21 
p2sb_set_hide(struct udevice * dev,bool hide)22 int p2sb_set_hide(struct udevice *dev, bool hide)
23 {
24 	struct p2sb_ops *ops = p2sb_get_ops(dev);
25 
26 	if (!ops->set_hide)
27 		return -ENOSYS;
28 
29 	return ops->set_hide(dev, hide);
30 }
31 
pcr_reg_address(struct udevice * dev,uint offset)32 void *pcr_reg_address(struct udevice *dev, uint offset)
33 {
34 	struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
35 	struct udevice *p2sb = dev_get_parent(dev);
36 	struct p2sb_uc_priv *upriv = dev_get_uclass_priv(p2sb);
37 	uintptr_t reg_addr;
38 
39 	/* Create an address based off of port id and offset */
40 	reg_addr = upriv->mmio_base;
41 	reg_addr += pplat->pid << PCR_PORTID_SHIFT;
42 	reg_addr += offset;
43 
44 	return map_sysmem(reg_addr, 4);
45 }
46 
47 /*
48  * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB
49  * agents are using 32-bit aligned accesses for their configuration
50  * registers. For IOSF versions greater than 1_0, IOSF-SB
51  * agents can use any access (8/16/32 bit aligned) for their
52  * configuration registers
53  */
check_pcr_offset_align(uint offset,uint size)54 static inline void check_pcr_offset_align(uint offset, uint size)
55 {
56 	const size_t align = PCR_COMMON_IOSF_1_0 ? sizeof(uint32_t) : size;
57 
58 	assert(IS_ALIGNED(offset, align));
59 }
60 
pcr_read32(struct udevice * dev,uint offset)61 uint pcr_read32(struct udevice *dev, uint offset)
62 {
63 	void *ptr;
64 	uint val;
65 
66 	/* Ensure the PCR offset is correctly aligned */
67 	assert(IS_ALIGNED(offset, sizeof(uint32_t)));
68 
69 	ptr = pcr_reg_address(dev, offset);
70 	val = readl(ptr);
71 	unmap_sysmem(ptr);
72 
73 	return val;
74 }
75 
pcr_read16(struct udevice * dev,uint offset)76 uint pcr_read16(struct udevice *dev, uint offset)
77 {
78 	/* Ensure the PCR offset is correctly aligned */
79 	check_pcr_offset_align(offset, sizeof(uint16_t));
80 
81 	return readw(pcr_reg_address(dev, offset));
82 }
83 
pcr_read8(struct udevice * dev,uint offset)84 uint pcr_read8(struct udevice *dev, uint offset)
85 {
86 	/* Ensure the PCR offset is correctly aligned */
87 	check_pcr_offset_align(offset, sizeof(uint8_t));
88 
89 	return readb(pcr_reg_address(dev, offset));
90 }
91 
92 /*
93  * After every write one needs to perform a read an innocuous register to
94  * ensure the writes are completed for certain ports. This is done for
95  * all ports so that the callers don't need the per-port knowledge for
96  * each transaction.
97  */
write_completion(struct udevice * dev,uint offset)98 static void write_completion(struct udevice *dev, uint offset)
99 {
100 	readl(pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
101 }
102 
pcr_write32(struct udevice * dev,uint offset,uint indata)103 void pcr_write32(struct udevice *dev, uint offset, uint indata)
104 {
105 	/* Ensure the PCR offset is correctly aligned */
106 	assert(IS_ALIGNED(offset, sizeof(indata)));
107 
108 	writel(indata, pcr_reg_address(dev, offset));
109 	/* Ensure the writes complete */
110 	write_completion(dev, offset);
111 }
112 
pcr_write16(struct udevice * dev,uint offset,uint indata)113 void pcr_write16(struct udevice *dev, uint offset, uint indata)
114 {
115 	/* Ensure the PCR offset is correctly aligned */
116 	check_pcr_offset_align(offset, sizeof(uint16_t));
117 
118 	writew(indata, pcr_reg_address(dev, offset));
119 	/* Ensure the writes complete */
120 	write_completion(dev, offset);
121 }
122 
pcr_write8(struct udevice * dev,uint offset,uint indata)123 void pcr_write8(struct udevice *dev, uint offset, uint indata)
124 {
125 	/* Ensure the PCR offset is correctly aligned */
126 	check_pcr_offset_align(offset, sizeof(uint8_t));
127 
128 	writeb(indata, pcr_reg_address(dev, offset));
129 	/* Ensure the writes complete */
130 	write_completion(dev, offset);
131 }
132 
pcr_clrsetbits32(struct udevice * dev,uint offset,uint clr,uint set)133 void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set)
134 {
135 	uint data32;
136 
137 	data32 = pcr_read32(dev, offset);
138 	data32 &= ~clr;
139 	data32 |= set;
140 	pcr_write32(dev, offset, data32);
141 }
142 
pcr_clrsetbits16(struct udevice * dev,uint offset,uint clr,uint set)143 void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set)
144 {
145 	uint data16;
146 
147 	data16 = pcr_read16(dev, offset);
148 	data16 &= ~clr;
149 	data16 |= set;
150 	pcr_write16(dev, offset, data16);
151 }
152 
pcr_clrsetbits8(struct udevice * dev,uint offset,uint clr,uint set)153 void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set)
154 {
155 	uint data8;
156 
157 	data8 = pcr_read8(dev, offset);
158 	data8 &= ~clr;
159 	data8 |= set;
160 	pcr_write8(dev, offset, data8);
161 }
162 
p2sb_get_port_id(struct udevice * dev)163 int p2sb_get_port_id(struct udevice *dev)
164 {
165 	struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
166 
167 	return pplat->pid;
168 }
169 
p2sb_set_port_id(struct udevice * dev,int portid)170 int p2sb_set_port_id(struct udevice *dev, int portid)
171 {
172 	struct p2sb_child_plat *pplat;
173 
174 	if (!CONFIG_IS_ENABLED(OF_PLATDATA))
175 		return -ENOSYS;
176 
177 	pplat = dev_get_parent_plat(dev);
178 	pplat->pid = portid;
179 
180 	return 0;
181 }
182 
p2sb_child_post_bind(struct udevice * dev)183 static int p2sb_child_post_bind(struct udevice *dev)
184 {
185 	if (CONFIG_IS_ENABLED(OF_REAL)) {
186 		struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
187 		int ret;
188 		u32 pid;
189 
190 		ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
191 		if (ret)
192 			return ret;
193 		pplat->pid = pid;
194 	}
195 
196 	return 0;
197 }
198 
p2sb_post_bind(struct udevice * dev)199 static int p2sb_post_bind(struct udevice *dev)
200 {
201 	if (xpl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA))
202 		return dm_scan_fdt_dev(dev);
203 
204 	return 0;
205 }
206 
207 UCLASS_DRIVER(p2sb) = {
208 	.id		= UCLASS_P2SB,
209 	.name		= "p2sb",
210 	.per_device_auto	= sizeof(struct p2sb_uc_priv),
211 	.post_bind	= p2sb_post_bind,
212 	.child_post_bind = p2sb_child_post_bind,
213 	.per_child_plat_auto = sizeof(struct p2sb_child_plat),
214 };
215