Annotation of sys/arch/macppc/dev/xlights.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: xlights.c,v 1.3 2007/06/01 08:29:30 gwk Exp $ */
2: /*
3: * Copyright (c) 2007 Gordon Willem Klok <gwk@openbsd,org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/types.h>
18: #include <sys/param.h>
19: #include <sys/systm.h>
20: #include <sys/proc.h>
21: #include <sys/device.h>
22: #include <sys/kthread.h>
23: #include <sys/timeout.h>
24: #include <dev/ofw/openfirm.h>
25:
26: #include <machine/bus.h>
27: #include <machine/autoconf.h>
28: #include <macppc/dev/dbdma.h>
29: #include <macppc/dev/i2sreg.h>
30:
31: struct xlights_softc {
32: struct device sc_dev;
33: int sc_node;
34: int sc_intr;
35: uint32_t sc_freq;
36: int sc_dmasts;
37:
38: u_char *sc_reg;
39: dbdma_regmap_t *sc_dma;
40: bus_dma_tag_t sc_dmat;
41: bus_dmamap_t sc_bufmap;
42: bus_dma_segment_t sc_bufseg[1];
43: dbdma_t sc_dbdma;
44: dbdma_command_t *sc_dmacmd;
45: uint32_t *sc_buf;
46: uint32_t *sc_bufpos;
47:
48: struct timeout sc_tmo;
49: };
50:
51: int xlights_match(struct device *, void *, void *);
52: void xlights_attach(struct device *, struct device *, void *);
53: int xlights_intr(void *);
54: void xlights_startdma(struct xlights_softc *);
55: void xlights_deferred(void *);
56: void xlights_theosDOT(void *);
57: void xlights_timeout(void *);
58: void xlights_pwm(struct xlights_softc *, u_char *, int);
59: extern void keylargo_fcr_enable(int, u_int32_t);
60: extern void keylargo_fcr_disable(int, u_int32_t);
61:
62: struct cfattach xlights_ca = {
63: sizeof(struct xlights_softc), xlights_match,
64: xlights_attach
65: };
66:
67: struct cfdriver xlights_cd = {
68: NULL, "xlights", DV_DULL
69: };
70:
71: #define BL_BUFSZ PAGE_SIZE
72: #define BL_DBDMA_CMDS 2
73:
74: int
75: xlights_match(struct device *parent, void *arg, void *aux)
76: {
77: struct confargs *ca = aux;
78: int soundbus, soundchip, error;
79: char compat[32];
80:
81: if (strcmp(ca->ca_name, "i2s") != 0)
82: return 0;
83: if ((soundbus = OF_child(ca->ca_node)) == 0)
84: return 0;
85: if ((soundchip = OF_child(soundbus)) == 0)
86: return 0;
87:
88: error = OF_getprop(soundchip, "virtual", compat, sizeof(compat));
89: if (error == -1) {
90: error = OF_getprop(soundchip, "name", compat,
91: sizeof(compat));
92:
93: if (error == -1 || (strcmp(compat, "lightshow")) != 0)
94: return 0;
95: }
96:
97: /* we require at least 4 registers */
98: if (ca->ca_nreg / sizeof(int) < 4)
99: return 0;
100: /* we require at least 3 interrupts */
101: if (ca->ca_nintr / sizeof(int) < 6)
102: return 0;
103:
104: return 1;
105: }
106:
107: void
108: xlights_attach(struct device *parent, struct device *self, void *aux)
109: {
110: struct xlights_softc *sc = (struct xlights_softc *)self;
111: struct confargs *ca = aux;
112: int nseg, error, intr[6];
113: u_int32_t reg[4];
114:
115: sc->sc_node = OF_child(ca->ca_node);
116:
117: OF_getprop(sc->sc_node, "reg", reg, sizeof(reg));
118: ca->ca_reg[0] += ca->ca_baseaddr;
119: ca->ca_reg[2] += ca->ca_baseaddr;
120:
121: if ((sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1])) == NULL) {
122: printf(": cannot map registers\n");
123: return;
124: }
125: sc->sc_dmat = ca->ca_dmat;
126:
127: if ((sc->sc_dma = mapiodev(ca->ca_reg[2], ca->ca_reg[3])) == NULL) {
128: printf(": cannot map DMA registers\n");
129: goto nodma;
130: }
131:
132: if ((sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, BL_DBDMA_CMDS)) == NULL) {
133: printf(": cannot alloc DMA descriptors\n");
134: goto nodbdma;
135: }
136: sc->sc_dmacmd = sc->sc_dbdma->d_addr;
137:
138: if ((error = bus_dmamem_alloc(sc->sc_dmat, BL_BUFSZ, 0, 0,
139: sc->sc_bufseg, 1, &nseg, BUS_DMA_NOWAIT))) {
140: printf(": cannot allocate DMA mem (%d)\n", error);
141: goto nodmamem;
142: }
143:
144: if ((error = bus_dmamem_map(sc->sc_dmat, sc->sc_bufseg, nseg,
145: BL_BUFSZ, (caddr_t *)&sc->sc_buf, BUS_DMA_NOWAIT))) {
146: printf(": cannot map DMA mem (%d)\n", error);
147: goto nodmamap;
148: }
149: sc->sc_bufpos = sc->sc_buf;
150:
151: if ((error = bus_dmamap_create(sc->sc_dmat, BL_BUFSZ, 1, BL_BUFSZ, 0,
152: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_bufmap))) {
153: printf(": cannot create DMA map (%d)\n", error);
154: goto nodmacreate;
155: }
156:
157: if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_bufmap, sc->sc_buf,
158: BL_BUFSZ, NULL, BUS_DMA_NOWAIT))) {
159: printf(": cannot load DMA map (%d)\n", error);
160: goto nodmaload;
161: }
162: /* XXX: Should probably extract this from the clock data
163: * property of the soundchip node */
164: sc->sc_freq = 44100;
165:
166: OF_getprop(sc->sc_node, "interrupts", intr, sizeof(intr));
167: sc->sc_intr = intr[2];
168: printf(": irq %d\n", sc->sc_intr);
169:
170: keylargo_fcr_enable(I2SClockOffset, I2S0EN);
171: out32rb(sc->sc_reg + I2S_INT, I2S_INT_CLKSTOPPEND);
172: keylargo_fcr_disable(I2SClockOffset, I2S0CLKEN);
173: for (error = 0; error < 1000; error++) {
174: if (in32rb(sc->sc_reg + I2S_INT) & I2S_INT_CLKSTOPPEND) {
175: error = 0;
176: break;
177: }
178: delay(1);
179: }
180: if (error) {
181: printf("%s: i2s timeout\n", sc->sc_dev.dv_xname);
182: goto nodmaload;
183: }
184:
185: mac_intr_establish(parent, sc->sc_intr, intr[3] ? IST_LEVEL :
186: IST_EDGE, IPL_AUDIO, xlights_intr, sc, sc->sc_dev.dv_xname);
187:
188: out32rb(sc->sc_reg + I2S_FORMAT, CLKSRC_VS);
189: keylargo_fcr_enable(I2SClockOffset, I2S0CLKEN);
190:
191: kthread_create_deferred(xlights_deferred, sc);
192: timeout_set(&sc->sc_tmo, xlights_timeout, sc);
193: return;
194: nodmaload:
195: bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufmap);
196: nodmacreate:
197: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf, BL_BUFSZ);
198: nodmamap:
199: bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, nseg);
200: nodmamem:
201: dbdma_free(sc->sc_dbdma);
202: nodbdma:
203: unmapiodev((void *)sc->sc_dma, ca->ca_reg[3]);
204: nodma:
205: unmapiodev(sc->sc_reg, ca->ca_reg[1]);
206: }
207:
208: void
209: xlights_deferred(void *v)
210: {
211: kthread_create(xlights_theosDOT, v, NULL, "xlights");
212: }
213:
214: void
215: xlights_theosDOT(void *v)
216: {
217: struct xlights_softc *sc = (struct xlights_softc *)v;
218: u_char leds[16];
219: int offset, i, s, speed;
220:
221: while (1) {
222: speed = (averunnable.ldavg[0] / 100) / 2;
223: for (offset = 8; offset < 16; offset++) {
224: s = offset - 2;
225: if (s < 8) {
226: for (i = 1; i <= (8 - s); i++)
227: leds[i - 1] = 0x7f / i;
228: s += 8 - s;
229: }
230: for (i = offset; i >= s; i--)
231: leds[i] = 0xff / (offset + 1 - s);
232:
233: xlights_pwm(sc, leds, speed);
234: bzero(leds, sizeof(leds));
235: }
236: for (offset = 7; offset >= 0; offset--) {
237: s = offset + 2;
238: if (s > 7) {
239: for (i = 1; i <= (s - 7); i++)
240: leds[15 - (i - 1)] = (0xff / (s - 7)) / i;
241: s-= s - 7;
242: }
243: for (i = offset; i <= s; i++)
244: leds[i] = 0xff / (offset + 1) - s;
245: xlights_pwm(sc, leds, speed);
246: bzero(leds, sizeof(leds));
247: }
248: }
249: }
250:
251: void
252: xlights_pwm(struct xlights_softc *sc, u_char *leds, int msecs)
253: {
254: uint32_t *p;
255: int s, l, k, nsamp;
256: uint32_t freq[16] = {0};
257:
258: p = sc->sc_bufpos;
259:
260: nsamp = sc->sc_freq / 1000 * msecs;
261:
262: for (k = 1; k < nsamp;) {
263: if (p - sc->sc_buf < BL_BUFSZ / sizeof(uint32_t)) {
264: s = 0;
265: for (l = 0; l < 16; l++) {
266: s >>= 1;
267: if (leds[l] &&
268: ((k - freq[l]) == (0xff / leds[l]))) {
269: s |= 1 << 15;
270: freq[l] = k;
271: }
272: }
273: *p = (s << 17) | (s >> 15);
274: p++;
275: k++;
276: sc->sc_bufpos++;
277: } else {
278: xlights_startdma(sc);
279: while (sc->sc_dmasts)
280: tsleep(sc->sc_buf, PWAIT, "blinken", 0);
281: sc->sc_bufpos = p = sc->sc_buf;
282: }
283: }
284: }
285:
286: void
287: xlights_startdma(struct xlights_softc *sc)
288: {
289: dbdma_command_t *cmdp = sc->sc_dmacmd;
290:
291: sc->sc_dmasts = 1;
292: timeout_add(&sc->sc_tmo, 250);
293:
294: DBDMA_BUILD(cmdp, DBDMA_CMD_OUT_LAST, 0,
295: sc->sc_bufmap->dm_segs[0].ds_len,
296: sc->sc_bufmap->dm_segs[0].ds_addr, DBDMA_INT_ALWAYS,
297: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
298: cmdp++;
299:
300: DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0, DBDMA_INT_NEVER,
301: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
302:
303: dbdma_start(sc->sc_dma, sc->sc_dbdma);
304: }
305:
306: void
307: xlights_timeout(void *v)
308: {
309: struct xlights_softc *sc = (struct xlights_softc *)v;
310:
311: dbdma_reset(sc->sc_dma);
312: timeout_del(&sc->sc_tmo);
313: sc->sc_dmasts = 0;
314: wakeup(sc->sc_buf);
315: }
316:
317: int
318: xlights_intr(void *v)
319: {
320: struct xlights_softc *sc = (struct xlights_softc *)v;
321: int status;
322: dbdma_command_t *cmd;
323:
324: cmd = sc->sc_dmacmd;
325: status = dbdma_ld16(&cmd->d_status);
326: if (sc->sc_dmasts) {
327: sc->sc_dmasts = 0;
328: timeout_del(&sc->sc_tmo);
329: wakeup(sc->sc_buf);
330: return (1);
331: }
332: return (0);
333: }
CVSweb