This source file includes following definitions.
- alipm_match
- alipm_attach
- alipm_smb_acquire_bus
- alipm_smb_release_bus
- alipm_smb_exec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <sys/param.h>
20 #include <sys/device.h>
21 #include <sys/kernel.h>
22 #include <sys/rwlock.h>
23 #include <sys/proc.h>
24 #include <sys/systm.h>
25
26 #include <dev/i2c/i2cvar.h>
27
28 #include <dev/pci/pcidevs.h>
29 #include <dev/pci/pcireg.h>
30 #include <dev/pci/pcivar.h>
31
32 #ifdef __sparc64__
33 #include <arch/sparc64/dev/ofwi2cvar.h>
34 #endif
35
36
37
38
39
40
41 #define ALIPM_CONF 0xd0
42 #define ALIPM_CONF_SMBEN 0x0400
43 #define ALIPM_BASE 0xe0
44 #define ALIPM_SMB_HOSTC 0xf0
45 #define ALIPM_SMB_HOSTC_HSTEN 0x00000001
46 #define ALIPM_SMB_HOSTC_CLOCK 0x00e00000
47 #define ALIPM_SMB_HOSTC_149K 0x00000000
48 #define ALIPM_SMB_HOSTC_74K 0x00200000
49 #define ALIPM_SMB_HOSTC_37K 0x00400000
50 #define ALIPM_SMB_HOSTC_223K 0x00800000
51 #define ALIPM_SMB_HOSTC_111K 0x00a00000
52 #define ALIPM_SMB_HOSTC_55K 0x00c00000
53
54 #define ALIPM_SMB_SIZE 32
55
56
57 #define ALIPM_SMB_HS 0x00
58 #define ALIPM_SMB_HS_IDLE 0x04
59 #define ALIPM_SMB_HS_BUSY 0x08
60 #define ALIPM_SMB_HS_DONE 0x10
61 #define ALIPM_SMB_HS_DEVERR 0x20
62 #define ALIPM_SMB_HS_BUSERR 0x40
63 #define ALIPM_SMB_HS_FAILED 0x80
64 #define ALIPM_SMB_HS_BITS \
65 "\020\003IDLE\004BUSY\005DONE\006DEVERR\007BUSERR\010FAILED"
66 #define ALIPM_SMB_HC 0x01
67 #define ALIPM_SMB_HC_KILL 0x04
68 #define ALIPM_SMB_HC_RESET 0x08
69 #define ALIPM_SMB_HC_CMD_QUICK 0x00
70 #define ALIPM_SMB_HC_CMD_BYTE 0x10
71 #define ALIPM_SMB_HC_CMD_BDATA 0x20
72 #define ALIPM_SMB_HC_CMD_WDATA 0x30
73 #define ALIPM_SMB_HC_CMD_BLOCK 0x40
74 #define ALIPM_SMB_START 0x02
75 #define ALIPM_SMB_TXSLVA 0x03
76 #define ALIPM_SMB_TXSLVA_READ (1 << 0)
77 #define ALIPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1)
78 #define ALIPM_SMB_HD0 0x04
79 #define ALIPM_SMB_HD1 0x05
80 #define ALIPM_SMB_HBDB 0x06
81 #define ALIPM_SMB_HCMD 0x07
82
83
84
85
86
87
88 #define ALIPM_SMB_BASE 0x14
89 #define ALIPM_SMB_HOSTX 0xe0
90
91 #ifdef ALIPM_DEBUG
92 #define DPRINTF(x) printf x
93 #else
94 #define DPRINTF(x)
95 #endif
96
97 #define ALIPM_DELAY 100
98 #define ALIPM_TIMEOUT 1
99
100 struct alipm_softc {
101 struct device sc_dev;
102
103 bus_space_tag_t sc_iot;
104 bus_space_handle_t sc_ioh;
105
106 struct i2c_controller sc_smb_tag;
107 struct rwlock sc_smb_lock;
108 };
109
110 int alipm_match(struct device *, void *, void *);
111 void alipm_attach(struct device *, struct device *, void *);
112
113 int alipm_smb_acquire_bus(void *, int);
114 void alipm_smb_release_bus(void *, int);
115 int alipm_smb_exec(void *, i2c_op_t, i2c_addr_t, const void *,
116 size_t, void *, size_t, int);
117
118 struct cfattach alipm_ca = {
119 sizeof(struct alipm_softc),
120 alipm_match,
121 alipm_attach
122 };
123
124 struct cfdriver alipm_cd = {
125 NULL, "alipm", DV_DULL
126 };
127
128 int
129 alipm_match(struct device *parent, void *match, void *aux)
130 {
131 struct pci_attach_args *pa = aux;
132
133 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
134 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M7101))
135 return (1);
136 return (0);
137 }
138
139 void
140 alipm_attach(struct device *parent, struct device *self, void *aux)
141 {
142 struct alipm_softc *sc = (struct alipm_softc *) self;
143 struct pci_attach_args *pa = aux;
144 struct i2cbus_attach_args iba;
145 pcireg_t iobase, reg;
146 bus_size_t iosize = ALIPM_SMB_SIZE;
147
148
149 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
150 if ((reg & PCI_STATUS_CAPLIST_SUPPORT) == 0) {
151
152 iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_BASE);
153 sc->sc_iot = pa->pa_iot;
154 if (iobase == 0 ||
155 bus_space_map(sc->sc_iot, iobase >> 16,
156 iosize, 0, &sc->sc_ioh)) {
157 printf(": can't map I/O space\n");
158 return;
159 }
160
161 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_CONF);
162 if ((reg & ALIPM_CONF_SMBEN) == 0) {
163 printf(": SMBus disabled\n");
164 goto fail;
165 }
166
167 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_SMB_HOSTC);
168 if ((reg & ALIPM_SMB_HOSTC_HSTEN) == 0) {
169 printf(": SMBus host disabled\n");
170 goto fail;
171 }
172 } else {
173
174 if (pci_mapreg_map(pa, ALIPM_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
175 &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, ALIPM_SMB_SIZE)) {
176 printf(": can't map I/O space\n");
177 return;
178 }
179
180 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, ALIPM_SMB_HOSTX);
181 if ((reg & ALIPM_SMB_HOSTC_HSTEN) == 0) {
182 printf(": SMBus host disabled\n");
183 goto fail;
184 }
185 }
186
187 switch (reg & ALIPM_SMB_HOSTC_CLOCK) {
188 case ALIPM_SMB_HOSTC_149K:
189 printf(": 149KHz clock");
190 break;
191 case ALIPM_SMB_HOSTC_74K:
192 printf(": 74KHz clock");
193 break;
194 case ALIPM_SMB_HOSTC_37K:
195 printf(": 37KHz clock");
196 break;
197 case ALIPM_SMB_HOSTC_223K:
198 printf(": 223KHz clock");
199 break;
200 case ALIPM_SMB_HOSTC_111K:
201 printf(": 111KHz clock");
202 break;
203 case ALIPM_SMB_HOSTC_55K:
204 printf(": 55KHz clock");
205 break;
206 default:
207 printf(" unknown clock speed");
208 break;
209 }
210
211 printf("\n");
212
213
214 rw_init(&sc->sc_smb_lock, "alipm");
215 sc->sc_smb_tag.ic_cookie = sc;
216 sc->sc_smb_tag.ic_acquire_bus = alipm_smb_acquire_bus;
217 sc->sc_smb_tag.ic_release_bus = alipm_smb_release_bus;
218 sc->sc_smb_tag.ic_exec = alipm_smb_exec;
219
220 bzero(&iba, sizeof iba);
221 iba.iba_name = "iic";
222 iba.iba_tag = &sc->sc_smb_tag;
223 #ifdef __sparc64__
224 iba.iba_bus_scan = ofwiic_pci_scan;
225 iba.iba_bus_scan_arg = pa;
226 #endif
227 config_found(&sc->sc_dev, &iba, iicbus_print);
228
229 return;
230
231 fail:
232 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
233 }
234
235 int
236 alipm_smb_acquire_bus(void *cookie, int flags)
237 {
238 struct alipm_softc *sc = cookie;
239
240 if (flags & I2C_F_POLL)
241 return (0);
242
243 return (rw_enter(&sc->sc_smb_lock, RW_WRITE | RW_INTR));
244 }
245
246 void
247 alipm_smb_release_bus(void *cookie, int flags)
248 {
249 struct alipm_softc *sc = cookie;
250
251 if (flags & I2C_F_POLL)
252 return;
253
254 rw_exit(&sc->sc_smb_lock);
255 }
256
257 int
258 alipm_smb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
259 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
260 {
261 struct alipm_softc *sc = cookie;
262 u_int8_t *b;
263 u_int8_t ctl, st;
264 int retries, error = 0;
265
266 DPRINTF(("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
267 "flags 0x%x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
268 len, flags));
269
270 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
271 return (EOPNOTSUPP);
272
273
274 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS,
275 ALIPM_SMB_HS_DONE | ALIPM_SMB_HS_FAILED |
276 ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR);
277 bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
278 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
279
280
281 for (retries = 1000; retries > 0; retries--) {
282 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
283 bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
284 BUS_SPACE_BARRIER_READ);
285 if (st & (ALIPM_SMB_HS_IDLE | ALIPM_SMB_HS_FAILED |
286 ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR))
287 break;
288 DELAY(ALIPM_DELAY);
289 }
290 if (retries == 0) {
291 printf("%s: timeout st 0x%b\n", sc->sc_dev.dv_xname,
292 st, ALIPM_SMB_HS_BITS);
293 return (ETIMEDOUT);
294 }
295 if (st & (ALIPM_SMB_HS_FAILED |
296 ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR)) {
297 printf("%s: error st 0x%b\n", sc->sc_dev.dv_xname,
298 st, ALIPM_SMB_HS_BITS);
299 return (EIO);
300 }
301
302
303 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_TXSLVA,
304 ALIPM_SMB_TXSLVA_ADDR(addr) |
305 (I2C_OP_READ_P(op) ? ALIPM_SMB_TXSLVA_READ : 0));
306
307 b = (void *)cmdbuf;
308 if (cmdlen > 0)
309
310 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
311 ALIPM_SMB_HCMD, b[0]);
312
313 if (I2C_OP_WRITE_P(op)) {
314
315 b = buf;
316 if (len > 0)
317 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
318 ALIPM_SMB_HD0, b[0]);
319 if (len > 1)
320 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
321 ALIPM_SMB_HD1, b[1]);
322 }
323
324
325 if (len == 0)
326 ctl = ALIPM_SMB_HC_CMD_BYTE;
327 else if (len == 1)
328 ctl = ALIPM_SMB_HC_CMD_BDATA;
329 else if (len == 2)
330 ctl = ALIPM_SMB_HC_CMD_WDATA;
331 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HC, ctl);
332
333
334 bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
335 BUS_SPACE_BARRIER_WRITE);
336 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_START, 0xff);
337 bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
338 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
339
340
341 DELAY(ALIPM_DELAY);
342 for (retries = 1000; retries > 0; retries--) {
343 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
344 bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
345 BUS_SPACE_BARRIER_READ);
346 if (st & (ALIPM_SMB_HS_IDLE | ALIPM_SMB_HS_FAILED |
347 ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR))
348 break;
349 DELAY(ALIPM_DELAY);
350 }
351 if (retries == 0) {
352 printf("%s: timeout st 0x%b, resetting\n",
353 sc->sc_dev.dv_xname, st, ALIPM_SMB_HS_BITS);
354 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HC,
355 ALIPM_SMB_HC_RESET);
356 bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
357 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
358 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
359 bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
360 BUS_SPACE_BARRIER_READ);
361 error = ETIMEDOUT;
362 goto done;
363 }
364
365 if ((st & ALIPM_SMB_HS_DONE) == 0) {
366 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HC,
367 ALIPM_SMB_HC_KILL);
368 bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, ALIPM_SMB_SIZE,
369 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
370 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS);
371 bus_space_barrier(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, 1,
372 BUS_SPACE_BARRIER_READ);
373 if ((st & ALIPM_SMB_HS_FAILED) == 0)
374 printf("%s: error st 0x%b\n", sc->sc_dev.dv_xname,
375 st, ALIPM_SMB_HS_BITS);
376 }
377
378
379 if (st & (ALIPM_SMB_HS_FAILED |
380 ALIPM_SMB_HS_BUSERR | ALIPM_SMB_HS_DEVERR)) {
381 error = EIO;
382 goto done;
383 }
384
385 if (I2C_OP_READ_P(op)) {
386
387 b = buf;
388 if (len > 0) {
389 b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
390 ALIPM_SMB_HD0);
391 bus_space_barrier(sc->sc_iot, sc->sc_ioh,
392 ALIPM_SMB_HD0, 1, BUS_SPACE_BARRIER_READ);
393 }
394 if (len > 1) {
395 b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
396 ALIPM_SMB_HD1);
397 bus_space_barrier(sc->sc_iot, sc->sc_ioh,
398 ALIPM_SMB_HD1, 1, BUS_SPACE_BARRIER_READ);
399 }
400 }
401
402 done:
403
404 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ALIPM_SMB_HS, st);
405
406 return (error);
407 }