dt-bindings: pinctrl: k3: Synchronize with v5.14 kernel
[platform/kernel/u-boot.git] / drivers / misc / p2sb-uclass.c
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
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
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  */
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
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
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
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  */
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
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
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
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
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
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
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
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
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
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
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 };