|
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); |