View | Details | Raw Unified | Return to bug 224481
Collapse All | Expand All

(-)/freebsd_branch/sys/arm/allwinner/aw_sid.c (-41 / +113 lines)
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);

Return to bug 224481