Esempio n. 1
0
static void
fdt_fixup_busfreq(phandle_t root)
{
	phandle_t sb, cpus, child;
	pcell_t freq;

	/*
	 * Do a strict check so as to skip non-SOC nodes, which also claim
	 * simple-bus compatibility such as eLBC etc.
	 */
	if ((sb = fdt_find_compatible(root, "simple-bus", 1)) == 0)
		return;

	/*
	 * This fixup uses /cpus/ bus-frequency prop value to set simple-bus
	 * bus-frequency property.
	 */
	if ((cpus = OF_finddevice("/cpus")) == 0)
		return;

	if ((child = OF_child(cpus)) == 0)
		return;

	if (OF_getprop(child, "bus-frequency", (void *)&freq,
	    sizeof(freq)) <= 0)
		return;

	OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq));
}
Esempio n. 2
0
int
fdt_immr_addr(vm_offset_t immr_va)
{
	phandle_t node;
	u_long base, size;
	int r;

	/*
	 * Try to access the SOC node directly i.e. through /aliases/.
	 */
	if ((node = OF_finddevice("soc")) != 0)
		if (fdt_is_compatible(node, "simple-bus"))
			goto moveon;
	/*
	 * Find the node the long way.
	 */
	if ((node = OF_finddevice("/")) == 0)
		return (ENXIO);

	if ((node = fdt_find_compatible(node, "simple-bus", 0)) == 0)
		return (ENXIO);

moveon:
	if ((r = fdt_get_range(node, 0, &base, &size)) == 0) {
		fdt_immr_pa = base;
		fdt_immr_va = immr_va;
		fdt_immr_size = size;
	}

	return (r);
}
Esempio n. 3
0
static phandle_t
find_node_for_device(const char *device, const char **compatible)
{
	int i;
	phandle_t node;

	/*
	 * Try to access the node directly i.e. through /aliases/.
	 */

	if ((node = OF_finddevice(device)) != 0)
		for (i = 0; compatible[i]; i++)
			if (fdt_is_compatible_strict(node, compatible[i]))
				return node;

	/*
	 * Find the node the long way.
	 */

	for (i = 0; compatible[i]; i++) {
		if ((node = OF_finddevice("/soc")) == 0)
			return (0);

		if ((node = fdt_find_compatible(node, compatible[i], 1)) != 0)
			return node;
	}

	return (0);
}
Esempio n. 4
0
static void
gpioled_identify(driver_t *driver, device_t bus)
{
	phandle_t child, leds, root;

	root = OF_finddevice("/");
	if (root == 0)
		return;
	leds = fdt_find_compatible(root, "gpio-leds", 1);
	if (leds == 0)
		return;

	/* Traverse the 'gpio-leds' node and add its children. */
	for (child = OF_child(leds); child != 0; child = OF_peer(child))
		if (ofw_gpiobus_add_fdt_child(bus, child) == NULL)
			continue;
}
Esempio n. 5
0
static int
am335x_lcd_attach(device_t dev)
{
	struct am335x_lcd_softc *sc;
	int rid;
	int div;
	struct panel_info panel;
	uint32_t reg, timing0, timing1, timing2;
	struct sysctl_ctx_list *ctx;
	struct sysctl_oid *tree;
	uint32_t burst_log;
	int err;
	size_t dma_size;
	uint32_t hbp, hfp, hsw;
	uint32_t vbp, vfp, vsw;
	uint32_t width, height;
	phandle_t root, panel_node;

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	root = OF_finddevice("/");
	if (root == 0) {
		device_printf(dev, "failed to get FDT root node\n");
		return (ENXIO);
	}

	panel_node = fdt_find_compatible(root, "ti,tilcdc,panel", 1);
	if (panel_node == 0) {
		device_printf(dev, "failed to find compatible panel in FDT blob\n");
		return (ENXIO);
	}

	if (am335x_read_panel_info(dev, panel_node, &panel)) {
		device_printf(dev, "failed to read panel info\n");
		return (ENXIO);
	}

	if (am335x_read_timing(dev, panel_node, &panel)) {
		device_printf(dev, "failed to read timings\n");
		return (ENXIO);
	}

	int ref_freq = 0;
	ti_prcm_clk_enable(LCDC_CLK);
	if (ti_prcm_clk_get_source_freq(LCDC_CLK, &ref_freq)) {
		device_printf(dev, "Can't get reference frequency\n");
		return (ENXIO);
	}

	rid = 0;
	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (!sc->sc_mem_res) {
		device_printf(dev, "cannot allocate memory window\n");
		return (ENXIO);
	}

	rid = 0;
	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
	    RF_ACTIVE);
	if (!sc->sc_irq_res) {
		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
		device_printf(dev, "cannot allocate interrupt\n");
		return (ENXIO);
	}

	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
			NULL, am335x_lcd_intr, sc,
			&sc->sc_intr_hl) != 0) {
		bus_release_resource(dev, SYS_RES_IRQ, rid,
		    sc->sc_irq_res);
		bus_release_resource(dev, SYS_RES_MEMORY, rid,
		    sc->sc_mem_res);
		device_printf(dev, "Unable to setup the irq handler.\n");
		return (ENXIO);
	}

	LCD_LOCK_INIT(sc);

	/* Panle initialization */
	dma_size = round_page(panel.panel_width*panel.panel_height*panel.bpp/8);

	/*
	 * Now allocate framebuffer memory
	 */
	err = bus_dma_tag_create(
	    bus_get_dma_tag(dev),
	    4, 0,		/* alignment, boundary */
	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
	    BUS_SPACE_MAXADDR,		/* highaddr */
	    NULL, NULL,			/* filter, filterarg */
	    dma_size, 1,			/* maxsize, nsegments */
	    dma_size, 0,			/* maxsegsize, flags */
	    NULL, NULL,			/* lockfunc, lockarg */
	    &sc->sc_dma_tag);
	if (err)
		goto fail;

	err = bus_dmamem_alloc(sc->sc_dma_tag, (void **)&sc->sc_fb_base,
	    BUS_DMA_COHERENT, &sc->sc_dma_map);

	if (err) {
		device_printf(dev, "cannot allocate framebuffer\n");
		goto fail;
	}

	err = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, sc->sc_fb_base,
	    dma_size, am335x_fb_dmamap_cb, &sc->sc_fb_phys, BUS_DMA_NOWAIT);

	if (err) {
		device_printf(dev, "cannot load DMA map\n");
		goto fail;
	}

	/* Make sure it's blank */
	memset(sc->sc_fb_base, 0x00, dma_size);

	/* Calculate actual FB Size */
	sc->sc_fb_size = panel.panel_width*panel.panel_height*panel.bpp/8;

	/* Only raster mode is supported */
	reg = CTRL_RASTER_MODE;
	div = am335x_lcd_calc_divisor(ref_freq, panel.panel_pxl_clk);
	reg |= (div << CTRL_DIV_SHIFT);
	LCD_WRITE4(sc, LCD_CTRL, reg); 

	/* Set timing */
	timing0 = timing1 = timing2 = 0;

	hbp = panel.panel_hbp - 1;
	hfp = panel.panel_hfp - 1;
	hsw = panel.panel_hsw - 1;

	vbp = panel.panel_vbp;
	vfp = panel.panel_vfp;
	vsw = panel.panel_vsw - 1;

	height = panel.panel_height - 1;
	width = panel.panel_width - 1;

	/* Horizontal back porch */
	timing0 |= (hbp & 0xff) << RASTER_TIMING_0_HBP_SHIFT;
	timing2 |= ((hbp >> 8) & 3) << RASTER_TIMING_2_HBPHI_SHIFT;
	/* Horizontal front porch */
	timing0 |= (hfp & 0xff) << RASTER_TIMING_0_HFP_SHIFT;
	timing2 |= ((hfp >> 8) & 3) << RASTER_TIMING_2_HFPHI_SHIFT;
	/* Horizontal sync width */
	timing0 |= (hsw & 0x3f) << RASTER_TIMING_0_HSW_SHIFT;
	timing2 |= ((hsw >> 6) & 0xf) << RASTER_TIMING_2_HSWHI_SHIFT;

	/* Vertical back porch, front porch, sync width */
	timing1 |= (vbp & 0xff) << RASTER_TIMING_1_VBP_SHIFT;
	timing1 |= (vfp & 0xff) << RASTER_TIMING_1_VFP_SHIFT;
	timing1 |= (vsw & 0x3f) << RASTER_TIMING_1_VSW_SHIFT;

	/* Pixels per line */
	timing0 |= ((width >> 10) & 1)
	    << RASTER_TIMING_0_PPLMSB_SHIFT;
	timing0 |= ((width >> 4) & 0x3f)
	    << RASTER_TIMING_0_PPLLSB_SHIFT;

	/* Lines per panel */
	timing1 |= (height & 0x3ff) 
	    << RASTER_TIMING_1_LPP_SHIFT;
	timing2 |= ((height >> 10 ) & 1) 
	    << RASTER_TIMING_2_LPP_B10_SHIFT;

	/* clock signal settings */
	if (panel.sync_ctrl)
		timing2 |= RASTER_TIMING_2_PHSVS;
	if (panel.sync_edge)
		timing2 |= RASTER_TIMING_2_PHSVS_RISE;
	else
		timing2 |= RASTER_TIMING_2_PHSVS_FALL;
	if (panel.hsync_active == 0)
		timing2 |= RASTER_TIMING_2_IHS;
	if (panel.vsync_active == 0)
		timing2 |= RASTER_TIMING_2_IVS;
	if (panel.pixelclk_active == 0)
		timing2 |= RASTER_TIMING_2_IPC;

	/* AC bias */
	timing2 |= (panel.ac_bias << RASTER_TIMING_2_ACB_SHIFT);
	timing2 |= (panel.ac_bias_intrpt << RASTER_TIMING_2_ACBI_SHIFT);

	LCD_WRITE4(sc, LCD_RASTER_TIMING_0, timing0); 
	LCD_WRITE4(sc, LCD_RASTER_TIMING_1, timing1); 
	LCD_WRITE4(sc, LCD_RASTER_TIMING_2, timing2); 

	/* DMA settings */
	reg = LCDDMA_CTRL_FB0_FB1;
	/* Find power of 2 for current burst size */
	switch (panel.dma_burst_sz) {
	case 1:
		burst_log = 0;
		break;
	case 2:
		burst_log = 1;
		break;
	case 4:
		burst_log = 2;
		break;
	case 8:
		burst_log = 3;
		break;
	case 16:
	default:
		burst_log = 4;
		break;
	}
	reg |= (burst_log << LCDDMA_CTRL_BURST_SIZE_SHIFT);
	/* XXX: FIFO TH */
	reg |= (0 << LCDDMA_CTRL_TH_FIFO_RDY_SHIFT);
	LCD_WRITE4(sc, LCD_LCDDMA_CTRL, reg); 

	LCD_WRITE4(sc, LCD_LCDDMA_FB0_BASE, sc->sc_fb_phys); 
	LCD_WRITE4(sc, LCD_LCDDMA_FB0_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); 
	LCD_WRITE4(sc, LCD_LCDDMA_FB1_BASE, sc->sc_fb_phys); 
	LCD_WRITE4(sc, LCD_LCDDMA_FB1_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); 

	/* Enable LCD */
	reg = RASTER_CTRL_LCDTFT;
	reg |= (panel.fdd << RASTER_CTRL_REQDLY_SHIFT);
	reg |= (PALETTE_DATA_ONLY << RASTER_CTRL_PALMODE_SHIFT);
	if (panel.bpp >= 24)
		reg |= RASTER_CTRL_TFT24;
	if (panel.bpp == 32)
		reg |= RASTER_CTRL_TFT24_UNPACKED;
	LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 

	LCD_WRITE4(sc, LCD_CLKC_ENABLE,
	    CLKC_ENABLE_DMA | CLKC_ENABLE_LDID | CLKC_ENABLE_CORE);

	LCD_WRITE4(sc, LCD_CLKC_RESET, CLKC_RESET_MAIN);
	DELAY(100);
	LCD_WRITE4(sc, LCD_CLKC_RESET, 0);

	reg = IRQ_EOF1 | IRQ_EOF0 | IRQ_FUF | IRQ_PL |
	    IRQ_ACB | IRQ_SYNC_LOST |  IRQ_RASTER_DONE |
	    IRQ_FRAME_DONE;
	LCD_WRITE4(sc, LCD_IRQENABLE_SET, reg);

	reg = LCD_READ4(sc, LCD_RASTER_CTRL);
 	reg |= RASTER_CTRL_LCDEN;
	LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 

	LCD_WRITE4(sc, LCD_SYSCONFIG,
	    SYSCONFIG_STANDBY_SMART | SYSCONFIG_IDLE_SMART); 

	/* Init backlight interface */
	ctx = device_get_sysctl_ctx(sc->sc_dev);
	tree = device_get_sysctl_tree(sc->sc_dev);
	sc->sc_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
	    "backlight", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
	    am335x_lcd_sysctl_backlight, "I", "LCD backlight");
	sc->sc_backlight = 0;
	/* Check if eCAS interface is available at this point */
	if (am335x_pwm_config_ecap(PWM_UNIT,
	    PWM_PERIOD, PWM_PERIOD) == 0)
		sc->sc_backlight = 100;

	sc->sc_fb_info.fb_name = device_get_nameunit(sc->sc_dev);
	sc->sc_fb_info.fb_vbase = (intptr_t)sc->sc_fb_base;
	sc->sc_fb_info.fb_pbase = sc->sc_fb_phys;
	sc->sc_fb_info.fb_size = sc->sc_fb_size;
	sc->sc_fb_info.fb_bpp = sc->sc_fb_info.fb_depth = panel.bpp;
	sc->sc_fb_info.fb_stride = panel.panel_width*panel.bpp / 8;
	sc->sc_fb_info.fb_width = panel.panel_width;
	sc->sc_fb_info.fb_height = panel.panel_height;

#ifdef	DEV_SC
	err = (sc_attach_unit(device_get_unit(dev),
	    device_get_flags(dev) | SC_AUTODETECT_KBD));

	if (err) {
		device_printf(dev, "failed to attach syscons\n");
		goto fail;
	}

	am335x_lcd_syscons_setup((vm_offset_t)sc->sc_fb_base, sc->sc_fb_phys, &panel);
#else /* VT */
	device_t fbd = device_add_child(dev, "fbd",
	device_get_unit(dev));
	if (fbd == NULL) {
		device_printf(dev, "Failed to add fbd child\n");
		goto fail;
	}
	if (device_probe_and_attach(fbd) != 0) {
		device_printf(dev, "Failed to attach fbd device\n");
		goto fail;
	}
#endif

	return (0);

fail:
	return (err);
}