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; }
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; }