diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip/rockchip_lvds.c')
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_lvds.c | 488 |
1 files changed, 332 insertions, 156 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 8a4c9af0ba73..f25a36743cbd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -10,6 +10,7 @@ #include <linux/component.h> #include <linux/mfd/syscon.h> #include <linux/of_graph.h> +#include <linux/phy/phy.h> #include <linux/pinctrl/devinfo.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -31,6 +32,8 @@ #define DISPLAY_OUTPUT_LVDS 1 #define DISPLAY_OUTPUT_DUAL_LVDS 2 +struct rockchip_lvds; + #define connector_to_lvds(c) \ container_of(c, struct rockchip_lvds, connector) @@ -39,16 +42,12 @@ /** * 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. + * @probe: LVDS platform probe function + * @helper_funcs: LVDS connector helper functions */ struct rockchip_lvds_soc_data { - u32 ch1_offset; - int grf_soc_con6; - int grf_soc_con7; - bool has_vop_sel; + int (*probe)(struct platform_device *pdev, struct rockchip_lvds *lvds); + const struct drm_encoder_helper_funcs *helper_funcs; }; struct rockchip_lvds { @@ -56,6 +55,7 @@ struct rockchip_lvds { void __iomem *regs; struct regmap *grf; struct clk *pclk; + struct phy *dphy; const struct rockchip_lvds_soc_data *soc_data; int output; /* rgb lvds or dual lvds output */ int format; /* vesa or jeida format */ @@ -67,15 +67,16 @@ struct rockchip_lvds { struct dev_pin_info *pins; }; -static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val) +static inline void rk3288_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); + writel_relaxed(val, lvds->regs + offset + RK3288_LVDS_CH1_OFFSET); } -static inline int lvds_name_to_format(const char *s) +static inline int rockchip_lvds_name_to_format(const char *s) { if (strncmp(s, "jeida-18", 8) == 0) return LVDS_JEIDA_18; @@ -87,7 +88,7 @@ static inline int lvds_name_to_format(const char *s) return -EINVAL; } -static inline int lvds_name_to_output(const char *s) +static inline int rockchip_lvds_name_to_output(const char *s) { if (strncmp(s, "rgb", 3) == 0) return DISPLAY_OUTPUT_RGB; @@ -99,7 +100,41 @@ static inline int lvds_name_to_output(const char *s) return -EINVAL; } -static int rockchip_lvds_poweron(struct rockchip_lvds *lvds) +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, connector); +} + +static const +struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = { + .get_modes = rockchip_lvds_connector_get_modes, +}; + +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 int rk3288_lvds_poweron(struct rockchip_lvds *lvds) { int ret; u32 val; @@ -121,66 +156,73 @@ static int rockchip_lvds_poweron(struct rockchip_lvds *lvds) 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); + rk3288_writel(lvds, RK3288_LVDS_CH0_REG0, val); + rk3288_writel(lvds, RK3288_LVDS_CH0_REG2, + RK3288_LVDS_PLL_FBDIV_REG2(0x46)); + rk3288_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); + rk3288_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); + rk3288_writel(lvds, RK3288_LVDS_CH0_REG0, val); + rk3288_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); + rk3288_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)); + rk3288_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00); + rk3288_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); + rk3288_writel(lvds, RK3288_LVDS_CH0_REG3, + RK3288_LVDS_PLL_FBDIV_REG3(0x46)); + rk3288_writel(lvds, RK3288_LVDS_CH0_REGD, + RK3288_LVDS_PLL_PREDIV_REGD(0x0a)); + rk3288_writel(lvds, RK3288_LVDS_CH0_REG20, + RK3288_LVDS_CH0_REG20_LSB); + + rk3288_writel(lvds, RK3288_LVDS_CFG_REGC, + RK3288_LVDS_CFG_REGC_PLL_ENABLE); + rk3288_writel(lvds, RK3288_LVDS_CFG_REG21, + RK3288_LVDS_CFG_REG21_TX_ENABLE); return 0; } -static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds) +static void rk3288_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); + rk3288_writel(lvds, RK3288_LVDS_CFG_REG21, + RK3288_LVDS_CFG_REG21_TX_ENABLE); + rk3288_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); + ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON7, val); if (ret != 0) DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); @@ -188,29 +230,8 @@ static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds) 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) +static int rk3288_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; @@ -234,22 +255,19 @@ static void rockchip_lvds_grf_config(struct drm_encoder *encoder, 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) { + ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON7, val); + if (ret) DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret); - return; - } + + return ret; } -static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds, - struct drm_encoder *encoder) +static int rk3288_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; @@ -258,56 +276,162 @@ static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds, if (ret) val |= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT; - ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val); + ret = regmap_write(lvds->grf, RK3288_LVDS_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) +static void rk3288_lvds_encoder_enable(struct drm_encoder *encoder) { - struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct rockchip_lvds *lvds = encoder_to_lvds(encoder); + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; + int ret; - s->output_mode = ROCKCHIP_OUT_MODE_P888; - s->output_type = DRM_MODE_CONNECTOR_LVDS; + drm_panel_prepare(lvds->panel); - return 0; + ret = rk3288_lvds_poweron(lvds); + if (ret < 0) { + DRM_DEV_ERROR(lvds->dev, "failed to power on LVDS: %d\n", ret); + drm_panel_unprepare(lvds->panel); + return; + } + + ret = rk3288_lvds_grf_config(encoder, mode); + if (ret) { + DRM_DEV_ERROR(lvds->dev, "failed to configure LVDS: %d\n", ret); + drm_panel_unprepare(lvds->panel); + return; + } + + ret = rk3288_lvds_set_vop_source(lvds, encoder); + if (ret) { + DRM_DEV_ERROR(lvds->dev, "failed to set VOP source: %d\n", ret); + drm_panel_unprepare(lvds->panel); + return; + } + + drm_panel_enable(lvds->panel); +} + +static void rk3288_lvds_encoder_disable(struct drm_encoder *encoder) +{ + struct rockchip_lvds *lvds = encoder_to_lvds(encoder); + + drm_panel_disable(lvds->panel); + rk3288_lvds_poweroff(lvds); + drm_panel_unprepare(lvds->panel); +} + +static int px30_lvds_poweron(struct rockchip_lvds *lvds) +{ + int ret; + + ret = pm_runtime_get_sync(lvds->dev); + if (ret < 0) { + DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret); + return ret; + } + + /* Enable LVDS mode */ + return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1, + PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1), + PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1)); +} + +static void px30_lvds_poweroff(struct rockchip_lvds *lvds) +{ + regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1, + PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1), + PX30_LVDS_MODE_EN(0) | PX30_LVDS_P2S_EN(0)); + + pm_runtime_put(lvds->dev); +} + +static int px30_lvds_grf_config(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct rockchip_lvds *lvds = encoder_to_lvds(encoder); + + if (lvds->output != DISPLAY_OUTPUT_LVDS) { + DRM_DEV_ERROR(lvds->dev, "Unsupported display output %d\n", + lvds->output); + return -EINVAL; + } + + /* Set format */ + return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1, + PX30_LVDS_FORMAT(lvds->format), + PX30_LVDS_FORMAT(lvds->format)); +} + +static int px30_lvds_set_vop_source(struct rockchip_lvds *lvds, + struct drm_encoder *encoder) +{ + int vop; + + vop = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder); + if (vop < 0) + return vop; + + return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1, + PX30_LVDS_VOP_SEL(1), + PX30_LVDS_VOP_SEL(vop)); } -static void rockchip_lvds_encoder_enable(struct drm_encoder *encoder) +static void px30_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); + + ret = px30_lvds_poweron(lvds); + if (ret) { + DRM_DEV_ERROR(lvds->dev, "failed to power on LVDS: %d\n", ret); drm_panel_unprepare(lvds->panel); + return; + } + + ret = px30_lvds_grf_config(encoder, mode); + if (ret) { + DRM_DEV_ERROR(lvds->dev, "failed to configure LVDS: %d\n", ret); + drm_panel_unprepare(lvds->panel); + return; } - rockchip_lvds_grf_config(encoder, mode); - rockchip_lvds_set_vop_source(lvds, encoder); + + ret = px30_lvds_set_vop_source(lvds, encoder); + if (ret) { + DRM_DEV_ERROR(lvds->dev, "failed to set VOP source: %d\n", ret); + drm_panel_unprepare(lvds->panel); + return; + } + drm_panel_enable(lvds->panel); } -static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder) +static void px30_lvds_encoder_disable(struct drm_encoder *encoder) { struct rockchip_lvds *lvds = encoder_to_lvds(encoder); drm_panel_disable(lvds->panel); - rockchip_lvds_poweroff(lvds); + px30_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, +struct drm_encoder_helper_funcs rk3288_lvds_encoder_helper_funcs = { + .enable = rk3288_lvds_encoder_enable, + .disable = rk3288_lvds_encoder_disable, + .atomic_check = rockchip_lvds_encoder_atomic_check, +}; + +static const +struct drm_encoder_helper_funcs px30_lvds_encoder_helper_funcs = { + .enable = px30_lvds_encoder_enable, + .disable = px30_lvds_encoder_disable, .atomic_check = rockchip_lvds_encoder_atomic_check, }; @@ -315,11 +439,88 @@ static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = { .destroy = drm_encoder_cleanup, }; +static int rk3288_lvds_probe(struct platform_device *pdev, + struct rockchip_lvds *lvds) +{ + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lvds->regs = devm_ioremap_resource(lvds->dev, res); + if (IS_ERR(lvds->regs)) + return PTR_ERR(lvds->regs); + + lvds->pclk = devm_clk_get(lvds->dev, "pclk_lvds"); + if (IS_ERR(lvds->pclk)) { + DRM_DEV_ERROR(lvds->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(lvds->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(lvds->dev, "no default pinctrl state\n"); + devm_kfree(lvds->dev, lvds->pins); + lvds->pins = NULL; + } + } + + ret = clk_prepare(lvds->pclk); + if (ret < 0) { + DRM_DEV_ERROR(lvds->dev, "failed to prepare pclk_lvds\n"); + return ret; + } + + return 0; +} + +static int px30_lvds_probe(struct platform_device *pdev, + struct rockchip_lvds *lvds) +{ + int ret; + + /* MSB */ + ret = regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1, + PX30_LVDS_MSBSEL(1), + PX30_LVDS_MSBSEL(1)); + if (ret) + return ret; + + /* PHY */ + lvds->dphy = devm_phy_get(&pdev->dev, "dphy"); + if (IS_ERR(lvds->dphy)) + return PTR_ERR(lvds->dphy); + + phy_init(lvds->dphy); + if (ret) + return ret; + + phy_set_mode(lvds->dphy, PHY_MODE_LVDS); + if (ret) + return ret; + + return phy_power_on(lvds->dphy); +} + 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, + .probe = rk3288_lvds_probe, + .helper_funcs = &rk3288_lvds_encoder_helper_funcs, +}; + +static const struct rockchip_lvds_soc_data px30_lvds_data = { + .probe = px30_lvds_probe, + .helper_funcs = &px30_lvds_encoder_helper_funcs, }; static const struct of_device_id rockchip_lvds_dt_ids[] = { @@ -327,6 +528,10 @@ static const struct of_device_id rockchip_lvds_dt_ids[] = { .compatible = "rockchip,rk3288-lvds", .data = &rk3288_lvds_data }, + { + .compatible = "rockchip,px30-lvds", + .data = &px30_lvds_data + }, {} }; MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids); @@ -378,7 +583,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, /* default set it as output rgb */ lvds->output = DISPLAY_OUTPUT_RGB; else - lvds->output = lvds_name_to_output(name); + lvds->output = rockchip_lvds_name_to_output(name); if (lvds->output < 0) { DRM_DEV_ERROR(dev, "invalid output type [%s]\n", name); @@ -390,7 +595,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, /* default set it as format vesa 18 */ lvds->format = LVDS_VESA_18; else - lvds->format = lvds_name_to_format(name); + lvds->format = rockchip_lvds_name_to_format(name); if (lvds->format < 0) { DRM_DEV_ERROR(dev, "invalid data-mapping format [%s]\n", name); @@ -410,7 +615,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, goto err_put_remote; } - drm_encoder_helper_add(encoder, &rockchip_lvds_encoder_helper_funcs); + drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs); if (lvds->panel) { connector = &lvds->connector; @@ -471,8 +676,10 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master, void *data) { struct rockchip_lvds *lvds = dev_get_drvdata(dev); + const struct drm_encoder_helper_funcs *encoder_funcs; - rockchip_lvds_encoder_disable(&lvds->encoder); + encoder_funcs = lvds->soc_data->helper_funcs; + encoder_funcs->disable(&lvds->encoder); if (lvds->panel) drm_panel_detach(lvds->panel); pm_runtime_disable(dev); @@ -490,7 +697,6 @@ 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) @@ -506,37 +712,6 @@ static int rockchip_lvds_probe(struct platform_device *pdev) 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)) { @@ -544,13 +719,14 @@ static int rockchip_lvds_probe(struct platform_device *pdev) 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"); + ret = lvds->soc_data->probe(pdev, lvds); + if (ret) { + DRM_DEV_ERROR(dev, "Platform initialization failed\n"); return ret; } + + dev_set_drvdata(dev, lvds); + ret = component_add(&pdev->dev, &rockchip_lvds_component_ops); if (ret < 0) { DRM_DEV_ERROR(dev, "failed to add component\n"); |