blob: 016c807337821d4d62a3e4549a4f25b3fba71a8a [file] [log] [blame]
Simon Glass2ee1f6a2019-12-06 21:41:55 -07001// 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
Patrick Delaunay81313352021-04-27 11:02:19 +02009#define LOG_CATEGORY UCLASS_P2SB
10
Simon Glass2ee1f6a2019-12-06 21:41:55 -070011#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glass2ee1f6a2019-12-06 21:41:55 -070014#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
Simon Glass5e13b0f2020-07-07 21:32:30 -060022int 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
Simon Glass25f16c12020-07-07 21:32:19 -060032void *pcr_reg_address(struct udevice *dev, uint offset)
Simon Glass2ee1f6a2019-12-06 21:41:55 -070033{
Simon Glassb75b15b2020-12-03 16:55:23 -070034 struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
Simon Glass2ee1f6a2019-12-06 21:41:55 -070035 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 */
54static 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
61uint 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
Simon Glass25f16c12020-07-07 21:32:19 -060069 ptr = pcr_reg_address(dev, offset);
Simon Glass2ee1f6a2019-12-06 21:41:55 -070070 val = readl(ptr);
71 unmap_sysmem(ptr);
72
73 return val;
74}
75
76uint 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
Simon Glass25f16c12020-07-07 21:32:19 -060081 return readw(pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -070082}
83
84uint 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
Simon Glass25f16c12020-07-07 21:32:19 -060089 return readb(pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -070090}
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 */
98static void write_completion(struct udevice *dev, uint offset)
99{
Simon Glass25f16c12020-07-07 21:32:19 -0600100 readl(pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700101}
102
103void 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
Simon Glass25f16c12020-07-07 21:32:19 -0600108 writel(indata, pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700109 /* Ensure the writes complete */
110 write_completion(dev, offset);
111}
112
113void 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
Simon Glass25f16c12020-07-07 21:32:19 -0600118 writew(indata, pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700119 /* Ensure the writes complete */
120 write_completion(dev, offset);
121}
122
123void 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
Simon Glass25f16c12020-07-07 21:32:19 -0600128 writeb(indata, pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700129 /* Ensure the writes complete */
130 write_completion(dev, offset);
131}
132
133void 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
143void 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
153void 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
163int p2sb_get_port_id(struct udevice *dev)
164{
Simon Glassb75b15b2020-12-03 16:55:23 -0700165 struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700166
167 return pplat->pid;
168}
169
170int p2sb_set_port_id(struct udevice *dev, int portid)
171{
Simon Glassb75b15b2020-12-03 16:55:23 -0700172 struct p2sb_child_plat *pplat;
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700173
174 if (!CONFIG_IS_ENABLED(OF_PLATDATA))
175 return -ENOSYS;
176
Simon Glass71fa5b42020-12-03 16:55:18 -0700177 pplat = dev_get_parent_plat(dev);
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700178 pplat->pid = portid;
179
180 return 0;
181}
182
183static int p2sb_child_post_bind(struct udevice *dev)
184{
Simon Glass6d70ba02021-08-07 07:24:06 -0600185 if (CONFIG_IS_ENABLED(OF_REAL)) {
186 struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
187 int ret;
188 u32 pid;
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700189
Simon Glass6d70ba02021-08-07 07:24:06 -0600190 ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
191 if (ret)
192 return ret;
193 pplat->pid = pid;
194 }
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700195
196 return 0;
197}
198
199static int p2sb_post_bind(struct udevice *dev)
200{
201 if (spl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA))
202 return dm_scan_fdt_dev(dev);
203
204 return 0;
205}
206
207UCLASS_DRIVER(p2sb) = {
208 .id = UCLASS_P2SB,
209 .name = "p2sb",
Simon Glass8a2b47f2020-12-03 16:55:17 -0700210 .per_device_auto = sizeof(struct p2sb_uc_priv),
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700211 .post_bind = p2sb_post_bind,
212 .child_post_bind = p2sb_child_post_bind,
Simon Glassb75b15b2020-12-03 16:55:23 -0700213 .per_child_plat_auto = sizeof(struct p2sb_child_plat),
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700214};