/*
- * drivers/video/rockchip/lcdc/rk31xx_lcdc.c
+ * drivers/video/rockchip/transmitter/rk31xx_lvds.c
*
* Copyright (C) 2014 ROCKCHIP, Inc.
* Author: zhuangwenlong<zwl@rock-chips.com>
#define grf_writel(v,offset) \
do { \
writel_relaxed(v, RK_GRF_VIRT + offset); \
- dsb(); \
+ dsb(sy); \
} while (0)
{
lvds->pclk = devm_clk_get(lvds->dev, "pclk_lvds");
if (IS_ERR(lvds->pclk)) {
- dev_err(lvds->dev, "get clk failed\n");
+ dev_err(lvds->dev, "get pclk failed\n");
return PTR_ERR(lvds->pclk);
}
-
- lvds->pd = devm_clk_get(lvds->dev,"pd_lvds");
- if (IS_ERR(lvds->pd)) {
- dev_err(lvds->dev, "get clk failed\n");
- return PTR_ERR(lvds->pd);
- }
+
+ lvds->ctrl_pclk = devm_clk_get(lvds->dev, "pclk_lvds_ctl");
+ if (IS_ERR(lvds->ctrl_pclk)) {
+ dev_err(lvds->dev, "get ctrl pclk failed\n");
+ return PTR_ERR(lvds->ctrl_pclk);
+ }
+
+ if (lvds->data->soc_type == LVDS_SOC_RK312X) {
+ lvds->ctrl_hclk = devm_clk_get(lvds->dev, "hclk_vio_h2p");
+ if (IS_ERR(lvds->ctrl_hclk)) {
+ dev_err(lvds->dev, "get ctrl hclk failed\n");
+ return PTR_ERR(lvds->ctrl_hclk);
+ }
+ } else {
+ lvds->pd = devm_clk_get(lvds->dev, "pd_lvds");
+ if (IS_ERR(lvds->pd)) {
+ dev_err(lvds->dev, "get pd_lvds failed\n");
+ return PTR_ERR(lvds->pd);
+ }
+ }
+
return 0;
}
static int rk31xx_lvds_clk_enable(struct rk_lvds_device *lvds)
{
if (!lvds->clk_on) {
- clk_prepare_enable(lvds->pd);
clk_prepare_enable(lvds->pclk);
+ clk_prepare_enable(lvds->ctrl_pclk);
+ if (lvds->data->soc_type == LVDS_SOC_RK312X)
+ clk_prepare_enable(lvds->ctrl_hclk);
+ else
+ clk_prepare_enable(lvds->pd);
lvds->clk_on = true;
}
{
if (lvds->clk_on) {
clk_disable_unprepare(lvds->pclk);
- clk_disable_unprepare(lvds->pd);
+ if (lvds->data->soc_type == LVDS_SOC_RK312X)
+ clk_disable_unprepare(lvds->ctrl_hclk);
+ else
+ clk_disable_unprepare(lvds->pd);
+ clk_disable_unprepare(lvds->ctrl_pclk);
lvds->clk_on = false;
}
struct rk_lvds_device *lvds = rk31xx_lvds;
if (lvds->screen.type == SCREEN_LVDS) {
- /* power up lvds pll and bandgap */
- lvds_msk_reg(lvds, MIPIPHY_REGEA,
- m_BG_POWER_DOWN | m_PLL_POWER_DOWN,
- v_BG_POWER_DOWN(0) | v_PLL_POWER_DOWN(0));
+ /* set VOCM 900 mv and V-DIFF 350 mv */
+ lvds_msk_reg(lvds, MIPIPHY_REGE4, m_VOCM | m_DIFF_V,
+ v_VOCM(0) | v_DIFF_V(2));
+
+ /* power up lvds pll and ldo */
+ lvds_msk_reg(lvds, MIPIPHY_REG1,
+ m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN,
+ v_SYNC_RST(0) | v_LDO_PWR_DOWN(0) | v_PLL_PWR_DOWN(0));
+
+ /* enable lvds lane and power on pll */
+ lvds_writel(lvds, MIPIPHY_REGEB,
+ v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) |
+ v_LANE3_EN(1) | v_LANECLK_EN(1) | v_PLL_PWR_OFF(0));
/* enable lvds */
lvds_msk_reg(lvds, MIPIPHY_REGE3,
{
struct rk_lvds_device *lvds = rk31xx_lvds;
+ /* disable lvds lane and power off pll */
+ lvds_writel(lvds, MIPIPHY_REGEB,
+ v_LANE0_EN(0) | v_LANE1_EN(0) | v_LANE2_EN(0) |
+ v_LANE3_EN(0) | v_LANECLK_EN(0) | v_PLL_PWR_OFF(1));
+
/* power down lvds pll and bandgap */
- lvds_msk_reg(lvds, MIPIPHY_REGEA, m_BG_POWER_DOWN | m_PLL_POWER_DOWN,
- v_BG_POWER_DOWN(1) | v_PLL_POWER_DOWN(1));
+ lvds_msk_reg(lvds, MIPIPHY_REG1,
+ m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN,
+ v_SYNC_RST(1) | v_LDO_PWR_DOWN(1) | v_PLL_PWR_DOWN(1));
+
/* disable lvds */
lvds_msk_reg(lvds, MIPIPHY_REGE3, m_LVDS_EN | m_TTL_EN,
v_LVDS_EN(0) | v_TTL_EN(0));
static int rk31xx_lvds_disable(void)
{
struct rk_lvds_device *lvds = rk31xx_lvds;
+ u32 val;
- if (!lvds->sys_state)
+ if (unlikely(!lvds) || !lvds->sys_state)
return 0;
+ if (lvds->data->soc_type == LVDS_SOC_RK3368) {
+ val = v_RK3368_LVDSMODE_EN(0) | v_RK3368_MIPIPHY_TTL_EN(0);
+ lvds_grf_writel(lvds, GRF_SOC_CON7_LVDS, val);
+ } else {
+ grf_writel(v_LVDSMODE_EN(0) | v_MIPIPHY_TTL_EN(0), RK312X_GRF_LVDS_CON0);
+ }
- grf_writel(v_LVDSMODE_EN(0) | v_MIPIPHY_TTL_EN(0), RK312X_GRF_LVDS_CON0);
-
- rk31xx_lvds_pwr_off();
+ rk31xx_lvds_pwr_off();
rk31xx_lvds_clk_disable(lvds);
+
+#if !defined(CONFIG_RK_FPGA)
+#ifdef CONFIG_PINCTRL
+ if (lvds->screen.type == SCREEN_RGB) {
+ if (lvds->dev->pins) {
+ pinctrl_select_state(lvds->dev->pins->p,
+ lvds->dev->pins->sleep_state);
+ } else if (lvds->pins && !IS_ERR(lvds->pins->sleep_state)) {
+ pinctrl_select_state(lvds->pins->p,
+ lvds->pins->sleep_state);
+ }
+ }
+#endif
+#endif
lvds->sys_state = false;
return 0;
}
struct rk_screen *screen)
{
u32 val = 0;
+ u32 delay_times = 20;
/* if LVDS transmitter source from VOP, vop_dclk need get invert
* set iomux in dts pinctrl
*/
- val = 0;
- val |= v_LVDSMODE_EN(1) | v_MIPIPHY_TTL_EN(0); /* enable lvds mode */
- val |= v_LVDS_DATA_SEL(LVDS_DATA_FROM_LCDC); /* config data source */
- val |= v_LVDS_OUTPUT_FORMAT(screen->lvds_format); /* config lvds_format */
- val |= v_LVDS_MSBSEL(LVDS_MSB_D7); /* LSB receive mode */
- grf_writel(val, RK312X_GRF_LVDS_CON0);
-
- /* enable lvds lane */
- val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) |
- v_LANECLK_EN(1);
- lvds_writel(lvds, MIPIPHY_REG0, val);
+ if (lvds->data->soc_type == LVDS_SOC_RK3368) {
+ /* enable lvds mode */
+ val |= v_RK3368_LVDSMODE_EN(1) | v_RK3368_MIPIPHY_TTL_EN(0);
+ /* config data source */
+ /*val |= v_LVDS_DATA_SEL(LVDS_DATA_FROM_LCDC); */
+ /* config lvds_format */
+ val |= v_RK3368_LVDS_OUTPUT_FORMAT(screen->lvds_format);
+ /* LSB receive mode */
+ val |= v_RK3368_LVDS_MSBSEL(LVDS_MSB_D7);
+ val |= v_RK3368_MIPIPHY_LANE0_EN(1) |
+ v_RK3368_MIPIDPI_FORCEX_EN(1);
+ /*rk3368 RK3368_GRF_SOC_CON7 = 0X0041C*/
+ /*grf_writel(val, 0x0041C);*/
+ lvds_grf_writel(lvds, GRF_SOC_CON7_LVDS, val);
+ } else {
+ /* enable lvds mode */
+ val |= v_LVDSMODE_EN(1) | v_MIPIPHY_TTL_EN(0);
+ /* config data source */
+ val |= v_LVDS_DATA_SEL(LVDS_DATA_FROM_LCDC);
+ /* config lvds_format */
+ val |= v_LVDS_OUTPUT_FORMAT(screen->lvds_format);
+ /* LSB receive mode */
+ val |= v_LVDS_MSBSEL(LVDS_MSB_D7);
+ val |= v_MIPIPHY_LANE0_EN(1) | v_MIPIDPI_FORCEX_EN(1);
+ /*rk312x RK312X_GRF_LVDS_CON0 = 0X00150*/
+ grf_writel(val, 0X00150);
+ }
+ /* digital internal disable */
+ lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0));
/* set pll prediv and fbdiv */
- lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(1) | v_FBDIV_MSB(0));
- lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(7));
+ lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0));
+ lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28));
+
+ lvds_writel(lvds, MIPIPHY_REGE8, 0xfc);
/* set lvds mode and reset phy config */
- val = v_LVDS_MODE_EN(1) | v_TTL_MODE_EN(0) | v_MIPI_MODE_EN(0) |
- v_MSB_SEL(1) | v_DIG_INTER_RST(1);
- lvds_writel(lvds, MIPIPHY_REGE0, val);
+ lvds_msk_reg(lvds, MIPIPHY_REGE0,
+ m_MSB_SEL | m_DIG_INTER_RST,
+ v_MSB_SEL(1) | v_DIG_INTER_RST(1));
- lvds_writel(lvds, MIPIPHY_REGE1, 0x92);
-#if 0
- lvds_writel(lvds, MIPIPHY_REGE2, 0xa0); /* timing */
- lvds_writel(lvds, MIPIPHY_REGE7, 0xfc); /* phase */
+ /* power on pll and enable lane */
+ rk31xx_lvds_pwr_on();
+
+ /* delay for waitting pll lock on */
+ while (delay_times--) {
+ if (lvds_phy_lockon(lvds)) {
+ msleep(1);
+ break;
+ }
+ udelay(100);
+ }
+ /* digital internal enable */
+ lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1));
+
+#if 0
+ lvds_writel(lvds, MIPIPHY_REGE2, 0xa0); /* timing */
+ lvds_writel(lvds, MIPIPHY_REGE7, 0xfc); /* phase */
#endif
- rk31xx_lvds_pwr_on();
}
{
u32 val = 0;
- /* iomux to lcdc */
- grf_writel(0xffff5555, RK312X_GRF_GPIO2B_IOMUX);
- grf_writel(0x00ff0055, RK312X_GRF_GPIO2C_IOMUX);
- grf_writel(0x77771111, 0x00e8); /* RK312X_GRF_GPIO2C_IOMUX2 */
- grf_writel(0x700c1008, RK312X_GRF_GPIO2D_IOMUX);
-
- val |= v_LVDSMODE_EN(0) | v_MIPIPHY_TTL_EN(1); /* enable lvds mode */
- val |= v_LVDS_DATA_SEL(LVDS_DATA_FROM_LCDC); /* config data source */
- grf_writel(val, RK312X_GRF_LVDS_CON0);
-
- /* set pll prediv and fbdiv */
- lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(1) | v_FBDIV_MSB(0));
- lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(7));
+ if (lvds->data->soc_type == LVDS_SOC_RK3368) {
+ /* iomux to lcdc */
+#ifdef CONFIG_PINCTRL
+ if (lvds->pins && !IS_ERR(lvds->pins->default_state))
+ pinctrl_select_state(lvds->pins->p,
+ lvds->pins->default_state);
+#endif
+ lvds_dsi_writel(lvds, 0x0, 0x4);/*set clock lane enable*/
+ /* enable lvds mode */
+ val |= v_RK3368_LVDSMODE_EN(0) | v_RK3368_MIPIPHY_TTL_EN(1) |
+ v_RK3368_MIPIPHY_LANE0_EN(1) |
+ v_RK3368_MIPIDPI_FORCEX_EN(1);
+ lvds_grf_writel(lvds, GRF_SOC_CON7_LVDS, val);
+ val = v_RK3368_FORCE_JETAG(0);
+ lvds_grf_writel(lvds, GRF_SOC_CON15_LVDS, val);
+ /*val = v_MIPITTL_CLK_EN(1) | v_MIPITTL_LANE0_EN(1) |
+ v_MIPITTL_LANE1_EN(1) | v_MIPITTL_LANE2_EN(1) |
+ v_MIPITTL_LANE3_EN(1);
+ grf_writel(val, RK312X_GRF_SOC_CON1);*/
+ } else {
+ /* iomux to lcdc */
+#if defined(CONFIG_RK_FPGA)
+ grf_writel(0xffff5555, RK312X_GRF_GPIO2B_IOMUX);
+ grf_writel(0x00ff0055, RK312X_GRF_GPIO2C_IOMUX);
+ grf_writel(0x77771111, 0x00e8); /* RK312X_GRF_GPIO2C_IOMUX2 */
+ grf_writel(0x700c1004, RK312X_GRF_GPIO2D_IOMUX);
+#else
+#ifdef CONFIG_PINCTRL
+ if (lvds->pins && !IS_ERR(lvds->pins->default_state))
+ pinctrl_select_state(lvds->pins->p,
+ lvds->pins->default_state);
+#endif
+#endif
+ /* enable lvds mode */
+ val |= v_LVDSMODE_EN(0) | v_MIPIPHY_TTL_EN(1);
+ /* config data source */
+ val |= v_LVDS_DATA_SEL(LVDS_DATA_FROM_LCDC);
+ grf_writel(0xffff0380, RK312X_GRF_LVDS_CON0);
+
+ val = v_MIPITTL_CLK_EN(1) | v_MIPITTL_LANE0_EN(1) |
+ v_MIPITTL_LANE1_EN(1) | v_MIPITTL_LANE2_EN(1) |
+ v_MIPITTL_LANE3_EN(1);
+ grf_writel(val, RK312X_GRF_SOC_CON1);
+ }
+ /* enable lane */
+ lvds_writel(lvds, MIPIPHY_REG0, 0x7f);
+ val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) |
+ v_LANECLK_EN(1) | v_PLL_PWR_OFF(1);
+ lvds_writel(lvds, MIPIPHY_REGEB, val);
/* set ttl mode and reset phy config */
val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) |
v_MSB_SEL(1) | v_DIG_INTER_RST(1);
lvds_writel(lvds, MIPIPHY_REGE0, val);
- lvds_writel(lvds, MIPIPHY_REGE1, 0x92);
-
- /* enable ttl */
rk31xx_lvds_pwr_on();
}
static int rk31xx_lvds_en(void)
{
struct rk_lvds_device *lvds = rk31xx_lvds;
- struct rk_screen *screen = &lvds->screen;
+ struct rk_screen *screen;
- if (lvds->sys_state)
+ if (unlikely(!lvds))//|| lvds->sys_state)
return 0;
+ screen = &lvds->screen;
rk_fb_get_prmry_screen(screen);
/* enable clk */
.dsp_pwr_on = rk31xx_lvds_pwr_on,
.dsp_pwr_off = rk31xx_lvds_pwr_off,
};
+#if defined(CONFIG_OF)
+static struct rk_lvds_drvdata rk31xx_lvds_drvdata = {
+ .soc_type = LVDS_SOC_RK312X,
+};
+
+static struct rk_lvds_drvdata rk3368_lvds_drvdata = {
+ .soc_type = LVDS_SOC_RK3368,
+};
+
+
+static const struct of_device_id rk31xx_lvds_dt_ids[] = {
+ {.compatible = "rockchip,rk31xx-lvds",
+ .data = (void *)&rk31xx_lvds_drvdata,},
+ {.compatible = "rockchip,rk3368-lvds",
+ .data = (void *)&rk3368_lvds_drvdata,},
+ {}
+};
+
+/*MODULE_DEVICE_TABLE(of, rk31xx_lvds_dt_ids);*/
+
+#endif
static int rk31xx_lvds_probe(struct platform_device *pdev)
{
struct rk_lvds_device *lvds;
struct resource *res;
struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
int ret = 0;
if (!np) {
return -ENOMEM;
}
lvds->dev = &pdev->dev;
+ match = of_match_node(rk31xx_lvds_dt_ids, np);
+ lvds->data = (struct rk_lvds_drvdata *)match->data;
+ dev_info(lvds->dev, "%s,type=%d\n",
+ __func__, lvds->data->soc_type);
rk_fb_get_prmry_screen(&lvds->screen);
if ((lvds->screen.type != SCREEN_RGB) &&
platform_set_drvdata(pdev, lvds);
dev_set_name(lvds->dev, "rk31xx-lvds");
+#ifdef CONFIG_PINCTRL
+ if (lvds->dev->pins == NULL && lvds->screen.type == SCREEN_RGB) {
+ lvds->pins = devm_kzalloc(lvds->dev, sizeof(*(lvds->pins)),
+ GFP_KERNEL);
+ if (!lvds->pins) {
+ dev_err(lvds->dev, "kzalloc lvds pins failed\n");
+ return -ENOMEM;
+ }
+
+ lvds->pins->p = devm_pinctrl_get(lvds->dev);
+ if (IS_ERR(lvds->pins->p)) {
+ dev_info(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");
+ lvds->pins->sleep_state =
+ pinctrl_lookup_state(lvds->pins->p, "sleep");
+ if (IS_ERR(lvds->pins->default_state)) {
+ dev_info(lvds->dev, "no default pinctrl state\n");
+ devm_kfree(lvds->dev, lvds->pins);
+ lvds->pins = NULL;
+ }
+ }
+ }
+
+#endif
/* lvds regs on MIPIPHY_REG */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mipi_lvds_phy");
lvds->regbase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(lvds->regbase)) {
- dev_err(&pdev->dev, "ioremap reg failed\n");
+ dev_err(&pdev->dev, "ioremap mipi-lvds phy reg failed\n");
return PTR_ERR(lvds->regbase);
}
+ /* pll lock on status reg that is MIPICTRL Register */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mipi_lvds_ctl");
+ lvds->ctrl_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(lvds->ctrl_reg)) {
+ dev_err(&pdev->dev, "ioremap mipi-lvds ctl reg failed\n");
+ return PTR_ERR(lvds->ctrl_reg);
+ }
+#ifdef CONFIG_MFD_SYSCON
+ if (lvds->data->soc_type == LVDS_SOC_RK3368) {
+ lvds->grf_lvds_base =
+ syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(lvds->grf_lvds_base)) {
+ dev_err(&pdev->dev, "can't find rockchip,grf property\n");
+ return PTR_ERR(lvds->grf_lvds_base);
+ }
+ }
+#endif
ret = rk31xx_lvds_clk_init(lvds);
if(ret < 0)
goto err_clk_init;
- if (support_uboot_display())
+ if (support_uboot_display()) {
rk31xx_lvds_clk_enable(lvds);
+ /*lvds->sys_state = true;*/
+ }
rk31xx_lvds = lvds;
rk_fb_trsm_ops_register(&trsm_lvds_ops, SCREEN_LVDS);
return;
}
-#if defined(CONFIG_OF)
-static const struct of_device_id rk31xx_lvds_dt_ids[] = {
- {.compatible = "rockchip,rk31xx-lvds",},
- {}
-};
-#endif
static struct platform_driver rk31xx_lvds_driver = {
.driver = {