[PATCH v5 1/2] drm/bridge: Add Cadence DSI driver

Boris Brezillon boris.brezillon at free-electrons.com
Mon Jan 29 13:14:09 UTC 2018


On Mon, 29 Jan 2018 13:56:21 +0200
Tomi Valkeinen <tomi.valkeinen at ti.com> wrote:

> > +
> > +static void cdns_dsi_init_link(struct cdns_dsi *dsi)
> > +{
> > +	struct cdns_dsi_output *output = &dsi->output;
> > +	unsigned long sysclk_period, ulpout;
> > +	u32 val;
> > +	int i;
> > +
> > +	if (dsi->link_initialized)
> > +		return;
> > +
> > +	val = 0;
> > +	for (i = 1; i < output->dev->lanes; i++)
> > +		val |= DATA_LANE_EN(i);
> > +
> > +	if (!(output->dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS))
> > +		val |= CLK_CONTINUOUS;
> > +
> > +	writel(val, dsi->regs + MCTL_MAIN_PHY_CTL);
> > +
> > +	/* ULPOUT should be set to 1ms and is expressed in sysclk cycles. */
> > +	sysclk_period = NSEC_PER_SEC / clk_get_rate(dsi->dsi_sys_clk);
> > +	ulpout = DIV_ROUND_UP(NSEC_PER_MSEC, sysclk_period);
> > +	writel(CLK_LANE_ULPOUT_TIME(ulpout) | DATA_LANE_ULPOUT_TIME(ulpout),
> > +	       dsi->regs + MCTL_ULPOUT_TIME);
> > +
> > +	writel(LINK_EN, dsi->regs + MCTL_MAIN_DATA_CTL);
> > +
> > +	val = CLK_LANE_EN | PLL_START;
> > +	for (i = 0; i < output->dev->lanes; i++)
> > +		val |= DATA_LANE_START(i);
> > +
> > +	writel(val, dsi->regs + MCTL_MAIN_EN);
> > +
> > +	ndelay(100);  
> 
> It's good to have a comment about each sleep/delay on what is for and
> where does the value come from.

Yep, I'll figure this out.

> 
> > +	dsi->link_initialized = true;
> > +}
> > +


> > +static int cdns_dsi_drm_probe(struct platform_device *pdev)
> > +{
> > +	struct cdns_dsi *dsi;
> > +	struct cdns_dsi_input *input;
> > +	struct resource *res;
> > +	int ret, irq;
> > +	u32 val;
> > +
> > +	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
> > +	if (!dsi)
> > +		return -ENOMEM;
> > +
> > +	platform_set_drvdata(pdev, dsi);
> > +
> > +	input = &dsi->input;
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	dsi->regs = devm_ioremap_resource(&pdev->dev, res);
> > +	if (IS_ERR(dsi->regs))
> > +		return PTR_ERR(dsi->regs);
> > +
> > +	dsi->dsi_p_clk = devm_clk_get(&pdev->dev, "dsi_p_clk");
> > +	if (IS_ERR(dsi->dsi_p_clk))
> > +		return PTR_ERR(dsi->dsi_p_clk);
> > +
> > +	dsi->dsi_p_rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
> > +								"dsi_p_rst");
> > +	if (IS_ERR(dsi->dsi_p_rst))
> > +		return PTR_ERR(dsi->dsi_p_rst);
> > +
> > +	dsi->dsi_sys_clk = devm_clk_get(&pdev->dev, "dsi_sys_clk");
> > +	if (IS_ERR(dsi->dsi_sys_clk))
> > +		return PTR_ERR(dsi->dsi_sys_clk);
> > +
> > +	irq = platform_get_irq(pdev, 0);
> > +	if (irq < 0)
> > +		return irq;
> > +
> > +	ret = clk_prepare_enable(dsi->dsi_p_clk);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = clk_prepare_enable(dsi->dsi_sys_clk);
> > +	if (ret)
> > +		goto err_disable_pclk;
> > +
> > +	val = readl(dsi->regs + ID_REG);
> > +	if (REV_VENDOR_ID(val) != 0xcad) {
> > +		dev_err(&pdev->dev, "invalid vendor id\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	val = readl(dsi->regs + IP_CONF);
> > +	dsi->direct_cmd_fifo_depth = 1 << (DIRCMD_FIFO_DEPTH(val) + 2);
> > +	dsi->rx_fifo_depth = RX_FIFO_DEPTH(val);
> > +	init_completion(&dsi->direct_cmd_comp);
> > +
> > +	writel(0, dsi->regs + MCTL_MAIN_DATA_CTL);
> > +	writel(0, dsi->regs + MCTL_MAIN_EN);
> > +	writel(0, dsi->regs + MCTL_MAIN_PHY_CTL);
> > +
> > +	/*
> > +	 * We only support the DPI input, so force input->id to
> > +	 * CDNS_DPI_INPUT.
> > +	 */
> > +	input->id = CDNS_DPI_INPUT;
> > +	input->bridge.funcs = &cdns_dsi_bridge_funcs;
> > +	input->bridge.of_node = pdev->dev.of_node;
> > +
> > +	/* Mask all interrupts before registering the IRQ handler. */
> > +	writel(0, dsi->regs + MCTL_MAIN_STS_CTL);
> > +	writel(0, dsi->regs + MCTL_DPHY_ERR_CTL1);
> > +	writel(0, dsi->regs + CMD_MODE_STS_CTL);
> > +	writel(0, dsi->regs + DIRECT_CMD_STS_CTL);
> > +	writel(0, dsi->regs + DIRECT_CMD_RD_STS_CTL);
> > +	writel(0, dsi->regs + VID_MODE_STS_CTL);
> > +	writel(0, dsi->regs + TVG_STS_CTL);
> > +	writel(0, dsi->regs + DPI_IRQ_EN);
> > +	ret = devm_request_irq(&pdev->dev, irq, cdns_dsi_interrupt, 0,
> > +			       dev_name(&pdev->dev), dsi);
> > +	if (ret)
> > +		goto err_disable_pclk;
> > +
> > +	pm_runtime_enable(&pdev->dev);
> > +	dsi->base.dev = &pdev->dev;
> > +	dsi->base.ops = &cdns_dsi_ops;
> > +
> > +	ret = mipi_dsi_host_register(&dsi->base);
> > +	if (ret)
> > +		goto err_disable_runtime_pm;
> > +
> > +	clk_disable_unprepare(dsi->dsi_p_clk);
> > +
> > +	return 0;
> > +
> > +err_disable_runtime_pm:
> > +	pm_runtime_disable(&pdev->dev);
> > +
> > +err_disable_pclk:
> > +	clk_disable_unprepare(dsi->dsi_p_clk);
> > +
> > +	return ret;
> > +}  
> 
> You don't disable the dsi_sys_clk neither in the ok nor in the error paths.

Hm, it shouldn't be enabled in the first place: the runtime resume
hook takes care of enabling it, and we don't need this clock to access
IP registers (which is all we do in the probe).

I'll fix that.


More information about the dri-devel mailing list