diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip')
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/cdn-dp-reg.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 86 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/inno_hdmi.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_lvds.c | 581 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_lvds.h | 114 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 |
15 files changed, 828 insertions, 98 deletions
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index dcc539ba85d6..0c31f0a27b9c 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -57,4 +57,12 @@ config ROCKCHIP_INNO_HDMI for the Innosilicon HDMI driver. If you want to enable HDMI on RK3036 based SoC, you should select this option. +config ROCKCHIP_LVDS + bool "Rockchip LVDS support" + depends on DRM_ROCKCHIP + help + Choose this option to enable support for Rockchip LVDS controllers. + Rockchip rk3288 SoC has LVDS TX Controller can be used, and it + support LVDS, rgb, dual LVDS output mode. say Y to enable its + driver. endif diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index fa8dc9d9aac2..a881d2cc4f25 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -12,5 +12,6 @@ rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o +rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 9606121fa185..4d3f6ad0abdd 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -88,7 +88,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) if (!analogix_dp_psr_supported(dp->dev)) return; - dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); + DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); spin_lock_irqsave(&dp->psr_lock, flags); if (enabled) @@ -110,7 +110,7 @@ static void analogix_dp_psr_work(struct work_struct *work) ret = rockchip_drm_wait_vact_end(dp->encoder.crtc, PSR_WAIT_LINE_FLAG_TIMEOUT_MS); if (ret) { - dev_err(dp->dev, "line flag interrupt did not arrive\n"); + DRM_DEV_ERROR(dp->dev, "line flag interrupt did not arrive\n"); return; } @@ -140,13 +140,13 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) ret = clk_prepare_enable(dp->pclk); if (ret < 0) { - dev_err(dp->dev, "failed to enable pclk %d\n", ret); + DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); return ret; } ret = rockchip_dp_pre_init(dp); if (ret < 0) { - dev_err(dp->dev, "failed to dp pre init %d\n", ret); + DRM_DEV_ERROR(dp->dev, "failed to dp pre init %d\n", ret); clk_disable_unprepare(dp->pclk); return ret; } @@ -211,17 +211,17 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) else val = dp->data->lcdsel_big; - dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); + DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); ret = clk_prepare_enable(dp->grfclk); if (ret < 0) { - dev_err(dp->dev, "failed to enable grfclk %d\n", ret); + DRM_DEV_ERROR(dp->dev, "failed to enable grfclk %d\n", ret); return; } ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); if (ret != 0) - dev_err(dp->dev, "Could not write to GRF: %d\n", ret); + DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); clk_disable_unprepare(dp->grfclk); } @@ -277,7 +277,7 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp) dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(dp->grf)) { - dev_err(dev, "failed to get rockchip,grf property\n"); + DRM_DEV_ERROR(dev, "failed to get rockchip,grf property\n"); return PTR_ERR(dp->grf); } @@ -287,31 +287,31 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp) } else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) { return -EPROBE_DEFER; } else if (IS_ERR(dp->grfclk)) { - dev_err(dev, "failed to get grf clock\n"); + DRM_DEV_ERROR(dev, "failed to get grf clock\n"); return PTR_ERR(dp->grfclk); } dp->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dp->pclk)) { - dev_err(dev, "failed to get pclk property\n"); + DRM_DEV_ERROR(dev, "failed to get pclk property\n"); return PTR_ERR(dp->pclk); } dp->rst = devm_reset_control_get(dev, "dp"); if (IS_ERR(dp->rst)) { - dev_err(dev, "failed to get dp reset control\n"); + DRM_DEV_ERROR(dev, "failed to get dp reset control\n"); return PTR_ERR(dp->rst); } ret = clk_prepare_enable(dp->pclk); if (ret < 0) { - dev_err(dp->dev, "failed to enable pclk %d\n", ret); + DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); return ret; } ret = rockchip_dp_pre_init(dp); if (ret < 0) { - dev_err(dp->dev, "failed to pre init %d\n", ret); + DRM_DEV_ERROR(dp->dev, "failed to pre init %d\n", ret); clk_disable_unprepare(dp->pclk); return ret; } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index b14d211f6c21..eb3042c6d1b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -323,7 +323,7 @@ int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; dp->fw_version |= reg << 24; - dev_dbg(dp->dev, "firmware version: %x\n", dp->fw_version); + DRM_DEV_DEBUG(dp->dev, "firmware version: %x\n", dp->fw_version); return 0; } diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 9a20b9dc27c8..b15755b6129c 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -430,9 +430,9 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) testdin = max_mbps_to_testdin(dsi->lane_mbps); if (testdin < 0) { - dev_err(dsi->dev, - "failed to get testdin for %dmbps lane clock\n", - dsi->lane_mbps); + DRM_DEV_ERROR(dsi->dev, + "failed to get testdin for %dmbps lane clock\n", + dsi->lane_mbps); return testdin; } @@ -443,7 +443,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) ret = clk_prepare_enable(dsi->phy_cfg_clk); if (ret) { - dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n"); + DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n"); return ret; } @@ -501,7 +501,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US); if (ret < 0) { - dev_err(dsi->dev, "failed to wait for phy lock state\n"); + DRM_DEV_ERROR(dsi->dev, "failed to wait for phy lock state\n"); goto phy_init_end; } @@ -509,8 +509,8 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) val, val & STOP_STATE_CLK_LANE, 1000, PHY_STATUS_TIMEOUT_US); if (ret < 0) - dev_err(dsi->dev, - "failed to wait for phy clk lane stop state\n"); + DRM_DEV_ERROR(dsi->dev, + "failed to wait for phy clk lane stop state\n"); phy_init_end: clk_disable_unprepare(dsi->phy_cfg_clk); @@ -529,8 +529,9 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi, bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); if (bpp < 0) { - dev_err(dsi->dev, "failed to get bpp for pixel format %d\n", - dsi->format); + DRM_DEV_ERROR(dsi->dev, + "failed to get bpp for pixel format %d\n", + dsi->format); return bpp; } @@ -541,7 +542,8 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi, if (tmp < max_mbps) target_mbps = tmp; else - dev_err(dsi->dev, "DPHY clock frequency is out of range\n"); + DRM_DEV_ERROR(dsi->dev, + "DPHY clock frequency is out of range\n"); } pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC); @@ -582,8 +584,9 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, struct dw_mipi_dsi *dsi = host_to_dsi(host); if (device->lanes > dsi->pdata->max_data_lanes) { - dev_err(dsi->dev, "the number of data lanes(%u) is too many\n", - device->lanes); + DRM_DEV_ERROR(dsi->dev, + "the number of data lanes(%u) is too many\n", + device->lanes); return -EINVAL; } @@ -632,7 +635,8 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) val, !(val & GEN_CMD_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { - dev_err(dsi->dev, "failed to get available command FIFO\n"); + DRM_DEV_ERROR(dsi->dev, + "failed to get available command FIFO\n"); return ret; } @@ -643,7 +647,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) val, (val & mask) == mask, 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { - dev_err(dsi->dev, "failed to write command FIFO\n"); + DRM_DEV_ERROR(dsi->dev, "failed to write command FIFO\n"); return ret; } @@ -663,8 +667,9 @@ static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi, data |= tx_buf[1] << 8; if (msg->tx_len > 2) { - dev_err(dsi->dev, "too long tx buf length %zu for short write\n", - msg->tx_len); + DRM_DEV_ERROR(dsi->dev, + "too long tx buf length %zu for short write\n", + msg->tx_len); return -EINVAL; } @@ -682,8 +687,9 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, u32 val; if (msg->tx_len < 3) { - dev_err(dsi->dev, "wrong tx buf length %zu for long write\n", - msg->tx_len); + DRM_DEV_ERROR(dsi->dev, + "wrong tx buf length %zu for long write\n", + msg->tx_len); return -EINVAL; } @@ -704,8 +710,8 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, val, !(val & GEN_PLD_W_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { - dev_err(dsi->dev, - "failed to get available write payload FIFO\n"); + DRM_DEV_ERROR(dsi->dev, + "failed to get available write payload FIFO\n"); return ret; } } @@ -731,8 +737,8 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, ret = dw_mipi_dsi_dcs_long_write(dsi, msg); break; default: - dev_err(dsi->dev, "unsupported message type 0x%02x\n", - msg->type); + DRM_DEV_ERROR(dsi->dev, "unsupported message type 0x%02x\n", + msg->type); ret = -EINVAL; } @@ -935,7 +941,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) return; if (clk_prepare_enable(dsi->pclk)) { - dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); + DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n"); return; } @@ -967,7 +973,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) return; if (clk_prepare_enable(dsi->pclk)) { - dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); + DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n"); return; } @@ -991,7 +997,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) */ ret = clk_prepare_enable(dsi->grf_clk); if (ret) { - dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret); + DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret); return; } @@ -1004,7 +1010,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); if (drm_panel_prepare(dsi->panel)) - dev_err(dsi->dev, "failed to prepare panel\n"); + DRM_DEV_ERROR(dsi->dev, "failed to prepare panel\n"); dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); drm_panel_enable(dsi->panel); @@ -1017,7 +1023,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) val = pdata->dsi0_en_bit << 16; regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val); - dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); + DRM_DEV_DEBUG(dsi->dev, + "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); dsi->dpms_mode = DRM_MODE_DPMS_ON; clk_disable_unprepare(dsi->grf_clk); @@ -1111,7 +1118,7 @@ static int dw_mipi_dsi_register(struct drm_device *drm, ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs, DRM_MODE_ENCODER_DSI, NULL); if (ret) { - dev_err(dev, "Failed to initialize encoder with drm\n"); + DRM_DEV_ERROR(dev, "Failed to initialize encoder with drm\n"); return ret; } @@ -1133,7 +1140,7 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi) dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(dsi->grf_regmap)) { - dev_err(dsi->dev, "Unable to get rockchip,grf\n"); + DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n"); return PTR_ERR(dsi->grf_regmap); } @@ -1205,14 +1212,15 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, dsi->pllref_clk = devm_clk_get(dev, "ref"); if (IS_ERR(dsi->pllref_clk)) { ret = PTR_ERR(dsi->pllref_clk); - dev_err(dev, "Unable to get pll reference clock: %d\n", ret); + DRM_DEV_ERROR(dev, + "Unable to get pll reference clock: %d\n", ret); return ret; } dsi->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dsi->pclk)) { ret = PTR_ERR(dsi->pclk); - dev_err(dev, "Unable to get pclk: %d\n", ret); + DRM_DEV_ERROR(dev, "Unable to get pclk: %d\n", ret); return ret; } @@ -1226,7 +1234,8 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, if (ret == -ENOENT) { apb_rst = NULL; } else { - dev_err(dev, "Unable to get reset control: %d\n", ret); + DRM_DEV_ERROR(dev, + "Unable to get reset control: %d\n", ret); return ret; } } @@ -1234,7 +1243,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, if (apb_rst) { ret = clk_prepare_enable(dsi->pclk); if (ret) { - dev_err(dev, "%s: Failed to enable pclk\n", __func__); + DRM_DEV_ERROR(dev, "Failed to enable pclk\n"); return ret; } @@ -1249,7 +1258,8 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); if (IS_ERR(dsi->phy_cfg_clk)) { ret = PTR_ERR(dsi->phy_cfg_clk); - dev_err(dev, "Unable to get phy_cfg_clk: %d\n", ret); + DRM_DEV_ERROR(dev, + "Unable to get phy_cfg_clk: %d\n", ret); return ret; } } @@ -1258,20 +1268,20 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, dsi->grf_clk = devm_clk_get(dev, "grf"); if (IS_ERR(dsi->grf_clk)) { ret = PTR_ERR(dsi->grf_clk); - dev_err(dev, "Unable to get grf_clk: %d\n", ret); + DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret); return ret; } } ret = clk_prepare_enable(dsi->pllref_clk); if (ret) { - dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); + DRM_DEV_ERROR(dev, "Failed to enable pllref_clk\n"); return ret; } ret = dw_mipi_dsi_register(drm, dsi); if (ret) { - dev_err(dev, "Failed to register mipi_dsi: %d\n", ret); + DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret); goto err_pllref; } @@ -1281,7 +1291,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, dsi->dsi_host.dev = dev; ret = mipi_dsi_host_register(&dsi->dsi_host); if (ret) { - dev_err(dev, "Failed to register MIPI host: %d\n", ret); + DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret); goto err_cleanup; } diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index ccd5d595ada7..1eb02a82fd91 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -168,7 +168,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(hdmi->regmap)) { - dev_err(hdmi->dev, "Unable to get rockchip,grf\n"); + DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n"); return PTR_ERR(hdmi->regmap); } @@ -178,7 +178,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) { return -EPROBE_DEFER; } else if (IS_ERR(hdmi->vpll_clk)) { - dev_err(hdmi->dev, "failed to get grf clock\n"); + DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); return PTR_ERR(hdmi->vpll_clk); } @@ -188,13 +188,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { return -EPROBE_DEFER; } else if (IS_ERR(hdmi->grf_clk)) { - dev_err(hdmi->dev, "failed to get grf clock\n"); + DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); return PTR_ERR(hdmi->grf_clk); } ret = clk_prepare_enable(hdmi->vpll_clk); if (ret) { - dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret); + DRM_DEV_ERROR(hdmi->dev, + "Failed to enable HDMI vpll: %d\n", ret); return ret; } @@ -259,17 +260,17 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) ret = clk_prepare_enable(hdmi->grf_clk); if (ret < 0) { - dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret); + DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret); return; } ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val); if (ret != 0) - dev_err(hdmi->dev, "Could not write to GRF: %d\n", ret); + DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret); clk_disable_unprepare(hdmi->grf_clk); - dev_dbg(hdmi->dev, "vop %s output to hdmi\n", - ret ? "LIT" : "BIG"); + DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n", + ret ? "LIT" : "BIG"); } static int @@ -368,7 +369,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, ret = rockchip_hdmi_parse_dt(hdmi); if (ret) { - dev_err(hdmi->dev, "Unable to parse OF data\n"); + DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n"); return ret; } diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 7a251a54e792..ee584d87111f 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -224,7 +224,7 @@ static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) break; default: - dev_err(hdmi->dev, "Unknown power mode %d\n", mode); + DRM_DEV_ERROR(hdmi->dev, "Unknown power mode %d\n", mode); } } @@ -742,8 +742,9 @@ static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap, hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY); for (i = 0; i < num; i++) { - dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n", - i + 1, num, msgs[i].len, msgs[i].flags); + DRM_DEV_DEBUG(hdmi->dev, + "xfer: num: %d/%d, len: %d, flags: %#x\n", + i + 1, num, msgs[i].len, msgs[i].flags); if (msgs[i].flags & I2C_M_RD) ret = inno_hdmi_i2c_read(hdmi, &msgs[i]); @@ -806,7 +807,7 @@ static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi) hdmi->i2c = i2c; - dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); + DRM_DEV_INFO(hdmi->dev, "registered %s I2C bus driver\n", adap->name); return adap; } @@ -838,13 +839,14 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); if (IS_ERR(hdmi->pclk)) { - dev_err(hdmi->dev, "Unable to get HDMI pclk clk\n"); + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); return PTR_ERR(hdmi->pclk); } ret = clk_prepare_enable(hdmi->pclk); if (ret) { - dev_err(hdmi->dev, "Cannot enable HDMI pclk clock: %d\n", ret); + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI pclk clock: %d\n", ret); return ret; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index ff3d0f5efbb1..76d63de5921d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -58,7 +58,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, ret = iommu_attach_device(private->domain, dev); if (ret) { - dev_err(dev, "Failed to attach iommu device\n"); + DRM_DEV_ERROR(dev, "Failed to attach iommu device\n"); return ret; } @@ -373,8 +373,9 @@ static int rockchip_drm_platform_of_probe(struct device *dev) iommu = of_parse_phandle(port->parent, "iommus", 0); if (!iommu || !of_device_is_available(iommu->parent)) { - dev_dbg(dev, "no iommu attached for %pOF, using non-iommu buffers\n", - port->parent); + DRM_DEV_DEBUG(dev, + "no iommu attached for %pOF, using non-iommu buffers\n", + port->parent); /* * if there is a crtc not support iommu, force set all * crtc use non-iommu buffer. @@ -389,12 +390,13 @@ static int rockchip_drm_platform_of_probe(struct device *dev) } if (i == 0) { - dev_err(dev, "missing 'ports' property\n"); + DRM_DEV_ERROR(dev, "missing 'ports' property\n"); return -ENODEV; } if (!found) { - dev_err(dev, "No available vop found for display-subsystem.\n"); + DRM_DEV_ERROR(dev, + "No available vop found for display-subsystem.\n"); return -ENODEV; } @@ -453,6 +455,8 @@ static int __init rockchip_drm_init(void) num_rockchip_sub_drivers = 0; ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP); + ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, + CONFIG_ROCKCHIP_LVDS); ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, CONFIG_ROCKCHIP_ANALOGIX_DP); ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index c7e96b82cf63..498dfbc52cec 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -69,5 +69,6 @@ extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; extern struct platform_driver dw_mipi_dsi_driver; extern struct platform_driver inno_hdmi_driver; extern struct platform_driver rockchip_dp_driver; +extern struct platform_driver rockchip_lvds_driver; extern struct platform_driver vop_platform_driver; #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 70773041785b..cd2ace0c3caa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -100,8 +100,9 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm ret = drm_framebuffer_init(dev, &rockchip_fb->fb, &rockchip_drm_fb_funcs); if (ret) { - dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", - ret); + DRM_DEV_ERROR(dev->dev, + "Failed to initialize framebuffer: %d\n", + ret); kfree(rockchip_fb); return ERR_PTR(ret); } @@ -134,7 +135,8 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); if (!obj) { - dev_err(dev->dev, "Failed to lookup GEM object\n"); + DRM_DEV_ERROR(dev->dev, + "Failed to lookup GEM object\n"); ret = -ENXIO; goto err_gem_object_unreference; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index 724579ebf947..e6650553f5d6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c @@ -76,7 +76,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, fbi = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(fbi)) { - dev_err(dev->dev, "Failed to create framebuffer info.\n"); + DRM_DEV_ERROR(dev->dev, "Failed to create framebuffer info.\n"); ret = PTR_ERR(fbi); goto out; } @@ -84,7 +84,8 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, helper->fb = rockchip_drm_framebuffer_init(dev, &mode_cmd, private->fbdev_bo); if (IS_ERR(helper->fb)) { - dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); + DRM_DEV_ERROR(dev->dev, + "Failed to allocate DRM framebuffer.\n"); ret = PTR_ERR(helper->fb); goto out; } @@ -138,21 +139,24 @@ int rockchip_drm_fbdev_init(struct drm_device *dev) ret = drm_fb_helper_init(dev, helper, ROCKCHIP_MAX_CONNECTOR); if (ret < 0) { - dev_err(dev->dev, "Failed to initialize drm fb helper - %d.\n", - ret); + DRM_DEV_ERROR(dev->dev, + "Failed to initialize drm fb helper - %d.\n", + ret); return ret; } ret = drm_fb_helper_single_add_all_connectors(helper); if (ret < 0) { - dev_err(dev->dev, "Failed to add connectors - %d.\n", ret); + DRM_DEV_ERROR(dev->dev, + "Failed to add connectors - %d.\n", ret); goto err_drm_fb_helper_fini; } ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); if (ret < 0) { - dev_err(dev->dev, "Failed to set initial hw config - %d.\n", - ret); + DRM_DEV_ERROR(dev->dev, + "Failed to set initial hw config - %d.\n", + ret); goto err_drm_fb_helper_fini; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index bf9ed0e63973..19128b4dea54 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -160,7 +160,7 @@ static void vop_reg_set(struct vop *vop, const struct vop_reg *reg, int offset, mask, shift; if (!reg || !reg->mask) { - dev_dbg(vop->dev, "Warning: not support %s\n", reg_name); + DRM_DEV_DEBUG(vop->dev, "Warning: not support %s\n", reg_name); return; } @@ -499,7 +499,7 @@ static int vop_enable(struct drm_crtc *crtc) ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { - dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); + DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); return ret; } @@ -523,7 +523,8 @@ static int vop_enable(struct drm_crtc *crtc) */ ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev); if (ret) { - dev_err(vop->dev, "failed to attach dma mapping, %d\n", ret); + DRM_DEV_ERROR(vop->dev, + "failed to attach dma mapping, %d\n", ret); goto err_disable_aclk; } @@ -1361,42 +1362,42 @@ static int vop_initial(struct vop *vop) vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); if (IS_ERR(vop->hclk)) { - dev_err(vop->dev, "failed to get hclk source\n"); + DRM_DEV_ERROR(vop->dev, "failed to get hclk source\n"); return PTR_ERR(vop->hclk); } vop->aclk = devm_clk_get(vop->dev, "aclk_vop"); if (IS_ERR(vop->aclk)) { - dev_err(vop->dev, "failed to get aclk source\n"); + DRM_DEV_ERROR(vop->dev, "failed to get aclk source\n"); return PTR_ERR(vop->aclk); } vop->dclk = devm_clk_get(vop->dev, "dclk_vop"); if (IS_ERR(vop->dclk)) { - dev_err(vop->dev, "failed to get dclk source\n"); + DRM_DEV_ERROR(vop->dev, "failed to get dclk source\n"); return PTR_ERR(vop->dclk); } ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { - dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); + DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); return ret; } ret = clk_prepare(vop->dclk); if (ret < 0) { - dev_err(vop->dev, "failed to prepare dclk\n"); + DRM_DEV_ERROR(vop->dev, "failed to prepare dclk\n"); goto err_put_pm_runtime; } /* Enable both the hclk and aclk to setup the vop */ ret = clk_prepare_enable(vop->hclk); if (ret < 0) { - dev_err(vop->dev, "failed to prepare/enable hclk\n"); + DRM_DEV_ERROR(vop->dev, "failed to prepare/enable hclk\n"); goto err_unprepare_dclk; } ret = clk_prepare_enable(vop->aclk); if (ret < 0) { - dev_err(vop->dev, "failed to prepare/enable aclk\n"); + DRM_DEV_ERROR(vop->dev, "failed to prepare/enable aclk\n"); goto err_disable_hclk; } @@ -1405,7 +1406,7 @@ static int vop_initial(struct vop *vop) */ ahb_rst = devm_reset_control_get(vop->dev, "ahb"); if (IS_ERR(ahb_rst)) { - dev_err(vop->dev, "failed to get ahb reset\n"); + DRM_DEV_ERROR(vop->dev, "failed to get ahb reset\n"); ret = PTR_ERR(ahb_rst); goto err_disable_aclk; } @@ -1434,7 +1435,7 @@ static int vop_initial(struct vop *vop) */ vop->dclk_rst = devm_reset_control_get(vop->dev, "dclk"); if (IS_ERR(vop->dclk_rst)) { - dev_err(vop->dev, "failed to get dclk reset\n"); + DRM_DEV_ERROR(vop->dev, "failed to get dclk reset\n"); ret = PTR_ERR(vop->dclk_rst); goto err_disable_aclk; } @@ -1511,7 +1512,7 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) vop_line_flag_irq_disable(vop); if (jiffies_left == 0) { - dev_err(vop->dev, "Timeout waiting for IRQ\n"); + DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n"); return -ETIMEDOUT; } @@ -1558,7 +1559,7 @@ static int vop_bind(struct device *dev, struct device *master, void *data) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "cannot find irq for vop\n"); + DRM_DEV_ERROR(dev, "cannot find irq for vop\n"); return irq; } vop->irq = (unsigned int)irq; @@ -1584,7 +1585,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data) ret = vop_initial(vop); if (ret < 0) { - dev_err(&pdev->dev, "cannot initial vop dev - err %d\n", ret); + DRM_DEV_ERROR(&pdev->dev, + "cannot initial vop dev - err %d\n", ret); goto err_disable_pm_runtime; } diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c new file mode 100644 index 000000000000..c5fbe533796c --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -0,0 +1,581 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: + * Mark Yao <mark.yao@rock-chips.com> + * Sandy Huang <hjc@rock-chips.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_dp_helper.h> +#include <drm/drm_panel.h> +#include <drm/drm_of.h> + +#include <linux/component.h> +#include <linux/clk.h> +#include <linux/mfd/syscon.h> +#include <linux/of_graph.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_vop.h" +#include "rockchip_lvds.h" + +#define DISPLAY_OUTPUT_RGB 0 +#define DISPLAY_OUTPUT_LVDS 1 +#define DISPLAY_OUTPUT_DUAL_LVDS 2 + +#define connector_to_lvds(c) \ + container_of(c, struct rockchip_lvds, connector) + +#define encoder_to_lvds(c) \ + container_of(c, struct rockchip_lvds, encoder) + +/** + * rockchip_lvds_soc_data - rockchip lvds Soc private data + * @ch1_offset: lvds channel 1 registe offset + * grf_soc_con6: general registe offset for LVDS contrl + * grf_soc_con7: general registe offset for LVDS contrl + * has_vop_sel: to indicate whether need to choose from different VOP. + */ +struct rockchip_lvds_soc_data { + u32 ch1_offset; + int grf_soc_con6; + int grf_soc_con7; + bool has_vop_sel; +}; + +struct rockchip_lvds { + struct device *dev; + void __iomem *regs; + struct regmap *grf; + struct clk *pclk; + const struct rockchip_lvds_soc_data *soc_data; + int output; /* rgb lvds or dual lvds output */ + int format; /* vesa or jeida format */ + struct drm_device *drm_dev; + struct drm_panel *panel; + struct drm_bridge *bridge; + struct drm_connector connector; + struct drm_encoder encoder; + struct dev_pin_info *pins; +}; + +static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val) +{ + writel_relaxed(val, lvds->regs + offset); + if (lvds->output == DISPLAY_OUTPUT_LVDS) + return; + writel_relaxed(val, lvds->regs + offset + lvds->soc_data->ch1_offset); +} + +static inline int lvds_name_to_format(const char *s) +{ + if (strncmp(s, "jeida-18", 8) == 0) + return LVDS_JEIDA_18; + else if (strncmp(s, "jeida-24", 8) == 0) + return LVDS_JEIDA_24; + else if (strncmp(s, "vesa-24", 7) == 0) + return LVDS_VESA_24; + + return -EINVAL; +} + +static inline int lvds_name_to_output(const char *s) +{ + if (strncmp(s, "rgb", 3) == 0) + return DISPLAY_OUTPUT_RGB; + else if (strncmp(s, "lvds", 4) == 0) + return DISPLAY_OUTPUT_LVDS; + else if (strncmp(s, "duallvds", 8) == 0) + return DISPLAY_OUTPUT_DUAL_LVDS; + + return -EINVAL; +} + +static int rockchip_lvds_poweron(struct rockchip_lvds *lvds) +{ + int ret; + u32 val; + + ret = clk_enable(lvds->pclk); + if (ret < 0) { + DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret); + return ret; + } + ret = pm_runtime_get_sync(lvds->dev); + if (ret < 0) { + DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret); + clk_disable(lvds->pclk); + return ret; + } + val = 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; + if (lvds->output == DISPLAY_OUTPUT_RGB) { + val |= RK3288_LVDS_CH0_REG0_TTL_EN | + RK3288_LVDS_CH0_REG0_LANECK_EN; + lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val); + lvds_writel(lvds, RK3288_LVDS_CH0_REG2, + RK3288_LVDS_PLL_FBDIV_REG2(0x46)); + lvds_writel(lvds, 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(lvds, 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); + } else { + val |= RK3288_LVDS_CH0_REG0_LVDS_EN | + RK3288_LVDS_CH0_REG0_LANECK_EN; + lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val); + lvds_writel(lvds, 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(lvds, 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(lvds, RK3288_LVDS_CH0_REG4, 0x00); + lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00); + } + lvds_writel(lvds, RK3288_LVDS_CH0_REG3, RK3288_LVDS_PLL_FBDIV_REG3(0x46)); + lvds_writel(lvds, RK3288_LVDS_CH0_REGD, RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); + lvds_writel(lvds, RK3288_LVDS_CH0_REG20, RK3288_LVDS_CH0_REG20_LSB); + + lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); + lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); + + return 0; +} + +static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds) +{ + int ret; + u32 val; + + lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE); + lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE); + val = LVDS_DUAL | LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN | LVDS_PWRDN; + val |= val << 16; + ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val); + if (ret != 0) + DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); + + pm_runtime_put(lvds->dev); + clk_disable(lvds->pclk); +} + +static const struct drm_connector_funcs rockchip_lvds_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int rockchip_lvds_connector_get_modes(struct drm_connector *connector) +{ + struct rockchip_lvds *lvds = connector_to_lvds(connector); + struct drm_panel *panel = lvds->panel; + + return drm_panel_get_modes(panel); +} + +static const +struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = { + .get_modes = rockchip_lvds_connector_get_modes, +}; + +static void rockchip_lvds_grf_config(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct rockchip_lvds *lvds = encoder_to_lvds(encoder); + u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0; + u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0; + u32 val; + int ret; + + /* iomux to LCD data/sync mode */ + if (lvds->output == DISPLAY_OUTPUT_RGB) + if (lvds->pins && !IS_ERR(lvds->pins->default_state)) + pinctrl_select_state(lvds->pins->p, + lvds->pins->default_state); + val = lvds->format | LVDS_CH0_EN; + if (lvds->output == DISPLAY_OUTPUT_RGB) + val |= LVDS_TTL_EN | LVDS_CH1_EN; + else if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS) + val |= LVDS_DUAL | LVDS_CH1_EN; + + if ((mode->htotal - mode->hsync_start) & 0x01) + val |= LVDS_START_PHASE_RST_1; + + val |= (pin_dclk << 8) | (pin_hsync << 9); + val |= (0xffff << 16); + ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val); + if (ret != 0) { + DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); + return; + } +} + +static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds, + struct drm_encoder *encoder) +{ + u32 val; + int ret; + + if (!lvds->soc_data->has_vop_sel) + return 0; + + ret = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder); + if (ret < 0) + return ret; + + val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16; + if (ret) + val |= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT; + + ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val); + if (ret < 0) + return ret; + + return 0; +} + +static int +rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + + s->output_mode = ROCKCHIP_OUT_MODE_P888; + s->output_type = DRM_MODE_CONNECTOR_LVDS; + + return 0; +} + +static void rockchip_lvds_encoder_enable(struct drm_encoder *encoder) +{ + struct rockchip_lvds *lvds = encoder_to_lvds(encoder); + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; + int ret; + + drm_panel_prepare(lvds->panel); + ret = rockchip_lvds_poweron(lvds); + if (ret < 0) { + DRM_DEV_ERROR(lvds->dev, "failed to power on lvds: %d\n", ret); + drm_panel_unprepare(lvds->panel); + } + rockchip_lvds_grf_config(encoder, mode); + rockchip_lvds_set_vop_source(lvds, encoder); + drm_panel_enable(lvds->panel); +} + +static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder) +{ + struct rockchip_lvds *lvds = encoder_to_lvds(encoder); + + drm_panel_disable(lvds->panel); + rockchip_lvds_poweroff(lvds); + drm_panel_unprepare(lvds->panel); +} + +static const +struct drm_encoder_helper_funcs rockchip_lvds_encoder_helper_funcs = { + .enable = rockchip_lvds_encoder_enable, + .disable = rockchip_lvds_encoder_disable, + .atomic_check = rockchip_lvds_encoder_atomic_check, +}; + +static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static const struct rockchip_lvds_soc_data rk3288_lvds_data = { + .ch1_offset = 0x100, + .grf_soc_con6 = 0x025c, + .grf_soc_con7 = 0x0260, + .has_vop_sel = true, +}; + +static const struct of_device_id rockchip_lvds_dt_ids[] = { + { + .compatible = "rockchip,rk3288-lvds", + .data = &rk3288_lvds_data + }, + {} +}; +MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids); + +static int rockchip_lvds_bind(struct device *dev, struct device *master, + void *data) +{ + struct rockchip_lvds *lvds = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + struct drm_encoder *encoder; + struct drm_connector *connector; + struct device_node *remote = NULL; + struct device_node *port, *endpoint; + int ret; + const char *name; + u32 endpoint_id; + + lvds->drm_dev = drm_dev; + port = of_graph_get_port_by_id(dev->of_node, 1); + if (!port) { + DRM_DEV_ERROR(dev, + "can't found port point, please init lvds panel port!\n"); + return -EINVAL; + } + for_each_child_of_node(port, endpoint) { + of_property_read_u32(endpoint, "reg", &endpoint_id); + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id, + &lvds->panel, &lvds->bridge); + if (!ret) + break; + } + if (ret) { + DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); + ret = -EPROBE_DEFER; + goto err_put_port; + } + if (lvds->panel) + remote = lvds->panel->dev->of_node; + else + remote = lvds->bridge->of_node; + if (of_property_read_string(dev->of_node, "rockchip,output", &name)) + /* default set it as output rgb */ + lvds->output = DISPLAY_OUTPUT_RGB; + else + lvds->output = lvds_name_to_output(name); + + if (lvds->output < 0) { + DRM_DEV_ERROR(dev, "invalid output type [%s]\n", name); + ret = lvds->output; + goto err_put_remote; + } + + if (of_property_read_string(remote, "data-mapping", &name)) + /* default set it as format vesa 18 */ + lvds->format = LVDS_VESA_18; + else + lvds->format = lvds_name_to_format(name); + + if (lvds->format < 0) { + DRM_DEV_ERROR(dev, "invalid data-mapping format [%s]\n", name); + ret = lvds->format; + goto err_put_remote; + } + + encoder = &lvds->encoder; + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, + dev->of_node); + + ret = drm_encoder_init(drm_dev, encoder, &rockchip_lvds_encoder_funcs, + DRM_MODE_ENCODER_LVDS, NULL); + if (ret < 0) { + DRM_DEV_ERROR(drm_dev->dev, + "failed to initialize encoder: %d\n", ret); + goto err_put_remote; + } + + drm_encoder_helper_add(encoder, &rockchip_lvds_encoder_helper_funcs); + + if (lvds->panel) { + connector = &lvds->connector; + connector->dpms = DRM_MODE_DPMS_OFF; + ret = drm_connector_init(drm_dev, connector, + &rockchip_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + if (ret < 0) { + DRM_DEV_ERROR(drm_dev->dev, + "failed to initialize connector: %d\n", ret); + goto err_free_encoder; + } + + drm_connector_helper_add(connector, + &rockchip_lvds_connector_helper_funcs); + + ret = drm_mode_connector_attach_encoder(connector, encoder); + if (ret < 0) { + DRM_DEV_ERROR(drm_dev->dev, + "failed to attach encoder: %d\n", ret); + goto err_free_connector; + } + + ret = drm_panel_attach(lvds->panel, connector); + if (ret < 0) { + DRM_DEV_ERROR(drm_dev->dev, + "failed to attach panel: %d\n", ret); + goto err_free_connector; + } + } else { + lvds->bridge->encoder = encoder; + ret = drm_bridge_attach(encoder, lvds->bridge, NULL); + if (ret) { + DRM_DEV_ERROR(drm_dev->dev, + "failed to attach bridge: %d\n", ret); + goto err_free_encoder; + } + encoder->bridge = lvds->bridge; + } + + pm_runtime_enable(dev); + of_node_put(remote); + of_node_put(port); + + return 0; + +err_free_connector: + drm_connector_cleanup(connector); +err_free_encoder: + drm_encoder_cleanup(encoder); +err_put_remote: + of_node_put(remote); +err_put_port: + of_node_put(port); + + return ret; +} + +static void rockchip_lvds_unbind(struct device *dev, struct device *master, + void *data) +{ + struct rockchip_lvds *lvds = dev_get_drvdata(dev); + + rockchip_lvds_encoder_disable(&lvds->encoder); + if (lvds->panel) + drm_panel_detach(lvds->panel); + pm_runtime_disable(dev); + drm_connector_cleanup(&lvds->connector); + drm_encoder_cleanup(&lvds->encoder); +} + +static const struct component_ops rockchip_lvds_component_ops = { + .bind = rockchip_lvds_bind, + .unbind = rockchip_lvds_unbind, +}; + +static int rockchip_lvds_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rockchip_lvds *lvds; + const struct of_device_id *match; + struct resource *res; + int ret; + + if (!dev->of_node) + return -ENODEV; + + lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); + if (!lvds) + return -ENOMEM; + + lvds->dev = dev; + match = of_match_node(rockchip_lvds_dt_ids, dev->of_node); + if (!match) + return -ENODEV; + lvds->soc_data = match->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lvds->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(lvds->regs)) + return PTR_ERR(lvds->regs); + + lvds->pclk = devm_clk_get(&pdev->dev, "pclk_lvds"); + if (IS_ERR(lvds->pclk)) { + DRM_DEV_ERROR(dev, "could not get pclk_lvds\n"); + return PTR_ERR(lvds->pclk); + } + + lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins), + GFP_KERNEL); + if (!lvds->pins) + return -ENOMEM; + + lvds->pins->p = devm_pinctrl_get(lvds->dev); + if (IS_ERR(lvds->pins->p)) { + DRM_DEV_ERROR(dev, "no pinctrl handle\n"); + devm_kfree(lvds->dev, lvds->pins); + lvds->pins = NULL; + } else { + lvds->pins->default_state = + pinctrl_lookup_state(lvds->pins->p, "lcdc"); + if (IS_ERR(lvds->pins->default_state)) { + DRM_DEV_ERROR(dev, "no default pinctrl state\n"); + devm_kfree(lvds->dev, lvds->pins); + lvds->pins = NULL; + } + } + + lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + if (IS_ERR(lvds->grf)) { + DRM_DEV_ERROR(dev, "missing rockchip,grf property\n"); + return PTR_ERR(lvds->grf); + } + + dev_set_drvdata(dev, lvds); + + ret = clk_prepare(lvds->pclk); + if (ret < 0) { + DRM_DEV_ERROR(dev, "failed to prepare pclk_lvds\n"); + return ret; + } + ret = component_add(&pdev->dev, &rockchip_lvds_component_ops); + if (ret < 0) { + DRM_DEV_ERROR(dev, "failed to add component\n"); + clk_unprepare(lvds->pclk); + } + + return ret; +} + +static int rockchip_lvds_remove(struct platform_device *pdev) +{ + struct rockchip_lvds *lvds = dev_get_drvdata(&pdev->dev); + + component_del(&pdev->dev, &rockchip_lvds_component_ops); + clk_unprepare(lvds->pclk); + + return 0; +} + +struct platform_driver rockchip_lvds_driver = { + .probe = rockchip_lvds_probe, + .remove = rockchip_lvds_remove, + .driver = { + .name = "rockchip-lvds", + .of_match_table = of_match_ptr(rockchip_lvds_dt_ids), + }, +}; diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.h b/drivers/gpu/drm/rockchip/rockchip_lvds.h new file mode 100644 index 000000000000..15810b737809 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: + * Sandy Huang <hjc@rock-chips.com> + * Mark Yao <mark.yao@rock-chips.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _ROCKCHIP_LVDS_ +#define _ROCKCHIP_LVDS_ + +#define RK3288_LVDS_CH0_REG0 0x00 +#define RK3288_LVDS_CH0_REG0_LVDS_EN BIT(7) +#define RK3288_LVDS_CH0_REG0_TTL_EN BIT(6) +#define RK3288_LVDS_CH0_REG0_LANECK_EN BIT(5) +#define RK3288_LVDS_CH0_REG0_LANE4_EN BIT(4) +#define RK3288_LVDS_CH0_REG0_LANE3_EN BIT(3) +#define RK3288_LVDS_CH0_REG0_LANE2_EN BIT(2) +#define RK3288_LVDS_CH0_REG0_LANE1_EN BIT(1) +#define RK3288_LVDS_CH0_REG0_LANE0_EN BIT(0) + +#define RK3288_LVDS_CH0_REG1 0x04 +#define RK3288_LVDS_CH0_REG1_LANECK_BIAS BIT(5) +#define RK3288_LVDS_CH0_REG1_LANE4_BIAS BIT(4) +#define RK3288_LVDS_CH0_REG1_LANE3_BIAS BIT(3) +#define RK3288_LVDS_CH0_REG1_LANE2_BIAS BIT(2) +#define RK3288_LVDS_CH0_REG1_LANE1_BIAS BIT(1) +#define RK3288_LVDS_CH0_REG1_LANE0_BIAS BIT(0) + +#define RK3288_LVDS_CH0_REG2 0x08 +#define RK3288_LVDS_CH0_REG2_RESERVE_ON BIT(7) +#define RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE BIT(6) +#define RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE BIT(5) +#define RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE BIT(4) +#define RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE BIT(3) +#define RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE BIT(2) +#define RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE BIT(1) +#define RK3288_LVDS_CH0_REG2_PLL_FBDIV8 BIT(0) + +#define RK3288_LVDS_CH0_REG3 0x0c +#define RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK 0xff + +#define RK3288_LVDS_CH0_REG4 0x10 +#define RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE BIT(5) +#define RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE BIT(4) +#define RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE BIT(3) +#define RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE BIT(2) +#define RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE BIT(1) +#define RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE BIT(0) + +#define RK3288_LVDS_CH0_REG5 0x14 +#define RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA BIT(5) +#define RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA BIT(4) +#define RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA BIT(3) +#define RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA BIT(2) +#define RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA BIT(1) +#define RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA BIT(0) + +#define RK3288_LVDS_CFG_REGC 0x30 +#define RK3288_LVDS_CFG_REGC_PLL_ENABLE 0x00 +#define RK3288_LVDS_CFG_REGC_PLL_DISABLE 0xff + +#define RK3288_LVDS_CH0_REGD 0x34 +#define RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK 0x1f + +#define RK3288_LVDS_CH0_REG20 0x80 +#define RK3288_LVDS_CH0_REG20_MSB 0x45 +#define RK3288_LVDS_CH0_REG20_LSB 0x44 + +#define RK3288_LVDS_CFG_REG21 0x84 +#define RK3288_LVDS_CFG_REG21_TX_ENABLE 0x92 +#define RK3288_LVDS_CFG_REG21_TX_DISABLE 0x00 +#define RK3288_LVDS_CH1_OFFSET 0x100 + +/* fbdiv value is split over 2 registers, with bit8 in reg2 */ +#define RK3288_LVDS_PLL_FBDIV_REG2(_fbd) \ + (_fbd & BIT(8) ? RK3288_LVDS_CH0_REG2_PLL_FBDIV8 : 0) +#define RK3288_LVDS_PLL_FBDIV_REG3(_fbd) \ + (_fbd & RK3288_LVDS_CH0_REG3_PLL_FBDIV_MASK) +#define RK3288_LVDS_PLL_PREDIV_REGD(_pd) \ + (_pd & RK3288_LVDS_CH0_REGD_PLL_PREDIV_MASK) + +#define RK3288_LVDS_SOC_CON6_SEL_VOP_LIT BIT(3) + +#define LVDS_FMT_MASK (0x07 << 16) +#define LVDS_MSB BIT(3) +#define LVDS_DUAL BIT(4) +#define LVDS_FMT_1 BIT(5) +#define LVDS_TTL_EN BIT(6) +#define LVDS_START_PHASE_RST_1 BIT(7) +#define LVDS_DCLK_INV BIT(8) +#define LVDS_CH0_EN BIT(11) +#define LVDS_CH1_EN BIT(12) +#define LVDS_PWRDN BIT(15) + +#define LVDS_24BIT (0 << 1) +#define LVDS_18BIT (1 << 1) +#define LVDS_FORMAT_VESA (0 << 0) +#define LVDS_FORMAT_JEIDA (1 << 0) + +#define LVDS_VESA_24 0 +#define LVDS_JEIDA_24 1 +#define LVDS_VESA_18 2 +#define LVDS_JEIDA_18 3 + +#endif /* _ROCKCHIP_LVDS_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 94de7b9f6fde..4a39049e901a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -533,7 +533,7 @@ static int vop_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; if (!dev->of_node) { - dev_err(dev, "can't find vop devices\n"); + DRM_DEV_ERROR(dev, "can't find vop devices\n"); return -ENODEV; } |