Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/annapurna/alpine/alpine_serdes.c
39536 views
1
/*-
2
* Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates
3
* All rights reserved.
4
*
5
* Developed by Semihalf.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/systm.h>
31
#include <sys/kernel.h>
32
#include <sys/module.h>
33
#include <sys/bus.h>
34
#include <sys/rman.h>
35
#include <sys/conf.h>
36
#include <sys/resource.h>
37
38
#include <machine/bus.h>
39
#include <dev/ofw/ofw_bus_subr.h>
40
41
#include "al_serdes.h"
42
#include "alpine_serdes.h"
43
44
#define SERDES_NUM_GROUPS 5
45
46
static void *serdes_base;
47
static uint32_t serdes_grp_offset[] = {0, 0x400, 0x800, 0xc00, 0x2000};
48
49
static struct alpine_serdes_eth_group_mode {
50
struct mtx lock;
51
enum alpine_serdes_eth_mode mode;
52
bool mode_set;
53
} alpine_serdes_eth_group_mode[SERDES_NUM_GROUPS];
54
55
static int al_serdes_probe(device_t dev);
56
static int al_serdes_attach(device_t dev);
57
static int al_serdes_detach(device_t dev);
58
59
static struct resource_spec al_serdes_spec[] = {
60
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
61
{ -1, 0 }
62
};
63
64
struct al_serdes_softc {
65
struct resource *res;
66
};
67
68
static device_method_t al_serdes_methods[] = {
69
DEVMETHOD(device_probe, al_serdes_probe),
70
DEVMETHOD(device_attach, al_serdes_attach),
71
DEVMETHOD(device_detach, al_serdes_detach),
72
73
DEVMETHOD_END
74
};
75
76
static driver_t al_serdes_driver = {
77
"serdes",
78
al_serdes_methods,
79
sizeof(struct al_serdes_softc)
80
};
81
82
DRIVER_MODULE(al_serdes, simplebus, al_serdes_driver, 0, 0);
83
DRIVER_MODULE(al_serdes, ofwbus, al_serdes_driver, 0, 0);
84
85
static int
86
al_serdes_probe(device_t dev)
87
{
88
89
if (!ofw_bus_status_okay(dev))
90
return (ENXIO);
91
92
if (!ofw_bus_is_compatible(dev, "annapurna-labs,al-serdes"))
93
return (ENXIO);
94
95
device_set_desc(dev, "Alpine Serdes");
96
97
return (BUS_PROBE_DEFAULT);
98
}
99
100
static int
101
al_serdes_attach(device_t dev)
102
{
103
struct al_serdes_softc *sc;
104
int err;
105
106
sc = device_get_softc(dev);
107
108
err = bus_alloc_resources(dev, al_serdes_spec, &sc->res);
109
if (err != 0) {
110
device_printf(dev, "could not allocate resources\n");
111
return (err);
112
}
113
114
/* Initialize Serdes group locks and mode */
115
for (int i = 0; i < nitems(alpine_serdes_eth_group_mode); i++) {
116
mtx_init(&alpine_serdes_eth_group_mode[i].lock, "AlSerdesMtx",
117
NULL, MTX_DEF);
118
alpine_serdes_eth_group_mode[i].mode_set = false;
119
}
120
121
serdes_base = (void *)rman_get_bushandle(sc->res);
122
123
return (0);
124
}
125
126
static int
127
al_serdes_detach(device_t dev)
128
{
129
struct al_serdes_softc *sc;
130
131
sc = device_get_softc(dev);
132
133
bus_release_resources(dev, al_serdes_spec, &sc->res);
134
135
for (int i = 0; i < nitems(alpine_serdes_eth_group_mode); i++) {
136
mtx_destroy(&alpine_serdes_eth_group_mode[i].lock);
137
alpine_serdes_eth_group_mode[i].mode_set = false;
138
}
139
140
return (0);
141
}
142
143
void *
144
alpine_serdes_resource_get(uint32_t group)
145
{
146
void *base;
147
148
base = NULL;
149
if (group >= SERDES_NUM_GROUPS)
150
return (NULL);
151
152
if (serdes_base != NULL)
153
base = (void *)((uintptr_t)serdes_base +
154
serdes_grp_offset[group]);
155
156
return (base);
157
}
158
159
int
160
alpine_serdes_eth_mode_set(uint32_t group, enum alpine_serdes_eth_mode mode)
161
{
162
struct alpine_serdes_eth_group_mode *group_mode;
163
164
group_mode = &alpine_serdes_eth_group_mode[group];
165
166
if (serdes_base == NULL)
167
return (EINVAL);
168
169
if (group >= SERDES_NUM_GROUPS)
170
return (EINVAL);
171
172
mtx_lock(&group_mode->lock);
173
174
if (!group_mode->mode_set || (group_mode->mode != mode)) {
175
struct al_serdes_grp_obj obj;
176
177
al_serdes_handle_grp_init(alpine_serdes_resource_get(group),
178
group, &obj);
179
180
if (mode == ALPINE_SERDES_ETH_MODE_SGMII)
181
obj.mode_set_sgmii(&obj);
182
else
183
obj.mode_set_kr(&obj);
184
185
group_mode->mode = mode;
186
group_mode->mode_set = true;
187
}
188
189
mtx_unlock(&group_mode->lock);
190
191
return (0);
192
}
193
194
void
195
alpine_serdes_eth_group_lock(uint32_t group)
196
{
197
struct alpine_serdes_eth_group_mode *group_mode;
198
199
group_mode = &alpine_serdes_eth_group_mode[group];
200
201
if (mtx_initialized(&group_mode->lock) == 0)
202
return;
203
204
mtx_lock(&group_mode->lock);
205
}
206
207
void
208
alpine_serdes_eth_group_unlock(uint32_t group)
209
{
210
struct alpine_serdes_eth_group_mode *group_mode;
211
212
group_mode = &alpine_serdes_eth_group_mode[group];
213
214
if (mtx_initialized(&group_mode->lock) == 0)
215
return;
216
217
mtx_unlock(&group_mode->lock);
218
}
219
220