Exemplo n.º 1
0
static int
pl111_init_clock_divider(struct drm_device *drm)
{
	struct pl111_drm_dev_private *priv = drm->dev_private;
	struct clk *parent = devm_clk_get(drm->dev, "clcdclk");
	struct clk_hw *div = &priv->clk_div;
	const char *parent_name;
	struct clk_init_data init = {
		.name = "pl111_div",
		.ops = &pl111_clk_div_ops,
		.parent_names = &parent_name,
		.num_parents = 1,
		.flags = CLK_SET_RATE_PARENT,
	};
	int ret;

	if (IS_ERR(parent)) {
		dev_err(drm->dev, "CLCD: unable to get clcdclk.\n");
		return PTR_ERR(parent);
	}
	/* If the clock divider is broken, use the parent directly */
	if (priv->variant->broken_clockdivider) {
		priv->clk = parent;
		return 0;
	}
	parent_name = __clk_get_name(parent);

	spin_lock_init(&priv->tim2_lock);
	div->init = &init;

	ret = devm_clk_hw_register(drm->dev, div);

	priv->clk = div->clk;
	return ret;
}

int pl111_display_init(struct drm_device *drm)
{
	struct pl111_drm_dev_private *priv = drm->dev_private;
	struct device *dev = drm->dev;
	struct device_node *endpoint;
	u32 tft_r0b0g0[3];
	int ret;

	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
	if (!endpoint)
		return -ENODEV;

	if (of_property_read_u32_array(endpoint,
				       "arm,pl11x,tft-r0g0b0-pads",
				       tft_r0b0g0,
				       ARRAY_SIZE(tft_r0b0g0)) != 0) {
		dev_err(dev, "arm,pl11x,tft-r0g0b0-pads should be 3 ints\n");
		of_node_put(endpoint);
		return -ENOENT;
	}
	of_node_put(endpoint);

	ret = pl111_init_clock_divider(drm);
	if (ret)
		return ret;

	if (!priv->variant->broken_vblank) {
		pl111_display_funcs.enable_vblank = pl111_display_enable_vblank;
		pl111_display_funcs.disable_vblank = pl111_display_disable_vblank;
	}

	ret = drm_simple_display_pipe_init(drm, &priv->pipe,
					   &pl111_display_funcs,
					   priv->variant->formats,
					   priv->variant->nformats,
					   NULL,
					   priv->connector);
	if (ret)
		return ret;

	return 0;
}
Exemplo n.º 2
0
static int mxsfb_load(struct drm_device *drm, unsigned long flags)
{
	struct platform_device *pdev = to_platform_device(drm->dev);
	struct mxsfb_drm_private *mxsfb;
	struct resource *res;
	int ret;

	mxsfb = devm_kzalloc(&pdev->dev, sizeof(*mxsfb), GFP_KERNEL);
	if (!mxsfb)
		return -ENOMEM;

	drm->dev_private = mxsfb;
	mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	mxsfb->base = devm_ioremap_resource(drm->dev, res);
	if (IS_ERR(mxsfb->base))
		return PTR_ERR(mxsfb->base);

	mxsfb->clk = devm_clk_get(drm->dev, NULL);
	if (IS_ERR(mxsfb->clk))
		return PTR_ERR(mxsfb->clk);

	mxsfb->clk_axi = devm_clk_get(drm->dev, "axi");
	if (IS_ERR(mxsfb->clk_axi))
		mxsfb->clk_axi = NULL;

	mxsfb->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi");
	if (IS_ERR(mxsfb->clk_disp_axi))
		mxsfb->clk_disp_axi = NULL;

	ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
	if (ret)
		return ret;

	pm_runtime_enable(drm->dev);

	ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
	if (ret < 0) {
		dev_err(drm->dev, "Failed to initialise vblank\n");
		goto err_vblank;
	}

	/* Modeset init */
	drm_mode_config_init(drm);

	ret = mxsfb_create_output(drm);
	if (ret < 0) {
		dev_err(drm->dev, "Failed to create outputs\n");
		goto err_vblank;
	}

	ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
			mxsfb_formats, ARRAY_SIZE(mxsfb_formats),
			&mxsfb->connector);
	if (ret < 0) {
		dev_err(drm->dev, "Cannot setup simple display pipe\n");
		goto err_vblank;
	}

	ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector);
	if (ret) {
		dev_err(drm->dev, "Cannot connect panel\n");
		goto err_vblank;
	}

	drm->mode_config.min_width	= MXSFB_MIN_XRES;
	drm->mode_config.min_height	= MXSFB_MIN_YRES;
	drm->mode_config.max_width	= MXSFB_MAX_XRES;
	drm->mode_config.max_height	= MXSFB_MAX_YRES;
	drm->mode_config.funcs		= &mxsfb_mode_config_funcs;

	drm_mode_config_reset(drm);

	pm_runtime_get_sync(drm->dev);
	ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
	pm_runtime_put_sync(drm->dev);

	if (ret < 0) {
		dev_err(drm->dev, "Failed to install IRQ handler\n");
		goto err_irq;
	}

	drm_kms_helper_poll_init(drm);

	mxsfb->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
					  drm->mode_config.num_connector);
	if (IS_ERR(mxsfb->fbdev)) {
		mxsfb->fbdev = NULL;
		dev_err(drm->dev, "Failed to init FB CMA area\n");
		goto err_cma;
	}

	platform_set_drvdata(pdev, drm);

	drm_helper_hpd_irq_event(drm);

	return 0;

err_cma:
	drm_irq_uninstall(drm);
err_irq:
	drm_panel_detach(mxsfb->panel);
err_vblank:
	pm_runtime_disable(drm->dev);

	return ret;
}