static void awin_tcon0_enable(struct awin_tcon_softc *sc, bool enable) { uint32_t val; /* turn on/off backlight */ if (sc->sc_lcdblk_pin_name != NULL) { awin_gpio_pindata_write(&sc->sc_lcdblk_pin, enable ? 1 : 0); } /* turn on/off LCD */ if (sc->sc_lcdpwr_pin_name != NULL) { awin_gpio_pindata_write(&sc->sc_lcdpwr_pin, enable ? 1 : 0); } /* and finally disable of enable the tcon */ KASSERT(sc->sc_output_type != OUTPUT_HDMI); awin_debe_enable(device_unit(sc->sc_dev), enable); delay(20000); if (enable) { val = TCON_READ(sc, AWIN_TCON_GCTL_REG); val |= AWIN_TCON_GCTL_EN; TCON_WRITE(sc, AWIN_TCON_GCTL_REG, val); val = TCON_READ(sc, AWIN_TCON0_CTL_REG); val |= AWIN_TCONx_CTL_EN; TCON_WRITE(sc, AWIN_TCON0_CTL_REG, val); val = TCON_READ(sc, AWIN_TCON0_LVDS_IF_REG); val |= AWIN_TCON0_LVDS_IF_EN; TCON_WRITE(sc, AWIN_TCON0_LVDS_IF_REG, val); TCON_WRITE(sc, AWIN_TCON0_IO_TRI_REG, 0); } else { TCON_WRITE(sc, AWIN_TCON0_IO_TRI_REG, 0xffffffff); val = TCON_READ(sc, AWIN_TCON0_LVDS_IF_REG); val &= ~AWIN_TCON0_LVDS_IF_EN; TCON_WRITE(sc, AWIN_TCON0_LVDS_IF_REG, val); val = TCON_READ(sc, AWIN_TCON0_CTL_REG); val &= ~AWIN_TCONx_CTL_EN; TCON_WRITE(sc, AWIN_TCON0_CTL_REG, val); val = TCON_READ(sc, AWIN_TCON_GCTL_REG); val &= ~AWIN_TCON_GCTL_EN; TCON_WRITE(sc, AWIN_TCON_GCTL_REG, val); } }
static void awin_otg_init(struct awin_otg_softc *sc) { uint32_t val; /* initialize the USB phy */ awin_otg_phy_write(sc, 0x0c, 0x01, 1); awin_otg_phy_write(sc, 0x20, 0x14, 5); awin_otg_phy_write(sc, 0x2a, 0x03, 2); if (awin_gpio_pin_reserve("usb0drv", &sc->sc_drv_pin)) { awin_gpio_pindata_write(&sc->sc_drv_pin, 1); } else { aprint_error_dev(sc->sc_motg.sc_dev, "no power gpio found\n"); } if (awin_gpio_pin_reserve("usb0restrict", &sc->sc_restrict_pin)) { awin_gpio_pindata_write(&sc->sc_restrict_pin, 1); } else { aprint_error_dev(sc->sc_motg.sc_dev, "no restrict gpio found\n"); } val = OTG_READ4(sc, AWIN_USB0_PHY_CSR_REG); val &= ~AWIN_USB0_PHY_CSR_VBUS_CHANGE_DET; val &= ~AWIN_USB0_PHY_CSR_ID_CHANGE_DET; val &= ~AWIN_USB0_PHY_CSR_DPDM_CHANGE_DET; val |= AWIN_USB0_PHY_CSR_DPDM_PULLUP_EN; val |= AWIN_USB0_PHY_CSR_ID_PULLUP_EN; val &= ~AWIN_USB0_PHY_CSR_FORCE_ID; val |= __SHIFTIN(AWIN_USB0_PHY_CSR_FORCE_ID_LOW, AWIN_USB0_PHY_CSR_FORCE_ID); val &= ~AWIN_USB0_PHY_CSR_FORCE_VBUS_VALID; val |= __SHIFTIN(AWIN_USB0_PHY_CSR_FORCE_VBUS_VALID_HIGH, AWIN_USB0_PHY_CSR_FORCE_VBUS_VALID); OTG_WRITE4(sc, AWIN_USB0_PHY_CSR_REG, val); OTG_WRITE1(sc, MUSB2_REG_AWIN_VEND0, 0); }
static void awin_ahci_attach(device_t parent, device_t self, void *aux) { struct awin_ahci_softc * const asc = device_private(self); struct ahci_softc * const sc = &asc->asc_sc; struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; awin_ahci_enable(aio->aio_core_bst, aio->aio_ccm_bsh); sc->sc_atac.atac_dev = self; sc->sc_dmat = aio->aio_dmat; sc->sc_ahcit = aio->aio_core_bst; sc->sc_ahcis = loc->loc_size; sc->sc_ahci_ports = 1; sc->sc_ahci_quirks = AHCI_QUIRK_BADPMP; sc->sc_save_init_data = true; sc->sc_channel_start = awin_ahci_channel_start; bus_space_subregion(aio->aio_core_bst, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &sc->sc_ahcih); aprint_naive(": AHCI SATA controller\n"); aprint_normal(": AHCI SATA controller\n"); /* * Bring up the PHY. */ awin_ahci_phy_init(asc); /* * If there is a GPIO to turn on power, do it now. */ const char *pin_name; prop_dictionary_t dict = device_properties(self); if (prop_dictionary_get_cstring_nocopy(dict, "power-gpio", &pin_name)) { if (awin_gpio_pin_reserve(pin_name, &asc->asc_gpio_pin)) { awin_gpio_pindata_write(&asc->asc_gpio_pin, 1); } else { aprint_error_dev(self, "failed to reserve GPIO \"%s\"\n", pin_name); } } /* * Establish the interrupt */ asc->asc_ih = intr_establish(loc->loc_intr, IPL_BIO, IST_LEVEL, ahci_intr, sc); if (asc->asc_ih == NULL) { aprint_error_dev(self, "failed to establish interrupt %d\n", loc->loc_intr); goto fail; } aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr); ahci_attach(sc); return; fail: if (asc->asc_ih) { intr_disestablish(asc->asc_ih); asc->asc_ih = NULL; } }
static void awin_tcon0_set_video(struct awin_tcon_softc *sc) { int32_t lcd_x, lcd_y, lcd_dclk_freq; int32_t lcd_hbp, lcd_ht, lcd_vbp, lcd_vt; int32_t lcd_hspw, lcd_vspw, lcd_io_cfg0; uint32_t vblk, start_delay; prop_dictionary_t cfg = device_properties(sc->sc_dev); uint32_t val; bool propb; bool dualchan = false; static struct videomode mode; if (!prop_dictionary_get_int32(cfg, "lcd_x", &lcd_x)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_x\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_y", &lcd_y)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_y\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_dclk_freq", &lcd_dclk_freq)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_dclk_freq\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_hbp", &lcd_hbp)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_hbp\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_ht", &lcd_ht)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_ht\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_vbp", &lcd_vbp)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_vbp\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_vt", &lcd_vt)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_vt\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_hspw", &lcd_hspw)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_hspw\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_vspw", &lcd_vspw)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_vspw\n"); return; } if (!prop_dictionary_get_int32(cfg, "lcd_io_cfg0", &lcd_io_cfg0)) { aprint_error_dev(sc->sc_dev, ": can't read lcd_io_cfg0\n"); return; } if (prop_dictionary_get_bool(cfg, "lvds_dual", &propb) && propb) dualchan = true; if (!awin_gpio_pinset_available(&awin_lvds0_pinset)) { aprint_error_dev(sc->sc_dev, "lvds0 pins not available\n"); return; } if (dualchan && !awin_gpio_pinset_available(&awin_lvds1_pinset)) { aprint_error_dev(sc->sc_dev, "lvds1 pins not available\n"); return; } awin_gpio_pinset_acquire(&awin_lvds0_pinset); if (dualchan) { awin_gpio_pinset_acquire(&awin_lvds1_pinset); } prop_dictionary_get_cstring_nocopy(cfg, "lcd_power_en", &sc->sc_lcdpwr_pin_name); if (sc->sc_lcdpwr_pin_name != NULL) { if (!awin_gpio_pin_reserve( sc->sc_lcdpwr_pin_name, &sc->sc_lcdpwr_pin)) { aprint_error_dev(sc->sc_dev, "failed to reserve GPIO \"%s\" for LCD power\n", sc->sc_lcdpwr_pin_name); sc->sc_lcdpwr_pin_name = NULL; } else { aprint_verbose_dev(sc->sc_dev, ": using GPIO \"%s\" for LCD power\n", sc->sc_lcdpwr_pin_name); } } prop_dictionary_get_cstring_nocopy(cfg, "lcd_bl_en", &sc->sc_lcdblk_pin_name); if (sc->sc_lcdblk_pin_name != NULL) { if (!awin_gpio_pin_reserve( sc->sc_lcdblk_pin_name, &sc->sc_lcdblk_pin)) { aprint_error_dev(sc->sc_dev, "failed to reserve GPIO \"%s\" for backlight\n", sc->sc_lcdblk_pin_name); sc->sc_lcdblk_pin_name = NULL; } else { if (sc->sc_lcdpwr_pin_name == NULL) { aprint_verbose_dev(sc->sc_dev, ": using GPIO \"%s\" for backlight\n", sc->sc_lcdblk_pin_name); } else { aprint_verbose( ", GPIO \"%s\" for backlight\n", sc->sc_lcdblk_pin_name); } } } if (sc->sc_lcdpwr_pin_name != NULL) { awin_gpio_pindata_write(&sc->sc_lcdpwr_pin, 1); } vblk = (lcd_vt / 2) - lcd_y; start_delay = (vblk >= 32) ? 30 : (vblk - 2); if (lcd_dclk_freq > 150) /* hardware limit ? */ lcd_dclk_freq = 150; awin_tcon_set_pll(sc, lcd_dclk_freq * 1000, 7); val = AWIN_TCONx_CTL_EN; val |= __SHIFTIN(start_delay, AWIN_TCONx_CTL_START_DELAY); /* * the DE selector selects the primary DEBE for this tcon: * 0 selects debe0 for tcon0 and debe1 for tcon1 */ val |= __SHIFTIN(AWIN_TCONx_CTL_SRC_SEL_DE0, AWIN_TCONx_CTL_SRC_SEL); TCON_WRITE(sc, AWIN_TCON0_CTL_REG, val); val = (lcd_x - 1) << 16 | (lcd_y - 1); TCON_WRITE(sc, AWIN_TCON0_BASIC0_REG, val); val = (lcd_ht - 1) << 16 | (lcd_hbp - 1); TCON_WRITE(sc, AWIN_TCON0_BASIC1_REG, val); val = (lcd_vt) << 16 | (lcd_vbp - 1); TCON_WRITE(sc, AWIN_TCON0_BASIC2_REG, val); val = ((lcd_hspw > 0) ? (lcd_hspw - 1) : 0) << 16; val |= ((lcd_vspw > 0) ? (lcd_vspw - 1) : 0); TCON_WRITE(sc, AWIN_TCON0_BASIC3_REG, val); val = 0; if (dualchan) val |= AWIN_TCON0_LVDS_IF_DUALCHAN; if (prop_dictionary_get_bool(cfg, "lvds_mode_jeida", &propb) && propb) val |= AWIN_TCON0_LVDS_IF_MODE_JEIDA; if (prop_dictionary_get_bool(cfg, "lvds_18bits", &propb) && propb) val |= AWIN_TCON0_LVDS_IF_18BITS; TCON_WRITE(sc, AWIN_TCON0_LVDS_IF_REG, val); TCON_WRITE(sc, AWIN_TCON0_IO_POL_REG, lcd_io_cfg0); TCON_WRITE(sc, AWIN_TCON0_IO_TRI_REG, 0); TCON_WRITE(sc, AWIN_TCON_GINT1_REG, __SHIFTIN(start_delay + 2, AWIN_TCON_GINT1_TCON0_LINENO)); val = 0xf0000000; val &= ~AWIN_TCON0_DCLK_DIV; val |= __SHIFTIN(sc->sc_clk_div, AWIN_TCON0_DCLK_DIV); TCON_WRITE(sc, AWIN_TCON0_DCLK_REG, val); mode.dot_clock = lcd_dclk_freq; mode.hdisplay = lcd_x; mode.hsync_start = lcd_ht - lcd_hbp; mode.hsync_end = lcd_hspw + mode.hsync_start; mode.htotal = lcd_ht; mode.vdisplay = lcd_y; mode.vsync_start = lcd_vt - lcd_vbp; mode.vsync_end = lcd_vspw + mode.vsync_start; mode.vtotal = lcd_vt; mode.flags = 0; mode.name = NULL; awin_debe_set_videomode(sc->sc_debe_unit, &mode); /* and finally, enable it */ awin_debe_enable(sc->sc_debe_unit, true); delay(20000); val = TCON_READ(sc, AWIN_TCON_GCTL_REG); val |= AWIN_TCON_GCTL_EN; TCON_WRITE(sc, AWIN_TCON_GCTL_REG, val); delay(20000); val = TCON_READ(sc, AWIN_TCON0_LVDS_IF_REG); val |= AWIN_TCON0_LVDS_IF_EN; TCON_WRITE(sc, AWIN_TCON0_LVDS_IF_REG, val); /* XXX * magic values here from linux. these are not documented * in the A20 user manual, and other Allwiner LVDS-capable SoC * documentation don't make sense with these values */ val = TCON_READ(sc, AWIN_TCON_LVDS_ANA0); val |= 0x3F310000; TCON_WRITE(sc, AWIN_TCON_LVDS_ANA0, val); val = TCON_READ(sc, AWIN_TCON_LVDS_ANA0); val |= 1 << 22; TCON_WRITE(sc, AWIN_TCON_LVDS_ANA0, val); delay(2); val = TCON_READ(sc, AWIN_TCON_LVDS_ANA1); val |= (0x1f << 26 | 0x1f << 10); TCON_WRITE(sc, AWIN_TCON_LVDS_ANA1, val); delay(2); val = TCON_READ(sc, AWIN_TCON_LVDS_ANA1); val |= (0x1f << 16 | 0x1f << 0); TCON_WRITE(sc, AWIN_TCON_LVDS_ANA1, val); val = TCON_READ(sc, AWIN_TCON_LVDS_ANA0); val |= 1 << 22; TCON_WRITE(sc, AWIN_TCON_LVDS_ANA0, val); if (sc->sc_lcdblk_pin_name != NULL) { awin_gpio_pindata_write(&sc->sc_lcdblk_pin, 1); } }
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); }