-/* $OpenBSD: imxehci.c,v 1.9 2016/05/19 09:54:18 jsg Exp $ */
+/* $OpenBSD: imxehci.c,v 1.10 2016/07/09 12:32:50 kettenis Exp $ */
/*
* Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
*
#include <machine/intr.h>
#include <machine/bus.h>
+#include <machine/fdt.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <armv7/imx/imxccmvar.h>
#include <armv7/imx/imxgpiovar.h>
+#include <dev/ofw/openfirm.h>
+
#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>
#define USBPHY_CTRL_SFTRST (1U << 31)
/* ehci */
+#define USB_EHCI_OFFSET 0x100
+
#define EHCI_USBMODE 0xa8
#define EHCI_USBMODE_HOST (3 << 0)
#define USBNC_USB_UH1_CTRL_OVER_CUR_POL (1 << 8)
#define USBNC_USB_UH1_CTRL_OVER_CUR_DIS (1 << 7)
-/* port specific addresses */
-#define USBOTG_EHCI_ADDR 0x02184100
-#define USBUH1_EHCI_ADDR 0x02184300
-#define USBUH2_EHCI_ADDR 0x02184500
-#define USBUH3_EHCI_ADDR 0x02184700
-
/* board specific */
#define EHCI_HUMMINGBOARD_USB_H1_PWR 0
#define EHCI_HUMMINGBOARD_USB_OTG_PWR (2*32+22)
#define EHCI_SABRESD_USB_PWR (0*32+29)
#define EHCI_UTILITE_USB_HUB_RST (6*32+8)
+int imxehci_match(struct device *, void *, void *);
void imxehci_attach(struct device *, struct device *, void *);
int imxehci_detach(struct device *, int);
};
struct cfattach imxehci_ca = {
- sizeof (struct imxehci_softc), NULL, imxehci_attach,
- imxehci_detach, NULL
+ sizeof (struct imxehci_softc), imxehci_match, imxehci_attach,
+ imxehci_detach
};
+int
+imxehci_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "fsl,imx27-usb");
+}
+
void
imxehci_attach(struct device *parent, struct device *self, void *aux)
{
- struct imxehci_softc *sc = (struct imxehci_softc *)self;
- struct armv7_attach_args *aa = aux;
- usbd_status r;
+ struct imxehci_softc *sc = (struct imxehci_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ usbd_status r;
char *devname = sc->sc.sc_bus.bdev.dv_xname;
+ uint32_t phy[1], misc[2];
+ uint32_t phy_reg[2];
+ uint32_t misc_reg[2];
+ int node;
- sc->sc.iot = aa->aa_iot;
- sc->sc.sc_bus.dmatag = aa->aa_dmat;
- sc->sc.sc_size = aa->aa_dev->mem[0].size;
+ if (faa->fa_nreg < 2 || faa->fa_nintr < 3)
+ return;
+
+ if (OF_getpropintarray(faa->fa_node, "fsl,usbphy",
+ phy, sizeof(phy)) != sizeof(phy))
+ return;
+
+ if (OF_getpropintarray(faa->fa_node, "fsl,usbmisc",
+ misc, sizeof(misc)) != sizeof(misc))
+ return;
+
+ node = OF_getnodebyphandle(phy[0]);
+ if (node == 0)
+ return;
+
+ if (OF_getpropintarray(node, "reg", phy_reg,
+ sizeof(phy_reg)) != sizeof(phy_reg))
+ return;
+
+ node = OF_getnodebyphandle(misc[0]);
+ if (node == 0)
+ return;
+
+ if (OF_getpropintarray(node, "reg", misc_reg,
+ sizeof(misc_reg)) != sizeof(misc_reg))
+ return;
+
+ sc->sc.iot = faa->fa_iot;
+ sc->sc.sc_bus.dmatag = faa->fa_dmat;
+ sc->sc.sc_size = faa->fa_reg[1] - USB_EHCI_OFFSET;
/* Map I/O space */
- if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[0].addr,
- aa->aa_dev->mem[0].size, 0, &sc->sc.ioh)) {
+ if (bus_space_map(sc->sc.iot, faa->fa_reg[0],
+ faa->fa_reg[1], 0, &sc->uh_ioh)) {
printf(": cannot map mem space\n");
goto out;
}
-
- if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[1].addr,
- aa->aa_dev->mem[1].size, 0, &sc->uh_ioh)) {
+ if (bus_space_subregion(sc->sc.iot, sc->uh_ioh, USB_EHCI_OFFSET,
+ sc->sc.sc_size, &sc->sc.ioh)) {
printf(": cannot map mem space\n");
goto mem0;
}
- if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[2].addr,
- aa->aa_dev->mem[2].size, 0, &sc->ph_ioh)) {
+ if (bus_space_map(sc->sc.iot, phy_reg[0],
+ phy_reg[1], 0, &sc->ph_ioh)) {
printf(": cannot map mem space\n");
goto mem1;
}
- if (bus_space_map(sc->sc.iot, aa->aa_dev->mem[3].addr,
- aa->aa_dev->mem[3].size, 0, &sc->nc_ioh)) {
+ if (bus_space_map(sc->sc.iot, misc_reg[0],
+ misc_reg[1], 0, &sc->nc_ioh)) {
printf(": cannot map mem space\n");
goto mem2;
}
imxccm_enable_usboh3();
delay(1000);
- if (aa->aa_dev->mem[0].addr == USBUH1_EHCI_ADDR) {
+ if (misc[1] == 1) {
/* enable usb port power */
- switch (board_id)
- {
+ switch (board_id) {
case BOARD_ID_IMX6_CUBOXI:
case BOARD_ID_IMX6_HUMMINGBOARD:
imxgpio_set_bit(EHCI_HUMMINGBOARD_USB_H1_PWR);
bus_space_write_4(sc->sc.iot, sc->nc_ioh, USBNC_USB_UH1_CTRL,
bus_space_read_4(sc->sc.iot, sc->nc_ioh, USBNC_USB_UH1_CTRL) |
(USBNC_USB_UH1_CTRL_OVER_CUR_POL | USBNC_USB_UH1_CTRL_OVER_CUR_DIS));
- } else if (aa->aa_dev->mem[0].addr == USBOTG_EHCI_ADDR) {
+ } else if (misc[1] == 0) {
/* enable usb port power */
- switch (board_id)
- {
+ switch (board_id) {
case BOARD_ID_IMX6_CUBOXI:
case BOARD_ID_IMX6_HUMMINGBOARD:
imxgpio_set_dir(EHCI_HUMMINGBOARD_USB_OTG_PWR, IMXGPIO_DIR_OUT);
EOWRITE4(&sc->sc, EHCI_PORTSC(1),
EOREAD4(&sc->sc, EHCI_PORTSC(1)) & ~EHCI_PS_PTS_UTMI_MASK);
- sc->sc_ih = arm_intr_establish(aa->aa_dev->irq[0], IPL_USB,
+ sc->sc_ih = arm_intr_establish(faa->fa_intr[1], IPL_USB,
ehci_intr, &sc->sc, devname);
if (sc->sc_ih == NULL) {
printf(": unable to establish interrupt\n");
arm_intr_disestablish(sc->sc_ih);
sc->sc_ih = NULL;
mem3:
- bus_space_unmap(sc->sc.iot, sc->nc_ioh, aa->aa_dev->mem[3].addr);
+ bus_space_unmap(sc->sc.iot, sc->nc_ioh, misc_reg[1]);
mem2:
- bus_space_unmap(sc->sc.iot, sc->ph_ioh, aa->aa_dev->mem[2].addr);
+ bus_space_unmap(sc->sc.iot, sc->ph_ioh, phy_reg[1]);
mem1:
- bus_space_unmap(sc->sc.iot, sc->uh_ioh, aa->aa_dev->mem[1].addr);
mem0:
- bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+ bus_space_unmap(sc->sc.iot, sc->sc.ioh, faa->fa_reg[1]);
sc->sc.sc_size = 0;
out:
return;