diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2012-03-26 10:15:09 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2012-03-26 10:15:09 +0200 |
commit | 918638f58d2d744d956d8025f89e1d0625119152 (patch) | |
tree | 4092e7782e4cc8c02d9a71a370571db36549b6f8 /rtemsbsd/dev/usb/controller/ehci_mpc83xx.c | |
parent | Use new fsync_or_fdatasync default (diff) | |
download | rtems-libbsd-918638f58d2d744d956d8025f89e1d0625119152.tar.bz2 |
New USB device specific controller files
Diffstat (limited to 'rtemsbsd/dev/usb/controller/ehci_mpc83xx.c')
-rw-r--r-- | rtemsbsd/dev/usb/controller/ehci_mpc83xx.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/rtemsbsd/dev/usb/controller/ehci_mpc83xx.c b/rtemsbsd/dev/usb/controller/ehci_mpc83xx.c new file mode 100644 index 00000000..88952e5f --- /dev/null +++ b/rtemsbsd/dev/usb/controller/ehci_mpc83xx.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <freebsd/machine/rtems-bsd-config.h> + +#include <bsp.h> + +#if defined(__GEN83xx_BSP_h) || defined(LIBBSP_POWERPC_QORIQ_BSP_H) + +#include <bsp/irq.h> +#include <bsp/utility.h> + +#ifdef __GEN83xx_BSP_h + #include <mpc83xx/mpc83xx.h> + #define BSP_EHCI_REGISTER_BASE_ADDR ((unsigned) &mpc83xx.usb_dr.caplength) + #define BSP_EHCI_IRQ_VECTOR BSP_IPIC_IRQ_USB_DR +#endif + +#ifdef LIBBSP_POWERPC_QORIQ_BSP_H + #include <bsp/qoriq.h> + #define BSP_EHCI_REGISTER_BASE_ADDR ((unsigned) &qoriq.usb_1 + 0x100) + #define BSP_EHCI_IRQ_VECTOR QORIQ_IRQ_USB_1 +#endif + +#include <freebsd/sys/cdefs.h> +#include <freebsd/sys/stdint.h> +#include <freebsd/sys/stddef.h> +#include <freebsd/sys/param.h> +#include <freebsd/sys/queue.h> +#include <freebsd/sys/types.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/kernel.h> +#include <freebsd/sys/bus.h> +#include <freebsd/sys/linker_set.h> +#include <freebsd/sys/module.h> +#include <freebsd/sys/lock.h> +#include <freebsd/sys/mutex.h> +#include <freebsd/sys/condvar.h> +#include <freebsd/sys/sysctl.h> +#include <freebsd/sys/sx.h> +#include <freebsd/sys/unistd.h> +#include <freebsd/sys/callout.h> +#include <freebsd/sys/malloc.h> +#include <freebsd/sys/priv.h> + +#include <freebsd/dev/usb/usb.h> +#include <freebsd/dev/usb/usbdi.h> + +#include <freebsd/dev/usb/usb_core.h> +#include <freebsd/dev/usb/usb_busdma.h> +#include <freebsd/dev/usb/usb_process.h> +#include <freebsd/dev/usb/usb_util.h> + +#include <freebsd/dev/usb/usb_controller.h> +#include <freebsd/dev/usb/usb_bus.h> +#include <freebsd/dev/usb/controller/ehci.h> + +static device_probe_t ehci_mpc83xx_probe; +static device_attach_t ehci_mpc83xx_attach; +static device_detach_t ehci_mpc83xx_detach; +static device_suspend_t ehci_mpc83xx_suspend; +static device_resume_t ehci_mpc83xx_resume; + +static int +ehci_mpc83xx_suspend(device_t self) +{ + ehci_softc_t *e = device_get_softc(self); + int eno = bus_generic_suspend(self); + + if (eno != 0) { + return (eno); + } + + ehci_suspend(e); + + return (0); +} + +static int +ehci_mpc83xx_resume(device_t self) +{ + ehci_softc_t *e = device_get_softc(self); + + ehci_resume(e); + + bus_generic_resume(self); + + return (0); +} + + +static int +ehci_mpc83xx_probe(device_t self) +{ + device_set_desc(self, "EHCI"); + + return (0); +} + +#define CONTROL_ULPI_INT_EN BSP_BBIT32(31) +#define CONTROL_WU_INT_EN BSP_BBIT32(30) +#define CONTROL_USB_EN BSP_BBIT32(29) +#define CONTROL_LSF_EN BSP_BBIT32(28) +#define CONTROL_KEEP_OTG_ON BSP_BBIT32(27) +#define CONTROL_OTG_PORT BSP_BBIT32(26) +#define CONTROL_REFSEL(val) BSP_BFLD32(val, 24, 25) +#define CONTROL_PLL_RESET BSP_BBIT32(23) +#define CONTROL_UTMI_PHY_EN BSP_BBIT32(22) +#define CONTROL_PHY_CLOCK_SEL BSP_BBIT32(21) +#define CONTROL_CLKIN_SEL(val) BSP_BFLD32(val, 19, 20) +#define CONTROL_WU_INT BSP_BBIT32(15) +#define CONTROL_PHY_CLK_VALID BSP_BBIT32(14) + +static void +ehci_mpc83xx_phy_init(void) +{ +#ifdef __GEN83xx_BSP_h + volatile uint32_t *control = &mpc83xx.usb_dr.control; + + *control = CONTROL_PLL_RESET | CONTROL_REFSEL(0x2U); + *control = CONTROL_UTMI_PHY_EN | CONTROL_REFSEL(0x2U); + + while ((*control & CONTROL_PHY_CLK_VALID) == 0) { + /* Wait for PLL */ + } +#endif +} + +#define USBMODE_SDIS BSP_BIT32(4) +#define USBMODE_SLOM BSP_BIT32(3) +#define USBMODE_CM_IDLE BSP_FLD32(0x0, 0, 1) +#define USBMODE_CM_DEVICE BSP_FLD32(0x2, 0, 1) +#define USBMODE_CM_HOST BSP_FLD32(0x3, 0, 1) + +#define PORTSC_PTS(val) BSP_FLD32(val, 30, 31) +#define PORTSC_PTS_UTMI PORTSC_PTS(0x0) +#define PORTSC_PTS_ULPI PORTSC_PTS(0x2) +#define PORTSC_PE BSP_BIT32(2) + +#define SNOOP_ADDR(val) BSP_BFLD32(val, 0, 19) +#define SNOOP_ENABLE(val) BSP_BFLD32(val, 27, 31) +#define SNOOP_SIZE_2GB SNOOP_ENABLE(0x1e) + +static void +ehci_mpc83xx_host_init(void) +{ +#ifdef __GEN83xx_BSP_h + mpc83xx.usb_dr.snoop1 = SNOOP_ADDR(0x0) | SNOOP_SIZE_2GB; + mpc83xx.usb_dr.snoop2 = SNOOP_ADDR(0x80000) | SNOOP_SIZE_2GB; + mpc83xx.usb_dr.control = CONTROL_UTMI_PHY_EN | CONTROL_REFSEL(0x2) | CONTROL_USB_EN; + mpc83xx.usb_dr.portsc1 = htole32(PORTSC_PTS_UTMI); +#if 0 + mpc83xx.usb_dr.pri_ctrl = 0xcU; + mpc83xx.usb_dr.age_cnt_thresh = 0x40U; + mpc83xx.usb_dr.si_ctrl = 0x1U; +#endif + mpc83xx.usb_dr.usbmode = USBMODE_CM_HOST; +#endif +#ifdef LIBBSP_POWERPC_QORIQ_BSP_H + qoriq.usb_1.snoop1 = SNOOP_ADDR(0x0) | SNOOP_SIZE_2GB; + qoriq.usb_1.snoop2 = SNOOP_ADDR(0x80000) | SNOOP_SIZE_2GB; + qoriq.usb_1.control = CONTROL_USB_EN; + qoriq.usb_1.portsc1 = htole32(PORTSC_PTS_ULPI | BSP_BIT32(28) | PORTSC_PE); + qoriq.usb_1.usbmode = USBMODE_CM_HOST; +#endif +} + +static int +ehci_mpc83xx_attach(device_t self) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + ehci_softc_t *e = device_get_softc(self); + usb_error_t ue = USB_ERR_NORMAL_COMPLETION; + int eno = 0; + + memset(e, 0, sizeof(*e)); + + /* Initialize some bus fields */ + e->sc_bus.parent = self; + e->sc_bus.devices = e->sc_devices; + e->sc_bus.devices_max = EHCI_MAX_DEVICES; + e->sc_bus.usbrev = USB_REV_2_0; + + /* Get all DMA memory */ + if (usb_bus_mem_alloc_all(&e->sc_bus, USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { + return (ENOMEM); + } + + /* Child device */ + e->sc_bus.bdev = device_add_child(self, "usbus", -1); + if (e->sc_bus.bdev == NULL) { + device_printf(self, "Could not add USB device\n"); + goto error; + } + device_set_ivars(e->sc_bus.bdev, &e->sc_bus); + device_set_desc(e->sc_bus.bdev, "EHCI"); + snprintf(e->sc_vendor, sizeof(e->sc_vendor), "Freescale"); + + /* Register space */ + e->sc_io_tag = 0; + e->sc_io_hdl = BSP_EHCI_REGISTER_BASE_ADDR; + e->sc_io_size = 0x88; + + ehci_mpc83xx_phy_init(); + + ehci_mpc83xx_host_init(); + + /* Install interrupt handler */ + sc = rtems_interrupt_server_handler_install( + RTEMS_ID_NONE, + BSP_EHCI_IRQ_VECTOR, + "USB", + RTEMS_INTERRUPT_UNIQUE, + (rtems_interrupt_handler) ehci_interrupt, + e + ); + BSD_ASSERT_SC(sc); + + e->sc_flags |= EHCI_SCFLG_SETMODE | EHCI_SCFLG_NORESTERM | EHCI_SCFLG_TT; + + /* EHCI intitialization */ + ue = ehci_init(e); + if (ue != USB_ERR_NORMAL_COMPLETION) { + goto error; + } + + /* Probe and attach child */ + eno = device_probe_and_attach(e->sc_bus.bdev); + if (eno != 0) { + goto error; + } + + return (0); + +error: + ehci_mpc83xx_detach(self); + + return (ENXIO); +} + +static int +ehci_mpc83xx_detach(device_t self) +{ + BSD_PRINTF("TODO\n"); + + return (0); +} + +static device_method_t ehci_methods [] = { + /* Device interface */ + DEVMETHOD(device_probe, ehci_mpc83xx_probe), + DEVMETHOD(device_attach, ehci_mpc83xx_attach), + DEVMETHOD(device_detach, ehci_mpc83xx_detach), + DEVMETHOD(device_suspend, ehci_mpc83xx_suspend), + DEVMETHOD(device_resume, ehci_mpc83xx_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + {0, 0} +}; + +static driver_t ehci_driver = { + .name = "ehci", + .methods = ehci_methods, + .size = sizeof(struct ehci_softc) +}; + +static devclass_t ehci_devclass; + +DRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0); +MODULE_DEPEND(ehci, usb, 1, 1, 1); + +#endif /* defined(__GEN83xx_BSP_h) || defined(LIBBSP_POWERPC_QORIQ_BSP_H) */ |