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