示例#1
0
文件: awin_tve.c 项目: ryo/netbsd-src
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);
}
示例#2
0
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);
}
示例#3
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);
}
示例#5
0
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);
}
示例#7
0
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;
}
示例#8
0
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);
	}
}
示例#9
0
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
}
示例#10
0
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);
}