static int awin_com_match(device_t parent, cfdata_t cf, void *aux) { struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; bus_space_tag_t iot = aio->aio_core_a4x_bst; bus_space_handle_t bsh; const struct awin_gpio_pinset *pinset; if (awin_chip_id() == AWIN_CHIP_ID_A31) { pinset = awin_com_pinsets_a31; } else if (awin_chip_id() == AWIN_CHIP_ID_A80) { pinset = awin_com_pinsets_a80; } else { pinset = loc->loc_port + ((cf->cf_flags & 1) ? awin_com_alt_pinsets : awin_com_pinsets); } KASSERT(!strcmp(cf->cf_name, loc->loc_name)); #if defined(ALLWINNER_A80) KASSERT(loc->loc_offset >= AWIN_A80_UART0_OFFSET); KASSERT(loc->loc_offset <= AWIN_A80_UART5_OFFSET); #else KASSERT(loc->loc_offset >= AWIN_UART0_OFFSET); KASSERT(loc->loc_offset <= AWIN_UART7_OFFSET); #endif KASSERT((loc->loc_offset & 0x3ff) == 0); KASSERT((awin_com_ports & __BIT(loc->loc_port)) == 0); KASSERT(cf->cf_loc[AWINIOCF_PORT] == AWINIOCF_PORT_DEFAULT || cf->cf_loc[AWINIOCF_PORT] == loc->loc_port); if (!awin_gpio_pinset_available(pinset)) return 0; if (com_is_console(iot, AWIN_CORE_PBASE + loc->loc_offset, NULL)) return 1; awin_gpio_pinset_acquire(pinset); bus_space_subregion(iot, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &bsh); const int rv = comprobe1(iot, bsh); awin_gpio_pinset_release(pinset); return rv; }
static void awin_com_attach(device_t parent, device_t self, void *aux) { cfdata_t cf = device_cfdata(self); struct awin_com_softc * const asc = device_private(self); struct com_softc * const sc = &asc->asc_sc; struct awinio_attach_args * const aio = aux; const struct awin_locators * const loc = &aio->aio_loc; bus_space_tag_t iot = aio->aio_core_a4x_bst; const bus_addr_t iobase = AWIN_CORE_PBASE + loc->loc_offset; const struct awin_gpio_pinset *pinset; bus_space_handle_t ioh; if (awin_chip_id() == AWIN_CHIP_ID_A31) { pinset = awin_com_pinsets_a31; } else if (awin_chip_id() == AWIN_CHIP_ID_A80) { pinset = awin_com_pinsets_a80; } else { pinset = loc->loc_port + ((cf->cf_flags & 1) ? awin_com_alt_pinsets : awin_com_pinsets); } awin_com_ports |= __BIT(loc->loc_port); awin_gpio_pinset_acquire(pinset); sc->sc_dev = self; sc->sc_frequency = AWIN_UART_FREQ; sc->sc_type = COM_TYPE_NORMAL; if (com_is_console(iot, iobase, &ioh) == 0 && bus_space_subregion(iot, aio->aio_core_bsh, loc->loc_offset / 4, loc->loc_size, &ioh)) { panic(": can't map registers"); } COM_INIT_REGS(sc->sc_regs, iot, ioh, iobase); com_attach_subr(sc); aprint_naive("\n"); KASSERT(loc->loc_intr != AWINIO_INTR_DEFAULT); asc->asc_ih = intr_establish(loc->loc_intr, IPL_SERIAL, IST_EDGE | IST_MPSAFE, comintr, sc); if (asc->asc_ih == NULL) panic("%s: failed to establish interrupt %d", device_xname(self), loc->loc_intr); }
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; sc->sc_dev = self; awin_gpio_pinset_acquire(&awin_gige_pinset); sc->sc_bst = aio->aio_core_bst; sc->sc_dmat = aio->aio_dmat; bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, loc->loc_offset, loc->loc_size, &sc->sc_bsh); aprint_naive("\n"); aprint_normal(": Gigabit Ethernet Controller\n"); }
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); } }
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); }