From dcc5bdc3a5287421c399926ca3cd394915f2a77d Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Mon, 27 Aug 2018 10:30:55 +0000
Subject: [PATCH 01/17] drivers: clk-rk3288: support for dedicating NPLL to a
VOP
As controlled by the just introduced dts property.
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
---
drivers/clk/rockchip/clk-rk3288.c | 70 +++++++++++++++++++++++++------
drivers/clk/rockchip/clk.h | 3 ++
2 files changed, 61 insertions(+), 12 deletions(-)
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 0a1e017df7c6..f302e321f8ff 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -195,10 +195,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", "unstable:usbphy480m_src" };
-PNAME(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "unstable:usbphy480m_src", "npll" };
+PNAME_ED(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "unstable:usbphy480m_src", "npll" };
PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "xin24m" };
PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
@@ -442,24 +446,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),
@@ -468,16 +472,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),
@@ -551,7 +555,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),
@@ -933,6 +937,7 @@ static void __init rk3288_common_init(struct device_node *np,
{
struct rockchip_clk_provider *ctx;
unsigned long clk_nr_clks;
+ s32 npll_vop = -1;
rk3288_cru_base = of_iomap(np, 0);
if (!rk3288_cru_base) {
@@ -940,9 +945,50 @@ static void __init rk3288_common_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);
+ }
+ }
+
clk_nr_clks = rockchip_clk_find_max_clk_id(rk3288_clk_branches,
ARRAY_SIZE(rk3288_clk_branches)) + 1;
ctx = rockchip_clk_init(np, rk3288_cru_base, clk_nr_clks);
+
if (IS_ERR(ctx)) {
pr_err("%s: rockchip clk init failed\n", __func__);
iounmap(rk3288_cru_base);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 7c5e74c7a2e2..76d0a5e093fd 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -661,6 +661,9 @@ struct clk *rockchip_clk_register_gate_grf(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,
--
2.44.0
From 42520c94e3beb72591fc9be609ca09167b375890 Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Wed, 22 Aug 2018 18:36:40 +0000
Subject: [PATCH 02/17] drm: dw_hdmi-rockchip: better clock selection logic and
dts-based rate list
This contains traces of the following commits from the ChromeOS 3.14
tree, which improve RF/EMI performance and detach the clock selection
logic from the HDMI PHY configurations, plus support for configuring
the allowed clock rates via device tree as they are dependent on
PLL configuration and maybe even the PCB layout and other hardware things,
eg. interference to wifi or such (EMI).
Rates that were allowed previous to this patch are added as the fallback
list if no dts configuration exists.
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Adjust rockchip_mpll_cfg for 146.25
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: expand the informal mpll config
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: add slop to more tables
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: redo rockchip hdmi to allow slop
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Use auto-generated tables
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Fixup the clock to be what we expect
CHROMIUM: drm/rockchip: hdmi: adjust cklvl & txlvl for RF/EMI
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Set cur_ctr to 0 always
CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Decrease slop
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
Signed-off-by: Maya Matuszczyk <maccraft123mc@gmail.com>
---
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 136 ++++++++++++++++----
1 file changed, 109 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index acb59b25d928..f029fe4729e7 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -81,8 +81,13 @@ struct rockchip_hdmi {
struct clk *grf_clk;
struct dw_hdmi *hdmi;
struct phy *phy;
+ u32* rates;
+ u32 rates_cnt;
};
+#define CLK_SLOP(clk) ((clk) / 1000)
+#define CLK_PLUS_SLOP(clk) ((clk) + CLK_SLOP(clk))
+
static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
{
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
@@ -90,6 +95,23 @@ static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
return container_of(rkencoder, struct rockchip_hdmi, encoder);
}
+/* 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[] = {
{
30666000, {
@@ -179,7 +201,7 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
};
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
- /* pixelclk bpp8 bpp10 bpp12 */
+ /* pixelclk bpp8 bpp10 bpp12 */
{
600000000, { 0x0000, 0x0000, 0x0000 },
}, {
@@ -188,18 +210,18 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
};
static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
- /*pixelclk symbol term vlev*/
- { 74250000, 0x8009, 0x0004, 0x0272},
- { 165000000, 0x802b, 0x0004, 0x0209},
- { 297000000, 0x8039, 0x0005, 0x028d},
- { 594000000, 0x8039, 0x0000, 0x019d},
- { ~0UL, 0x0000, 0x0000, 0x0000}
+ /*pixelclk symbol term vlev*/
+ { 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 ret;
+ int rates_cnt;
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(hdmi->regmap)) {
@@ -227,34 +249,58 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
return ret;
ret = devm_regulator_get_enable(hdmi->dev, "avdd-1v8");
+ if (ret)
+ return ret;
- return ret;
+ 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 dw_hdmi *dw_hdmi, void *data,
- const struct drm_display_info *info,
+dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder,
const struct drm_display_mode *mode)
{
- struct rockchip_hdmi *hdmi = data;
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
int pclk = mode->clock * 1000;
+ int num_rates = hdmi->rates_cnt;
+ int i;
if (hdmi->chip_data->max_tmds_clock &&
mode->clock > hdmi->chip_data->max_tmds_clock)
return MODE_CLOCK_HIGH;
- if (hdmi->ref_clk) {
- int rpclk = clk_round_rate(hdmi->ref_clk, pclk);
-
- if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000)
- return MODE_NOCLOCK;
- }
+ /*
+ * 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;
- if (hdmi->hdmiphy_clk) {
- int rpclk = clk_round_rate(hdmi->hdmiphy_clk, pclk);
+ for (i = 0; i < num_rates; i++) {
+ int slop = CLK_SLOP(pclk);
- if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000)
- return MODE_NOCLOCK;
+ if ((pclk >= hdmi->rates[i] - slop) &&
+ (pclk <= hdmi->rates[i] + slop))
+ return MODE_OK;
}
return MODE_OK;
@@ -269,7 +315,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,
@@ -324,6 +402,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,
@@ -429,7 +508,9 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = {
};
static const struct dw_hdmi_plat_data rk3228_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,
.phy_data = &rk3228_chip_data,
.phy_ops = &rk3228_hdmi_phy_ops,
.phy_name = "inno_dw_hdmi_phy2",
@@ -444,7 +525,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,
@@ -465,7 +545,9 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = {
};
static const struct dw_hdmi_plat_data rk3328_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,
.phy_data = &rk3328_chip_data,
.phy_ops = &rk3328_hdmi_phy_ops,
.phy_name = "inno_dw_hdmi_phy2",
@@ -481,7 +563,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,
@@ -495,7 +576,6 @@ static struct rockchip_hdmi_chip_data rk3568_chip_data = {
};
static const struct dw_hdmi_plat_data rk3568_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,
@@ -614,6 +694,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
return 0;
err_bind:
+ devm_kfree(hdmi->dev, hdmi->rates);
drm_encoder_cleanup(encoder);
return ret;
@@ -624,6 +705,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);
drm_encoder_cleanup(&hdmi->encoder.encoder);
}
--
2.44.0
From f06dd7c475472237b836e77bcaf0d0629a8c003d Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Mon, 27 Aug 2018 19:00:50 +0000
Subject: [PATCH 03/17] dts: rk3288: support for dedicating npll to a vop
Add the VOP DCLKs to the assigned clocks list so their
parents can be set in the dts include files for
devices that do dedicate npll to a vop.
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
---
arch/arm/boot/dts/rockchip/rk3288.dtsi | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/rockchip/rk3288.dtsi b/arch/arm/boot/dts/rockchip/rk3288.dtsi
index 42d705b544ec..775f24876be4 100644
--- a/arch/arm/boot/dts/rockchip/rk3288.dtsi
+++ b/arch/arm/boot/dts/rockchip/rk3288.dtsi
@@ -873,12 +873,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>,
--
2.44.0
From 1fe48e89fb9de8aea3e8bdbd0a7000e02753dea0 Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Mon, 27 Aug 2018 19:03:49 +0000
Subject: [PATCH 04/17] dts: rk3288-veyron-chromebook: dedicate npll to
VOP0/HDMI + HDMI rates
This enables flexible HDMI rates on the rk3288 chromebooks so that they
actually work with displays (also others than a 1080p one) in the wild.
The frequency list matches what ChromeOS allows.
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
---
.../rockchip/rk3288-veyron-chromebook.dtsi | 62 +++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi
index 3677571b4d82..b61a4b0d7015 100644
--- a/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi
+++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi
@@ -83,6 +83,68 @@
};
};
+&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;
+
+&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 >;
+};
+
&rk808 {
vcc11-supply = <&vcc_5v>;
--
2.44.0
From 8cfedc4d406465040d778281dcc025fdfea6c1b4 Mon Sep 17 00:00:00 2001
From: SolidHal <hal@halemmerich.com>
Date: Sun, 21 Oct 2018 16:40:15 -0500
Subject: [PATCH 05/17] Added a second reset when having an issue reading the
emmc.
The c201 emmc can be... touchy. Sometimes one full reset isn't
enough to get it into a wokring state if it found it's way into
a really bad state. Note that in my testing WITHOUT this patch,
this only happens about once in just over 1600 reboots.
--
Edited by Urja Rannikko to actually limit the retries to once,
and to apply to 4.20.
--
Signed-off-by: SolidHal <hal@halemmerich.com>
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
---
drivers/mmc/core/block.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index dd6cffc0df72..04e30d8072da 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1090,6 +1090,7 @@ static unsigned int mmc_blk_data_timeout_ms(struct mmc_host *host,
static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
int type)
{
+ int retries = 1;
int err;
struct mmc_blk_data *main_md = dev_get_drvdata(&host->card->dev);
@@ -1097,7 +1098,14 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
return -EEXIST;
md->reset_done |= type;
+retry:
err = mmc_hw_reset(host->card);
+
+ /* Retry once because the C201 eMMC can be touchy */
+ if ((err) && (retries--)) {
+ goto retry;
+ }
+
/*
* A successful reset will leave the card in the main partition, but
* upon failure it might not be, so set it to MMC_BLK_PART_INVALID
--
2.44.0
From 283d0de6282db67b0f0f693ec5ba581103da55ad Mon Sep 17 00:00:00 2001
From: "Miouyouyou (Myy)" <myy@miouyouyou.fr>
Date: Tue, 9 Oct 2018 22:01:07 +0200
Subject: [PATCH 06/17] block: partitions: efi: Ignore bizarre Chromebook GPT
partitions
This patch is based on @SolidHal work here :
https://raw.githubusercontent.com/SolidHal/PrawnOS/master/resources/BuildResources/patches-tested/kernel/0001-block-partitions-efi-Add-support-for-IGNOREME-GPT-si.patch
Here's the initial commit message :
8<---
This patch adds support for a special GPT header signature marker (using
the string 'IGNOREME' instead of the spec's 'EFI PART'). This tells the
kernel to ignore this GPT completely and look at the other one instead.
Since the kernel always prefers the primary GPT anyway, all we really
need to do effectively is to check whether the primary GPT is marked
'IGNOREME' and force evaluation of the secondary one in that case.
Borrowed from the chrome os 3.14 kernel, the commit can be found here:
https://chromium.googlesource.com/chromiumos/third_party/kernel/+/abba28d0a1b7361da6e2023352e92687166ca30d
Also bundled in this commit
https://chromium.googlesource.com/chromiumos/third_party/kernel/+/bd0c62c7de0c8a63314b7955e5718d8f6192f9d2%5E%21/#F0
Which is a small compiler warning fix for the above patch
This patch fixes how the kernel detects and handles certain mmc
manufatures devices, and allows the partitions on the mmc to be bootable
and mountable.
>8---
Signed-off-by: Miouyouyou (Myy) <myy@miouyouyou.fr>
---
block/partitions/efi.c | 33 +++++++++++++++++++++++----------
block/partitions/efi.h | 3 ++-
2 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index 7acba66eed48..087032a4705e 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -328,23 +328,34 @@ static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state,
* @lba: logical block address of the GPT header to test
* @gpt: GPT header ptr, filled on return.
* @ptes: PTEs ptr, filled on return.
+ * @ignored is filled on return with 1 if this is an IGNOREME GPT,
+ * 0 otherwise. May be NULL.
*
* Description: returns 1 if valid, 0 on error.
* If valid, returns pointers to newly allocated GPT header and PTEs.
*/
static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
- gpt_header **gpt, gpt_entry **ptes)
+ gpt_header **gpt, gpt_entry **ptes, int *ignored)
{
u32 crc, origcrc;
u64 lastlba, pt_size;
+ if (ignored)
+ *ignored = 0;
if (!ptes)
return 0;
if (!(*gpt = alloc_read_gpt_header(state, lba)))
return 0;
/* Check the GUID Partition Table signature */
- if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
+
+ if (le64_to_cpu((*gpt)->signature) == GPT_HEADER_SIGNATURE_IGNORED) {
+ pr_debug("GUID Partition Table at LBA %llu marked IGNOREME\n",
+ (unsigned long long)lba);
+ if (ignored)
+ *ignored = 1;
+ goto fail;
+ } else if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
pr_debug("GUID Partition Table Header signature is wrong:"
"%lld != %lld\n",
(unsigned long long)le64_to_cpu((*gpt)->signature),
@@ -581,7 +592,7 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
gpt_entry **ptes)
{
- int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
+ int good_pgpt = 0, good_agpt = 0, good_pmbr = 0, pgpt_ignored = 0;
gpt_header *pgpt = NULL, *agpt = NULL;
gpt_entry *pptes = NULL, *aptes = NULL;
legacy_mbr *legacymbr;
@@ -613,13 +624,13 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
}
good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
- &pgpt, &pptes);
+ &pgpt, &pptes, &pgpt_ignored);
if (good_pgpt)
good_agpt = is_gpt_valid(state,
le64_to_cpu(pgpt->alternate_lba),
- &agpt, &aptes);
- if (!good_agpt && force_gpt)
- good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
+ &agpt, &aptes, NULL);
+ if (!good_agpt && (force_gpt || pgpt_ignored))
+ good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes, NULL);
if (!good_agpt && force_gpt && fops->alternative_gpt_sector) {
sector_t agpt_sector;
@@ -628,14 +639,15 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
err = fops->alternative_gpt_sector(disk, &agpt_sector);
if (!err)
good_agpt = is_gpt_valid(state, agpt_sector,
- &agpt, &aptes);
+ &agpt, &aptes, NULL);
}
/* The obviously unsuccessful case */
if (!good_pgpt && !good_agpt)
goto fail;
- compare_gpts(pgpt, agpt, lastlba);
+ if (!pgpt_ignored)
+ compare_gpts(pgpt, agpt, lastlba);
/* The good cases */
if (good_pgpt) {
@@ -652,7 +664,8 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
*ptes = aptes;
kfree(pgpt);
kfree(pptes);
- pr_warn("Primary GPT is invalid, using alternate GPT.\n");
+ pr_warn("Primary GPT is %s, using alternate GPT.\n",
+ pgpt_ignored ? "being ignored" : "invalid");
return 1;
}
diff --git a/block/partitions/efi.h b/block/partitions/efi.h
index 84b9f36b9e47..09726227e891 100644
--- a/block/partitions/efi.h
+++ b/block/partitions/efi.h
@@ -26,7 +26,8 @@
#define GPT_MBR_PROTECTIVE 1
#define GPT_MBR_HYBRID 2
-#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
+#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL /* 'EFI PART' */
+#define GPT_HEADER_SIGNATURE_IGNORED 0x454d45524f4e4749ULL /* 'IGNOREME' */
#define GPT_HEADER_REVISION_V1 0x00010000
#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
--
2.44.0
From 5f860327b788bb0465d2aa1c872942a54ec12160 Mon Sep 17 00:00:00 2001
From: "Miouyouyou (Myy)" <myy@miouyouyou.fr>
Date: Tue, 30 Oct 2018 22:44:54 +0100
Subject: [PATCH 07/17] mmc: Added a flag to disable cache flush during reset
The ASUS Chromebook suffer from 10 minutes long hang, when trying
to flush the cache of the eMMC, in order to recover from eMMC init
issues when booting the system.
A new flag "no-recovery-cache-flush" whose purpose is to disable
cache flush during recovery reset, has been added.
This work is adapted from @SolidHal work, which is available here :
https://github.com/SolidHal/PrawnOS/blob/develop-4.19/resources/BuildResources/patches-tested/kernel/Don-t-try-to-flush-cache-on-reset.patch
Signed-off-by: Miouyouyou (Myy) <myy@miouyouyou.fr>
---
drivers/mmc/core/host.c | 2 ++
drivers/mmc/core/mmc.c | 18 ++++++++++++++----
include/linux/mmc/host.h | 1 +
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index f14671ea5716..c5f8b935f036 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -405,6 +405,8 @@ int mmc_of_parse(struct mmc_host *host)
if (device_property_read_bool(dev, "no-mmc-hs400"))
host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
MMC_CAP2_HS400_ES);
+ if (device_property_read_bool(dev, "no-recovery-cache-flush"))
+ host->caps2 |= MMC_CAP2_NO_RECOVERY_CACHE_FLUSH;
/* Must be after "non-removable" check */
if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 5be9b42d5057..5e5cfd7c23b3 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2269,6 +2269,12 @@ static int mmc_runtime_resume(struct mmc_host *host)
return 0;
}
+static inline int mmc_can_flush_during_recovery(
+ struct mmc_host *host)
+{
+ return (host->caps2 & MMC_CAP2_NO_RECOVERY_CACHE_FLUSH) == 0;
+}
+
static bool mmc_card_can_reset(struct mmc_card *card)
{
u8 rst_n_function;
@@ -2281,11 +2287,15 @@ static int _mmc_hw_reset(struct mmc_host *host)
{
struct mmc_card *card = host->card;
- /*
- * In the case of recovery, we can't expect flushing the cache to work
- * always, but we have a go and ignore errors.
+ /* Using a "Cache flush" during recovery events seems...
+ * "dubious" at best, and generate significant issues on
+ * some platforms, like 10 minutes hang up, at worst.
+ * I'm keeping this line because the old code did it but...
+ * feel free to double check if that's needed at all.
*/
- _mmc_flush_cache(host);
+
+ if (mmc_can_flush_during_recovery(host))
+ _mmc_flush_cache(host);
if ((host->caps & MMC_CAP_HW_RESET) && host->ops->card_hw_reset &&
mmc_card_can_reset(card)) {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 68f09a955a90..eb7dbf0f9b10 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -459,6 +459,7 @@ struct mmc_host {
#define MMC_CAP2_CRYPTO 0
#endif
#define MMC_CAP2_ALT_GPT_TEGRA (1 << 28) /* Host with eMMC that has GPT entry at a non-standard location */
+#define MMC_CAP2_NO_RECOVERY_CACHE_FLUSH (1 << 29) /* Do not flush the device cache when recovering */
bool uhs2_sd_tran; /* UHS-II flag for SD_TRAN state */
bool uhs2_app_cmd; /* UHS-II flag for APP command */
--
2.44.0
From 79d6af95b3e561a0a06229accb4c0e3c827001b8 Mon Sep 17 00:00:00 2001
From: "Miouyouyou (Myy)" <myy@miouyouyou.fr>
Date: Thu, 1 Nov 2018 21:31:26 +0100
Subject: [PATCH 08/17] arm: dts: veyron: Added a flag to disable cache flush
during reset
Flushing the MMC cache of ASUS Chromebooks during initialization or
"recovery" generates 10 minutes hangup, according to @SolidHal.
This is an adaptation of @SolidHal, in order to pinpoint the fix to
Veyron Chromebooks, and avoiding issues other RK3288 boards.
Signed-off-by: Miouyouyou (Myy) <myy@miouyouyou.fr>
---
arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi b/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi
index 260d6c92cfd1..08ce8bfb70b2 100644
--- a/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi
+++ b/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi
@@ -157,6 +157,7 @@
mmc-hs200-1_8v;
mmc-pwrseq = <&emmc_pwrseq>;
non-removable;
+ no-recovery-cache-flush;
pinctrl-names = "default";
pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
};
--
2.44.0
From 44271ff5e6056ad04d9829d03e394561b2dc3ad7 Mon Sep 17 00:00:00 2001
From: Hal Emmerich <hal@halemmerich.com>
Date: Wed, 21 Aug 2019 16:52:41 -0500
Subject: [PATCH 09/17] Fix ath9k dwc2 init frame overruns
[ by Urja Rannikko: changed to log message to something more sensible. ]
This is a workaround for ar9271 drvices using the open ath9k firmware
With the dwc2 usb driver these endpoints end up throwing piles of
frame overrun errors and prevent the ath9k firmware from communicating
properly with the c201
This fix elongates the microframes by 4 so the dwc2 and ath9k devices
communicate properly. In my testing this did not impact network speeds.
---
drivers/usb/dwc2/hcd_queue.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 904fe0632b34..6a9ecc809814 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -1491,6 +1491,16 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
device_ns += dwc_tt->usb_tt->think_time;
qh->device_us = NS_TO_US(device_ns);
+ //Only enable workaround for highspeed devices, since only low and full speed devices so split, we can just check split
+ //The packets that fail right after the firmware is transferred are on an interrupt ep so we can use that to further narrow it down
+ //The ath9k device has issues with ep 3 and ep4
+ if(!do_split && !ep_is_isoc && ep_is_int && (urb->pipe_info.ep_num == 3 || urb->pipe_info.ep_num == 4)){
+ if (urb->interval == 1){
+ urb->interval = 4;
+ dev_info(hsotg->dev, "ath9k workaround: set usb urb interval to %d\n", urb->interval);
+ }
+ }
+
qh->device_interval = urb->interval;
qh->host_interval = urb->interval * (do_split ? 8 : 1);
--
2.44.0
From b7f6bbf0635a77fa5050b7a965940c563e2c62b6 Mon Sep 17 00:00:00 2001
From: barzur <boris@konbu.org>
Date: Fri, 12 Jul 2019 11:33:32 +0900
Subject: [PATCH 10/17] usb/dwc2/hcd: channel halt may not be an error
Truncating the data was causing null pointer exceptions in memcpy,
let's be more careful.
Addendum by Urja Rannikko:
This was reported as a pull request on my linux github repo and it came
with this reproducer & notes:
-- begin --
I sometimes get kernel oops when USB tethering.
Here is how to repro:
* create high load on the CPU: I build a kernel with -j6;
* saturate your cdc_ether connection to the phone (I use netcat on both sides
to do so, with termux on android);
I tracked down the issue to buffers getting truncated, the driver extracting
a target address from the end of the buffer (weird) & memcpy to a non validated
address.
I've fixed it by validating the address we write to & stopped treating
un-explained channel closure as errors. I guess the channel is closed due to a
timeout (maybe?), caused by heavy context switching on the machine.
I've been testing the following patch for ~1 week and it seems to work well.
-- end --
I do not have a suitable phone to reproduce this with so I cant personally
say if it works and I dont 100% understand it, but I looked at the patch
and I think it looks okay-ish (tho maybe should be two patches), so in the
meantime I'm including it here.
---
drivers/usb/dwc2/hcd.c | 3 ++-
drivers/usb/dwc2/hcd_intr.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 30eb8506617c..725012cf03d7 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -2457,7 +2457,8 @@ static void dwc2_free_dma_aligned_buffer(struct urb *urb)
else
length = urb->actual_length;
- memcpy(stored_xfer_buffer, urb->transfer_buffer, length);
+ if (stored_xfer_buffer)
+ memcpy(stored_xfer_buffer, urb->transfer_buffer, length);
}
kfree(urb->transfer_buffer);
urb->transfer_buffer = stored_xfer_buffer;
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index 5c7538d498dd..96dc5d8115d2 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -1935,7 +1935,8 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
"hcint 0x%08x, intsts 0x%08x\n",
chan->hcint,
dwc2_readl(hsotg, GINTSTS));
- goto error;
+ dwc2_halt_channel(hsotg, chan, qtd,
+ DWC2_HC_XFER_PERIODIC_INCOMPLETE);
}
}
} else {
--
2.44.0
From a98f7809d452a5a404938ab8b3dac3de5d20cdc3 Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Tue, 8 Oct 2019 11:03:37 +0000
Subject: [PATCH 11/17] drm/panel: edp: Extend Innolux N116BGE mode info for
~60Hz from 74.25 Mhz
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
---
drivers/gpu/drm/panel/panel-edp.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index d0aa602ecc9d..2bb437e3afff 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1294,16 +1294,25 @@ static const struct panel_desc innolux_n116bca_ea1 = {
* porch, back porch, or sync length. For now we'll leave a single setting
* here which allows a bit of tweaking of the pixel clock at the expense of
* refresh rate.
+ *
+ * Experimental testing with one panel suggests that the split among
+ * front/back/sync is not important, but the panel is not stable
+ * at htotal less than 1520 (atleast when running at 74.25 Mhz).
+ *
+ * There exists an experimental mode that gives very close to 60 Hz mode
+ * from 74.25 Mhz with htotal 1543 and vtotal 802 - we allow the
+ * hfront_porch and vback_porch to be adjusted to reach that mode.
+ *
*/
static const struct display_timing innolux_n116bge_timing = {
.pixelclock = { 72600000, 76420000, 80240000 },
.hactive = { 1366, 1366, 1366 },
- .hfront_porch = { 136, 136, 136 },
+ .hfront_porch = { 87, 136, 136 },
.hback_porch = { 60, 60, 60 },
.hsync_len = { 30, 30, 30 },
.vactive = { 768, 768, 768 },
.vfront_porch = { 8, 8, 8 },
- .vback_porch = { 12, 12, 12 },
+ .vback_porch = { 12, 12, 14 },
.vsync_len = { 12, 12, 12 },
.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
};
--
2.44.0
From 6c7208ec05a2e7041c3be59e9671ccaeb60433c8 Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Tue, 8 Oct 2019 11:12:33 +0000
Subject: [PATCH 12/17] ARM: dts: rockchip: Adjust rk3288-veyron n116bge mode
for ~60Hz
This is an experimental mode that gets very close to 60Hz (60.00067..)
from the available clock of 74.25Mhz on an rk3288. The mode
has htotal 1543 and vtotal 802.
Signed-off-by: Urja Rannikko <urjaman@gmail.com>
---
arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi b/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi
index fb031964fa2b..128176b7c372 100644
--- a/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi
+++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi
@@ -62,13 +62,13 @@
panel-timing {
clock-frequency = <74250000>;
hactive = <1366>;
- hfront-porch = <136>;
+ hfront-porch = <87>;
hback-porch = <60>;
hsync-len = <30>;
hsync-active = <0>;
vactive = <768>;
vfront-porch = <8>;
- vback-porch = <12>;
+ vback-porch = <14>;
vsync-len = <12>;
vsync-active = <0>;
};
--
2.44.0
From e266ac12673309e4ca5a190af9d272364d37f46d Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Mon, 25 Dec 2023 18:06:10 +0200
Subject: [PATCH 13/17] dts: veyron: bluetooth: disable dma on uart0
I just pulled this off the internet ;)
https://codeberg.org/petms/linux-veyron-patches-and-apkbuild
---
arch/arm/boot/dts/rockchip/rk3288.dtsi | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm/boot/dts/rockchip/rk3288.dtsi b/arch/arm/boot/dts/rockchip/rk3288.dtsi
index 775f24876be4..a19bf9f83a4d 100644
--- a/arch/arm/boot/dts/rockchip/rk3288.dtsi
+++ b/arch/arm/boot/dts/rockchip/rk3288.dtsi
@@ -384,8 +384,6 @@
reg-io-width = <4>;
clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
clock-names = "baudclk", "apb_pclk";
- dmas = <&dmac_peri 1>, <&dmac_peri 2>;
- dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer>;
status = "disabled";
--
2.44.0
From b78d3ad72810cb52cf1defd55b02bf43bfb447fe Mon Sep 17 00:00:00 2001
From: Urja Rannikko <urjaman@gmail.com>
Date: Tue, 28 Sep 2021 20:23:13 +0300
Subject: [PATCH 14/17] Revert "clk: divider: Implement and wire up
.determine_rate by default"
This reverts commit 69a00fb3d6970681c15a23595ec54233ce10295c.
That broke eMMC detection (error -110) on veyron speedy.
Why is still an open question but for now i'm doing this revert
in my tree to be able to test the rest of 5.15 rc's.
---
drivers/clk/clk-divider.c | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c1f426b8a504..3941b4d984f7 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -452,27 +452,6 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
divider->width, divider->flags);
}
-static int clk_divider_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
-{
- struct clk_divider *divider = to_clk_divider(hw);
-
- /* if read only, just return current value */
- if (divider->flags & CLK_DIVIDER_READ_ONLY) {
- u32 val;
-
- val = clk_div_readl(divider) >> divider->shift;
- val &= clk_div_mask(divider->width);
-
- return divider_ro_determine_rate(hw, req, divider->table,
- divider->width,
- divider->flags, val);
- }
-
- return divider_determine_rate(hw, req, divider->table, divider->width,
- divider->flags);
-}
-
int divider_get_val(unsigned long rate, unsigned long parent_rate,
const struct clk_div_table *table, u8 width,
unsigned long flags)
@@ -528,7 +507,6 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops clk_divider_ops = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_divider_round_rate,
- .determine_rate = clk_divider_determine_rate,
.set_rate = clk_divider_set_rate,
};
EXPORT_SYMBOL_GPL(clk_divider_ops);
@@ -536,7 +514,6 @@ EXPORT_SYMBOL_GPL(clk_divider_ops);
const struct clk_ops clk_divider_ro_ops = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_divider_round_rate,
- .determine_rate = clk_divider_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
--
2.44.0
From 97b8829f6c546efba2583781910aaa0d912b3483 Mon Sep 17 00:00:00 2001
From: Sebastian Reichel <sebastian.reichel@collabora.com>
Date: Tue, 30 Jul 2024 20:05:05 +0200
Subject: [PATCH 15/17] mfd: rk8xx: Fix shutdown handler
When I converted rk808 to device managed resources I converted the rk808
specific pm_power_off handler to devm_register_sys_off_handler() using
SYS_OFF_MODE_POWER_OFF_PREPARE, which is allowed to sleep. I did this
because the driver's poweroff function makes use of regmap and the backend
of that might sleep.
But the PMIC poweroff function will kill off the board power and the
kernel does some extra steps after the prepare handler. Thus the prepare
handler should not be used for the PMIC's poweroff routine. Instead the
normal SYS_OFF_MODE_POWER_OFF phase should be used. The old pm_power_off
method is also being called from there, so this would have been a
cleaner conversion anyways.
But it still makes sense to investigate the sleep handling and check
if there are any issues. Apparently the Rockchip and Meson I2C drivers
(the only platforms using the PMICs handled by this driver) both have
support for atomic transfers and thus may be called from the proper
poweroff context.
Things are different on the SPI side. That is so far only used by rk806
and that one is only used by Rockchip RK3588. Unfortunately the Rockchip
SPI driver does not support atomic transfers. That means using the
normal POWER_OFF handler would introduce the following error splash
during shutdown on all RK3588 boards currently supported upstream:
[ 13.761353] ------------[ cut here ]------------
[ 13.761764] Voluntary context switch within RCU read-side critical section!
[ 13.761776] WARNING: CPU: 0 PID: 1 at kernel/rcu/tree_plugin.h:330 rcu_note_context_switch+0x3ac/0x404
[ 13.763219] Modules linked in:
[ 13.763498] CPU: 0 UID: 0 PID: 1 Comm: systemd-shutdow Not tainted 6.10.0-12284-g2818a9a19514 #1499
[ 13.764297] Hardware name: Rockchip RK3588 EVB1 V10 Board (DT)
[ 13.764812] pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 13.765427] pc : rcu_note_context_switch+0x3ac/0x404
[ 13.765871] lr : rcu_note_context_switch+0x3ac/0x404
[ 13.766314] sp : ffff800084f4b5b0
[ 13.766609] x29: ffff800084f4b5b0 x28: ffff00040139b800 x27: 00007dfb4439ae80
[ 13.767245] x26: ffff00040139bc80 x25: 0000000000000000 x24: ffff800082118470
[ 13.767880] x23: 0000000000000000 x22: ffff000400300000 x21: ffff000400300000
[ 13.768515] x20: ffff800083a9d600 x19: ffff0004fee48600 x18: fffffffffffed448
[ 13.769151] x17: 000000040044ffff x16: 005000f2b5503510 x15: 0000000000000048
[ 13.769787] x14: fffffffffffed490 x13: ffff80008473b3c0 x12: 0000000000000900
[ 13.770421] x11: 0000000000000300 x10: ffff800084797bc0 x9 : ffff80008473b3c0
[ 13.771057] x8 : 00000000ffffefff x7 : ffff8000847933c0 x6 : 0000000000000300
[ 13.771692] x5 : 0000000000000301 x4 : 40000000fffff300 x3 : 0000000000000000
[ 13.772328] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000400300000
[ 13.772964] Call trace:
[ 13.773184] rcu_note_context_switch+0x3ac/0x404
[ 13.773598] __schedule+0x94/0xb0c
[ 13.773907] schedule+0x34/0x104
[ 13.774198] schedule_timeout+0x84/0xfc
[ 13.774544] wait_for_completion_timeout+0x78/0x14c
[ 13.774980] spi_transfer_one_message+0x588/0x690
[ 13.775403] __spi_pump_transfer_message+0x19c/0x4ec
[ 13.775846] __spi_sync+0x2a8/0x3c4
[ 13.776161] spi_write_then_read+0x120/0x208
[ 13.776543] rk806_spi_bus_read+0x54/0x88
[ 13.776905] _regmap_raw_read+0xec/0x16c
[ 13.777257] _regmap_bus_read+0x44/0x7c
[ 13.777601] _regmap_read+0x60/0xd8
[ 13.777915] _regmap_update_bits+0xf4/0x13c
[ 13.778289] regmap_update_bits_base+0x64/0x98
[ 13.778686] rk808_power_off+0x70/0xfc
[ 13.779024] sys_off_notify+0x40/0x6c
[ 13.779356] atomic_notifier_call_chain+0x60/0x90
[ 13.779776] do_kernel_power_off+0x54/0x6c
[ 13.780146] machine_power_off+0x18/0x24
[ 13.780499] kernel_power_off+0x70/0x7c
[ 13.780845] __do_sys_reboot+0x210/0x270
[ 13.781198] __arm64_sys_reboot+0x24/0x30
[ 13.781558] invoke_syscall+0x48/0x10c
[ 13.781897] el0_svc_common+0x3c/0xe8
[ 13.782228] do_el0_svc+0x20/0x2c
[ 13.782528] el0_svc+0x34/0xd8
[ 13.782806] el0t_64_sync_handler+0x120/0x12c
[ 13.783197] el0t_64_sync+0x190/0x194
[ 13.783527] ---[ end trace 0000000000000000 ]---
To avoid this we keep the SYS_OFF_MODE_POWER_OFF_PREPARE handler for the
SPI backend. This is not great, but at least avoids regressions and the
fix should be small enough to allow backporting.
As a side-effect this also works around a shutdown problem on the Asus
C201. For reasons unknown that skips calling the prepare handler and
directly calls the final shutdown handler.
Fixes: 4fec8a5a85c49 ("mfd: rk808: Convert to device managed resources")
Cc: stable@vger.kernel.org
Reported-by: Urja <urja@urja.dev>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
drivers/mfd/rk8xx-core.c | 16 ++++++++++++++--
drivers/mfd/rk8xx-i2c.c | 2 +-
drivers/mfd/rk8xx-spi.c | 2 +-
include/linux/mfd/rk808.h | 2 +-
4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c
index def4587fdfb8..073bbb34ab11 100644
--- a/drivers/mfd/rk8xx-core.c
+++ b/drivers/mfd/rk8xx-core.c
@@ -693,10 +693,11 @@ void rk8xx_shutdown(struct device *dev)
}
EXPORT_SYMBOL_GPL(rk8xx_shutdown);
-int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap *regmap)
+int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap *regmap, bool is_spi)
{
struct rk808 *rk808;
const struct rk808_reg_data *pre_init_reg;
+ enum sys_off_mode pwr_off_mode = SYS_OFF_MODE_POWER_OFF;
const struct mfd_cell *cells;
int dual_support = 0;
int nr_pre_init_regs;
@@ -797,10 +798,21 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
if (ret)
return dev_err_probe(dev, ret, "failed to add MFD devices\n");
+ /*
+ * Currently the Rockchip SPI driver always sleeps when doing SPI
+ * transfers. This is not allowed in the SYS_OFF_MODE_POWER_OFF
+ * handler, so we are using the prepare handler as a workaround.
+ * This should be removed once the Rockchip SPI driver has been
+ * adapted.
+ */
+ if (is_spi)
+ pwr_off_mode = SYS_OFF_MODE_POWER_OFF_PREPARE;
+
+
if (device_property_read_bool(dev, "system-power-controller") ||
device_property_read_bool(dev, "rockchip,system-power-controller")) {
ret = devm_register_sys_off_handler(dev,
- SYS_OFF_MODE_POWER_OFF_PREPARE, SYS_OFF_PRIO_HIGH,
+ pwr_off_mode, SYS_OFF_PRIO_HIGH,
&rk808_power_off, rk808);
if (ret)
return dev_err_probe(dev, ret,
diff --git a/drivers/mfd/rk8xx-i2c.c b/drivers/mfd/rk8xx-i2c.c
index 37287b06dab0..b8c0c368ab8a 100644
--- a/drivers/mfd/rk8xx-i2c.c
+++ b/drivers/mfd/rk8xx-i2c.c
@@ -213,7 +213,7 @@ static int rk8xx_i2c_probe(struct i2c_client *client)
return dev_err_probe(&client->dev, PTR_ERR(regmap),
"regmap initialization failed\n");
- return rk8xx_probe(&client->dev, data->variant, client->irq, regmap);
+ return rk8xx_probe(&client->dev, data->variant, client->irq, regmap, false);
}
static void rk8xx_i2c_shutdown(struct i2c_client *client)
diff --git a/drivers/mfd/rk8xx-spi.c b/drivers/mfd/rk8xx-spi.c
index 3405fb82ff9f..20f9428f94bb 100644
--- a/drivers/mfd/rk8xx-spi.c
+++ b/drivers/mfd/rk8xx-spi.c
@@ -94,7 +94,7 @@ static int rk8xx_spi_probe(struct spi_device *spi)
return dev_err_probe(&spi->dev, PTR_ERR(regmap),
"Failed to init regmap\n");
- return rk8xx_probe(&spi->dev, RK806_ID, spi->irq, regmap);
+ return rk8xx_probe(&spi->dev, RK806_ID, spi->irq, regmap, true);
}
static const struct of_device_id rk8xx_spi_of_match[] = {
diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
index 28170ee08898..f4ce5968e91c 100644
--- a/include/linux/mfd/rk808.h
+++ b/include/linux/mfd/rk808.h
@@ -1351,7 +1351,7 @@ struct rk808 {
};
void rk8xx_shutdown(struct device *dev);
-int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap *regmap);
+int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap *regmap, bool is_spi);
int rk8xx_suspend(struct device *dev);
int rk8xx_resume(struct device *dev);
--
2.44.0
From 650082ec16d4ad329affe1afdf874eb5d0899065 Mon Sep 17 00:00:00 2001
From: Robin Murphy <robin.murphy@arm.com>
Date: Tue, 20 May 2025 18:10:16 +0100
Subject: [PATCH 16/17] firmware: smccc: Stub out get_conduit()
Various callers use arm_smccc_1_1_get_conduit() to guard their
arm_smccc_smc() calls - since the latter is already stubbed out to
support optional usage in !HAVE_ARM_SMCCC configs, do the equivalent
for the former as well to make life easier.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
include/linux/arm-smccc.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 50b47eba7d01..9a8169194be7 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -320,7 +320,14 @@ enum arm_smccc_conduit {
*
* When SMCCCv1.1 is not present, returns SMCCC_CONDUIT_NONE.
*/
+#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void);
+#else
+static inline enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
+{
+ return SMCCC_CONDUIT_NONE;
+}
+#endif
/**
* arm_smccc_get_version()
--
2.44.0
From 27f4ea00c3b749f727f30f175ecc099531c4b535 Mon Sep 17 00:00:00 2001
From: Robin Murphy <robin.murphy@arm.com>
Date: Tue, 20 May 2025 18:10:17 +0100
Subject: [PATCH 17/17] pmdomain: rockchip: Relax SMCCC dependency
Most 32-bit Rockchip platforms do not use PSCI, so having to select
ARM_PSCI to satisfy a dependency chain to retain working power domain
support is a bit weird and non-obvious. Now that the offending SMCCC API
is properly stubbed out for optional usage, we can relax this again.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
drivers/pmdomain/rockchip/Kconfig | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/pmdomain/rockchip/Kconfig b/drivers/pmdomain/rockchip/Kconfig
index 218d43186e5b..ffe5e7b78494 100644
--- a/drivers/pmdomain/rockchip/Kconfig
+++ b/drivers/pmdomain/rockchip/Kconfig
@@ -4,7 +4,6 @@ if ARCH_ROCKCHIP || COMPILE_TEST
config ROCKCHIP_PM_DOMAINS
bool "Rockchip generic power domain"
depends on PM
- depends on HAVE_ARM_SMCCC_DISCOVERY
depends on REGULATOR
select PM_GENERIC_DOMAINS
help
--
2.44.0