| From 06e912bd821b21d9360a75cde2d78b03f17a5872 Mon Sep 17 00:00:00 2001 |
| From: Wen He <wen.he_1@nxp.com> |
| Date: Tue, 17 Sep 2019 15:35:52 +0800 |
| Subject: [PATCH] drm: ls1028a: Add DP driver support for LS1028A |
| |
| Add Display Port driver support for NXP Layerscape LS1028A platform. |
| |
| Signed-off-by: Wen He <wen.he_1@nxp.com> |
| --- |
| drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 1 + |
| drivers/gpu/drm/imx/Makefile | 2 +- |
| drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c | 13 +++ |
| drivers/gpu/drm/imx/cdn-mhdp-ls1028a.c | 110 ++++++++++++++++++++++++++ |
| drivers/gpu/drm/imx/cdns-mhdp-imx.h | 2 + |
| 5 files changed, 127 insertions(+), 1 deletion(-) |
| create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-ls1028a.c |
| |
| --- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c |
| +++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c |
| @@ -275,6 +275,7 @@ static int cdns_dp_bridge_attach(struct |
| struct drm_connector *connector = &mhdp->connector.base; |
| |
| connector->interlace_allowed = 1; |
| + |
| connector->polled = DRM_CONNECTOR_POLL_HPD; |
| |
| drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs); |
| --- a/drivers/gpu/drm/imx/Makefile |
| +++ b/drivers/gpu/drm/imx/Makefile |
| @@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o |
| obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o |
| |
| obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o |
| -obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o |
| +obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imxdrv.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o cdn-mhdp-imx8qm.o cdn-mhdp-ls1028a.o |
| --- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c |
| +++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c |
| @@ -94,6 +94,16 @@ static struct cdns_plat_data imx8qm_dp_d |
| .is_dp = true, |
| }; |
| |
| +static struct cdns_plat_data ls1028a_dp_drv_data = { |
| + .bind = cdns_dp_bind, |
| + .unbind = cdns_dp_unbind, |
| + .phy_set = cdns_dp_phy_set_imx8mq, |
| + .power_on = cdns_mhdp_power_on_ls1028a, |
| + .firmware_init = cdns_mhdp_firmware_init_imx8qm, |
| + .pclk_rate = cdns_mhdp_pclk_rate_ls1028a, |
| + .bus_type = BUS_TYPE_NORMAL_APB, |
| +}; |
| + |
| static const struct of_device_id cdns_mhdp_imx_dt_ids[] = { |
| { .compatible = "cdn,imx8mq-hdmi", |
| .data = &imx8mq_hdmi_drv_data |
| @@ -107,6 +117,9 @@ static const struct of_device_id cdns_mh |
| { .compatible = "cdn,imx8qm-dp", |
| .data = &imx8qm_dp_drv_data |
| }, |
| + { .compatible = "cdn,ls1028a-dp", |
| + .data = &ls1028a_dp_drv_data |
| + }, |
| {}, |
| }; |
| MODULE_DEVICE_TABLE(of, cdns_mhdp_imx_dt_ids); |
| --- /dev/null |
| +++ b/drivers/gpu/drm/imx/cdn-mhdp-ls1028a.c |
| @@ -0,0 +1,110 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +/* |
| + * Copyright 2019 NXP |
| + * |
| + */ |
| +#include <linux/clk.h> |
| +#include <drm/drmP.h> |
| +#include <linux/of.h> |
| +#include <linux/of_address.h> |
| +#include <linux/of_device.h> |
| + |
| +#include "cdns-mhdp-imx.h" |
| + |
| +static const struct of_device_id scfg_device_ids[] = { |
| + { .compatible = "fsl,ls1028a-scfg", }, |
| + {} |
| +}; |
| + |
| +static void ls1028a_phy_reset(u8 reset) |
| +{ |
| + struct device_node *scfg_node; |
| + void __iomem *scfg_base = NULL; |
| + |
| + scfg_node = of_find_matching_node(NULL, scfg_device_ids); |
| + if (scfg_node) |
| + scfg_base = of_iomap(scfg_node, 0); |
| + |
| + iowrite32(reset, scfg_base + 0x230); |
| +} |
| + |
| +int ls1028a_clocks_init(struct imx_mhdp_device *imx_mhdp) |
| +{ |
| + struct device *dev = imx_mhdp->mhdp.dev; |
| + struct imx_hdp_clks *clks = &imx_mhdp->clks; |
| + |
| + clks->clk_core = devm_clk_get(dev, "clk_core"); |
| + if (IS_ERR(clks->clk_core)) { |
| + dev_warn(dev, "failed to get hdp core clk\n"); |
| + return PTR_ERR(clks->clk_core); |
| + } |
| + |
| + clks->clk_pxl = devm_clk_get(dev, "clk_pxl"); |
| + if (IS_ERR(clks->clk_pxl)) { |
| + dev_warn(dev, "failed to get pxl clk\n"); |
| + return PTR_ERR(clks->clk_pxl); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +static int ls1028a_pixel_clk_enable(struct imx_mhdp_device *imx_mhdp) |
| +{ |
| + struct imx_hdp_clks *clks = &imx_mhdp->clks; |
| + struct device *dev = imx_mhdp->mhdp.dev; |
| + int ret; |
| + |
| + ret = clk_prepare_enable(clks->clk_pxl); |
| + if (ret < 0) { |
| + dev_err(dev, "%s, pre clk pxl error\n", __func__); |
| + return ret; |
| + } |
| + |
| + return ret; |
| +} |
| + |
| +static void ls1028a_pixel_clk_disable(struct imx_mhdp_device *imx_mhdp) |
| +{ |
| + struct imx_hdp_clks *clks = &imx_mhdp->clks; |
| + |
| + clk_disable_unprepare(clks->clk_pxl); |
| +} |
| + |
| +static void ls1028a_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp, |
| + u32 pclock) |
| +{ |
| + struct imx_hdp_clks *clks = &imx_mhdp->clks; |
| + |
| + clk_set_rate(clks->clk_pxl, pclock); |
| +} |
| + |
| +int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp) |
| +{ |
| + struct imx_mhdp_device *imx_mhdp = container_of |
| + (mhdp, struct imx_mhdp_device, mhdp); |
| + |
| + /* clock init and rate set */ |
| + ls1028a_clocks_init(imx_mhdp); |
| + |
| + ls1028a_pixel_clk_enable(imx_mhdp); |
| + |
| + /* Init pixel clock with 148.5MHz before FW init */ |
| + ls1028a_pixel_clk_set_rate(imx_mhdp, 148500000); |
| + |
| + ls1028a_phy_reset(1); |
| + |
| + return 0; |
| +} |
| + |
| +void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp) |
| +{ |
| + struct imx_mhdp_device *imx_mhdp = container_of |
| + (mhdp, struct imx_mhdp_device, mhdp); |
| + |
| + /* set pixel clock before video mode setup */ |
| + ls1028a_pixel_clk_disable(imx_mhdp); |
| + |
| + ls1028a_pixel_clk_set_rate(imx_mhdp, imx_mhdp->mhdp.mode.clock * 1000); |
| + |
| + ls1028a_pixel_clk_enable(imx_mhdp); |
| +} |
| --- a/drivers/gpu/drm/imx/cdns-mhdp-imx.h |
| +++ b/drivers/gpu/drm/imx/cdns-mhdp-imx.h |
| @@ -78,4 +78,6 @@ void cdns_mhdp_plat_deinit_imx8qm(struct |
| void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp); |
| int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp); |
| int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp); |
| +int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp); |
| +void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp); |
| #endif /* CDNS_MHDP_IMX_H_ */ |