2 * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/module.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
37 #include <sys/malloc.h>
39 #include <sys/mutex.h>
40 #include <sys/resource.h>
46 #include <machine/bus.h>
47 #include <machine/platform.h>
48 #include <machine/pmap.h>
49 #include <machine/resource.h>
51 #include <powerpc/ps3/ps3-hvcall.h>
55 #define PS3VUART_IRQ_BITMAP_SIZE 32
57 #define PS3VUART_IRQ_RID 0
59 struct ps3vuart_info
{
65 struct resource_list resources
;
68 struct ps3vuart_softc
{
72 static MALLOC_DEFINE(M_PS3VUART
, "ps3vuart", "PS3 VUART");
75 ps3vuart_identify(driver_t
*driver
, device_t parent
)
77 if (strcmp(installed_platform(), "ps3"))
80 if (!device_find_child(parent
, "ps3vuart", -1))
81 BUS_ADD_CHILD(parent
, 0, "ps3vuart", 0);
85 ps3vuart_probe(device_t dev
)
87 device_set_desc(dev
, "Playstation 3 VUART");
89 return (BUS_PROBE_NOWILDCARD
);
93 ps3vuart_attach(device_t dev
)
95 struct ps3vuart_softc
*sc
= device_get_softc(dev
);
96 struct ps3vuart_info
*info
;
99 uint64_t thread
, outlet
, ppe
;
104 /* Setup VUART IRQ */
106 bitmap
= contigmalloc(PS3VUART_IRQ_BITMAP_SIZE
, M_PS3VUART
,
107 M_NOWAIT
| M_ZERO
, 0, BUS_SPACE_MAXADDR
, 32 /* alignment */,
108 PAGE_SIZE
/* boundary */);
110 device_printf(dev
, "Could not allocate VUART IRQ bitmap\n");
114 lv1_deconfigure_virtual_uart_irq();
116 err
= lv1_configure_virtual_uart(vtophys(bitmap
), &outlet
);
118 device_printf(dev
, "Could not configure VUART IRQ (%d)\n", err
);
123 lv1_get_logical_ppe_id(&ppe
);
125 thread
= 32 - fls(mfctrl());
127 err
= lv1_connect_irq_plug_ext(ppe
, thread
, outlet
, outlet
, 0);
129 device_printf(dev
, "Could not connect VUART IRQ (%d)\n", err
);
131 goto deconfig_vuart_irq
;
136 info
= malloc(sizeof(*info
), M_PS3VUART
, M_WAITOK
| M_ZERO
);
138 device_printf(dev
, "Could not allocate bus private variables\n");
140 goto disconnect_vuart_irq
;
143 info
->irq_bitmap
= bitmap
;
144 info
->irq_thread
= thread
;
145 info
->irq_outlet
= outlet
;
147 resource_list_init(&info
->resources
);
148 resource_list_add(&info
->resources
, SYS_RES_IRQ
, PS3VUART_IRQ_RID
,
151 child
= device_add_child(dev
, "ps3vuart_bus", -1);
153 device_printf(dev
, "Could not add child\n");
158 device_set_ivars(child
, info
);
160 err
= bus_generic_attach(dev
);
168 device_delete_child(dev
, child
);
172 resource_list_free(&info
->resources
);
173 free(info
, M_PS3VUART
);
175 disconnect_vuart_irq
:
177 lv1_disconnect_irq_plug_ext(ppe
, thread
, outlet
);
181 lv1_deconfigure_virtual_uart_irq();
185 contigfree(bitmap
, PS3VUART_IRQ_BITMAP_SIZE
, M_PS3VUART
);
191 ps3vuart_detach(device_t dev
)
194 struct ps3vuart_info
*info
;
196 uint64_t thread
, outlet
, ppe
;
200 child
= device_find_child(dev
, "ps3vuart_bus", -1);
202 KASSERT(child
, ("could not find child"));
204 info
= device_get_ivars(child
);
206 bitmap
= info
->irq_bitmap
;
207 thread
= info
->irq_thread
;
208 outlet
= info
->irq_outlet
;
210 resource_list_free(&info
->resources
);
211 free(info
, M_PS3VUART
);
212 device_delete_child(dev
, child
);
214 /* Destroy VUART IRQ */
216 lv1_get_logical_ppe_id(&ppe
);
217 lv1_disconnect_irq_plug_ext(ppe
, thread
, outlet
);
218 lv1_deconfigure_virtual_uart_irq();
220 contigfree(bitmap
, PS3VUART_IRQ_BITMAP_SIZE
, M_PS3VUART
);
226 ps3vuart_print_child(device_t dev
, device_t child
)
228 struct ps3vuart_info
*info
= device_get_ivars(child
);
231 retval
= bus_print_child_header(dev
, child
);
232 retval
+= resource_list_print_type(&info
->resources
, "irq",
234 retval
+= bus_print_child_footer(dev
, child
);
240 ps3vuart_read_ivar(device_t dev
, device_t child
,
241 int index
, uintptr_t *result
)
243 struct ps3vuart_info
*info
= device_get_ivars(child
);
246 case PS3VUART_IVAR_IRQ_BITMAP
:
247 *result
= (uintptr_t) info
->irq_bitmap
;
256 static struct resource
*
257 ps3vuart_alloc_resource(device_t dev
, device_t child
, int type
, int *rid
,
258 u_long start
, u_long end
, u_long count
, u_int flags
)
260 struct ps3vuart_info
*info
= device_get_ivars(child
);
266 return (resource_list_alloc(&info
->resources
, dev
, child
,
267 type
, rid
, start
, end
, count
, flags
));
275 ps3vuart_release_resource(device_t dev
, device_t child
, int type
, int rid
,
278 struct ps3vuart_info
*info
= device_get_ivars(child
);
282 return (resource_list_release(&info
->resources
, dev
, child
,
291 ps3vuart_activate_resource(device_t dev
, device_t child
, int type
, int rid
,
294 if (type
== SYS_RES_IRQ
)
295 return (bus_activate_resource(dev
, type
, rid
, r
));
300 static device_method_t ps3vuart_methods
[] = {
301 /* Device interface */
302 DEVMETHOD(device_identify
, ps3vuart_identify
),
303 DEVMETHOD(device_probe
, ps3vuart_probe
),
304 DEVMETHOD(device_attach
, ps3vuart_attach
),
305 DEVMETHOD(device_detach
, ps3vuart_detach
),
308 DEVMETHOD(bus_print_child
, ps3vuart_print_child
),
309 DEVMETHOD(bus_read_ivar
, ps3vuart_read_ivar
),
310 DEVMETHOD(bus_alloc_resource
, ps3vuart_alloc_resource
),
311 DEVMETHOD(bus_release_resource
, ps3vuart_release_resource
),
312 DEVMETHOD(bus_activate_resource
, ps3vuart_activate_resource
),
313 DEVMETHOD(bus_deactivate_resource
, bus_generic_deactivate_resource
),
314 DEVMETHOD(bus_setup_intr
, bus_generic_setup_intr
),
315 DEVMETHOD(bus_teardown_intr
, bus_generic_teardown_intr
),
320 static driver_t ps3vuart_driver
= {
323 sizeof(struct ps3vuart_softc
)
326 static devclass_t ps3vuart_devclass
;
328 DRIVER_MODULE(ps3vuart
, nexus
, ps3vuart_driver
, ps3vuart_devclass
, 0, 0);
329 MODULE_VERSION(ps3vuart
, 1);