Lines 48-79
Link Here
|
48 |
|
48 |
|
49 |
#include <arm/allwinner/aw_sid.h> |
49 |
#include <arm/allwinner/aw_sid.h> |
50 |
|
50 |
|
51 |
#define SID_SRAM 0x200 |
51 |
#define SID_KEYS_SIZE 4 |
52 |
#define SID_THERMAL_CALIB0 (SID_SRAM + 0x34) |
52 |
|
53 |
#define SID_THERMAL_CALIB1 (SID_SRAM + 0x38) |
53 |
/* Registers and special values for doing register-based SID readout on H3 */ |
54 |
|
54 |
#define SUN8I_SID_PRCTL 0x40 |
55 |
#define A10_ROOT_KEY_OFF 0x0 |
55 |
#define SUN8I_SID_RDKEY 0x60 |
56 |
#define A83T_ROOT_KEY_OFF SID_SRAM |
56 |
|
57 |
|
57 |
#define SUN8I_SID_OFFSET_MASK 0x1FF |
58 |
#define ROOT_KEY_SIZE 4 |
58 |
#define SUN8I_SID_OFFSET_SHIFT 16 |
59 |
|
59 |
#define SUN8I_SID_OP_LOCK (0xAC << 8) |
60 |
enum sid_type { |
60 |
#define SUN8I_SID_READ (0x01 << 1) |
61 |
A10_SID = 1, |
61 |
|
62 |
A20_SID, |
62 |
struct sunxi_sid_cfg { |
63 |
A83T_SID, |
63 |
uint32_t sid_offset; /* Offset e-fuse area of SoC from a base address */ |
|
|
64 |
uint32_t size; /* Size e-fuse area of SoC (byte) */ |
65 |
uint32_t thermal; /* Offset of thermal sensor calibration data in e-fuse area */ |
66 |
bool need_register_readout; |
67 |
}; |
68 |
|
69 |
static const struct sunxi_sid_cfg sun4i_a10_cfg = { |
70 |
.size = 0x10, |
71 |
}; |
72 |
|
73 |
static const struct sunxi_sid_cfg sun7i_a20_cfg = { |
74 |
.size = 0x200, |
75 |
}; |
76 |
|
77 |
static const struct sunxi_sid_cfg sun8i_h3_cfg = { |
78 |
.sid_offset = 0x200, |
79 |
.size = 0x100, |
80 |
.thermal = 0x34, |
81 |
.need_register_readout = true, |
82 |
}; |
83 |
|
84 |
static const struct sunxi_sid_cfg sun50i_a64_cfg = { |
85 |
.sid_offset = 0x200, |
86 |
.size = 0x100, |
87 |
}; |
88 |
|
89 |
static const struct sunxi_sid_cfg sun8i_a83t_cfg = { |
90 |
.sid_offset = 0x200, |
91 |
.size = 0x100, |
92 |
.thermal = 0x34, |
64 |
}; |
93 |
}; |
65 |
|
94 |
|
66 |
static struct ofw_compat_data compat_data[] = { |
95 |
static struct ofw_compat_data compat_data[] = { |
67 |
{ "allwinner,sun4i-a10-sid", A10_SID}, |
96 |
{ "allwinner,sun4i-a10-sid", (uintptr_t)&sun4i_a10_cfg }, |
68 |
{ "allwinner,sun7i-a20-sid", A20_SID}, |
97 |
{ "allwinner,sun7i-a20-sid", (uintptr_t)&sun7i_a20_cfg }, |
69 |
{ "allwinner,sun8i-a83t-sid", A83T_SID}, |
98 |
{ "allwinner,sun8i-h3-sid", (uintptr_t)&sun8i_h3_cfg }, |
70 |
{ NULL, 0 } |
99 |
{ "allwinner,sun50i-a64-sid", (uintptr_t)&sun50i_a64_cfg }, |
|
|
100 |
{ "allwinner,sun8i-a83t-sid", (uintptr_t)&sun8i_a83t_cfg }, |
101 |
{ NULL, 0 } |
71 |
}; |
102 |
}; |
72 |
|
103 |
|
73 |
struct aw_sid_softc { |
104 |
struct aw_sid_softc { |
74 |
struct resource *res; |
105 |
struct resource *res; |
75 |
int type; |
106 |
uint32_t size; /* Size e-fuse area of SoC (byte) */ |
76 |
bus_size_t root_key_off; |
107 |
bus_size_t reg_sid; |
|
|
108 |
bus_size_t reg_thermal; |
77 |
}; |
109 |
}; |
78 |
|
110 |
|
79 |
static struct aw_sid_softc *aw_sid_sc; |
111 |
static struct aw_sid_softc *aw_sid_sc; |
Lines 90-95
Link Here
|
90 |
#define RD4(sc, reg) bus_read_4((sc)->res, (reg)) |
122 |
#define RD4(sc, reg) bus_read_4((sc)->res, (reg)) |
91 |
#define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) |
123 |
#define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) |
92 |
|
124 |
|
|
|
125 |
static int |
126 |
sun8i_sid_register_readout(struct aw_sid_softc *sc, const uint32_t word) |
127 |
{ |
128 |
uint32_t reg_val; |
129 |
int timeout; |
130 |
|
131 |
/* Set word, lock access, and set read command */ |
132 |
reg_val = (word & SUN8I_SID_OFFSET_MASK) << SUN8I_SID_OFFSET_SHIFT; |
133 |
reg_val |= SUN8I_SID_OP_LOCK | SUN8I_SID_READ; |
134 |
WR4(sc, SUN8I_SID_PRCTL, reg_val); |
135 |
|
136 |
for (timeout = 2500; timeout; timeout--) { |
137 |
if (!(RD4(sc, SUN8I_SID_PRCTL) & SUN8I_SID_READ)) |
138 |
break; |
139 |
DELAY(100); |
140 |
} |
141 |
if (RD4(sc, SUN8I_SID_PRCTL) & SUN8I_SID_READ) |
142 |
return (ETIMEDOUT); |
143 |
|
144 |
WR4(sc, SUN8I_SID_PRCTL, 0); |
145 |
return (0); |
146 |
} |
147 |
|
93 |
static int aw_sid_sysctl(SYSCTL_HANDLER_ARGS); |
148 |
static int aw_sid_sysctl(SYSCTL_HANDLER_ARGS); |
94 |
|
149 |
|
95 |
static int |
150 |
static int |
Lines 109-133
Link Here
|
109 |
aw_sid_attach(device_t dev) |
164 |
aw_sid_attach(device_t dev) |
110 |
{ |
165 |
{ |
111 |
struct aw_sid_softc *sc; |
166 |
struct aw_sid_softc *sc; |
|
|
167 |
int i, size; |
168 |
const struct sunxi_sid_cfg *cfg; |
112 |
|
169 |
|
113 |
sc = device_get_softc(dev); |
170 |
sc = device_get_softc(dev); |
114 |
|
171 |
|
115 |
if (bus_alloc_resources(dev, aw_sid_spec, &sc->res) != 0) { |
172 |
if (bus_alloc_resources(dev, aw_sid_spec, &sc->res) != 0) { |
116 |
device_printf(dev, "cannot allocate resources for device\n"); |
173 |
device_printf(dev, "cannot allocate resources for device\n"); |
117 |
return (ENXIO); |
174 |
return (ENXIO); |
118 |
} |
175 |
} |
119 |
|
176 |
|
120 |
aw_sid_sc = sc; |
177 |
aw_sid_sc = sc; |
121 |
|
178 |
|
122 |
sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; |
179 |
cfg = (struct sunxi_sid_cfg *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; |
123 |
switch (sc->type) { |
180 |
if (cfg == NULL) |
124 |
case A83T_SID: |
181 |
return (ENXIO); |
125 |
sc->root_key_off = A83T_ROOT_KEY_OFF; |
182 |
|
126 |
break; |
183 |
sc->reg_sid = cfg->sid_offset; |
127 |
default: |
184 |
size = cfg->size; |
128 |
sc->root_key_off = A10_ROOT_KEY_OFF; |
185 |
|
129 |
break; |
186 |
if (cfg->need_register_readout) { |
|
|
187 |
/* |
188 |
* H3's SID controller have a bug that the value at 0x200 |
189 |
* offset is not the correct value when the hardware is reseted. |
190 |
* However, after doing a register-based read operation, the |
191 |
* value become right. |
192 |
* Read a quarter of the memory SID here, but ignore its value |
193 |
* (as it's more fast to read by direct MMIO value than |
194 |
* with registers) |
195 |
*/ |
196 |
for (i = 0; i < (size >> 2); i++) |
197 |
if (sun8i_sid_register_readout(sc, i)) |
198 |
return (ENXIO); |
130 |
} |
199 |
} |
|
|
200 |
|
201 |
sc->reg_thermal = cfg->sid_offset + cfg->thermal; |
202 |
sc->size = size; |
131 |
|
203 |
|
132 |
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), |
204 |
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), |
133 |
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), |
205 |
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), |
Lines 145-156
Link Here
|
145 |
|
217 |
|
146 |
sc = aw_sid_sc; |
218 |
sc = aw_sid_sc; |
147 |
if (sc == NULL) |
219 |
if (sc == NULL) |
148 |
return (ENXIO); |
220 |
return (ENXIO); |
149 |
if (sc->type != A83T_SID) |
221 |
|
150 |
return (ENXIO); |
222 |
if (sc->reg_thermal == sc->reg_sid) |
|
|
223 |
return (ENXIO); |
151 |
|
224 |
|
152 |
*calib0 = RD4(sc, SID_THERMAL_CALIB0); |
225 |
*calib0 = RD4(sc, sc->reg_thermal); |
153 |
*calib1 = RD4(sc, SID_THERMAL_CALIB1); |
226 |
*calib1 = RD4(sc, sc->reg_thermal + 4); |
154 |
|
227 |
|
155 |
return (0); |
228 |
return (0); |
156 |
} |
229 |
} |
Lines 160-173
Link Here
|
160 |
{ |
233 |
{ |
161 |
struct aw_sid_softc *sc; |
234 |
struct aw_sid_softc *sc; |
162 |
int i; |
235 |
int i; |
163 |
u_int tmp; |
236 |
uint32_t tmp; |
164 |
|
237 |
|
165 |
sc = aw_sid_sc; |
238 |
sc = aw_sid_sc; |
166 |
if (sc == NULL) |
239 |
if (sc == NULL) |
167 |
return (ENXIO); |
240 |
return (ENXIO); |
168 |
|
241 |
|
169 |
for (i = 0; i < ROOT_KEY_SIZE ; i++) { |
242 |
for (i = 0; i < SID_KEYS_SIZE; i++) { |
170 |
tmp = RD4(aw_sid_sc, aw_sid_sc->root_key_off + (i * 4)); |
243 |
tmp = RD4(sc, sc->reg_sid + (i * 4)); |
171 |
be32enc(&out[i * 4], tmp); |
244 |
be32enc(&out[i * 4], tmp); |
172 |
} |
245 |
} |
173 |
|
246 |
|
Lines 186-193
Link Here
|
186 |
|
259 |
|
187 |
if (aw_sid_get_rootkey(rootkey) != 0) |
260 |
if (aw_sid_get_rootkey(rootkey) != 0) |
188 |
return (ENOENT); |
261 |
return (ENOENT); |
189 |
snprintf(out, sizeof(out), |
262 |
|
190 |
"%16D", rootkey, ""); |
263 |
snprintf(out, sizeof(out), "%16D", rootkey, ""); |
191 |
|
264 |
|
192 |
return sysctl_handle_string(oidp, out, sizeof(out), req); |
265 |
return sysctl_handle_string(oidp, out, sizeof(out), req); |
193 |
} |
266 |
} |
Lines 208-213
Link Here
|
208 |
|
281 |
|
209 |
static devclass_t aw_sid_devclass; |
282 |
static devclass_t aw_sid_devclass; |
210 |
|
283 |
|
211 |
EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, aw_sid_devclass, 0, 0, |
284 |
EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, aw_sid_devclass, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_FIRST); |
212 |
BUS_PASS_RESOURCE + BUS_PASS_ORDER_FIRST); |
|
|
213 |
MODULE_VERSION(aw_sid, 1); |
285 |
MODULE_VERSION(aw_sid, 1); |