2 * drivers/video/rockchip/lcdc/rk31xx_lcdc.c
4 * Copyright (C) 2014 ROCKCHIP, Inc.
5 * Author: zhuangwenlong<zwl@rock-chips.com>
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/kernel.h>
17 #include <linux/init.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
21 #include <linux/types.h>
22 #include <linux/i2c.h>
23 #include <linux/rk_fb.h>
24 #include <linux/clk.h>
25 #include <linux/delay.h>
26 #include <linux/rockchip/iomap.h>
27 #include <linux/rockchip/grf.h>
28 #include "rk31xx_lvds.h"
31 #define grf_readl(offset) readl_relaxed(RK_GRF_VIRT + offset)
32 #define grf_writel(v,offset) \
34 writel_relaxed(v, RK_GRF_VIRT + offset); \
39 static struct rk_lvds_device *rk31xx_lvds;
41 static int rk31xx_lvds_clk_init(struct rk_lvds_device *lvds)
43 lvds->pclk = devm_clk_get(lvds->dev, "pclk_lvds");
44 if (IS_ERR(lvds->pclk)) {
45 dev_err(lvds->dev, "get clk failed\n");
46 return PTR_ERR(lvds->pclk);
49 lvds->pd = devm_clk_get(lvds->dev,"pd_lvds");
50 if (IS_ERR(lvds->pd)) {
51 dev_err(lvds->dev, "get clk failed\n");
52 return PTR_ERR(lvds->pd);
57 static int rk31xx_lvds_clk_enable(struct rk_lvds_device *lvds)
60 clk_prepare_enable(lvds->pd);
61 clk_prepare_enable(lvds->pclk);
68 static int rk31xx_lvds_clk_disable(struct rk_lvds_device *lvds)
71 clk_disable_unprepare(lvds->pclk);
72 clk_disable_unprepare(lvds->pd);
79 static int rk31xx_lvds_pwr_on(void)
81 struct rk_lvds_device *lvds = rk31xx_lvds;
83 if (lvds->screen.type == SCREEN_LVDS) {
84 /* power up lvds pll and bandgap */
85 lvds_msk_reg(lvds, MIPIPHY_REGEA,
86 m_BG_POWER_DOWN | m_PLL_POWER_DOWN,
87 v_BG_POWER_DOWN(0) | v_PLL_POWER_DOWN(0));
90 lvds_msk_reg(lvds, MIPIPHY_REGE3,
91 m_MIPI_EN | m_LVDS_EN | m_TTL_EN,
92 v_MIPI_EN(0) | v_LVDS_EN(1) | v_TTL_EN(0));
94 lvds_msk_reg(lvds, MIPIPHY_REGE3,
95 m_MIPI_EN | m_LVDS_EN | m_TTL_EN,
96 v_MIPI_EN(0) | v_LVDS_EN(0) | v_TTL_EN(1));
101 static int rk31xx_lvds_pwr_off(void)
103 struct rk_lvds_device *lvds = rk31xx_lvds;
105 /* power down lvds pll and bandgap */
106 lvds_msk_reg(lvds, MIPIPHY_REGEA, m_BG_POWER_DOWN | m_PLL_POWER_DOWN,
107 v_BG_POWER_DOWN(1) | v_PLL_POWER_DOWN(1));
109 lvds_msk_reg(lvds, MIPIPHY_REGE3, m_LVDS_EN | m_TTL_EN,
110 v_LVDS_EN(0) | v_TTL_EN(0));
114 static int rk31xx_lvds_disable(void)
116 struct rk_lvds_device *lvds = rk31xx_lvds;
118 if (!lvds->sys_state)
121 grf_writel(v_LVDSMODE_EN(0) | v_MIPIPHY_TTL_EN(0), RK312X_GRF_LVDS_CON0);
123 rk31xx_lvds_pwr_off();
124 rk31xx_lvds_clk_disable(lvds);
125 lvds->sys_state = false;
129 static void rk31xx_output_lvds(struct rk_lvds_device *lvds,
130 struct rk_screen *screen)
134 /* if LVDS transmitter source from VOP, vop_dclk need get invert
135 * set iomux in dts pinctrl
138 val |= v_LVDSMODE_EN(1) | v_MIPIPHY_TTL_EN(0); /* enable lvds mode */
139 val |= v_LVDS_DATA_SEL(LVDS_DATA_FROM_LCDC); /* config data source */
140 val |= v_LVDS_OUTPUT_FORMAT(screen->lvds_format); /* config lvds_format */
141 val |= v_LVDS_MSBSEL(LVDS_MSB_D7); /* LSB receive mode */
142 grf_writel(val, RK312X_GRF_LVDS_CON0);
144 /* enable lvds lane */
145 val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) |
147 lvds_writel(lvds, MIPIPHY_REG0, val);
149 /* set pll prediv and fbdiv */
150 lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(1) | v_FBDIV_MSB(0));
151 lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(7));
153 /* set lvds mode and reset phy config */
154 val = v_LVDS_MODE_EN(1) | v_TTL_MODE_EN(0) | v_MIPI_MODE_EN(0) |
155 v_MSB_SEL(1) | v_DIG_INTER_RST(1);
156 lvds_writel(lvds, MIPIPHY_REGE0, val);
158 lvds_writel(lvds, MIPIPHY_REGE1, 0x92);
160 lvds_writel(lvds, MIPIPHY_REGE2, 0xa0); /* timing */
161 lvds_writel(lvds, MIPIPHY_REGE7, 0xfc); /* phase */
163 rk31xx_lvds_pwr_on();
167 static void rk31xx_output_lvttl(struct rk_lvds_device *lvds,
168 struct rk_screen *screen)
173 grf_writel(0xffff5555, RK312X_GRF_GPIO2B_IOMUX);
174 grf_writel(0x00ff0055, RK312X_GRF_GPIO2C_IOMUX);
175 grf_writel(0x77771111, 0x00e8); /* RK312X_GRF_GPIO2C_IOMUX2 */
176 grf_writel(0x700c1008, RK312X_GRF_GPIO2D_IOMUX);
178 val |= v_LVDSMODE_EN(0) | v_MIPIPHY_TTL_EN(1); /* enable lvds mode */
179 val |= v_LVDS_DATA_SEL(LVDS_DATA_FROM_LCDC); /* config data source */
180 grf_writel(val, RK312X_GRF_LVDS_CON0);
182 /* set pll prediv and fbdiv */
183 lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(1) | v_FBDIV_MSB(0));
184 lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(7));
186 /* set ttl mode and reset phy config */
187 val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) |
188 v_MSB_SEL(1) | v_DIG_INTER_RST(1);
189 lvds_writel(lvds, MIPIPHY_REGE0, val);
191 lvds_writel(lvds, MIPIPHY_REGE1, 0x92);
194 rk31xx_lvds_pwr_on();
198 static int rk31xx_lvds_en(void)
200 struct rk_lvds_device *lvds = rk31xx_lvds;
201 struct rk_screen *screen = &lvds->screen;
206 rk_fb_get_prmry_screen(screen);
209 rk31xx_lvds_clk_enable(lvds);
211 switch (screen->type) {
213 rk31xx_output_lvds(lvds, screen);
216 rk31xx_output_lvttl(lvds, screen);
219 printk("unsupport screen type\n");
223 lvds->sys_state = true;
227 static struct rk_fb_trsm_ops trsm_lvds_ops = {
228 .enable = rk31xx_lvds_en,
229 .disable = rk31xx_lvds_disable,
230 .dsp_pwr_on = rk31xx_lvds_pwr_on,
231 .dsp_pwr_off = rk31xx_lvds_pwr_off,
234 static int rk31xx_lvds_probe(struct platform_device *pdev)
236 struct rk_lvds_device *lvds;
237 struct resource *res;
238 struct device_node *np = pdev->dev.of_node;
242 dev_err(&pdev->dev, "Don't find lvds device tree node.\n");
246 lvds = devm_kzalloc(&pdev->dev, sizeof(struct rk_lvds_device), GFP_KERNEL);
248 dev_err(&pdev->dev, "kzalloc rk31xx lvds failed\n");
251 lvds->dev = &pdev->dev;
253 rk_fb_get_prmry_screen(&lvds->screen);
254 if ((lvds->screen.type != SCREEN_RGB) &&
255 (lvds->screen.type != SCREEN_LVDS)) {
256 dev_err(&pdev->dev, "screen is not lvds/rgb!\n");
258 goto err_screen_type;
261 platform_set_drvdata(pdev, lvds);
262 dev_set_name(lvds->dev, "rk31xx-lvds");
264 /* lvds regs on MIPIPHY_REG */
265 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
266 lvds->regbase = devm_ioremap_resource(&pdev->dev, res);
267 if (IS_ERR(lvds->regbase)) {
268 dev_err(&pdev->dev, "ioremap reg failed\n");
269 return PTR_ERR(lvds->regbase);
272 ret = rk31xx_lvds_clk_init(lvds);
276 if (support_uboot_display())
277 rk31xx_lvds_clk_enable(lvds);
280 rk_fb_trsm_ops_register(&trsm_lvds_ops, SCREEN_LVDS);
281 dev_info(&pdev->dev, "rk31xx lvds driver probe success\n");
287 devm_kfree(&pdev->dev, lvds);
292 static int rk31xx_lvds_remove(struct platform_device *pdev)
297 static void rk31xx_lvds_shutdown(struct platform_device *pdev)
302 #if defined(CONFIG_OF)
303 static const struct of_device_id rk31xx_lvds_dt_ids[] = {
304 {.compatible = "rockchip,rk31xx-lvds",},
309 static struct platform_driver rk31xx_lvds_driver = {
311 .name = "rk31xx-lvds",
312 .owner = THIS_MODULE,
313 #if defined(CONFIG_OF)
314 .of_match_table = of_match_ptr(rk31xx_lvds_dt_ids),
317 .probe = rk31xx_lvds_probe,
318 .remove = rk31xx_lvds_remove,
319 .shutdown = rk31xx_lvds_shutdown,
322 static int __init rk31xx_lvds_init(void)
324 return platform_driver_register(&rk31xx_lvds_driver);
327 static void __exit rk31xx_lvds_exit(void)
329 platform_driver_unregister(&rk31xx_lvds_driver);
332 fs_initcall(rk31xx_lvds_init);
333 module_exit(rk31xx_lvds_exit);