1/*	$Id: imx31lk_pcic.c,v 1.6 2012/11/12 18:00:39 skrll Exp $	*/
2/*	$NetBSD: imx31lk_pcic.c,v 1.5 2012/10/27 17:17:47 chs Exp $	*/
3/*	$OpenBSD: pxapcic.c,v 1.1 2005/07/01 23:51:55 uwe Exp $	*/
4
5/*
6 * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/cdefs.h>
22__KERNEL_RCSID(0, "$Id: imx31lk_pcic.c,v 1.6 2012/11/12 18:00:39 skrll Exp $");
23
24#include <sys/param.h>
25#include <sys/systm.h>
26#include <sys/device.h>
27
28#include <machine/intr.h>
29#include <sys/bus.h>
30
31#include <uvm/uvm.h>
32
33#ifdef NOTYET
34#include <arch/arm/imx/imx_emifs.h>
35#include <arch/arm/imx/imx_gpio.h>
36#endif
37#include <arch/arm/imx/imx31var.h>
38#include <arch/arm/imx/imx_pcic.h>
39
40
41static int	imx31lk_pcic_match(device_t, cfdata_t, void *);
42static void	imx31lk_pcic_attach(device_t, device_t, void *);
43
44CFATTACH_DECL_NEW(imx31lk_pcic, sizeof(struct imx_pcic_softc),
45	imx31lk_pcic_match, imx31lk_pcic_attach, NULL, NULL);
46
47static void	imx31lk_pcic_socket_setup(struct imx_pcic_socket *);
48static u_int	imx31lk_pcic_read(struct imx_pcic_socket *, int);
49static void	imx31lk_pcic_write(struct imx_pcic_socket *, int, u_int);
50static void	imx31lk_pcic_set_power(struct imx_pcic_socket *, int);
51static void	imx31lk_pcic_clear_intr(struct imx_pcic_socket *);
52static void 	*imx31lk_pcic_intr_establish(struct imx_pcic_socket *, int,
53		    int (*)(void *), void *);
54static void	imx31lk_pcic_intr_disestablish(struct imx_pcic_socket *, void *);
55
56struct imx_pcic_tag imx31lk_pcic_functions = {
57	imx31lk_pcic_read,
58	imx31lk_pcic_write,
59	imx31lk_pcic_set_power,
60	imx31lk_pcic_clear_intr,
61	imx31lk_pcic_intr_establish,
62	imx31lk_pcic_intr_disestablish
63};
64
65static int
66imx31lk_pcic_match(device_t parent, cfdata_t cf, void *aux)
67{
68
69	return 1;	/* XXX */
70}
71
72static void
73imx31lk_pcic_attach(device_t parent, device_t self, void *aux)
74{
75	struct imx_pcic_softc *sc = device_private(self);
76	struct aips_attach_args * const aipsa = aux;
77
78	sc->sc_dev = self;
79
80printf("\n");
81printf("imx_iot %p\n", aipsa->aipsa_memt);
82printf("imx_addr %lx\n", aipsa->aipsa_addr);
83printf("imx_size %lx\n", aipsa->aipsa_size);
84printf("imx_intr %d\n", aipsa->aipsa_intr);
85
86	sc->sc_pa = aipsa->aipsa_addr;
87	sc->sc_iot = aipsa->aipsa_memt;
88
89	sc->sc_nslots = 1;
90#ifdef NOTYET
91	sc->sc_irqpin[0] = aa->emifs_intr;	/* XXX */
92	sc->sc_irqcfpin[0] = -1;		/* XXX */
93#endif
94
95	sc->sc_flags |= PPF_REVERSE_ORDER;
96
97	imx_pcic_attach_common(sc, &imx31lk_pcic_socket_setup);
98}
99
100static void
101imx31lk_pcic_socket_setup(struct imx_pcic_socket *so)
102{
103	struct imx_pcic_softc *sc;
104	bus_addr_t pa;
105	bus_size_t size = 0x2000;		/* XXX */
106	bus_space_tag_t iot;
107	bus_space_handle_t imx31lkh;
108	int error;
109
110	sc = so->sc;
111	iot = sc->sc_iot;
112
113	if (so->socket != 0)
114		panic("%s: CF slot %d not supported", device_xname(sc->sc_dev), so->socket);
115
116	pa = sc->sc_pa;
117
118	error = bus_space_map(iot, trunc_page(pa), round_page(size),
119	    0, &imx31lkh);
120	if (error) {
121		panic("%s: failed to map memory %x for imx31lk",
122		    device_xname(sc->sc_dev), (uint32_t)pa);
123	}
124	imx31lkh += pa - trunc_page(pa);
125
126#ifdef NOTYET
127	/* setup */
128#endif
129
130#ifdef NOTYET
131	so->power_capability = PXAPCIC_POWER_3V;
132	if (so->socket == 0)
133		so->power_capability |= PXAPCIC_POWER_5V;
134#endif
135
136	so->pcictag_cookie = (void *)imx31lkh;
137	so->pcictag = &imx31lk_pcic_functions;
138}
139
140static u_int
141imx31lk_pcic_read(struct imx_pcic_socket *so, int reg)
142{
143#ifdef NOTYET
144	bus_space_tag_t iot = so->sc->sc_iot;
145	bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie;
146	uint16_t csr;
147
148	csr = bus_space_read_2(iot, ioh, SCOOP_CSR);
149
150	switch (reg) {
151	case PXAPCIC_CARD_STATUS:
152		if (csr & SCP_CSR_MISSING)
153			return (PXAPCIC_CARD_INVALID);
154		else
155			return (PXAPCIC_CARD_VALID);
156
157	case PXAPCIC_CARD_READY:
158		return ((bus_space_read_2(iot, ioh, SCOOP_CSR) &
159		    SCP_CSR_READY) != 0);
160
161	default:
162		panic("imx31lk_pcic_read: bogus register");
163	}
164	/*NOTREACHED*/
165#else
166	panic("imx31lk_pcic_read");
167#endif
168}
169
170static void
171imx31lk_pcic_write(struct imx_pcic_socket *so, int reg, u_int val)
172{
173#ifdef NOTYET
174	bus_space_tag_t iot = so->sc->sc_iot;
175	bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie;
176	uint16_t newval;
177	int s;
178
179	s = splhigh();
180
181	switch (reg) {
182	case PXAPCIC_CARD_POWER:
183		newval = bus_space_read_2(iot, ioh, SCOOP_CPR);
184		newval &= ~(SCP_CPR_PWR | SCP_CPR_3V | SCP_CPR_5V);
185
186		if (val == PXAPCIC_POWER_3V)
187			newval |= (SCP_CPR_PWR | SCP_CPR_3V);
188		else if (val == PXAPCIC_POWER_5V)
189			newval |= (SCP_CPR_PWR | SCP_CPR_5V);
190
191		bus_space_write_2(iot, ioh, SCOOP_CPR, newval);
192		break;
193
194	case PXAPCIC_CARD_RESET:
195		bus_space_write_2(iot, ioh, SCOOP_CCR,
196		    val ? SCP_CCR_RESET : 0);
197		break;
198
199	default:
200		panic("imx31lk_pcic_write: bogus register");
201	}
202
203	splx(s);
204#else
205	panic("imx31lk_pcic_write");
206#endif
207}
208
209static void
210imx31lk_pcic_set_power(struct imx_pcic_socket *so, int pwr)
211{
212#ifdef NOTYET
213	bus_space_tag_t iot = so->sc->sc_iot;
214	bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie;
215	uint16_t reg;
216	int s;
217
218	s = splhigh();
219
220	switch (pwr) {
221	case PXAPCIC_POWER_OFF:
222#if 0
223		/* XXX does this disable power to both sockets? */
224		reg = bus_space_read_2(iot, ioh, SCOOP_GPWR);
225		bus_space_write_2(iot, ioh, SCOOP_GPWR,
226		    reg & ~(1 << SCOOP0_CF_POWER_C3000));
227#endif
228		break;
229
230	case PXAPCIC_POWER_3V:
231	case PXAPCIC_POWER_5V:
232		/* XXX */
233		if (so->socket == 0) {
234			reg = bus_space_read_2(iot, ioh, SCOOP_GPWR);
235			bus_space_write_2(iot, ioh, SCOOP_GPWR,
236			    reg | (1 << SCOOP0_CF_POWER_C3000));
237		}
238		break;
239
240	default:
241		splx(s);
242		panic("imx31lk_pcic_set_power: bogus power state");
243	}
244
245	splx(s);
246#else
247	panic("imx31lk_pcic_set_power");
248#endif
249}
250
251static void
252imx31lk_pcic_clear_intr(struct imx_pcic_socket *so)
253{
254#ifdef NOTYET
255	bus_space_tag_t iot = so->sc->sc_iot;
256	bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie;
257
258	bus_space_write_2(iot, ioh, SCOOP_IRM, 0x00ff);
259	bus_space_write_2(iot, ioh, SCOOP_ISR, 0x0000);
260	bus_space_write_2(iot, ioh, SCOOP_IRM, 0x0000);
261#else
262	panic("imx31lk_pcic_clear_intr");
263#endif
264}
265
266static void *
267imx31lk_pcic_intr_establish(struct imx_pcic_socket *so, int ipl,
268    int (*func)(void *), void *arg)
269{
270#ifdef NOTYET
271printf("%s: irqpin %d\n", __func__, so->irqpin);
272	return (imx_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING,
273	    ipl, "pcic", func, arg));
274#else
275	return 0;		/* XXX */
276#endif
277}
278
279static void
280imx31lk_pcic_intr_disestablish(struct imx_pcic_socket *so, void *ih)
281{
282
283#ifdef NOTYET
284	imx_gpio_intr_disestablish(ih);
285#endif
286}
287