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 int awin_gige_match(device_t parent, cfdata_t cf, void *aux) { struct awinio_attach_args * const aio = aux; #ifdef DIAGNOSTIC const struct awin_locators * const loc = &aio->aio_loc; #endif if (cf->cf_flags & 1) return 0; KASSERT(!strcmp(cf->cf_name, loc->loc_name)); KASSERT(cf->cf_loc[AWINIOCF_PORT] == AWINIOCF_PORT_DEFAULT || cf->cf_loc[AWINIOCF_PORT] == loc->loc_port); if (!awin_gpio_pinset_available(&awin_gige_pinset)) return 0; return 1; }
static int awin_gige_match(device_t parent, cfdata_t cf, void *aux) { const struct awin_gpio_pinset *pinset = awin_chip_id() == AWIN_CHIP_ID_A31 ? &awin_gige_gpio_pinset_a31 : &awin_gige_gpio_pinset; struct awinio_attach_args * const aio __diagused = aux; const struct awin_locators * const loc __diagused = &aio->aio_loc; if (cf->cf_flags & 1) return 0; KASSERT(!strcmp(cf->cf_name, loc->loc_name)); 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; return 1; }
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); } }