64b21e6b47
Fixed a readme typo Hopefully doing locale generation correctly now added some new "untested" patches. I tried the emmc patch and the power patch but they didn't seem to change anything: They didnt remove the invalid clk rate emmc errors that seem harmless The HDMI patch seems to be a combination of patches, maybe they fix the sound issue?
734 lines
23 KiB
Diff
734 lines
23 KiB
Diff
From aeb42ff3a2d04e19ff87b1e537e0d84d63132c11 Mon Sep 17 00:00:00 2001
|
|
From: Urja Rannikko <urjaman@gmail.com>
|
|
Date: Wed, 22 Aug 2018 18:36:05 +0000
|
|
Subject: [PATCH] RK3288 HDMI clock hacks combined
|
|
|
|
This is only for my patching convenience, contains these:
|
|
|
|
clk: rockchip: improve rk3288 pll rates for better hdmi output
|
|
dt-bindings: clock: rk3288-cru: Add property to dedicate NPLL for VOPx
|
|
drivers: clk-rk3288: support for dedicating NPLL to a VOP
|
|
dt-bindings: display/rockchip: dw_hdmi: Add property for HDMI frequency list
|
|
drm: dw_hdmi-rockchip: better clock selection logic and dts-based rate list
|
|
dts: rk3288: support for dedicating npll to a vop
|
|
dts: rk3288-veyron-chromebook: dedicate npll to VOP0/HDMI + HDMI rates
|
|
|
|
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
|
|
---
|
|
.../bindings/clock/rockchip,rk3288-cru.txt | 3 +
|
|
.../display/rockchip/dw_hdmi-rockchip.txt | 1 +
|
|
.../boot/dts/rk3288-veyron-chromebook.dtsi | 67 +++++
|
|
arch/arm/boot/dts/rk3288.dtsi | 6 +-
|
|
drivers/clk/rockchip/clk-rk3288.c | 98 +++++--
|
|
drivers/clk/rockchip/clk.h | 3 +
|
|
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 269 ++++++++++++------
|
|
7 files changed, 335 insertions(+), 112 deletions(-)
|
|
|
|
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt
|
|
index 8cb47c39ba53..20724584e0a4 100644
|
|
--- a/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt
|
|
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt
|
|
@@ -16,6 +16,9 @@ Optional Properties:
|
|
|
|
- rockchip,grf: phandle to the syscon managing the "general register files"
|
|
If missing pll rates are not changeable, due to the missing pll lock status.
|
|
+- rockchip,npll-for-vop: u32 0 or 1, dedicates NPLL to a VOP output unit for
|
|
+ more frequency flexibility for the selected VOP output at a cost of
|
|
+ flexibility for other devices. Disabled if not present or -1.
|
|
|
|
Each clock is assigned an identifier and client nodes can use this identifier
|
|
to specify the clock which they consume. All available clocks are defined as
|
|
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
|
|
index adc94fc3c9f8..edeacbbc4f26 100644
|
|
--- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
|
|
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
|
|
@@ -34,6 +34,7 @@ Optional properties
|
|
- clock-names: May contain "cec" as defined in dw_hdmi.txt.
|
|
- clock-names: May contain "grf", power for grf io.
|
|
- clock-names: May contain "vpll", external clock for some hdmi phy.
|
|
+- rockchip,hdmi-rates-hz: List of allowed HDMI frequencies in Hz.
|
|
|
|
Example:
|
|
|
|
diff --git a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
|
|
index b16d570ff029..70ed0b2a9549 100644
|
|
--- a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
|
|
@@ -163,6 +163,25 @@
|
|
};
|
|
};
|
|
|
|
+&cru {
|
|
+ /* Dedicate NPLL for VOP0 / VOP_BIG for HDMI. */
|
|
+ rockchip,npll-for-vop = <0>;
|
|
+ /* The first assigned clocks are DCLK_VOP0 and DCLK_VOP1 */
|
|
+ assigned-clock-parents = <&cru PLL_NPLL>, <&cru PLL_GPLL>;
|
|
+};
|
|
+
|
|
+/* Delete the nodes that allow non-desirable VOP - connector links. That
|
|
+ * is the eDP cannot use vopb and HDMI cannot use vopl. */
|
|
+
|
|
+/delete-node/ &edp_in_vopb;
|
|
+/delete-node/ &vopb_out_edp;
|
|
+/delete-node/ &hdmi_in_vopl;
|
|
+/delete-node/ &vopl_out_hdmi;
|
|
+
|
|
+/* Delete the 500 Mhz GPU opp since that cannot be easily made
|
|
+ * without NPLL. */
|
|
+/delete-node/ &{/gpu-opp-table/opp@500000000};
|
|
+
|
|
&edp {
|
|
status = "okay";
|
|
|
|
@@ -186,6 +205,54 @@
|
|
status = "okay";
|
|
};
|
|
|
|
+&hdmi {
|
|
+ /* These depend on NPLL being dedicated to HDMI use. */
|
|
+ rockchip,hdmi-rates-hz = <
|
|
+ 25176471 /* for 25.175 MHz, 0.006% off */
|
|
+ 25200000
|
|
+ 27000000
|
|
+ 28320000
|
|
+ 30240000
|
|
+ 31500000
|
|
+ 32000000
|
|
+ 33750000
|
|
+ 36000000
|
|
+ 40000000
|
|
+ 49500000
|
|
+ 50000000
|
|
+ 54000000
|
|
+ 57290323 /* for 57.284 MHz, .011 % off */
|
|
+ 65000000
|
|
+ 68250000
|
|
+ 71000000
|
|
+ 72000000
|
|
+ 73250000
|
|
+ 74250000
|
|
+ 74437500 /* for 74.44 MHz, .003% off */
|
|
+ 75000000
|
|
+ 78750000
|
|
+ 78800000
|
|
+ 79500000
|
|
+ 83500000
|
|
+ 85500000
|
|
+ 88750000
|
|
+ 97750000
|
|
+ 101000000
|
|
+ 106500000
|
|
+ 108000000
|
|
+ 115500000
|
|
+ 118666667 /* for 118.68 MHz, .011% off */
|
|
+ 119000000
|
|
+ 121714286 /* for 121.75 MHz, .029% off */
|
|
+ 135000000
|
|
+ 136800000 /* for 136.75 MHz, .037% off */
|
|
+ 146250000
|
|
+ 148500000
|
|
+ 154000000
|
|
+ 162000000 >;
|
|
+};
|
|
+
|
|
+
|
|
&gpio_keys {
|
|
pinctrl-0 = <&pwr_key_l &ap_lid_int_l>;
|
|
lid {
|
|
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
|
|
index d7e49d29ace5..2106ddfdaf06 100644
|
|
--- a/arch/arm/boot/dts/rk3288.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3288.dtsi
|
|
@@ -840,12 +840,14 @@
|
|
rockchip,grf = <&grf>;
|
|
#clock-cells = <1>;
|
|
#reset-cells = <1>;
|
|
- assigned-clocks = <&cru PLL_GPLL>, <&cru PLL_CPLL>,
|
|
+ assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>,
|
|
+ <&cru PLL_GPLL>, <&cru PLL_CPLL>,
|
|
<&cru PLL_NPLL>, <&cru ACLK_CPU>,
|
|
<&cru HCLK_CPU>, <&cru PCLK_CPU>,
|
|
<&cru ACLK_PERI>, <&cru HCLK_PERI>,
|
|
<&cru PCLK_PERI>;
|
|
- assigned-clock-rates = <594000000>, <400000000>,
|
|
+ assigned-clock-rates = <0>, <0>,
|
|
+ <594000000>, <400000000>,
|
|
<500000000>, <300000000>,
|
|
<150000000>, <75000000>,
|
|
<300000000>, <150000000>,
|
|
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
|
|
index 450de24a1b42..7adf85e43078 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3288.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3288.c
|
|
@@ -83,22 +83,43 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
|
|
RK3066_PLL_RATE( 768000000, 1, 64, 2),
|
|
RK3066_PLL_RATE( 742500000, 8, 495, 2),
|
|
RK3066_PLL_RATE( 696000000, 1, 58, 2),
|
|
+ RK3066_PLL_RATE_NB(621000000, 1, 207, 8, 1),
|
|
RK3066_PLL_RATE( 600000000, 1, 50, 2),
|
|
RK3066_PLL_RATE_NB(594000000, 1, 198, 8, 1),
|
|
RK3066_PLL_RATE( 552000000, 1, 46, 2),
|
|
RK3066_PLL_RATE( 504000000, 1, 84, 4),
|
|
RK3066_PLL_RATE( 500000000, 3, 125, 2),
|
|
RK3066_PLL_RATE( 456000000, 1, 76, 4),
|
|
+ RK3066_PLL_RATE( 428000000, 1, 107, 6),
|
|
RK3066_PLL_RATE( 408000000, 1, 68, 4),
|
|
RK3066_PLL_RATE( 400000000, 3, 100, 2),
|
|
+ RK3066_PLL_RATE_NB( 394000000, 1, 197, 12, 1),
|
|
RK3066_PLL_RATE( 384000000, 2, 128, 4),
|
|
RK3066_PLL_RATE( 360000000, 1, 60, 4),
|
|
+ RK3066_PLL_RATE_NB( 356000000, 1, 178, 12, 1),
|
|
+ RK3066_PLL_RATE_NB( 324000000, 1, 189, 14, 1),
|
|
RK3066_PLL_RATE( 312000000, 1, 52, 4),
|
|
- RK3066_PLL_RATE( 300000000, 1, 50, 4),
|
|
- RK3066_PLL_RATE( 297000000, 2, 198, 8),
|
|
+ RK3066_PLL_RATE_NB( 308000000, 1, 154, 12, 1),
|
|
+ RK3066_PLL_RATE_NB( 303000000, 1, 202, 16, 1),
|
|
+ RK3066_PLL_RATE( 300000000, 1, 75, 6),
|
|
+ RK3066_PLL_RATE_NB( 297750000, 2, 397, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 293250000, 2, 391, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 292500000, 1, 195, 16, 1),
|
|
+ RK3066_PLL_RATE( 273600000, 1, 114, 10),
|
|
+ RK3066_PLL_RATE_NB( 273000000, 1, 182, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 270000000, 1, 180, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 266250000, 2, 355, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 256500000, 1, 171, 16, 1),
|
|
RK3066_PLL_RATE( 252000000, 1, 84, 8),
|
|
- RK3066_PLL_RATE( 216000000, 1, 72, 8),
|
|
- RK3066_PLL_RATE( 148500000, 2, 99, 8),
|
|
+ RK3066_PLL_RATE_NB( 250500000, 1, 167, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 243428571, 1, 142, 14, 1),
|
|
+ RK3066_PLL_RATE( 238000000, 1, 119, 12),
|
|
+ RK3066_PLL_RATE_NB( 219750000, 2, 293, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 216000000, 1, 144, 16, 1),
|
|
+ RK3066_PLL_RATE_NB( 213000000, 1, 142, 16, 1),
|
|
+ RK3066_PLL_RATE( 195428571, 1, 114, 14),
|
|
+ RK3066_PLL_RATE( 160000000, 1, 80, 12),
|
|
+ RK3066_PLL_RATE( 157500000, 1, 105, 16),
|
|
RK3066_PLL_RATE( 126000000, 1, 84, 16),
|
|
RK3066_PLL_RATE( 48000000, 1, 64, 32),
|
|
{ /* sentinel */ },
|
|
@@ -177,10 +198,14 @@ PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" };
|
|
PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu" };
|
|
|
|
PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" };
|
|
-PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" };
|
|
-PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" };
|
|
+PNAME_ED(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" };
|
|
+
|
|
+PNAME_ED(mux_pll_src_cgn_pll_nonvop_p) = { "cpll", "gpll", "npll" };
|
|
+PNAME_ED(mux_pll_src_cgn_pll_vop0_p) = { "cpll", "gpll", "npll" };
|
|
+PNAME_ED(mux_pll_src_cgn_pll_vop1_p) = { "cpll", "gpll", "npll" };
|
|
+
|
|
PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usbphy480m_src" };
|
|
-PNAME(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "usbphy480m_src", "npll" };
|
|
+PNAME_ED(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "usbphy480m_src", "npll" };
|
|
|
|
PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "xin24m" };
|
|
PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
|
|
@@ -426,24 +451,24 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 4, GFLAGS),
|
|
|
|
- COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cgn_pll_vop0_p, 0,
|
|
RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 1, GFLAGS),
|
|
- COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cgn_pll_vop1_p, 0,
|
|
RK3288_CLKSEL_CON(29), 6, 2, MFLAGS, 8, 8, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 3, GFLAGS),
|
|
|
|
COMPOSITE_NODIV(SCLK_EDP_24M, "sclk_edp_24m", mux_edp_24m_p, 0,
|
|
RK3288_CLKSEL_CON(28), 15, 1, MFLAGS,
|
|
RK3288_CLKGATE_CON(3), 12, GFLAGS),
|
|
- COMPOSITE(SCLK_EDP, "sclk_edp", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(SCLK_EDP, "sclk_edp", mux_pll_src_cgn_pll_nonvop_p, 0,
|
|
RK3288_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 6, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 13, GFLAGS),
|
|
|
|
- COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_cgn_pll_nonvop_p, 0,
|
|
RK3288_CLKSEL_CON(6), 6, 2, MFLAGS, 0, 6, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 14, GFLAGS),
|
|
- COMPOSITE(SCLK_ISP_JPE, "sclk_isp_jpe", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(SCLK_ISP_JPE, "sclk_isp_jpe", mux_pll_src_cgn_pll_nonvop_p, 0,
|
|
RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS,
|
|
RK3288_CLKGATE_CON(3), 15, GFLAGS),
|
|
|
|
@@ -452,16 +477,16 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0,
|
|
RK3288_CLKGATE_CON(5), 11, GFLAGS),
|
|
|
|
- COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_cgn_pll_nonvop_p, 0,
|
|
RK3288_CLKSEL_CON(39), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
|
RK3288_CLKGATE_CON(13), 13, GFLAGS),
|
|
DIV(HCLK_HEVC, "hclk_hevc", "aclk_hevc", 0,
|
|
RK3288_CLKSEL_CON(40), 12, 2, DFLAGS),
|
|
|
|
- COMPOSITE(SCLK_HEVC_CABAC, "sclk_hevc_cabac", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(SCLK_HEVC_CABAC, "sclk_hevc_cabac", mux_pll_src_cgn_pll_nonvop_p, 0,
|
|
RK3288_CLKSEL_CON(42), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
|
RK3288_CLKGATE_CON(13), 14, GFLAGS),
|
|
- COMPOSITE(SCLK_HEVC_CORE, "sclk_hevc_core", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(SCLK_HEVC_CORE, "sclk_hevc_core", mux_pll_src_cgn_pll_nonvop_p, 0,
|
|
RK3288_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
|
RK3288_CLKGATE_CON(13), 15, GFLAGS),
|
|
|
|
@@ -535,7 +560,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
COMPOSITE(0, "sclk_tspout", mux_tspout_p, 0,
|
|
RK3288_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
|
RK3288_CLKGATE_CON(4), 11, GFLAGS),
|
|
- COMPOSITE(0, "sclk_tsp", mux_pll_src_cpll_gpll_npll_p, 0,
|
|
+ COMPOSITE(0, "sclk_tsp", mux_pll_src_cgn_pll_nonvop_p, 0,
|
|
RK3288_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
|
RK3288_CLKGATE_CON(4), 10, GFLAGS),
|
|
|
|
@@ -895,6 +920,7 @@ static void __init rk3288_clk_init(struct device_node *np)
|
|
{
|
|
struct rockchip_clk_provider *ctx;
|
|
struct clk *clk;
|
|
+ s32 npll_vop = -1;
|
|
|
|
rk3288_cru_base = of_iomap(np, 0);
|
|
if (!rk3288_cru_base) {
|
|
@@ -902,6 +928,46 @@ static void __init rk3288_clk_init(struct device_node *np)
|
|
return;
|
|
}
|
|
|
|
+ if (!of_property_read_s32(np, "rockchip,npll-for-vop", &npll_vop)) {
|
|
+ if ((npll_vop < -1) || (npll_vop > 1)) {
|
|
+ pr_warn("%s: invalid VOP to dedicate NPLL to: %d\n",
|
|
+ __func__, npll_vop);
|
|
+ } else if (npll_vop >= 0) {
|
|
+ unsigned int vop_clk_id;
|
|
+ const char ** npll_names;
|
|
+ const char ** non_npll_names;
|
|
+ int i;
|
|
+
|
|
+ /* Firstly, not-VOP needs to not use npll */
|
|
+ mux_pll_src_npll_cpll_gpll_p[0] = "dummy_npll";
|
|
+ mux_pll_src_cgn_pll_nonvop_p[2] = "dummy_npll";
|
|
+ mux_pll_src_cpll_gll_usb_npll_p[3] = "dummy_npll";
|
|
+
|
|
+ /* Then the npll VOP needs to only use npll, and the other one not use npll. */
|
|
+ if (npll_vop) {
|
|
+ vop_clk_id = DCLK_VOP1;
|
|
+ npll_names = mux_pll_src_cgn_pll_vop1_p;
|
|
+ non_npll_names = mux_pll_src_cgn_pll_vop0_p;
|
|
+ } else {
|
|
+ vop_clk_id = DCLK_VOP0;
|
|
+ npll_names = mux_pll_src_cgn_pll_vop0_p;
|
|
+ non_npll_names = mux_pll_src_cgn_pll_vop1_p;
|
|
+ }
|
|
+ npll_names[0] = "dummy_cpll";
|
|
+ npll_names[1] = "dummy_gpll";
|
|
+ non_npll_names[2] = "dummy_npll";
|
|
+
|
|
+ /* Lastly the npll-dedicated-VOP needs to be able to control npll. */
|
|
+ for (i = 0; i < ARRAY_SIZE(rk3288_clk_branches); i++) {
|
|
+ if (rk3288_clk_branches[i].id == vop_clk_id) {
|
|
+ rk3288_clk_branches[i].flags |= CLK_SET_RATE_PARENT;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ pr_debug("%s: npll dedicated for VOP %d\n", __func__, npll_vop);
|
|
+ }
|
|
+ }
|
|
+
|
|
ctx = rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS);
|
|
if (IS_ERR(ctx)) {
|
|
pr_err("%s: rockchip clk init failed\n", __func__);
|
|
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
|
|
index ef601dded32c..8e2f70d62f03 100644
|
|
--- a/drivers/clk/rockchip/clk.h
|
|
+++ b/drivers/clk/rockchip/clk.h
|
|
@@ -343,6 +343,9 @@ struct clk *rockchip_clk_register_muxgrf(const char *name,
|
|
|
|
#define PNAME(x) static const char *const x[] __initconst
|
|
|
|
+/* For when you want to be able to modify the pointers. */
|
|
+#define PNAME_ED(x) static const char * x[] __initdata
|
|
+
|
|
enum rockchip_clk_branch_type {
|
|
branch_composite,
|
|
branch_mux,
|
|
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
index 11309a2a4e43..740b0aeea796 100644
|
|
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
|
@@ -49,122 +49,141 @@ struct rockchip_hdmi {
|
|
struct clk *vpll_clk;
|
|
struct clk *grf_clk;
|
|
struct dw_hdmi *hdmi;
|
|
+ u32* rates;
|
|
+ u32 rates_cnt;
|
|
};
|
|
|
|
+#define CLK_SLOP(clk) ((clk) / 1000)
|
|
+#define CLK_PLUS_SLOP(clk) ((clk) + CLK_SLOP(clk))
|
|
+
|
|
#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
|
|
|
|
+/* These were the rates allowed by the driver before rates list in device tree,
|
|
+ * so keep them around as a fallback */
|
|
+static const u32 dw_hdmi_fallback_rates[] = {
|
|
+ 27000000,
|
|
+ 36000000,
|
|
+ 40000000,
|
|
+ 54000000,
|
|
+ 65000000,
|
|
+ 66000000,
|
|
+ 74250000,
|
|
+ 83500000,
|
|
+ 106500000,
|
|
+ 108000000,
|
|
+ 146250000,
|
|
+ 148500000
|
|
+};
|
|
+
|
|
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
|
|
{
|
|
- 27000000, {
|
|
- { 0x00b3, 0x0000},
|
|
- { 0x2153, 0x0000},
|
|
- { 0x40f3, 0x0000}
|
|
+ 30666000, {
|
|
+ { 0x00b3, 0x0000 },
|
|
+ { 0x2153, 0x0000 },
|
|
+ { 0x40f3, 0x0000 },
|
|
+ },
|
|
+ }, {
|
|
+ 36800000, {
|
|
+ { 0x00b3, 0x0000 },
|
|
+ { 0x2153, 0x0000 },
|
|
+ { 0x40a2, 0x0001 },
|
|
},
|
|
- }, {
|
|
- 36000000, {
|
|
- { 0x00b3, 0x0000},
|
|
- { 0x2153, 0x0000},
|
|
- { 0x40f3, 0x0000}
|
|
+ }, {
|
|
+ 46000000, {
|
|
+ { 0x00b3, 0x0000 },
|
|
+ { 0x2142, 0x0001 },
|
|
+ { 0x40a2, 0x0001 },
|
|
},
|
|
- }, {
|
|
- 40000000, {
|
|
- { 0x00b3, 0x0000},
|
|
- { 0x2153, 0x0000},
|
|
- { 0x40f3, 0x0000}
|
|
+ }, {
|
|
+ 61333000, {
|
|
+ { 0x0072, 0x0001 },
|
|
+ { 0x2142, 0x0001 },
|
|
+ { 0x40a2, 0x0001 },
|
|
},
|
|
- }, {
|
|
- 54000000, {
|
|
- { 0x0072, 0x0001},
|
|
- { 0x2142, 0x0001},
|
|
- { 0x40a2, 0x0001},
|
|
+ }, {
|
|
+ 73600000, {
|
|
+ { 0x0072, 0x0001 },
|
|
+ { 0x2142, 0x0001 },
|
|
+ { 0x4061, 0x0002 },
|
|
},
|
|
- }, {
|
|
- 65000000, {
|
|
- { 0x0072, 0x0001},
|
|
- { 0x2142, 0x0001},
|
|
- { 0x40a2, 0x0001},
|
|
+ }, {
|
|
+ 92000000, {
|
|
+ { 0x0072, 0x0001 },
|
|
+ { 0x2145, 0x0002 },
|
|
+ { 0x4061, 0x0002 },
|
|
},
|
|
- }, {
|
|
- 66000000, {
|
|
- { 0x013e, 0x0003},
|
|
- { 0x217e, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 122666000, {
|
|
+ { 0x0051, 0x0002 },
|
|
+ { 0x2145, 0x0002 },
|
|
+ { 0x4061, 0x0002 },
|
|
},
|
|
- }, {
|
|
- 74250000, {
|
|
- { 0x0072, 0x0001},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 147200000, {
|
|
+ { 0x0051, 0x0002 },
|
|
+ { 0x2145, 0x0002 },
|
|
+ { 0x4064, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 83500000, {
|
|
- { 0x0072, 0x0001},
|
|
+ }, {
|
|
+ 184000000, {
|
|
+ { 0x0051, 0x0002 },
|
|
+ { 0x214c, 0x0003 },
|
|
+ { 0x4064, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 108000000, {
|
|
- { 0x0051, 0x0002},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 226666000, {
|
|
+ { 0x0040, 0x0003 },
|
|
+ { 0x214c, 0x0003 },
|
|
+ { 0x4064, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 106500000, {
|
|
- { 0x0051, 0x0002},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 272000000, {
|
|
+ { 0x0040, 0x0003 },
|
|
+ { 0x214c, 0x0003 },
|
|
+ { 0x5a64, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 146250000, {
|
|
- { 0x0051, 0x0002},
|
|
- { 0x2145, 0x0002},
|
|
- { 0x4061, 0x0002}
|
|
+ }, {
|
|
+ 340000000, {
|
|
+ { 0x0040, 0x0003 },
|
|
+ { 0x3b4c, 0x0003 },
|
|
+ { 0x5a64, 0x0003 },
|
|
},
|
|
- }, {
|
|
- 148500000, {
|
|
- { 0x0051, 0x0003},
|
|
- { 0x214c, 0x0003},
|
|
- { 0x4064, 0x0003}
|
|
+ }, {
|
|
+ 600000000, {
|
|
+ { 0x1a40, 0x0003 },
|
|
+ { 0x3b4c, 0x0003 },
|
|
+ { 0x5a64, 0x0003 },
|
|
},
|
|
- }, {
|
|
+ }, {
|
|
~0UL, {
|
|
- { 0x00a0, 0x000a },
|
|
- { 0x2001, 0x000f },
|
|
- { 0x4002, 0x000f },
|
|
+ { 0x0000, 0x0000 },
|
|
+ { 0x0000, 0x0000 },
|
|
+ { 0x0000, 0x0000 },
|
|
},
|
|
}
|
|
};
|
|
|
|
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
|
|
- /* pixelclk bpp8 bpp10 bpp12 */
|
|
+ /* pixelclk bpp8 bpp10 bpp12 */
|
|
{
|
|
- 40000000, { 0x0018, 0x0018, 0x0018 },
|
|
- }, {
|
|
- 65000000, { 0x0028, 0x0028, 0x0028 },
|
|
- }, {
|
|
- 66000000, { 0x0038, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 74250000, { 0x0028, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 83500000, { 0x0028, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 146250000, { 0x0038, 0x0038, 0x0038 },
|
|
- }, {
|
|
- 148500000, { 0x0000, 0x0038, 0x0038 },
|
|
- }, {
|
|
- ~0UL, { 0x0000, 0x0000, 0x0000},
|
|
- }
|
|
+ 600000000, { 0x0000, 0x0000, 0x0000 },
|
|
+ }, {
|
|
+ ~0UL, { 0x0000, 0x0000, 0x0000 },
|
|
+ },
|
|
};
|
|
|
|
static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
|
|
/*pixelclk symbol term vlev*/
|
|
- { 74250000, 0x8009, 0x0004, 0x0272},
|
|
- { 148500000, 0x802b, 0x0004, 0x028d},
|
|
- { 297000000, 0x8039, 0x0005, 0x028d},
|
|
- { ~0UL, 0x0000, 0x0000, 0x0000}
|
|
+ { CLK_PLUS_SLOP(74250000), 0x8009, 0x0004, 0x0272},
|
|
+ { CLK_PLUS_SLOP(165000000), 0x802b, 0x0004, 0x0209},
|
|
+ { CLK_PLUS_SLOP(297000000), 0x8039, 0x0005, 0x028d},
|
|
+ { ~0UL, 0x0000, 0x0000, 0x0000}
|
|
};
|
|
|
|
static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
|
|
{
|
|
struct device_node *np = hdmi->dev->of_node;
|
|
+ int rates_cnt;
|
|
|
|
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
|
if (IS_ERR(hdmi->regmap)) {
|
|
@@ -192,26 +211,55 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
|
|
return PTR_ERR(hdmi->grf_clk);
|
|
}
|
|
|
|
+ if ((rates_cnt = of_property_count_u32_elems(np, "rockchip,hdmi-rates-hz")) > 0) {
|
|
+ int rv;
|
|
+ u32 *rates = devm_kmalloc_array(hdmi->dev, rates_cnt, sizeof(u32), GFP_KERNEL);
|
|
+ if (!rates)
|
|
+ return -ENOMEM;
|
|
+ rv = of_property_read_u32_array(np, "rockchip,hdmi-rates-hz", rates, rates_cnt);
|
|
+ if (rv)
|
|
+ return rv;
|
|
+ hdmi->rates = rates;
|
|
+ hdmi->rates_cnt = rates_cnt;
|
|
+ } else {
|
|
+ rates_cnt = ARRAY_SIZE(dw_hdmi_fallback_rates);
|
|
+ hdmi->rates = devm_kmalloc_array(hdmi->dev, rates_cnt, sizeof(u32), GFP_KERNEL);
|
|
+ if (!hdmi->rates)
|
|
+ return -ENOMEM;
|
|
+ memcpy(hdmi->rates, dw_hdmi_fallback_rates, rates_cnt * sizeof(u32));
|
|
+ hdmi->rates_cnt = rates_cnt;
|
|
+ }
|
|
+
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
static enum drm_mode_status
|
|
-dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
|
|
+dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder,
|
|
const struct drm_display_mode *mode)
|
|
{
|
|
- const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
|
|
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
|
|
int pclk = mode->clock * 1000;
|
|
- bool valid = false;
|
|
+ int num_rates = hdmi->rates_cnt;
|
|
int i;
|
|
|
|
- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
|
|
- if (pclk == mpll_cfg[i].mpixelclock) {
|
|
- valid = true;
|
|
- break;
|
|
- }
|
|
+ /*
|
|
+ * Pixel clocks we support are always < 2GHz and so fit in an
|
|
+ * int. We should make sure source rate does too so we don't get
|
|
+ * overflow when we multiply by 1000.
|
|
+ */
|
|
+ if (mode->clock > INT_MAX / 1000)
|
|
+ return MODE_BAD;
|
|
+
|
|
+ for (i = 0; i < num_rates; i++) {
|
|
+ int slop = CLK_SLOP(pclk);
|
|
+
|
|
+ if ((pclk >= hdmi->rates[i] - slop) &&
|
|
+ (pclk <= hdmi->rates[i] + slop))
|
|
+ return MODE_OK;
|
|
}
|
|
|
|
- return (valid) ? MODE_OK : MODE_BAD;
|
|
+ return MODE_BAD;
|
|
}
|
|
|
|
static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
|
|
@@ -227,7 +275,39 @@ dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
|
|
const struct drm_display_mode *mode,
|
|
struct drm_display_mode *adj_mode)
|
|
{
|
|
- return true;
|
|
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
|
|
+ int pclk = adj_mode->clock * 1000;
|
|
+ int best_diff = INT_MAX;
|
|
+ int best_clock = 0;
|
|
+ int slop;
|
|
+ int i;
|
|
+
|
|
+ /* Pick the best clock */
|
|
+ for (i = 0; i < hdmi->rates_cnt; i++) {
|
|
+ int diff = hdmi->rates[i] - pclk;
|
|
+
|
|
+ if (diff < 0)
|
|
+ diff = -diff;
|
|
+ if (diff < best_diff) {
|
|
+ best_diff = diff;
|
|
+ best_clock = hdmi->rates[i];
|
|
+
|
|
+ /* Bail early if we're exact */
|
|
+ if (best_diff == 0)
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Double check that it's OK */
|
|
+ slop = CLK_SLOP(pclk);
|
|
+ if ((pclk >= best_clock - slop) && (pclk <= best_clock + slop)) {
|
|
+ adj_mode->clock = DIV_ROUND_UP(best_clock, 1000);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ /* Shoudn't be here; we should have said rate wasn't valid */
|
|
+ dev_warn(hdmi->dev, "tried to set invalid rate %d\n", adj_mode->clock);
|
|
+ return false;
|
|
}
|
|
|
|
static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
|
|
@@ -280,6 +360,7 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
|
|
}
|
|
|
|
static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
|
|
+ .mode_valid = dw_hdmi_rockchip_encoder_mode_valid,
|
|
.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
|
|
.mode_set = dw_hdmi_rockchip_encoder_mode_set,
|
|
.enable = dw_hdmi_rockchip_encoder_enable,
|
|
@@ -294,7 +375,6 @@ static struct rockchip_hdmi_chip_data rk3288_chip_data = {
|
|
};
|
|
|
|
static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
|
|
- .mode_valid = dw_hdmi_rockchip_mode_valid,
|
|
.mpll_cfg = rockchip_mpll_cfg,
|
|
.cur_ctr = rockchip_cur_ctr,
|
|
.phy_config = rockchip_phy_config,
|
|
@@ -308,7 +388,6 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = {
|
|
};
|
|
|
|
static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
|
|
- .mode_valid = dw_hdmi_rockchip_mode_valid,
|
|
.mpll_cfg = rockchip_mpll_cfg,
|
|
.cur_ctr = rockchip_cur_ctr,
|
|
.phy_config = rockchip_phy_config,
|
|
@@ -387,6 +466,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
|
*/
|
|
if (IS_ERR(hdmi->hdmi)) {
|
|
ret = PTR_ERR(hdmi->hdmi);
|
|
+ devm_kfree(hdmi->dev, hdmi->rates);
|
|
drm_encoder_cleanup(encoder);
|
|
clk_disable_unprepare(hdmi->vpll_clk);
|
|
}
|
|
@@ -399,6 +479,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
|
{
|
|
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
|
|
|
|
+ devm_kfree(hdmi->dev, hdmi->rates);
|
|
dw_hdmi_unbind(hdmi->hdmi);
|
|
clk_disable_unprepare(hdmi->vpll_clk);
|
|
}
|
|
--
|
|
2.18.0
|
|
|