/**
 * _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback
 * @id:		id of the remote processor
 * @op:		one of rproc_ops that indicate what operation to invoke
 *
 * Most of the checks and verification for remoteproc operations are more
 * or less same for almost all operations. This allows us to put a wrapper
 * and use the common checks to allow the driver to function appropriately.
 *
 * Return: 0 if all ok, else appropriate error value.
 */
static int _rproc_ops_wrapper(int id, enum rproc_ops op)
{
	struct udevice *dev = NULL;
	struct dm_rproc_uclass_pdata *uc_pdata;
	const struct dm_rproc_ops *ops;
	int (*fn)(struct udevice *dev);
	bool mandatory = false;
	char *op_str;
	int ret;

	ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
	if (ret) {
		debug("Unknown remote processor id '%d' requested(%d)\n",
		      id, ret);
		return ret;
	}

	uc_pdata = dev_get_uclass_platdata(dev);

	ops = rproc_get_ops(dev);
	if (!ops) {
		debug("%s driver has no ops?\n", dev->name);
		return -EINVAL;
	}
	switch (op) {
	case RPROC_START:
		fn = ops->start;
		mandatory = true;
		op_str = "Starting";
		break;
	case RPROC_STOP:
		fn = ops->stop;
		op_str = "Stopping";
		break;
	case RPROC_RESET:
		fn = ops->reset;
		op_str = "Resetting";
		break;
	case RPROC_RUNNING:
		fn = ops->is_running;
		op_str = "Checking if running:";
		break;
	case RPROC_PING:
		fn = ops->ping;
		op_str = "Pinging";
		break;
	default:
		debug("what is '%d' operation??\n", op);
		return -EINVAL;
	}

	debug("%s %s...\n", op_str, uc_pdata->name);
	if (fn)
		return fn(dev);

	if (mandatory)
		debug("%s: data corruption?? mandatory function is missing!\n",
		      dev->name);

	return -ENOSYS;
}
Beispiel #2
0
bool display_in_use(struct udevice *dev)
{
	struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev);

	return disp_uc_plat->in_use;
}
Beispiel #3
0
static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
		       lbaint_t blkcnt, void *buffer)
#endif
{
#ifdef CONFIG_BLK
	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
	struct udevice *bdev = dev->parent;
#else
	struct udevice *bdev = NULL;
#endif
	lbaint_t start, blks;
	uintptr_t buf_addr;
	unsigned short smallblks = 0;
	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;

	/* Setup device */
	pccb->target = block_dev->target;
	pccb->lun = block_dev->lun;
	buf_addr = (unsigned long)buffer;
	start = blknr;
	blks = blkcnt;
	debug("\nscsi_read: dev %d startblk " LBAF
	      ", blccnt " LBAF " buffer %lx\n",
	      block_dev->devnum, start, blks, (unsigned long)buffer);
	do {
		pccb->pdata = (unsigned char *)buf_addr;
#ifdef CONFIG_SYS_64BIT_LBA
		if (start > SCSI_LBA48_READ) {
			unsigned long blocks;
			blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
			pccb->datalen = block_dev->blksz * blocks;
			scsi_setup_read16(pccb, start, blocks);
			start += blocks;
			blks -= blocks;
		} else
#endif
		if (blks > SCSI_MAX_READ_BLK) {
			pccb->datalen = block_dev->blksz *
				SCSI_MAX_READ_BLK;
			smallblks = SCSI_MAX_READ_BLK;
			scsi_setup_read_ext(pccb, start, smallblks);
			start += SCSI_MAX_READ_BLK;
			blks -= SCSI_MAX_READ_BLK;
		} else {
			pccb->datalen = block_dev->blksz * blks;
			smallblks = (unsigned short)blks;
			scsi_setup_read_ext(pccb, start, smallblks);
			start += blks;
			blks = 0;
		}
		debug("scsi_read_ext: startblk " LBAF
		      ", blccnt %x buffer %" PRIXPTR "\n",
		      start, smallblks, buf_addr);
		if (scsi_exec(bdev, pccb)) {
			scsi_print_error(pccb);
			blkcnt -= blks;
			break;
		}
		buf_addr += pccb->datalen;
	} while (blks != 0);
	debug("scsi_read_ext: end startblk " LBAF
	      ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr);
	return blkcnt;
}
/**
 * rproc_pre_probe() - Pre probe accessor for the uclass
 * @dev:	device for which we are preprobing
 *
 * Parses and fills up the uclass pdata for use as needed by core and
 * remote proc drivers.
 *
 * Return: 0 if all wernt ok, else appropriate error value.
 */
static int rproc_pre_probe(struct udevice *dev)
{
	struct dm_rproc_uclass_pdata *uc_pdata;
	const struct dm_rproc_ops *ops;

	uc_pdata = dev_get_uclass_platdata(dev);

	/* See if we need to populate via fdt */

	if (!dev->platdata) {
#if CONFIG_IS_ENABLED(OF_CONTROL)
		int node = dev->of_offset;
		const void *blob = gd->fdt_blob;
		bool tmp;
		if (!blob) {
			debug("'%s' no dt?\n", dev->name);
			return -EINVAL;
		}
		debug("'%s': using fdt\n", dev->name);
		uc_pdata->name = fdt_getprop(blob, node,
					     "remoteproc-name", NULL);

		/* Default is internal memory mapped */
		uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
		tmp = fdtdec_get_bool(blob, node,
				      "remoteproc-internal-memory-mapped");
		if (tmp)
			uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
#else
		/* Nothing much we can do about this, can we? */
		return -EINVAL;
#endif

	} else {
		struct dm_rproc_uclass_pdata *pdata = dev->platdata;

		debug("'%s': using legacy data\n", dev->name);
		if (pdata->name)
			uc_pdata->name = pdata->name;
		uc_pdata->mem_type = pdata->mem_type;
		uc_pdata->driver_plat_data = pdata->driver_plat_data;
	}

	/* Else try using device Name */
	if (!uc_pdata->name)
		uc_pdata->name = dev->name;
	if (!uc_pdata->name) {
		debug("Unnamed device!");
		return -EINVAL;
	}

	if (!rproc_name_is_unique(dev, uc_pdata->name)) {
		debug("%s duplicate name '%s'\n", dev->name, uc_pdata->name);
		return -EINVAL;
	}

	ops = rproc_get_ops(dev);
	if (!ops) {
		debug("%s driver has no ops?\n", dev->name);
		return -EINVAL;
	}

	if (!ops->load || !ops->start) {
		debug("%s driver has missing mandatory ops?\n", dev->name);
		return -EINVAL;
	}

	return 0;
}
Beispiel #5
0
static int palmas_smps_probe(struct udevice *dev)
{
	struct dm_regulator_uclass_platdata *uc_pdata;
	struct udevice *parent;
	int idx;

	uc_pdata = dev_get_uclass_platdata(dev);

	parent = dev_get_parent(dev);
	int type = dev_get_driver_data(parent);

	uc_pdata->type = REGULATOR_TYPE_BUCK;

	switch (type) {
	case PALMAS:
	case TPS659038:
		switch (dev->driver_data) {
		case 123:
		case 12:
			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0];
			uc_pdata->volt_reg = palmas_smps_volt[type][0];
			break;
		case 3:
			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1];
			uc_pdata->volt_reg = palmas_smps_volt[type][1];
			break;
		case 45:
			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2];
			uc_pdata->volt_reg = palmas_smps_volt[type][2];
			break;
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
			idx = dev->driver_data - 3;
			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
			break;

		default:
			printf("Wrong ID for regulator\n");
		}
		break;

	case TPS65917:
		switch (dev->driver_data) {
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
			idx = dev->driver_data - 1;
			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
			break;
		case 12:
			idx = 0;
			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
			break;
		default:
			printf("Wrong ID for regulator\n");
		}
		break;

	default:
			printf("Invalid PMIC ID\n");
	}

	return 0;
}
int rk_lvds_enable(struct udevice *dev, int panel_bpp,
		   const struct display_timing *edid)
{
	struct rk_lvds_priv *priv = dev_get_priv(dev);
	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
	int ret = 0;
	unsigned int val = 0;

	ret = panel_enable_backlight(priv->panel);
	if (ret) {
		debug("%s: backlight error: %d\n", __func__, ret);
		return ret;
	}

	/* Select the video source */
	if (uc_plat->source_id)
		val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
		    (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
	else
		val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
	rk_setreg(&priv->grf->soc_con6, val);

	/* Select data transfer format */
	val = priv->format;
	if (priv->output == LVDS_OUTPUT_DUAL)
		val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
	else if (priv->output == LVDS_OUTPUT_SINGLE)
		val |= LVDS_CH0_EN;
	else if (priv->output == LVDS_OUTPUT_RGB)
		val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
	val |= (0xffff << 16);
	rk_setreg(&priv->grf->soc_con7, val);

	/* Enable LVDS PHY */
	if (priv->output == LVDS_OUTPUT_RGB) {
		lvds_writel(priv, RK3288_LVDS_CH0_REG0,
			    RK3288_LVDS_CH0_REG0_TTL_EN |
			    RK3288_LVDS_CH0_REG0_LANECK_EN |
			    RK3288_LVDS_CH0_REG0_LANE4_EN |
			    RK3288_LVDS_CH0_REG0_LANE3_EN |
			    RK3288_LVDS_CH0_REG0_LANE2_EN |
			    RK3288_LVDS_CH0_REG0_LANE1_EN |
			    RK3288_LVDS_CH0_REG0_LANE0_EN);
		lvds_writel(priv, RK3288_LVDS_CH0_REG2,
			    RK3288_LVDS_PLL_FBDIV_REG2(0x46));

		lvds_writel(priv, RK3288_LVDS_CH0_REG3,
			    RK3288_LVDS_PLL_FBDIV_REG3(0x46));
		lvds_writel(priv, RK3288_LVDS_CH0_REG4,
			    RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
			    RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
			    RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
			    RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
			    RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
			    RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
		lvds_writel(priv, RK3288_LVDS_CH0_REG5,
			    RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
			    RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
			    RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
			    RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
			    RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
			    RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
		lvds_writel(priv, RK3288_LVDS_CH0_REGD,
			    RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
		lvds_writel(priv, RK3288_LVDS_CH0_REG20,
			    RK3288_LVDS_CH0_REG20_LSB);
	} else {
		lvds_writel(priv, RK3288_LVDS_CH0_REG0,
			    RK3288_LVDS_CH0_REG0_LVDS_EN |
			    RK3288_LVDS_CH0_REG0_LANECK_EN |
			    RK3288_LVDS_CH0_REG0_LANE4_EN |
			    RK3288_LVDS_CH0_REG0_LANE3_EN |
			    RK3288_LVDS_CH0_REG0_LANE2_EN |
			    RK3288_LVDS_CH0_REG0_LANE1_EN |
			    RK3288_LVDS_CH0_REG0_LANE0_EN);
		lvds_writel(priv, RK3288_LVDS_CH0_REG1,
			    RK3288_LVDS_CH0_REG1_LANECK_BIAS |
			    RK3288_LVDS_CH0_REG1_LANE4_BIAS |
			    RK3288_LVDS_CH0_REG1_LANE3_BIAS |
			    RK3288_LVDS_CH0_REG1_LANE2_BIAS |
			    RK3288_LVDS_CH0_REG1_LANE1_BIAS |
			    RK3288_LVDS_CH0_REG1_LANE0_BIAS);
		lvds_writel(priv, RK3288_LVDS_CH0_REG2,
			    RK3288_LVDS_CH0_REG2_RESERVE_ON |
			    RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
			    RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
			    RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
			    RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
			    RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
			    RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
			    RK3288_LVDS_PLL_FBDIV_REG2(0x46));
		lvds_writel(priv, RK3288_LVDS_CH0_REG3,
			    RK3288_LVDS_PLL_FBDIV_REG3(0x46));
		lvds_writel(priv, RK3288_LVDS_CH0_REG4, 0x00);
		lvds_writel(priv, RK3288_LVDS_CH0_REG5, 0x00);
		lvds_writel(priv, RK3288_LVDS_CH0_REGD,
			    RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
		lvds_writel(priv, RK3288_LVDS_CH0_REG20,
			    RK3288_LVDS_CH0_REG20_LSB);
	}

	/* Power on */
	writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE,
	       priv->regs + RK3288_LVDS_CFG_REGC);

	writel(RK3288_LVDS_CFG_REG21_TX_ENABLE,
	       priv->regs + RK3288_LVDS_CFG_REG21);

	return 0;
}
static int rk_vop_probe(struct udevice *dev)
{
	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
	const void *blob = gd->fdt_blob;
	struct rk_vop_priv *priv = dev_get_priv(dev);
	struct udevice *reg;
	int ret, port, node;

	/* Before relocation we don't need to do anything */
	if (!(gd->flags & GD_FLG_RELOC))
		return 0;

	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
	priv->regs = (struct rk3288_vop *)dev_get_addr(dev);

	/* lcdc(vop) iodomain select 1.8V */
	rk_setreg(&priv->grf->io_vsel, 1 << 0);

	/*
	 * Try some common regulators. We should really get these from the
	 * device tree somehow.
	 */
	ret = regulator_autoset_by_name("vcc18_lcd", &reg);
	if (ret)
		debug("%s: Cannot autoset regulator vcc18_lcd\n", __func__);
	ret = regulator_autoset_by_name("VCC18_LCD", &reg);
	if (ret)
		debug("%s: Cannot autoset regulator VCC18_LCD\n", __func__);
	ret = regulator_autoset_by_name("vdd10_lcd_pwren_h", &reg);
	if (ret) {
		debug("%s: Cannot autoset regulator vdd10_lcd_pwren_h\n",
		      __func__);
	}
	ret = regulator_autoset_by_name("vdd10_lcd", &reg);
	if (ret) {
		debug("%s: Cannot autoset regulator vdd10_lcd\n",
		      __func__);
	}
	ret = regulator_autoset_by_name("VDD10_LCD", &reg);
	if (ret) {
		debug("%s: Cannot autoset regulator VDD10_LCD\n",
		      __func__);
	}
	ret = regulator_autoset_by_name("vcc33_lcd", &reg);
	if (ret)
		debug("%s: Cannot autoset regulator vcc33_lcd\n", __func__);

	/*
	 * Try all the ports until we find one that works. In practice this
	 * tries EDP first if available, then HDMI.
	 */
	port = fdt_subnode_offset(blob, dev->of_offset, "port");
	if (port < 0)
		return -EINVAL;
	for (node = fdt_first_subnode(blob, port);
	     node > 0;
	     node = fdt_next_subnode(blob, node)) {
		ret = rk_display_init(dev, plat->base, VIDEO_BPP16, node);
		if (ret)
			debug("Device failed: ret=%d\n", ret);
		if (!ret)
			break;
	}

	return ret;
}
/**
 * rk_display_init() - Try to enable the given display device
 *
 * This function performs many steps:
 * - Finds the display device being referenced by @ep_node
 * - Puts the VOP's ID into its uclass platform data
 * - Probes the device to set it up
 * - Reads the EDID timing information
 * - Sets up the VOP clocks, etc. for the selected pixel clock and display mode
 * - Enables the display (the display device handles this and will do different
 *     things depending on the display type)
 * - Tells the uclass about the display resolution so that the console will
 *     appear correctly
 *
 * @dev:	VOP device that we want to connect to the display
 * @fbbase:	Frame buffer address
 * @l2bpp	Log2 of bits-per-pixels for the display
 * @ep_node:	Device tree node to process - this is the offset of an endpoint
 *		node within the VOP's 'port' list.
 * @return 0 if OK, -ve if something went wrong
 */
int rk_display_init(struct udevice *dev, ulong fbbase,
		    enum video_log2_bpp l2bpp, int ep_node)
{
	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
	const void *blob = gd->fdt_blob;
	struct rk_vop_priv *priv = dev_get_priv(dev);
	int vop_id, remote_vop_id;
	struct rk3288_vop *regs = priv->regs;
	struct display_timing timing;
	struct udevice *disp;
	int ret, remote, i, offset;
	struct display_plat *disp_uc_plat;
	struct udevice *clk;

	vop_id = fdtdec_get_int(blob, ep_node, "reg", -1);
	debug("vop_id=%d\n", vop_id);
	remote = fdtdec_lookup_phandle(blob, ep_node, "remote-endpoint");
	if (remote < 0)
		return -EINVAL;
	remote_vop_id = fdtdec_get_int(blob, remote, "reg", -1);
	debug("remote vop_id=%d\n", remote_vop_id);

	for (i = 0, offset = remote; i < 3 && offset > 0; i++)
		offset = fdt_parent_offset(blob, offset);
	if (offset < 0) {
		debug("%s: Invalid remote-endpoint position\n", dev->name);
		return -EINVAL;
	}

	ret = uclass_find_device_by_of_offset(UCLASS_DISPLAY, offset, &disp);
	if (ret) {
		debug("%s: device '%s' display not found (ret=%d)\n", __func__,
		      dev->name, ret);
		return ret;
	}

	disp_uc_plat = dev_get_uclass_platdata(disp);
	debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
	disp_uc_plat->source_id = remote_vop_id;
	disp_uc_plat->src_dev = dev;

	ret = device_probe(disp);
	if (ret) {
		debug("%s: device '%s' display won't probe (ret=%d)\n",
		      __func__, dev->name, ret);
		return ret;
	}

	ret = display_read_timing(disp, &timing);
	if (ret) {
		debug("%s: Failed to read timings\n", __func__);
		return ret;
	}

	ret = rkclk_get_clk(CLK_NEW, &clk);
	if (!ret) {
		ret = clk_set_periph_rate(clk, DCLK_VOP0 + remote_vop_id,
					  timing.pixelclock.typ);
	}
	if (ret) {
		debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret);
		return ret;
	}

	rkvop_mode_set(regs, &timing, vop_id);

	rkvop_enable(regs, fbbase, 1 << l2bpp, &timing);

	ret = display_enable(disp, 1 << l2bpp, &timing);
	if (ret)
		return ret;

	uc_priv->xsize = timing.hactive.typ;
	uc_priv->ysize = timing.vactive.typ;
	uc_priv->bpix = l2bpp;
	debug("fb=%lx, size=%d %d\n", fbbase, uc_priv->xsize, uc_priv->ysize);

	return 0;
}
Beispiel #9
0
static int display_init(struct udevice *dev, void *lcdbase,
			int fb_bits_per_pixel, struct display_timing *timing)
{
	struct display_plat *disp_uc_plat;
	struct dc_ctlr *dc_ctlr;
	struct udevice *dp_dev;
	const int href_to_sync = 1, vref_to_sync = 1;
	int panel_bpp = 18;	/* default 18 bits per pixel */
	u32 plld_rate;
	int ret;

	/*
	 * Before we probe the display device (eDP), tell it that this device
	 * is the source of the display data.
	 */
	ret = uclass_find_first_device(UCLASS_DISPLAY, &dp_dev);
	if (ret) {
		debug("%s: device '%s' display not found (ret=%d)\n", __func__,
		      dev->name, ret);
		return ret;
	}

	disp_uc_plat = dev_get_uclass_platdata(dp_dev);
	debug("Found device '%s', disp_uc_priv=%p\n", dp_dev->name,
	      disp_uc_plat);
	disp_uc_plat->src_dev = dev;

	ret = uclass_get_device(UCLASS_DISPLAY, 0, &dp_dev);
	if (ret) {
		debug("%s: Failed to probe eDP, ret=%d\n", __func__, ret);
		return ret;
	}

	dc_ctlr = (struct dc_ctlr *)dev_read_addr(dev);
	if (ofnode_decode_display_timing(dev_ofnode(dev), 0, timing)) {
		debug("%s: Failed to decode display timing\n", __func__);
		return -EINVAL;
	}

	ret = display_update_config_from_edid(dp_dev, &panel_bpp, timing);
	if (ret) {
		debug("%s: Failed to decode EDID, using defaults\n", __func__);
		dump_config(panel_bpp, timing);
	}

	/*
	 * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER
	 * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the
	 * update_display_mode() for detail.
	 */
	plld_rate = clock_set_display_rate(timing->pixelclock.typ * 2);
	if (plld_rate == 0) {
		printf("dc: clock init failed\n");
		return -EIO;
	} else if (plld_rate != timing->pixelclock.typ * 2) {
		debug("dc: plld rounded to %u\n", plld_rate);
		timing->pixelclock.typ = plld_rate / 2;
	}

	/* Init dc */
	ret = tegra_dc_init(dc_ctlr);
	if (ret) {
		debug("dc: init failed\n");
		return ret;
	}

	/* Configure dc mode */
	ret = update_display_mode(dc_ctlr, timing, href_to_sync, vref_to_sync);
	if (ret) {
		debug("dc: failed to configure display mode\n");
		return ret;
	}

	/* Enable dp */
	ret = display_enable(dp_dev, panel_bpp, timing);
	if (ret) {
		debug("dc: failed to enable display: ret=%d\n", ret);
		return ret;
	}

	ret = update_window(dc_ctlr, (ulong)lcdbase, fb_bits_per_pixel, timing);
	if (ret) {
		debug("dc: failed to update window\n");
		return ret;
	}
	debug("%s: ready\n", __func__);

	return 0;
}
static void atmel_hlcdc_init(struct udevice *dev)
{
	struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
	struct atmel_hlcdc_priv *priv = dev_get_priv(dev);
	struct atmel_hlcd_regs *regs = priv->regs;
	struct display_timing *timing = &priv->timing;
	struct lcd_dma_desc *desc;
	unsigned long value, vl_clk_pol;
	int ret;

	/* Disable DISP signal */
	writel(LCDC_LCDDIS_DISPDIS, &regs->lcdc_lcddis);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_DISPSTS,
			   false, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);
	/* Disable synchronization */
	writel(LCDC_LCDDIS_SYNCDIS, &regs->lcdc_lcddis);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_LCDSTS,
			   false, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);
	/* Disable pixel clock */
	writel(LCDC_LCDDIS_CLKDIS, &regs->lcdc_lcddis);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_CLKSTS,
			   false, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);
	/* Disable PWM */
	writel(LCDC_LCDDIS_PWMDIS, &regs->lcdc_lcddis);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_PWMSTS,
			   false, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);

	/* Set pixel clock */
	value = priv->clk_rate / timing->pixelclock.typ;
	if (priv->clk_rate % timing->pixelclock.typ)
		value++;

	vl_clk_pol = 0;
	if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
		vl_clk_pol = LCDC_LCDCFG0_CLKPOL;

	if (value < 1) {
		/* Using system clock as pixel clock */
		writel(LCDC_LCDCFG0_CLKDIV(0)
			| LCDC_LCDCFG0_CGDISHCR
			| LCDC_LCDCFG0_CGDISHEO
			| LCDC_LCDCFG0_CGDISOVR1
			| LCDC_LCDCFG0_CGDISBASE
			| vl_clk_pol
			| LCDC_LCDCFG0_CLKSEL,
			&regs->lcdc_lcdcfg0);

	} else {
		writel(LCDC_LCDCFG0_CLKDIV(value - 2)
			| LCDC_LCDCFG0_CGDISHCR
			| LCDC_LCDCFG0_CGDISHEO
			| LCDC_LCDCFG0_CGDISOVR1
			| LCDC_LCDCFG0_CGDISBASE
			| vl_clk_pol,
			&regs->lcdc_lcdcfg0);
	}

	/* Initialize control register 5 */
	value = 0;

	if (!(timing->flags & DISPLAY_FLAGS_HSYNC_HIGH))
		value |= LCDC_LCDCFG5_HSPOL;
	if (!(timing->flags & DISPLAY_FLAGS_VSYNC_HIGH))
		value |= LCDC_LCDCFG5_VSPOL;

	switch (priv->output_mode) {
	case 12:
		value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
		break;
	case 16:
		value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
		break;
	case 18:
		value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
		break;
	case 24:
		value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
		break;
	default:
		BUG();
		break;
	}

	value |= LCDC_LCDCFG5_GUARDTIME(priv->guard_time);
	value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS);
	writel(value, &regs->lcdc_lcdcfg5);

	/* Vertical & Horizontal Timing */
	value = LCDC_LCDCFG1_VSPW(timing->vsync_len.typ - 1);
	value |= LCDC_LCDCFG1_HSPW(timing->hsync_len.typ - 1);
	writel(value, &regs->lcdc_lcdcfg1);

	value = LCDC_LCDCFG2_VBPW(timing->vback_porch.typ);
	value |= LCDC_LCDCFG2_VFPW(timing->vfront_porch.typ - 1);
	writel(value, &regs->lcdc_lcdcfg2);

	value = LCDC_LCDCFG3_HBPW(timing->hback_porch.typ - 1);
	value |= LCDC_LCDCFG3_HFPW(timing->hfront_porch.typ - 1);
	writel(value, &regs->lcdc_lcdcfg3);

	/* Display size */
	value = LCDC_LCDCFG4_RPF(timing->vactive.typ - 1);
	value |= LCDC_LCDCFG4_PPL(timing->hactive.typ - 1);
	writel(value, &regs->lcdc_lcdcfg4);

	writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO,
	       &regs->lcdc_basecfg0);

	switch (VNBITS(priv->vl_bpix)) {
	case 16:
		writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565,
		       &regs->lcdc_basecfg1);
		break;
	case 32:
		writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888,
		       &regs->lcdc_basecfg1);
		break;
	default:
		BUG();
		break;
	}

	writel(LCDC_BASECFG2_XSTRIDE(0), &regs->lcdc_basecfg2);
	writel(0, &regs->lcdc_basecfg3);
	writel(LCDC_BASECFG4_DMA, &regs->lcdc_basecfg4);

	/* Disable all interrupts */
	writel(~0UL, &regs->lcdc_lcdidr);
	writel(~0UL, &regs->lcdc_baseidr);

	/* Setup the DMA descriptor, this descriptor will loop to itself */
	desc = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*desc));
	if (!desc)
		return;

	desc->address = (u32)uc_plat->base;

	/* Disable DMA transfer interrupt & descriptor loaded interrupt. */
	desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
			| LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
	desc->next = (u32)desc;

	/* Flush the DMA descriptor if we enabled dcache */
	flush_dcache_range((u32)desc,
			   ALIGN(((u32)desc + sizeof(*desc)),
			   CONFIG_SYS_CACHELINE_SIZE));

	writel(desc->address, &regs->lcdc_baseaddr);
	writel(desc->control, &regs->lcdc_basectrl);
	writel(desc->next, &regs->lcdc_basenext);
	writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN,
	       &regs->lcdc_basecher);

	/* Enable LCD */
	value = readl(&regs->lcdc_lcden);
	writel(value | LCDC_LCDEN_CLKEN, &regs->lcdc_lcden);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_CLKSTS,
			   true, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);
	value = readl(&regs->lcdc_lcden);
	writel(value | LCDC_LCDEN_SYNCEN, &regs->lcdc_lcden);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_LCDSTS,
			   true, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);
	value = readl(&regs->lcdc_lcden);
	writel(value | LCDC_LCDEN_DISPEN, &regs->lcdc_lcden);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_DISPSTS,
			   true, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);
	value = readl(&regs->lcdc_lcden);
	writel(value | LCDC_LCDEN_PWMEN, &regs->lcdc_lcden);
	ret = wait_for_bit(__func__, &regs->lcdc_lcdsr, LCDC_LCDSR_PWMSTS,
			   true, 1000, false);
	if (ret)
		printf("%s: %d: Timeout!\n", __func__, __LINE__);
}
Beispiel #11
0
/* Set up the display ready for use */
static int video_post_probe(struct udevice *dev)
{
	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
	struct video_priv *priv = dev_get_uclass_priv(dev);
	char name[30], drv[15], *str;
	const char *drv_name = drv;
	struct udevice *cons;
	int ret;

	/* Set up the line and display size */
	priv->fb = map_sysmem(plat->base, plat->size);
	priv->line_length = priv->xsize * VNBYTES(priv->bpix);
	priv->fb_size = priv->line_length * priv->ysize;

	/* Set up colours - we could in future support other colours */
#ifdef CONFIG_SYS_WHITE_ON_BLACK
	priv->colour_fg = 0xffffff;
#else
	priv->colour_bg = 0xffffff;
#endif
	video_clear(dev);

	/*
	 * Create a text console device. For now we always do this, although
	 * it might be useful to support only bitmap drawing on the device
	 * for boards that don't need to display text. We create a TrueType
	 * console if enabled, a rotated console if the video driver requests
	 * it, otherwise a normal console.
	 *
	 * The console can be override by setting vidconsole_drv_name before
	 * probing this video driver, or in the probe() method.
	 *
	 * TrueType does not support rotation at present so fall back to the
	 * rotated console in that case.
	 */
	if (!priv->rot && IS_ENABLED(CONFIG_CONSOLE_TRUETYPE)) {
		snprintf(name, sizeof(name), "%s.vidconsole_tt", dev->name);
		strcpy(drv, "vidconsole_tt");
	} else {
		snprintf(name, sizeof(name), "%s.vidconsole%d", dev->name,
			 priv->rot);
		snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot);
	}

	str = strdup(name);
	if (!str)
		return -ENOMEM;
	if (priv->vidconsole_drv_name)
		drv_name = priv->vidconsole_drv_name;
	ret = device_bind_driver(dev, drv_name, str, &cons);
	if (ret) {
		debug("%s: Cannot bind console driver\n", __func__);
		return ret;
	}

	ret = device_probe(cons);
	if (ret) {
		debug("%s: Cannot probe console driver\n", __func__);
		return ret;
	}

	return 0;
};