blob: f24857a1515e27201ab9a642498864a43d84e701 [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 <common.h>
12#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070014#include <malloc.h>
Simon Glass2ee1f6a2019-12-06 21:41:55 -070015#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
Simon Glass5e13b0f2020-07-07 21:32:30 -060023int 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
Simon Glass25f16c12020-07-07 21:32:19 -060033void *pcr_reg_address(struct udevice *dev, uint offset)
Simon Glass2ee1f6a2019-12-06 21:41:55 -070034{
Simon Glassb75b15b2020-12-03 16:55:23 -070035 struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
Simon Glass2ee1f6a2019-12-06 21:41:55 -070036 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 */
55static 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
62uint 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
Simon Glass25f16c12020-07-07 21:32:19 -060070 ptr = pcr_reg_address(dev, offset);
Simon Glass2ee1f6a2019-12-06 21:41:55 -070071 val = readl(ptr);
72 unmap_sysmem(ptr);
73
74 return val;
75}
76
77uint 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
Simon Glass25f16c12020-07-07 21:32:19 -060082 return readw(pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -070083}
84
85uint 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
Simon Glass25f16c12020-07-07 21:32:19 -060090 return readb(pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -070091}
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 */
99static void write_completion(struct udevice *dev, uint offset)
100{
Simon Glass25f16c12020-07-07 21:32:19 -0600101 readl(pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700102}
103
104void 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
Simon Glass25f16c12020-07-07 21:32:19 -0600109 writel(indata, pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700110 /* Ensure the writes complete */
111 write_completion(dev, offset);
112}
113
114void 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
Simon Glass25f16c12020-07-07 21:32:19 -0600119 writew(indata, pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700120 /* Ensure the writes complete */
121 write_completion(dev, offset);
122}
123
124void 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
Simon Glass25f16c12020-07-07 21:32:19 -0600129 writeb(indata, pcr_reg_address(dev, offset));
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700130 /* Ensure the writes complete */
131 write_completion(dev, offset);
132}
133
134void 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
144void 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
154void 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
164int p2sb_get_port_id(struct udevice *dev)
165{
Simon Glassb75b15b2020-12-03 16:55:23 -0700166 struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700167
168 return pplat->pid;
169}
170
171int p2sb_set_port_id(struct udevice *dev, int portid)
172{
Simon Glassb75b15b2020-12-03 16:55:23 -0700173 struct p2sb_child_plat *pplat;
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700174
175 if (!CONFIG_IS_ENABLED(OF_PLATDATA))
176 return -ENOSYS;
177
Simon Glass71fa5b42020-12-03 16:55:18 -0700178 pplat = dev_get_parent_plat(dev);
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700179 pplat->pid = portid;
180
181 return 0;
182}
183
184static int p2sb_child_post_bind(struct udevice *dev)
185{
Simon Glass6d70ba02021-08-07 07:24:06 -0600186 if (CONFIG_IS_ENABLED(OF_REAL)) {
187 struct p2sb_child_plat *pplat = dev_get_parent_plat(dev);
188 int ret;
189 u32 pid;
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700190
Simon Glass6d70ba02021-08-07 07:24:06 -0600191 ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
192 if (ret)
193 return ret;
194 pplat->pid = pid;
195 }
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700196
197 return 0;
198}
199
200static 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
208UCLASS_DRIVER(p2sb) = {
209 .id = UCLASS_P2SB,
210 .name = "p2sb",
Simon Glass8a2b47f2020-12-03 16:55:17 -0700211 .per_device_auto = sizeof(struct p2sb_uc_priv),
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700212 .post_bind = p2sb_post_bind,
213 .child_post_bind = p2sb_child_post_bind,
Simon Glassb75b15b2020-12-03 16:55:23 -0700214 .per_child_plat_auto = sizeof(struct p2sb_child_plat),
Simon Glass2ee1f6a2019-12-06 21:41:55 -0700215};