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