1d46d4047SPhilipp Tomsich /*
2d46d4047SPhilipp Tomsich * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
3d46d4047SPhilipp Tomsich * Copyright (c) 2015 Google, Inc
4d46d4047SPhilipp Tomsich * Copyright 2014 Rockchip Inc.
5d46d4047SPhilipp Tomsich *
6d46d4047SPhilipp Tomsich * SPDX-License-Identifier: GPL-2.0+
7d46d4047SPhilipp Tomsich */
8d46d4047SPhilipp Tomsich
9d46d4047SPhilipp Tomsich #include <common.h>
10d46d4047SPhilipp Tomsich #include <display.h>
11d46d4047SPhilipp Tomsich #include <dm.h>
12d46d4047SPhilipp Tomsich #include <regmap.h>
13d46d4047SPhilipp Tomsich #include <syscon.h>
14d46d4047SPhilipp Tomsich #include <video.h>
15d46d4047SPhilipp Tomsich #include <asm/hardware.h>
16d46d4047SPhilipp Tomsich #include <asm/io.h>
17d46d4047SPhilipp Tomsich #include <asm/arch/clock.h>
18d46d4047SPhilipp Tomsich #include <asm/arch/grf_rk3288.h>
19d46d4047SPhilipp Tomsich #include "rk_vop.h"
20d46d4047SPhilipp Tomsich
21d46d4047SPhilipp Tomsich DECLARE_GLOBAL_DATA_PTR;
22d46d4047SPhilipp Tomsich
rk3288_set_pin_polarity(struct udevice * dev,enum vop_modes mode,u32 polarity)23d46d4047SPhilipp Tomsich static void rk3288_set_pin_polarity(struct udevice *dev,
24d46d4047SPhilipp Tomsich enum vop_modes mode, u32 polarity)
25d46d4047SPhilipp Tomsich {
26d46d4047SPhilipp Tomsich struct rk_vop_priv *priv = dev_get_priv(dev);
27d46d4047SPhilipp Tomsich struct rk3288_vop *regs = priv->regs;
28d46d4047SPhilipp Tomsich
29d46d4047SPhilipp Tomsich /* The RK3328 VOP (v3.1) has its polarity configuration in ctrl0 */
30d46d4047SPhilipp Tomsich clrsetbits_le32(®s->dsp_ctrl0,
31d46d4047SPhilipp Tomsich M_DSP_DCLK_POL | M_DSP_DEN_POL |
32d46d4047SPhilipp Tomsich M_DSP_VSYNC_POL | M_DSP_HSYNC_POL,
33d46d4047SPhilipp Tomsich V_DSP_PIN_POL(polarity));
34d46d4047SPhilipp Tomsich }
35d46d4047SPhilipp Tomsich
rk3288_set_io_vsel(struct udevice * dev)36d46d4047SPhilipp Tomsich static void rk3288_set_io_vsel(struct udevice *dev)
37d46d4047SPhilipp Tomsich {
38d46d4047SPhilipp Tomsich struct rk3288_grf *grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
39d46d4047SPhilipp Tomsich
40d46d4047SPhilipp Tomsich /* lcdc(vop) iodomain select 1.8V */
41d46d4047SPhilipp Tomsich rk_setreg(&grf->io_vsel, 1 << 0);
42d46d4047SPhilipp Tomsich }
43d46d4047SPhilipp Tomsich
44d46d4047SPhilipp Tomsich /*
45d46d4047SPhilipp Tomsich * Try some common regulators. We should really get these from the
46d46d4047SPhilipp Tomsich * device tree somehow.
47d46d4047SPhilipp Tomsich */
48d46d4047SPhilipp Tomsich static const char * const rk3288_regulator_names[] = {
49d46d4047SPhilipp Tomsich "vcc18_lcd",
50d46d4047SPhilipp Tomsich "VCC18_LCD",
51d46d4047SPhilipp Tomsich "vdd10_lcd_pwren_h",
52d46d4047SPhilipp Tomsich "vdd10_lcd",
53d46d4047SPhilipp Tomsich "VDD10_LCD",
54d46d4047SPhilipp Tomsich "vcc33_lcd"
55d46d4047SPhilipp Tomsich };
56d46d4047SPhilipp Tomsich
rk3288_vop_probe(struct udevice * dev)57d46d4047SPhilipp Tomsich static int rk3288_vop_probe(struct udevice *dev)
58d46d4047SPhilipp Tomsich {
59d46d4047SPhilipp Tomsich /* Before relocation we don't need to do anything */
60d46d4047SPhilipp Tomsich if (!(gd->flags & GD_FLG_RELOC))
61d46d4047SPhilipp Tomsich return 0;
62d46d4047SPhilipp Tomsich
63d46d4047SPhilipp Tomsich /* Set the LCDC(vop) iodomain to 1.8V */
64d46d4047SPhilipp Tomsich rk3288_set_io_vsel(dev);
65d46d4047SPhilipp Tomsich
66d46d4047SPhilipp Tomsich /* Probe regulators required for the RK3288 VOP */
67d46d4047SPhilipp Tomsich rk_vop_probe_regulators(dev, rk3288_regulator_names,
68d46d4047SPhilipp Tomsich ARRAY_SIZE(rk3288_regulator_names));
69d46d4047SPhilipp Tomsich
70d46d4047SPhilipp Tomsich return rk_vop_probe(dev);
71d46d4047SPhilipp Tomsich }
72d46d4047SPhilipp Tomsich
rk_vop_remove(struct udevice * dev)73*f418676eSSimon Glass static int rk_vop_remove(struct udevice *dev)
74*f418676eSSimon Glass {
75*f418676eSSimon Glass struct rk_vop_priv *priv = dev_get_priv(dev);
76*f418676eSSimon Glass struct rk3288_vop *regs = priv->regs;
77*f418676eSSimon Glass
78*f418676eSSimon Glass setbits_le32(®s->sys_ctrl, V_STANDBY_EN(1));
79*f418676eSSimon Glass
80*f418676eSSimon Glass /* wait frame complete (60Hz) to enter standby */
81*f418676eSSimon Glass mdelay(17);
82*f418676eSSimon Glass
83*f418676eSSimon Glass return 0;
84*f418676eSSimon Glass }
85*f418676eSSimon Glass
86d46d4047SPhilipp Tomsich struct rkvop_driverdata rk3288_driverdata = {
87d46d4047SPhilipp Tomsich .features = VOP_FEATURE_OUTPUT_10BIT,
88d46d4047SPhilipp Tomsich .set_pin_polarity = rk3288_set_pin_polarity,
89d46d4047SPhilipp Tomsich };
90d46d4047SPhilipp Tomsich
91d46d4047SPhilipp Tomsich static const struct udevice_id rk3288_vop_ids[] = {
92d46d4047SPhilipp Tomsich { .compatible = "rockchip,rk3288-vop",
93d46d4047SPhilipp Tomsich .data = (ulong)&rk3288_driverdata },
94d46d4047SPhilipp Tomsich { }
95d46d4047SPhilipp Tomsich };
96d46d4047SPhilipp Tomsich
97d46d4047SPhilipp Tomsich static const struct video_ops rk3288_vop_ops = {
98d46d4047SPhilipp Tomsich };
99d46d4047SPhilipp Tomsich
100d46d4047SPhilipp Tomsich U_BOOT_DRIVER(rk_vop) = {
101d46d4047SPhilipp Tomsich .name = "rk3288_vop",
102d46d4047SPhilipp Tomsich .id = UCLASS_VIDEO,
103d46d4047SPhilipp Tomsich .of_match = rk3288_vop_ids,
104d46d4047SPhilipp Tomsich .ops = &rk3288_vop_ops,
105d46d4047SPhilipp Tomsich .bind = rk_vop_bind,
106d46d4047SPhilipp Tomsich .probe = rk3288_vop_probe,
107*f418676eSSimon Glass .remove = rk_vop_remove,
108d46d4047SPhilipp Tomsich .priv_auto_alloc_size = sizeof(struct rk_vop_priv),
109d46d4047SPhilipp Tomsich };
110