static void awin_tve_attach(device_t parent, device_t self, void *aux) { struct awin_tve_softc *sc = device_private(self); struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; prop_dictionary_t cfg = device_properties(self); int8_t tcon_unit = -1; sc->sc_dev = self; sc->sc_bst = aio->aio_core_bst; bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &sc->sc_bsh); if (prop_dictionary_get_int8(cfg, "tcon_unit", &tcon_unit)) { sc->sc_tcon_unit = tcon_unit; } else { sc->sc_tcon_unit = 0; /* default value */ } sc->sc_tcon_pll = awin_tcon_get_clk_pll(sc->sc_tcon_unit); switch (sc->sc_tcon_pll) { case 3: awin_pll3_enable(); break; case 7: awin_pll7_enable(); break; default: panic("awin_tve pll"); } /* for now assume we're always at 0 */ awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING1_REG, AWIN_AHB_GATING1_TVE0, 0); aprint_naive("\n"); aprint_normal(": TV Encoder / VGA output\n"); if (tcon_unit >= 0) { aprint_verbose_dev(self, ": using TCON%d, pll%d\n", sc->sc_tcon_unit, sc->sc_tcon_pll); } sc->sc_i2c_blklen = 16; #if 0 sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL, awin_tve_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt %d\n", loc->loc_intr); return; } aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr); #endif awin_tve_i2c_init(sc); awin_tve_enable(sc); awin_tve_read_edid(sc); }
static void awin_tcon_clear_reset(struct awinio_attach_args * const aio, int unit) { KASSERT(unit == 0 || unit == 1); if (awin_chip_id() == AWIN_CHIP_ID_A31) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_A31_AHB_RESET1_REG, AWIN_A31_AHB_RESET1_LCD0_RST << unit, 0); } else { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_LCD0_CH0_CLK_REG + (unit * 4), AWIN_LCDx_CH0_CLK_LCDx_RST, 0); } awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING1_REG, AWIN_AHB_GATING1_LCD0 << unit, 0); }
static void awin_otg_attach(device_t parent, device_t self, void *aux) { struct awin_otg_softc *sc = device_private(self); struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; aprint_naive("\n"); aprint_normal(": OTG\n"); if (awin_chip_id() == AWIN_CHIP_ID_A31) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_USB_CLK_REG, AWIN_A31_USB_CLK_USBPHY0_ENABLE | AWIN_A31_USB_CLK_PHY0_ENABLE, 0); awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING0_REG, AWIN_A31_AHB_GATING0_USB0, 0); awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_A31_AHB_RESET0_REG, AWIN_A31_AHB_RESET0_USBOTG_RST, 0); } else { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING0_REG, AWIN_AHB_GATING0_USB0, 0); awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_USB_CLK_REG, AWIN_USB_CLK_USBPHY_ENABLE|AWIN_USB_CLK_PHY0_ENABLE, 0); awin_reg_set_clear(aio->aio_core_bst, aio->aio_core_bsh, AWIN_SRAM_OFFSET + AWIN_SRAM_CTL1_REG, __SHIFTIN(AWIN_SRAM_CTL1_SRAMD_MAP_USB0, AWIN_SRAM_CTL1_SRAMD_MAP), 0); } sc->sc_motg.sc_dev = self; sc->sc_motg.sc_bus.dmatag = aio->aio_dmat; sc->sc_motg.sc_iot = aio->aio_core_bst; bus_space_subregion(sc->sc_motg.sc_iot, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &sc->sc_motg.sc_ioh); sc->sc_motg.sc_size = loc->loc_size; sc->sc_motg.sc_intr_poll = awin_otg_poll; sc->sc_motg.sc_intr_poll_arg = sc; sc->sc_motg.sc_mode = MOTG_MODE_HOST; sc->sc_motg.sc_ep_max = 5; sc->sc_motg.sc_ep_fifosize = 512; sc->sc_ih = intr_establish(loc->loc_intr, IPL_USB, IST_LEVEL, awin_otg_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt %d\n", loc->loc_intr); return; } device_printf(self, "interrupting at irq %d\n", loc->loc_intr); awin_otg_init(sc); motg_init(&sc->sc_motg); }
static void awin_ahci_enable(bus_space_tag_t bst, bus_space_handle_t bsh) { /* * SATA needs PLL6 to be a 100MHz clock. */ awin_pll6_enable(); /* * Make sure it's enabled for the AHB. */ awin_reg_set_clear(bst, bsh, AWIN_AHB_GATING0_REG, AWIN_AHB_GATING0_SATA, 0); delay(1000); /* * Now turn it on (forcing it to use PLL6). */ bus_space_write_4(bst, bsh, AWIN_SATA_CLK_REG, AWIN_CLK_ENABLE); }
static void awin_hdmi_attach(device_t parent, device_t self, void *aux) { struct awin_hdmi_softc *sc = device_private(self); struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; prop_dictionary_t cfg = device_properties(self); uint32_t ver, clk; sc->sc_dev = self; sc->sc_bst = aio->aio_core_bst; bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &sc->sc_bsh); #if AWIN_HDMI_PLL == 3 awin_pll3_enable(); #elif AWIN_HDMI_PLL == 7 awin_pll7_enable(); #else #error AWIN_HDMI_PLL must be 3 or 7 #endif if (awin_chip_id() == AWIN_CHIP_ID_A31) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_A31_AHB_RESET1_REG, AWIN_A31_AHB_RESET1_HDMI_RST, 0); } #if AWIN_HDMI_PLL == 3 clk = __SHIFTIN(AWIN_HDMI_CLK_SRC_SEL_PLL3, AWIN_HDMI_CLK_SRC_SEL); #else clk = __SHIFTIN(AWIN_HDMI_CLK_SRC_SEL_PLL7, AWIN_HDMI_CLK_SRC_SEL); #endif clk |= AWIN_CLK_ENABLE; if (awin_chip_id() == AWIN_CHIP_ID_A31) { clk |= AWIN_A31_HDMI_CLK_DDC_GATING; } awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_HDMI_CLK_REG, clk, AWIN_HDMI_CLK_SRC_SEL); awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING1_REG, AWIN_AHB_GATING1_HDMI, 0); ver = HDMI_READ(sc, AWIN_HDMI_VERSION_ID_REG); const int vmaj = __SHIFTOUT(ver, AWIN_HDMI_VERSION_ID_H); const int vmin = __SHIFTOUT(ver, AWIN_HDMI_VERSION_ID_L); aprint_naive("\n"); aprint_normal(": HDMI %d.%d\n", vmaj, vmin); sc->sc_ver = ver; sc->sc_i2c_blklen = 16; const char *display_mode = NULL; prop_dictionary_get_cstring_nocopy(cfg, "display-mode", &display_mode); if (display_mode) { if (strcasecmp(display_mode, "hdmi") == 0) sc->sc_display_mode = DISPLAY_MODE_HDMI; else if (strcasecmp(display_mode, "dvi") == 0) sc->sc_display_mode = DISPLAY_MODE_DVI; } #if 0 sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL, awin_hdmi_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt %d\n", loc->loc_intr); return; } aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr); #endif awin_hdmi_i2c_init(sc); awin_hdmi_enable(sc); delay(50000); awin_hdmi_hpd(sc); kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, awin_hdmi_thread, sc, &sc->sc_thread, "%s", device_xname(sc->sc_dev)); }
static void awin_ahci_phy_init(struct awin_ahci_softc *asc) { bus_space_tag_t bst = asc->asc_sc.sc_ahcit; bus_space_handle_t bsh = asc->asc_sc.sc_ahcih; u_int timeout; uint32_t v; /* * This is dark magic. */ delay(5000); bus_space_write_4(bst, bsh, AWIN_AHCI_RWCR_REG, 0); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS1R_REG, __BIT(19), 0); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS0R_REG, __BIT(26)|__BIT(24)|__BIT(23)|__BIT(18), __BIT(25)); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS1R_REG, __BIT(17)|__BIT(10)|__BIT(9)|__BIT(7), __BIT(16)|__BIT(12)|__BIT(11)|__BIT(8)|__BIT(6)); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS1R_REG, __BIT(28)|__BIT(15), 0); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS1R_REG, 0, __BIT(19)); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS0R_REG, __BIT(21)|__BIT(20), __BIT(22)); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS2R_REG, __BIT(9)|__BIT(8)|__BIT(5), __BIT(7)|__BIT(6)); delay(10); awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS0R_REG, __BIT(19), 0); timeout = 1000; do { delay(1); v = bus_space_read_4(bst, bsh, AWIN_AHCI_PHYCS0R_REG); } while (--timeout && __SHIFTOUT(v, __BITS(30,28)) != 2); if (!timeout) { aprint_error_dev( asc->asc_sc.sc_atac.atac_dev, "SATA PHY power failed (%#x)\n", v); } else { awin_reg_set_clear(bst, bsh, AWIN_AHCI_PHYCS2R_REG, __BIT(24), 0); timeout = 1000; do { delay(10); v = bus_space_read_4(bst, bsh, AWIN_AHCI_PHYCS2R_REG); } while (--timeout && (v & __BIT(24))); if (!timeout) { aprint_error_dev( asc->asc_sc.sc_atac.atac_dev, "SATA PHY calibration failed (%#x)\n", v); } } delay(10); bus_space_write_4(bst, bsh, AWIN_AHCI_RWCR_REG, 7); }
static void awin_tcon_set_pll(struct awin_tcon_softc *sc, int dclk, int min_div) { int n = 0, m = 0, n2 = 0, m2 = 0; bool dbl = false; awin_tcon_calc_pll(3000, dclk, min_div, &m, &n); awin_tcon_calc_pll(6000, dclk, min_div, &m2, &n2); int f_single = m ? (n * 3000) / m : 0; int f_double = m2 ? (n2 * 6000) / m2 : 0; if (f_double > f_single) { dbl = true; n = n2; m = m2; } if (n == 0 || m == 0) { device_printf(sc->sc_dev, "couldn't set pll to %d Hz\n", dclk * 1000); sc->sc_clk_div = 0; return; } #ifdef AWIN_TCON_DEBUG device_printf(sc->sc_dev, "ch%d pll%d n=%d m=%d dbl=%c freq=%d\n", (sc->sc_output_type == OUTPUT_HDMI) ? 1 : 0, sc->sc_clk_pll, n, m, dbl ? 'Y' : 'N', n * 3000000); #endif switch(sc->sc_clk_pll) { case 3: awin_pll3_set_rate(n * 3000000); if ((sc->sc_output_type == OUTPUT_HDMI) || (sc->sc_output_type == OUTPUT_VGA)) { awin_reg_set_clear(sc->sc_bst, sc->sc_ch1clk_bsh, 0, AWIN_CLK_OUT_ENABLE | AWIN_LCDx_CH1_SCLK1_GATING | __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3_2X : AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3, AWIN_LCDx_CHx_CLK_SRC_SEL) | __SHIFTIN(m - 1, AWIN_LCDx_CH1_CLK_DIV_RATIO_M), AWIN_LCDx_CH1_CLK_DIV_RATIO_M | AWIN_LCDx_CHx_CLK_SRC_SEL | AWIN_LCDx_CH1_SCLK1_SRC_SEL); } else { awin_reg_set_clear(sc->sc_bst, sc->sc_ch0clk_bsh, 0, AWIN_CLK_OUT_ENABLE | AWIN_LCDx_CH0_CLK_LCDx_RST | __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3_2X : AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3, AWIN_LCDx_CHx_CLK_SRC_SEL), AWIN_LCDx_CHx_CLK_SRC_SEL); awin_reg_set_clear(sc->sc_bst, sc->sc_ch1clk_bsh, 0, AWIN_CLK_OUT_ENABLE | AWIN_LCDx_CH1_SCLK1_GATING | __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3_2X : AWIN_LCDx_CHx_CLK_SRC_SEL_PLL3, AWIN_LCDx_CHx_CLK_SRC_SEL) | __SHIFTIN(10, AWIN_LCDx_CH1_CLK_DIV_RATIO_M), AWIN_LCDx_CH1_CLK_DIV_RATIO_M | AWIN_LCDx_CHx_CLK_SRC_SEL | AWIN_LCDx_CH1_SCLK1_SRC_SEL); } break; case 7: awin_pll7_set_rate(n * 3000000); if ((sc->sc_output_type == OUTPUT_HDMI) || (sc->sc_output_type == OUTPUT_VGA)) { awin_reg_set_clear(sc->sc_bst, sc->sc_ch1clk_bsh, 0, AWIN_CLK_OUT_ENABLE | AWIN_LCDx_CH1_SCLK1_GATING | __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7_2X : AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7, AWIN_LCDx_CHx_CLK_SRC_SEL) | __SHIFTIN(m - 1, AWIN_LCDx_CH1_CLK_DIV_RATIO_M), AWIN_LCDx_CH1_CLK_DIV_RATIO_M | AWIN_LCDx_CHx_CLK_SRC_SEL | AWIN_LCDx_CH1_SCLK1_SRC_SEL); } else { /* pll7x2 not available for lcd0ch0 */ KASSERT(dbl == false || sc->sc_port != 0); awin_reg_set_clear(sc->sc_bst, sc->sc_ch0clk_bsh, 0, AWIN_CLK_OUT_ENABLE | AWIN_LCDx_CH0_CLK_LCDx_RST | __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7_2X : AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7, AWIN_LCDx_CHx_CLK_SRC_SEL), AWIN_LCDx_CHx_CLK_SRC_SEL); awin_reg_set_clear(sc->sc_bst, sc->sc_ch1clk_bsh, 0, AWIN_CLK_OUT_ENABLE | AWIN_LCDx_CH1_SCLK1_GATING | __SHIFTIN(dbl ? AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7_2X : AWIN_LCDx_CHx_CLK_SRC_SEL_PLL7, AWIN_LCDx_CHx_CLK_SRC_SEL) | __SHIFTIN(10, AWIN_LCDx_CH1_CLK_DIV_RATIO_M), AWIN_LCDx_CH1_CLK_DIV_RATIO_M | AWIN_LCDx_CHx_CLK_SRC_SEL | AWIN_LCDx_CH1_SCLK1_SRC_SEL); } break; default: panic("awin_tcon pll"); } sc->sc_clk_div = m; sc->sc_clk_dbl = dbl; }
static void awin_tcon_attach(device_t parent, device_t self, void *aux) { struct awin_tcon_softc *sc = device_private(self); struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; prop_dictionary_t cfg = device_properties(self); const char *output; sc->sc_dev = self; sc->sc_bst = aio->aio_core_bst; sc->sc_port = loc->loc_port; bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &sc->sc_bsh); bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, AWIN_LCD0_CH0_CLK_REG + (loc->loc_port * 4), 4, &sc->sc_ch0clk_bsh); bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, AWIN_LCD0_CH1_CLK_REG + (loc->loc_port * 4), 4, &sc->sc_ch1clk_bsh); if (!tcon_mux_inited) { /* the mux register is only in LCD0 */ bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, AWIN_LCD0_OFFSET + AWIN_TCON_MUX_CTL_REG, 4, &tcon_mux_bsh); tcon_mux_inited = true; /* always enable tcon0, the mux is there */ awin_tcon_clear_reset(aio, 0); } if (prop_dictionary_get_cstring_nocopy(cfg, "output", &output)) { if (strcmp(output, "hdmi") == 0) { sc->sc_output_type = OUTPUT_HDMI; } else if (strcmp(output, "lvds") == 0) { sc->sc_output_type = OUTPUT_LVDS; } else if (strcmp(output, "vga") == 0) { sc->sc_output_type = OUTPUT_VGA; } else { panic("tcon: wrong mode %s", output); } } else { sc->sc_output_type = OUTPUT_HDMI; /* default */ } aprint_naive("\n"); aprint_normal(": LCD/TV timing controller (TCON%d)\n", loc->loc_port); switch (sc->sc_port) { case 0: awin_pll3_enable(); sc->sc_clk_pll = 3; break; case 1: awin_pll7_enable(); sc->sc_clk_pll = 7; break; default: panic("awin_tcon port\n"); } aprint_verbose_dev(self, ": using DEBE%d, pll%d\n", device_unit(self), sc->sc_clk_pll); awin_tcon_clear_reset(aio, sc->sc_port); TCON_WRITE(sc, AWIN_TCON_GCTL_REG, 0); TCON_WRITE(sc, AWIN_TCON_GINT0_REG, 0); TCON_WRITE(sc, AWIN_TCON_GINT1_REG, __SHIFTIN(0x20, AWIN_TCON_GINT1_TCON0_LINENO)); TCON_WRITE(sc, AWIN_TCON0_DCLK_REG, 0xf0000000); TCON_WRITE(sc, AWIN_TCON0_CTL_REG, 0); TCON_WRITE(sc, AWIN_TCON0_IO_TRI_REG, 0xffffffff); TCON_WRITE(sc, AWIN_TCON1_CTL_REG, 0); TCON_WRITE(sc, AWIN_TCON1_IO_TRI_REG, 0xffffffff); if (sc->sc_output_type == OUTPUT_LVDS) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_LVDS_CLK_REG, AWIN_LVDS_CLK_ENABLE, 0); awin_tcon0_set_video(sc); } }
void awinusb_attach(device_t parent, device_t self, void *aux) { struct awinusb_softc * const usbsc = device_private(self); const struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; bus_space_handle_t usb_bsh; bool has_ohci = true; awinusb_ports |= __BIT(loc->loc_port); usbsc->usbsc_bst = aio->aio_core_bst; usbsc->usbsc_dmat = aio->aio_dmat; usbsc->usbsc_number = loc->loc_port + 1; usb_bsh = awin_chip_id() == AWIN_CHIP_ID_A80 ? aio->aio_a80_usb_bsh : aio->aio_core_bsh; bus_space_subregion(usbsc->usbsc_bst, usb_bsh, loc->loc_offset + AWIN_EHCI_OFFSET, AWIN_EHCI_SIZE, &usbsc->usbsc_ehci_bsh); bus_space_subregion(usbsc->usbsc_bst, usb_bsh, loc->loc_offset + AWIN_OHCI_OFFSET, AWIN_OHCI_SIZE, &usbsc->usbsc_ohci_bsh); if (awin_chip_id() != AWIN_CHIP_ID_A80) { bus_space_subregion(usbsc->usbsc_bst, usb_bsh, AWIN_USB0_OFFSET + AWIN_USB0_PHY_CTL_REG, 4, &usbsc->usbsc_usb0_phy_csr_bsh); } if (awin_chip_id() == AWIN_CHIP_ID_A80 && loc->loc_port == 1) { has_ohci = false; } aprint_naive("\n"); aprint_normal("\n"); if (awin_chip_id() == AWIN_CHIP_ID_A31) { /* Enable USB PHY */ awin_reg_set_clear(usbsc->usbsc_bst, aio->aio_ccm_bsh, AWIN_USB_CLK_REG, awinusb_usb_clk_set_a31[loc->loc_port], 0); /* AHB gate enable */ awin_reg_set_clear(usbsc->usbsc_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING0_REG, AWIN_A31_AHB_GATING0_USB0 | awinusb_ahb_gating_a31[loc->loc_port], 0); /* Soft reset */ awin_reg_set_clear(usbsc->usbsc_bst, aio->aio_ccm_bsh, AWIN_A31_AHB_RESET0_REG, awinusb_usb_ahb_reset_a31[loc->loc_port], 0); } else if (awin_chip_id() == AWIN_CHIP_ID_A80) { /* Gate enable */ awin_reg_set_clear(usbsc->usbsc_bst, aio->aio_ccm_bsh, AWIN_A80_CCU_SCLK_BUS_CLK_GATING1_REG, AWIN_A80_CCU_SCLK_BUS_CLK_GATING1_USB_HOST, 0); /* Enable USB PHY */ awin_reg_set_clear(usbsc->usbsc_bst, usb_bsh, AWIN_A80_USBPHY_OFFSET + AWIN_A80_USBPHY_HCI_PCR_REG, awinusb_usb_pcr_a80[loc->loc_port], 0); awin_reg_set_clear(usbsc->usbsc_bst, usb_bsh, AWIN_A80_USBPHY_OFFSET + AWIN_A80_USBPHY_HCI_SCR_REG, awinusb_usb_scr_a80[loc->loc_port], 0); if (!has_ohci) { /* No OHCI for USB1, force EHCI mode */ awin_reg_set_clear(usbsc->usbsc_bst, usb_bsh, loc->loc_offset + AWIN_USB_PMU_IRQ_REG, AWIN_USB_PMU_IRQ_EHCI_HS_FORCE | AWIN_USB_PMU_IRQ_HSIC_CONNECT_DET | AWIN_USB_PMU_IRQ_HSIC, 0); } } else { /* * Access to the USB phy is off USB0 so make sure it's on. */ awin_reg_set_clear(usbsc->usbsc_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING0_REG, AWIN_AHB_GATING0_USB0 | awinusb_ahb_gating[loc->loc_port], 0); /* * Enable the USB phy for this port. */ awin_reg_set_clear(usbsc->usbsc_bst, aio->aio_ccm_bsh, AWIN_USB_CLK_REG, awinusb_usb_clk_set[loc->loc_port], 0); } /* * Allow USB DMA engine access to the DRAM. */ awin_reg_set_clear(usbsc->usbsc_bst, usb_bsh, loc->loc_offset + AWIN_USB_PMU_IRQ_REG, AWIN_USB_PMU_IRQ_AHB_INCR8 | AWIN_USB_PMU_IRQ_AHB_INCR4 | AWIN_USB_PMU_IRQ_AHB_INCRX | AWIN_USB_PMU_IRQ_ULPI_BYPASS, 0); if (awin_chip_id() == AWIN_CHIP_ID_A20) { awin_reg_set_clear(usbsc->usbsc_bst, aio->aio_core_bsh, AWIN_DRAM_OFFSET + awinusb_dram_hpcr_regs[loc->loc_port], AWIN_DRAM_HPCR_ACCESS_EN, 0); } /* initialize the USB phy */ if (awin_chip_id() != AWIN_CHIP_ID_A80) { awin_usb_phy_write(usbsc, 0x20, 0x14, 5); awin_usb_phy_write(usbsc, 0x2a, 0x03, 2); } /* * Now get the GPIO that enables the power to the port and * turn it on. */ if (awin_gpio_pin_reserve(awinusb_drvpin_names[loc->loc_port], &usbsc->usbsc_drv_pin)) { awin_gpio_pindata_write(&usbsc->usbsc_drv_pin, 1); } else { aprint_error_dev(self, "no power gpio found\n"); } if (awin_gpio_pin_reserve(awinusb_restrictpin_names[loc->loc_port], &usbsc->usbsc_restrict_pin)) { awin_gpio_pindata_write(&usbsc->usbsc_restrict_pin, 1); } else { aprint_debug_dev(self, "no restrict gpio found\n"); } /* * Disable interrupts */ #if NOHCI > 0 if (has_ohci) { bus_space_write_4(usbsc->usbsc_bst, usbsc->usbsc_ohci_bsh, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); } #endif #if NEHCI > 0 bus_size_t caplength = bus_space_read_1(usbsc->usbsc_bst, usbsc->usbsc_ehci_bsh, EHCI_CAPLENGTH); bus_space_write_4(usbsc->usbsc_bst, usbsc->usbsc_ehci_bsh, caplength + EHCI_USBINTR, 0); #endif #if NOHCI > 0 if (has_ohci) { struct awinusb_attach_args usbaa_ohci = { .usbaa_name = "ohci", .usbaa_dmat = usbsc->usbsc_dmat, .usbaa_bst = usbsc->usbsc_bst, .usbaa_bsh = usbsc->usbsc_ohci_bsh, .usbaa_ccm_bsh = aio->aio_ccm_bsh, .usbaa_size = AWIN_OHCI_SIZE, .usbaa_port = loc->loc_port, }; usbsc->usbsc_ohci_dev = config_found(self, &usbaa_ohci, NULL); } #endif #if NEHCI > 0 struct awinusb_attach_args usbaa_ehci = { .usbaa_name = "ehci", .usbaa_dmat = usbsc->usbsc_dmat, .usbaa_bst = usbsc->usbsc_bst, .usbaa_bsh = usbsc->usbsc_ehci_bsh, .usbaa_ccm_bsh = aio->aio_ccm_bsh, .usbaa_size = AWIN_EHCI_SIZE, .usbaa_port = loc->loc_port, }; config_found(self, &usbaa_ehci, NULL); #endif }
static void awin_gige_attach(device_t parent, device_t self, void *aux) { struct awin_gige_softc * const sc = device_private(self); struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; struct awin_gpio_pinset pinset; prop_dictionary_t cfg = device_properties(self); uint32_t clkreg; const char *phy_type, *pin_name; bus_space_handle_t bsh; switch (awin_chip_id()) { case AWIN_CHIP_ID_A80: bsh = aio->aio_a80_core2_bsh; pinset = awin_gige_gpio_pinset_a80; break; case AWIN_CHIP_ID_A31: bsh = aio->aio_core_bsh; pinset = awin_gige_gpio_pinset_a31; break; default: bsh = aio->aio_core_bsh; pinset = awin_gige_gpio_pinset; break; } sc->sc_core.sc_dev = self; prop_dictionary_get_uint8(cfg, "pinset-func", &pinset.pinset_func); awin_gpio_pinset_acquire(&pinset); sc->sc_core.sc_bst = aio->aio_core_bst; sc->sc_core.sc_dmat = aio->aio_dmat; bus_space_subregion(sc->sc_core.sc_bst, bsh, loc->loc_offset, loc->loc_size, &sc->sc_core.sc_bsh); aprint_naive("\n"); aprint_normal(": Gigabit Ethernet Controller\n"); awin_gige_pmu_init(self); /* * Interrupt handler */ sc->sc_ih = intr_establish(loc->loc_intr, IPL_NET, IST_LEVEL, awin_gige_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "failed to establish interrupt %d\n", loc->loc_intr); return; } aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr); if (prop_dictionary_get_cstring_nocopy(cfg, "phy-power", &pin_name)) { if (awin_gpio_pin_reserve(pin_name, &sc->sc_power_pin)) { awin_gpio_pindata_write(&sc->sc_power_pin, 1); } else { aprint_error_dev(self, "failed to reserve GPIO \"%s\"\n", pin_name); } } /* * Enable GMAC clock */ if (awin_chip_id() == AWIN_CHIP_ID_A80) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_A80_CCU_SCLK_BUS_CLK_GATING1_REG, AWIN_A80_CCU_SCLK_BUS_CLK_GATING1_GMAC, 0); } else if (awin_chip_id() == AWIN_CHIP_ID_A31) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING0_REG, AWIN_A31_AHB_GATING0_GMAC, 0); } else if (awin_chip_id() == AWIN_CHIP_ID_A20) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_AHB_GATING1_REG, AWIN_AHB_GATING1_GMAC, 0); } /* * Soft reset */ if (awin_chip_id() == AWIN_CHIP_ID_A80) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_A80_CCU_SCLK_BUS_SOFT_RST1_REG, AWIN_A80_CCU_SCLK_BUS_SOFT_RST1_GMAC, 0); } else if (awin_chip_id() == AWIN_CHIP_ID_A31) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_A31_AHB_RESET0_REG, AWIN_A31_AHB_RESET0_GMAC_RST, 0); } /* * PHY clock setup */ if (!prop_dictionary_get_cstring_nocopy(cfg, "phy-type", &phy_type)) phy_type = "rgmii"; if (strcmp(phy_type, "rgmii") == 0) { clkreg = AWIN_GMAC_CLK_PIT | AWIN_GMAC_CLK_TCS_INT_RGMII; } else if (strcmp(phy_type, "rgmii-bpi") == 0) { clkreg = AWIN_GMAC_CLK_PIT | AWIN_GMAC_CLK_TCS_INT_RGMII; /* * These magic bits seem to be necessary for RGMII at gigabit * speeds on Banana Pi. */ clkreg |= __BITS(11,10); } else if (strcmp(phy_type, "gmii") == 0) { clkreg = AWIN_GMAC_CLK_TCS_INT_RGMII; } else if (strcmp(phy_type, "mii") == 0) { clkreg = AWIN_GMAC_CLK_TCS_MII; } else { panic("unknown phy type '%s'", phy_type); } if (awin_chip_id() == AWIN_CHIP_ID_A80) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_a80_core2_bsh, AWIN_A80_SYS_CTRL_OFFSET + AWIN_A80_SYS_CTRL_EMAC_CLK_REG, clkreg, AWIN_GMAC_CLK_PIT|AWIN_GMAC_CLK_TCS); } else if (awin_chip_id() == AWIN_CHIP_ID_A31) { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_A31_GMAC_CLK_REG, clkreg, AWIN_GMAC_CLK_PIT|AWIN_GMAC_CLK_TCS); } else { awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, AWIN_GMAC_CLK_REG, clkreg, AWIN_GMAC_CLK_PIT|AWIN_GMAC_CLK_TCS); } dwc_gmac_attach(&sc->sc_core, GMAC_MII_CLK_150_250M_DIV102); }