1/*
2 * Copyright (c) 2002, 2003, 2005  Genetec corp.  All rights reserved.
3 *
4 * PCMCIA/CF support for TWINTAIL (G4255EB)
5 * Written by Hiroyuki Bessho for Genetec corp.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of Genetec corp. may not be used to endorse
16 *    or promote products derived from this software without specific prior
17 *    written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORP.
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/device.h>
36#include <sys/callout.h>
37#include <sys/kernel.h>
38#include <sys/kthread.h>
39#include <sys/malloc.h>
40#include <uvm/uvm.h>
41
42#include <sys/bus.h>
43#include <machine/intr.h>
44
45#include <dev/pcmcia/pcmciareg.h>
46#include <dev/pcmcia/pcmciavar.h>
47#include <dev/pcmcia/pcmciachip.h>
48
49#include <arch/arm/xscale/pxa2x0var.h>
50#include <arch/arm/xscale/pxa2x0reg.h>
51#include <arch/arm/sa11x0/sa11xx_pcicvar.h>
52#include <arch/evbarm/g42xxeb/g42xxeb_reg.h>
53#include <arch/evbarm/g42xxeb/g42xxeb_var.h>
54#include <arch/evbarm/g42xxeb/gb225reg.h>
55#include <arch/evbarm/g42xxeb/gb225var.h>
56
57
58//#define DONT_USE_CARD_DETECT_INTR
59
60#define PCMCIA_INT	G42XXEB_INT_EXT1
61#define CF_INT     	G42XXEB_INT_EXT0
62
63#ifdef DEBUG
64#define DPRINTF(arg)	printf arg
65#else
66#define DPRINTF(arg)
67#endif
68
69struct opcic_softc;
70
71struct opcic_socket {
72	struct sapcic_socket ss;	/* inherit socket for sa11x0 pcic */
73
74#if 0
75	int voltage;			/* card power voltage selected by
76					   upper layer */
77#endif
78};
79
80struct opcic_softc {
81	struct sapcic_softc sc_pc;	/* inherit SA11xx pcic */
82
83	struct opcic_socket sc_socket[2];
84	int sc_cards;
85	bus_space_handle_t sc_memctl_ioh;
86};
87
88static int  	opcic_match(struct device *, struct cfdata *, void *);
89static void  	opcic_attach(struct device *, struct device *, void *);
90static int 	opcic_print(void *, const char *);
91
92static	int	opcic_read(struct sapcic_socket *, int);
93static	void	opcic_write(struct sapcic_socket *, int, int);
94static	void	opcic_set_power(struct sapcic_socket *, int);
95static	void	opcic_clear_intr(int);
96static	void	*opcic_intr_establish(struct sapcic_socket *, int,
97				       int (*)(void *), void *);
98static	void	opcic_intr_disestablish(struct sapcic_socket *, void *);
99#ifndef DONT_USE_CARD_DETECT_INTR
100static	int	opcic_card_detect(void *, int);
101#endif
102
103CFATTACH_DECL(opcic, sizeof(struct opcic_softc),
104    opcic_match, opcic_attach, NULL, NULL);
105
106static struct sapcic_tag opcic_tag = {
107	opcic_read,
108	opcic_write,
109	opcic_set_power,
110	opcic_clear_intr,
111	opcic_intr_establish,
112	opcic_intr_disestablish,
113};
114
115
116#define HAVE_CARD(r)	(((r)&CARDDET_DET)==0)
117
118static inline uint8_t
119opcic_read_card_status(struct opcic_socket *so)
120{
121	struct opcic_softc *sc = (struct opcic_softc *)(so->ss.sc);
122	struct opio_softc *osc =
123	    device_private(device_parent(sc->sc_pc.sc_dev));
124
125	return bus_space_read_1(osc->sc_iot, osc->sc_ioh,
126	    GB225_CFDET + 2 * so->ss.socket);
127
128}
129
130static int
131opcic_match(struct device *parent, struct cfdata *cf, void *aux)
132{
133	return	1;
134}
135
136static void
137opcic_attach(struct device *parent, struct device *self, void *aux)
138{
139	int i;
140	struct pcmciabus_attach_args paa;
141	struct opcic_softc *sc = (struct opcic_softc *)self;
142	struct opio_softc *psc = (struct opio_softc *)parent;
143	struct obio_softc *bsd = (struct obio_softc *)device_parent(parent);
144	bus_space_handle_t memctl_ioh = bsd->sc_memctl_ioh;
145	bus_space_tag_t iot =  psc->sc_iot;
146
147	printf("\n");
148
149	/* tell PXA2X0 that we have two sockets */
150#if 0
151	bus_space_write_4(iot, memctl_ioh, MEMCTL_MECR, MECR_NOS);
152#else
153	bus_space_write_4(iot, memctl_ioh, MEMCTL_MECR, MECR_CIT|MECR_NOS);
154#endif
155	sc->sc_pc.sc_iot = psc->sc_iot;
156	sc->sc_memctl_ioh = memctl_ioh;
157
158	sc->sc_cards = 0;
159
160	for(i = 0; i < 2; i++) {
161		sc->sc_socket[i].ss.sc = &sc->sc_pc;
162		sc->sc_socket[i].ss.socket = i;
163		sc->sc_socket[i].ss.pcictag_cookie = NULL;
164		sc->sc_socket[i].ss.pcictag = &opcic_tag;
165		sc->sc_socket[i].ss.event_thread = NULL;
166		sc->sc_socket[i].ss.event = 0;
167		sc->sc_socket[i].ss.laststatus = CARDDET_NOCARD;
168		sc->sc_socket[i].ss.shutdown = 0;
169
170		sc->sc_socket[i].ss.power_capability =
171		    (SAPCIC_POWER_5V|SAPCIC_POWER_3V);
172
173		bus_space_write_4(iot, memctl_ioh, MEMCTL_MCIO(i),
174		    MC_TIMING_VAL(1,1,1));
175#if 0
176		bus_space_write_4(iot, memctl_ioh, MEMCTL_MCATT(i),
177		    MC_TIMING_VAL(31,31,31));
178#endif
179
180		paa.paa_busname = "pcmcia";
181		paa.pct = (pcmcia_chipset_tag_t)&sa11x0_pcmcia_functions;
182		paa.pch = (pcmcia_chipset_handle_t)&sc->sc_socket[i].ss;
183
184		sc->sc_socket[i].ss.pcmcia =
185		    config_found_ia(sc->sc_pc.sc_dev,
186		    "pcmciabus", &paa, opcic_print);
187
188#ifndef DONT_USE_CARD_DETECT_INTR
189		/* interrupt for card insertion/removal */
190		opio_intr_establish(psc,
191		    i==0 ? OPIO_INTR_CF_INSERT : OPIO_INTR_PCMCIA_INSERT,
192		    IPL_BIO, opcic_card_detect, &sc->sc_socket[i]);
193#else
194		bus_space_write_4(iot, ioh, MEMCTL_MECR, MECR_NOS | MECR_CIT);
195
196#endif
197
198		/* schedule kthread creation */
199		sapcic_kthread_create(&sc->sc_socket[i].ss);
200	}
201
202}
203
204static int
205opcic_print(void *aux, const char *name)
206{
207	return (UNCONF);
208}
209
210#ifndef DONT_USE_CARD_DETECT_INTR
211static int
212opcic_card_detect(void *arg, int val)
213{
214	struct opcic_socket *socket = arg;
215	struct opcic_softc *sc = (struct opcic_softc *)socket->ss.sc;
216	bus_space_tag_t iot = sc->sc_pc.sc_iot;
217	bus_space_handle_t memctl_ioh = sc->sc_memctl_ioh;
218	int sock_no = socket->ss.socket;
219	int last, s;
220
221	s = splbio();
222	last = sc->sc_cards;
223	if (HAVE_CARD(val)) {
224		sc->sc_cards |= 1<<sock_no;
225		/* if it is the first card, turn on expansion memory
226		 * control. */
227		if (last == 0)
228			bus_space_write_4(iot, memctl_ioh, MEMCTL_MECR,
229			    MECR_NOS | MECR_CIT);
230	}
231	else {
232		sc->sc_cards &= ~(1<<sock_no);
233		/* if we loast all cards, turn off expansion memory
234		 * control. */
235#if 0
236		if (sc->sc_cards == 0)
237			bus_space_write_4(iot, memctl_ioh,
238			    MEMCTL_MECR, MECR_NOS);
239#endif
240	}
241	splx(s);
242
243	DPRINTF(("%s: card %d %s\n", device_xname(sc->sc_pc.sc_dev), sock_no,
244	    HAVE_CARD(val) ? "inserted" : "removed"));
245
246	sapcic_intr(arg);
247
248	return 1;
249}
250#endif /* DONT_USE_CARD_DETECT_INTR */
251
252static int
253opcic_read(struct sapcic_socket *__so, int which)
254{
255	struct opcic_socket *so = (struct opcic_socket *)__so;
256	uint8_t reg;
257
258	reg = opcic_read_card_status(so);
259
260	switch (which) {
261	case SAPCIC_STATUS_CARD:
262		return HAVE_CARD(reg) ?
263		    SAPCIC_CARD_VALID : SAPCIC_CARD_INVALID;
264
265	case SAPCIC_STATUS_VS1:
266		return (reg & CARDDET_NVS1) == 0;
267
268	case SAPCIC_STATUS_VS2:
269		return (reg & CARDDET_NVS2) == 0;
270
271	case SAPCIC_STATUS_READY:
272		return 1;
273
274	default:
275		panic("%s: bogus register", __func__);
276	}
277}
278
279static void
280opcic_write(struct sapcic_socket *__so, int which, int arg)
281{
282	struct opcic_socket *so = (struct opcic_socket *)__so;
283	struct opcic_softc *sc = (struct opcic_softc *)so->ss.sc;
284	struct opio_softc *psc =
285	     device_private(device_parent(sc->sc_pc.sc_dev));
286	struct obio_softc *bsc =
287	     device_private(device_parent(psc->sc_dev));
288
289	switch (which) {
290	case SAPCIC_CONTROL_RESET:
291		obio_peripheral_reset(bsc, so->ss.socket, arg);
292		delay(500*1000);
293		break;
294
295	case SAPCIC_CONTROL_LINEENABLE:
296		break;
297
298	case SAPCIC_CONTROL_WAITENABLE:
299		break;
300
301	case SAPCIC_CONTROL_POWERSELECT:
302#if 0
303		so->voltage = arg;
304#endif
305		break;
306
307	default:
308		panic("%s: bogus register", __func__);
309	}
310}
311
312static void
313opcic_set_power(struct sapcic_socket *__so, int arg)
314{
315	struct opcic_socket *so = (struct opcic_socket *)__so;
316	struct opcic_softc *sc = (struct opcic_softc *)so->ss.sc;
317	struct opio_softc *psc =
318	    device_private(device_parent(sc->sc_pc.sc_dev));
319 	int shift, save;
320	volatile uint8_t *p;
321
322	if( arg < 0 || SAPCIC_POWER_5V < arg )
323		panic("sacpcic_set_power: bogus arg\n");
324
325	DPRINTF(("card %d: DET=%x\n",
326	    so->ss.socket,
327	    bus_space_read_1(psc->sc_iot, psc->sc_ioh,
328		GB225_CFDET + 2*so->ss.socket)));
329
330	p = (volatile uint8_t *)bus_space_vaddr(psc->sc_iot, psc->sc_ioh)
331	    + GB225_CARDPOW;
332
333	shift = 4 * !so->ss.socket;
334
335	save = disable_interrupts(I32_bit);
336	*p = (*p & ~(0x0f << shift)) | ((CARDPOW_VPPVCC | (arg<<2)) << shift);
337	restore_interrupts(save);
338
339	DPRINTF(("card %d power: %x\n", so->ss.socket, *p));
340}
341
342static void
343opcic_clear_intr(int arg)
344{
345}
346
347static void *
348opcic_intr_establish(struct sapcic_socket *so, int level,
349    int (* ih_fun)(void *), void *ih_arg)
350{
351	struct opcic_softc *sc = (struct opcic_softc *)so->sc;
352	struct opio_softc *psc =
353	    device_private(device_parent(sc->sc_pc.sc_dev));
354	struct obio_softc *bsc =
355	    device_private(device_parent(psc->sc_dev));
356	int irq;
357
358	DPRINTF(("opcic_intr_establish %d\n", so->socket));
359
360	irq = so->socket ? PCMCIA_INT : CF_INT;
361	return obio_intr_establish(bsc, irq, level, IST_EDGE_FALLING,
362	    ih_fun, ih_arg);
363}
364
365static void
366opcic_intr_disestablish(struct sapcic_socket *so, void *ih)
367{
368	struct opcic_softc *sc = (struct opcic_softc *)so->sc;
369	struct opio_softc *psc =
370	    device_private(device_parent(sc->sc_pc.sc_dev));
371	struct obio_softc *bsc =
372	    (struct obio_softc *) device_parent(psc->sc_dev);
373	int (* func)(void *) = ((struct obio_handler *)ih)->func;
374
375	int irq = so->socket ? PCMCIA_INT : CF_INT;
376
377	obio_intr_disestablish(bsc, irq, func);
378}
379