예제 #1
0
파일: awin_tcon.c 프로젝트: ryo/netbsd-src
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);
	}
}
예제 #2
0
static void
awin_hdmi_read_edid(struct awin_hdmi_softc *sc)
{
	const struct videomode *mode;
	char edid[128];
	struct edid_info ei;
	int retry = 4;
	u_int display_mode;

	memset(edid, 0, sizeof(edid));
	memset(&ei, 0, sizeof(ei));

	while (--retry > 0) {
		if (!awin_hdmi_read_edid_block(sc, edid, 0))
			break;
	}
	if (retry == 0) {
		device_printf(sc->sc_dev, "failed to read EDID\n");
	} else {
		if (edid_parse(edid, &ei) != 0) {
			device_printf(sc->sc_dev, "failed to parse EDID\n");
		}
#ifdef AWIN_HDMI_DEBUG
		else {
			edid_print(&ei);
		}
#endif
	}

	if (sc->sc_display_mode == DISPLAY_MODE_AUTO)
		display_mode = awin_hdmi_get_display_mode(sc, &ei);
	else
		display_mode = sc->sc_display_mode;

	const char *forced = sc->sc_display_mode == DISPLAY_MODE_AUTO ?
	    "auto-detected" : "forced";
	device_printf(sc->sc_dev, "%s mode (%s)\n",
	    display_mode == DISPLAY_MODE_HDMI ? "HDMI" : "DVI", forced);

	strlcpy(sc->sc_display_vendor, ei.edid_vendorname,
	    sizeof(sc->sc_display_vendor));
	strlcpy(sc->sc_display_product, ei.edid_productname,
	    sizeof(sc->sc_display_product));
	sc->sc_current_display_mode = display_mode;

	mode = ei.edid_preferred_mode;
	if (mode == NULL)
		mode = pick_mode_by_ref(640, 480, 60);

	if (mode != NULL) {
		awin_hdmi_video_enable(sc, false);
		awin_tcon_enable(false);
		delay(20000);

		awin_debe_set_videomode(mode);
		awin_tcon_set_videomode(mode);
		awin_hdmi_set_videomode(sc, mode, display_mode);
		awin_hdmi_set_audiomode(sc, mode, display_mode);
		awin_debe_enable(true);
		delay(20000);
		awin_tcon_enable(true);
		delay(20000);
		awin_hdmi_video_enable(sc, true);
	}
}
예제 #3
0
파일: awin_tcon.c 프로젝트: ryo/netbsd-src
void
awin_tcon1_enable(int unit, bool enable)
{
	struct awin_tcon_softc *sc;
	device_t dev;
	uint32_t val;

	dev = device_find_by_driver_unit("awintcon", unit);
	if (dev == NULL) {
		printf("TCON%d: no driver found\n", unit);
		return;
	}
	sc = device_private(dev);
	KASSERT((sc->sc_output_type == OUTPUT_HDMI) || 
		    (sc->sc_output_type == OUTPUT_VGA));

	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_TCON1_CTL_REG);
		val |= AWIN_TCONx_CTL_EN;
		TCON_WRITE(sc, AWIN_TCON1_CTL_REG, val);
		if (sc->sc_output_type == OUTPUT_VGA) {
			TCON_WRITE(sc, AWIN_TCON1_IO_TRI_REG, 0x0cffffff);
		} else
			TCON_WRITE(sc, AWIN_TCON1_IO_TRI_REG, 0);
	} else {
		TCON_WRITE(sc, AWIN_TCON1_IO_TRI_REG, 0xffffffff);
		val = TCON_READ(sc, AWIN_TCON1_CTL_REG);
		val &= ~AWIN_TCONx_CTL_EN;
		TCON_WRITE(sc, AWIN_TCON1_CTL_REG, val);
		val = TCON_READ(sc, AWIN_TCON_GCTL_REG);
		val &= ~AWIN_TCON_GCTL_EN;
		TCON_WRITE(sc, AWIN_TCON_GCTL_REG, val);
	}

	KASSERT(tcon_mux_inited);
	val = bus_space_read_4(sc->sc_bst, tcon_mux_bsh, 0);
#ifdef AWIN_TCON_DEBUG
	printf("awin_tcon1_enable(%d) %d val 0x%x", unit, enable, val);
#endif
	val &= ~ AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC;
	if (unit == 0) {
		val |= __SHIFTIN(AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC_LCDC0_TCON1,
		    AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC);
	} else if (unit == 1) {
		val |= __SHIFTIN(AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC_LCDC1_TCON1,
		    AWIN_TCON_MUX_CTL_HDMI_OUTPUT_SRC);
	} 
#ifdef AWIN_TCON_DEBUG
	printf(" -> 0x%x", val);
#endif
	bus_space_write_4(sc->sc_bst, tcon_mux_bsh, 0, val);
#ifdef AWIN_TCON_DEBUG
	printf(": 0x%" PRIxBSH " 0x%" PRIxBSH " 0x%x 0x%x\n", sc->sc_bsh,
	    tcon_mux_bsh, bus_space_read_4(sc->sc_bst, tcon_mux_bsh, 0),
	    TCON_READ(sc, AWIN_TCON_MUX_CTL_REG));
#endif
}
예제 #4
0
파일: awin_tcon.c 프로젝트: ryo/netbsd-src
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);
	}
}