10 Commits

Author SHA1 Message Date
ZhengShunQian
a5bb31b08b iommu/rockchip: add compatible string for vpu_mmu
vpu changed its mmu compatible string, modify accordingly.

Signed-off-by: ZhengShunQian <zhengsq@rock-chips.com>
2016-03-22 09:32:24 +08:00
Chris Zhong
024956ae51 CONFIG: Turn on CONFIG_ARM_ERRATA_818325_852422
This errata affects rk3288 and we care about that.  Enable it.

BUG=chrome-os-partner:50137
TEST=CL:If49e61d7825bdfaf0eb3664c42aa9b0ba2fe66b2

Change-Id: Ic9353ab1c5963930772867cd6a66129f48c4cf75
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/329523
Reviewed-by: Olof Johansson <olofj@chromium.org>

Signed-off-by: Chris Zhong <zyw@rock-chips.com>
(cherry picked from commit de081d99917f3571c0b9e3f8ee3d593b70ba03ac)
2016-03-01 09:23:18 +08:00
Douglas Anderson
74a45b7ad6 CHROMIUM: ARM: rockchip: Handle ERRATA 818325 / 852422 for resume
The normal prov-v7.S code doesn't run on the main CPU during resume from
S3.  Apply the errata early in the resume at the same time that we
restore the l2ctlr.

BUG=chrome-os-partner:50137
TEST=CL:If49e61d7825bdfaf0eb3664c42aa9b0ba2fe66b2

Change-Id: I22549b24ee308524edf9db931d6817aa28e5efd3
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/329522
Reviewed-by: Olof Johansson <olofj@chromium.org>
(cherry picked from commit f6f678d14d507b58102c5d5e6f17af2584320934)
2016-03-01 09:23:09 +08:00
Douglas Anderson
ed65feb600 BACKPORT: FROMLIST: ARM: errata: Workaround errata A12 818325/852422 A17 852423
There are several similar errata on Cortex A12 and A17 that all have the
same workaround: setting bit[12] of the Feature Register.  Technically
the list of errata are:

- A12 818325: Execution of an UNPREDICTABLE STR or STM instruction might
  deadlock.  Fixed in r0p1.
- A12 852422: Execution of a sequence of instructions might lead to
  either a data corruption or a CPU deadlock.  Not fixed in any A12s
  yet.
- A17 852423: Execution of a sequence of instructions might lead to
  either a data corruption or a CPU deadlock.  Not fixed in any A17s
  yet.

Since A12 got renamed to A17 it seems likely that there won't be any
future Cortex-A12 cores, so we'll enable for all Cortex-A12.

For Cortex-A17 I believe that all known revisions are affected and that
all knows revisions means <= r1p2.  Presumably if a new A17 was released
it would have this problem fixed.

Note that in <https://patchwork.kernel.org/patch/4735341/> folks
previously expressed opposition to this change because:
A) It was thought to only apply to r0p0 and there were no known r0p0
   boards supported in mainline.
B) It was argued that such a workaround beloned in firmware.

Now that this same fix solves other errata on real boards (like rk3288)
point A) is addressed.

Point B) is impossible to address on boards like rk3288.  On rk3288 the
firmware doesn't stay resident in RAM and isn't involved at all in the
suspend/resume process nor in the SMP bringup process.  That means that
the most the firmware could do would be to set the bit on "core 0" and
this bit would be lost at suspend/resume time.  It is true that we could
write a "generic" solution that saved the boot-time "core 0" value of
this register and applied it at SMP bringup / resume time.  However,
since this register (described as the "Feature Register" in errata)
appears to be undocumented (as far as I can tell) and is only modified
for these errata, that "generic" solution seems questionably cleaner.
The generic solution also won't fix existing users that haven't happened
to do a FW update.

Note that in ARM64 presumably PSCI will be universal and fixes like this
will end up in ATF.  Hopefully we are nearing the end of this style of
errata workaround.

BUG=chrome-os-partner:50137
TEST=CL:If49e61d7825bdfaf0eb3664c42aa9b0ba2fe66b2

Conflicts:
	arch/arm/mm/proc-v7.S
...due to massive re-org upstream that doesn't make sense to pick back.
Note also that while backporting I fixed a few random bugs where we
would apply errata to cores not manufactured by ARM and optimized the
jumps a bit for A8 / A9.  These types of issues have already been fixed
by the reorg upstream.

Change-Id: Id0ecbb83b8da159237d75a33bab82dd4677740c3
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Huang Tao <huangtao@rock-chips.com>
Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
(am from https://patchwork.kernel.org/patch/8441441/)
Reviewed-on: https://chromium-review.googlesource.com/329521
Reviewed-by: Olof Johansson <olofj@chromium.org>

(cherry picked from commit 2498b98fd7946175016af8edde72059d58405ae7)
2016-03-01 09:22:59 +08:00
Yakir Yang
a7ce3801d4 ARM: dts: rk3288-evb: Add lvds device node on rk3288-evb board
Enable LVDS driver on rk3288-evb board, and attch the "cpt,claa070wp03xg"
simple panel to it.

Note that lvds-panel and edp-panel share the same enable-gpios, and one
gpio couldn't request for twice, so just a hack that I delete the enable-gpios
numbers from lvds-panel.

Due to there are only two vop module, that's to say we can't keep enable
eDP / LVDS / HDMI at the same time, so this time we still keep LVDS device
disabled. So if you want to test lvds device, then you should disable the
HDMI or eDP device, and enable the LVDS device, like:

 &hdmi {
        ddc-i2c-bus = <&i2c5>;
-       status = "okay";
+       status = "disabled";
 };

 &lvds {
        rockchip,data-width = <24>;
        rockchip,output = "lvds";
        rockchip,panel = <&lvds_panel>;
-       status = "disabled";
+       status = "okay";
 };

Signed-off-by: Yakir Yang <ykk@rock-chips.com>
(cherry picked from commit ad350853190db8ab1cfca1382ac0e7772d35524c)
2016-01-30 17:04:57 +08:00
Heiko Stuebner
f19f45a1a9 ARM: dts: rockchip: add rk3288 lvds node
Add the basic node for the lvds controller of rk3288 and hook it into the
display-subsystem hirarchy.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
(cherry picked from commit 519eb3b24a1200bf2166d71fdad1d2db20aaaa83)
2016-01-30 17:04:57 +08:00
Heiko Stuebner
656c768a10 ARM: dts: rockchip: add rk3288 lcdc0 pinmux settings
Add pinctrl settings for the configurable lcdc0 signals dclk, den, hsync
and vsync. The lcdc0 data pin configuration is not software controlable.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
(cherry picked from commit a4d71b93437fab66b6f7ad05ad131afac99c0d1c)
2016-01-30 17:04:56 +08:00
Heiko Stuebner
e399f38920 drm/rockchip: enable rgb output of vops for all other connectors
The socs itself contains encoders for a lot of different outputs. But every
unsupported connector will be routed through the lvds, as it controls the
pins in question.
Therefore enable the lvds output for all of those.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
(cherry picked from commit 2757c4eb2e2c08288c60e534a8ba20c2073edd3a)
2016-01-30 17:04:55 +08:00
Mark Yao
c9e027044b drm/rockchip: Add support for Rockchip Soc LVDS
This adds support for Rockchip soc lvds found on rk3288

Signed-off-by: Mark Yao <yzq@rock-chips.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
(cherry picked from commit 0ee45f472d80111d506601949f3be6cb1b967156)
2016-01-30 17:04:55 +08:00
Mark Yao
01f7d46183 dt-bindings: Add documentation for rockchip lvds
Add binding documentation for Rockchip SoC LVDS driver.

Signed-off-by: Mark Yao <yzq@rock-chips.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
(cherry picked from commit c18a4a6d82e98caa24e3f1b9b4475ab6d80d2307)
2016-01-30 17:04:54 +08:00
13 changed files with 955 additions and 39 deletions

View File

@@ -0,0 +1,74 @@
Rockchip RK3288 LVDS interface
================================
Required properties:
- compatible: "rockchip,rk3288-lvds";
- reg: physical base address of the controller and length
of memory mapped region.
- clocks: must include clock specifiers corresponding to entries in the
clock-names property.
- clock-names: must contain "pclk_lvds"
- avdd1v0-supply: regulator phandle for 1.0V analog power
- avdd1v8-supply: regulator phandle for 1.8V analog power
- avdd3v3-supply: regulator phandle for 3.3V analog power
- rockchip,grf: phandle to the general register files syscon
- rockchip,data-mapping: should be "vesa" or "jeida",
This describes how the color bits are laid out in the
serialized LVDS signal.
- rockchip,data-width : should be <18> or <24>;
- rockchip,output: should be "rgb", "lvds" or "duallvds",
This describes the output face.
Required nodes:
The lvds has two video ports as described by
Documentation/devicetree/bindings/media/video-interfaces.txt.
Their connections are modeled using the OF graph bindings specified in
Documentation/devicetree/bindings/graph.txt.
- video port 0 for the VOP inputs
- video port 1 for either a panel or subsequent encoder
Example:
lvds: lvds@ff96c000 {
compatible = "rockchip,rk3288-lvds";
rockchip,grf = <&grf>;
reg = <0xff96c000 0x4000>;
clocks = <&cru PCLK_LVDS_PHY>;
clock-names = "pclk_lvds";
avdd1v0-supply = <&vdd10_lcd>;
avdd1v8-supply = <&vcc18_lcd>;
avdd3v3-supply = <&vcca_33>;
rockchip,data-mapping = "jeida";
rockchip,data-width = <24>;
rockchip,output = "rgb";
ports {
#address-cells = <1>;
#size-cells = <0>;
lvds_in: port@0 {
reg = <0>;
lvds_in_vopb: endpoint@0 {
reg = <0>;
remote-endpoint = <&vopb_out_lvds>;
};
lvds_in_vopl: endpoint@1 {
reg = <1>;
remote-endpoint = <&vopl_out_lvds>;
};
};
lvds_out: port@1 {
reg = <1>;
lvds_out_panel: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};

View File

@@ -1378,19 +1378,32 @@ config ARM_ERRATA_773022
loop buffer may deliver incorrect instructions. This
workaround disables the loop buffer to avoid the erratum.
config ARM_ERRATA_818325
bool "ARM errata: Execution of an UNPREDICTABLE STR or STM instruction might deadlock"
config ARM_ERRATA_818325_852422
bool "ARM errata: A12: some seqs of opposed cond code instrs => deadlock or corruption"
depends on CPU_V7
help
This option enables the workaround for the 818325 Cortex-A12
(r0p0..r0p1-00lac0-rc11) erratum. When a CPU executes a sequence of
two conditional store instructions with opposite condition code and
updating the same register, the system might enter a deadlock if the
second conditional instruction is an UNPREDICTABLE STR or STM
instruction. This workaround setting bit[12] of the Feature Register
prevents the erratum. This bit disables an optimisation applied to a
This option enables the workaround for:
- Cortex-A12 818325: Execution of an UNPREDICTABLE STR or STM
instruction might deadlock. Fixed in r0p1.
- Cortex-A12 852422: Execution of a sequence of instructions might
lead to either a data corruption or a CPU deadlock. Not fixed in
any Cortex-A12 cores yet.
This workaround for all both errata involves setting bit[12] of the
Feature Register. This bit disables an optimisation applied to a
sequence of 2 instructions that use opposing condition codes.
config ARM_ERRATA_852423
bool "ARM errata: A17: some seqs of opposed cond code instrs => deadlock or corruption"
depends on CPU_V7
help
This option enables the workaround for:
- Cortex-A17 852423: Execution of a sequence of instructions might
lead to either a data corruption or a CPU deadlock. Not fixed in
any Cortex-A17 cores yet.
This is identical to Cortex-A12 erratum 852422. It is a separate
config option from the A12 erratum due to the way errata are checked
for and handled.
endmenu
source "arch/arm/common/Kconfig"

View File

@@ -94,7 +94,7 @@
pwms = <&pwm0 0 1000000 PWM_POLARITY_INVERTED>;
};
panel: panel {
edp_panel: edp_dp_panel {
compatible ="sdk,f402","simple-panel";
status = "okay";
power-supply = <&vcc_lcd>;
@@ -104,6 +104,15 @@
backlight = <&backlight>;
};
lvds_panel: lvds_panel {
compatible ="cpt,claa070wp03xg","simple-panel";
status = "okay";
power-supply = <&vcc_lcd>;
pinctrl-names = "default";
pinctrl-0 = <&lcd_cs>;
backlight = <&backlight>;
};
gpio-keys {
compatible = "gpio-keys";
#address-cells = <1>;
@@ -275,7 +284,7 @@
&edp {
status = "okay";
rockchip,panel = <&panel>;
rockchip,panel = <&edp_panel>;
};
&emmc {
@@ -323,6 +332,14 @@
status = "okay";
};
&lvds {
rockchip,data-mapping = "jeida";
rockchip,data-width = <24>;
rockchip,output = "lvds";
rockchip,panel = <&lvds_panel>;
status = "disabled";
};
&vopb {
status = "okay";
};

View File

@@ -664,6 +664,10 @@
reg = <1>;
remote-endpoint = <&hdmi_in_vopb>;
};
vopb_out_lvds: endpoint@2 {
reg = <2>;
remote-endpoint = <&lvds_in_vopb>;
};
};
};
@@ -699,7 +703,10 @@
reg = <1>;
remote-endpoint = <&hdmi_in_vopl>;
};
vopl_out_lvds: endpoint@2 {
reg = <2>;
remote-endpoint = <&lvds_in_vopb>;
};
};
};
@@ -740,6 +747,38 @@
};
};
lvds: lvds@ff96c000 {
compatible = "rockchip,rk3288-lvds";
reg = <0xff96c000 0x4000>;
clocks = <&cru PCLK_LVDS_PHY>;
clock-names = "pclk_lvds";
pinctrl-names = "default";
pinctrl-0 = <&lcdc0_ctl>;
rockchip,grf = <&grf>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
lvds_in: port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
lvds_in_vopb: endpoint@0 {
reg = <0>;
remote-endpoint = <&vopb_out_lvds>;
};
lvds_in_vopl: endpoint@1 {
reg = <1>;
remote-endpoint = <&vopl_out_lvds>;
};
};
};
};
hdmi: hdmi@ff980000 {
compatible = "rockchip,rk3288-dw-hdmi";
reg = <0xff980000 0x20000>;
@@ -812,7 +851,7 @@
};
vpu_mmu: iommu@ff9a0800 {
compatible = "rockchip,iommu";
compatible = "rockchip,vpu_mmu";
reg = <0xff9a0800 0x100>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "vpu_mmu";
@@ -1116,6 +1155,15 @@
};
};
lcdc0 {
lcdc0_ctl: lcdc0-ctl {
rockchip,pins = <1 24 RK_FUNC_1 &pcfg_pull_none>,
<1 25 RK_FUNC_1 &pcfg_pull_none>,
<1 26 RK_FUNC_1 &pcfg_pull_none>,
<1 27 RK_FUNC_1 &pcfg_pull_none>;
};
};
sdmmc {
sdmmc_clk: sdmmc-clk {
rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none>;

View File

@@ -33,7 +33,7 @@ CONFIG_ARCH_ROCKCHIP=y
CONFIG_TEGRA_AHB=y
CONFIG_ARM_THUMBEE=y
CONFIG_ARM_KERNMEM_PERMS=y
CONFIG_ARM_ERRATA_818325=y
CONFIG_ARM_ERRATA_818325_852422=y
CONFIG_SMP=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_AEABI=y

View File

@@ -59,6 +59,16 @@ static void __noreturn rk3288_resume_c(void)
asm("mcr p15, 1, %0, c9, c0, 2" : :
"r" (rk3288_resume_params.l2ctlr));
/* We will have lost this when the CPU powered off */
if (IS_ENABLED(CONFIG_ARM_ERRATA_818325_852422)) {
u32 diag_reg;
asm volatile("mrc p15, 0, %0, c15, c0, 1" : "=r" (diag_reg));
diag_reg |= (1 << 12);
asm volatile("mcr p15, 0, %0, c15, c0, 1" : : "r" (diag_reg));
asm volatile("isb");
}
if (rk3288_resume_params.ddr_resume_f)
rk3288_ddr_resume_early(&rk3288_resume_params.ddr_save_data);

View File

@@ -271,7 +271,7 @@ __v7_setup:
mrc p15, 0, r0, c0, c0, 0 @ read main ID register
and r10, r0, #0xff000000 @ ARM?
teq r10, #0x41000000
bne 3f
bne 6f
and r5, r0, #0x00f00000 @ variant
and r6, r0, #0x0000000f @ revision
orr r6, r6, r5, lsr #20-4 @ combine variant and revision
@@ -302,7 +302,7 @@ __v7_setup:
orreq r10, r10, #(1 << 22) @ set the Write Allocate disable bit
mcreq p15, 1, r10, c9, c0, 2 @ write the L2 cache aux ctrl register
#endif
b 3f
b 6f
/* Cortex-A9 Errata */
2: ldr r10, =0x00000c09 @ Cortex-A9 primary part number
@@ -337,11 +337,35 @@ __v7_setup:
mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register
1:
#endif
b 6f
/* Cortex-A15 Errata */
3: ldr r10, =0x00000c0f @ Cortex-A15 primary part number
/* Cortex-A12 Errata */
3: ldr r10, =0x00000c0d @ Cortex-A12 primary part number
teq r0, r10
bne 4f
#ifdef CONFIG_ARM_ERRATA_818325_852422
mrc p15, 0, r10, c15, c0, 1 @ read diagnostic register
orr r10, r10, #1 << 12 @ set bit #12
mcr p15, 0, r10, c15, c0, 1 @ write diagnostic register
#endif
b 6f
/* Cortex-A17 Errata */
4: ldr r10, =0x00000c0e @ Cortex-A17 primary part number
teq r0, r10
bne 5f
#ifdef CONFIG_ARM_ERRATA_852423
cmp r6, #0x12 @ only present up to r1p2
mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register
orrle r10, r10, #1 << 12 @ set bit #12
mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register
#endif
b 6f
/* Cortex-A15 Errata */
5: ldr r10, =0x00000c0f @ Cortex-A15 primary part number
teq r0, r10
bne 6f
#ifdef CONFIG_ARM_ERRATA_773022
cmp r6, #0x4 @ only present up to r0p4
@@ -350,20 +374,7 @@ __v7_setup:
mcrle p15, 0, r10, c1, c0, 1 @ write aux control register
#endif
/* Cortex-A12 Errata */
4: ldr r10, =0x00000c0d @ Cortex-A12 primary part number
teq r0, r10
bne 5f
#ifdef CONFIG_ARM_ERRATA_818325
teq r6, #0x00 @ present in r0p0
teqne r6, #0x01 @ present in r0p1-00lac0-rc11
mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register
orreq r10, r10, #1 << 12 @ set bit #12
mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
isb
#endif
5: mov r10, #0
6: mov r10, #0
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
#ifdef CONFIG_MMU
mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs

View File

@@ -34,3 +34,12 @@ config ROCKCHIP_EDP
Rockchip rk3288 SoC has eDP TX Controller can be used.
If you have an Embedded DisplayPort Panel, say Y to enable its
driver.
config ROCKCHIP_LVDS
tristate "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.

View File

@@ -7,5 +7,6 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_EDP) += rockchip_edp_core.o rockchip_edp_reg.o
rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o

View File

@@ -1459,20 +1459,16 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
clk_disable(vop->dclk);
switch (vop->connector_type) {
case DRM_MODE_CONNECTOR_LVDS:
VOP_CTRL_SET(vop, rgb_en, 1);
break;
case DRM_MODE_CONNECTOR_eDP:
VOP_CTRL_SET(vop, edp_en, 1);
break;
case DRM_MODE_CONNECTOR_HDMIA:
VOP_CTRL_SET(vop, hdmi_en, 1);
break;
case DRM_MODE_CONNECTOR_LVDS:
default:
/* TODO: undo stuff already done */
DRM_ERROR("unsupport connector_type[%d]\n",
vop->connector_type);
return -EINVAL;
VOP_CTRL_SET(vop, rgb_en, 1);
break;
};
VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);

View File

@@ -0,0 +1,628 @@
/*
* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
* Author:
* 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.
*/
#include <drm/drmP.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/regmap.h>
#include <linux/reset.h>
#include <video/display_timing.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)
/*
* @grf_offset: offset inside the grf regmap for setting the rockchip lvds
*/
struct rockchip_lvds_soc_data {
int grf_soc_con6;
int grf_soc_con7;
};
struct rockchip_lvds {
void *base;
struct device *dev;
void __iomem *regs;
struct regmap *grf;
struct clk *pclk;
const struct rockchip_lvds_soc_data *soc_data;
int output;
int format;
struct drm_device *drm_dev;
struct drm_panel *panel;
struct drm_connector connector;
struct drm_encoder encoder;
struct mutex suspend_lock;
int suspend;
};
static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val)
{
writel_relaxed(val, lvds->regs + offset);
writel_relaxed(val, lvds->regs + offset + 0x100);
}
static inline int lvds_name_to_format(const char *s)
{
if (!s)
return -EINVAL;
if (strncmp(s, "jeida", 6) == 0)
return LVDS_FORMAT_JEIDA;
else if (strncmp(s, "vesa", 6) == 0)
return LVDS_FORMAT_VESA;
return -EINVAL;
}
static inline int lvds_name_to_output(const char *s)
{
if (!s)
return -EINVAL;
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;
ret = clk_enable(lvds->pclk);
if (ret < 0) {
dev_err(lvds->dev, "failed to enable lvds pclk %d\n", ret);
return ret;
}
writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE,
lvds->regs + RK3288_LVDS_CFG_REGC);
writel(RK3288_LVDS_CFG_REG21_TX_ENABLE,
lvds->regs + RK3288_LVDS_CFG_REG21);
return 0;
}
static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds)
{
int ret;
ret = regmap_write(lvds->grf,
lvds->soc_data->grf_soc_con7, 0xffff8000);
if (ret != 0)
dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
writel(RK3288_LVDS_CFG_REG21_TX_DISABLE,
lvds->regs + RK3288_LVDS_CFG_REG21);
writel(RK3288_LVDS_CFG_REGC_PLL_DISABLE,
lvds->regs + RK3288_LVDS_CFG_REGC);
clk_disable(lvds->pclk);
}
static enum drm_connector_status
rockchip_lvds_connector_detect(struct drm_connector *connector, bool force)
{
return connector_status_connected;
}
static void rockchip_lvds_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}
static struct drm_connector_funcs rockchip_lvds_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = rockchip_lvds_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = rockchip_lvds_connector_destroy,
};
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 panel->funcs->get_modes(panel);
}
static struct drm_encoder *
rockchip_lvds_connector_best_encoder(struct drm_connector *connector)
{
struct rockchip_lvds *lvds = connector_to_lvds(connector);
return &lvds->encoder;
}
static enum drm_mode_status rockchip_lvds_connector_mode_valid(
struct drm_connector *connector,
struct drm_display_mode *mode)
{
return MODE_OK;
}
static
struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = {
.get_modes = rockchip_lvds_connector_get_modes,
.mode_valid = rockchip_lvds_connector_mode_valid,
.best_encoder = rockchip_lvds_connector_best_encoder,
};
static void rockchip_lvds_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
int ret;
mutex_lock(&lvds->suspend_lock);
switch (mode) {
case DRM_MODE_DPMS_ON:
if (!lvds->suspend)
goto out;
drm_panel_prepare(lvds->panel);
ret = rockchip_lvds_poweron(lvds);
if (ret < 0) {
drm_panel_unprepare(lvds->panel);
return;
}
drm_panel_enable(lvds->panel);
lvds->suspend = false;
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
if (lvds->suspend)
goto out;
drm_panel_disable(lvds->panel);
rockchip_lvds_poweroff(lvds);
drm_panel_unprepare(lvds->panel);
lvds->suspend = true;
break;
default:
break;
}
out:
mutex_unlock(&lvds->suspend_lock);
}
static bool
rockchip_lvds_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void rockchip_lvds_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted)
{
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
u32 h_bp = mode->htotal - mode->hsync_start;
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;
val = lvds->format;
if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)
val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
else if (lvds->output == DISPLAY_OUTPUT_LVDS)
val |= LVDS_CH0_EN;
else if (lvds->output == DISPLAY_OUTPUT_RGB)
val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
if (h_bp & 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) {
dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
return;
}
if (lvds->output == DISPLAY_OUTPUT_RGB) {
lvds_writel(lvds, RK3288_LVDS_CH0_REG0,
RK3288_LVDS_CH0_REG0_TTL_EN |
RK3288_LVDS_CH0_REG0_LANECK_EN |
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);
lvds_writel(lvds, RK3288_LVDS_CH0_REG2,
RK3288_LVDS_PLL_FBDIV_REG2(0x46));
lvds_writel(lvds, RK3288_LVDS_CH0_REG3,
RK3288_LVDS_PLL_FBDIV_REG3(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);
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);
} else {
lvds_writel(lvds, RK3288_LVDS_CH0_REG0,
RK3288_LVDS_CH0_REG0_LVDS_EN |
RK3288_LVDS_CH0_REG0_LANECK_EN |
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);
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_REG3,
RK3288_LVDS_PLL_FBDIV_REG3(0x46));
lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00);
lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00);
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);
}
dsb();
}
static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds,
struct drm_encoder *encoder)
{
u32 val;
int ret;
ret = rockchip_drm_encoder_get_mux_id(lvds->dev->of_node, encoder);
if (ret < 0)
return ret;
if (ret)
val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
(RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
else
val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val);
if (ret < 0)
return ret;
return 0;
}
static void rockchip_lvds_encoder_prepare(struct drm_encoder *encoder)
{
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
int ret;
ret = rockchip_drm_crtc_mode_config(encoder->crtc,
lvds->connector.connector_type,
ROCKCHIP_OUT_MODE_P888);
if (ret < 0) {
dev_err(lvds->dev, "Could not set crtc mode config: %d\n", ret);
return;
}
ret = rockchip_lvds_set_vop_source(lvds, encoder);
if (ret < 0) {
dev_err(lvds->dev, "Could not set vop source: %d\n", ret);
return;
}
}
static void rockchip_lvds_encoder_commit(struct drm_encoder *encoder)
{
rockchip_lvds_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
}
static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder)
{
rockchip_lvds_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
}
static struct drm_encoder_helper_funcs rockchip_lvds_encoder_helper_funcs = {
.dpms = rockchip_lvds_encoder_dpms,
.mode_fixup = rockchip_lvds_encoder_mode_fixup,
.mode_set = rockchip_lvds_encoder_mode_set,
.prepare = rockchip_lvds_encoder_prepare,
.commit = rockchip_lvds_encoder_commit,
.disable = rockchip_lvds_encoder_disable,
};
static void rockchip_lvds_encoder_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
}
static struct drm_encoder_funcs rockchip_lvds_encoder_funcs = {
.destroy = rockchip_lvds_encoder_destroy,
};
static struct rockchip_lvds_soc_data rk3288_lvds_data = {
.grf_soc_con6 = 0x025c,
.grf_soc_con7 = 0x0260,
};
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;
int ret;
lvds->drm_dev = drm_dev;
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);
if (ret < 0) {
DRM_ERROR("failed to initialize encoder with drm\n");
return ret;
}
drm_encoder_helper_add(encoder, &rockchip_lvds_encoder_helper_funcs);
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_ERROR("failed to initialize connector with drm\n");
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_ERROR("failed to attach connector and encoder\n");
goto err_free_connector;
}
ret = drm_panel_attach(lvds->panel, connector);
if (ret < 0) {
DRM_ERROR("failed to attach connector and encoder\n");
goto err_free_connector;
}
return 0;
err_free_connector:
drm_connector_cleanup(connector);
err_free_encoder:
drm_encoder_cleanup(encoder);
return ret;
}
static void rockchip_lvds_unbind(struct device *dev, struct device *master,
void *data)
{
struct rockchip_lvds *lvds = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
rockchip_lvds_encoder_dpms(&lvds->encoder, DRM_MODE_DPMS_OFF);
drm_panel_detach(lvds->panel);
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;
struct device_node *output_node = NULL;
const struct of_device_id *match;
struct resource *res;
const char *name;
int i, ret;
if (!dev->of_node)
return -ENODEV;
lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
if (!lvds)
return -ENOMEM;
lvds->dev = dev;
lvds->suspend = true;
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->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(lvds->grf)) {
dev_err(dev, "missing rockchip,grf property\n");
return PTR_ERR(lvds->grf);
}
lvds->pclk = devm_clk_get(&pdev->dev, "pclk_lvds");
if (IS_ERR(lvds->pclk)) {
dev_err(dev, "could not get pclk_lvds\n");
return PTR_ERR(lvds->pclk);
}
ret = clk_prepare(lvds->pclk);
if (ret < 0) {
dev_err(dev, "failed to prepare pclk_lvds\n");
return ret;
}
match = of_match_node(rockchip_lvds_dt_ids, dev->of_node);
lvds->soc_data = match->data;
dev_set_drvdata(dev, lvds);
mutex_init(&lvds->suspend_lock);
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 (of_property_read_string(dev->of_node, "rockchip,data-mapping",
&name))
/* default set it as format jeida */
lvds->format = LVDS_FORMAT_JEIDA;
else
lvds->format = lvds_name_to_format(name);
if (of_property_read_u32(dev->of_node, "rockchip,data-width", &i)) {
lvds->format |= LVDS_24BIT;
} else {
if (i == 24) {
lvds->format |= LVDS_24BIT;
} else if (i == 18) {
lvds->format |= LVDS_18BIT;
} else {
dev_err(&pdev->dev,
"rockchip-lvds unsupport data-width[%d]\n", i);
ret = -EINVAL;
goto err_unprepare_pclk;
}
}
output_node = of_parse_phandle(dev->of_node, "rockchip,panel", 0);
if (!output_node) {
DRM_ERROR("failed to find rockchip,panel dt node\n");
return -ENODEV;
}
lvds->panel = of_drm_find_panel(output_node);
of_node_put(output_node);
if (!lvds->panel) {
DRM_ERROR("failed to find panel\n");
return -EPROBE_DEFER;
}
ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
if (ret < 0)
goto err_unprepare_pclk;
return 0;
err_unprepare_pclk:
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),
},
};
module_platform_driver(rockchip_lvds_driver);
MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");
MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
MODULE_DESCRIPTION("ROCKCHIP LVDS Driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
* Author:
* hjc <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
/* 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 (0x01 << 3)
#define LVDS_DUAL (0x01 << 4)
#define LVDS_FMT_1 (0x01 << 5)
#define LVDS_TTL_EN (0x01 << 6)
#define LVDS_START_PHASE_RST_1 (0x01 << 7)
#define LVDS_DCLK_INV (0x01 << 8)
#define LVDS_CH0_EN (0x01 << 11)
#define LVDS_CH1_EN (0x01 << 12)
#define LVDS_PWRDN (0x01 << 15)
#define LVDS_24BIT (0 << 1)
#define LVDS_18BIT (1 << 1)
#define LVDS_FORMAT_VESA (0 << 0)
#define LVDS_FORMAT_JEIDA (1 << 0)
#endif /* _ROCKCHIP_LVDS_ */

View File

@@ -1163,6 +1163,7 @@ static int rk_iommu_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id rk_iommu_dt_ids[] = {
{ .compatible = "rockchip,iommu" },
{ .compatible = "rockchip,vpu_mmu" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rk_iommu_dt_ids);