diff --git a/packages/linux/patches/amlogic/amlogic-0001-FROMGIT-drm-bridge-dw-hdmi-Use-automatic-CTS-generat.patch b/packages/linux/patches/amlogic/amlogic-0001-FROMGIT-drm-bridge-dw-hdmi-Use-automatic-CTS-generat.patch new file mode 100644 index 0000000000..c9a360e037 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0001-FROMGIT-drm-bridge-dw-hdmi-Use-automatic-CTS-generat.patch @@ -0,0 +1,110 @@ +From f75a1c26012288dca8df4128cb5937afeca70a40 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 12 Jun 2019 10:51:47 +0200 +Subject: [PATCH 001/186] FROMGIT: drm/bridge: dw-hdmi: Use automatic CTS + generation mode when using non-AHB audio + +When using an I2S source using a different clock source (usually the I2S +audio HW uses dedicated PLLs, different from the HDMI PHY PLL), fixed +CTS values will cause some frequent audio drop-out and glitches as +reported on Amlogic, Allwinner and Rockchip SoCs setups. + +Setting the CTS in automatic mode will let the HDMI controller generate +automatically the CTS value to match the input audio clock. + +The DesignWare DW-HDMI User Guide explains: + For Automatic CTS generation + Write "0" on the bit field "CTS_manual", Register 0x3205: AUD_CTS3 + +The DesignWare DW-HDMI Databook explains : + If "CTS_manual" bit equals 0b this registers contains "audCTS[19:0]" + generated by the Cycle time counter according to specified timing. + +Cc: Jernej Skrabec +Cc: Maxime Ripard +Cc: Jonas Karlman +Cc: Heiko Stuebner +Cc: Jerome Brunet +Signed-off-by: Neil Armstrong +Tested-by: Jernej Skrabec +Reviewed-by: Jernej Skrabec +Tested-by: Douglas Anderson +Signed-off-by: Andrzej Hajda +Link: https://patchwork.freedesktop.org/patch/msgid/20190612085147.26971-1-narmstrong@baylibre.com +(cherry-picked from fdbdcc83ffd7d00265a531e71f1d166566c09d66 + git://anongit.freedesktop.org/drm/drm-misc) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 45 +++++++++++++++-------- + 1 file changed, 30 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index c6490949d9db..218a7b2308f7 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -508,8 +508,14 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, + /* nshift factor = 0 */ + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); + +- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | +- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); ++ /* Use automatic CTS generation mode when CTS is not set */ ++ if (cts) ++ hdmi_writeb(hdmi, ((cts >> 16) & ++ HDMI_AUD_CTS3_AUDCTS19_16_MASK) | ++ HDMI_AUD_CTS3_CTS_MANUAL, ++ HDMI_AUD_CTS3); ++ else ++ hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3); + hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); + hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); + +@@ -579,24 +585,33 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, + { + unsigned long ftdms = pixel_clk; + unsigned int n, cts; ++ u8 config3; + u64 tmp; + + n = hdmi_compute_n(sample_rate, pixel_clk); + +- /* +- * Compute the CTS value from the N value. Note that CTS and N +- * can be up to 20 bits in total, so we need 64-bit math. Also +- * note that our TDMS clock is not fully accurate; it is accurate +- * to kHz. This can introduce an unnecessary remainder in the +- * calculation below, so we don't try to warn about that. +- */ +- tmp = (u64)ftdms * n; +- do_div(tmp, 128 * sample_rate); +- cts = tmp; ++ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); + +- dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", +- __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000, +- n, cts); ++ /* Only compute CTS when using internal AHB audio */ ++ if (config3 & HDMI_CONFIG3_AHBAUDDMA) { ++ /* ++ * Compute the CTS value from the N value. Note that CTS and N ++ * can be up to 20 bits in total, so we need 64-bit math. Also ++ * note that our TDMS clock is not fully accurate; it is ++ * accurate to kHz. This can introduce an unnecessary remainder ++ * in the calculation below, so we don't try to warn about that. ++ */ ++ tmp = (u64)ftdms * n; ++ do_div(tmp, 128 * sample_rate); ++ cts = tmp; ++ ++ dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", ++ __func__, sample_rate, ++ ftdms / 1000000, (ftdms / 1000) % 1000, ++ n, cts); ++ } else { ++ cts = 0; ++ } + + spin_lock_irq(&hdmi->audio_lock); + hdmi->audio_n = n; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0002-FROMGIT-clk-meson-g12a-fix-hifi-typo-in-mali-parent_.patch b/packages/linux/patches/amlogic/amlogic-0002-FROMGIT-clk-meson-g12a-fix-hifi-typo-in-mali-parent_.patch new file mode 100644 index 0000000000..d7bc57a2ae --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0002-FROMGIT-clk-meson-g12a-fix-hifi-typo-in-mali-parent_.patch @@ -0,0 +1,36 @@ +From eb9dac6427adef3545346e0c860be7bcfdab5e49 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Fri, 24 May 2019 11:15:32 +0200 +Subject: [PATCH 002/186] FROMGIT: clk: meson: g12a: fix hifi typo in mali + parent_names + +Replace hihi by hifi in the mali parent_names of the g12a SoC family. + +Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") +Signed-off-by: Alexandre Mergnat +Acked-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Jerome Brunet +(cherry picked from commit b6297d9e078a4127fb608ede4d0944855dde667d + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index db1c4ed9d54e..7bc5566b66f7 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -2888,7 +2888,7 @@ static struct clk_regmap g12a_hdmi = { + */ + + static const char * const g12a_mali_0_1_parent_names[] = { +- IN_PREFIX "xtal", "gp0_pll", "hihi_pll", "fclk_div2p5", ++ IN_PREFIX "xtal", "gp0_pll", "hifi_pll", "fclk_div2p5", + "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7" + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0003-FROMGIT-clk-meson-axg-audio-migrate-to-the-new-paren.patch b/packages/linux/patches/amlogic/amlogic-0003-FROMGIT-clk-meson-axg-audio-migrate-to-the-new-paren.patch new file mode 100644 index 0000000000..0c39679c8b --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0003-FROMGIT-clk-meson-axg-audio-migrate-to-the-new-paren.patch @@ -0,0 +1,534 @@ +From 9ab959a3f5d6518065e1e957b21ef08d663550d1 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:40:23 +0200 +Subject: [PATCH 003/186] FROMGIT: clk: meson: axg-audio: migrate to the new + parent description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. A recent patch [0] +allows parents to be specified without string names or with device-tree +clock name by using a new assignment structure. + +Migrate to the new way by using .parent_hws where possible (when parent +clocks are localy declared in the controller) and use .parent_data +otherwise. + +Remove clk input helper and all bypass clocks (declared in probe function) +which are no longer used since we are able to use device-tree clock name +directly. + +[0] commit fc0c209c147f ("clk: Allow parents to be specified without string names") + +Signed-off-by: Alexandre Mergnat +[jbrunet@baylibre.com: remove CLK_SET_RATE_PARENT from mst muxes] +Signed-off-by: Jerome Brunet +(cherry picked from commit 282420eed23f237963f2033b2f2bedb90fbcc5e1 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/Kconfig | 1 - + drivers/clk/meson/axg-audio.c | 261 ++++++++++++++++------------------ + 2 files changed, 120 insertions(+), 142 deletions(-) + +diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig +index a6b20e123e0c..ee0b84b6b329 100644 +--- a/drivers/clk/meson/Kconfig ++++ b/drivers/clk/meson/Kconfig +@@ -86,7 +86,6 @@ config COMMON_CLK_AXG + config COMMON_CLK_AXG_AUDIO + tristate "Meson AXG Audio Clock Controller Driver" + depends on ARCH_MESON +- select COMMON_CLK_MESON_INPUT + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_PHASE + select COMMON_CLK_MESON_SCLK_DIV +diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c +index 8028ff6f6610..741df7e955ca 100644 +--- a/drivers/clk/meson/axg-audio.c ++++ b/drivers/clk/meson/axg-audio.c +@@ -15,7 +15,6 @@ + #include + + #include "axg-audio.h" +-#include "clk-input.h" + #include "clk-regmap.h" + #include "clk-phase.h" + #include "sclk-div.h" +@@ -24,7 +23,7 @@ + #define AUD_SLV_SCLK_COUNT 10 + #define AUD_SLV_LRCLK_COUNT 10 + +-#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ ++#define AUD_GATE(_name, _reg, _bit, _phws, _iflags) \ + struct clk_regmap aud_##_name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ +@@ -33,13 +32,13 @@ struct clk_regmap aud_##_name = { \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_gate_ops, \ +- .parent_names = (const char *[]){ _pname }, \ ++ .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ + } + +-#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ ++#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pdata, _iflags) \ + struct clk_regmap aud_##_name = { \ + .data = &(struct clk_regmap_mux_data){ \ + .offset = (_reg), \ +@@ -50,13 +49,13 @@ struct clk_regmap aud_##_name = { \ + .hw.init = &(struct clk_init_data){ \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_mux_ops, \ +- .parent_names = (_pnames), \ +- .num_parents = ARRAY_SIZE(_pnames), \ ++ .parent_data = _pdata, \ ++ .num_parents = ARRAY_SIZE(_pdata), \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ + } + +-#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ ++#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _phws, _iflags) \ + struct clk_regmap aud_##_name = { \ + .data = &(struct clk_regmap_div_data){ \ + .offset = (_reg), \ +@@ -67,15 +66,27 @@ struct clk_regmap aud_##_name = { \ + .hw.init = &(struct clk_init_data){ \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_divider_ops, \ +- .parent_names = (const char *[]) { _pname }, \ ++ .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ + } + + #define AUD_PCLK_GATE(_name, _bit) \ +- AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "audio_pclk", 0) +- ++struct clk_regmap aud_##_name = { \ ++ .data = &(struct clk_regmap_gate_data){ \ ++ .offset = (AUDIO_CLK_GATE_EN), \ ++ .bit_idx = (_bit), \ ++ }, \ ++ .hw.init = &(struct clk_init_data) { \ ++ .name = "aud_"#_name, \ ++ .ops = &clk_regmap_gate_ops, \ ++ .parent_data = &(const struct clk_parent_data) { \ ++ .fw_name = "pclk", \ ++ }, \ ++ .num_parents = 1, \ ++ }, \ ++} + /* Audio peripheral clocks */ + static AUD_PCLK_GATE(ddr_arb, 0); + static AUD_PCLK_GATE(pdm, 1); +@@ -100,14 +111,20 @@ static AUD_PCLK_GATE(power_detect, 19); + static AUD_PCLK_GATE(spdifout_b, 21); + + /* Audio Master Clocks */ +-static const char * const mst_mux_parent_names[] = { +- "aud_mst_in0", "aud_mst_in1", "aud_mst_in2", "aud_mst_in3", +- "aud_mst_in4", "aud_mst_in5", "aud_mst_in6", "aud_mst_in7", ++static const struct clk_parent_data mst_mux_parent_data[] = { ++ { .fw_name = "mst_in0", }, ++ { .fw_name = "mst_in1", }, ++ { .fw_name = "mst_in2", }, ++ { .fw_name = "mst_in3", }, ++ { .fw_name = "mst_in4", }, ++ { .fw_name = "mst_in5", }, ++ { .fw_name = "mst_in6", }, ++ { .fw_name = "mst_in7", }, + }; + + #define AUD_MST_MUX(_name, _reg, _flag) \ + AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ +- mst_mux_parent_names, CLK_SET_RATE_PARENT) ++ mst_mux_parent_data, 0) + + #define AUD_MST_MCLK_MUX(_name, _reg) \ + AUD_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) +@@ -129,7 +146,7 @@ static AUD_MST_MCLK_MUX(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + + #define AUD_MST_DIV(_name, _reg, _flag) \ + AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ +- "aud_"#_name"_sel", CLK_SET_RATE_PARENT) \ ++ aud_##_name##_sel, CLK_SET_RATE_PARENT) \ + + #define AUD_MST_MCLK_DIV(_name, _reg) \ + AUD_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) +@@ -150,7 +167,7 @@ static AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); + static AUD_MST_MCLK_DIV(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + + #define AUD_MST_MCLK_GATE(_name, _reg) \ +- AUD_GATE(_name, _reg, 31, "aud_"#_name"_div", \ ++ AUD_GATE(_name, _reg, 31, aud_##_name##_div, \ + CLK_SET_RATE_PARENT) + + static AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); +@@ -168,7 +185,7 @@ static AUD_MST_MCLK_GATE(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + /* Sample Clocks */ + #define AUD_MST_SCLK_PRE_EN(_name, _reg) \ + AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ +- "aud_mst_"#_name"_mclk", 0) ++ aud_mst_##_name##_mclk, 0) + + static AUD_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); + static AUD_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); +@@ -178,7 +195,7 @@ static AUD_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); + static AUD_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); + + #define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ +- _hi_shift, _hi_width, _pname, _iflags) \ ++ _hi_shift, _hi_width, _phws, _iflags) \ + struct clk_regmap aud_##_name = { \ + .data = &(struct meson_sclk_div_data) { \ + .div = { \ +@@ -195,7 +212,7 @@ struct clk_regmap aud_##_name = { \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &meson_sclk_div_ops, \ +- .parent_names = (const char *[]) { _pname }, \ ++ .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +@@ -203,7 +220,7 @@ struct clk_regmap aud_##_name = { \ + + #define AUD_MST_SCLK_DIV(_name, _reg) \ + AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ +- "aud_mst_"#_name"_sclk_pre_en", \ ++ aud_mst_##_name##_sclk_pre_en, \ + CLK_SET_RATE_PARENT) + + static AUD_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +@@ -214,8 +231,8 @@ static AUD_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); + static AUD_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + + #define AUD_MST_SCLK_POST_EN(_name, _reg) \ +- AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ +- "aud_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) ++ AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ ++ aud_mst_##_name##_sclk_div, CLK_SET_RATE_PARENT) + + static AUD_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); + static AUD_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); +@@ -224,8 +241,8 @@ static AUD_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); + static AUD_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); + static AUD_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); + +-#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ +- _pname, _iflags) \ ++#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ ++ _phws, _iflags) \ + struct clk_regmap aud_##_name = { \ + .data = &(struct meson_clk_triphase_data) { \ + .ph0 = { \ +@@ -247,7 +264,7 @@ struct clk_regmap aud_##_name = { \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &meson_clk_triphase_ops, \ +- .parent_names = (const char *[]) { _pname }, \ ++ .parent_hws = (const struct clk_hw *[]) { &_phws.hw }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ +@@ -255,7 +272,7 @@ struct clk_regmap aud_##_name = { \ + + #define AUD_MST_SCLK(_name, _reg) \ + AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ +- "aud_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) ++ aud_mst_##_name##_sclk_post_en, CLK_SET_RATE_PARENT) + + static AUD_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); + static AUD_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); +@@ -266,7 +283,7 @@ static AUD_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); + + #define AUD_MST_LRCLK_DIV(_name, _reg) \ + AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ +- "aud_mst_"#_name"_sclk_post_en", 0) \ ++ aud_mst_##_name##_sclk_post_en, 0) \ + + static AUD_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); + static AUD_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +@@ -277,7 +294,7 @@ static AUD_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + + #define AUD_MST_LRCLK(_name, _reg) \ + AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ +- "aud_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) ++ aud_mst_##_name##_lrclk_div, CLK_SET_RATE_PARENT) + + static AUD_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); + static AUD_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); +@@ -286,19 +303,29 @@ static AUD_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); + static AUD_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); + static AUD_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); + +-static const char * const tdm_sclk_parent_names[] = { +- "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", +- "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", +- "aud_slv_sclk0", "aud_slv_sclk1", "aud_slv_sclk2", +- "aud_slv_sclk3", "aud_slv_sclk4", "aud_slv_sclk5", +- "aud_slv_sclk6", "aud_slv_sclk7", "aud_slv_sclk8", +- "aud_slv_sclk9" ++static const struct clk_parent_data tdm_sclk_parent_data[] = { ++ { .hw = &aud_mst_a_sclk.hw, }, ++ { .hw = &aud_mst_b_sclk.hw, }, ++ { .hw = &aud_mst_c_sclk.hw, }, ++ { .hw = &aud_mst_d_sclk.hw, }, ++ { .hw = &aud_mst_e_sclk.hw, }, ++ { .hw = &aud_mst_f_sclk.hw, }, ++ { .fw_name = "slv_sclk0", }, ++ { .fw_name = "slv_sclk1", }, ++ { .fw_name = "slv_sclk2", }, ++ { .fw_name = "slv_sclk3", }, ++ { .fw_name = "slv_sclk4", }, ++ { .fw_name = "slv_sclk5", }, ++ { .fw_name = "slv_sclk6", }, ++ { .fw_name = "slv_sclk7", }, ++ { .fw_name = "slv_sclk8", }, ++ { .fw_name = "slv_sclk9", }, + }; + + #define AUD_TDM_SCLK_MUX(_name, _reg) \ + AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ + CLK_MUX_ROUND_CLOSEST, \ +- tdm_sclk_parent_names, 0) ++ tdm_sclk_parent_data, 0) + + static AUD_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); + static AUD_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); +@@ -310,7 +337,7 @@ static AUD_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + + #define AUD_TDM_SCLK_PRE_EN(_name, _reg) \ + AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ +- "aud_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) ++ aud_tdm##_name##_sclk_sel, CLK_SET_RATE_PARENT) + + static AUD_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); + static AUD_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +@@ -322,7 +349,7 @@ static AUD_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + + #define AUD_TDM_SCLK_POST_EN(_name, _reg) \ + AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ +- "aud_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) ++ aud_tdm##_name##_sclk_pre_en, CLK_SET_RATE_PARENT) + + static AUD_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); + static AUD_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +@@ -344,8 +371,9 @@ static AUD_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + .hw.init = &(struct clk_init_data) { \ + .name = "aud_tdm"#_name"_sclk", \ + .ops = &meson_clk_phase_ops, \ +- .parent_names = (const char *[]) \ +- { "aud_tdm"#_name"_sclk_post_en" }, \ ++ .parent_hws = (const struct clk_hw *[]) { \ ++ &aud_tdm##_name##_sclk_post_en.hw \ ++ }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \ + }, \ +@@ -359,19 +387,29 @@ static AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); + static AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); + static AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +-static const char * const tdm_lrclk_parent_names[] = { +- "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", +- "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", +- "aud_slv_lrclk0", "aud_slv_lrclk1", "aud_slv_lrclk2", +- "aud_slv_lrclk3", "aud_slv_lrclk4", "aud_slv_lrclk5", +- "aud_slv_lrclk6", "aud_slv_lrclk7", "aud_slv_lrclk8", +- "aud_slv_lrclk9" ++static const struct clk_parent_data tdm_lrclk_parent_data[] = { ++ { .hw = &aud_mst_a_lrclk.hw, }, ++ { .hw = &aud_mst_b_lrclk.hw, }, ++ { .hw = &aud_mst_c_lrclk.hw, }, ++ { .hw = &aud_mst_d_lrclk.hw, }, ++ { .hw = &aud_mst_e_lrclk.hw, }, ++ { .hw = &aud_mst_f_lrclk.hw, }, ++ { .fw_name = "slv_lrclk0", }, ++ { .fw_name = "slv_lrclk1", }, ++ { .fw_name = "slv_lrclk2", }, ++ { .fw_name = "slv_lrclk3", }, ++ { .fw_name = "slv_lrclk4", }, ++ { .fw_name = "slv_lrclk5", }, ++ { .fw_name = "slv_lrclk6", }, ++ { .fw_name = "slv_lrclk7", }, ++ { .fw_name = "slv_lrclk8", }, ++ { .fw_name = "slv_lrclk9", }, + }; + +-#define AUD_TDM_LRLCK(_name, _reg) \ +- AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ +- CLK_MUX_ROUND_CLOSEST, \ +- tdm_lrclk_parent_names, 0) ++#define AUD_TDM_LRLCK(_name, _reg) \ ++ AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ ++ CLK_MUX_ROUND_CLOSEST, \ ++ tdm_lrclk_parent_data, 0) + + static AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); + static AUD_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +@@ -386,39 +424,51 @@ static AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + AUD_MUX(tdm_##_name, _reg, 0x7, _shift, 0, _parents, \ + CLK_SET_RATE_NO_REPARENT) + +-static const char * const mclk_pad_ctrl_parent_names[] = { +- "aud_mst_a_mclk", "aud_mst_b_mclk", "aud_mst_c_mclk", +- "aud_mst_d_mclk", "aud_mst_e_mclk", "aud_mst_f_mclk", ++static const struct clk_parent_data mclk_pad_ctrl_parent_data[] = { ++ { .hw = &aud_mst_a_mclk.hw }, ++ { .hw = &aud_mst_b_mclk.hw }, ++ { .hw = &aud_mst_c_mclk.hw }, ++ { .hw = &aud_mst_d_mclk.hw }, ++ { .hw = &aud_mst_e_mclk.hw }, ++ { .hw = &aud_mst_f_mclk.hw }, + }; + + static AUD_TDM_PAD_CTRL(mclk_pad_0, AUDIO_MST_PAD_CTRL0, 0, +- mclk_pad_ctrl_parent_names); ++ mclk_pad_ctrl_parent_data); + static AUD_TDM_PAD_CTRL(mclk_pad_1, AUDIO_MST_PAD_CTRL0, 4, +- mclk_pad_ctrl_parent_names); +- +-static const char * const lrclk_pad_ctrl_parent_names[] = { +- "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", +- "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", ++ mclk_pad_ctrl_parent_data); ++ ++static const struct clk_parent_data lrclk_pad_ctrl_parent_data[] = { ++ { .hw = &aud_mst_a_lrclk.hw }, ++ { .hw = &aud_mst_b_lrclk.hw }, ++ { .hw = &aud_mst_c_lrclk.hw }, ++ { .hw = &aud_mst_d_lrclk.hw }, ++ { .hw = &aud_mst_e_lrclk.hw }, ++ { .hw = &aud_mst_f_lrclk.hw }, + }; + + static AUD_TDM_PAD_CTRL(lrclk_pad_0, AUDIO_MST_PAD_CTRL1, 16, +- lrclk_pad_ctrl_parent_names); ++ lrclk_pad_ctrl_parent_data); + static AUD_TDM_PAD_CTRL(lrclk_pad_1, AUDIO_MST_PAD_CTRL1, 20, +- lrclk_pad_ctrl_parent_names); ++ lrclk_pad_ctrl_parent_data); + static AUD_TDM_PAD_CTRL(lrclk_pad_2, AUDIO_MST_PAD_CTRL1, 24, +- lrclk_pad_ctrl_parent_names); +- +-static const char * const sclk_pad_ctrl_parent_names[] = { +- "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", +- "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", ++ lrclk_pad_ctrl_parent_data); ++ ++static const struct clk_parent_data sclk_pad_ctrl_parent_data[] = { ++ { .hw = &aud_mst_a_sclk.hw }, ++ { .hw = &aud_mst_b_sclk.hw }, ++ { .hw = &aud_mst_c_sclk.hw }, ++ { .hw = &aud_mst_d_sclk.hw }, ++ { .hw = &aud_mst_e_sclk.hw }, ++ { .hw = &aud_mst_f_sclk.hw }, + }; + + static AUD_TDM_PAD_CTRL(sclk_pad_0, AUDIO_MST_PAD_CTRL1, 0, +- sclk_pad_ctrl_parent_names); ++ sclk_pad_ctrl_parent_data); + static AUD_TDM_PAD_CTRL(sclk_pad_1, AUDIO_MST_PAD_CTRL1, 4, +- sclk_pad_ctrl_parent_names); ++ sclk_pad_ctrl_parent_data); + static AUD_TDM_PAD_CTRL(sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, +- sclk_pad_ctrl_parent_names); ++ sclk_pad_ctrl_parent_data); + + /* + * Array of all clocks provided by this provider +@@ -868,54 +918,6 @@ static int devm_clk_get_enable(struct device *dev, char *id) + return 0; + } + +-static int axg_register_clk_hw_input(struct device *dev, +- const char *name) +-{ +- char *clk_name; +- struct clk_hw *hw; +- int err = 0; +- +- clk_name = kasprintf(GFP_KERNEL, "aud_%s", name); +- if (!clk_name) +- return -ENOMEM; +- +- hw = meson_clk_hw_register_input(dev, name, clk_name, 0); +- if (IS_ERR(hw)) { +- /* It is ok if an input clock is missing */ +- if (PTR_ERR(hw) == -ENOENT) { +- dev_dbg(dev, "%s not provided", name); +- } else { +- err = PTR_ERR(hw); +- if (err != -EPROBE_DEFER) +- dev_err(dev, "failed to get %s clock", name); +- } +- } +- +- kfree(clk_name); +- return err; +-} +- +-static int axg_register_clk_hw_inputs(struct device *dev, +- const char *basename, +- unsigned int count) +-{ +- char *name; +- int i, ret; +- +- for (i = 0; i < count; i++) { +- name = kasprintf(GFP_KERNEL, "%s%d", basename, i); +- if (!name) +- return -ENOMEM; +- +- ret = axg_register_clk_hw_input(dev, name); +- kfree(name); +- if (ret) +- return ret; +- } +- +- return 0; +-} +- + static const struct regmap_config axg_audio_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, +@@ -963,29 +965,6 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) + return ret; + } + +- /* Register the peripheral input clock */ +- hw = meson_clk_hw_register_input(dev, "pclk", "audio_pclk", 0); +- if (IS_ERR(hw)) +- return PTR_ERR(hw); +- +- /* Register optional input master clocks */ +- ret = axg_register_clk_hw_inputs(dev, "mst_in", +- AUD_MST_IN_COUNT); +- if (ret) +- return ret; +- +- /* Register optional input slave sclks */ +- ret = axg_register_clk_hw_inputs(dev, "slv_sclk", +- AUD_SLV_SCLK_COUNT); +- if (ret) +- return ret; +- +- /* Register optional input slave lrclks */ +- ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", +- AUD_SLV_LRCLK_COUNT); +- if (ret) +- return ret; +- + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(aud_clk_regmaps); i++) + aud_clk_regmaps[i]->map = map; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0004-FROMGIT-clk-meson-g12a-aoclk-migrate-to-the-new-pare.patch b/packages/linux/patches/amlogic/amlogic-0004-FROMGIT-clk-meson-g12a-aoclk-migrate-to-the-new-pare.patch new file mode 100644 index 0000000000..630dbb8257 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0004-FROMGIT-clk-meson-g12a-aoclk-migrate-to-the-new-pare.patch @@ -0,0 +1,240 @@ +From 187df4ce3a3b4444407efb45ed5cf082079bc87d Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:41:23 +0200 +Subject: [PATCH 004/186] FROMGIT: clk: meson: g12a-aoclk: migrate to the new + parent description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (when parent +clocks are localy declared in the controller) and use .parent_data +otherwise. + +Remove clk input helper and all bypass clocks (declared in probe function) +which are no longer used since we are able to use device-tree clock name +directly. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit ba626081107dceacff554e5ca2efc7cea7326b6e + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a-aoclk.c | 81 +++++++++++++++++++++------------- + 1 file changed, 50 insertions(+), 31 deletions(-) + +diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c +index 1994e735396b..62499563e4f5 100644 +--- a/drivers/clk/meson/g12a-aoclk.c ++++ b/drivers/clk/meson/g12a-aoclk.c +@@ -18,8 +18,6 @@ + #include "clk-regmap.h" + #include "clk-dualdiv.h" + +-#define IN_PREFIX "ao-in-" +- + /* + * AO Configuration Clock registers offsets + * Register offsets from the data sheet must be multiplied by 4. +@@ -51,7 +49,9 @@ static struct clk_regmap g12a_aoclk_##_name = { \ + .hw.init = &(struct clk_init_data) { \ + .name = "g12a_ao_" #_name, \ + .ops = &clk_regmap_gate_ops, \ +- .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ ++ .parent_data = &(const struct clk_parent_data) { \ ++ .fw_name = "mpeg-clk", \ ++ }, \ + .num_parents = 1, \ + .flags = CLK_IGNORE_UNUSED, \ + }, \ +@@ -81,7 +81,9 @@ static struct clk_regmap g12a_aoclk_cts_oscin = { + .hw.init = &(struct clk_init_data){ + .name = "cts_oscin", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -106,7 +108,9 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin_pre", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_oscin" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_cts_oscin.hw ++ }, + .num_parents = 1, + }, + }; +@@ -143,7 +147,9 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_div = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin_div", + .ops = &meson_clk_dualdiv_ops, +- .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_32k_by_oscin_pre.hw ++ }, + .num_parents = 1, + }, + }; +@@ -158,8 +164,10 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_div", +- "g12a_ao_32k_by_oscin_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_32k_by_oscin_div.hw, ++ &g12a_aoclk_32k_by_oscin_pre.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -173,7 +181,9 @@ static struct clk_regmap g12a_aoclk_32k_by_oscin = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_32k_by_oscin_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -189,7 +199,9 @@ static struct clk_regmap g12a_aoclk_cec_pre = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec_pre", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_oscin" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_cts_oscin.hw ++ }, + .num_parents = 1, + }, + }; +@@ -226,7 +238,9 @@ static struct clk_regmap g12a_aoclk_cec_div = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec_div", + .ops = &meson_clk_dualdiv_ops, +- .parent_names = (const char *[]){ "g12a_ao_cec_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_cec_pre.hw ++ }, + .num_parents = 1, + }, + }; +@@ -241,8 +255,10 @@ static struct clk_regmap g12a_aoclk_cec_sel = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "g12a_ao_cec_div", +- "g12a_ao_cec_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_cec_div.hw, ++ &g12a_aoclk_cec_pre.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -256,7 +272,9 @@ static struct clk_regmap g12a_aoclk_cec = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "g12a_ao_cec_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_cec_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -272,8 +290,10 @@ static struct clk_regmap g12a_aoclk_cts_rtc_oscin = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin", +- IN_PREFIX "ext_32k-0" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .hw = &g12a_aoclk_32k_by_oscin.hw }, ++ { .fw_name = "ext-32k-0", }, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -289,8 +309,10 @@ static struct clk_regmap g12a_aoclk_clk81 = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_clk81", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", +- "g12a_ao_cts_rtc_oscin"}, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "mpeg-clk", }, ++ { .hw = &g12a_aoclk_cts_rtc_oscin.hw }, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -305,8 +327,10 @@ static struct clk_regmap g12a_aoclk_saradc_mux = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_saradc_mux", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal", +- "g12a_ao_clk81" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_aoclk_clk81.hw }, ++ }, + .num_parents = 2, + }, + }; +@@ -320,7 +344,9 @@ static struct clk_regmap g12a_aoclk_saradc_div = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_saradc_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "g12a_ao_saradc_mux" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_saradc_mux.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -334,7 +360,9 @@ static struct clk_regmap g12a_aoclk_saradc_gate = { + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_saradc_gate", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "g12a_ao_saradc_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_aoclk_saradc_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -417,12 +445,6 @@ static const struct clk_hw_onecell_data g12a_aoclk_onecell_data = { + .num = NR_CLKS, + }; + +-static const struct meson_aoclk_input g12a_aoclk_inputs[] = { +- { .name = "xtal", .required = true }, +- { .name = "mpeg-clk", .required = true }, +- { .name = "ext-32k-0", .required = false }, +-}; +- + static const struct meson_aoclk_data g12a_aoclkc_data = { + .reset_reg = AO_RTI_GEN_CNTL_REG0, + .num_reset = ARRAY_SIZE(g12a_aoclk_reset), +@@ -430,9 +452,6 @@ static const struct meson_aoclk_data g12a_aoclkc_data = { + .num_clks = ARRAY_SIZE(g12a_aoclk_regmap), + .clks = g12a_aoclk_regmap, + .hw_data = &g12a_aoclk_onecell_data, +- .inputs = g12a_aoclk_inputs, +- .num_inputs = ARRAY_SIZE(g12a_aoclk_inputs), +- .input_prefix = IN_PREFIX, + }; + + static const struct of_device_id g12a_aoclkc_match_table[] = { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0005-FROMGIT-clk-meson-gxbb-aoclk-migrate-to-the-new-pare.patch b/packages/linux/patches/amlogic/amlogic-0005-FROMGIT-clk-meson-gxbb-aoclk-migrate-to-the-new-pare.patch new file mode 100644 index 0000000000..9d84040c1c --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0005-FROMGIT-clk-meson-gxbb-aoclk-migrate-to-the-new-pare.patch @@ -0,0 +1,172 @@ +From 407d6f2dcb17af68280aee9544316961344a5889 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:41:24 +0200 +Subject: [PATCH 005/186] FROMGIT: clk: meson: gxbb-aoclk: migrate to the new + parent description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (when parent +clocks are localy declared in the controller) and use .parent_data +otherwise. + +Remove clk input helper and all bypass clocks (declared in probe function) +which are no longer used since we are able to use device-tree clock name +directly. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit 6e2bfc352e7a3a9b22f13c36627545d5f4caf3e9 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/gxbb-aoclk.c | 55 +++++++++++++++++----------------- + 1 file changed, 27 insertions(+), 28 deletions(-) + +diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c +index 449f6ac189d8..e940861a396b 100644 +--- a/drivers/clk/meson/gxbb-aoclk.c ++++ b/drivers/clk/meson/gxbb-aoclk.c +@@ -11,8 +11,6 @@ + #include "clk-regmap.h" + #include "clk-dualdiv.h" + +-#define IN_PREFIX "ao-in-" +- + /* AO Configuration Clock registers offsets */ + #define AO_RTI_PWR_CNTL_REG1 0x0c + #define AO_RTI_PWR_CNTL_REG0 0x10 +@@ -31,7 +29,9 @@ static struct clk_regmap _name##_ao = { \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name "_ao", \ + .ops = &clk_regmap_gate_ops, \ +- .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ ++ .parent_data = &(const struct clk_parent_data) { \ ++ .fw_name = "mpeg-clk", \ ++ }, \ + .num_parents = 1, \ + .flags = CLK_IGNORE_UNUSED, \ + }, \ +@@ -52,7 +52,9 @@ static struct clk_regmap ao_cts_oscin = { + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_oscin", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -65,7 +67,7 @@ static struct clk_regmap ao_32k_pre = { + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_pre", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "ao_cts_oscin" }, ++ .parent_hws = (const struct clk_hw *[]) { &ao_cts_oscin.hw }, + .num_parents = 1, + }, + }; +@@ -112,7 +114,7 @@ static struct clk_regmap ao_32k_div = { + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_div", + .ops = &meson_clk_dualdiv_ops, +- .parent_names = (const char *[]){ "ao_32k_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { &ao_32k_pre.hw }, + .num_parents = 1, + }, + }; +@@ -127,8 +129,10 @@ static struct clk_regmap ao_32k_sel = { + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "ao_32k_div", +- "ao_32k_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &ao_32k_div.hw, ++ &ao_32k_pre.hw ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -142,7 +146,7 @@ static struct clk_regmap ao_32k = { + .hw.init = &(struct clk_init_data){ + .name = "ao_32k", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "ao_32k_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &ao_32k_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -159,10 +163,12 @@ static struct clk_regmap ao_cts_rtc_oscin = { + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ IN_PREFIX "ext-32k-0", +- IN_PREFIX "ext-32k-1", +- IN_PREFIX "ext-32k-2", +- "ao_32k" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "ext-32k-0", }, ++ { .fw_name = "ext-32k-1", }, ++ { .fw_name = "ext-32k-2", }, ++ { .hw = &ao_32k.hw }, ++ }, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -178,8 +184,10 @@ static struct clk_regmap ao_clk81 = { + .hw.init = &(struct clk_init_data){ + .name = "ao_clk81", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", +- "ao_cts_rtc_oscin" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "mpeg-clk", }, ++ { .hw = &ao_cts_rtc_oscin.hw }, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -208,8 +216,10 @@ static struct clk_regmap ao_cts_cec = { + * Until CCF gets fixed, adding this fake parent that won't + * ever be registered should work around the problem + */ +- .parent_names = (const char *[]){ "fixme", +- "ao_cts_rtc_oscin" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .name = "fixme", .index = -1, }, ++ { .hw = &ao_cts_rtc_oscin.hw }, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -261,14 +271,6 @@ static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { + .num = NR_CLKS, + }; + +-static const struct meson_aoclk_input gxbb_aoclk_inputs[] = { +- { .name = "xtal", .required = true, }, +- { .name = "mpeg-clk", .required = true, }, +- {. name = "ext-32k-0", .required = false, }, +- {. name = "ext-32k-1", .required = false, }, +- {. name = "ext-32k-2", .required = false, }, +-}; +- + static const struct meson_aoclk_data gxbb_aoclkc_data = { + .reset_reg = AO_RTI_GEN_CNTL_REG0, + .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), +@@ -276,9 +278,6 @@ static const struct meson_aoclk_data gxbb_aoclkc_data = { + .num_clks = ARRAY_SIZE(gxbb_aoclk), + .clks = gxbb_aoclk, + .hw_data = &gxbb_aoclk_onecell_data, +- .inputs = gxbb_aoclk_inputs, +- .num_inputs = ARRAY_SIZE(gxbb_aoclk_inputs), +- .input_prefix = IN_PREFIX, + }; + + static const struct of_device_id gxbb_aoclkc_match_table[] = { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0006-FROMGIT-clk-meson-axg-aoclk-migrate-to-the-new-paren.patch b/packages/linux/patches/amlogic/amlogic-0006-FROMGIT-clk-meson-axg-aoclk-migrate-to-the-new-paren.patch new file mode 100644 index 0000000000..1b4929ac6c --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0006-FROMGIT-clk-meson-axg-aoclk-migrate-to-the-new-paren.patch @@ -0,0 +1,194 @@ +From a1d4a324255c10d7fcb33270f81a365f40c05f84 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:41:25 +0200 +Subject: [PATCH 006/186] FROMGIT: clk: meson: axg-aoclk: migrate to the new + parent description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (when parent +clocks are localy declared in the controller) and use .parent_data +otherwise. + +Remove clk input helper and all bypass clocks (declared in probe function) +which are no longer used since we are able to use device-tree clock name +directly. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit b90ec1e344a2dd4c1afebd75c1ce05afaf9e116b + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/axg-aoclk.c | 63 ++++++++++++++++++++--------------- + 1 file changed, 37 insertions(+), 26 deletions(-) + +diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c +index 0086f31288eb..b488b40c9d0e 100644 +--- a/drivers/clk/meson/axg-aoclk.c ++++ b/drivers/clk/meson/axg-aoclk.c +@@ -18,8 +18,6 @@ + #include "clk-regmap.h" + #include "clk-dualdiv.h" + +-#define IN_PREFIX "ao-in-" +- + /* + * AO Configuration Clock registers offsets + * Register offsets from the data sheet must be multiplied by 4. +@@ -42,7 +40,9 @@ static struct clk_regmap axg_aoclk_##_name = { \ + .hw.init = &(struct clk_init_data) { \ + .name = "axg_ao_" #_name, \ + .ops = &clk_regmap_gate_ops, \ +- .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ ++ .parent_data = &(const struct clk_parent_data) { \ ++ .fw_name = "mpeg-clk", \ ++ }, \ + .num_parents = 1, \ + .flags = CLK_IGNORE_UNUSED, \ + }, \ +@@ -64,7 +64,9 @@ static struct clk_regmap axg_aoclk_cts_oscin = { + .hw.init = &(struct clk_init_data){ + .name = "cts_oscin", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -77,7 +79,9 @@ static struct clk_regmap axg_aoclk_32k_pre = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_pre", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_oscin" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_aoclk_cts_oscin.hw ++ }, + .num_parents = 1, + }, + }; +@@ -124,7 +128,9 @@ static struct clk_regmap axg_aoclk_32k_div = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_div", + .ops = &meson_clk_dualdiv_ops, +- .parent_names = (const char *[]){ "axg_ao_32k_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_aoclk_32k_pre.hw ++ }, + .num_parents = 1, + }, + }; +@@ -139,8 +145,10 @@ static struct clk_regmap axg_aoclk_32k_sel = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "axg_ao_32k_div", +- "axg_ao_32k_pre" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_aoclk_32k_div.hw, ++ &axg_aoclk_32k_pre.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -154,7 +162,9 @@ static struct clk_regmap axg_aoclk_32k = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "axg_ao_32k_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_aoclk_32k_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -170,8 +180,10 @@ static struct clk_regmap axg_aoclk_cts_rtc_oscin = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "axg_ao_32k", +- IN_PREFIX "ext_32k-0" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .hw = &axg_aoclk_32k.hw }, ++ { .fw_name = "ext_32k-0", }, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -187,8 +199,10 @@ static struct clk_regmap axg_aoclk_clk81 = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_clk81", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", +- "axg_ao_cts_rtc_oscin"}, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "mpeg-clk", }, ++ { .hw = &axg_aoclk_cts_rtc_oscin.hw }, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -203,8 +217,10 @@ static struct clk_regmap axg_aoclk_saradc_mux = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_saradc_mux", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal", +- "axg_ao_clk81" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &axg_aoclk_clk81.hw }, ++ }, + .num_parents = 2, + }, + }; +@@ -218,7 +234,9 @@ static struct clk_regmap axg_aoclk_saradc_div = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_saradc_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "axg_ao_saradc_mux" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_aoclk_saradc_mux.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -232,7 +250,9 @@ static struct clk_regmap axg_aoclk_saradc_gate = { + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_saradc_gate", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "axg_ao_saradc_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_aoclk_saradc_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -290,12 +310,6 @@ static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { + .num = NR_CLKS, + }; + +-static const struct meson_aoclk_input axg_aoclk_inputs[] = { +- { .name = "xtal", .required = true }, +- { .name = "mpeg-clk", .required = true }, +- { .name = "ext-32k-0", .required = false }, +-}; +- + static const struct meson_aoclk_data axg_aoclkc_data = { + .reset_reg = AO_RTI_GEN_CNTL_REG0, + .num_reset = ARRAY_SIZE(axg_aoclk_reset), +@@ -303,9 +317,6 @@ static const struct meson_aoclk_data axg_aoclkc_data = { + .num_clks = ARRAY_SIZE(axg_aoclk_regmap), + .clks = axg_aoclk_regmap, + .hw_data = &axg_aoclk_onecell_data, +- .inputs = axg_aoclk_inputs, +- .num_inputs = ARRAY_SIZE(axg_aoclk_inputs), +- .input_prefix = IN_PREFIX, + }; + + static const struct of_device_id axg_aoclkc_match_table[] = { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0007-FROMGIT-clk-meson-remove-ao-input-bypass-clocks.patch b/packages/linux/patches/amlogic/amlogic-0007-FROMGIT-clk-meson-remove-ao-input-bypass-clocks.patch new file mode 100644 index 0000000000..2568e3cdf0 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0007-FROMGIT-clk-meson-remove-ao-input-bypass-clocks.patch @@ -0,0 +1,130 @@ +From 6faf769562fb26a5b7865727a01067817910de4f Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:41:26 +0200 +Subject: [PATCH 007/186] FROMGIT: clk: meson: remove ao input bypass clocks + +During probe, bypass clocks (i.e. ao-in-xtal) are made from device-tree +inputs to provide input clocks which can be access through global name. +The cons of this method are the duplicated clocks, means more string +comparison. + +Specify parent directly with device-tree clock name. + +Function to regiter bypass clocks is removed. + +Input parameters from meson aoclk data structure are deprecated and then +deleted since all aoclk files are migrated. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit 072a043f5a2e02441002fff34e3885e6026714eb + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/Kconfig | 1 - + drivers/clk/meson/meson-aoclk.c | 37 --------------------------------- + drivers/clk/meson/meson-aoclk.h | 8 ------- + 3 files changed, 46 deletions(-) + +diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig +index ee0b84b6b329..178ee72ba4bc 100644 +--- a/drivers/clk/meson/Kconfig ++++ b/drivers/clk/meson/Kconfig +@@ -33,7 +33,6 @@ config COMMON_CLK_MESON_VID_PLL_DIV + config COMMON_CLK_MESON_AO_CLKC + tristate + select COMMON_CLK_MESON_REGMAP +- select COMMON_CLK_MESON_INPUT + select RESET_CONTROLLER + + config COMMON_CLK_MESON_EE_CLKC +diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c +index b67951909e04..bf8bea675d24 100644 +--- a/drivers/clk/meson/meson-aoclk.c ++++ b/drivers/clk/meson/meson-aoclk.c +@@ -17,8 +17,6 @@ + #include + #include "meson-aoclk.h" + +-#include "clk-input.h" +- + static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev, + unsigned long id) + { +@@ -33,37 +31,6 @@ static const struct reset_control_ops meson_aoclk_reset_ops = { + .reset = meson_aoclk_do_reset, + }; + +-static int meson_aoclkc_register_inputs(struct device *dev, +- struct meson_aoclk_data *data) +-{ +- struct clk_hw *hw; +- char *str; +- int i; +- +- for (i = 0; i < data->num_inputs; i++) { +- const struct meson_aoclk_input *in = &data->inputs[i]; +- +- str = kasprintf(GFP_KERNEL, "%s%s", data->input_prefix, +- in->name); +- if (!str) +- return -ENOMEM; +- +- hw = meson_clk_hw_register_input(dev, in->name, str, 0); +- kfree(str); +- +- if (IS_ERR(hw)) { +- if (!in->required && PTR_ERR(hw) == -ENOENT) +- continue; +- else if (PTR_ERR(hw) != -EPROBE_DEFER) +- dev_err(dev, "failed to register input %s\n", +- in->name); +- return PTR_ERR(hw); +- } +- } +- +- return 0; +-} +- + int meson_aoclkc_probe(struct platform_device *pdev) + { + struct meson_aoclk_reset_controller *rstc; +@@ -86,10 +53,6 @@ int meson_aoclkc_probe(struct platform_device *pdev) + return PTR_ERR(regmap); + } + +- ret = meson_aoclkc_register_inputs(dev, data); +- if (ret) +- return ret; +- + /* Reset Controller */ + rstc->data = data; + rstc->regmap = regmap; +diff --git a/drivers/clk/meson/meson-aoclk.h b/drivers/clk/meson/meson-aoclk.h +index 999cde3868f7..605b43855a69 100644 +--- a/drivers/clk/meson/meson-aoclk.h ++++ b/drivers/clk/meson/meson-aoclk.h +@@ -18,20 +18,12 @@ + + #include "clk-regmap.h" + +-struct meson_aoclk_input { +- const char *name; +- bool required; +-}; +- + struct meson_aoclk_data { + const unsigned int reset_reg; + const int num_reset; + const unsigned int *reset; + const int num_clks; + struct clk_regmap **clks; +- const int num_inputs; +- const struct meson_aoclk_input *inputs; +- const char *input_prefix; + const struct clk_hw_onecell_data *hw_data; + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0008-FROMGIT-clk-meson-g12a-migrate-to-the-new-parent-des.patch b/packages/linux/patches/amlogic/amlogic-0008-FROMGIT-clk-meson-g12a-migrate-to-the-new-parent-des.patch new file mode 100644 index 0000000000..c11a799e90 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0008-FROMGIT-clk-meson-g12a-migrate-to-the-new-parent-des.patch @@ -0,0 +1,2363 @@ +From d26d1a78b880798336850c31342ac4b80dc4b661 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:42:31 +0200 +Subject: [PATCH 008/186] FROMGIT: clk: meson: g12a: migrate to the new parent + description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (ie. when +all clocks are local to the controller) and use .parent_data otherwise. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit 25e682a02d91e2d09f47c089a4b42bba726106b9 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 1087 ++++++++++++++++++++++++-------------- + 1 file changed, 693 insertions(+), 394 deletions(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index 7bc5566b66f7..8cc7f5acf7ab 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -15,7 +15,6 @@ + #include + #include + +-#include "clk-input.h" + #include "clk-mpll.h" + #include "clk-pll.h" + #include "clk-regmap.h" +@@ -61,7 +60,9 @@ static struct clk_regmap g12a_fixed_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -76,7 +77,9 @@ static struct clk_regmap g12a_fixed_pll = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "fixed_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fixed_pll_dco.hw ++ }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so +@@ -130,7 +133,9 @@ static struct clk_regmap g12a_sys_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -145,7 +150,9 @@ static struct clk_regmap g12a_sys_pll = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "sys_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sys_pll_dco.hw ++ }, + .num_parents = 1, + }, + }; +@@ -181,7 +188,9 @@ static struct clk_regmap g12b_sys1_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -196,7 +205,9 @@ static struct clk_regmap g12b_sys1_pll = { + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "sys1_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_sys1_pll_dco.hw ++ }, + .num_parents = 1, + }, + }; +@@ -209,7 +220,7 @@ static struct clk_regmap g12a_sys_pll_div16_en = { + .hw.init = &(struct clk_init_data) { + .name = "sys_pll_div16_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "sys_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_sys_pll.hw }, + .num_parents = 1, + /* + * This clock is used to debug the sys_pll range +@@ -226,7 +237,9 @@ static struct clk_regmap g12b_sys1_pll_div16_en = { + .hw.init = &(struct clk_init_data) { + .name = "sys1_pll_div16_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "sys1_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_sys1_pll.hw ++ }, + .num_parents = 1, + /* + * This clock is used to debug the sys_pll range +@@ -241,7 +254,9 @@ static struct clk_fixed_factor g12a_sys_pll_div16 = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_div16", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "sys_pll_div16_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sys_pll_div16_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -252,11 +267,75 @@ static struct clk_fixed_factor g12b_sys1_pll_div16 = { + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll_div16", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "sys1_pll_div16_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_sys1_pll_div16_en.hw ++ }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_fixed_factor g12a_fclk_div2_div = { ++ .mult = 1, ++ .div = 2, ++ .hw.init = &(struct clk_init_data){ ++ .name = "fclk_div2_div", ++ .ops = &clk_fixed_factor_ops, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12a_fclk_div2 = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_FIX_PLL_CNTL1, ++ .bit_idx = 24, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "fclk_div2", ++ .ops = &clk_regmap_gate_ops, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fclk_div2_div.hw ++ }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_fixed_factor g12a_fclk_div3_div = { ++ .mult = 1, ++ .div = 3, ++ .hw.init = &(struct clk_init_data){ ++ .name = "fclk_div3_div", ++ .ops = &clk_fixed_factor_ops, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, + }; + ++static struct clk_regmap g12a_fclk_div3 = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_FIX_PLL_CNTL1, ++ .bit_idx = 20, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "fclk_div3", ++ .ops = &clk_regmap_gate_ops, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fclk_div3_div.hw ++ }, ++ .num_parents = 1, ++ /* ++ * This clock is used by the resident firmware and is required ++ * by the platform to operate correctly. ++ * Until the following condition are met, we need this clock to ++ * be marked as critical: ++ * a) Mark the clock used by a firmware resource, if possible ++ * b) CCF has a clock hand-off mechanism to make the sure the ++ * clock stays on until the proper driver comes along ++ */ ++ .flags = CLK_IS_CRITICAL, ++ }, ++}; ++ + /* Datasheet names this field as "premux0" */ + static struct clk_regmap g12a_cpu_clk_premux0 = { + .data = &(struct clk_regmap_mux_data){ +@@ -267,9 +346,30 @@ static struct clk_regmap g12a_cpu_clk_premux0 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal", +- "fclk_div2", +- "fclk_div3" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_fclk_div2.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ }, ++ .num_parents = 3, ++ }, ++}; ++ ++/* Datasheet names this field as "premux1" */ ++static struct clk_regmap g12a_cpu_clk_premux1 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x3, ++ .shift = 16, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn1_sel", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_fclk_div2.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ }, + .num_parents = 3, + }, + }; +@@ -284,7 +384,9 @@ static struct clk_regmap g12a_cpu_clk_mux0_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_dyn0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_premux0.hw ++ }, + .num_parents = 1, + }, + }; +@@ -299,29 +401,14 @@ static struct clk_regmap g12a_cpu_clk_postmux0 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_dyn0_sel", +- "cpu_clk_dyn0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_premux0.hw, ++ &g12a_cpu_clk_mux0_div.hw, ++ }, + .num_parents = 2, + }, + }; + +-/* Datasheet names this field as "premux1" */ +-static struct clk_regmap g12a_cpu_clk_premux1 = { +- .data = &(struct clk_regmap_mux_data){ +- .offset = HHI_SYS_CPU_CLK_CNTL0, +- .mask = 0x3, +- .shift = 16, +- }, +- .hw.init = &(struct clk_init_data){ +- .name = "cpu_clk_dyn1_sel", +- .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal", +- "fclk_div2", +- "fclk_div3" }, +- .num_parents = 3, +- }, +-}; +- + /* Datasheet names this field as "Mux1_divn_tcnt" */ + static struct clk_regmap g12a_cpu_clk_mux1_div = { + .data = &(struct clk_regmap_div_data){ +@@ -332,7 +419,9 @@ static struct clk_regmap g12a_cpu_clk_mux1_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_dyn1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_premux1.hw ++ }, + .num_parents = 1, + }, + }; +@@ -347,8 +436,10 @@ static struct clk_regmap g12a_cpu_clk_postmux1 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_dyn1_sel", +- "cpu_clk_dyn1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_premux1.hw, ++ &g12a_cpu_clk_mux1_div.hw, ++ }, + .num_parents = 2, + }, + }; +@@ -363,8 +454,10 @@ static struct clk_regmap g12a_cpu_clk_dyn = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_dyn0", +- "cpu_clk_dyn1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_postmux0.hw, ++ &g12a_cpu_clk_postmux1.hw, ++ }, + .num_parents = 2, + }, + }; +@@ -379,8 +472,10 @@ static struct clk_regmap g12a_cpu_clk = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_dyn", +- "sys_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_dyn.hw, ++ &g12a_sys_pll.hw, ++ }, + .num_parents = 2, + }, + }; +@@ -395,8 +490,10 @@ static struct clk_regmap g12b_cpu_clk = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_dyn", +- "sys1_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_dyn.hw, ++ &g12b_sys1_pll.hw ++ }, + .num_parents = 2, + }, + }; +@@ -411,9 +508,11 @@ static struct clk_regmap g12b_cpub_clk_premux0 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal", +- "fclk_div2", +- "fclk_div3" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_fclk_div2.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ }, + .num_parents = 3, + }, + }; +@@ -428,7 +527,9 @@ static struct clk_regmap g12b_cpub_clk_mux0_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_dyn0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_premux0.hw ++ }, + .num_parents = 1, + }, + }; +@@ -443,8 +544,10 @@ static struct clk_regmap g12b_cpub_clk_postmux0 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_dyn0_sel", +- "cpub_clk_dyn0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_premux0.hw, ++ &g12b_cpub_clk_mux0_div.hw ++ }, + .num_parents = 2, + }, + }; +@@ -459,9 +562,11 @@ static struct clk_regmap g12b_cpub_clk_premux1 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal", +- "fclk_div2", +- "fclk_div3" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_fclk_div2.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ }, + .num_parents = 3, + }, + }; +@@ -476,7 +581,9 @@ static struct clk_regmap g12b_cpub_clk_mux1_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_dyn1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_premux1.hw ++ }, + .num_parents = 1, + }, + }; +@@ -491,8 +598,10 @@ static struct clk_regmap g12b_cpub_clk_postmux1 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_dyn1_sel", +- "cpub_clk_dyn1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_premux1.hw, ++ &g12b_cpub_clk_mux1_div.hw ++ }, + .num_parents = 2, + }, + }; +@@ -507,8 +616,10 @@ static struct clk_regmap g12b_cpub_clk_dyn = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_dyn0", +- "cpub_clk_dyn1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_postmux0.hw, ++ &g12b_cpub_clk_postmux1.hw ++ }, + .num_parents = 2, + }, + }; +@@ -523,8 +634,10 @@ static struct clk_regmap g12b_cpub_clk = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_dyn", +- "sys_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_dyn.hw, ++ &g12a_sys_pll.hw ++ }, + .num_parents = 2, + }, + }; +@@ -537,7 +650,9 @@ static struct clk_regmap g12a_cpu_clk_div16_en = { + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_div16_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk.hw ++ }, + .num_parents = 1, + /* + * This clock is used to debug the cpu_clk range +@@ -554,7 +669,9 @@ static struct clk_regmap g12b_cpub_clk_div16_en = { + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_div16_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + /* + * This clock is used to debug the cpu_clk range +@@ -569,7 +686,9 @@ static struct clk_fixed_factor g12a_cpu_clk_div16 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div16", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk_div16_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_div16_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -580,7 +699,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div16 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div16", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk_div16_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_div16_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -595,7 +716,7 @@ static struct clk_regmap g12a_cpu_clk_apb_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_apb_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_cpu_clk.hw }, + .num_parents = 1, + }, + }; +@@ -608,7 +729,9 @@ static struct clk_regmap g12a_cpu_clk_apb = { + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_apb", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_apb_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_apb_div.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -627,7 +750,7 @@ static struct clk_regmap g12a_cpu_clk_atb_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_atb_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_cpu_clk.hw }, + .num_parents = 1, + }, + }; +@@ -640,7 +763,9 @@ static struct clk_regmap g12a_cpu_clk_atb = { + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_atb", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_atb_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_atb_div.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -659,7 +784,7 @@ static struct clk_regmap g12a_cpu_clk_axi_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_axi_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_cpu_clk.hw }, + .num_parents = 1, + }, + }; +@@ -672,7 +797,9 @@ static struct clk_regmap g12a_cpu_clk_axi = { + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_axi", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_axi_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_axi_div.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -691,7 +818,17 @@ static struct clk_regmap g12a_cpu_clk_trace_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_trace_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_data = &(const struct clk_parent_data) { ++ /* ++ * Note: ++ * G12A and G12B have different cpu_clks (with ++ * different struct clk_hw). We fallback to the global ++ * naming string mechanism so cpu_clk_trace_div picks ++ * up the appropriate one. ++ */ ++ .name = "cpu_clk", ++ .index = -1, ++ }, + .num_parents = 1, + }, + }; +@@ -704,7 +841,9 @@ static struct clk_regmap g12a_cpu_clk_trace = { + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_trace", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpu_clk_trace_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cpu_clk_trace_div.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -719,7 +858,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -730,7 +871,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div3 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div3", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -741,7 +884,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -752,7 +897,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div5 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div5", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -763,7 +910,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div6 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -774,7 +923,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div7 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div7", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -785,7 +936,9 @@ static struct clk_fixed_factor g12b_cpub_clk_div8 = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div8", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpub_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -801,13 +954,15 @@ static struct clk_regmap g12b_cpub_clk_apb_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_apb_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_div2", +- "cpub_clk_div3", +- "cpub_clk_div4", +- "cpub_clk_div5", +- "cpub_clk_div6", +- "cpub_clk_div7", +- "cpub_clk_div8" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_div2.hw, ++ &g12b_cpub_clk_div3.hw, ++ &g12b_cpub_clk_div4.hw, ++ &g12b_cpub_clk_div5.hw, ++ &g12b_cpub_clk_div6.hw, ++ &g12b_cpub_clk_div7.hw, ++ &g12b_cpub_clk_div8.hw ++ }, + .num_parents = 7, + }, + }; +@@ -821,7 +976,9 @@ static struct clk_regmap g12b_cpub_clk_apb = { + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_apb", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_apb_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_apb_sel.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -840,13 +997,15 @@ static struct clk_regmap g12b_cpub_clk_atb_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_atb_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_div2", +- "cpub_clk_div3", +- "cpub_clk_div4", +- "cpub_clk_div5", +- "cpub_clk_div6", +- "cpub_clk_div7", +- "cpub_clk_div8" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_div2.hw, ++ &g12b_cpub_clk_div3.hw, ++ &g12b_cpub_clk_div4.hw, ++ &g12b_cpub_clk_div5.hw, ++ &g12b_cpub_clk_div6.hw, ++ &g12b_cpub_clk_div7.hw, ++ &g12b_cpub_clk_div8.hw ++ }, + .num_parents = 7, + }, + }; +@@ -860,7 +1019,9 @@ static struct clk_regmap g12b_cpub_clk_atb = { + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_atb", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_atb_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_atb_sel.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -879,13 +1040,15 @@ static struct clk_regmap g12b_cpub_clk_axi_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_axi_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_div2", +- "cpub_clk_div3", +- "cpub_clk_div4", +- "cpub_clk_div5", +- "cpub_clk_div6", +- "cpub_clk_div7", +- "cpub_clk_div8" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_div2.hw, ++ &g12b_cpub_clk_div3.hw, ++ &g12b_cpub_clk_div4.hw, ++ &g12b_cpub_clk_div5.hw, ++ &g12b_cpub_clk_div6.hw, ++ &g12b_cpub_clk_div7.hw, ++ &g12b_cpub_clk_div8.hw ++ }, + .num_parents = 7, + }, + }; +@@ -899,7 +1062,9 @@ static struct clk_regmap g12b_cpub_clk_axi = { + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_axi", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_axi_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_axi_sel.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -918,13 +1083,15 @@ static struct clk_regmap g12b_cpub_clk_trace_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_trace_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_div2", +- "cpub_clk_div3", +- "cpub_clk_div4", +- "cpub_clk_div5", +- "cpub_clk_div6", +- "cpub_clk_div7", +- "cpub_clk_div8" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_div2.hw, ++ &g12b_cpub_clk_div3.hw, ++ &g12b_cpub_clk_div4.hw, ++ &g12b_cpub_clk_div5.hw, ++ &g12b_cpub_clk_div6.hw, ++ &g12b_cpub_clk_div7.hw, ++ &g12b_cpub_clk_div8.hw ++ }, + .num_parents = 7, + }, + }; +@@ -938,7 +1105,9 @@ static struct clk_regmap g12b_cpub_clk_trace = { + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_trace", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cpub_clk_trace_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12b_cpub_clk_trace_sel.hw ++ }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, +@@ -1003,7 +1172,9 @@ static struct clk_regmap g12a_gp0_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -1019,7 +1190,9 @@ static struct clk_regmap g12a_gp0_pll = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "gp0_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_gp0_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1077,7 +1250,9 @@ static struct clk_regmap g12a_hifi_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -1093,7 +1268,9 @@ static struct clk_regmap g12a_hifi_pll = { + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "hifi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_hifi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1164,7 +1341,9 @@ static struct clk_regmap g12a_pcie_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pcie_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -1175,7 +1354,9 @@ static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "pcie_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_pcie_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1193,7 +1374,9 @@ static struct clk_regmap g12a_pcie_pll_od = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "pcie_pll_dco_div2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_pcie_pll_dco_div2.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1205,7 +1388,9 @@ static struct clk_fixed_factor g12a_pcie_pll = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_pll", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "pcie_pll_od" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_pcie_pll_od.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1247,7 +1432,9 @@ static struct clk_regmap g12a_hdmi_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need +@@ -1267,7 +1454,9 @@ static struct clk_regmap g12a_hdmi_pll_od = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_hdmi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -1283,7 +1472,9 @@ static struct clk_regmap g12a_hdmi_pll_od2 = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_od" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_hdmi_pll_od.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -1299,77 +1490,21 @@ static struct clk_regmap g12a_hdmi_pll = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_od2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_hdmi_pll_od2.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, + }; + +-static struct clk_fixed_factor g12a_fclk_div2_div = { +- .mult = 1, +- .div = 2, +- .hw.init = &(struct clk_init_data){ +- .name = "fclk_div2_div", +- .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, +- .num_parents = 1, +- }, +-}; +- +-static struct clk_regmap g12a_fclk_div2 = { +- .data = &(struct clk_regmap_gate_data){ +- .offset = HHI_FIX_PLL_CNTL1, +- .bit_idx = 24, +- }, +- .hw.init = &(struct clk_init_data){ +- .name = "fclk_div2", +- .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div2_div" }, +- .num_parents = 1, +- }, +-}; +- +-static struct clk_fixed_factor g12a_fclk_div3_div = { +- .mult = 1, +- .div = 3, +- .hw.init = &(struct clk_init_data){ +- .name = "fclk_div3_div", +- .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, +- .num_parents = 1, +- }, +-}; +- +-static struct clk_regmap g12a_fclk_div3 = { +- .data = &(struct clk_regmap_gate_data){ +- .offset = HHI_FIX_PLL_CNTL1, +- .bit_idx = 20, +- }, +- .hw.init = &(struct clk_init_data){ +- .name = "fclk_div3", +- .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div3_div" }, +- .num_parents = 1, +- /* +- * This clock is used by the resident firmware and is required +- * by the platform to operate correctly. +- * Until the following condition are met, we need this clock to +- * be marked as critical: +- * a) Mark the clock used by a firmware resource, if possible +- * b) CCF has a clock hand-off mechanism to make the sure the +- * clock stays on until the proper driver comes along +- */ +- .flags = CLK_IS_CRITICAL, +- }, +-}; +- + static struct clk_fixed_factor g12a_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -1382,7 +1517,9 @@ static struct clk_regmap g12a_fclk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div4_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fclk_div4_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1393,7 +1530,7 @@ static struct clk_fixed_factor g12a_fclk_div5_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -1406,7 +1543,9 @@ static struct clk_regmap g12a_fclk_div5 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div5_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fclk_div5_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1417,7 +1556,7 @@ static struct clk_fixed_factor g12a_fclk_div7_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -1430,7 +1569,9 @@ static struct clk_regmap g12a_fclk_div7 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div7_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fclk_div7_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1441,7 +1582,9 @@ static struct clk_fixed_factor g12a_fclk_div2p5_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fixed_pll_dco.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1454,7 +1597,9 @@ static struct clk_regmap g12a_fclk_div2p5 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div2p5_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fclk_div2p5_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1465,7 +1610,9 @@ static struct clk_fixed_factor g12a_mpll_50m_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fixed_pll_dco.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1479,8 +1626,10 @@ static struct clk_regmap g12a_mpll_50m = { + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal", +- "mpll_50m_div" }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_mpll_50m_div.hw }, ++ }, + .num_parents = 2, + }, + }; +@@ -1491,7 +1640,9 @@ static struct clk_fixed_factor g12a_mpll_prediv = { + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_fixed_pll_dco.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1529,7 +1680,9 @@ static struct clk_regmap g12a_mpll0_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1542,7 +1695,7 @@ static struct clk_regmap g12a_mpll0 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_mpll0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1581,7 +1734,9 @@ static struct clk_regmap g12a_mpll1_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1594,7 +1749,7 @@ static struct clk_regmap g12a_mpll1 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1633,7 +1788,9 @@ static struct clk_regmap g12a_mpll2_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1646,7 +1803,7 @@ static struct clk_regmap g12a_mpll2 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1685,7 +1842,9 @@ static struct clk_regmap g12a_mpll3_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1698,16 +1857,21 @@ static struct clk_regmap g12a_mpll3 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll3_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_mpll3_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + + static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; +-static const char * const clk81_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", +- "fclk_div3", "fclk_div5" ++static const struct clk_parent_data clk81_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_fclk_div7.hw }, ++ { .hw = &g12a_mpll1.hw }, ++ { .hw = &g12a_mpll2.hw }, ++ { .hw = &g12a_fclk_div4.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ { .hw = &g12a_fclk_div5.hw }, + }; + + static struct clk_regmap g12a_mpeg_clk_sel = { +@@ -1720,8 +1884,8 @@ static struct clk_regmap g12a_mpeg_clk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = clk81_parent_names, +- .num_parents = ARRAY_SIZE(clk81_parent_names), ++ .parent_data = clk81_parent_data, ++ .num_parents = ARRAY_SIZE(clk81_parent_data), + }, + }; + +@@ -1734,7 +1898,9 @@ static struct clk_regmap g12a_mpeg_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mpeg_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mpeg_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1748,15 +1914,20 @@ static struct clk_regmap g12a_clk81 = { + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpeg_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mpeg_clk_div.hw ++ }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + }, + }; + +-static const char * const g12a_sd_emmc_clk0_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", +- ++static const struct clk_parent_data g12a_sd_emmc_clk0_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_fclk_div2.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ { .hw = &g12a_fclk_div5.hw }, ++ { .hw = &g12a_fclk_div7.hw }, + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All +@@ -1775,8 +1946,8 @@ static struct clk_regmap g12a_sd_emmc_a_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), ++ .parent_data = g12a_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1790,7 +1961,9 @@ static struct clk_regmap g12a_sd_emmc_a_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sd_emmc_a_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1804,7 +1977,9 @@ static struct clk_regmap g12a_sd_emmc_a_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sd_emmc_a_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1820,8 +1995,8 @@ static struct clk_regmap g12a_sd_emmc_b_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), ++ .parent_data = g12a_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1835,7 +2010,9 @@ static struct clk_regmap g12a_sd_emmc_b_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sd_emmc_b_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1849,7 +2026,9 @@ static struct clk_regmap g12a_sd_emmc_b_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sd_emmc_b_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1865,8 +2044,8 @@ static struct clk_regmap g12a_sd_emmc_c_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), ++ .parent_data = g12a_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1880,7 +2059,9 @@ static struct clk_regmap g12a_sd_emmc_c_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sd_emmc_c_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1894,17 +2075,89 @@ static struct clk_regmap g12a_sd_emmc_c_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_sd_emmc_c_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + ++/* Video Clocks */ ++ ++static struct clk_regmap g12a_vid_pll_div = { ++ .data = &(struct meson_vid_pll_div_data){ ++ .val = { ++ .reg_off = HHI_VID_PLL_CLK_DIV, ++ .shift = 0, ++ .width = 15, ++ }, ++ .sel = { ++ .reg_off = HHI_VID_PLL_CLK_DIV, ++ .shift = 16, ++ .width = 2, ++ }, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "vid_pll_div", ++ .ops = &meson_vid_pll_div_ro_ops, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_pll.hw }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, ++ }, ++}; ++ ++static const struct clk_hw *g12a_vid_pll_parent_hws[] = { ++ &g12a_vid_pll_div.hw, ++ &g12a_hdmi_pll.hw, ++}; ++ ++static struct clk_regmap g12a_vid_pll_sel = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_VID_PLL_CLK_DIV, ++ .mask = 0x1, ++ .shift = 18, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "vid_pll_sel", ++ .ops = &clk_regmap_mux_ops, ++ /* ++ * bit 18 selects from 2 possible parents: ++ * vid_pll_div or hdmi_pll ++ */ ++ .parent_hws = g12a_vid_pll_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vid_pll_parent_hws), ++ .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, ++ }, ++}; ++ ++static struct clk_regmap g12a_vid_pll = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_VID_PLL_CLK_DIV, ++ .bit_idx = 19, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "vid_pll", ++ .ops = &clk_regmap_gate_ops, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vid_pll_sel.hw ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, ++ }, ++}; ++ + /* VPU Clock */ + +-static const char * const g12a_vpu_parent_names[] = { +- "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7", +- "mpll1", "vid_pll", "hifi_pll", "gp0_pll", ++static const struct clk_hw *g12a_vpu_parent_hws[] = { ++ &g12a_fclk_div3.hw, ++ &g12a_fclk_div4.hw, ++ &g12a_fclk_div5.hw, ++ &g12a_fclk_div7.hw, ++ &g12a_mpll1.hw, ++ &g12a_vid_pll.hw, ++ &g12a_hifi_pll.hw, ++ &g12a_gp0_pll.hw, + }; + + static struct clk_regmap g12a_vpu_0_sel = { +@@ -1916,8 +2169,8 @@ static struct clk_regmap g12a_vpu_0_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vpu_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vpu_parent_names), ++ .parent_hws = g12a_vpu_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vpu_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -1931,7 +2184,7 @@ static struct clk_regmap g12a_vpu_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vpu_0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1945,7 +2198,7 @@ static struct clk_regmap g12a_vpu_0 = { + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vpu_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1960,8 +2213,8 @@ static struct clk_regmap g12a_vpu_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vpu_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vpu_parent_names), ++ .parent_hws = g12a_vpu_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vpu_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -1975,7 +2228,7 @@ static struct clk_regmap g12a_vpu_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vpu_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1989,7 +2242,7 @@ static struct clk_regmap g12a_vpu_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vpu_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2008,7 +2261,10 @@ static struct clk_regmap g12a_vpu = { + * bit 31 selects from 2 possible parents: + * vpu_0 or vpu_1 + */ +- .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vpu_0.hw, ++ &g12a_vpu_1.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -2016,9 +2272,14 @@ static struct clk_regmap g12a_vpu = { + + /* VDEC clocks */ + +-static const char * const g12a_vdec_parent_names[] = { +- "fclk_div2p5", "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7", +- "hifi_pll", "gp0_pll", ++static const struct clk_hw *g12a_vdec_parent_hws[] = { ++ &g12a_fclk_div2p5.hw, ++ &g12a_fclk_div3.hw, ++ &g12a_fclk_div4.hw, ++ &g12a_fclk_div5.hw, ++ &g12a_fclk_div7.hw, ++ &g12a_hifi_pll.hw, ++ &g12a_gp0_pll.hw, + }; + + static struct clk_regmap g12a_vdec_1_sel = { +@@ -2031,8 +2292,8 @@ static struct clk_regmap g12a_vdec_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vdec_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), ++ .parent_hws = g12a_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2047,7 +2308,9 @@ static struct clk_regmap g12a_vdec_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vdec_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2061,7 +2324,9 @@ static struct clk_regmap g12a_vdec_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vdec_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2077,8 +2342,8 @@ static struct clk_regmap g12a_vdec_hevcf_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevcf_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vdec_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), ++ .parent_hws = g12a_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2093,7 +2358,9 @@ static struct clk_regmap g12a_vdec_hevcf_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevcf_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_hevcf_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vdec_hevcf_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2107,7 +2374,9 @@ static struct clk_regmap g12a_vdec_hevcf = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevcf", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_hevcf_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vdec_hevcf_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2123,8 +2392,8 @@ static struct clk_regmap g12a_vdec_hevc_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vdec_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), ++ .parent_hws = g12a_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2139,7 +2408,9 @@ static struct clk_regmap g12a_vdec_hevc_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_hevc_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vdec_hevc_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2153,7 +2424,9 @@ static struct clk_regmap g12a_vdec_hevc = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_hevc_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vdec_hevc_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2161,9 +2434,15 @@ static struct clk_regmap g12a_vdec_hevc = { + + /* VAPB Clock */ + +-static const char * const g12a_vapb_parent_names[] = { +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", +- "mpll1", "vid_pll", "mpll2", "fclk_div2p5", ++static const struct clk_hw *g12a_vapb_parent_hws[] = { ++ &g12a_fclk_div4.hw, ++ &g12a_fclk_div3.hw, ++ &g12a_fclk_div5.hw, ++ &g12a_fclk_div7.hw, ++ &g12a_mpll1.hw, ++ &g12a_vid_pll.hw, ++ &g12a_mpll2.hw, ++ &g12a_fclk_div2p5.hw, + }; + + static struct clk_regmap g12a_vapb_0_sel = { +@@ -2175,8 +2454,8 @@ static struct clk_regmap g12a_vapb_0_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vapb_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vapb_parent_names), ++ .parent_hws = g12a_vapb_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vapb_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -2190,7 +2469,9 @@ static struct clk_regmap g12a_vapb_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vapb_0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vapb_0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2204,7 +2485,9 @@ static struct clk_regmap g12a_vapb_0 = { + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vapb_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vapb_0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2219,8 +2502,8 @@ static struct clk_regmap g12a_vapb_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vapb_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vapb_parent_names), ++ .parent_hws = g12a_vapb_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vapb_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -2234,7 +2517,9 @@ static struct clk_regmap g12a_vapb_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vapb_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vapb_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2248,7 +2533,9 @@ static struct clk_regmap g12a_vapb_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vapb_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vapb_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2267,7 +2554,10 @@ static struct clk_regmap g12a_vapb_sel = { + * bit 31 selects from 2 possible parents: + * vapb_0 or vapb_1 + */ +- .parent_names = (const char *[]){ "vapb_0", "vapb_1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vapb_0.hw, ++ &g12a_vapb_1.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -2281,75 +2571,21 @@ static struct clk_regmap g12a_vapb = { + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vapb_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vapb_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }; + +-/* Video Clocks */ +- +-static struct clk_regmap g12a_vid_pll_div = { +- .data = &(struct meson_vid_pll_div_data){ +- .val = { +- .reg_off = HHI_VID_PLL_CLK_DIV, +- .shift = 0, +- .width = 15, +- }, +- .sel = { +- .reg_off = HHI_VID_PLL_CLK_DIV, +- .shift = 16, +- .width = 2, +- }, +- }, +- .hw.init = &(struct clk_init_data) { +- .name = "vid_pll_div", +- .ops = &meson_vid_pll_div_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll" }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, +- }, +-}; +- +-static const char * const g12a_vid_pll_parent_names[] = { "vid_pll_div", +- "hdmi_pll" }; +- +-static struct clk_regmap g12a_vid_pll_sel = { +- .data = &(struct clk_regmap_mux_data){ +- .offset = HHI_VID_PLL_CLK_DIV, +- .mask = 0x1, +- .shift = 18, +- }, +- .hw.init = &(struct clk_init_data){ +- .name = "vid_pll_sel", +- .ops = &clk_regmap_mux_ops, +- /* +- * bit 18 selects from 2 possible parents: +- * vid_pll_div or hdmi_pll +- */ +- .parent_names = g12a_vid_pll_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vid_pll_parent_names), +- .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, +- }, +-}; +- +-static struct clk_regmap g12a_vid_pll = { +- .data = &(struct clk_regmap_gate_data){ +- .offset = HHI_VID_PLL_CLK_DIV, +- .bit_idx = 19, +- }, +- .hw.init = &(struct clk_init_data) { +- .name = "vid_pll", +- .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vid_pll_sel" }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, +- }, +-}; +- +-static const char * const g12a_vclk_parent_names[] = { +- "vid_pll", "gp0_pll", "hifi_pll", "mpll1", "fclk_div3", "fclk_div4", +- "fclk_div5", "fclk_div7" ++static const struct clk_hw *g12a_vclk_parent_hws[] = { ++ &g12a_vid_pll.hw, ++ &g12a_gp0_pll.hw, ++ &g12a_hifi_pll.hw, ++ &g12a_mpll1.hw, ++ &g12a_fclk_div3.hw, ++ &g12a_fclk_div4.hw, ++ &g12a_fclk_div5.hw, ++ &g12a_fclk_div7.hw, + }; + + static struct clk_regmap g12a_vclk_sel = { +@@ -2361,8 +2597,8 @@ static struct clk_regmap g12a_vclk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vclk_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vclk_parent_names), ++ .parent_hws = g12a_vclk_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2376,8 +2612,8 @@ static struct clk_regmap g12a_vclk2_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_vclk_parent_names, +- .num_parents = ARRAY_SIZE(g12a_vclk_parent_names), ++ .parent_hws = g12a_vclk_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2390,7 +2626,7 @@ static struct clk_regmap g12a_vclk_input = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2404,7 +2640,7 @@ static struct clk_regmap g12a_vclk2_input = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2419,7 +2655,9 @@ static struct clk_regmap g12a_vclk_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vclk_input" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk_input.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +@@ -2434,7 +2672,9 @@ static struct clk_regmap g12a_vclk2_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vclk2_input" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk2_input.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +@@ -2448,7 +2688,7 @@ static struct clk_regmap g12a_vclk = { + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2462,7 +2702,7 @@ static struct clk_regmap g12a_vclk2 = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2476,7 +2716,7 @@ static struct clk_regmap g12a_vclk_div1 = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2490,7 +2730,7 @@ static struct clk_regmap g12a_vclk_div2_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2504,7 +2744,7 @@ static struct clk_regmap g12a_vclk_div4_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2518,7 +2758,7 @@ static struct clk_regmap g12a_vclk_div6_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2532,7 +2772,7 @@ static struct clk_regmap g12a_vclk_div12_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2546,7 +2786,7 @@ static struct clk_regmap g12a_vclk2_div1 = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2560,7 +2800,7 @@ static struct clk_regmap g12a_vclk2_div2_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2574,7 +2814,7 @@ static struct clk_regmap g12a_vclk2_div4_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2588,7 +2828,7 @@ static struct clk_regmap g12a_vclk2_div6_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2602,7 +2842,7 @@ static struct clk_regmap g12a_vclk2_div12_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2614,7 +2854,9 @@ static struct clk_fixed_factor g12a_vclk_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div2_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk_div2_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -2625,7 +2867,9 @@ static struct clk_fixed_factor g12a_vclk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div4_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk_div4_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -2636,7 +2880,9 @@ static struct clk_fixed_factor g12a_vclk_div6 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div6_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk_div6_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -2647,7 +2893,9 @@ static struct clk_fixed_factor g12a_vclk_div12 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div12_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk_div12_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -2658,7 +2906,9 @@ static struct clk_fixed_factor g12a_vclk2_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div2_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk2_div2_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -2669,7 +2919,9 @@ static struct clk_fixed_factor g12a_vclk2_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div4_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk2_div4_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -2680,7 +2932,9 @@ static struct clk_fixed_factor g12a_vclk2_div6 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div6_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk2_div6_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -2691,16 +2945,25 @@ static struct clk_fixed_factor g12a_vclk2_div12 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div12_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_vclk2_div12_en.hw ++ }, + .num_parents = 1, + }, + }; + + static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +-static const char * const g12a_cts_parent_names[] = { +- "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", +- "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", +- "vclk2_div6", "vclk2_div12" ++static const struct clk_hw *g12a_cts_parent_hws[] = { ++ &g12a_vclk_div1.hw, ++ &g12a_vclk_div2.hw, ++ &g12a_vclk_div4.hw, ++ &g12a_vclk_div6.hw, ++ &g12a_vclk_div12.hw, ++ &g12a_vclk2_div1.hw, ++ &g12a_vclk2_div2.hw, ++ &g12a_vclk2_div4.hw, ++ &g12a_vclk2_div6.hw, ++ &g12a_vclk2_div12.hw, + }; + + static struct clk_regmap g12a_cts_enci_sel = { +@@ -2713,8 +2976,8 @@ static struct clk_regmap g12a_cts_enci_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_cts_parent_names, +- .num_parents = ARRAY_SIZE(g12a_cts_parent_names), ++ .parent_hws = g12a_cts_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2729,8 +2992,8 @@ static struct clk_regmap g12a_cts_encp_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_cts_parent_names, +- .num_parents = ARRAY_SIZE(g12a_cts_parent_names), ++ .parent_hws = g12a_cts_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2745,18 +3008,25 @@ static struct clk_regmap g12a_cts_vdac_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_cts_parent_names, +- .num_parents = ARRAY_SIZE(g12a_cts_parent_names), ++ .parent_hws = g12a_cts_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; + + /* TOFIX: add support for cts_tcon */ + static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +-static const char * const g12a_cts_hdmi_tx_parent_names[] = { +- "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", +- "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", +- "vclk2_div6", "vclk2_div12" ++static const struct clk_hw *g12a_cts_hdmi_tx_parent_hws[] = { ++ &g12a_vclk_div1.hw, ++ &g12a_vclk_div2.hw, ++ &g12a_vclk_div4.hw, ++ &g12a_vclk_div6.hw, ++ &g12a_vclk_div12.hw, ++ &g12a_vclk2_div1.hw, ++ &g12a_vclk2_div2.hw, ++ &g12a_vclk2_div4.hw, ++ &g12a_vclk2_div6.hw, ++ &g12a_vclk2_div12.hw, + }; + + static struct clk_regmap g12a_hdmi_tx_sel = { +@@ -2769,8 +3039,8 @@ static struct clk_regmap g12a_hdmi_tx_sel = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_cts_hdmi_tx_parent_names, +- .num_parents = ARRAY_SIZE(g12a_cts_hdmi_tx_parent_names), ++ .parent_hws = g12a_cts_hdmi_tx_parent_hws, ++ .num_parents = ARRAY_SIZE(g12a_cts_hdmi_tx_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2783,7 +3053,9 @@ static struct clk_regmap g12a_cts_enci = { + .hw.init = &(struct clk_init_data) { + .name = "cts_enci", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_enci_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cts_enci_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2797,7 +3069,9 @@ static struct clk_regmap g12a_cts_encp = { + .hw.init = &(struct clk_init_data) { + .name = "cts_encp", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_encp_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cts_encp_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2811,7 +3085,9 @@ static struct clk_regmap g12a_cts_vdac = { + .hw.init = &(struct clk_init_data) { + .name = "cts_vdac", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_vdac_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_cts_vdac_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2825,7 +3101,9 @@ static struct clk_regmap g12a_hdmi_tx = { + .hw.init = &(struct clk_init_data) { + .name = "hdmi_tx", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "hdmi_tx_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_hdmi_tx_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2833,8 +3111,11 @@ static struct clk_regmap g12a_hdmi_tx = { + + /* HDMI Clocks */ + +-static const char * const g12a_hdmi_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5" ++static const struct clk_parent_data g12a_hdmi_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_fclk_div4.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ { .hw = &g12a_fclk_div5.hw }, + }; + + static struct clk_regmap g12a_hdmi_sel = { +@@ -2847,8 +3128,8 @@ static struct clk_regmap g12a_hdmi_sel = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_hdmi_parent_names, +- .num_parents = ARRAY_SIZE(g12a_hdmi_parent_names), ++ .parent_data = g12a_hdmi_parent_data, ++ .num_parents = ARRAY_SIZE(g12a_hdmi_parent_data), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2862,7 +3143,7 @@ static struct clk_regmap g12a_hdmi_div = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "hdmi_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_sel.hw }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +@@ -2876,7 +3157,7 @@ static struct clk_regmap g12a_hdmi = { + .hw.init = &(struct clk_init_data) { + .name = "hdmi", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "hdmi_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2886,10 +3167,15 @@ static struct clk_regmap g12a_hdmi = { + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch. + */ +- +-static const char * const g12a_mali_0_1_parent_names[] = { +- IN_PREFIX "xtal", "gp0_pll", "hifi_pll", "fclk_div2p5", +- "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7" ++static const struct clk_parent_data g12a_mali_0_1_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &g12a_gp0_pll.hw }, ++ { .hw = &g12a_hifi_pll.hw }, ++ { .hw = &g12a_fclk_div2p5.hw }, ++ { .hw = &g12a_fclk_div3.hw }, ++ { .hw = &g12a_fclk_div4.hw }, ++ { .hw = &g12a_fclk_div5.hw }, ++ { .hw = &g12a_fclk_div7.hw }, + }; + + static struct clk_regmap g12a_mali_0_sel = { +@@ -2901,7 +3187,7 @@ static struct clk_regmap g12a_mali_0_sel = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_mali_0_1_parent_names, ++ .parent_data = g12a_mali_0_1_parent_data, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -2916,7 +3202,9 @@ static struct clk_regmap g12a_mali_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mali_0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mali_0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -2930,7 +3218,9 @@ static struct clk_regmap g12a_mali_0 = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mali_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mali_0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2945,7 +3235,7 @@ static struct clk_regmap g12a_mali_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_mali_0_1_parent_names, ++ .parent_data = g12a_mali_0_1_parent_data, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -2960,7 +3250,9 @@ static struct clk_regmap g12a_mali_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mali_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mali_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -2974,14 +3266,17 @@ static struct clk_regmap g12a_mali_1 = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mali_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_mali_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + +-static const char * const g12a_mali_parent_names[] = { +- "mali_0", "mali_1" ++static const struct clk_hw *g12a_mali_parent_hws[] = { ++ &g12a_mali_0.hw, ++ &g12a_mali_1.hw, + }; + + static struct clk_regmap g12a_mali = { +@@ -2993,7 +3288,7 @@ static struct clk_regmap g12a_mali = { + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, +- .parent_names = g12a_mali_parent_names, ++ .parent_hws = g12a_mali_parent_hws, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -3008,7 +3303,9 @@ static struct clk_regmap g12a_ts_div = { + .hw.init = &(struct clk_init_data){ + .name = "ts_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -3021,7 +3318,9 @@ static struct clk_regmap g12a_ts = { + .hw.init = &(struct clk_init_data){ + .name = "ts", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "ts_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &g12a_ts_div.hw ++ }, + .num_parents = 1, + }, + }; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0009-FROMGIT-clk-meson-gxbb-migrate-to-the-new-parent-des.patch b/packages/linux/patches/amlogic/amlogic-0009-FROMGIT-clk-meson-gxbb-migrate-to-the-new-parent-des.patch new file mode 100644 index 0000000000..c25e2e3760 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0009-FROMGIT-clk-meson-gxbb-migrate-to-the-new-parent-des.patch @@ -0,0 +1,1677 @@ +From c46905eab972999ffc51d1dc51bdeca65113832d Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:42:33 +0200 +Subject: [PATCH 009/186] FROMGIT: clk: meson: gxbb: migrate to the new parent + description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (ie. when +all clocks are local to the controller) and use .parent_data otherwise. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit 0dea3f35996f4571eacbf6cac889d57bfd20822a + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/gxbb.c | 654 +++++++++++++++++++++++++++------------ + 1 file changed, 451 insertions(+), 203 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index dab16d9b1af8..67e466356d4b 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -10,15 +10,12 @@ + #include + + #include "gxbb.h" +-#include "clk-input.h" + #include "clk-regmap.h" + #include "clk-pll.h" + #include "clk-mpll.h" + #include "meson-eeclk.h" + #include "vid-pll-div.h" + +-#define IN_PREFIX "ee-in-" +- + static DEFINE_SPINLOCK(meson_clk_lock); + + static const struct pll_params_table gxbb_gp0_pll_params_table[] = { +@@ -121,7 +118,9 @@ static struct clk_regmap gxbb_fixed_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -136,7 +135,9 @@ static struct clk_regmap gxbb_fixed_pll = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "fixed_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_fixed_pll_dco.hw ++ }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so +@@ -151,7 +152,9 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_pre_mult", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -192,7 +195,9 @@ static struct clk_regmap gxbb_hdmi_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_hdmi_pll_pre_mult.hw ++ }, + .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need +@@ -244,7 +249,9 @@ static struct clk_regmap gxl_hdmi_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need +@@ -264,7 +271,9 @@ static struct clk_regmap gxbb_hdmi_pll_od = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_hdmi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -280,7 +289,9 @@ static struct clk_regmap gxbb_hdmi_pll_od2 = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_od" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_hdmi_pll_od.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -296,7 +307,9 @@ static struct clk_regmap gxbb_hdmi_pll = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_od2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_hdmi_pll_od2.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -312,7 +325,9 @@ static struct clk_regmap gxl_hdmi_pll_od = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxl_hdmi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -328,7 +343,9 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_od" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxl_hdmi_pll_od.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -344,7 +361,9 @@ static struct clk_regmap gxl_hdmi_pll = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_od2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxl_hdmi_pll_od2.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +@@ -381,7 +400,9 @@ static struct clk_regmap gxbb_sys_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -396,7 +417,9 @@ static struct clk_regmap gxbb_sys_pll = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "sys_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sys_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -442,7 +465,9 @@ static struct clk_regmap gxbb_gp0_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -494,7 +519,9 @@ static struct clk_regmap gxl_gp0_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -509,7 +536,17 @@ static struct clk_regmap gxbb_gp0_pll = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "gp0_pll_dco" }, ++ .parent_data = &(const struct clk_parent_data) { ++ /* ++ * Note: ++ * GXL and GXBB have different gp0_pll_dco (with ++ * different struct clk_hw). We fallback to the global ++ * naming string mechanism so gp0_pll picks up the ++ * appropriate one. ++ */ ++ .name = "gp0_pll_dco", ++ .index = -1, ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -521,7 +558,9 @@ static struct clk_fixed_factor gxbb_fclk_div2_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -534,7 +573,9 @@ static struct clk_regmap gxbb_fclk_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_fclk_div2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +@@ -546,7 +587,7 @@ static struct clk_fixed_factor gxbb_fclk_div3_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -559,7 +600,9 @@ static struct clk_regmap gxbb_fclk_div3 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div3_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_fclk_div3_div.hw ++ }, + .num_parents = 1, + /* + * FIXME: +@@ -582,7 +625,7 @@ static struct clk_fixed_factor gxbb_fclk_div4_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -595,7 +638,9 @@ static struct clk_regmap gxbb_fclk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div4_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_fclk_div4_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -606,7 +651,7 @@ static struct clk_fixed_factor gxbb_fclk_div5_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -619,7 +664,9 @@ static struct clk_regmap gxbb_fclk_div5 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div5_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_fclk_div5_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -630,7 +677,7 @@ static struct clk_fixed_factor gxbb_fclk_div7_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -643,7 +690,9 @@ static struct clk_regmap gxbb_fclk_div7 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div7_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_fclk_div7_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -657,7 +706,7 @@ static struct clk_regmap gxbb_mpll_prediv = { + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -684,7 +733,9 @@ static struct clk_regmap gxbb_mpll0_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -697,7 +748,7 @@ static struct clk_regmap gxbb_mpll0 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -725,7 +776,9 @@ static struct clk_regmap gxbb_mpll1_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -738,7 +791,7 @@ static struct clk_regmap gxbb_mpll1 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -766,7 +819,9 @@ static struct clk_regmap gxbb_mpll2_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -779,16 +834,21 @@ static struct clk_regmap gxbb_mpll2 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + + static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; +-static const char * const clk81_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", +- "fclk_div3", "fclk_div5" ++static const struct clk_parent_data clk81_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &gxbb_fclk_div7.hw }, ++ { .hw = &gxbb_mpll1.hw }, ++ { .hw = &gxbb_mpll2.hw }, ++ { .hw = &gxbb_fclk_div4.hw }, ++ { .hw = &gxbb_fclk_div3.hw }, ++ { .hw = &gxbb_fclk_div5.hw }, + }; + + static struct clk_regmap gxbb_mpeg_clk_sel = { +@@ -806,8 +866,8 @@ static struct clk_regmap gxbb_mpeg_clk_sel = { + * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, + * fclk_div4, fclk_div3, fclk_div5 + */ +- .parent_names = clk81_parent_names, +- .num_parents = ARRAY_SIZE(clk81_parent_names), ++ .parent_data = clk81_parent_data, ++ .num_parents = ARRAY_SIZE(clk81_parent_data), + }, + }; + +@@ -820,7 +880,9 @@ static struct clk_regmap gxbb_mpeg_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "mpeg_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mpeg_clk_sel.hw ++ }, + .num_parents = 1, + }, + }; +@@ -834,7 +896,9 @@ static struct clk_regmap gxbb_clk81 = { + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpeg_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mpeg_clk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +@@ -850,7 +914,10 @@ static struct clk_regmap gxbb_sar_adc_clk_sel = { + .name = "sar_adc_clk_sel", + .ops = &clk_regmap_mux_ops, + /* NOTE: The datasheet doesn't list the parents for bit 10 */ +- .parent_names = (const char *[]){ IN_PREFIX "xtal", "clk81", }, ++ .parent_data = (const struct clk_parent_data []) { ++ { .fw_name = "xtal", }, ++ { .hw = &gxbb_clk81.hw }, ++ }, + .num_parents = 2, + }, + }; +@@ -864,7 +931,9 @@ static struct clk_regmap gxbb_sar_adc_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "sar_adc_clk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sar_adc_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sar_adc_clk_sel.hw ++ }, + .num_parents = 1, + }, + }; +@@ -877,7 +946,9 @@ static struct clk_regmap gxbb_sar_adc_clk = { + .hw.init = &(struct clk_init_data){ + .name = "sar_adc_clk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sar_adc_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sar_adc_clk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -888,9 +959,15 @@ static struct clk_regmap gxbb_sar_adc_clk = { + * muxed by a glitch-free switch. + */ + +-static const char * const gxbb_mali_0_1_parent_names[] = { +- IN_PREFIX "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", +- "fclk_div4", "fclk_div3", "fclk_div5" ++static const struct clk_parent_data gxbb_mali_0_1_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &gxbb_gp0_pll.hw }, ++ { .hw = &gxbb_mpll2.hw }, ++ { .hw = &gxbb_mpll1.hw }, ++ { .hw = &gxbb_fclk_div7.hw }, ++ { .hw = &gxbb_fclk_div4.hw }, ++ { .hw = &gxbb_fclk_div3.hw }, ++ { .hw = &gxbb_fclk_div5.hw }, + }; + + static struct clk_regmap gxbb_mali_0_sel = { +@@ -907,7 +984,7 @@ static struct clk_regmap gxbb_mali_0_sel = { + * xtal, gp0_pll, mpll2, mpll1, fclk_div7, + * fclk_div4, fclk_div3, fclk_div5 + */ +- .parent_names = gxbb_mali_0_1_parent_names, ++ .parent_data = gxbb_mali_0_1_parent_data, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -922,7 +999,9 @@ static struct clk_regmap gxbb_mali_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mali_0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mali_0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -936,7 +1015,9 @@ static struct clk_regmap gxbb_mali_0 = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mali_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mali_0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -956,7 +1037,7 @@ static struct clk_regmap gxbb_mali_1_sel = { + * xtal, gp0_pll, mpll2, mpll1, fclk_div7, + * fclk_div4, fclk_div3, fclk_div5 + */ +- .parent_names = gxbb_mali_0_1_parent_names, ++ .parent_data = gxbb_mali_0_1_parent_data, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -971,7 +1052,9 @@ static struct clk_regmap gxbb_mali_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mali_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mali_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -985,14 +1068,17 @@ static struct clk_regmap gxbb_mali_1 = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mali_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mali_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + +-static const char * const gxbb_mali_parent_names[] = { +- "mali_0", "mali_1" ++static const struct clk_hw *gxbb_mali_parent_hws[] = { ++ &gxbb_mali_0.hw, ++ &gxbb_mali_1.hw, + }; + + static struct clk_regmap gxbb_mali = { +@@ -1004,7 +1090,7 @@ static struct clk_regmap gxbb_mali = { + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_mali_parent_names, ++ .parent_hws = gxbb_mali_parent_hws, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -1021,7 +1107,11 @@ static struct clk_regmap gxbb_cts_amclk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mpll0.hw, ++ &gxbb_mpll1.hw, ++ &gxbb_mpll2.hw, ++ }, + .num_parents = 3, + }, + }; +@@ -1036,7 +1126,9 @@ static struct clk_regmap gxbb_cts_amclk_div = { + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "cts_amclk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_amclk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1050,7 +1142,9 @@ static struct clk_regmap gxbb_cts_amclk = { + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_amclk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_amclk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1067,7 +1161,11 @@ static struct clk_regmap gxbb_cts_mclk_i958_sel = { + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_mpll0.hw, ++ &gxbb_mpll1.hw, ++ &gxbb_mpll2.hw, ++ }, + .num_parents = 3, + }, + }; +@@ -1082,7 +1180,9 @@ static struct clk_regmap gxbb_cts_mclk_i958_div = { + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_mclk_i958_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1096,7 +1196,9 @@ static struct clk_regmap gxbb_cts_mclk_i958 = { + .hw.init = &(struct clk_init_data){ + .name = "cts_mclk_i958", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_mclk_i958_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_mclk_i958_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1111,7 +1213,10 @@ static struct clk_regmap gxbb_cts_i958 = { + .hw.init = &(struct clk_init_data){ + .name = "cts_i958", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_amclk.hw, ++ &gxbb_cts_mclk_i958.hw ++ }, + .num_parents = 2, + /* + *The parent is specific to origin of the audio data. Let the +@@ -1121,6 +1226,33 @@ static struct clk_regmap gxbb_cts_i958 = { + }, + }; + ++static const struct clk_parent_data gxbb_32k_clk_parent_data[] = { ++ { .fw_name = "xtal", }, ++ /* ++ * FIXME: This clock is provided by the ao clock controller but the ++ * clock is not yet part of the binding of this controller, so string ++ * name must be use to set this parent. ++ */ ++ { .name = "cts_slow_oscin", .index = -1 }, ++ { .hw = &gxbb_fclk_div3.hw }, ++ { .hw = &gxbb_fclk_div5.hw }, ++}; ++ ++static struct clk_regmap gxbb_32k_clk_sel = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_32K_CLK_CNTL, ++ .mask = 0x3, ++ .shift = 16, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "32k_clk_sel", ++ .ops = &clk_regmap_mux_ops, ++ .parent_data = gxbb_32k_clk_parent_data, ++ .num_parents = 4, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ + static struct clk_regmap gxbb_32k_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_32K_CLK_CNTL, +@@ -1130,7 +1262,9 @@ static struct clk_regmap gxbb_32k_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "32k_clk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "32k_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_32k_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, + }, +@@ -1144,34 +1278,20 @@ static struct clk_regmap gxbb_32k_clk = { + .hw.init = &(struct clk_init_data){ + .name = "32k_clk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "32k_clk_div" }, +- .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, +- }, +-}; +- +-static const char * const gxbb_32k_clk_parent_names[] = { +- IN_PREFIX "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" +-}; +- +-static struct clk_regmap gxbb_32k_clk_sel = { +- .data = &(struct clk_regmap_mux_data){ +- .offset = HHI_32K_CLK_CNTL, +- .mask = 0x3, +- .shift = 16, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_32k_clk_div.hw + }, +- .hw.init = &(struct clk_init_data){ +- .name = "32k_clk_sel", +- .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_32k_clk_parent_names, +- .num_parents = 4, ++ .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + +-static const char * const gxbb_sd_emmc_clk0_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", +- ++static const struct clk_parent_data gxbb_sd_emmc_clk0_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &gxbb_fclk_div2.hw }, ++ { .hw = &gxbb_fclk_div3.hw }, ++ { .hw = &gxbb_fclk_div5.hw }, ++ { .hw = &gxbb_fclk_div7.hw }, + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All +@@ -1190,8 +1310,8 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), ++ .parent_data = gxbb_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1206,7 +1326,9 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sd_emmc_a_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1220,7 +1342,9 @@ static struct clk_regmap gxbb_sd_emmc_a_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sd_emmc_a_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1236,8 +1360,8 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), ++ .parent_data = gxbb_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1252,7 +1376,9 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sd_emmc_b_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1266,7 +1392,9 @@ static struct clk_regmap gxbb_sd_emmc_b_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sd_emmc_b_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1282,8 +1410,8 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), ++ .parent_data = gxbb_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1298,7 +1426,9 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sd_emmc_c_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1312,7 +1442,9 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_sd_emmc_c_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1320,8 +1452,11 @@ static struct clk_regmap gxbb_sd_emmc_c_clk0 = { + + /* VPU Clock */ + +-static const char * const gxbb_vpu_parent_names[] = { +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" ++static const struct clk_hw *gxbb_vpu_parent_hws[] = { ++ &gxbb_fclk_div4.hw, ++ &gxbb_fclk_div3.hw, ++ &gxbb_fclk_div5.hw, ++ &gxbb_fclk_div7.hw, + }; + + static struct clk_regmap gxbb_vpu_0_sel = { +@@ -1337,8 +1472,8 @@ static struct clk_regmap gxbb_vpu_0_sel = { + * bits 9:10 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ +- .parent_names = gxbb_vpu_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vpu_parent_names), ++ .parent_hws = gxbb_vpu_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vpu_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -1352,7 +1487,7 @@ static struct clk_regmap gxbb_vpu_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vpu_0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1366,7 +1501,7 @@ static struct clk_regmap gxbb_vpu_0 = { + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vpu_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1385,8 +1520,8 @@ static struct clk_regmap gxbb_vpu_1_sel = { + * bits 25:26 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ +- .parent_names = gxbb_vpu_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vpu_parent_names), ++ .parent_hws = gxbb_vpu_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vpu_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -1400,7 +1535,7 @@ static struct clk_regmap gxbb_vpu_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vpu_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1414,7 +1549,7 @@ static struct clk_regmap gxbb_vpu_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vpu_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1433,7 +1568,10 @@ static struct clk_regmap gxbb_vpu = { + * bit 31 selects from 2 possible parents: + * vpu_0 or vpu_1 + */ +- .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vpu_0.hw, ++ &gxbb_vpu_1.hw ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -1441,8 +1579,11 @@ static struct clk_regmap gxbb_vpu = { + + /* VAPB Clock */ + +-static const char * const gxbb_vapb_parent_names[] = { +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" ++static const struct clk_hw *gxbb_vapb_parent_hws[] = { ++ &gxbb_fclk_div4.hw, ++ &gxbb_fclk_div3.hw, ++ &gxbb_fclk_div5.hw, ++ &gxbb_fclk_div7.hw, + }; + + static struct clk_regmap gxbb_vapb_0_sel = { +@@ -1458,8 +1599,8 @@ static struct clk_regmap gxbb_vapb_0_sel = { + * bits 9:10 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ +- .parent_names = gxbb_vapb_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vapb_parent_names), ++ .parent_hws = gxbb_vapb_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vapb_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -1473,7 +1614,9 @@ static struct clk_regmap gxbb_vapb_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vapb_0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vapb_0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1487,7 +1630,9 @@ static struct clk_regmap gxbb_vapb_0 = { + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vapb_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vapb_0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1506,8 +1651,8 @@ static struct clk_regmap gxbb_vapb_1_sel = { + * bits 25:26 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ +- .parent_names = gxbb_vapb_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vapb_parent_names), ++ .parent_hws = gxbb_vapb_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vapb_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; +@@ -1521,7 +1666,9 @@ static struct clk_regmap gxbb_vapb_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vapb_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vapb_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1535,7 +1682,9 @@ static struct clk_regmap gxbb_vapb_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vapb_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vapb_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1554,7 +1703,10 @@ static struct clk_regmap gxbb_vapb_sel = { + * bit 31 selects from 2 possible parents: + * vapb_0 or vapb_1 + */ +- .parent_names = (const char *[]){ "vapb_0", "vapb_1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vapb_0.hw, ++ &gxbb_vapb_1.hw ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -1568,7 +1720,7 @@ static struct clk_regmap gxbb_vapb = { + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vapb_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vapb_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1592,13 +1744,33 @@ static struct clk_regmap gxbb_vid_pll_div = { + .hw.init = &(struct clk_init_data) { + .name = "vid_pll_div", + .ops = &meson_vid_pll_div_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll" }, ++ .parent_data = &(const struct clk_parent_data) { ++ /* ++ * Note: ++ * GXL and GXBB have different hdmi_plls (with ++ * different struct clk_hw). We fallback to the global ++ * naming string mechanism so vid_pll_div picks up the ++ * appropriate one. ++ */ ++ .name = "hdmi_pll", ++ .index = -1, ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, + }; + +-static const char * const gxbb_vid_pll_parent_names[] = { "vid_pll_div", "hdmi_pll" }; ++static const struct clk_parent_data gxbb_vid_pll_parent_data[] = { ++ { .hw = &gxbb_vid_pll_div.hw }, ++ /* ++ * Note: ++ * GXL and GXBB have different hdmi_plls (with ++ * different struct clk_hw). We fallback to the global ++ * naming string mechanism so vid_pll_div picks up the ++ * appropriate one. ++ */ ++ { .name = "hdmi_pll", .index = -1 }, ++}; + + static struct clk_regmap gxbb_vid_pll_sel = { + .data = &(struct clk_regmap_mux_data){ +@@ -1613,8 +1785,8 @@ static struct clk_regmap gxbb_vid_pll_sel = { + * bit 18 selects from 2 possible parents: + * vid_pll_div or hdmi_pll + */ +- .parent_names = gxbb_vid_pll_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_names), ++ .parent_data = gxbb_vid_pll_parent_data, ++ .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_data), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -1627,15 +1799,22 @@ static struct clk_regmap gxbb_vid_pll = { + .hw.init = &(struct clk_init_data) { + .name = "vid_pll", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vid_pll_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vid_pll_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }; + +-static const char * const gxbb_vclk_parent_names[] = { +- "vid_pll", "fclk_div4", "fclk_div3", "fclk_div5", "vid_pll", +- "fclk_div7", "mpll1", ++static const struct clk_hw *gxbb_vclk_parent_hws[] = { ++ &gxbb_vid_pll.hw, ++ &gxbb_fclk_div4.hw, ++ &gxbb_fclk_div3.hw, ++ &gxbb_fclk_div5.hw, ++ &gxbb_vid_pll.hw, ++ &gxbb_fclk_div7.hw, ++ &gxbb_mpll1.hw, + }; + + static struct clk_regmap gxbb_vclk_sel = { +@@ -1652,8 +1831,8 @@ static struct clk_regmap gxbb_vclk_sel = { + * vid_pll, fclk_div4, fclk_div3, fclk_div5, + * vid_pll, fclk_div7, mp1 + */ +- .parent_names = gxbb_vclk_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names), ++ .parent_hws = gxbb_vclk_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -1672,8 +1851,8 @@ static struct clk_regmap gxbb_vclk2_sel = { + * vid_pll, fclk_div4, fclk_div3, fclk_div5, + * vid_pll, fclk_div7, mp1 + */ +- .parent_names = gxbb_vclk_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names), ++ .parent_hws = gxbb_vclk_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -1686,7 +1865,7 @@ static struct clk_regmap gxbb_vclk_input = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1700,7 +1879,7 @@ static struct clk_regmap gxbb_vclk2_input = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1715,7 +1894,9 @@ static struct clk_regmap gxbb_vclk_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vclk_input" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk_input.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +@@ -1730,7 +1911,9 @@ static struct clk_regmap gxbb_vclk2_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vclk2_input" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk2_input.hw ++ }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +@@ -1744,7 +1927,7 @@ static struct clk_regmap gxbb_vclk = { + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1758,7 +1941,7 @@ static struct clk_regmap gxbb_vclk2 = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1772,7 +1955,7 @@ static struct clk_regmap gxbb_vclk_div1 = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1786,7 +1969,7 @@ static struct clk_regmap gxbb_vclk_div2_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1800,7 +1983,7 @@ static struct clk_regmap gxbb_vclk_div4_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1814,7 +1997,7 @@ static struct clk_regmap gxbb_vclk_div6_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1828,7 +2011,7 @@ static struct clk_regmap gxbb_vclk_div12_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1842,7 +2025,7 @@ static struct clk_regmap gxbb_vclk2_div1 = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1856,7 +2039,7 @@ static struct clk_regmap gxbb_vclk2_div2_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1870,7 +2053,7 @@ static struct clk_regmap gxbb_vclk2_div4_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1884,7 +2067,7 @@ static struct clk_regmap gxbb_vclk2_div6_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1898,7 +2081,7 @@ static struct clk_regmap gxbb_vclk2_div12_en = { + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vclk2" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -1910,7 +2093,9 @@ static struct clk_fixed_factor gxbb_vclk_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div2_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk_div2_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1921,7 +2106,9 @@ static struct clk_fixed_factor gxbb_vclk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div4_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk_div4_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1932,7 +2119,9 @@ static struct clk_fixed_factor gxbb_vclk_div6 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div6_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk_div6_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1943,7 +2132,9 @@ static struct clk_fixed_factor gxbb_vclk_div12 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_div12_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk_div12_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1954,7 +2145,9 @@ static struct clk_fixed_factor gxbb_vclk2_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div2_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk2_div2_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1965,7 +2158,9 @@ static struct clk_fixed_factor gxbb_vclk2_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div4_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk2_div4_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1976,7 +2171,9 @@ static struct clk_fixed_factor gxbb_vclk2_div6 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div6_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk2_div6_en.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1987,16 +2184,25 @@ static struct clk_fixed_factor gxbb_vclk2_div12 = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_div12_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vclk2_div12_en.hw ++ }, + .num_parents = 1, + }, + }; + + static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +-static const char * const gxbb_cts_parent_names[] = { +- "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", +- "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", +- "vclk2_div6", "vclk2_div12" ++static const struct clk_hw *gxbb_cts_parent_hws[] = { ++ &gxbb_vclk_div1.hw, ++ &gxbb_vclk_div2.hw, ++ &gxbb_vclk_div4.hw, ++ &gxbb_vclk_div6.hw, ++ &gxbb_vclk_div12.hw, ++ &gxbb_vclk2_div1.hw, ++ &gxbb_vclk2_div2.hw, ++ &gxbb_vclk2_div4.hw, ++ &gxbb_vclk2_div6.hw, ++ &gxbb_vclk2_div12.hw, + }; + + static struct clk_regmap gxbb_cts_enci_sel = { +@@ -2009,8 +2215,8 @@ static struct clk_regmap gxbb_cts_enci_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_cts_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_cts_parent_names), ++ .parent_hws = gxbb_cts_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2025,8 +2231,8 @@ static struct clk_regmap gxbb_cts_encp_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_cts_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_cts_parent_names), ++ .parent_hws = gxbb_cts_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2041,18 +2247,25 @@ static struct clk_regmap gxbb_cts_vdac_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_cts_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_cts_parent_names), ++ .parent_hws = gxbb_cts_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; + + /* TOFIX: add support for cts_tcon */ + static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +-static const char * const gxbb_cts_hdmi_tx_parent_names[] = { +- "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6", +- "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4", +- "vclk2_div6", "vclk2_div12" ++static const struct clk_hw *gxbb_cts_hdmi_tx_parent_hws[] = { ++ &gxbb_vclk_div1.hw, ++ &gxbb_vclk_div2.hw, ++ &gxbb_vclk_div4.hw, ++ &gxbb_vclk_div6.hw, ++ &gxbb_vclk_div12.hw, ++ &gxbb_vclk2_div1.hw, ++ &gxbb_vclk2_div2.hw, ++ &gxbb_vclk2_div4.hw, ++ &gxbb_vclk2_div6.hw, ++ &gxbb_vclk2_div12.hw, + }; + + static struct clk_regmap gxbb_hdmi_tx_sel = { +@@ -2071,8 +2284,8 @@ static struct clk_regmap gxbb_hdmi_tx_sel = { + * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12, + * cts_tcon + */ +- .parent_names = gxbb_cts_hdmi_tx_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_names), ++ .parent_hws = gxbb_cts_hdmi_tx_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2085,7 +2298,9 @@ static struct clk_regmap gxbb_cts_enci = { + .hw.init = &(struct clk_init_data) { + .name = "cts_enci", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_enci_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_enci_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2099,7 +2314,9 @@ static struct clk_regmap gxbb_cts_encp = { + .hw.init = &(struct clk_init_data) { + .name = "cts_encp", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_encp_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_encp_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2113,7 +2330,9 @@ static struct clk_regmap gxbb_cts_vdac = { + .hw.init = &(struct clk_init_data) { + .name = "cts_vdac", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_vdac_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_cts_vdac_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2127,7 +2346,9 @@ static struct clk_regmap gxbb_hdmi_tx = { + .hw.init = &(struct clk_init_data) { + .name = "hdmi_tx", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "hdmi_tx_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_hdmi_tx_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2135,8 +2356,11 @@ static struct clk_regmap gxbb_hdmi_tx = { + + /* HDMI Clocks */ + +-static const char * const gxbb_hdmi_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5" ++static const struct clk_parent_data gxbb_hdmi_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &gxbb_fclk_div4.hw }, ++ { .hw = &gxbb_fclk_div3.hw }, ++ { .hw = &gxbb_fclk_div5.hw }, + }; + + static struct clk_regmap gxbb_hdmi_sel = { +@@ -2149,8 +2373,8 @@ static struct clk_regmap gxbb_hdmi_sel = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_hdmi_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_hdmi_parent_names), ++ .parent_data = gxbb_hdmi_parent_data, ++ .num_parents = ARRAY_SIZE(gxbb_hdmi_parent_data), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, + }; +@@ -2164,7 +2388,7 @@ static struct clk_regmap gxbb_hdmi_div = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "hdmi_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_hdmi_sel.hw }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +@@ -2178,7 +2402,7 @@ static struct clk_regmap gxbb_hdmi = { + .hw.init = &(struct clk_init_data) { + .name = "hdmi", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "hdmi_div" }, ++ .parent_hws = (const struct clk_hw *[]) { &gxbb_hdmi_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +@@ -2186,8 +2410,11 @@ static struct clk_regmap gxbb_hdmi = { + + /* VDEC clocks */ + +-static const char * const gxbb_vdec_parent_names[] = { +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" ++static const struct clk_hw *gxbb_vdec_parent_hws[] = { ++ &gxbb_fclk_div4.hw, ++ &gxbb_fclk_div3.hw, ++ &gxbb_fclk_div5.hw, ++ &gxbb_fclk_div7.hw, + }; + + static struct clk_regmap gxbb_vdec_1_sel = { +@@ -2200,8 +2427,8 @@ static struct clk_regmap gxbb_vdec_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_vdec_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vdec_parent_names), ++ .parent_hws = gxbb_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2216,7 +2443,9 @@ static struct clk_regmap gxbb_vdec_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vdec_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2230,7 +2459,9 @@ static struct clk_regmap gxbb_vdec_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vdec_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2246,8 +2477,8 @@ static struct clk_regmap gxbb_vdec_hevc_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = gxbb_vdec_parent_names, +- .num_parents = ARRAY_SIZE(gxbb_vdec_parent_names), ++ .parent_hws = gxbb_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(gxbb_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2262,7 +2493,9 @@ static struct clk_regmap gxbb_vdec_hevc_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_hevc_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vdec_hevc_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2276,7 +2509,9 @@ static struct clk_regmap gxbb_vdec_hevc = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_hevc_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_vdec_hevc_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2284,9 +2519,18 @@ static struct clk_regmap gxbb_vdec_hevc = { + + static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, + 9, 10, 11, 13, 14, }; +-static const char * const gen_clk_parent_names[] = { +- IN_PREFIX "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", ++static const struct clk_parent_data gen_clk_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &gxbb_vdec_1.hw }, ++ { .hw = &gxbb_vdec_hevc.hw }, ++ { .hw = &gxbb_mpll0.hw }, ++ { .hw = &gxbb_mpll1.hw }, ++ { .hw = &gxbb_mpll2.hw }, ++ { .hw = &gxbb_fclk_div4.hw }, ++ { .hw = &gxbb_fclk_div3.hw }, ++ { .hw = &gxbb_fclk_div5.hw }, ++ { .hw = &gxbb_fclk_div7.hw }, ++ { .hw = &gxbb_gp0_pll.hw }, + }; + + static struct clk_regmap gxbb_gen_clk_sel = { +@@ -2305,8 +2549,8 @@ static struct clk_regmap gxbb_gen_clk_sel = { + * vid_pll, vid2_pll (hevc), mpll0, mpll1, mpll2, fdiv4, + * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll + */ +- .parent_names = gen_clk_parent_names, +- .num_parents = ARRAY_SIZE(gen_clk_parent_names), ++ .parent_data = gen_clk_parent_data, ++ .num_parents = ARRAY_SIZE(gen_clk_parent_data), + }, + }; + +@@ -2319,7 +2563,9 @@ static struct clk_regmap gxbb_gen_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "gen_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_gen_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2333,7 +2579,9 @@ static struct clk_regmap gxbb_gen_clk = { + .hw.init = &(struct clk_init_data){ + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "gen_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &gxbb_gen_clk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0010-FROMGIT-clk-meson-axg-migrate-to-the-new-parent-desc.patch b/packages/linux/patches/amlogic/amlogic-0010-FROMGIT-clk-meson-axg-migrate-to-the-new-parent-desc.patch new file mode 100644 index 0000000000..2a4f539fe5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0010-FROMGIT-clk-meson-axg-migrate-to-the-new-parent-desc.patch @@ -0,0 +1,579 @@ +From 742b86907dc0a2e79d98081fd535f331c2a3632a Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:42:34 +0200 +Subject: [PATCH 010/186] FROMGIT: clk: meson: axg: migrate to the new parent + description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (ie. when +all clocks are local to the controller) and use .parent_data otherwise. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit cc132d113dc589d8449fe2b53043b0f17029acac + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/axg.c | 204 ++++++++++++++++++++++++++++------------ + 1 file changed, 144 insertions(+), 60 deletions(-) + +diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c +index 3ddd0efc9ee0..7a3d795cc614 100644 +--- a/drivers/clk/meson/axg.c ++++ b/drivers/clk/meson/axg.c +@@ -14,7 +14,6 @@ + #include + #include + +-#include "clk-input.h" + #include "clk-regmap.h" + #include "clk-pll.h" + #include "clk-mpll.h" +@@ -59,7 +58,9 @@ static struct clk_regmap axg_fixed_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -74,7 +75,9 @@ static struct clk_regmap axg_fixed_pll = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "fixed_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fixed_pll_dco.hw ++ }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so +@@ -114,7 +117,9 @@ static struct clk_regmap axg_sys_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -129,7 +134,9 @@ static struct clk_regmap axg_sys_pll = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "sys_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_sys_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -215,7 +222,9 @@ static struct clk_regmap axg_gp0_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -230,7 +239,9 @@ static struct clk_regmap axg_gp0_pll = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "gp0_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_gp0_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -284,7 +295,9 @@ static struct clk_regmap axg_hifi_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -299,7 +312,9 @@ static struct clk_regmap axg_hifi_pll = { + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "hifi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_hifi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -311,7 +326,7 @@ static struct clk_fixed_factor axg_fclk_div2_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -324,7 +339,9 @@ static struct clk_regmap axg_fclk_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fclk_div2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +@@ -336,7 +353,7 @@ static struct clk_fixed_factor axg_fclk_div3_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -349,7 +366,9 @@ static struct clk_regmap axg_fclk_div3 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div3_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fclk_div3_div.hw ++ }, + .num_parents = 1, + /* + * FIXME: +@@ -372,7 +391,7 @@ static struct clk_fixed_factor axg_fclk_div4_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -385,7 +404,9 @@ static struct clk_regmap axg_fclk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div4_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fclk_div4_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -396,7 +417,7 @@ static struct clk_fixed_factor axg_fclk_div5_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, + }; +@@ -409,7 +430,9 @@ static struct clk_regmap axg_fclk_div5 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div5_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fclk_div5_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -420,7 +443,9 @@ static struct clk_fixed_factor axg_fclk_div7_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -433,7 +458,9 @@ static struct clk_regmap axg_fclk_div7 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div7_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fclk_div7_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -447,7 +474,9 @@ static struct clk_regmap axg_mpll_prediv = { + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -480,7 +509,9 @@ static struct clk_regmap axg_mpll0_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -493,7 +524,9 @@ static struct clk_regmap axg_mpll0 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -527,7 +560,9 @@ static struct clk_regmap axg_mpll1_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -540,7 +575,9 @@ static struct clk_regmap axg_mpll1 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -579,7 +616,9 @@ static struct clk_regmap axg_mpll2_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -592,7 +631,9 @@ static struct clk_regmap axg_mpll2 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -626,7 +667,9 @@ static struct clk_regmap axg_mpll3_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -639,7 +682,9 @@ static struct clk_regmap axg_mpll3 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll3_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpll3_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -702,7 +747,9 @@ static struct clk_regmap axg_pcie_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "xtal", ++ }, + .num_parents = 1, + }, + }; +@@ -717,7 +764,9 @@ static struct clk_regmap axg_pcie_pll_od = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "pcie_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_pcie_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -733,7 +782,9 @@ static struct clk_regmap axg_pcie_pll = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "pcie_pll_od" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_pcie_pll_od.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -750,7 +801,7 @@ static struct clk_regmap axg_pcie_mux = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_mux", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "pcie_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_pcie_pll.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -767,7 +818,7 @@ static struct clk_regmap axg_pcie_ref = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_ref", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "pcie_mux" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_pcie_mux.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -781,7 +832,7 @@ static struct clk_regmap axg_pcie_cml_en0 = { + .hw.init = &(struct clk_init_data) { + .name = "pcie_cml_en0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "pcie_ref" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_pcie_ref.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + +@@ -796,16 +847,21 @@ static struct clk_regmap axg_pcie_cml_en1 = { + .hw.init = &(struct clk_init_data) { + .name = "pcie_cml_en1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "pcie_ref" }, ++ .parent_hws = (const struct clk_hw *[]) { &axg_pcie_ref.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + + static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; +-static const char * const clk81_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", +- "fclk_div3", "fclk_div5" ++static const struct clk_parent_data clk81_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &axg_fclk_div7.hw }, ++ { .hw = &axg_mpll1.hw }, ++ { .hw = &axg_mpll2.hw }, ++ { .hw = &axg_fclk_div4.hw }, ++ { .hw = &axg_fclk_div3.hw }, ++ { .hw = &axg_fclk_div5.hw }, + }; + + static struct clk_regmap axg_mpeg_clk_sel = { +@@ -818,8 +874,8 @@ static struct clk_regmap axg_mpeg_clk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = clk81_parent_names, +- .num_parents = ARRAY_SIZE(clk81_parent_names), ++ .parent_data = clk81_parent_data, ++ .num_parents = ARRAY_SIZE(clk81_parent_data), + }, + }; + +@@ -832,7 +888,9 @@ static struct clk_regmap axg_mpeg_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mpeg_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpeg_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -846,15 +904,20 @@ static struct clk_regmap axg_clk81 = { + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpeg_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_mpeg_clk_div.hw ++ }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + }, + }; + +-static const char * const axg_sd_emmc_clk0_parent_names[] = { +- IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", +- ++static const struct clk_parent_data axg_sd_emmc_clk0_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &axg_fclk_div2.hw }, ++ { .hw = &axg_fclk_div3.hw }, ++ { .hw = &axg_fclk_div5.hw }, ++ { .hw = &axg_fclk_div7.hw }, + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All +@@ -873,8 +936,8 @@ static struct clk_regmap axg_sd_emmc_b_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = axg_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), ++ .parent_data = axg_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -889,7 +952,9 @@ static struct clk_regmap axg_sd_emmc_b_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_sd_emmc_b_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -903,7 +968,9 @@ static struct clk_regmap axg_sd_emmc_b_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_sd_emmc_b_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -919,8 +986,8 @@ static struct clk_regmap axg_sd_emmc_c_clk0_sel = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = axg_sd_emmc_clk0_parent_names, +- .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), ++ .parent_data = axg_sd_emmc_clk0_parent_data, ++ .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -935,7 +1002,9 @@ static struct clk_regmap axg_sd_emmc_c_clk0_div = { + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_sd_emmc_c_clk0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -949,7 +1018,9 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_sd_emmc_c_clk0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -957,9 +1028,18 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { + + static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, + 9, 10, 11, 13, 14, }; +-static const char * const gen_clk_parent_names[] = { +- IN_PREFIX "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", ++static const struct clk_parent_data gen_clk_parent_data[] = { ++ { .fw_name = "xtal", }, ++ { .hw = &axg_hifi_pll.hw }, ++ { .hw = &axg_mpll0.hw }, ++ { .hw = &axg_mpll1.hw }, ++ { .hw = &axg_mpll2.hw }, ++ { .hw = &axg_mpll3.hw }, ++ { .hw = &axg_fclk_div4.hw }, ++ { .hw = &axg_fclk_div3.hw }, ++ { .hw = &axg_fclk_div5.hw }, ++ { .hw = &axg_fclk_div7.hw }, ++ { .hw = &axg_gp0_pll.hw }, + }; + + static struct clk_regmap axg_gen_clk_sel = { +@@ -978,8 +1058,8 @@ static struct clk_regmap axg_gen_clk_sel = { + * hifi_pll, mpll0, mpll1, mpll2, mpll3, fdiv4, + * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll + */ +- .parent_names = gen_clk_parent_names, +- .num_parents = ARRAY_SIZE(gen_clk_parent_names), ++ .parent_data = gen_clk_parent_data, ++ .num_parents = ARRAY_SIZE(gen_clk_parent_data), + }, + }; + +@@ -992,7 +1072,9 @@ static struct clk_regmap axg_gen_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "gen_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_gen_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1006,7 +1088,9 @@ static struct clk_regmap axg_gen_clk = { + .hw.init = &(struct clk_init_data){ + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "gen_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &axg_gen_clk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0011-FROMGIT-clk-meson-meson8b-migrate-to-the-new-parent-.patch b/packages/linux/patches/amlogic/amlogic-0011-FROMGIT-clk-meson-meson8b-migrate-to-the-new-parent-.patch new file mode 100644 index 0000000000..18970e83e1 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0011-FROMGIT-clk-meson-meson8b-migrate-to-the-new-parent-.patch @@ -0,0 +1,1729 @@ +From 21854175b3a8641c22881be5f3e383625f7aff90 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:42:35 +0200 +Subject: [PATCH 011/186] FROMGIT: clk: meson: meson8b: migrate to the new + parent description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (ie. when +all clocks are local to the controller) and use .parent_data otherwise. + +Signed-off-by: Alexandre Mergnat +Reviewed-by: Martin Blumenstingl +Tested-by: Martin Blumenstingl +Signed-off-by: Jerome Brunet +(cherry picked from commit 4b5b85c0e6505c50d4a986f75effe5b88d923737 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/meson8b.c | 707 +++++++++++++++++++++++++----------- + 1 file changed, 496 insertions(+), 211 deletions(-) + +diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c +index 537219fa573e..b30279a5bfcc 100644 +--- a/drivers/clk/meson/meson8b.c ++++ b/drivers/clk/meson/meson8b.c +@@ -97,7 +97,9 @@ static struct clk_regmap meson8b_fixed_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ "xtal" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_xtal.hw ++ }, + .num_parents = 1, + }, + }; +@@ -112,7 +114,9 @@ static struct clk_regmap meson8b_fixed_pll = { + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "fixed_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fixed_pll_dco.hw ++ }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so +@@ -158,7 +162,9 @@ static struct clk_regmap meson8b_hdmi_pll_dco = { + /* sometimes also called "HPLL" or "HPLL PLL" */ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, +- .parent_names = (const char *[]){ "xtal" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_xtal.hw ++ }, + .num_parents = 1, + }, + }; +@@ -173,7 +179,9 @@ static struct clk_regmap meson8b_hdmi_pll_lvds_out = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_lvds_out", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_hdmi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -189,7 +197,9 @@ static struct clk_regmap meson8b_hdmi_pll_hdmi_out = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_hdmi_out", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_hdmi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -227,7 +237,9 @@ static struct clk_regmap meson8b_sys_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ "xtal" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_xtal.hw ++ }, + .num_parents = 1, + }, + }; +@@ -242,7 +254,9 @@ static struct clk_regmap meson8b_sys_pll = { + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "sys_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_sys_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -254,7 +268,9 @@ static struct clk_fixed_factor meson8b_fclk_div2_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -267,7 +283,9 @@ static struct clk_regmap meson8b_fclk_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fclk_div2_div.hw ++ }, + .num_parents = 1, + /* + * FIXME: Ethernet with a RGMII PHYs is not working if +@@ -285,7 +303,9 @@ static struct clk_fixed_factor meson8b_fclk_div3_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -298,7 +318,9 @@ static struct clk_regmap meson8b_fclk_div3 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div3_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fclk_div3_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -309,7 +331,9 @@ static struct clk_fixed_factor meson8b_fclk_div4_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -322,7 +346,9 @@ static struct clk_regmap meson8b_fclk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div4_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fclk_div4_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -333,7 +359,9 @@ static struct clk_fixed_factor meson8b_fclk_div5_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -346,7 +374,9 @@ static struct clk_regmap meson8b_fclk_div5 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div5_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fclk_div5_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -357,7 +387,9 @@ static struct clk_fixed_factor meson8b_fclk_div7_div = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -370,7 +402,9 @@ static struct clk_regmap meson8b_fclk_div7 = { + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "fclk_div7_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fclk_div7_div.hw ++ }, + .num_parents = 1, + }, + }; +@@ -384,7 +418,9 @@ static struct clk_regmap meson8b_mpll_prediv = { + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "fixed_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fixed_pll.hw ++ }, + .num_parents = 1, + }, + }; +@@ -416,7 +452,9 @@ static struct clk_regmap meson8b_mpll0_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -429,7 +467,9 @@ static struct clk_regmap meson8b_mpll0 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpll0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -457,7 +497,9 @@ static struct clk_regmap meson8b_mpll1_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -470,7 +512,9 @@ static struct clk_regmap meson8b_mpll1 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpll1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -498,7 +542,9 @@ static struct clk_regmap meson8b_mpll2_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, +- .parent_names = (const char *[]){ "mpll_prediv" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpll_prediv.hw ++ }, + .num_parents = 1, + }, + }; +@@ -511,7 +557,9 @@ static struct clk_regmap meson8b_mpll2 = { + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpll2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpll2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -533,8 +581,11 @@ static struct clk_regmap meson8b_mpeg_clk_sel = { + * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, + * fclk_div4, fclk_div3, fclk_div5 + */ +- .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", +- "fclk_div5" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fclk_div3.hw, ++ &meson8b_fclk_div4.hw, ++ &meson8b_fclk_div5.hw, ++ }, + .num_parents = 3, + }, + }; +@@ -548,7 +599,9 @@ static struct clk_regmap meson8b_mpeg_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "mpeg_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpeg_clk_sel.hw ++ }, + .num_parents = 1, + }, + }; +@@ -561,7 +614,9 @@ static struct clk_regmap meson8b_clk81 = { + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mpeg_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mpeg_clk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +@@ -576,7 +631,10 @@ static struct clk_regmap meson8b_cpu_in_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "xtal", "sys_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_xtal.hw, ++ &meson8b_sys_pll.hw, ++ }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), +@@ -589,7 +647,9 @@ static struct clk_fixed_factor meson8b_cpu_in_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_in_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_in_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -601,7 +661,9 @@ static struct clk_fixed_factor meson8b_cpu_in_div3 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_div3", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_in_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_in_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -630,7 +692,9 @@ static struct clk_regmap meson8b_cpu_scale_div = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_scale_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "cpu_in_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_in_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -649,13 +713,15 @@ static struct clk_regmap meson8b_cpu_scale_out_sel = { + .ops = &clk_regmap_mux_ops, + /* + * NOTE: We are skipping the parent with value 0x2 (which is +- * "cpu_in_div3") because it results in a duty cycle of 33% +- * which makes the system unstable and can result in a lockup +- * of the whole system. ++ * meson8b_cpu_in_div3) because it results in a duty cycle of ++ * 33% which makes the system unstable and can result in a ++ * lockup of the whole system. + */ +- .parent_names = (const char *[]) { "cpu_in_sel", +- "cpu_in_div2", +- "cpu_scale_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_in_sel.hw, ++ &meson8b_cpu_in_div2.hw, ++ &meson8b_cpu_scale_div.hw, ++ }, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -670,8 +736,10 @@ static struct clk_regmap meson8b_cpu_clk = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "xtal", +- "cpu_scale_out_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_xtal.hw, ++ &meson8b_cpu_scale_out_sel.hw, ++ }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT | +@@ -690,8 +758,13 @@ static struct clk_regmap meson8b_nand_clk_sel = { + .name = "nand_clk_sel", + .ops = &clk_regmap_mux_ops, + /* FIXME all other parents are unknown: */ +- .parent_names = (const char *[]){ "fclk_div4", "fclk_div3", +- "fclk_div5", "fclk_div7", "xtal" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_fclk_div4.hw, ++ &meson8b_fclk_div3.hw, ++ &meson8b_fclk_div5.hw, ++ &meson8b_fclk_div7.hw, ++ &meson8b_xtal.hw, ++ }, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -707,7 +780,9 @@ static struct clk_regmap meson8b_nand_clk_div = { + .hw.init = &(struct clk_init_data){ + .name = "nand_clk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "nand_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_nand_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -721,7 +796,9 @@ static struct clk_regmap meson8b_nand_clk_gate = { + .hw.init = &(struct clk_init_data){ + .name = "nand_clk_gate", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "nand_clk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_nand_clk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -733,7 +810,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div2 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -744,7 +823,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div3 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div3", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -755,7 +836,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div4 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -766,7 +849,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div5 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div5", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -777,7 +862,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div6 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -788,7 +875,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div7 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div7", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -799,7 +888,9 @@ static struct clk_fixed_factor meson8b_cpu_clk_div8 = { + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div8", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "cpu_clk" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk.hw ++ }, + .num_parents = 1, + }, + }; +@@ -815,13 +906,15 @@ static struct clk_regmap meson8b_apb_clk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "apb_clk_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "cpu_clk_div2", +- "cpu_clk_div3", +- "cpu_clk_div4", +- "cpu_clk_div5", +- "cpu_clk_div6", +- "cpu_clk_div7", +- "cpu_clk_div8", }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk_div2.hw, ++ &meson8b_cpu_clk_div3.hw, ++ &meson8b_cpu_clk_div4.hw, ++ &meson8b_cpu_clk_div5.hw, ++ &meson8b_cpu_clk_div6.hw, ++ &meson8b_cpu_clk_div7.hw, ++ &meson8b_cpu_clk_div8.hw, ++ }, + .num_parents = 7, + }, + }; +@@ -835,7 +928,9 @@ static struct clk_regmap meson8b_apb_clk_gate = { + .hw.init = &(struct clk_init_data){ + .name = "apb_clk_dis", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "apb_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_apb_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -850,13 +945,15 @@ static struct clk_regmap meson8b_periph_clk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "periph_clk_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "cpu_clk_div2", +- "cpu_clk_div3", +- "cpu_clk_div4", +- "cpu_clk_div5", +- "cpu_clk_div6", +- "cpu_clk_div7", +- "cpu_clk_div8", }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk_div2.hw, ++ &meson8b_cpu_clk_div3.hw, ++ &meson8b_cpu_clk_div4.hw, ++ &meson8b_cpu_clk_div5.hw, ++ &meson8b_cpu_clk_div6.hw, ++ &meson8b_cpu_clk_div7.hw, ++ &meson8b_cpu_clk_div8.hw, ++ }, + .num_parents = 7, + }, + }; +@@ -870,7 +967,9 @@ static struct clk_regmap meson8b_periph_clk_gate = { + .hw.init = &(struct clk_init_data){ + .name = "periph_clk_dis", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "periph_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_periph_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -887,13 +986,15 @@ static struct clk_regmap meson8b_axi_clk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "axi_clk_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "cpu_clk_div2", +- "cpu_clk_div3", +- "cpu_clk_div4", +- "cpu_clk_div5", +- "cpu_clk_div6", +- "cpu_clk_div7", +- "cpu_clk_div8", }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk_div2.hw, ++ &meson8b_cpu_clk_div3.hw, ++ &meson8b_cpu_clk_div4.hw, ++ &meson8b_cpu_clk_div5.hw, ++ &meson8b_cpu_clk_div6.hw, ++ &meson8b_cpu_clk_div7.hw, ++ &meson8b_cpu_clk_div8.hw, ++ }, + .num_parents = 7, + }, + }; +@@ -907,7 +1008,9 @@ static struct clk_regmap meson8b_axi_clk_gate = { + .hw.init = &(struct clk_init_data){ + .name = "axi_clk_dis", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "axi_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_axi_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -922,13 +1025,15 @@ static struct clk_regmap meson8b_l2_dram_clk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "l2_dram_clk_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "cpu_clk_div2", +- "cpu_clk_div3", +- "cpu_clk_div4", +- "cpu_clk_div5", +- "cpu_clk_div6", +- "cpu_clk_div7", +- "cpu_clk_div8", }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cpu_clk_div2.hw, ++ &meson8b_cpu_clk_div3.hw, ++ &meson8b_cpu_clk_div4.hw, ++ &meson8b_cpu_clk_div5.hw, ++ &meson8b_cpu_clk_div6.hw, ++ &meson8b_cpu_clk_div7.hw, ++ &meson8b_cpu_clk_div8.hw, ++ }, + .num_parents = 7, + }, + }; +@@ -942,7 +1047,9 @@ static struct clk_regmap meson8b_l2_dram_clk_gate = { + .hw.init = &(struct clk_init_data){ + .name = "l2_dram_clk_dis", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "l2_dram_clk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_l2_dram_clk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -963,7 +1070,9 @@ static struct clk_regmap meson8b_vid_pll_in_sel = { + * Meson8b: hdmi_pll_dco + * Meson8m2: vid2_pll + */ +- .parent_names = (const char *[]){ "hdmi_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_hdmi_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -977,7 +1086,9 @@ static struct clk_regmap meson8b_vid_pll_in_en = { + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_in_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vid_pll_in_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vid_pll_in_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -992,7 +1103,9 @@ static struct clk_regmap meson8b_vid_pll_pre_div = { + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_pre_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "vid_pll_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vid_pll_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1007,7 +1120,9 @@ static struct clk_regmap meson8b_vid_pll_post_div = { + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_post_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "vid_pll_pre_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vid_pll_pre_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1023,8 +1138,10 @@ static struct clk_regmap meson8b_vid_pll = { + .name = "vid_pll", + .ops = &clk_regmap_mux_ro_ops, + /* TODO: parent 0x2 is vid_pll_pre_div_mult7_div2 */ +- .parent_names = (const char *[]){ "vid_pll_pre_div", +- "vid_pll_post_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vid_pll_pre_div.hw, ++ &meson8b_vid_pll_post_div.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1039,15 +1156,22 @@ static struct clk_regmap meson8b_vid_pll_final_div = { + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_final_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "vid_pll" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vid_pll.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + +-static const char * const meson8b_vclk_mux_parents[] = { +- "vid_pll_final_div", "fclk_div4", "fclk_div3", "fclk_div5", +- "vid_pll_final_div", "fclk_div7", "mpll1" ++static const struct clk_hw *meson8b_vclk_mux_parent_hws[] = { ++ &meson8b_vid_pll_final_div.hw, ++ &meson8b_fclk_div4.hw, ++ &meson8b_fclk_div3.hw, ++ &meson8b_fclk_div5.hw, ++ &meson8b_vid_pll_final_div.hw, ++ &meson8b_fclk_div7.hw, ++ &meson8b_mpll1.hw, + }; + + static struct clk_regmap meson8b_vclk_in_sel = { +@@ -1059,8 +1183,8 @@ static struct clk_regmap meson8b_vclk_in_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_in_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), ++ .parent_hws = meson8b_vclk_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1073,7 +1197,9 @@ static struct clk_regmap meson8b_vclk_in_en = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_in_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk_in_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_in_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1087,7 +1213,9 @@ static struct clk_regmap meson8b_vclk_div1_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div1_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1099,7 +1227,9 @@ static struct clk_fixed_factor meson8b_vclk_div2_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1113,7 +1243,9 @@ static struct clk_regmap meson8b_vclk_div2_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk_div2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_div2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1125,7 +1257,9 @@ static struct clk_fixed_factor meson8b_vclk_div4_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1139,7 +1273,9 @@ static struct clk_regmap meson8b_vclk_div4_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk_div4" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_div4_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1151,7 +1287,9 @@ static struct clk_fixed_factor meson8b_vclk_div6_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1165,7 +1303,9 @@ static struct clk_regmap meson8b_vclk_div6_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk_div6" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_div6_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1177,7 +1317,9 @@ static struct clk_fixed_factor meson8b_vclk_div12_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1191,7 +1333,9 @@ static struct clk_regmap meson8b_vclk_div12_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk_div12" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk_div12_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1206,8 +1350,8 @@ static struct clk_regmap meson8b_vclk2_in_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_in_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), ++ .parent_hws = meson8b_vclk_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1220,7 +1364,9 @@ static struct clk_regmap meson8b_vclk2_clk_in_en = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_in_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk2_in_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_in_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1234,7 +1380,9 @@ static struct clk_regmap meson8b_vclk2_div1_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div1_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk2_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_clk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1246,7 +1394,9 @@ static struct clk_fixed_factor meson8b_vclk2_div2_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_clk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1260,7 +1410,9 @@ static struct clk_regmap meson8b_vclk2_div2_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk2_div2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_div2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1272,7 +1424,9 @@ static struct clk_fixed_factor meson8b_vclk2_div4_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_clk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1286,7 +1440,9 @@ static struct clk_regmap meson8b_vclk2_div4_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk2_div4" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_div4_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1298,7 +1454,9 @@ static struct clk_fixed_factor meson8b_vclk2_div6_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_clk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1312,7 +1470,9 @@ static struct clk_regmap meson8b_vclk2_div6_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk2_div6" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_div6_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1324,7 +1484,9 @@ static struct clk_fixed_factor meson8b_vclk2_div12_div = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, +- .parent_names = (const char *[]){ "vclk2_in_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_clk_in_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +@@ -1338,15 +1500,20 @@ static struct clk_regmap meson8b_vclk2_div12_div_gate = { + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "vclk2_div12" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vclk2_div12_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + +-static const char * const meson8b_vclk_enc_mux_parents[] = { +- "vclk_div1_en", "vclk_div2_en", "vclk_div4_en", "vclk_div6_en", +- "vclk_div12_en", ++static const struct clk_hw *meson8b_vclk_enc_mux_parent_hws[] = { ++ &meson8b_vclk_div1_gate.hw, ++ &meson8b_vclk_div2_div_gate.hw, ++ &meson8b_vclk_div4_div_gate.hw, ++ &meson8b_vclk_div6_div_gate.hw, ++ &meson8b_vclk_div12_div_gate.hw, + }; + + static struct clk_regmap meson8b_cts_enct_sel = { +@@ -1358,8 +1525,8 @@ static struct clk_regmap meson8b_cts_enct_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_enct_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk_enc_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), ++ .parent_hws = meson8b_vclk_enc_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1372,7 +1539,9 @@ static struct clk_regmap meson8b_cts_enct = { + .hw.init = &(struct clk_init_data){ + .name = "cts_enct", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cts_enct_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_enct_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1387,8 +1556,8 @@ static struct clk_regmap meson8b_cts_encp_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk_enc_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), ++ .parent_hws = meson8b_vclk_enc_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1401,7 +1570,9 @@ static struct clk_regmap meson8b_cts_encp = { + .hw.init = &(struct clk_init_data){ + .name = "cts_encp", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cts_encp_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_encp_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1416,8 +1587,8 @@ static struct clk_regmap meson8b_cts_enci_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk_enc_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), ++ .parent_hws = meson8b_vclk_enc_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1430,7 +1601,9 @@ static struct clk_regmap meson8b_cts_enci = { + .hw.init = &(struct clk_init_data){ + .name = "cts_enci", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cts_enci_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_enci_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1445,8 +1618,8 @@ static struct clk_regmap meson8b_hdmi_tx_pixel_sel = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk_enc_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), ++ .parent_hws = meson8b_vclk_enc_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1459,15 +1632,20 @@ static struct clk_regmap meson8b_hdmi_tx_pixel = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "hdmi_tx_pixel_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_hdmi_tx_pixel_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + +-static const char * const meson8b_vclk2_enc_mux_parents[] = { +- "vclk2_div1_en", "vclk2_div2_en", "vclk2_div4_en", "vclk2_div6_en", +- "vclk2_div12_en", ++static const struct clk_hw *meson8b_vclk2_enc_mux_parent_hws[] = { ++ &meson8b_vclk2_div1_gate.hw, ++ &meson8b_vclk2_div2_div_gate.hw, ++ &meson8b_vclk2_div4_div_gate.hw, ++ &meson8b_vclk2_div6_div_gate.hw, ++ &meson8b_vclk2_div12_div_gate.hw, + }; + + static struct clk_regmap meson8b_cts_encl_sel = { +@@ -1479,8 +1657,8 @@ static struct clk_regmap meson8b_cts_encl_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk2_enc_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), ++ .parent_hws = meson8b_vclk2_enc_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1493,7 +1671,9 @@ static struct clk_regmap meson8b_cts_encl = { + .hw.init = &(struct clk_init_data){ + .name = "cts_encl", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cts_encl_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_encl_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1508,8 +1688,8 @@ static struct clk_regmap meson8b_cts_vdac0_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac0_sel", + .ops = &clk_regmap_mux_ro_ops, +- .parent_names = meson8b_vclk2_enc_mux_parents, +- .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), ++ .parent_hws = meson8b_vclk2_enc_mux_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1522,7 +1702,9 @@ static struct clk_regmap meson8b_cts_vdac0 = { + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac0", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "cts_vdac0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_vdac0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1539,7 +1721,9 @@ static struct clk_regmap meson8b_hdmi_sys_sel = { + .name = "hdmi_sys_sel", + .ops = &clk_regmap_mux_ro_ops, + /* FIXME: all other parents are unknown */ +- .parent_names = (const char *[]){ "xtal" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_xtal.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +@@ -1554,7 +1738,9 @@ static struct clk_regmap meson8b_hdmi_sys_div = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sys_div", + .ops = &clk_regmap_divider_ro_ops, +- .parent_names = (const char *[]){ "hdmi_sys_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_hdmi_sys_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1568,7 +1754,9 @@ static struct clk_regmap meson8b_hdmi_sys = { + .hw.init = &(struct clk_init_data) { + .name = "hdmi_sys", + .ops = &clk_regmap_gate_ro_ops, +- .parent_names = (const char *[]){ "hdmi_sys_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_hdmi_sys_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1579,9 +1767,14 @@ static struct clk_regmap meson8b_hdmi_sys = { + * muxed by a glitch-free switch on Meson8b and Meson8m2. Meson8 only + * has mali_0 and no glitch-free mux. + */ +-static const char * const meson8b_mali_0_1_parent_names[] = { +- "xtal", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", +- "fclk_div5" ++static const struct clk_hw *meson8b_mali_0_1_parent_hws[] = { ++ &meson8b_xtal.hw, ++ &meson8b_mpll2.hw, ++ &meson8b_mpll1.hw, ++ &meson8b_fclk_div7.hw, ++ &meson8b_fclk_div4.hw, ++ &meson8b_fclk_div3.hw, ++ &meson8b_fclk_div5.hw, + }; + + static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +@@ -1596,8 +1789,8 @@ static struct clk_regmap meson8b_mali_0_sel = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_mali_0_1_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), ++ .parent_hws = meson8b_mali_0_1_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_hws), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and +@@ -1617,7 +1810,9 @@ static struct clk_regmap meson8b_mali_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mali_0_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mali_0_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1631,7 +1826,9 @@ static struct clk_regmap meson8b_mali_0 = { + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mali_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mali_0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1647,8 +1844,8 @@ static struct clk_regmap meson8b_mali_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_mali_0_1_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), ++ .parent_hws = meson8b_mali_0_1_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_hws), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and +@@ -1668,7 +1865,9 @@ static struct clk_regmap meson8b_mali_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "mali_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mali_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1682,7 +1881,9 @@ static struct clk_regmap meson8b_mali_1 = { + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "mali_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mali_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1697,7 +1898,10 @@ static struct clk_regmap meson8b_mali = { + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "mali_0", "mali_1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_mali_0.hw, ++ &meson8b_mali_1.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1740,7 +1944,9 @@ static struct clk_regmap meson8m2_gp_pll_dco = { + .hw.init = &(struct clk_init_data){ + .name = "gp_pll_dco", + .ops = &meson_clk_pll_ops, +- .parent_names = (const char *[]){ "xtal" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_xtal.hw ++ }, + .num_parents = 1, + }, + }; +@@ -1755,18 +1961,26 @@ static struct clk_regmap meson8m2_gp_pll = { + .hw.init = &(struct clk_init_data){ + .name = "gp_pll", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "gp_pll_dco" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8m2_gp_pll_dco.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + +-static const char * const meson8b_vpu_0_1_parent_names[] = { +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" ++static const struct clk_hw *meson8b_vpu_0_1_parent_hws[] = { ++ &meson8b_fclk_div4.hw, ++ &meson8b_fclk_div3.hw, ++ &meson8b_fclk_div5.hw, ++ &meson8b_fclk_div7.hw, + }; + +-static const char * const mmeson8m2_vpu_0_1_parent_names[] = { +- "fclk_div4", "fclk_div3", "fclk_div5", "gp_pll" ++static const struct clk_hw *mmeson8m2_vpu_0_1_parent_hws[] = { ++ &meson8b_fclk_div4.hw, ++ &meson8b_fclk_div3.hw, ++ &meson8b_fclk_div5.hw, ++ &meson8m2_gp_pll.hw, + }; + + static struct clk_regmap meson8b_vpu_0_sel = { +@@ -1778,8 +1992,8 @@ static struct clk_regmap meson8b_vpu_0_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_vpu_0_1_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names), ++ .parent_hws = meson8b_vpu_0_1_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1793,8 +2007,8 @@ static struct clk_regmap meson8m2_vpu_0_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = mmeson8m2_vpu_0_1_parent_names, +- .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_names), ++ .parent_hws = mmeson8m2_vpu_0_1_parent_hws, ++ .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1808,7 +2022,17 @@ static struct clk_regmap meson8b_vpu_0_div = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vpu_0_sel" }, ++ .parent_data = &(const struct clk_parent_data) { ++ /* ++ * Note: ++ * meson8b and meson8m2 have different vpu_0_sels (with ++ * different struct clk_hw). We fallback to the global ++ * naming string mechanism so vpu_0_div picks up the ++ * appropriate one. ++ */ ++ .name = "vpu_0_sel", ++ .index = -1, ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1822,7 +2046,9 @@ static struct clk_regmap meson8b_vpu_0 = { + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vpu_0_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vpu_0_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1837,8 +2063,8 @@ static struct clk_regmap meson8b_vpu_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_vpu_0_1_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_names), ++ .parent_hws = meson8b_vpu_0_1_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1852,8 +2078,8 @@ static struct clk_regmap meson8m2_vpu_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = mmeson8m2_vpu_0_1_parent_names, +- .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_names), ++ .parent_hws = mmeson8m2_vpu_0_1_parent_hws, ++ .num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1867,7 +2093,17 @@ static struct clk_regmap meson8b_vpu_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vpu_1_sel" }, ++ .parent_data = &(const struct clk_parent_data) { ++ /* ++ * Note: ++ * meson8b and meson8m2 have different vpu_1_sels (with ++ * different struct clk_hw). We fallback to the global ++ * naming string mechanism so vpu_1_div picks up the ++ * appropriate one. ++ */ ++ .name = "vpu_1_sel", ++ .index = -1, ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1881,7 +2117,9 @@ static struct clk_regmap meson8b_vpu_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vpu_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vpu_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1896,14 +2134,22 @@ static struct clk_regmap meson8b_vpu = { + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vpu_0.hw, ++ &meson8b_vpu_1.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; + +-static const char * const meson8b_vdec_parent_names[] = { +- "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "mpll2", "mpll1" ++static const struct clk_hw *meson8b_vdec_parent_hws[] = { ++ &meson8b_fclk_div4.hw, ++ &meson8b_fclk_div3.hw, ++ &meson8b_fclk_div5.hw, ++ &meson8b_fclk_div7.hw, ++ &meson8b_mpll2.hw, ++ &meson8b_mpll1.hw, + }; + + static struct clk_regmap meson8b_vdec_1_sel = { +@@ -1916,8 +2162,8 @@ static struct clk_regmap meson8b_vdec_1_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_vdec_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), ++ .parent_hws = meson8b_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -1932,7 +2178,9 @@ static struct clk_regmap meson8b_vdec_1_1_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_1_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1946,7 +2194,9 @@ static struct clk_regmap meson8b_vdec_1_1 = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_1_1", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_1_1_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_1_1_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1962,7 +2212,9 @@ static struct clk_regmap meson8b_vdec_1_2_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_2_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_1_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_1_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1976,7 +2228,9 @@ static struct clk_regmap meson8b_vdec_1_2 = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_1_2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_1_2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_1_2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -1992,7 +2246,10 @@ static struct clk_regmap meson8b_vdec_1 = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_1", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "vdec_1_1", "vdec_1_2" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_1_1.hw, ++ &meson8b_vdec_1_2.hw, ++ }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2008,8 +2265,8 @@ static struct clk_regmap meson8b_vdec_hcodec_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hcodec_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_vdec_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), ++ .parent_hws = meson8b_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2024,7 +2281,9 @@ static struct clk_regmap meson8b_vdec_hcodec_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hcodec_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_hcodec_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_hcodec_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2038,7 +2297,9 @@ static struct clk_regmap meson8b_vdec_hcodec = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_hcodec", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_hcodec_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_hcodec_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2054,8 +2315,8 @@ static struct clk_regmap meson8b_vdec_2_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_2_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_vdec_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), ++ .parent_hws = meson8b_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2070,7 +2331,9 @@ static struct clk_regmap meson8b_vdec_2_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_2_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_2_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_2_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2084,7 +2347,9 @@ static struct clk_regmap meson8b_vdec_2 = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_2", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_2_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_2_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2100,8 +2365,8 @@ static struct clk_regmap meson8b_vdec_hevc_sel = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_vdec_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_vdec_parent_names), ++ .parent_hws = meson8b_vdec_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, + }; +@@ -2116,7 +2381,9 @@ static struct clk_regmap meson8b_vdec_hevc_div = { + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "vdec_hevc_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_hevc_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2130,7 +2397,9 @@ static struct clk_regmap meson8b_vdec_hevc_en = { + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc_en", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "vdec_hevc_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_hevc_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2147,15 +2416,19 @@ static struct clk_regmap meson8b_vdec_hevc = { + .name = "vdec_hevc", + .ops = &clk_regmap_mux_ops, + /* TODO: The second parent is currently unknown */ +- .parent_names = (const char *[]){ "vdec_hevc_en" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_vdec_hevc_en.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + + /* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */ +-static const char * const meson8b_cts_amclk_parent_names[] = { +- "mpll0", "mpll1", "mpll2" ++static const struct clk_hw *meson8b_cts_amclk_parent_hws[] = { ++ &meson8b_mpll0.hw, ++ &meson8b_mpll1.hw, ++ &meson8b_mpll2.hw + }; + + static u32 meson8b_cts_amclk_mux_table[] = { 1, 2, 3 }; +@@ -2171,8 +2444,8 @@ static struct clk_regmap meson8b_cts_amclk_sel = { + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_cts_amclk_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_names), ++ .parent_hws = meson8b_cts_amclk_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_hws), + }, + }; + +@@ -2186,7 +2459,9 @@ static struct clk_regmap meson8b_cts_amclk_div = { + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "cts_amclk_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_amclk_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2200,15 +2475,19 @@ static struct clk_regmap meson8b_cts_amclk = { + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_amclk_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_amclk_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, + }; + + /* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */ +-static const char * const meson8b_cts_mclk_i958_parent_names[] = { +- "mpll0", "mpll1", "mpll2" ++static const struct clk_hw *meson8b_cts_mclk_i958_parent_hws[] = { ++ &meson8b_mpll0.hw, ++ &meson8b_mpll1.hw, ++ &meson8b_mpll2.hw + }; + + static u32 meson8b_cts_mclk_i958_mux_table[] = { 1, 2, 3 }; +@@ -2224,8 +2503,8 @@ static struct clk_regmap meson8b_cts_mclk_i958_sel = { + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_sel", + .ops = &clk_regmap_mux_ops, +- .parent_names = meson8b_cts_mclk_i958_parent_names, +- .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_names), ++ .parent_hws = meson8b_cts_mclk_i958_parent_hws, ++ .num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_hws), + }, + }; + +@@ -2239,7 +2518,9 @@ static struct clk_regmap meson8b_cts_mclk_i958_div = { + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_div", + .ops = &clk_regmap_divider_ops, +- .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_mclk_i958_sel.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2253,7 +2534,9 @@ static struct clk_regmap meson8b_cts_mclk_i958 = { + .hw.init = &(struct clk_init_data){ + .name = "cts_mclk_i958", + .ops = &clk_regmap_gate_ops, +- .parent_names = (const char *[]){ "cts_mclk_i958_div" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_mclk_i958_div.hw ++ }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -2268,8 +2551,10 @@ static struct clk_regmap meson8b_cts_i958 = { + .hw.init = &(struct clk_init_data){ + .name = "cts_i958", + .ops = &clk_regmap_mux_ops, +- .parent_names = (const char *[]){ "cts_amclk", +- "cts_mclk_i958" }, ++ .parent_hws = (const struct clk_hw *[]) { ++ &meson8b_cts_amclk.hw, ++ &meson8b_cts_mclk_i958.hw ++ }, + .num_parents = 2, + /* + * The parent is specific to origin of the audio data. Let the +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0012-FROMGIT-clk-meson-clk-regmap-migrate-to-new-parent-d.patch b/packages/linux/patches/amlogic/amlogic-0012-FROMGIT-clk-meson-clk-regmap-migrate-to-new-parent-d.patch new file mode 100644 index 0000000000..e0ca2210b5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0012-FROMGIT-clk-meson-clk-regmap-migrate-to-new-parent-d.patch @@ -0,0 +1,121 @@ +From 0cfea924293edf3953e835dba72988839b69c05f Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:42:36 +0200 +Subject: [PATCH 012/186] FROMGIT: clk: meson: clk-regmap: migrate to new + parent description method + +This clock controller use the string comparison method to describe parent +relation between the clocks, which is not optimized. + +Migrate to the new way by using .parent_hws where possible (ie. when +all clocks are local to the controller) and use .parent_data otherwise. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit 3a36044e7f3909c7ddb7ddfc727ab8104a563439 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/axg.c | 3 +++ + drivers/clk/meson/clk-regmap.h | 12 ++++++------ + drivers/clk/meson/g12a.c | 6 ++++++ + drivers/clk/meson/gxbb.c | 3 +++ + drivers/clk/meson/meson8b.c | 3 +++ + 5 files changed, 21 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c +index 7a3d795cc614..13fc0006f63d 100644 +--- a/drivers/clk/meson/axg.c ++++ b/drivers/clk/meson/axg.c +@@ -1096,6 +1096,9 @@ static struct clk_regmap axg_gen_clk = { + }, + }; + ++#define MESON_GATE(_name, _reg, _bit) \ ++ MESON_PCLK(_name, _reg, _bit, &axg_clk81.hw) ++ + /* Everything Else (EE) domain gates */ + static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); + static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); +diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h +index 1dd0abe3ba91..c4a39604cffd 100644 +--- a/drivers/clk/meson/clk-regmap.h ++++ b/drivers/clk/meson/clk-regmap.h +@@ -111,7 +111,7 @@ clk_get_regmap_mux_data(struct clk_regmap *clk) + extern const struct clk_ops clk_regmap_mux_ops; + extern const struct clk_ops clk_regmap_mux_ro_ops; + +-#define __MESON_GATE(_name, _reg, _bit, _ops) \ ++#define __MESON_PCLK(_name, _reg, _bit, _ops, _pname) \ + struct clk_regmap _name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ +@@ -120,15 +120,15 @@ struct clk_regmap _name = { \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = _ops, \ +- .parent_names = (const char *[]){ "clk81" }, \ ++ .parent_hws = (const struct clk_hw *[]) { _pname }, \ + .num_parents = 1, \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + }, \ + } + +-#define MESON_GATE(_name, _reg, _bit) \ +- __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ops) ++#define MESON_PCLK(_name, _reg, _bit, _pname) \ ++ __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pname) + +-#define MESON_GATE_RO(_name, _reg, _bit) \ +- __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ro_ops) ++#define MESON_PCLK_RO(_name, _reg, _bit, _pname) \ ++ __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pname) + #endif /* __CLK_REGMAP_H */ +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index 8cc7f5acf7ab..a8f706de811b 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -3325,6 +3325,12 @@ static struct clk_regmap g12a_ts = { + }, + }; + ++#define MESON_GATE(_name, _reg, _bit) \ ++ MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw) ++ ++#define MESON_GATE_RO(_name, _reg, _bit) \ ++ MESON_PCLK_RO(_name, _reg, _bit, &g12a_clk81.hw) ++ + /* Everything Else (EE) domain gates */ + static MESON_GATE(g12a_ddr, HHI_GCLK_MPEG0, 0); + static MESON_GATE(g12a_dos, HHI_GCLK_MPEG0, 1); +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index 67e466356d4b..7cfb998eeb3e 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -2587,6 +2587,9 @@ static struct clk_regmap gxbb_gen_clk = { + }, + }; + ++#define MESON_GATE(_name, _reg, _bit) \ ++ MESON_PCLK(_name, _reg, _bit, &gxbb_clk81.hw) ++ + /* Everything Else (EE) domain gates */ + static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); + static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); +diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c +index b30279a5bfcc..67e6691e080c 100644 +--- a/drivers/clk/meson/meson8b.c ++++ b/drivers/clk/meson/meson8b.c +@@ -2564,6 +2564,9 @@ static struct clk_regmap meson8b_cts_i958 = { + }, + }; + ++#define MESON_GATE(_name, _reg, _bit) \ ++ MESON_PCLK(_name, _reg, _bit, &meson8b_clk81.hw) ++ + /* Everything Else (EE) domain gates */ + + static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0013-FROMGIT-clk-meson-remove-ee-input-bypass-clocks.patch b/packages/linux/patches/amlogic/amlogic-0013-FROMGIT-clk-meson-remove-ee-input-bypass-clocks.patch new file mode 100644 index 0000000000..8e73b3f69a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0013-FROMGIT-clk-meson-remove-ee-input-bypass-clocks.patch @@ -0,0 +1,88 @@ +From f6353b89b99dfe51f7b98bb91f0f2ea61e7a85b3 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:42:37 +0200 +Subject: [PATCH 013/186] FROMGIT: clk: meson: remove ee input bypass clocks + +During probe, bypass clocks (i.e. ee-in-xtal) are made from device-tree +inputs to provide input clocks which can be access through global name. +The cons of this method are the duplicated clocks, means more string +comparison. + +Specify parent directly with device-tree clock name. + +Remove the bypass clock registration from the ee probe function. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit b11cfaba5b4d6e287540a3d64c403e5b26dd2728 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/Kconfig | 1 - + drivers/clk/meson/meson-eeclk.c | 10 ---------- + drivers/clk/meson/meson-eeclk.h | 2 -- + 3 files changed, 13 deletions(-) + +diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig +index 178ee72ba4bc..72a37572501f 100644 +--- a/drivers/clk/meson/Kconfig ++++ b/drivers/clk/meson/Kconfig +@@ -38,7 +38,6 @@ config COMMON_CLK_MESON_AO_CLKC + config COMMON_CLK_MESON_EE_CLKC + tristate + select COMMON_CLK_MESON_REGMAP +- select COMMON_CLK_MESON_INPUT + + config COMMON_CLK_MESON8B + bool +diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c +index 6ba2094be257..a7cb1e7aedc4 100644 +--- a/drivers/clk/meson/meson-eeclk.c ++++ b/drivers/clk/meson/meson-eeclk.c +@@ -10,7 +10,6 @@ + #include + #include + +-#include "clk-input.h" + #include "clk-regmap.h" + #include "meson-eeclk.h" + +@@ -18,7 +17,6 @@ int meson_eeclkc_probe(struct platform_device *pdev) + { + const struct meson_eeclkc_data *data; + struct device *dev = &pdev->dev; +- struct clk_hw *input; + struct regmap *map; + int ret, i; + +@@ -37,14 +35,6 @@ int meson_eeclkc_probe(struct platform_device *pdev) + if (data->init_count) + regmap_multi_reg_write(map, data->init_regs, data->init_count); + +- input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); +- if (IS_ERR(input)) { +- ret = PTR_ERR(input); +- if (ret != -EPROBE_DEFER) +- dev_err(dev, "failed to get input clock"); +- return ret; +- } +- + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < data->regmap_clk_num; i++) + data->regmap_clks[i]->map = map; +diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h +index 9ab5d6fa7ccb..77316207bde1 100644 +--- a/drivers/clk/meson/meson-eeclk.h ++++ b/drivers/clk/meson/meson-eeclk.h +@@ -10,8 +10,6 @@ + #include + #include "clk-regmap.h" + +-#define IN_PREFIX "ee-in-" +- + struct platform_device; + + struct meson_eeclkc_data { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0014-FROMGIT-clk-meson-remove-clk-input-helper.patch b/packages/linux/patches/amlogic/amlogic-0014-FROMGIT-clk-meson-remove-clk-input-helper.patch new file mode 100644 index 0000000000..294e44f5f8 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0014-FROMGIT-clk-meson-remove-clk-input-helper.patch @@ -0,0 +1,130 @@ +From 7da31180caf32e166a7bbb896918f0fd4ec2e996 Mon Sep 17 00:00:00 2001 +From: Alexandre Mergnat +Date: Thu, 25 Jul 2019 18:42:38 +0200 +Subject: [PATCH 014/186] FROMGIT: clk: meson: remove clk input helper + +The clk input function which allows clock controllers to register a bypass +clock from a clock producer is no longer needed anymore since meson clock +controllers have migrated to a new parent allocation method. + +Signed-off-by: Alexandre Mergnat +Signed-off-by: Jerome Brunet +(cherry picked from commit e96c7612315a1183e12d5b6ebd523a3a93617510 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/Kconfig | 3 --- + drivers/clk/meson/Makefile | 1 - + drivers/clk/meson/clk-input.c | 49 ----------------------------------- + drivers/clk/meson/clk-input.h | 19 -------------- + 4 files changed, 72 deletions(-) + delete mode 100644 drivers/clk/meson/clk-input.c + delete mode 100644 drivers/clk/meson/clk-input.h + +diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig +index 72a37572501f..500be0b0d473 100644 +--- a/drivers/clk/meson/Kconfig ++++ b/drivers/clk/meson/Kconfig +@@ -1,7 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only +-config COMMON_CLK_MESON_INPUT +- tristate +- + config COMMON_CLK_MESON_REGMAP + tristate + select REGMAP +diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile +index bc35a4efd6b7..f09d83dc3d60 100644 +--- a/drivers/clk/meson/Makefile ++++ b/drivers/clk/meson/Makefile +@@ -4,7 +4,6 @@ + obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o + obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o + obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o +-obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o + obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o + obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o + obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o +diff --git a/drivers/clk/meson/clk-input.c b/drivers/clk/meson/clk-input.c +deleted file mode 100644 +index 086226e9dba6..000000000000 +--- a/drivers/clk/meson/clk-input.c ++++ /dev/null +@@ -1,49 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0 OR MIT) +-/* +- * Copyright (c) 2018 BayLibre, SAS. +- * Author: Jerome Brunet +- */ +- +-#include +-#include +-#include +-#include +-#include "clk-input.h" +- +-static const struct clk_ops meson_clk_no_ops = {}; +- +-struct clk_hw *meson_clk_hw_register_input(struct device *dev, +- const char *of_name, +- const char *clk_name, +- unsigned long flags) +-{ +- struct clk *parent_clk = devm_clk_get(dev, of_name); +- struct clk_init_data init; +- const char *parent_name; +- struct clk_hw *hw; +- int ret; +- +- if (IS_ERR(parent_clk)) +- return (struct clk_hw *)parent_clk; +- +- hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); +- if (!hw) +- return ERR_PTR(-ENOMEM); +- +- parent_name = __clk_get_name(parent_clk); +- init.name = clk_name; +- init.ops = &meson_clk_no_ops; +- init.flags = flags; +- init.parent_names = &parent_name; +- init.num_parents = 1; +- hw->init = &init; +- +- ret = devm_clk_hw_register(dev, hw); +- +- return ret ? ERR_PTR(ret) : hw; +-} +-EXPORT_SYMBOL_GPL(meson_clk_hw_register_input); +- +-MODULE_DESCRIPTION("Amlogic clock input helper"); +-MODULE_AUTHOR("Jerome Brunet "); +-MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/meson/clk-input.h b/drivers/clk/meson/clk-input.h +deleted file mode 100644 +index 4a541b9685a6..000000000000 +--- a/drivers/clk/meson/clk-input.h ++++ /dev/null +@@ -1,19 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Copyright (c) 2019 BayLibre, SAS. +- * Author: Jerome Brunet +- */ +- +-#ifndef __MESON_CLK_INPUT_H +-#define __MESON_CLK_INPUT_H +- +-#include +- +-struct device; +- +-struct clk_hw *meson_clk_hw_register_input(struct device *dev, +- const char *of_name, +- const char *clk_name, +- unsigned long flags); +- +-#endif /* __MESON_CLK_INPUT_H */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0015-FROMGIT-clk-core-introduce-clk_hw_set_parent.patch b/packages/linux/patches/amlogic/amlogic-0015-FROMGIT-clk-core-introduce-clk_hw_set_parent.patch new file mode 100644 index 0000000000..c60c336c79 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0015-FROMGIT-clk-core-introduce-clk_hw_set_parent.patch @@ -0,0 +1,56 @@ +From dc9ff799c4ae81fc4279d622036eb2a7044d2ae1 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 31 Jul 2019 10:40:16 +0200 +Subject: [PATCH 015/186] FROMGIT: clk: core: introduce clk_hw_set_parent() + +Introduce the clk_hw_set_parent() provider call to change parent of +a clock by using the clk_hw pointers. + +This eases the clock reparenting from clock rate notifiers and +implementing DVFS with simpler code avoiding the boilerplates +functions as __clk_lookup(clk_hw_get_name()) then clk_set_parent(). + +Signed-off-by: Neil Armstrong +Acked-by: Martin Blumenstingl +Acked-by: Stephen Boyd +Signed-off-by: Jerome Brunet +(cherry picked from commit 3567894b6914813299300019e028874927210880 + https://github.com/BayLibre/clk-meson v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/clk/clk.c | 6 ++++++ + include/linux/clk-provider.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 1c46babeb093..ca99e9db6575 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -2510,6 +2510,12 @@ static int clk_core_set_parent_nolock(struct clk_core *core, + return ret; + } + ++int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *parent) ++{ ++ return clk_core_set_parent_nolock(hw->core, parent->core); ++} ++EXPORT_SYMBOL_GPL(clk_hw_set_parent); ++ + /** + * clk_set_parent - switch the parent of a mux clk + * @clk: the mux clk whose input we are switching +diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h +index 2ae7604783dd..dce5521a9bf6 100644 +--- a/include/linux/clk-provider.h ++++ b/include/linux/clk-provider.h +@@ -817,6 +817,7 @@ unsigned int clk_hw_get_num_parents(const struct clk_hw *hw); + struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw); + struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, + unsigned int index); ++int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *new_parent); + unsigned int __clk_get_enable_count(struct clk *clk); + unsigned long clk_hw_get_rate(const struct clk_hw *hw); + unsigned long __clk_get_flags(struct clk *clk); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0016-FROMGIT-clk-meson-add-g12a-cpu-dynamic-divider-drive.patch b/packages/linux/patches/amlogic/amlogic-0016-FROMGIT-clk-meson-add-g12a-cpu-dynamic-divider-drive.patch new file mode 100644 index 0000000000..2d802d3bc8 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0016-FROMGIT-clk-meson-add-g12a-cpu-dynamic-divider-drive.patch @@ -0,0 +1,170 @@ +From 6ff05d5114e4073db11738008cdfa6fb81c5e7aa Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 31 Jul 2019 10:40:17 +0200 +Subject: [PATCH 016/186] FROMGIT: clk: meson: add g12a cpu dynamic divider + driver + +Add a clock driver for the cpu dynamic divider, this divider needs +to have a flag set before setting the divider value then removed +while writing the new value to the register. + +This drivers implements this behavior and will be used essentially +on the Amlogic G12A and G12B SoCs for cpu clock trees. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Jerome Brunet +(cherry picked from commit 26d34431add04a98a60b8935c25765914fa773f7 + https://github.com/BayLibre/clk-meson v5.4/drivers) +--- + drivers/clk/meson/Kconfig | 5 ++ + drivers/clk/meson/Makefile | 1 + + drivers/clk/meson/clk-cpu-dyndiv.c | 73 ++++++++++++++++++++++++++++++ + drivers/clk/meson/clk-cpu-dyndiv.h | 20 ++++++++ + 4 files changed, 99 insertions(+) + create mode 100644 drivers/clk/meson/clk-cpu-dyndiv.c + create mode 100644 drivers/clk/meson/clk-cpu-dyndiv.h + +diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig +index 500be0b0d473..dabeb435d067 100644 +--- a/drivers/clk/meson/Kconfig ++++ b/drivers/clk/meson/Kconfig +@@ -36,6 +36,10 @@ config COMMON_CLK_MESON_EE_CLKC + tristate + select COMMON_CLK_MESON_REGMAP + ++config COMMON_CLK_MESON_CPU_DYNDIV ++ tristate ++ select COMMON_CLK_MESON_REGMAP ++ + config COMMON_CLK_MESON8B + bool + depends on ARCH_MESON +@@ -98,6 +102,7 @@ config COMMON_CLK_G12A + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_AO_CLKC + select COMMON_CLK_MESON_EE_CLKC ++ select COMMON_CLK_MESON_CPU_DYNDIV + select MFD_SYSCON + help + Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 +diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile +index f09d83dc3d60..3939f218587a 100644 +--- a/drivers/clk/meson/Makefile ++++ b/drivers/clk/meson/Makefile +@@ -2,6 +2,7 @@ + # Amlogic clock drivers + + obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o ++obj-$(CONFIG_COMMON_CLK_MESON_CPU_DYNDIV) += clk-cpu-dyndiv.o + obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o + obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o + obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o +diff --git a/drivers/clk/meson/clk-cpu-dyndiv.c b/drivers/clk/meson/clk-cpu-dyndiv.c +new file mode 100644 +index 000000000000..36976927fe82 +--- /dev/null ++++ b/drivers/clk/meson/clk-cpu-dyndiv.c +@@ -0,0 +1,73 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS. ++ * Author: Neil Armstrong ++ */ ++ ++#include ++#include ++ ++#include "clk-regmap.h" ++#include "clk-cpu-dyndiv.h" ++ ++static inline struct meson_clk_cpu_dyndiv_data * ++meson_clk_cpu_dyndiv_data(struct clk_regmap *clk) ++{ ++ return (struct meson_clk_cpu_dyndiv_data *)clk->data; ++} ++ ++static unsigned long meson_clk_cpu_dyndiv_recalc_rate(struct clk_hw *hw, ++ unsigned long prate) ++{ ++ struct clk_regmap *clk = to_clk_regmap(hw); ++ struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); ++ ++ return divider_recalc_rate(hw, prate, ++ meson_parm_read(clk->map, &data->div), ++ NULL, 0, data->div.width); ++} ++ ++static long meson_clk_cpu_dyndiv_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_regmap *clk = to_clk_regmap(hw); ++ struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); ++ ++ return divider_round_rate(hw, rate, prate, NULL, data->div.width, 0); ++} ++ ++static int meson_clk_cpu_dyndiv_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_regmap *clk = to_clk_regmap(hw); ++ struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); ++ unsigned int val; ++ int ret; ++ ++ ret = divider_get_val(rate, parent_rate, NULL, data->div.width, 0); ++ if (ret < 0) ++ return ret; ++ ++ val = (unsigned int)ret << data->div.shift; ++ ++ /* Write the SYS_CPU_DYN_ENABLE bit before changing the divider */ ++ meson_parm_write(clk->map, &data->dyn, 1); ++ ++ /* Update the divider while removing the SYS_CPU_DYN_ENABLE bit */ ++ return regmap_update_bits(clk->map, data->div.reg_off, ++ SETPMASK(data->div.width, data->div.shift) | ++ SETPMASK(data->dyn.width, data->dyn.shift), ++ val); ++}; ++ ++const struct clk_ops meson_clk_cpu_dyndiv_ops = { ++ .recalc_rate = meson_clk_cpu_dyndiv_recalc_rate, ++ .round_rate = meson_clk_cpu_dyndiv_round_rate, ++ .set_rate = meson_clk_cpu_dyndiv_set_rate, ++}; ++EXPORT_SYMBOL_GPL(meson_clk_cpu_dyndiv_ops); ++ ++MODULE_DESCRIPTION("Amlogic CPU Dynamic Clock divider"); ++MODULE_AUTHOR("Neil Armstrong "); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/meson/clk-cpu-dyndiv.h b/drivers/clk/meson/clk-cpu-dyndiv.h +new file mode 100644 +index 000000000000..f4908404792e +--- /dev/null ++++ b/drivers/clk/meson/clk-cpu-dyndiv.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2019 BayLibre, SAS. ++ * Author: Neil Armstrong ++ */ ++ ++#ifndef __MESON_CLK_CPU_DYNDIV_H ++#define __MESON_CLK_CPU_DYNDIV_H ++ ++#include ++#include "parm.h" ++ ++struct meson_clk_cpu_dyndiv_data { ++ struct parm div; ++ struct parm dyn; ++}; ++ ++extern const struct clk_ops meson_clk_cpu_dyndiv_ops; ++ ++#endif /* __MESON_CLK_CPU_DYNDIV_H */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0017-FROMGIT-clk-meson-g12a-add-notifiers-to-handle-cpu-c.patch b/packages/linux/patches/amlogic/amlogic-0017-FROMGIT-clk-meson-g12a-add-notifiers-to-handle-cpu-c.patch new file mode 100644 index 0000000000..72781785ca --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0017-FROMGIT-clk-meson-g12a-add-notifiers-to-handle-cpu-c.patch @@ -0,0 +1,872 @@ +From 89141a5825cfa0672ee737d17027987b5a1a5b60 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 31 Jul 2019 10:40:18 +0200 +Subject: [PATCH 017/186] FROMGIT: clk: meson: g12a: add notifiers to handle + cpu clock change + +In order to implement clock switching for the CLKID_CPU_CLK and +CLKID_CPUB_CLK, notifiers are added on specific points of the +clock tree : + +cpu_clk / cpub_clk +| \- cpu_clk_dyn +| | \- cpu_clk_premux0 +| | |- cpu_clk_postmux0 +| | | |- cpu_clk_dyn0_div +| | | \- xtal/fclk_div2/fclk_div3 +| | \- xtal/fclk_div2/fclk_div3 +| \- cpu_clk_premux1 +| |- cpu_clk_postmux1 +| | |- cpu_clk_dyn1_div +| | \- xtal/fclk_div2/fclk_div3 +| \- xtal/fclk_div2/fclk_div3 +\ sys_pll / sys1_pll + +This for each cluster, a single one for G12A, two for G12B. + +Each cpu_clk_premux1 tree is marked as read-only and CLK_SET_RATE_NO_REPARENT, +to be used as "parking" clock in a safe clock frequency. + +A notifier is added on each cpu_clk_premux0 to detech when CCF want to +change the frequency of the cpu_clk_dyn tree. +In this notifier, the cpu_clk_premux1 tree is configured to use the xtal +clock and then the cpu_clk_dyn is switch to cpu_clk_premux1 while CCF +updates the cpu_clk_premux0 tree. + +A notifier is added on each sys_pll/sys1_pll to detect when CCF wants to +change the PLL clock source of the cpu_clk. +In this notifier, the cpu_clk is switched to cpu_clk_dyn while CCF +updates the sys_pll/sys1_pll frequency. + +A third small notifier is added on each cpu_clk / cpub_clk and cpu_clk_dyn, +add a small delay at PRE_RATE_CHANGE/POST_RATE_CHANGE to let the other +notofiers change propagate before changing the cpu_clk_premux0 and sys_pll +clock trees. + +This notifier set permits switching the cpu_clk / cpub_clk without any +glitches and using a safe parking clock while switching between sub-GHz +clocks using the cpu_clk_dyn tree. + +This setup has been tested and validated on the Amlogic G12A and G12B +SoCs running the arm64 cpuburn at [1] and cycling between all the possible +cpufreq translations of each cluster and checking the final frequency using +the clock-measurer, script at [2]. + +[1] https://github.com/ssvb/cpuburn-arm/blob/master/cpuburn-a53.S +[2] https://gist.github.com/superna9999/d4de964dbc0f84b7d527e1df2ddea25f + +Signed-off-by: Neil Armstrong +Signed-off-by: Jerome Brunet +(cherry picked from commit ffae8475b90c045ca508675794c08a0c8c12d202 + https://github.com/BayLibre/clk-meson v5.4/drivers) +--- + drivers/clk/meson/g12a.c | 535 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 481 insertions(+), 54 deletions(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index a8f706de811b..c3f0ffc3280d 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -14,10 +14,12 @@ + #include + #include + #include ++#include + + #include "clk-mpll.h" + #include "clk-pll.h" + #include "clk-regmap.h" ++#include "clk-cpu-dyndiv.h" + #include "vid-pll-div.h" + #include "meson-eeclk.h" + #include "g12a.h" +@@ -88,16 +90,9 @@ static struct clk_regmap g12a_fixed_pll = { + }, + }; + +-/* +- * Internal sys pll emulation configuration parameters +- */ +-static const struct reg_sequence g12a_sys_init_regs[] = { +- { .reg = HHI_SYS_PLL_CNTL1, .def = 0x00000000 }, +- { .reg = HHI_SYS_PLL_CNTL2, .def = 0x00000000 }, +- { .reg = HHI_SYS_PLL_CNTL3, .def = 0x48681c00 }, +- { .reg = HHI_SYS_PLL_CNTL4, .def = 0x88770290 }, +- { .reg = HHI_SYS_PLL_CNTL5, .def = 0x39272000 }, +- { .reg = HHI_SYS_PLL_CNTL6, .def = 0x56540000 }, ++static const struct pll_mult_range g12a_sys_pll_mult_range = { ++ .min = 128, ++ .max = 250, + }; + + static struct clk_regmap g12a_sys_pll_dco = { +@@ -127,16 +122,17 @@ static struct clk_regmap g12a_sys_pll_dco = { + .shift = 29, + .width = 1, + }, +- .init_regs = g12a_sys_init_regs, +- .init_count = ARRAY_SIZE(g12a_sys_init_regs), ++ .range = &g12a_sys_pll_mult_range, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", +- .ops = &meson_clk_pll_ro_ops, ++ .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, ++ /* This clock feeds the CPU, avoid disabling it */ ++ .flags = CLK_IS_CRITICAL, + }, + }; + +@@ -149,11 +145,12 @@ static struct clk_regmap g12a_sys_pll = { + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", +- .ops = &clk_regmap_divider_ro_ops, ++ .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sys_pll_dco.hw + }, + .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -184,14 +181,17 @@ static struct clk_regmap g12b_sys1_pll_dco = { + .shift = 29, + .width = 1, + }, ++ .range = &g12a_sys_pll_mult_range, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll_dco", +- .ops = &meson_clk_pll_ro_ops, ++ .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, ++ /* This clock feeds the CPU, avoid disabling it */ ++ .flags = CLK_IS_CRITICAL, + }, + }; + +@@ -204,11 +204,12 @@ static struct clk_regmap g12b_sys1_pll = { + }, + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll", +- .ops = &clk_regmap_divider_ro_ops, ++ .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_sys1_pll_dco.hw + }, + .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -345,13 +346,15 @@ static struct clk_regmap g12a_cpu_clk_premux0 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_sel", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, ++ /* This sub-tree is used a parking clock */ ++ .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; + +@@ -364,30 +367,40 @@ static struct clk_regmap g12a_cpu_clk_premux1 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1_sel", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, ++ /* This sub-tree is used a parking clock */ ++ .flags = CLK_SET_RATE_NO_REPARENT + }, + }; + + /* Datasheet names this field as "mux0_divn_tcnt" */ + static struct clk_regmap g12a_cpu_clk_mux0_div = { +- .data = &(struct clk_regmap_div_data){ +- .offset = HHI_SYS_CPU_CLK_CNTL0, +- .shift = 4, +- .width = 6, ++ .data = &(struct meson_clk_cpu_dyndiv_data){ ++ .div = { ++ .reg_off = HHI_SYS_CPU_CLK_CNTL0, ++ .shift = 4, ++ .width = 6, ++ }, ++ .dyn = { ++ .reg_off = HHI_SYS_CPU_CLK_CNTL0, ++ .shift = 26, ++ .width = 1, ++ }, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_div", +- .ops = &clk_regmap_divider_ro_ops, ++ .ops = &meson_clk_cpu_dyndiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_premux0.hw + }, + .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -400,12 +413,13 @@ static struct clk_regmap g12a_cpu_clk_postmux0 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_premux0.hw, + &g12a_cpu_clk_mux0_div.hw, + }, + .num_parents = 2, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -435,12 +449,14 @@ static struct clk_regmap g12a_cpu_clk_postmux1 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_premux1.hw, + &g12a_cpu_clk_mux1_div.hw, + }, + .num_parents = 2, ++ /* This sub-tree is used a parking clock */ ++ .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; + +@@ -453,12 +469,13 @@ static struct clk_regmap g12a_cpu_clk_dyn = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_postmux0.hw, + &g12a_cpu_clk_postmux1.hw, + }, + .num_parents = 2, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -471,12 +488,13 @@ static struct clk_regmap g12a_cpu_clk = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn.hw, + &g12a_sys_pll.hw, + }, + .num_parents = 2, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -489,12 +507,13 @@ static struct clk_regmap g12b_cpu_clk = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn.hw, + &g12b_sys1_pll.hw + }, + .num_parents = 2, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -507,7 +526,7 @@ static struct clk_regmap g12b_cpub_clk_premux0 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0_sel", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, +@@ -519,18 +538,26 @@ static struct clk_regmap g12b_cpub_clk_premux0 = { + + /* Datasheet names this field as "mux0_divn_tcnt" */ + static struct clk_regmap g12b_cpub_clk_mux0_div = { +- .data = &(struct clk_regmap_div_data){ +- .offset = HHI_SYS_CPUB_CLK_CNTL, +- .shift = 4, +- .width = 6, ++ .data = &(struct meson_clk_cpu_dyndiv_data){ ++ .div = { ++ .reg_off = HHI_SYS_CPUB_CLK_CNTL, ++ .shift = 4, ++ .width = 6, ++ }, ++ .dyn = { ++ .reg_off = HHI_SYS_CPUB_CLK_CNTL, ++ .shift = 26, ++ .width = 1, ++ }, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0_div", +- .ops = &clk_regmap_divider_ro_ops, ++ .ops = &meson_clk_cpu_dyndiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_premux0.hw + }, + .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -543,12 +570,13 @@ static struct clk_regmap g12b_cpub_clk_postmux0 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_premux0.hw, + &g12b_cpub_clk_mux0_div.hw + }, + .num_parents = 2, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -561,13 +589,15 @@ static struct clk_regmap g12b_cpub_clk_premux1 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1_sel", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, ++ /* This sub-tree is used a parking clock */ ++ .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; + +@@ -597,12 +627,14 @@ static struct clk_regmap g12b_cpub_clk_postmux1 = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_premux1.hw, + &g12b_cpub_clk_mux1_div.hw + }, + .num_parents = 2, ++ /* This sub-tree is used a parking clock */ ++ .flags = CLK_SET_RATE_NO_REPARENT, + }, + }; + +@@ -615,12 +647,13 @@ static struct clk_regmap g12b_cpub_clk_dyn = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_postmux0.hw, + &g12b_cpub_clk_postmux1.hw + }, + .num_parents = 2, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + +@@ -633,15 +666,227 @@ static struct clk_regmap g12b_cpub_clk = { + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk", +- .ops = &clk_regmap_mux_ro_ops, ++ .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn.hw, + &g12a_sys_pll.hw + }, + .num_parents = 2, ++ .flags = CLK_SET_RATE_PARENT, + }, + }; + ++static int g12a_cpu_clk_mux_notifier_cb(struct notifier_block *nb, ++ unsigned long event, void *data) ++{ ++ if (event == POST_RATE_CHANGE || event == PRE_RATE_CHANGE) { ++ /* Wait for clock propagation before/after changing the mux */ ++ udelay(100); ++ return NOTIFY_OK; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block g12a_cpu_clk_mux_nb = { ++ .notifier_call = g12a_cpu_clk_mux_notifier_cb, ++}; ++ ++struct g12a_cpu_clk_postmux_nb_data { ++ struct notifier_block nb; ++ struct clk_hw *xtal; ++ struct clk_hw *cpu_clk_dyn; ++ struct clk_hw *cpu_clk_postmux0; ++ struct clk_hw *cpu_clk_postmux1; ++ struct clk_hw *cpu_clk_premux1; ++}; ++ ++static int g12a_cpu_clk_postmux_notifier_cb(struct notifier_block *nb, ++ unsigned long event, void *data) ++{ ++ struct g12a_cpu_clk_postmux_nb_data *nb_data = ++ container_of(nb, struct g12a_cpu_clk_postmux_nb_data, nb); ++ ++ switch (event) { ++ case PRE_RATE_CHANGE: ++ /* ++ * This notifier means cpu_clk_postmux0 clock will be changed ++ * to feed cpu_clk, this is the current path : ++ * cpu_clk ++ * \- cpu_clk_dyn ++ * \- cpu_clk_postmux0 ++ * \- cpu_clk_muxX_div ++ * \- cpu_clk_premux0 ++ * \- fclk_div3 or fclk_div2 ++ * OR ++ * \- cpu_clk_premux0 ++ * \- fclk_div3 or fclk_div2 ++ */ ++ ++ /* Setup cpu_clk_premux1 to xtal */ ++ clk_hw_set_parent(nb_data->cpu_clk_premux1, ++ nb_data->xtal); ++ ++ /* Setup cpu_clk_postmux1 to bypass divider */ ++ clk_hw_set_parent(nb_data->cpu_clk_postmux1, ++ nb_data->cpu_clk_premux1); ++ ++ /* Switch to parking clk on cpu_clk_postmux1 */ ++ clk_hw_set_parent(nb_data->cpu_clk_dyn, ++ nb_data->cpu_clk_postmux1); ++ ++ /* ++ * Now, cpu_clk is 24MHz in the current path : ++ * cpu_clk ++ * \- cpu_clk_dyn ++ * \- cpu_clk_postmux1 ++ * \- cpu_clk_premux1 ++ * \- xtal ++ */ ++ ++ udelay(100); ++ ++ return NOTIFY_OK; ++ ++ case POST_RATE_CHANGE: ++ /* ++ * The cpu_clk_postmux0 has ben updated, now switch back ++ * cpu_clk_dyn to cpu_clk_postmux0 and take the changes ++ * in account. ++ */ ++ ++ /* Configure cpu_clk_dyn back to cpu_clk_postmux0 */ ++ clk_hw_set_parent(nb_data->cpu_clk_dyn, ++ nb_data->cpu_clk_postmux0); ++ ++ /* ++ * new path : ++ * cpu_clk ++ * \- cpu_clk_dyn ++ * \- cpu_clk_postmux0 ++ * \- cpu_clk_muxX_div ++ * \- cpu_clk_premux0 ++ * \- fclk_div3 or fclk_div2 ++ * OR ++ * \- cpu_clk_premux0 ++ * \- fclk_div3 or fclk_div2 ++ */ ++ ++ udelay(100); ++ ++ return NOTIFY_OK; ++ ++ default: ++ return NOTIFY_DONE; ++ } ++} ++ ++static struct g12a_cpu_clk_postmux_nb_data g12a_cpu_clk_postmux0_nb_data = { ++ .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, ++ .cpu_clk_postmux0 = &g12a_cpu_clk_postmux0.hw, ++ .cpu_clk_postmux1 = &g12a_cpu_clk_postmux1.hw, ++ .cpu_clk_premux1 = &g12a_cpu_clk_premux1.hw, ++ .nb.notifier_call = g12a_cpu_clk_postmux_notifier_cb, ++}; ++ ++static struct g12a_cpu_clk_postmux_nb_data g12b_cpub_clk_postmux0_nb_data = { ++ .cpu_clk_dyn = &g12b_cpub_clk_dyn.hw, ++ .cpu_clk_postmux0 = &g12b_cpub_clk_postmux0.hw, ++ .cpu_clk_postmux1 = &g12b_cpub_clk_postmux1.hw, ++ .cpu_clk_premux1 = &g12b_cpub_clk_premux1.hw, ++ .nb.notifier_call = g12a_cpu_clk_postmux_notifier_cb, ++}; ++ ++struct g12a_sys_pll_nb_data { ++ struct notifier_block nb; ++ struct clk_hw *sys_pll; ++ struct clk_hw *cpu_clk; ++ struct clk_hw *cpu_clk_dyn; ++}; ++ ++static int g12a_sys_pll_notifier_cb(struct notifier_block *nb, ++ unsigned long event, void *data) ++{ ++ struct g12a_sys_pll_nb_data *nb_data = ++ container_of(nb, struct g12a_sys_pll_nb_data, nb); ++ ++ switch (event) { ++ case PRE_RATE_CHANGE: ++ /* ++ * This notifier means sys_pll clock will be changed ++ * to feed cpu_clk, this the current path : ++ * cpu_clk ++ * \- sys_pll ++ * \- sys_pll_dco ++ */ ++ ++ /* Configure cpu_clk to use cpu_clk_dyn */ ++ clk_hw_set_parent(nb_data->cpu_clk, ++ nb_data->cpu_clk_dyn); ++ ++ /* ++ * Now, cpu_clk uses the dyn path ++ * cpu_clk ++ * \- cpu_clk_dyn ++ * \- cpu_clk_dynX ++ * \- cpu_clk_dynX_sel ++ * \- cpu_clk_dynX_div ++ * \- xtal/fclk_div2/fclk_div3 ++ * \- xtal/fclk_div2/fclk_div3 ++ */ ++ ++ udelay(100); ++ ++ return NOTIFY_OK; ++ ++ case POST_RATE_CHANGE: ++ /* ++ * The sys_pll has ben updated, now switch back cpu_clk to ++ * sys_pll ++ */ ++ ++ /* Configure cpu_clk to use sys_pll */ ++ clk_hw_set_parent(nb_data->cpu_clk, ++ nb_data->sys_pll); ++ ++ udelay(100); ++ ++ /* new path : ++ * cpu_clk ++ * \- sys_pll ++ * \- sys_pll_dco ++ */ ++ ++ return NOTIFY_OK; ++ ++ default: ++ return NOTIFY_DONE; ++ } ++} ++ ++static struct g12a_sys_pll_nb_data g12a_sys_pll_nb_data = { ++ .sys_pll = &g12a_sys_pll.hw, ++ .cpu_clk = &g12a_cpu_clk.hw, ++ .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, ++ .nb.notifier_call = g12a_sys_pll_notifier_cb, ++}; ++ ++/* G12B first CPU cluster uses sys1_pll */ ++static struct g12a_sys_pll_nb_data g12b_cpu_clk_sys1_pll_nb_data = { ++ .sys_pll = &g12b_sys1_pll.hw, ++ .cpu_clk = &g12b_cpu_clk.hw, ++ .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, ++ .nb.notifier_call = g12a_sys_pll_notifier_cb, ++}; ++ ++/* G12B second CPU cluster uses sys_pll */ ++static struct g12a_sys_pll_nb_data g12b_cpub_clk_sys_pll_nb_data = { ++ .sys_pll = &g12a_sys_pll.hw, ++ .cpu_clk = &g12b_cpub_clk.hw, ++ .cpu_clk_dyn = &g12b_cpub_clk_dyn.hw, ++ .nb.notifier_call = g12a_sys_pll_notifier_cb, ++}; ++ + static struct clk_regmap g12a_cpu_clk_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, +@@ -4097,28 +4342,210 @@ static const struct reg_sequence g12a_init_regs[] = { + { .reg = HHI_MPLL_CNTL0, .def = 0x00000543 }, + }; + +-static const struct meson_eeclkc_data g12a_clkc_data = { +- .regmap_clks = g12a_clk_regmaps, +- .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), +- .hw_onecell_data = &g12a_hw_onecell_data, +- .init_regs = g12a_init_regs, +- .init_count = ARRAY_SIZE(g12a_init_regs), +-}; +- +-static const struct meson_eeclkc_data g12b_clkc_data = { +- .regmap_clks = g12a_clk_regmaps, +- .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), +- .hw_onecell_data = &g12b_hw_onecell_data ++static int meson_g12a_dvfs_setup_common(struct platform_device *pdev, ++ struct clk_hw **hws) ++{ ++ const char *notifier_clk_name; ++ struct clk *notifier_clk; ++ struct clk_hw *xtal; ++ int ret; ++ ++ xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); ++ ++ /* Setup clock notifier for cpu_clk_postmux0 */ ++ g12a_cpu_clk_postmux0_nb_data.xtal = xtal; ++ notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_postmux0.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, ++ &g12a_cpu_clk_postmux0_nb_data.nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the cpu_clk_postmux0 notifier\n"); ++ return ret; ++ } ++ ++ /* Setup clock notifier for cpu_clk_dyn mux */ ++ notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk_dyn.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the cpu_clk_dyn notifier\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_g12b_dvfs_setup(struct platform_device *pdev) ++{ ++ struct clk_hw **hws = g12b_hw_onecell_data.hws; ++ const char *notifier_clk_name; ++ struct clk *notifier_clk; ++ struct clk_hw *xtal; ++ int ret; ++ ++ ret = meson_g12a_dvfs_setup_common(pdev, hws); ++ if (ret) ++ return ret; ++ ++ xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); ++ ++ /* Setup clock notifier for cpu_clk mux */ ++ notifier_clk_name = clk_hw_get_name(&g12b_cpu_clk.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n"); ++ return ret; ++ } ++ ++ /* Setup clock notifier for sys1_pll */ ++ notifier_clk_name = clk_hw_get_name(&g12b_sys1_pll.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, ++ &g12b_cpu_clk_sys1_pll_nb_data.nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the sys1_pll notifier\n"); ++ return ret; ++ } ++ ++ /* Add notifiers for the second CPU cluster */ ++ ++ /* Setup clock notifier for cpub_clk_postmux0 */ ++ g12b_cpub_clk_postmux0_nb_data.xtal = xtal; ++ notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_postmux0.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, ++ &g12b_cpub_clk_postmux0_nb_data.nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the cpub_clk_postmux0 notifier\n"); ++ return ret; ++ } ++ ++ /* Setup clock notifier for cpub_clk_dyn mux */ ++ notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk_dyn.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the cpub_clk_dyn notifier\n"); ++ return ret; ++ } ++ ++ /* Setup clock notifier for cpub_clk mux */ ++ notifier_clk_name = clk_hw_get_name(&g12b_cpub_clk.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the cpub_clk notifier\n"); ++ return ret; ++ } ++ ++ /* Setup clock notifier for sys_pll */ ++ notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, ++ &g12b_cpub_clk_sys_pll_nb_data.nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the sys_pll notifier\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_g12a_dvfs_setup(struct platform_device *pdev) ++{ ++ struct clk_hw **hws = g12a_hw_onecell_data.hws; ++ const char *notifier_clk_name; ++ struct clk *notifier_clk; ++ int ret; ++ ++ ret = meson_g12a_dvfs_setup_common(pdev, hws); ++ if (ret) ++ return ret; ++ ++ /* Setup clock notifier for cpu_clk mux */ ++ notifier_clk_name = clk_hw_get_name(&g12a_cpu_clk.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, &g12a_cpu_clk_mux_nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the cpu_clk notifier\n"); ++ return ret; ++ } ++ ++ /* Setup clock notifier for sys_pll */ ++ notifier_clk_name = clk_hw_get_name(&g12a_sys_pll.hw); ++ notifier_clk = __clk_lookup(notifier_clk_name); ++ ret = clk_notifier_register(notifier_clk, &g12a_sys_pll_nb_data.nb); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register the sys_pll notifier\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++struct meson_g12a_data { ++ const struct meson_eeclkc_data eeclkc_data; ++ int (*dvfs_setup)(struct platform_device *pdev); ++}; ++ ++static int meson_g12a_probe(struct platform_device *pdev) ++{ ++ const struct meson_eeclkc_data *eeclkc_data; ++ const struct meson_g12a_data *g12a_data; ++ int ret; ++ ++ eeclkc_data = of_device_get_match_data(&pdev->dev); ++ if (!eeclkc_data) ++ return -EINVAL; ++ ++ ret = meson_eeclkc_probe(pdev); ++ if (ret) ++ return ret; ++ ++ g12a_data = container_of(eeclkc_data, struct meson_g12a_data, ++ eeclkc_data); ++ ++ if (g12a_data->dvfs_setup) ++ return g12a_data->dvfs_setup(pdev); ++ ++ return 0; ++} ++ ++static const struct meson_g12a_data g12a_clkc_data = { ++ .eeclkc_data = { ++ .regmap_clks = g12a_clk_regmaps, ++ .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), ++ .hw_onecell_data = &g12a_hw_onecell_data, ++ .init_regs = g12a_init_regs, ++ .init_count = ARRAY_SIZE(g12a_init_regs), ++ }, ++ .dvfs_setup = meson_g12a_dvfs_setup, ++}; ++ ++static const struct meson_g12a_data g12b_clkc_data = { ++ .eeclkc_data = { ++ .regmap_clks = g12a_clk_regmaps, ++ .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), ++ .hw_onecell_data = &g12b_hw_onecell_data, ++ }, ++ .dvfs_setup = meson_g12b_dvfs_setup, + }; + + static const struct of_device_id clkc_match_table[] = { +- { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data }, +- { .compatible = "amlogic,g12b-clkc", .data = &g12b_clkc_data }, ++ { ++ .compatible = "amlogic,g12a-clkc", ++ .data = &g12a_clkc_data.eeclkc_data ++ }, ++ { ++ .compatible = "amlogic,g12b-clkc", ++ .data = &g12b_clkc_data.eeclkc_data ++ }, + {} + }; + + static struct platform_driver g12a_driver = { +- .probe = meson_eeclkc_probe, ++ .probe = meson_g12a_probe, + .driver = { + .name = "g12a-clkc", + .of_match_table = clkc_match_table, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0018-FROMGIT-clk-meson-g12a-expose-CPUB-clock-ID-for-G12B.patch b/packages/linux/patches/amlogic/amlogic-0018-FROMGIT-clk-meson-g12a-expose-CPUB-clock-ID-for-G12B.patch new file mode 100644 index 0000000000..a10bb2b5e5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0018-FROMGIT-clk-meson-g12a-expose-CPUB-clock-ID-for-G12B.patch @@ -0,0 +1,45 @@ +From d0998101225886bf6126c3cb7dd281bf91d06435 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 31 Jul 2019 10:40:19 +0200 +Subject: [PATCH 018/186] FROMGIT: clk: meson: g12a: expose CPUB clock ID for + G12B + +Expose the CPUB clock id to add DVFS to the second CPU cluster of +the Amlogic G12B SoC. + +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +Signed-off-by: Jerome Brunet +(cherry picked from commit 85ab9d954698961960240622de4fad85c7d8a61e + https://github.com/BayLibre/clk-meson v5.4/drivers) +--- + drivers/clk/meson/g12a.h | 1 - + include/dt-bindings/clock/g12a-clkc.h | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h +index c8aed31fbe17..559a34cfdfeb 100644 +--- a/drivers/clk/meson/g12a.h ++++ b/drivers/clk/meson/g12a.h +@@ -216,7 +216,6 @@ + #define CLKID_CPUB_CLK_DYN1_DIV 221 + #define CLKID_CPUB_CLK_DYN1 222 + #define CLKID_CPUB_CLK_DYN 223 +-#define CLKID_CPUB_CLK 224 + #define CLKID_CPUB_CLK_DIV16_EN 225 + #define CLKID_CPUB_CLK_DIV16 226 + #define CLKID_CPUB_CLK_DIV2 227 +diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h +index b6b127e45634..8ccc29ac7a72 100644 +--- a/include/dt-bindings/clock/g12a-clkc.h ++++ b/include/dt-bindings/clock/g12a-clkc.h +@@ -137,5 +137,6 @@ + #define CLKID_VDEC_HEVC 207 + #define CLKID_VDEC_HEVCF 210 + #define CLKID_TS 212 ++#define CLKID_CPUB_CLK 224 + + #endif /* __G12A_CLKC_H */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0019-FROMGIT-soc-amlogic-meson-clk-measure-protect-measur.patch b/packages/linux/patches/amlogic/amlogic-0019-FROMGIT-soc-amlogic-meson-clk-measure-protect-measur.patch new file mode 100644 index 0000000000..5a3624c87a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0019-FROMGIT-soc-amlogic-meson-clk-measure-protect-measur.patch @@ -0,0 +1,67 @@ +From 65a2ec7507a4b3bb728856d68a385caa3d4c5560 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:02:17 +0200 +Subject: [PATCH 019/186] FROMGIT: soc: amlogic: meson-clk-measure: protect + measure with a mutex + +In order to protect clock measuring when multiple process asks for +a measure, protect the main measure function with mutexes. + +Reviewed-by: Kevin Hilman +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 3a760d986568b67d1f8411dab64608075817b90d + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/drivers) +--- + drivers/soc/amlogic/meson-clk-measure.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c +index 19d4cbc93a17..c470e24f1dfa 100644 +--- a/drivers/soc/amlogic/meson-clk-measure.c ++++ b/drivers/soc/amlogic/meson-clk-measure.c +@@ -11,6 +11,8 @@ + #include + #include + ++static DEFINE_MUTEX(measure_lock); ++ + #define MSR_CLK_DUTY 0x0 + #define MSR_CLK_REG0 0x4 + #define MSR_CLK_REG1 0x8 +@@ -360,6 +362,10 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id, + unsigned int val; + int ret; + ++ ret = mutex_lock_interruptible(&measure_lock); ++ if (ret) ++ return ret; ++ + regmap_write(priv->regmap, MSR_CLK_REG0, 0); + + /* Set measurement duration */ +@@ -377,8 +383,10 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id, + + ret = regmap_read_poll_timeout(priv->regmap, MSR_CLK_REG0, + val, !(val & MSR_BUSY), 10, 10000); +- if (ret) ++ if (ret) { ++ mutex_unlock(&measure_lock); + return ret; ++ } + + /* Disable */ + regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_ENABLE, 0); +@@ -386,6 +394,8 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id, + /* Get the value in multiple of gate time counts */ + regmap_read(priv->regmap, MSR_CLK_REG2, &val); + ++ mutex_unlock(&measure_lock); ++ + if (val >= MSR_VAL_MASK) + return -EINVAL; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0020-FROMGIT-soc-amlogic-meson-clk-measure-add-G12B-secon.patch b/packages/linux/patches/amlogic/amlogic-0020-FROMGIT-soc-amlogic-meson-clk-measure-add-G12B-secon.patch new file mode 100644 index 0000000000..2ee75bd172 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0020-FROMGIT-soc-amlogic-meson-clk-measure-add-G12B-secon.patch @@ -0,0 +1,37 @@ +From 08a3283d36ef13a50a8ddfacd739ff55bdac3c34 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:02:18 +0200 +Subject: [PATCH 020/186] FROMGIT: soc: amlogic: meson-clk-measure: add G12B + second cluster cpu clk + +Add the G12B second CPU cluster CPU and SYS_PLL measure IDs. + +These IDs returns 0Hz on G12A. + +Reviewed-by: Kevin Hilman +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit c33b2777d01eb0039a53f14f8c0e4cca8df501c7 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/soc/amlogic/meson-clk-measure.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c +index c470e24f1dfa..f09b404b39d3 100644 +--- a/drivers/soc/amlogic/meson-clk-measure.c ++++ b/drivers/soc/amlogic/meson-clk-measure.c +@@ -324,6 +324,8 @@ static struct meson_msr_id clk_msr_g12a[CLK_MSR_MAX] = { + CLK_MSR_ID(84, "co_tx"), + CLK_MSR_ID(89, "hdmi_todig"), + CLK_MSR_ID(90, "hdmitx_sys"), ++ CLK_MSR_ID(91, "sys_cpub_div16"), ++ CLK_MSR_ID(92, "sys_pll_cpub_div16"), + CLK_MSR_ID(94, "eth_phy_rx"), + CLK_MSR_ID(95, "eth_phy_pll"), + CLK_MSR_ID(96, "vpu_b"), +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0021-FROMGIT-soc-amlogic-meson-gx-socinfo-add-A311D-id.patch b/packages/linux/patches/amlogic/amlogic-0021-FROMGIT-soc-amlogic-meson-gx-socinfo-add-A311D-id.patch new file mode 100644 index 0000000000..710d6624e7 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0021-FROMGIT-soc-amlogic-meson-gx-socinfo-add-A311D-id.patch @@ -0,0 +1,32 @@ +From ba74cf5f60291b58387057319b422c5547da6fac Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Wed, 31 Jul 2019 14:39:55 +0200 +Subject: [PATCH 021/186] FROMGIT: soc: amlogic: meson-gx-socinfo: add A311D id + +Add the SoC ID for the A311D Amlogic SoC. + +Signed-off-by: Christian Hewitt +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit 0baf212eab4daf8e4882afd624e1403846418610 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/drivers) +--- + drivers/soc/amlogic/meson-gx-socinfo.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c +index bca34954518e..ff86a75939e8 100644 +--- a/drivers/soc/amlogic/meson-gx-socinfo.c ++++ b/drivers/soc/amlogic/meson-gx-socinfo.c +@@ -65,6 +65,7 @@ static const struct meson_gx_package_id { + { "S905D2", 0x28, 0x10, 0xf0 }, + { "S905X2", 0x28, 0x40, 0xf0 }, + { "S922X", 0x29, 0x40, 0xf0 }, ++ { "A311D", 0x29, 0x10, 0xf0 }, + }; + + static inline unsigned int socinfo_to_major(u32 socinfo) +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0022-FROMGIT-arm64-dts-move-common-G12A-G12B-modes-to-mes.patch b/packages/linux/patches/amlogic/amlogic-0022-FROMGIT-arm64-dts-move-common-G12A-G12B-modes-to-mes.patch new file mode 100644 index 0000000000..55568263a3 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0022-FROMGIT-arm64-dts-move-common-G12A-G12B-modes-to-mes.patch @@ -0,0 +1,4935 @@ +From e9516a21254a7f2da040ac8b63cd8961c80f03cb Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:26:17 +0200 +Subject: [PATCH 022/186] FROMGIT: arm64: dts: move common G12A & G12B modes to + meson-g12-common.dtsi + +To simplify the representation of differences betweem the G12A and G12B +SoCs, move the common nodes into a meson-g12-common.dtsi file and +express the CPU nodes and differences in meson-g12a.dtsi and meson-g12b.dtsi. + +This separation will help for DVFS and future Amlogic SM1 Family support. + +The sd_emmc_a quirk is added in the g12a/g12b since since it's already +known the sd_emmc_a controller is fixed in the next SM1 SoC family. + +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit c49051f9e3bfea3dcaf241095d81e52c9733cdcb + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + .../boot/dts/amlogic/meson-g12-common.dtsi | 2409 +++++++++++++++++ + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 2406 +--------------- + arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 30 +- + 3 files changed, 2440 insertions(+), 2405 deletions(-) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +new file mode 100644 +index 000000000000..06e186ca41e3 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -0,0 +1,2409 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2018 Amlogic, Inc. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/ { ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ tdmif_a: audio-controller-0 { ++ compatible = "amlogic,axg-tdm-iface"; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TDM_A"; ++ clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>, ++ <&clkc_audio AUD_CLKID_MST_A_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_A_LRCLK>; ++ clock-names = "mclk", "sclk", "lrclk"; ++ status = "disabled"; ++ }; ++ ++ tdmif_b: audio-controller-1 { ++ compatible = "amlogic,axg-tdm-iface"; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TDM_B"; ++ clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>, ++ <&clkc_audio AUD_CLKID_MST_B_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_B_LRCLK>; ++ clock-names = "mclk", "sclk", "lrclk"; ++ status = "disabled"; ++ }; ++ ++ tdmif_c: audio-controller-2 { ++ compatible = "amlogic,axg-tdm-iface"; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TDM_C"; ++ clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>, ++ <&clkc_audio AUD_CLKID_MST_C_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_C_LRCLK>; ++ clock-names = "mclk", "sclk", "lrclk"; ++ status = "disabled"; ++ }; ++ ++ efuse: efuse { ++ compatible = "amlogic,meson-gxbb-efuse"; ++ clocks = <&clkc CLKID_EFUSE>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ read-only; ++ }; ++ ++ psci { ++ compatible = "arm,psci-1.0"; ++ method = "smc"; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* 3 MiB reserved for ARM Trusted Firmware (BL31) */ ++ secmon_reserved: secmon@5000000 { ++ reg = <0x0 0x05000000 0x0 0x300000>; ++ no-map; ++ }; ++ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; ++ size = <0x0 0x10000000>; ++ alignment = <0x0 0x400000>; ++ linux,cma-default; ++ }; ++ }; ++ ++ sm: secure-monitor { ++ compatible = "amlogic,meson-gxbb-sm"; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ ethmac: ethernet@ff3f0000 { ++ compatible = "amlogic,meson-axg-dwmac", ++ "snps,dwmac-3.70a", ++ "snps,dwmac"; ++ reg = <0x0 0xff3f0000 0x0 0x10000 ++ 0x0 0xff634540 0x0 0x8>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ clocks = <&clkc CLKID_ETH>, ++ <&clkc CLKID_FCLK_DIV2>, ++ <&clkc CLKID_MPLL2>; ++ clock-names = "stmmaceth", "clkin0", "clkin1"; ++ status = "disabled"; ++ ++ mdio0: mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,dwmac-mdio"; ++ }; ++ }; ++ ++ apb: bus@ff600000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0xff600000 0x0 0x200000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0xff600000 0x0 0x200000>; ++ ++ hdmi_tx: hdmi-tx@0 { ++ compatible = "amlogic,meson-g12a-dw-hdmi"; ++ reg = <0x0 0x0 0x0 0x10000>; ++ interrupts = ; ++ resets = <&reset RESET_HDMITX_CAPB3>, ++ <&reset RESET_HDMITX_PHY>, ++ <&reset RESET_HDMITX>; ++ reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; ++ clocks = <&clkc CLKID_HDMI>, ++ <&clkc CLKID_HTX_PCLK>, ++ <&clkc CLKID_VPU_INTR>; ++ clock-names = "isfr", "iahb", "venci"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #sound-dai-cells = <0>; ++ status = "disabled"; ++ ++ /* VPU VENC Input */ ++ hdmi_tx_venc_port: port@0 { ++ reg = <0>; ++ ++ hdmi_tx_in: endpoint { ++ remote-endpoint = <&hdmi_tx_out>; ++ }; ++ }; ++ ++ /* TMDS Output */ ++ hdmi_tx_tmds_port: port@1 { ++ reg = <1>; ++ }; ++ }; ++ ++ apb_efuse: bus@30000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x30000 0x0 0x2000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x30000 0x0 0x2000>; ++ ++ hwrng: rng@218 { ++ compatible = "amlogic,meson-rng"; ++ reg = <0x0 0x218 0x0 0x4>; ++ }; ++ }; ++ ++ periphs: bus@34400 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x34400 0x0 0x400>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x34400 0x0 0x400>; ++ ++ periphs_pinctrl: pinctrl@40 { ++ compatible = "amlogic,meson-g12a-periphs-pinctrl"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gpio: bank@40 { ++ reg = <0x0 0x40 0x0 0x4c>, ++ <0x0 0xe8 0x0 0x18>, ++ <0x0 0x120 0x0 0x18>, ++ <0x0 0x2c0 0x0 0x40>, ++ <0x0 0x340 0x0 0x1c>; ++ reg-names = "gpio", ++ "pull", ++ "pull-enable", ++ "mux", ++ "ds"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&periphs_pinctrl 0 0 86>; ++ }; ++ ++ cec_ao_a_h_pins: cec_ao_a_h { ++ mux { ++ groups = "cec_ao_a_h"; ++ function = "cec_ao_a_h"; ++ bias-disable; ++ }; ++ }; ++ ++ cec_ao_b_h_pins: cec_ao_b_h { ++ mux { ++ groups = "cec_ao_b_h"; ++ function = "cec_ao_b_h"; ++ bias-disable; ++ }; ++ }; ++ ++ emmc_pins: emmc { ++ mux-0 { ++ groups = "emmc_nand_d0", ++ "emmc_nand_d1", ++ "emmc_nand_d2", ++ "emmc_nand_d3", ++ "emmc_nand_d4", ++ "emmc_nand_d5", ++ "emmc_nand_d6", ++ "emmc_nand_d7", ++ "emmc_cmd"; ++ function = "emmc"; ++ bias-pull-up; ++ drive-strength-microamp = <4000>; ++ }; ++ ++ mux-1 { ++ groups = "emmc_clk"; ++ function = "emmc"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ emmc_ds_pins: emmc-ds { ++ mux { ++ groups = "emmc_nand_ds"; ++ function = "emmc"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ emmc_clk_gate_pins: emmc_clk_gate { ++ mux { ++ groups = "BOOT_8"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ hdmitx_ddc_pins: hdmitx_ddc { ++ mux { ++ groups = "hdmitx_sda", ++ "hdmitx_sck"; ++ function = "hdmitx"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ hdmitx_hpd_pins: hdmitx_hpd { ++ mux { ++ groups = "hdmitx_hpd_in"; ++ function = "hdmitx"; ++ bias-disable; ++ }; ++ }; ++ ++ ++ i2c0_sda_c_pins: i2c0-sda-c { ++ mux { ++ groups = "i2c0_sda_c"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ ++ }; ++ }; ++ ++ i2c0_sck_c_pins: i2c0-sck-c { ++ mux { ++ groups = "i2c0_sck_c"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sda_z0_pins: i2c0-sda-z0 { ++ mux { ++ groups = "i2c0_sda_z0"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sck_z1_pins: i2c0-sck-z1 { ++ mux { ++ groups = "i2c0_sck_z1"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sda_z7_pins: i2c0-sda-z7 { ++ mux { ++ groups = "i2c0_sda_z7"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sda_z8_pins: i2c0-sda-z8 { ++ mux { ++ groups = "i2c0_sda_z8"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sda_x_pins: i2c1-sda-x { ++ mux { ++ groups = "i2c1_sda_x"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sck_x_pins: i2c1-sck-x { ++ mux { ++ groups = "i2c1_sck_x"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sda_h2_pins: i2c1-sda-h2 { ++ mux { ++ groups = "i2c1_sda_h2"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sck_h3_pins: i2c1-sck-h3 { ++ mux { ++ groups = "i2c1_sck_h3"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sda_h6_pins: i2c1-sda-h6 { ++ mux { ++ groups = "i2c1_sda_h6"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sck_h7_pins: i2c1-sck-h7 { ++ mux { ++ groups = "i2c1_sck_h7"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sda_x_pins: i2c2-sda-x { ++ mux { ++ groups = "i2c2_sda_x"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sck_x_pins: i2c2-sck-x { ++ mux { ++ groups = "i2c2_sck_x"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sda_z_pins: i2c2-sda-z { ++ mux { ++ groups = "i2c2_sda_z"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sck_z_pins: i2c2-sck-z { ++ mux { ++ groups = "i2c2_sck_z"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sda_h_pins: i2c3-sda-h { ++ mux { ++ groups = "i2c3_sda_h"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sck_h_pins: i2c3-sck-h { ++ mux { ++ groups = "i2c3_sck_h"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sda_a_pins: i2c3-sda-a { ++ mux { ++ groups = "i2c3_sda_a"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sck_a_pins: i2c3-sck-a { ++ mux { ++ groups = "i2c3_sck_a"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk0_a_pins: mclk0-a { ++ mux { ++ groups = "mclk0_a"; ++ function = "mclk0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk1_a_pins: mclk1-a { ++ mux { ++ groups = "mclk1_a"; ++ function = "mclk1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk1_x_pins: mclk1-x { ++ mux { ++ groups = "mclk1_x"; ++ function = "mclk1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk1_z_pins: mclk1-z { ++ mux { ++ groups = "mclk1_z"; ++ function = "mclk1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ pdm_din0_a_pins: pdm-din0-a { ++ mux { ++ groups = "pdm_din0_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din0_c_pins: pdm-din0-c { ++ mux { ++ groups = "pdm_din0_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din0_x_pins: pdm-din0-x { ++ mux { ++ groups = "pdm_din0_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din0_z_pins: pdm-din0-z { ++ mux { ++ groups = "pdm_din0_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_a_pins: pdm-din1-a { ++ mux { ++ groups = "pdm_din1_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_c_pins: pdm-din1-c { ++ mux { ++ groups = "pdm_din1_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_x_pins: pdm-din1-x { ++ mux { ++ groups = "pdm_din1_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_z_pins: pdm-din1-z { ++ mux { ++ groups = "pdm_din1_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_a_pins: pdm-din2-a { ++ mux { ++ groups = "pdm_din2_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_c_pins: pdm-din2-c { ++ mux { ++ groups = "pdm_din2_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_x_pins: pdm-din2-x { ++ mux { ++ groups = "pdm_din2_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_z_pins: pdm-din2-z { ++ mux { ++ groups = "pdm_din2_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_a_pins: pdm-din3-a { ++ mux { ++ groups = "pdm_din3_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_c_pins: pdm-din3-c { ++ mux { ++ groups = "pdm_din3_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_x_pins: pdm-din3-x { ++ mux { ++ groups = "pdm_din3_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_z_pins: pdm-din3-z { ++ mux { ++ groups = "pdm_din3_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_dclk_a_pins: pdm-dclk-a { ++ mux { ++ groups = "pdm_dclk_a"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ ++ pdm_dclk_c_pins: pdm-dclk-c { ++ mux { ++ groups = "pdm_dclk_c"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ ++ pdm_dclk_x_pins: pdm-dclk-x { ++ mux { ++ groups = "pdm_dclk_x"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ ++ pdm_dclk_z_pins: pdm-dclk-z { ++ mux { ++ groups = "pdm_dclk_z"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ ++ pwm_a_pins: pwm-a { ++ mux { ++ groups = "pwm_a"; ++ function = "pwm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_b_x7_pins: pwm-b-x7 { ++ mux { ++ groups = "pwm_b_x7"; ++ function = "pwm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_b_x19_pins: pwm-b-x19 { ++ mux { ++ groups = "pwm_b_x19"; ++ function = "pwm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_c_c_pins: pwm-c-c { ++ mux { ++ groups = "pwm_c_c"; ++ function = "pwm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_c_x5_pins: pwm-c-x5 { ++ mux { ++ groups = "pwm_c_x5"; ++ function = "pwm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_c_x8_pins: pwm-c-x8 { ++ mux { ++ groups = "pwm_c_x8"; ++ function = "pwm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_d_x3_pins: pwm-d-x3 { ++ mux { ++ groups = "pwm_d_x3"; ++ function = "pwm_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_d_x6_pins: pwm-d-x6 { ++ mux { ++ groups = "pwm_d_x6"; ++ function = "pwm_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_e_pins: pwm-e { ++ mux { ++ groups = "pwm_e"; ++ function = "pwm_e"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_f_x_pins: pwm-f-x { ++ mux { ++ groups = "pwm_f_x"; ++ function = "pwm_f"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_f_h_pins: pwm-f-h { ++ mux { ++ groups = "pwm_f_h"; ++ function = "pwm_f"; ++ bias-disable; ++ }; ++ }; ++ ++ sdcard_c_pins: sdcard_c { ++ mux-0 { ++ groups = "sdcard_d0_c", ++ "sdcard_d1_c", ++ "sdcard_d2_c", ++ "sdcard_d3_c", ++ "sdcard_cmd_c"; ++ function = "sdcard"; ++ bias-pull-up; ++ drive-strength-microamp = <4000>; ++ }; ++ ++ mux-1 { ++ groups = "sdcard_clk_c"; ++ function = "sdcard"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdcard_clk_gate_c_pins: sdcard_clk_gate_c { ++ mux { ++ groups = "GPIOC_4"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdcard_z_pins: sdcard_z { ++ mux-0 { ++ groups = "sdcard_d0_z", ++ "sdcard_d1_z", ++ "sdcard_d2_z", ++ "sdcard_d3_z", ++ "sdcard_cmd_z"; ++ function = "sdcard"; ++ bias-pull-up; ++ drive-strength-microamp = <4000>; ++ }; ++ ++ mux-1 { ++ groups = "sdcard_clk_z"; ++ function = "sdcard"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdcard_clk_gate_z_pins: sdcard_clk_gate_z { ++ mux { ++ groups = "GPIOZ_6"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdio_pins: sdio { ++ mux { ++ groups = "sdio_d0", ++ "sdio_d1", ++ "sdio_d2", ++ "sdio_d3", ++ "sdio_clk", ++ "sdio_cmd"; ++ function = "sdio"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdio_clk_gate_pins: sdio_clk_gate { ++ mux { ++ groups = "GPIOX_4"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ spdif_in_a10_pins: spdif-in-a10 { ++ mux { ++ groups = "spdif_in_a10"; ++ function = "spdif_in"; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_in_a12_pins: spdif-in-a12 { ++ mux { ++ groups = "spdif_in_a12"; ++ function = "spdif_in"; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_in_h_pins: spdif-in-h { ++ mux { ++ groups = "spdif_in_h"; ++ function = "spdif_in"; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_out_h_pins: spdif-out-h { ++ mux { ++ groups = "spdif_out_h"; ++ function = "spdif_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_out_a11_pins: spdif-out-a11 { ++ mux { ++ groups = "spdif_out_a11"; ++ function = "spdif_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_out_a13_pins: spdif-out-a13 { ++ mux { ++ groups = "spdif_out_a13"; ++ function = "spdif_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_a_din0_pins: tdm-a-din0 { ++ mux { ++ groups = "tdm_a_din0"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ ++ tdm_a_din1_pins: tdm-a-din1 { ++ mux { ++ groups = "tdm_a_din1"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_a_dout0_pins: tdm-a-dout0 { ++ mux { ++ groups = "tdm_a_dout0"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_dout1_pins: tdm-a-dout1 { ++ mux { ++ groups = "tdm_a_dout1"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_fs_pins: tdm-a-fs { ++ mux { ++ groups = "tdm_a_fs"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_sclk_pins: tdm-a-sclk { ++ mux { ++ groups = "tdm_a_sclk"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_slv_fs_pins: tdm-a-slv-fs { ++ mux { ++ groups = "tdm_a_slv_fs"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ ++ tdm_a_slv_sclk_pins: tdm-a-slv-sclk { ++ mux { ++ groups = "tdm_a_slv_sclk"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din0_pins: tdm-b-din0 { ++ mux { ++ groups = "tdm_b_din0"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din1_pins: tdm-b-din1 { ++ mux { ++ groups = "tdm_b_din1"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din2_pins: tdm-b-din2 { ++ mux { ++ groups = "tdm_b_din2"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din3_a_pins: tdm-b-din3-a { ++ mux { ++ groups = "tdm_b_din3_a"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din3_h_pins: tdm-b-din3-h { ++ mux { ++ groups = "tdm_b_din3_h"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_dout0_pins: tdm-b-dout0 { ++ mux { ++ groups = "tdm_b_dout0"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout1_pins: tdm-b-dout1 { ++ mux { ++ groups = "tdm_b_dout1"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout2_pins: tdm-b-dout2 { ++ mux { ++ groups = "tdm_b_dout2"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout3_a_pins: tdm-b-dout3-a { ++ mux { ++ groups = "tdm_b_dout3_a"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout3_h_pins: tdm-b-dout3-h { ++ mux { ++ groups = "tdm_b_dout3_h"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_fs_pins: tdm-b-fs { ++ mux { ++ groups = "tdm_b_fs"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_sclk_pins: tdm-b-sclk { ++ mux { ++ groups = "tdm_b_sclk"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_slv_fs_pins: tdm-b-slv-fs { ++ mux { ++ groups = "tdm_b_slv_fs"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_slv_sclk_pins: tdm-b-slv-sclk { ++ mux { ++ groups = "tdm_b_slv_sclk"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din0_a_pins: tdm-c-din0-a { ++ mux { ++ groups = "tdm_c_din0_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din0_z_pins: tdm-c-din0-z { ++ mux { ++ groups = "tdm_c_din0_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din1_a_pins: tdm-c-din1-a { ++ mux { ++ groups = "tdm_c_din1_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din1_z_pins: tdm-c-din1-z { ++ mux { ++ groups = "tdm_c_din1_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din2_a_pins: tdm-c-din2-a { ++ mux { ++ groups = "tdm_c_din2_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ eth_leds_pins: eth-leds { ++ mux { ++ groups = "eth_link_led", ++ "eth_act_led"; ++ function = "eth"; ++ bias-disable; ++ }; ++ }; ++ ++ eth_pins: eth { ++ mux { ++ groups = "eth_mdio", ++ "eth_mdc", ++ "eth_rgmii_rx_clk", ++ "eth_rx_dv", ++ "eth_rxd0", ++ "eth_rxd1", ++ "eth_txen", ++ "eth_txd0", ++ "eth_txd1"; ++ function = "eth"; ++ drive-strength-microamp = <4000>; ++ bias-disable; ++ }; ++ }; ++ ++ eth_rgmii_pins: eth-rgmii { ++ mux { ++ groups = "eth_rxd2_rgmii", ++ "eth_rxd3_rgmii", ++ "eth_rgmii_tx_clk", ++ "eth_txd2_rgmii", ++ "eth_txd3_rgmii"; ++ function = "eth"; ++ drive-strength-microamp = <4000>; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din2_z_pins: tdm-c-din2-z { ++ mux { ++ groups = "tdm_c_din2_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din3_a_pins: tdm-c-din3-a { ++ mux { ++ groups = "tdm_c_din3_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din3_z_pins: tdm-c-din3-z { ++ mux { ++ groups = "tdm_c_din3_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_dout0_a_pins: tdm-c-dout0-a { ++ mux { ++ groups = "tdm_c_dout0_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout0_z_pins: tdm-c-dout0-z { ++ mux { ++ groups = "tdm_c_dout0_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout1_a_pins: tdm-c-dout1-a { ++ mux { ++ groups = "tdm_c_dout1_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout1_z_pins: tdm-c-dout1-z { ++ mux { ++ groups = "tdm_c_dout1_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout2_a_pins: tdm-c-dout2-a { ++ mux { ++ groups = "tdm_c_dout2_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout2_z_pins: tdm-c-dout2-z { ++ mux { ++ groups = "tdm_c_dout2_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout3_a_pins: tdm-c-dout3-a { ++ mux { ++ groups = "tdm_c_dout3_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout3_z_pins: tdm-c-dout3-z { ++ mux { ++ groups = "tdm_c_dout3_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_fs_a_pins: tdm-c-fs-a { ++ mux { ++ groups = "tdm_c_fs_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_fs_z_pins: tdm-c-fs-z { ++ mux { ++ groups = "tdm_c_fs_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_sclk_a_pins: tdm-c-sclk-a { ++ mux { ++ groups = "tdm_c_sclk_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_sclk_z_pins: tdm-c-sclk-z { ++ mux { ++ groups = "tdm_c_sclk_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_slv_fs_a_pins: tdm-c-slv-fs-a { ++ mux { ++ groups = "tdm_c_slv_fs_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_slv_fs_z_pins: tdm-c-slv-fs-z { ++ mux { ++ groups = "tdm_c_slv_fs_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_slv_sclk_a_pins: tdm-c-slv-sclk-a { ++ mux { ++ groups = "tdm_c_slv_sclk_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_slv_sclk_z_pins: tdm-c-slv-sclk-z { ++ mux { ++ groups = "tdm_c_slv_sclk_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_a_pins: uart-a { ++ mux { ++ groups = "uart_a_tx", ++ "uart_a_rx"; ++ function = "uart_a"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_a_cts_rts_pins: uart-a-cts-rts { ++ mux { ++ groups = "uart_a_cts", ++ "uart_a_rts"; ++ function = "uart_a"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_b_pins: uart-b { ++ mux { ++ groups = "uart_b_tx", ++ "uart_b_rx"; ++ function = "uart_b"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_c_pins: uart-c { ++ mux { ++ groups = "uart_c_tx", ++ "uart_c_rx"; ++ function = "uart_c"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_c_cts_rts_pins: uart-c-cts-rts { ++ mux { ++ groups = "uart_c_cts", ++ "uart_c_rts"; ++ function = "uart_c"; ++ bias-disable; ++ }; ++ }; ++ }; ++ }; ++ ++ usb2_phy0: phy@36000 { ++ compatible = "amlogic,g12a-usb2-phy"; ++ reg = <0x0 0x36000 0x0 0x2000>; ++ clocks = <&xtal>; ++ clock-names = "xtal"; ++ resets = <&reset RESET_USB_PHY20>; ++ reset-names = "phy"; ++ #phy-cells = <0>; ++ }; ++ ++ dmc: bus@38000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x38000 0x0 0x400>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>; ++ ++ canvas: video-lut@48 { ++ compatible = "amlogic,canvas"; ++ reg = <0x0 0x48 0x0 0x14>; ++ }; ++ }; ++ ++ usb2_phy1: phy@3a000 { ++ compatible = "amlogic,g12a-usb2-phy"; ++ reg = <0x0 0x3a000 0x0 0x2000>; ++ clocks = <&xtal>; ++ clock-names = "xtal"; ++ resets = <&reset RESET_USB_PHY21>; ++ reset-names = "phy"; ++ #phy-cells = <0>; ++ }; ++ ++ hiu: bus@3c000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x3c000 0x0 0x1400>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x3c000 0x0 0x1400>; ++ ++ hhi: system-controller@0 { ++ compatible = "amlogic,meson-gx-hhi-sysctrl", ++ "simple-mfd", "syscon"; ++ reg = <0 0 0 0x400>; ++ ++ clkc: clock-controller { ++ compatible = "amlogic,g12a-clkc"; ++ #clock-cells = <1>; ++ clocks = <&xtal>; ++ clock-names = "xtal"; ++ }; ++ }; ++ }; ++ ++ pdm: audio-controller@40000 { ++ compatible = "amlogic,g12a-pdm", ++ "amlogic,axg-pdm"; ++ reg = <0x0 0x40000 0x0 0x34>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "PDM"; ++ clocks = <&clkc_audio AUD_CLKID_PDM>, ++ <&clkc_audio AUD_CLKID_PDM_DCLK>, ++ <&clkc_audio AUD_CLKID_PDM_SYSCLK>; ++ clock-names = "pclk", "dclk", "sysclk"; ++ status = "disabled"; ++ }; ++ ++ audio: bus@42000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x42000 0x0 0x2000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>; ++ ++ clkc_audio: clock-controller@0 { ++ status = "disabled"; ++ compatible = "amlogic,g12a-audio-clkc"; ++ reg = <0x0 0x0 0x0 0xb4>; ++ #clock-cells = <1>; ++ ++ clocks = <&clkc CLKID_AUDIO>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>, ++ <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL3>, ++ <&clkc CLKID_HIFI_PLL>, ++ <&clkc CLKID_FCLK_DIV3>, ++ <&clkc CLKID_FCLK_DIV4>, ++ <&clkc CLKID_GP0_PLL>; ++ clock-names = "pclk", ++ "mst_in0", ++ "mst_in1", ++ "mst_in2", ++ "mst_in3", ++ "mst_in4", ++ "mst_in5", ++ "mst_in6", ++ "mst_in7"; ++ ++ resets = <&reset RESET_AUDIO>; ++ }; ++ ++ toddr_a: audio-controller@100 { ++ compatible = "amlogic,g12a-toddr", ++ "amlogic,axg-toddr"; ++ reg = <0x0 0x100 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TODDR_A"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_TODDR_A>; ++ resets = <&arb AXG_ARB_TODDR_A>; ++ status = "disabled"; ++ }; ++ ++ toddr_b: audio-controller@140 { ++ compatible = "amlogic,g12a-toddr", ++ "amlogic,axg-toddr"; ++ reg = <0x0 0x140 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TODDR_B"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_TODDR_B>; ++ resets = <&arb AXG_ARB_TODDR_B>; ++ status = "disabled"; ++ }; ++ ++ toddr_c: audio-controller@180 { ++ compatible = "amlogic,g12a-toddr", ++ "amlogic,axg-toddr"; ++ reg = <0x0 0x180 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TODDR_C"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_TODDR_C>; ++ resets = <&arb AXG_ARB_TODDR_C>; ++ status = "disabled"; ++ }; ++ ++ frddr_a: audio-controller@1c0 { ++ compatible = "amlogic,g12a-frddr", ++ "amlogic,axg-frddr"; ++ reg = <0x0 0x1c0 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "FRDDR_A"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; ++ resets = <&arb AXG_ARB_FRDDR_A>; ++ status = "disabled"; ++ }; ++ ++ frddr_b: audio-controller@200 { ++ compatible = "amlogic,g12a-frddr", ++ "amlogic,axg-frddr"; ++ reg = <0x0 0x200 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "FRDDR_B"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_FRDDR_B>; ++ resets = <&arb AXG_ARB_FRDDR_B>; ++ status = "disabled"; ++ }; ++ ++ frddr_c: audio-controller@240 { ++ compatible = "amlogic,g12a-frddr", ++ "amlogic,axg-frddr"; ++ reg = <0x0 0x240 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "FRDDR_C"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_FRDDR_C>; ++ resets = <&arb AXG_ARB_FRDDR_C>; ++ status = "disabled"; ++ }; ++ ++ arb: reset-controller@280 { ++ status = "disabled"; ++ compatible = "amlogic,meson-axg-audio-arb"; ++ reg = <0x0 0x280 0x0 0x4>; ++ #reset-cells = <1>; ++ clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; ++ }; ++ ++ tdmin_a: audio-controller@300 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x300 0x0 0x40>; ++ sound-name-prefix = "TDMIN_A"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_A>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmin_b: audio-controller@340 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x340 0x0 0x40>; ++ sound-name-prefix = "TDMIN_B"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_B>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmin_c: audio-controller@380 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x380 0x0 0x40>; ++ sound-name-prefix = "TDMIN_C"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_C>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmin_lb: audio-controller@3c0 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x3c0 0x0 0x40>; ++ sound-name-prefix = "TDMIN_LB"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ spdifin: audio-controller@400 { ++ compatible = "amlogic,g12a-spdifin", ++ "amlogic,axg-spdifin"; ++ reg = <0x0 0x400 0x0 0x30>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "SPDIFIN"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_SPDIFIN>, ++ <&clkc_audio AUD_CLKID_SPDIFIN_CLK>; ++ clock-names = "pclk", "refclk"; ++ status = "disabled"; ++ }; ++ ++ spdifout: audio-controller@480 { ++ compatible = "amlogic,g12a-spdifout", ++ "amlogic,axg-spdifout"; ++ reg = <0x0 0x480 0x0 0x50>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "SPDIFOUT"; ++ clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>, ++ <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>; ++ clock-names = "pclk", "mclk"; ++ status = "disabled"; ++ }; ++ ++ tdmout_a: audio-controller@500 { ++ compatible = "amlogic,g12a-tdmout"; ++ reg = <0x0 0x500 0x0 0x40>; ++ sound-name-prefix = "TDMOUT_A"; ++ clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmout_b: audio-controller@540 { ++ compatible = "amlogic,g12a-tdmout"; ++ reg = <0x0 0x540 0x0 0x40>; ++ sound-name-prefix = "TDMOUT_B"; ++ clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmout_c: audio-controller@580 { ++ compatible = "amlogic,g12a-tdmout"; ++ reg = <0x0 0x580 0x0 0x40>; ++ sound-name-prefix = "TDMOUT_C"; ++ clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ spdifout_b: audio-controller@680 { ++ compatible = "amlogic,g12a-spdifout", ++ "amlogic,axg-spdifout"; ++ reg = <0x0 0x680 0x0 0x50>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "SPDIFOUT_B"; ++ clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>, ++ <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>; ++ clock-names = "pclk", "mclk"; ++ status = "disabled"; ++ }; ++ ++ tohdmitx: audio-controller@744 { ++ compatible = "amlogic,g12a-tohdmitx"; ++ reg = <0x0 0x744 0x0 0x4>; ++ #sound-dai-cells = <1>; ++ sound-name-prefix = "TOHDMITX"; ++ status = "disabled"; ++ }; ++ }; ++ ++ usb3_pcie_phy: phy@46000 { ++ compatible = "amlogic,g12a-usb3-pcie-phy"; ++ reg = <0x0 0x46000 0x0 0x2000>; ++ clocks = <&clkc CLKID_PCIE_PLL>; ++ clock-names = "ref_clk"; ++ resets = <&reset RESET_PCIE_PHY>; ++ reset-names = "phy"; ++ assigned-clocks = <&clkc CLKID_PCIE_PLL>; ++ assigned-clock-rates = <100000000>; ++ #phy-cells = <1>; ++ }; ++ ++ eth_phy: mdio-multiplexer@4c000 { ++ compatible = "amlogic,g12a-mdio-mux"; ++ reg = <0x0 0x4c000 0x0 0xa4>; ++ clocks = <&clkc CLKID_ETH_PHY>, ++ <&xtal>, ++ <&clkc CLKID_MPLL_50M>; ++ clock-names = "pclk", "clkin0", "clkin1"; ++ mdio-parent-bus = <&mdio0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ext_mdio: mdio@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ int_mdio: mdio@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ internal_ephy: ethernet_phy@8 { ++ compatible = "ethernet-phy-id0180.3301", ++ "ethernet-phy-ieee802.3-c22"; ++ interrupts = ; ++ reg = <8>; ++ max-speed = <100>; ++ }; ++ }; ++ }; ++ }; ++ ++ aobus: bus@ff800000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0xff800000 0x0 0x100000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; ++ ++ rti: sys-ctrl@0 { ++ compatible = "amlogic,meson-gx-ao-sysctrl", ++ "simple-mfd", "syscon"; ++ reg = <0x0 0x0 0x0 0x100>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x0 0x0 0x100>; ++ ++ clkc_AO: clock-controller { ++ compatible = "amlogic,meson-g12a-aoclkc"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ clocks = <&xtal>, <&clkc CLKID_CLK81>; ++ clock-names = "xtal", "mpeg-clk"; ++ }; ++ ++ pwrc_vpu: power-controller-vpu { ++ compatible = "amlogic,meson-g12a-pwrc-vpu"; ++ #power-domain-cells = <0>; ++ amlogic,hhi-sysctrl = <&hhi>; ++ resets = <&reset RESET_VIU>, ++ <&reset RESET_VENC>, ++ <&reset RESET_VCBUS>, ++ <&reset RESET_BT656>, ++ <&reset RESET_RDMA>, ++ <&reset RESET_VENCI>, ++ <&reset RESET_VENCP>, ++ <&reset RESET_VDAC>, ++ <&reset RESET_VDI6>, ++ <&reset RESET_VENCL>, ++ <&reset RESET_VID_LOCK>; ++ clocks = <&clkc CLKID_VPU>, ++ <&clkc CLKID_VAPB>; ++ clock-names = "vpu", "vapb"; ++ /* ++ * VPU clocking is provided by two identical clock paths ++ * VPU_0 and VPU_1 muxed to a single clock by a glitch ++ * free mux to safely change frequency while running. ++ * Same for VAPB but with a final gate after the glitch free mux. ++ */ ++ assigned-clocks = <&clkc CLKID_VPU_0_SEL>, ++ <&clkc CLKID_VPU_0>, ++ <&clkc CLKID_VPU>, /* Glitch free mux */ ++ <&clkc CLKID_VAPB_0_SEL>, ++ <&clkc CLKID_VAPB_0>, ++ <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ ++ assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, ++ <0>, /* Do Nothing */ ++ <&clkc CLKID_VPU_0>, ++ <&clkc CLKID_FCLK_DIV4>, ++ <0>, /* Do Nothing */ ++ <&clkc CLKID_VAPB_0>; ++ assigned-clock-rates = <0>, /* Do Nothing */ ++ <666666666>, ++ <0>, /* Do Nothing */ ++ <0>, /* Do Nothing */ ++ <250000000>, ++ <0>; /* Do Nothing */ ++ }; ++ ++ ao_pinctrl: pinctrl@14 { ++ compatible = "amlogic,meson-g12a-aobus-pinctrl"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gpio_ao: bank@14 { ++ reg = <0x0 0x14 0x0 0x8>, ++ <0x0 0x1c 0x0 0x8>, ++ <0x0 0x24 0x0 0x14>; ++ reg-names = "mux", ++ "ds", ++ "gpio"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&ao_pinctrl 0 0 15>; ++ }; ++ ++ i2c_ao_sck_pins: i2c_ao_sck_pins { ++ mux { ++ groups = "i2c_ao_sck"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c_ao_sda_pins: i2c_ao_sda { ++ mux { ++ groups = "i2c_ao_sda"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c_ao_sck_e_pins: i2c_ao_sck_e { ++ mux { ++ groups = "i2c_ao_sck_e"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c_ao_sda_e_pins: i2c_ao_sda_e { ++ mux { ++ groups = "i2c_ao_sda_e"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk0_ao_pins: mclk0-ao { ++ mux { ++ groups = "mclk0_ao"; ++ function = "mclk0_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_din0_pins: tdm-ao-b-din0 { ++ mux { ++ groups = "tdm_ao_b_din0"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_ao_out_pins: spdif-ao-out { ++ mux { ++ groups = "spdif_ao_out"; ++ function = "spdif_ao_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_din1_pins: tdm-ao-b-din1 { ++ mux { ++ groups = "tdm_ao_b_din1"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_din2_pins: tdm-ao-b-din2 { ++ mux { ++ groups = "tdm_ao_b_din2"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_dout0_pins: tdm-ao-b-dout0 { ++ mux { ++ groups = "tdm_ao_b_dout0"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_dout1_pins: tdm-ao-b-dout1 { ++ mux { ++ groups = "tdm_ao_b_dout1"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_dout2_pins: tdm-ao-b-dout2 { ++ mux { ++ groups = "tdm_ao_b_dout2"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_fs_pins: tdm-ao-b-fs { ++ mux { ++ groups = "tdm_ao_b_fs"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_sclk_pins: tdm-ao-b-sclk { ++ mux { ++ groups = "tdm_ao_b_sclk"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_slv_fs_pins: tdm-ao-b-slv-fs { ++ mux { ++ groups = "tdm_ao_b_slv_fs"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_slv_sclk_pins: tdm-ao-b-slv-sclk { ++ mux { ++ groups = "tdm_ao_b_slv_sclk"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_ao_a_pins: uart-a-ao { ++ mux { ++ groups = "uart_ao_a_tx", ++ "uart_ao_a_rx"; ++ function = "uart_ao_a"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts { ++ mux { ++ groups = "uart_ao_a_cts", ++ "uart_ao_a_rts"; ++ function = "uart_ao_a"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_a_pins: pwm-ao-a { ++ mux { ++ groups = "pwm_ao_a"; ++ function = "pwm_ao_a"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_b_pins: pwm-ao-b { ++ mux { ++ groups = "pwm_ao_b"; ++ function = "pwm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_c_4_pins: pwm-ao-c-4 { ++ mux { ++ groups = "pwm_ao_c_4"; ++ function = "pwm_ao_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_c_6_pins: pwm-ao-c-6 { ++ mux { ++ groups = "pwm_ao_c_6"; ++ function = "pwm_ao_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_d_5_pins: pwm-ao-d-5 { ++ mux { ++ groups = "pwm_ao_d_5"; ++ function = "pwm_ao_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_d_10_pins: pwm-ao-d-10 { ++ mux { ++ groups = "pwm_ao_d_10"; ++ function = "pwm_ao_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_d_e_pins: pwm-ao-d-e { ++ mux { ++ groups = "pwm_ao_d_e"; ++ function = "pwm_ao_d"; ++ }; ++ }; ++ ++ remote_input_ao_pins: remote-input-ao { ++ mux { ++ groups = "remote_ao_input"; ++ function = "remote_ao_input"; ++ bias-disable; ++ }; ++ }; ++ }; ++ }; ++ ++ cec_AO: cec@100 { ++ compatible = "amlogic,meson-gx-ao-cec"; ++ reg = <0x0 0x00100 0x0 0x14>; ++ interrupts = ; ++ clocks = <&clkc_AO CLKID_AO_CEC>; ++ clock-names = "core"; ++ status = "disabled"; ++ }; ++ ++ sec_AO: ao-secure@140 { ++ compatible = "amlogic,meson-gx-ao-secure", "syscon"; ++ reg = <0x0 0x140 0x0 0x140>; ++ amlogic,has-chip-id; ++ }; ++ ++ cecb_AO: cec@280 { ++ compatible = "amlogic,meson-g12a-ao-cec"; ++ reg = <0x0 0x00280 0x0 0x1c>; ++ interrupts = ; ++ clocks = <&clkc_AO CLKID_AO_CTS_OSCIN>; ++ clock-names = "oscin"; ++ status = "disabled"; ++ }; ++ ++ pwm_AO_cd: pwm@2000 { ++ compatible = "amlogic,meson-g12a-ao-pwm-cd"; ++ reg = <0x0 0x2000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ uart_AO: serial@3000 { ++ compatible = "amlogic,meson-gx-uart", ++ "amlogic,meson-ao-uart"; ++ reg = <0x0 0x3000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; ++ ++ uart_AO_B: serial@4000 { ++ compatible = "amlogic,meson-gx-uart", ++ "amlogic,meson-ao-uart"; ++ reg = <0x0 0x4000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; ++ ++ i2c_AO: i2c@5000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x05000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ pwm_AO_ab: pwm@7000 { ++ compatible = "amlogic,meson-g12a-ao-pwm-ab"; ++ reg = <0x0 0x7000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ ir: ir@8000 { ++ compatible = "amlogic,meson-gxbb-ir"; ++ reg = <0x0 0x8000 0x0 0x20>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ saradc: adc@9000 { ++ compatible = "amlogic,meson-g12a-saradc", ++ "amlogic,meson-saradc"; ++ reg = <0x0 0x9000 0x0 0x48>; ++ #io-channel-cells = <1>; ++ interrupts = ; ++ clocks = <&xtal>, ++ <&clkc_AO CLKID_AO_SAR_ADC>, ++ <&clkc_AO CLKID_AO_SAR_ADC_CLK>, ++ <&clkc_AO CLKID_AO_SAR_ADC_SEL>; ++ clock-names = "clkin", "core", "adc_clk", "adc_sel"; ++ status = "disabled"; ++ }; ++ }; ++ ++ vpu: vpu@ff900000 { ++ compatible = "amlogic,meson-g12a-vpu"; ++ reg = <0x0 0xff900000 0x0 0x100000>, ++ <0x0 0xff63c000 0x0 0x1000>; ++ reg-names = "vpu", "hhi"; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ amlogic,canvas = <&canvas>; ++ power-domains = <&pwrc_vpu>; ++ ++ /* CVBS VDAC output port */ ++ cvbs_vdac_port: port@0 { ++ reg = <0>; ++ }; ++ ++ /* HDMI-TX output port */ ++ hdmi_tx_port: port@1 { ++ reg = <1>; ++ ++ hdmi_tx_out: endpoint { ++ remote-endpoint = <&hdmi_tx_in>; ++ }; ++ }; ++ }; ++ ++ gic: interrupt-controller@ffc01000 { ++ compatible = "arm,gic-400"; ++ reg = <0x0 0xffc01000 0 0x1000>, ++ <0x0 0xffc02000 0 0x2000>, ++ <0x0 0xffc04000 0 0x2000>, ++ <0x0 0xffc06000 0 0x2000>; ++ interrupt-controller; ++ interrupts = ; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ }; ++ ++ cbus: bus@ffd00000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0xffd00000 0x0 0x100000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x100000>; ++ ++ reset: reset-controller@1004 { ++ compatible = "amlogic,meson-g12a-reset", ++ "amlogic,meson-axg-reset"; ++ reg = <0x0 0x1004 0x0 0x9c>; ++ #reset-cells = <1>; ++ }; ++ ++ gpio_intc: interrupt-controller@f080 { ++ compatible = "amlogic,meson-g12a-gpio-intc", ++ "amlogic,meson-gpio-intc"; ++ reg = <0x0 0xf080 0x0 0x10>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; ++ }; ++ ++ pwm_ef: pwm@19000 { ++ compatible = "amlogic,meson-g12a-ee-pwm"; ++ reg = <0x0 0x19000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pwm_cd: pwm@1a000 { ++ compatible = "amlogic,meson-g12a-ee-pwm"; ++ reg = <0x0 0x1a000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pwm_ab: pwm@1b000 { ++ compatible = "amlogic,meson-g12a-ee-pwm"; ++ reg = <0x0 0x1b000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@1c000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1c000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ i2c2: i2c@1d000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1d000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ i2c1: i2c@1e000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1e000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ i2c0: i2c@1f000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1f000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ clk_msr: clock-measure@18000 { ++ compatible = "amlogic,meson-g12a-clk-measure"; ++ reg = <0x0 0x18000 0x0 0x10>; ++ }; ++ ++ uart_C: serial@22000 { ++ compatible = "amlogic,meson-gx-uart"; ++ reg = <0x0 0x22000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; ++ ++ uart_B: serial@23000 { ++ compatible = "amlogic,meson-gx-uart"; ++ reg = <0x0 0x23000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; ++ ++ uart_A: serial@24000 { ++ compatible = "amlogic,meson-gx-uart"; ++ reg = <0x0 0x24000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; ++ }; ++ ++ sd_emmc_a: sd@ffe03000 { ++ compatible = "amlogic,meson-axg-mmc"; ++ reg = <0x0 0xffe03000 0x0 0x800>; ++ interrupts = ; ++ status = "disabled"; ++ clocks = <&clkc CLKID_SD_EMMC_A>, ++ <&clkc CLKID_SD_EMMC_A_CLK0>, ++ <&clkc CLKID_FCLK_DIV2>; ++ clock-names = "core", "clkin0", "clkin1"; ++ resets = <&reset RESET_SD_EMMC_A>; ++ }; ++ ++ sd_emmc_b: sd@ffe05000 { ++ compatible = "amlogic,meson-axg-mmc"; ++ reg = <0x0 0xffe05000 0x0 0x800>; ++ interrupts = ; ++ status = "disabled"; ++ clocks = <&clkc CLKID_SD_EMMC_B>, ++ <&clkc CLKID_SD_EMMC_B_CLK0>, ++ <&clkc CLKID_FCLK_DIV2>; ++ clock-names = "core", "clkin0", "clkin1"; ++ resets = <&reset RESET_SD_EMMC_B>; ++ }; ++ ++ sd_emmc_c: mmc@ffe07000 { ++ compatible = "amlogic,meson-axg-mmc"; ++ reg = <0x0 0xffe07000 0x0 0x800>; ++ interrupts = ; ++ status = "disabled"; ++ clocks = <&clkc CLKID_SD_EMMC_C>, ++ <&clkc CLKID_SD_EMMC_C_CLK0>, ++ <&clkc CLKID_FCLK_DIV2>; ++ clock-names = "core", "clkin0", "clkin1"; ++ resets = <&reset RESET_SD_EMMC_C>; ++ }; ++ ++ usb: usb@ffe09000 { ++ status = "disabled"; ++ compatible = "amlogic,meson-g12a-usb-ctrl"; ++ reg = <0x0 0xffe09000 0x0 0xa0>; ++ interrupts = ; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clocks = <&clkc CLKID_USB>; ++ resets = <&reset RESET_USB>; ++ ++ dr_mode = "otg"; ++ ++ phys = <&usb2_phy0>, <&usb2_phy1>, ++ <&usb3_pcie_phy PHY_TYPE_USB3>; ++ phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; ++ ++ dwc2: usb@ff400000 { ++ compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; ++ reg = <0x0 0xff400000 0x0 0x40000>; ++ interrupts = ; ++ clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; ++ clock-names = "ddr"; ++ phys = <&usb2_phy1>; ++ phy-names = "usb2-phy"; ++ dr_mode = "peripheral"; ++ g-rx-fifo-size = <192>; ++ g-np-tx-fifo-size = <128>; ++ g-tx-fifo-size = <128 128 16 16 16>; ++ }; ++ ++ dwc3: usb@ff500000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0xff500000 0x0 0x100000>; ++ interrupts = ; ++ dr_mode = "host"; ++ snps,dis_u2_susphy_quirk; ++ snps,quirk-frame-length-adjustment; ++ }; ++ }; ++ ++ mali: gpu@ffe40000 { ++ compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; ++ reg = <0x0 0xffe40000 0x0 0x40000>; ++ interrupt-parent = <&gic>; ++ interrupts = , ++ , ++ ; ++ interrupt-names = "gpu", "mmu", "job"; ++ clocks = <&clkc CLKID_MALI>; ++ resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; ++ ++ /* ++ * Mali clocking is provided by two identical clock paths ++ * MALI_0 and MALI_1 muxed to a single clock by a glitch ++ * free mux to safely change frequency while running. ++ */ ++ assigned-clocks = <&clkc CLKID_MALI_0_SEL>, ++ <&clkc CLKID_MALI_0>, ++ <&clkc CLKID_MALI>; /* Glitch free mux */ ++ assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>, ++ <0>, /* Do Nothing */ ++ <&clkc CLKID_MALI_0>; ++ assigned-clock-rates = <0>, /* Do Nothing */ ++ <800000000>, ++ <0>; /* Do Nothing */ ++ }; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ xtal: xtal-clk { ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ clock-output-names = "xtal"; ++ #clock-cells = <0>; ++ }; ++ ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 1785552d450c..ac15967bb7fa 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -3,56 +3,11 @@ + * Copyright (c) 2018 Amlogic, Inc. All rights reserved. + */ + +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include "meson-g12-common.dtsi" + + / { + compatible = "amlogic,g12a"; + +- interrupt-parent = <&gic>; +- #address-cells = <2>; +- #size-cells = <2>; +- +- tdmif_a: audio-controller-0 { +- compatible = "amlogic,axg-tdm-iface"; +- #sound-dai-cells = <0>; +- sound-name-prefix = "TDM_A"; +- clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>, +- <&clkc_audio AUD_CLKID_MST_A_SCLK>, +- <&clkc_audio AUD_CLKID_MST_A_LRCLK>; +- clock-names = "mclk", "sclk", "lrclk"; +- status = "disabled"; +- }; +- +- tdmif_b: audio-controller-1 { +- compatible = "amlogic,axg-tdm-iface"; +- #sound-dai-cells = <0>; +- sound-name-prefix = "TDM_B"; +- clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>, +- <&clkc_audio AUD_CLKID_MST_B_SCLK>, +- <&clkc_audio AUD_CLKID_MST_B_LRCLK>; +- clock-names = "mclk", "sclk", "lrclk"; +- status = "disabled"; +- }; +- +- tdmif_c: audio-controller-2 { +- compatible = "amlogic,axg-tdm-iface"; +- #sound-dai-cells = <0>; +- sound-name-prefix = "TDM_C"; +- clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>, +- <&clkc_audio AUD_CLKID_MST_C_SCLK>, +- <&clkc_audio AUD_CLKID_MST_C_LRCLK>; +- clock-names = "mclk", "sclk", "lrclk"; +- status = "disabled"; +- }; +- + cpus { + #address-cells = <0x2>; + #size-cells = <0x0>; +@@ -93,2361 +48,8 @@ + compatible = "cache"; + }; + }; ++}; + +- efuse: efuse { +- compatible = "amlogic,meson-gxbb-efuse"; +- clocks = <&clkc CLKID_EFUSE>; +- #address-cells = <1>; +- #size-cells = <1>; +- read-only; +- }; +- +- psci { +- compatible = "arm,psci-1.0"; +- method = "smc"; +- }; +- +- reserved-memory { +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; +- +- /* 3 MiB reserved for ARM Trusted Firmware (BL31) */ +- secmon_reserved: secmon@5000000 { +- reg = <0x0 0x05000000 0x0 0x300000>; +- no-map; +- }; +- +- linux,cma { +- compatible = "shared-dma-pool"; +- reusable; +- size = <0x0 0x10000000>; +- alignment = <0x0 0x400000>; +- linux,cma-default; +- }; +- }; +- +- sm: secure-monitor { +- compatible = "amlogic,meson-gxbb-sm"; +- }; +- +- soc { +- compatible = "simple-bus"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; +- +- ethmac: ethernet@ff3f0000 { +- compatible = "amlogic,meson-axg-dwmac", +- "snps,dwmac-3.70a", +- "snps,dwmac"; +- reg = <0x0 0xff3f0000 0x0 0x10000 +- 0x0 0xff634540 0x0 0x8>; +- interrupts = ; +- interrupt-names = "macirq"; +- clocks = <&clkc CLKID_ETH>, +- <&clkc CLKID_FCLK_DIV2>, +- <&clkc CLKID_MPLL2>; +- clock-names = "stmmaceth", "clkin0", "clkin1"; +- status = "disabled"; +- +- mdio0: mdio { +- #address-cells = <1>; +- #size-cells = <0>; +- compatible = "snps,dwmac-mdio"; +- }; +- }; +- +- apb: bus@ff600000 { +- compatible = "simple-bus"; +- reg = <0x0 0xff600000 0x0 0x200000>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0xff600000 0x0 0x200000>; +- +- hdmi_tx: hdmi-tx@0 { +- compatible = "amlogic,meson-g12a-dw-hdmi"; +- reg = <0x0 0x0 0x0 0x10000>; +- interrupts = ; +- resets = <&reset RESET_HDMITX_CAPB3>, +- <&reset RESET_HDMITX_PHY>, +- <&reset RESET_HDMITX>; +- reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; +- clocks = <&clkc CLKID_HDMI>, +- <&clkc CLKID_HTX_PCLK>, +- <&clkc CLKID_VPU_INTR>; +- clock-names = "isfr", "iahb", "venci"; +- #address-cells = <1>; +- #size-cells = <0>; +- #sound-dai-cells = <0>; +- status = "disabled"; +- +- /* VPU VENC Input */ +- hdmi_tx_venc_port: port@0 { +- reg = <0>; +- +- hdmi_tx_in: endpoint { +- remote-endpoint = <&hdmi_tx_out>; +- }; +- }; +- +- /* TMDS Output */ +- hdmi_tx_tmds_port: port@1 { +- reg = <1>; +- }; +- }; +- +- apb_efuse: bus@30000 { +- compatible = "simple-bus"; +- reg = <0x0 0x30000 0x0 0x2000>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0x30000 0x0 0x2000>; +- +- hwrng: rng@218 { +- compatible = "amlogic,meson-rng"; +- reg = <0x0 0x218 0x0 0x4>; +- }; +- }; +- +- periphs: bus@34400 { +- compatible = "simple-bus"; +- reg = <0x0 0x34400 0x0 0x400>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0x34400 0x0 0x400>; +- +- periphs_pinctrl: pinctrl@40 { +- compatible = "amlogic,meson-g12a-periphs-pinctrl"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; +- +- gpio: bank@40 { +- reg = <0x0 0x40 0x0 0x4c>, +- <0x0 0xe8 0x0 0x18>, +- <0x0 0x120 0x0 0x18>, +- <0x0 0x2c0 0x0 0x40>, +- <0x0 0x340 0x0 0x1c>; +- reg-names = "gpio", +- "pull", +- "pull-enable", +- "mux", +- "ds"; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-ranges = <&periphs_pinctrl 0 0 86>; +- }; +- +- cec_ao_a_h_pins: cec_ao_a_h { +- mux { +- groups = "cec_ao_a_h"; +- function = "cec_ao_a_h"; +- bias-disable; +- }; +- }; +- +- cec_ao_b_h_pins: cec_ao_b_h { +- mux { +- groups = "cec_ao_b_h"; +- function = "cec_ao_b_h"; +- bias-disable; +- }; +- }; +- +- emmc_pins: emmc { +- mux-0 { +- groups = "emmc_nand_d0", +- "emmc_nand_d1", +- "emmc_nand_d2", +- "emmc_nand_d3", +- "emmc_nand_d4", +- "emmc_nand_d5", +- "emmc_nand_d6", +- "emmc_nand_d7", +- "emmc_cmd"; +- function = "emmc"; +- bias-pull-up; +- drive-strength-microamp = <4000>; +- }; +- +- mux-1 { +- groups = "emmc_clk"; +- function = "emmc"; +- bias-disable; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- emmc_ds_pins: emmc-ds { +- mux { +- groups = "emmc_nand_ds"; +- function = "emmc"; +- bias-pull-down; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- emmc_clk_gate_pins: emmc_clk_gate { +- mux { +- groups = "BOOT_8"; +- function = "gpio_periphs"; +- bias-pull-down; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- hdmitx_ddc_pins: hdmitx_ddc { +- mux { +- groups = "hdmitx_sda", +- "hdmitx_sck"; +- function = "hdmitx"; +- bias-disable; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- hdmitx_hpd_pins: hdmitx_hpd { +- mux { +- groups = "hdmitx_hpd_in"; +- function = "hdmitx"; +- bias-disable; +- }; +- }; +- +- +- i2c0_sda_c_pins: i2c0-sda-c { +- mux { +- groups = "i2c0_sda_c"; +- function = "i2c0"; +- bias-disable; +- drive-strength-microamp = <3000>; +- +- }; +- }; +- +- i2c0_sck_c_pins: i2c0-sck-c { +- mux { +- groups = "i2c0_sck_c"; +- function = "i2c0"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c0_sda_z0_pins: i2c0-sda-z0 { +- mux { +- groups = "i2c0_sda_z0"; +- function = "i2c0"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c0_sck_z1_pins: i2c0-sck-z1 { +- mux { +- groups = "i2c0_sck_z1"; +- function = "i2c0"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c0_sda_z7_pins: i2c0-sda-z7 { +- mux { +- groups = "i2c0_sda_z7"; +- function = "i2c0"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c0_sda_z8_pins: i2c0-sda-z8 { +- mux { +- groups = "i2c0_sda_z8"; +- function = "i2c0"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c1_sda_x_pins: i2c1-sda-x { +- mux { +- groups = "i2c1_sda_x"; +- function = "i2c1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c1_sck_x_pins: i2c1-sck-x { +- mux { +- groups = "i2c1_sck_x"; +- function = "i2c1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c1_sda_h2_pins: i2c1-sda-h2 { +- mux { +- groups = "i2c1_sda_h2"; +- function = "i2c1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c1_sck_h3_pins: i2c1-sck-h3 { +- mux { +- groups = "i2c1_sck_h3"; +- function = "i2c1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c1_sda_h6_pins: i2c1-sda-h6 { +- mux { +- groups = "i2c1_sda_h6"; +- function = "i2c1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c1_sck_h7_pins: i2c1-sck-h7 { +- mux { +- groups = "i2c1_sck_h7"; +- function = "i2c1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c2_sda_x_pins: i2c2-sda-x { +- mux { +- groups = "i2c2_sda_x"; +- function = "i2c2"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c2_sck_x_pins: i2c2-sck-x { +- mux { +- groups = "i2c2_sck_x"; +- function = "i2c2"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c2_sda_z_pins: i2c2-sda-z { +- mux { +- groups = "i2c2_sda_z"; +- function = "i2c2"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c2_sck_z_pins: i2c2-sck-z { +- mux { +- groups = "i2c2_sck_z"; +- function = "i2c2"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c3_sda_h_pins: i2c3-sda-h { +- mux { +- groups = "i2c3_sda_h"; +- function = "i2c3"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c3_sck_h_pins: i2c3-sck-h { +- mux { +- groups = "i2c3_sck_h"; +- function = "i2c3"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c3_sda_a_pins: i2c3-sda-a { +- mux { +- groups = "i2c3_sda_a"; +- function = "i2c3"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c3_sck_a_pins: i2c3-sck-a { +- mux { +- groups = "i2c3_sck_a"; +- function = "i2c3"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- mclk0_a_pins: mclk0-a { +- mux { +- groups = "mclk0_a"; +- function = "mclk0"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- mclk1_a_pins: mclk1-a { +- mux { +- groups = "mclk1_a"; +- function = "mclk1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- mclk1_x_pins: mclk1-x { +- mux { +- groups = "mclk1_x"; +- function = "mclk1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- mclk1_z_pins: mclk1-z { +- mux { +- groups = "mclk1_z"; +- function = "mclk1"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- pdm_din0_a_pins: pdm-din0-a { +- mux { +- groups = "pdm_din0_a"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din0_c_pins: pdm-din0-c { +- mux { +- groups = "pdm_din0_c"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din0_x_pins: pdm-din0-x { +- mux { +- groups = "pdm_din0_x"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din0_z_pins: pdm-din0-z { +- mux { +- groups = "pdm_din0_z"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din1_a_pins: pdm-din1-a { +- mux { +- groups = "pdm_din1_a"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din1_c_pins: pdm-din1-c { +- mux { +- groups = "pdm_din1_c"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din1_x_pins: pdm-din1-x { +- mux { +- groups = "pdm_din1_x"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din1_z_pins: pdm-din1-z { +- mux { +- groups = "pdm_din1_z"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din2_a_pins: pdm-din2-a { +- mux { +- groups = "pdm_din2_a"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din2_c_pins: pdm-din2-c { +- mux { +- groups = "pdm_din2_c"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din2_x_pins: pdm-din2-x { +- mux { +- groups = "pdm_din2_x"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din2_z_pins: pdm-din2-z { +- mux { +- groups = "pdm_din2_z"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din3_a_pins: pdm-din3-a { +- mux { +- groups = "pdm_din3_a"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din3_c_pins: pdm-din3-c { +- mux { +- groups = "pdm_din3_c"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din3_x_pins: pdm-din3-x { +- mux { +- groups = "pdm_din3_x"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_din3_z_pins: pdm-din3-z { +- mux { +- groups = "pdm_din3_z"; +- function = "pdm"; +- bias-disable; +- }; +- }; +- +- pdm_dclk_a_pins: pdm-dclk-a { +- mux { +- groups = "pdm_dclk_a"; +- function = "pdm"; +- bias-disable; +- drive-strength-microamp = <500>; +- }; +- }; +- +- pdm_dclk_c_pins: pdm-dclk-c { +- mux { +- groups = "pdm_dclk_c"; +- function = "pdm"; +- bias-disable; +- drive-strength-microamp = <500>; +- }; +- }; +- +- pdm_dclk_x_pins: pdm-dclk-x { +- mux { +- groups = "pdm_dclk_x"; +- function = "pdm"; +- bias-disable; +- drive-strength-microamp = <500>; +- }; +- }; +- +- pdm_dclk_z_pins: pdm-dclk-z { +- mux { +- groups = "pdm_dclk_z"; +- function = "pdm"; +- bias-disable; +- drive-strength-microamp = <500>; +- }; +- }; +- +- pwm_a_pins: pwm-a { +- mux { +- groups = "pwm_a"; +- function = "pwm_a"; +- bias-disable; +- }; +- }; +- +- pwm_b_x7_pins: pwm-b-x7 { +- mux { +- groups = "pwm_b_x7"; +- function = "pwm_b"; +- bias-disable; +- }; +- }; +- +- pwm_b_x19_pins: pwm-b-x19 { +- mux { +- groups = "pwm_b_x19"; +- function = "pwm_b"; +- bias-disable; +- }; +- }; +- +- pwm_c_c_pins: pwm-c-c { +- mux { +- groups = "pwm_c_c"; +- function = "pwm_c"; +- bias-disable; +- }; +- }; +- +- pwm_c_x5_pins: pwm-c-x5 { +- mux { +- groups = "pwm_c_x5"; +- function = "pwm_c"; +- bias-disable; +- }; +- }; +- +- pwm_c_x8_pins: pwm-c-x8 { +- mux { +- groups = "pwm_c_x8"; +- function = "pwm_c"; +- bias-disable; +- }; +- }; +- +- pwm_d_x3_pins: pwm-d-x3 { +- mux { +- groups = "pwm_d_x3"; +- function = "pwm_d"; +- bias-disable; +- }; +- }; +- +- pwm_d_x6_pins: pwm-d-x6 { +- mux { +- groups = "pwm_d_x6"; +- function = "pwm_d"; +- bias-disable; +- }; +- }; +- +- pwm_e_pins: pwm-e { +- mux { +- groups = "pwm_e"; +- function = "pwm_e"; +- bias-disable; +- }; +- }; +- +- pwm_f_x_pins: pwm-f-x { +- mux { +- groups = "pwm_f_x"; +- function = "pwm_f"; +- bias-disable; +- }; +- }; +- +- pwm_f_h_pins: pwm-f-h { +- mux { +- groups = "pwm_f_h"; +- function = "pwm_f"; +- bias-disable; +- }; +- }; +- +- sdcard_c_pins: sdcard_c { +- mux-0 { +- groups = "sdcard_d0_c", +- "sdcard_d1_c", +- "sdcard_d2_c", +- "sdcard_d3_c", +- "sdcard_cmd_c"; +- function = "sdcard"; +- bias-pull-up; +- drive-strength-microamp = <4000>; +- }; +- +- mux-1 { +- groups = "sdcard_clk_c"; +- function = "sdcard"; +- bias-disable; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- sdcard_clk_gate_c_pins: sdcard_clk_gate_c { +- mux { +- groups = "GPIOC_4"; +- function = "gpio_periphs"; +- bias-pull-down; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- sdcard_z_pins: sdcard_z { +- mux-0 { +- groups = "sdcard_d0_z", +- "sdcard_d1_z", +- "sdcard_d2_z", +- "sdcard_d3_z", +- "sdcard_cmd_z"; +- function = "sdcard"; +- bias-pull-up; +- drive-strength-microamp = <4000>; +- }; +- +- mux-1 { +- groups = "sdcard_clk_z"; +- function = "sdcard"; +- bias-disable; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- sdcard_clk_gate_z_pins: sdcard_clk_gate_z { +- mux { +- groups = "GPIOZ_6"; +- function = "gpio_periphs"; +- bias-pull-down; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- sdio_pins: sdio { +- mux { +- groups = "sdio_d0", +- "sdio_d1", +- "sdio_d2", +- "sdio_d3", +- "sdio_clk", +- "sdio_cmd"; +- function = "sdio"; +- bias-disable; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- sdio_clk_gate_pins: sdio_clk_gate { +- mux { +- groups = "GPIOX_4"; +- function = "gpio_periphs"; +- bias-pull-down; +- drive-strength-microamp = <4000>; +- }; +- }; +- +- spdif_in_a10_pins: spdif-in-a10 { +- mux { +- groups = "spdif_in_a10"; +- function = "spdif_in"; +- bias-disable; +- }; +- }; +- +- spdif_in_a12_pins: spdif-in-a12 { +- mux { +- groups = "spdif_in_a12"; +- function = "spdif_in"; +- bias-disable; +- }; +- }; +- +- spdif_in_h_pins: spdif-in-h { +- mux { +- groups = "spdif_in_h"; +- function = "spdif_in"; +- bias-disable; +- }; +- }; +- +- spdif_out_h_pins: spdif-out-h { +- mux { +- groups = "spdif_out_h"; +- function = "spdif_out"; +- drive-strength-microamp = <500>; +- bias-disable; +- }; +- }; +- +- spdif_out_a11_pins: spdif-out-a11 { +- mux { +- groups = "spdif_out_a11"; +- function = "spdif_out"; +- drive-strength-microamp = <500>; +- bias-disable; +- }; +- }; +- +- spdif_out_a13_pins: spdif-out-a13 { +- mux { +- groups = "spdif_out_a13"; +- function = "spdif_out"; +- drive-strength-microamp = <500>; +- bias-disable; +- }; +- }; +- +- tdm_a_din0_pins: tdm-a-din0 { +- mux { +- groups = "tdm_a_din0"; +- function = "tdm_a"; +- bias-disable; +- }; +- }; +- +- +- tdm_a_din1_pins: tdm-a-din1 { +- mux { +- groups = "tdm_a_din1"; +- function = "tdm_a"; +- bias-disable; +- }; +- }; +- +- tdm_a_dout0_pins: tdm-a-dout0 { +- mux { +- groups = "tdm_a_dout0"; +- function = "tdm_a"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_a_dout1_pins: tdm-a-dout1 { +- mux { +- groups = "tdm_a_dout1"; +- function = "tdm_a"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_a_fs_pins: tdm-a-fs { +- mux { +- groups = "tdm_a_fs"; +- function = "tdm_a"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_a_sclk_pins: tdm-a-sclk { +- mux { +- groups = "tdm_a_sclk"; +- function = "tdm_a"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_a_slv_fs_pins: tdm-a-slv-fs { +- mux { +- groups = "tdm_a_slv_fs"; +- function = "tdm_a"; +- bias-disable; +- }; +- }; +- +- +- tdm_a_slv_sclk_pins: tdm-a-slv-sclk { +- mux { +- groups = "tdm_a_slv_sclk"; +- function = "tdm_a"; +- bias-disable; +- }; +- }; +- +- tdm_b_din0_pins: tdm-b-din0 { +- mux { +- groups = "tdm_b_din0"; +- function = "tdm_b"; +- bias-disable; +- }; +- }; +- +- tdm_b_din1_pins: tdm-b-din1 { +- mux { +- groups = "tdm_b_din1"; +- function = "tdm_b"; +- bias-disable; +- }; +- }; +- +- tdm_b_din2_pins: tdm-b-din2 { +- mux { +- groups = "tdm_b_din2"; +- function = "tdm_b"; +- bias-disable; +- }; +- }; +- +- tdm_b_din3_a_pins: tdm-b-din3-a { +- mux { +- groups = "tdm_b_din3_a"; +- function = "tdm_b"; +- bias-disable; +- }; +- }; +- +- tdm_b_din3_h_pins: tdm-b-din3-h { +- mux { +- groups = "tdm_b_din3_h"; +- function = "tdm_b"; +- bias-disable; +- }; +- }; +- +- tdm_b_dout0_pins: tdm-b-dout0 { +- mux { +- groups = "tdm_b_dout0"; +- function = "tdm_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_b_dout1_pins: tdm-b-dout1 { +- mux { +- groups = "tdm_b_dout1"; +- function = "tdm_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_b_dout2_pins: tdm-b-dout2 { +- mux { +- groups = "tdm_b_dout2"; +- function = "tdm_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_b_dout3_a_pins: tdm-b-dout3-a { +- mux { +- groups = "tdm_b_dout3_a"; +- function = "tdm_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_b_dout3_h_pins: tdm-b-dout3-h { +- mux { +- groups = "tdm_b_dout3_h"; +- function = "tdm_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_b_fs_pins: tdm-b-fs { +- mux { +- groups = "tdm_b_fs"; +- function = "tdm_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_b_sclk_pins: tdm-b-sclk { +- mux { +- groups = "tdm_b_sclk"; +- function = "tdm_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_b_slv_fs_pins: tdm-b-slv-fs { +- mux { +- groups = "tdm_b_slv_fs"; +- function = "tdm_b"; +- bias-disable; +- }; +- }; +- +- tdm_b_slv_sclk_pins: tdm-b-slv-sclk { +- mux { +- groups = "tdm_b_slv_sclk"; +- function = "tdm_b"; +- bias-disable; +- }; +- }; +- +- tdm_c_din0_a_pins: tdm-c-din0-a { +- mux { +- groups = "tdm_c_din0_a"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_din0_z_pins: tdm-c-din0-z { +- mux { +- groups = "tdm_c_din0_z"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_din1_a_pins: tdm-c-din1-a { +- mux { +- groups = "tdm_c_din1_a"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_din1_z_pins: tdm-c-din1-z { +- mux { +- groups = "tdm_c_din1_z"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_din2_a_pins: tdm-c-din2-a { +- mux { +- groups = "tdm_c_din2_a"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- eth_leds_pins: eth-leds { +- mux { +- groups = "eth_link_led", +- "eth_act_led"; +- function = "eth"; +- bias-disable; +- }; +- }; +- +- eth_pins: eth { +- mux { +- groups = "eth_mdio", +- "eth_mdc", +- "eth_rgmii_rx_clk", +- "eth_rx_dv", +- "eth_rxd0", +- "eth_rxd1", +- "eth_txen", +- "eth_txd0", +- "eth_txd1"; +- function = "eth"; +- drive-strength-microamp = <4000>; +- bias-disable; +- }; +- }; +- +- eth_rgmii_pins: eth-rgmii { +- mux { +- groups = "eth_rxd2_rgmii", +- "eth_rxd3_rgmii", +- "eth_rgmii_tx_clk", +- "eth_txd2_rgmii", +- "eth_txd3_rgmii"; +- function = "eth"; +- drive-strength-microamp = <4000>; +- bias-disable; +- }; +- }; +- +- tdm_c_din2_z_pins: tdm-c-din2-z { +- mux { +- groups = "tdm_c_din2_z"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_din3_a_pins: tdm-c-din3-a { +- mux { +- groups = "tdm_c_din3_a"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_din3_z_pins: tdm-c-din3-z { +- mux { +- groups = "tdm_c_din3_z"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_dout0_a_pins: tdm-c-dout0-a { +- mux { +- groups = "tdm_c_dout0_a"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_dout0_z_pins: tdm-c-dout0-z { +- mux { +- groups = "tdm_c_dout0_z"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_dout1_a_pins: tdm-c-dout1-a { +- mux { +- groups = "tdm_c_dout1_a"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_dout1_z_pins: tdm-c-dout1-z { +- mux { +- groups = "tdm_c_dout1_z"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_dout2_a_pins: tdm-c-dout2-a { +- mux { +- groups = "tdm_c_dout2_a"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_dout2_z_pins: tdm-c-dout2-z { +- mux { +- groups = "tdm_c_dout2_z"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_dout3_a_pins: tdm-c-dout3-a { +- mux { +- groups = "tdm_c_dout3_a"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_dout3_z_pins: tdm-c-dout3-z { +- mux { +- groups = "tdm_c_dout3_z"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_fs_a_pins: tdm-c-fs-a { +- mux { +- groups = "tdm_c_fs_a"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_fs_z_pins: tdm-c-fs-z { +- mux { +- groups = "tdm_c_fs_z"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_sclk_a_pins: tdm-c-sclk-a { +- mux { +- groups = "tdm_c_sclk_a"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_sclk_z_pins: tdm-c-sclk-z { +- mux { +- groups = "tdm_c_sclk_z"; +- function = "tdm_c"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_c_slv_fs_a_pins: tdm-c-slv-fs-a { +- mux { +- groups = "tdm_c_slv_fs_a"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_slv_fs_z_pins: tdm-c-slv-fs-z { +- mux { +- groups = "tdm_c_slv_fs_z"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_slv_sclk_a_pins: tdm-c-slv-sclk-a { +- mux { +- groups = "tdm_c_slv_sclk_a"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- tdm_c_slv_sclk_z_pins: tdm-c-slv-sclk-z { +- mux { +- groups = "tdm_c_slv_sclk_z"; +- function = "tdm_c"; +- bias-disable; +- }; +- }; +- +- uart_a_pins: uart-a { +- mux { +- groups = "uart_a_tx", +- "uart_a_rx"; +- function = "uart_a"; +- bias-disable; +- }; +- }; +- +- uart_a_cts_rts_pins: uart-a-cts-rts { +- mux { +- groups = "uart_a_cts", +- "uart_a_rts"; +- function = "uart_a"; +- bias-disable; +- }; +- }; +- +- uart_b_pins: uart-b { +- mux { +- groups = "uart_b_tx", +- "uart_b_rx"; +- function = "uart_b"; +- bias-disable; +- }; +- }; +- +- uart_c_pins: uart-c { +- mux { +- groups = "uart_c_tx", +- "uart_c_rx"; +- function = "uart_c"; +- bias-disable; +- }; +- }; +- +- uart_c_cts_rts_pins: uart-c-cts-rts { +- mux { +- groups = "uart_c_cts", +- "uart_c_rts"; +- function = "uart_c"; +- bias-disable; +- }; +- }; +- }; +- }; +- +- usb2_phy0: phy@36000 { +- compatible = "amlogic,g12a-usb2-phy"; +- reg = <0x0 0x36000 0x0 0x2000>; +- clocks = <&xtal>; +- clock-names = "xtal"; +- resets = <&reset RESET_USB_PHY20>; +- reset-names = "phy"; +- #phy-cells = <0>; +- }; +- +- dmc: bus@38000 { +- compatible = "simple-bus"; +- reg = <0x0 0x38000 0x0 0x400>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>; +- +- canvas: video-lut@48 { +- compatible = "amlogic,canvas"; +- reg = <0x0 0x48 0x0 0x14>; +- }; +- }; +- +- usb2_phy1: phy@3a000 { +- compatible = "amlogic,g12a-usb2-phy"; +- reg = <0x0 0x3a000 0x0 0x2000>; +- clocks = <&xtal>; +- clock-names = "xtal"; +- resets = <&reset RESET_USB_PHY21>; +- reset-names = "phy"; +- #phy-cells = <0>; +- }; +- +- hiu: bus@3c000 { +- compatible = "simple-bus"; +- reg = <0x0 0x3c000 0x0 0x1400>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0x3c000 0x0 0x1400>; +- +- hhi: system-controller@0 { +- compatible = "amlogic,meson-gx-hhi-sysctrl", +- "simple-mfd", "syscon"; +- reg = <0 0 0 0x400>; +- +- clkc: clock-controller { +- compatible = "amlogic,g12a-clkc"; +- #clock-cells = <1>; +- clocks = <&xtal>; +- clock-names = "xtal"; +- }; +- }; +- }; +- +- pdm: audio-controller@40000 { +- compatible = "amlogic,g12a-pdm", +- "amlogic,axg-pdm"; +- reg = <0x0 0x40000 0x0 0x34>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "PDM"; +- clocks = <&clkc_audio AUD_CLKID_PDM>, +- <&clkc_audio AUD_CLKID_PDM_DCLK>, +- <&clkc_audio AUD_CLKID_PDM_SYSCLK>; +- clock-names = "pclk", "dclk", "sysclk"; +- status = "disabled"; +- }; +- +- audio: bus@42000 { +- compatible = "simple-bus"; +- reg = <0x0 0x42000 0x0 0x2000>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>; +- +- clkc_audio: clock-controller@0 { +- status = "disabled"; +- compatible = "amlogic,g12a-audio-clkc"; +- reg = <0x0 0x0 0x0 0xb4>; +- #clock-cells = <1>; +- +- clocks = <&clkc CLKID_AUDIO>, +- <&clkc CLKID_MPLL0>, +- <&clkc CLKID_MPLL1>, +- <&clkc CLKID_MPLL2>, +- <&clkc CLKID_MPLL3>, +- <&clkc CLKID_HIFI_PLL>, +- <&clkc CLKID_FCLK_DIV3>, +- <&clkc CLKID_FCLK_DIV4>, +- <&clkc CLKID_GP0_PLL>; +- clock-names = "pclk", +- "mst_in0", +- "mst_in1", +- "mst_in2", +- "mst_in3", +- "mst_in4", +- "mst_in5", +- "mst_in6", +- "mst_in7"; +- +- resets = <&reset RESET_AUDIO>; +- }; +- +- toddr_a: audio-controller@100 { +- compatible = "amlogic,g12a-toddr", +- "amlogic,axg-toddr"; +- reg = <0x0 0x100 0x0 0x1c>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "TODDR_A"; +- interrupts = ; +- clocks = <&clkc_audio AUD_CLKID_TODDR_A>; +- resets = <&arb AXG_ARB_TODDR_A>; +- status = "disabled"; +- }; +- +- toddr_b: audio-controller@140 { +- compatible = "amlogic,g12a-toddr", +- "amlogic,axg-toddr"; +- reg = <0x0 0x140 0x0 0x1c>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "TODDR_B"; +- interrupts = ; +- clocks = <&clkc_audio AUD_CLKID_TODDR_B>; +- resets = <&arb AXG_ARB_TODDR_B>; +- status = "disabled"; +- }; +- +- toddr_c: audio-controller@180 { +- compatible = "amlogic,g12a-toddr", +- "amlogic,axg-toddr"; +- reg = <0x0 0x180 0x0 0x1c>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "TODDR_C"; +- interrupts = ; +- clocks = <&clkc_audio AUD_CLKID_TODDR_C>; +- resets = <&arb AXG_ARB_TODDR_C>; +- status = "disabled"; +- }; +- +- frddr_a: audio-controller@1c0 { +- compatible = "amlogic,g12a-frddr", +- "amlogic,axg-frddr"; +- reg = <0x0 0x1c0 0x0 0x1c>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "FRDDR_A"; +- interrupts = ; +- clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; +- resets = <&arb AXG_ARB_FRDDR_A>; +- status = "disabled"; +- }; +- +- frddr_b: audio-controller@200 { +- compatible = "amlogic,g12a-frddr", +- "amlogic,axg-frddr"; +- reg = <0x0 0x200 0x0 0x1c>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "FRDDR_B"; +- interrupts = ; +- clocks = <&clkc_audio AUD_CLKID_FRDDR_B>; +- resets = <&arb AXG_ARB_FRDDR_B>; +- status = "disabled"; +- }; +- +- frddr_c: audio-controller@240 { +- compatible = "amlogic,g12a-frddr", +- "amlogic,axg-frddr"; +- reg = <0x0 0x240 0x0 0x1c>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "FRDDR_C"; +- interrupts = ; +- clocks = <&clkc_audio AUD_CLKID_FRDDR_C>; +- resets = <&arb AXG_ARB_FRDDR_C>; +- status = "disabled"; +- }; +- +- arb: reset-controller@280 { +- status = "disabled"; +- compatible = "amlogic,meson-axg-audio-arb"; +- reg = <0x0 0x280 0x0 0x4>; +- #reset-cells = <1>; +- clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; +- }; +- +- tdmin_a: audio-controller@300 { +- compatible = "amlogic,g12a-tdmin", +- "amlogic,axg-tdmin"; +- reg = <0x0 0x300 0x0 0x40>; +- sound-name-prefix = "TDMIN_A"; +- clocks = <&clkc_audio AUD_CLKID_TDMIN_A>, +- <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>, +- <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>; +- clock-names = "pclk", "sclk", "sclk_sel", +- "lrclk", "lrclk_sel"; +- status = "disabled"; +- }; +- +- tdmin_b: audio-controller@340 { +- compatible = "amlogic,g12a-tdmin", +- "amlogic,axg-tdmin"; +- reg = <0x0 0x340 0x0 0x40>; +- sound-name-prefix = "TDMIN_B"; +- clocks = <&clkc_audio AUD_CLKID_TDMIN_B>, +- <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>, +- <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>; +- clock-names = "pclk", "sclk", "sclk_sel", +- "lrclk", "lrclk_sel"; +- status = "disabled"; +- }; +- +- tdmin_c: audio-controller@380 { +- compatible = "amlogic,g12a-tdmin", +- "amlogic,axg-tdmin"; +- reg = <0x0 0x380 0x0 0x40>; +- sound-name-prefix = "TDMIN_C"; +- clocks = <&clkc_audio AUD_CLKID_TDMIN_C>, +- <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>, +- <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>; +- clock-names = "pclk", "sclk", "sclk_sel", +- "lrclk", "lrclk_sel"; +- status = "disabled"; +- }; +- +- tdmin_lb: audio-controller@3c0 { +- compatible = "amlogic,g12a-tdmin", +- "amlogic,axg-tdmin"; +- reg = <0x0 0x3c0 0x0 0x40>; +- sound-name-prefix = "TDMIN_LB"; +- clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>, +- <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>, +- <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>, +- <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>; +- clock-names = "pclk", "sclk", "sclk_sel", +- "lrclk", "lrclk_sel"; +- status = "disabled"; +- }; +- +- spdifin: audio-controller@400 { +- compatible = "amlogic,g12a-spdifin", +- "amlogic,axg-spdifin"; +- reg = <0x0 0x400 0x0 0x30>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "SPDIFIN"; +- interrupts = ; +- clocks = <&clkc_audio AUD_CLKID_SPDIFIN>, +- <&clkc_audio AUD_CLKID_SPDIFIN_CLK>; +- clock-names = "pclk", "refclk"; +- status = "disabled"; +- }; +- +- spdifout: audio-controller@480 { +- compatible = "amlogic,g12a-spdifout", +- "amlogic,axg-spdifout"; +- reg = <0x0 0x480 0x0 0x50>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "SPDIFOUT"; +- clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>, +- <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>; +- clock-names = "pclk", "mclk"; +- status = "disabled"; +- }; +- +- tdmout_a: audio-controller@500 { +- compatible = "amlogic,g12a-tdmout"; +- reg = <0x0 0x500 0x0 0x40>; +- sound-name-prefix = "TDMOUT_A"; +- clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, +- <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, +- <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, +- <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>, +- <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>; +- clock-names = "pclk", "sclk", "sclk_sel", +- "lrclk", "lrclk_sel"; +- status = "disabled"; +- }; +- +- tdmout_b: audio-controller@540 { +- compatible = "amlogic,g12a-tdmout"; +- reg = <0x0 0x540 0x0 0x40>; +- sound-name-prefix = "TDMOUT_B"; +- clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>, +- <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>, +- <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>, +- <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>, +- <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>; +- clock-names = "pclk", "sclk", "sclk_sel", +- "lrclk", "lrclk_sel"; +- status = "disabled"; +- }; +- +- tdmout_c: audio-controller@580 { +- compatible = "amlogic,g12a-tdmout"; +- reg = <0x0 0x580 0x0 0x40>; +- sound-name-prefix = "TDMOUT_C"; +- clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>, +- <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>, +- <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>, +- <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>, +- <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>; +- clock-names = "pclk", "sclk", "sclk_sel", +- "lrclk", "lrclk_sel"; +- status = "disabled"; +- }; +- +- spdifout_b: audio-controller@680 { +- compatible = "amlogic,g12a-spdifout", +- "amlogic,axg-spdifout"; +- reg = <0x0 0x680 0x0 0x50>; +- #sound-dai-cells = <0>; +- sound-name-prefix = "SPDIFOUT_B"; +- clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>, +- <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>; +- clock-names = "pclk", "mclk"; +- status = "disabled"; +- }; +- +- tohdmitx: audio-controller@744 { +- compatible = "amlogic,g12a-tohdmitx"; +- reg = <0x0 0x744 0x0 0x4>; +- #sound-dai-cells = <1>; +- sound-name-prefix = "TOHDMITX"; +- status = "disabled"; +- }; +- }; +- +- usb3_pcie_phy: phy@46000 { +- compatible = "amlogic,g12a-usb3-pcie-phy"; +- reg = <0x0 0x46000 0x0 0x2000>; +- clocks = <&clkc CLKID_PCIE_PLL>; +- clock-names = "ref_clk"; +- resets = <&reset RESET_PCIE_PHY>; +- reset-names = "phy"; +- assigned-clocks = <&clkc CLKID_PCIE_PLL>; +- assigned-clock-rates = <100000000>; +- #phy-cells = <1>; +- }; +- +- eth_phy: mdio-multiplexer@4c000 { +- compatible = "amlogic,g12a-mdio-mux"; +- reg = <0x0 0x4c000 0x0 0xa4>; +- clocks = <&clkc CLKID_ETH_PHY>, +- <&xtal>, +- <&clkc CLKID_MPLL_50M>; +- clock-names = "pclk", "clkin0", "clkin1"; +- mdio-parent-bus = <&mdio0>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- ext_mdio: mdio@0 { +- reg = <0>; +- #address-cells = <1>; +- #size-cells = <0>; +- }; +- +- int_mdio: mdio@1 { +- reg = <1>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- internal_ephy: ethernet_phy@8 { +- compatible = "ethernet-phy-id0180.3301", +- "ethernet-phy-ieee802.3-c22"; +- interrupts = ; +- reg = <8>; +- max-speed = <100>; +- }; +- }; +- }; +- }; +- +- aobus: bus@ff800000 { +- compatible = "simple-bus"; +- reg = <0x0 0xff800000 0x0 0x100000>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; +- +- rti: sys-ctrl@0 { +- compatible = "amlogic,meson-gx-ao-sysctrl", +- "simple-mfd", "syscon"; +- reg = <0x0 0x0 0x0 0x100>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0x0 0x0 0x100>; +- +- clkc_AO: clock-controller { +- compatible = "amlogic,meson-g12a-aoclkc"; +- #clock-cells = <1>; +- #reset-cells = <1>; +- clocks = <&xtal>, <&clkc CLKID_CLK81>; +- clock-names = "xtal", "mpeg-clk"; +- }; +- +- pwrc_vpu: power-controller-vpu { +- compatible = "amlogic,meson-g12a-pwrc-vpu"; +- #power-domain-cells = <0>; +- amlogic,hhi-sysctrl = <&hhi>; +- resets = <&reset RESET_VIU>, +- <&reset RESET_VENC>, +- <&reset RESET_VCBUS>, +- <&reset RESET_BT656>, +- <&reset RESET_RDMA>, +- <&reset RESET_VENCI>, +- <&reset RESET_VENCP>, +- <&reset RESET_VDAC>, +- <&reset RESET_VDI6>, +- <&reset RESET_VENCL>, +- <&reset RESET_VID_LOCK>; +- clocks = <&clkc CLKID_VPU>, +- <&clkc CLKID_VAPB>; +- clock-names = "vpu", "vapb"; +- /* +- * VPU clocking is provided by two identical clock paths +- * VPU_0 and VPU_1 muxed to a single clock by a glitch +- * free mux to safely change frequency while running. +- * Same for VAPB but with a final gate after the glitch free mux. +- */ +- assigned-clocks = <&clkc CLKID_VPU_0_SEL>, +- <&clkc CLKID_VPU_0>, +- <&clkc CLKID_VPU>, /* Glitch free mux */ +- <&clkc CLKID_VAPB_0_SEL>, +- <&clkc CLKID_VAPB_0>, +- <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ +- assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, +- <0>, /* Do Nothing */ +- <&clkc CLKID_VPU_0>, +- <&clkc CLKID_FCLK_DIV4>, +- <0>, /* Do Nothing */ +- <&clkc CLKID_VAPB_0>; +- assigned-clock-rates = <0>, /* Do Nothing */ +- <666666666>, +- <0>, /* Do Nothing */ +- <0>, /* Do Nothing */ +- <250000000>, +- <0>; /* Do Nothing */ +- }; +- +- ao_pinctrl: pinctrl@14 { +- compatible = "amlogic,meson-g12a-aobus-pinctrl"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; +- +- gpio_ao: bank@14 { +- reg = <0x0 0x14 0x0 0x8>, +- <0x0 0x1c 0x0 0x8>, +- <0x0 0x24 0x0 0x14>; +- reg-names = "mux", +- "ds", +- "gpio"; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-ranges = <&ao_pinctrl 0 0 15>; +- }; +- +- i2c_ao_sck_pins: i2c_ao_sck_pins { +- mux { +- groups = "i2c_ao_sck"; +- function = "i2c_ao"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c_ao_sda_pins: i2c_ao_sda { +- mux { +- groups = "i2c_ao_sda"; +- function = "i2c_ao"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c_ao_sck_e_pins: i2c_ao_sck_e { +- mux { +- groups = "i2c_ao_sck_e"; +- function = "i2c_ao"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- i2c_ao_sda_e_pins: i2c_ao_sda_e { +- mux { +- groups = "i2c_ao_sda_e"; +- function = "i2c_ao"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- mclk0_ao_pins: mclk0-ao { +- mux { +- groups = "mclk0_ao"; +- function = "mclk0_ao"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_ao_b_din0_pins: tdm-ao-b-din0 { +- mux { +- groups = "tdm_ao_b_din0"; +- function = "tdm_ao_b"; +- bias-disable; +- }; +- }; +- +- spdif_ao_out_pins: spdif-ao-out { +- mux { +- groups = "spdif_ao_out"; +- function = "spdif_ao_out"; +- drive-strength-microamp = <500>; +- bias-disable; +- }; +- }; +- +- tdm_ao_b_din1_pins: tdm-ao-b-din1 { +- mux { +- groups = "tdm_ao_b_din1"; +- function = "tdm_ao_b"; +- bias-disable; +- }; +- }; +- +- tdm_ao_b_din2_pins: tdm-ao-b-din2 { +- mux { +- groups = "tdm_ao_b_din2"; +- function = "tdm_ao_b"; +- bias-disable; +- }; +- }; +- +- tdm_ao_b_dout0_pins: tdm-ao-b-dout0 { +- mux { +- groups = "tdm_ao_b_dout0"; +- function = "tdm_ao_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_ao_b_dout1_pins: tdm-ao-b-dout1 { +- mux { +- groups = "tdm_ao_b_dout1"; +- function = "tdm_ao_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_ao_b_dout2_pins: tdm-ao-b-dout2 { +- mux { +- groups = "tdm_ao_b_dout2"; +- function = "tdm_ao_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_ao_b_fs_pins: tdm-ao-b-fs { +- mux { +- groups = "tdm_ao_b_fs"; +- function = "tdm_ao_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_ao_b_sclk_pins: tdm-ao-b-sclk { +- mux { +- groups = "tdm_ao_b_sclk"; +- function = "tdm_ao_b"; +- bias-disable; +- drive-strength-microamp = <3000>; +- }; +- }; +- +- tdm_ao_b_slv_fs_pins: tdm-ao-b-slv-fs { +- mux { +- groups = "tdm_ao_b_slv_fs"; +- function = "tdm_ao_b"; +- bias-disable; +- }; +- }; +- +- tdm_ao_b_slv_sclk_pins: tdm-ao-b-slv-sclk { +- mux { +- groups = "tdm_ao_b_slv_sclk"; +- function = "tdm_ao_b"; +- bias-disable; +- }; +- }; +- +- uart_ao_a_pins: uart-a-ao { +- mux { +- groups = "uart_ao_a_tx", +- "uart_ao_a_rx"; +- function = "uart_ao_a"; +- bias-disable; +- }; +- }; +- +- uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts { +- mux { +- groups = "uart_ao_a_cts", +- "uart_ao_a_rts"; +- function = "uart_ao_a"; +- bias-disable; +- }; +- }; +- +- pwm_ao_a_pins: pwm-ao-a { +- mux { +- groups = "pwm_ao_a"; +- function = "pwm_ao_a"; +- bias-disable; +- }; +- }; +- +- pwm_ao_b_pins: pwm-ao-b { +- mux { +- groups = "pwm_ao_b"; +- function = "pwm_ao_b"; +- bias-disable; +- }; +- }; +- +- pwm_ao_c_4_pins: pwm-ao-c-4 { +- mux { +- groups = "pwm_ao_c_4"; +- function = "pwm_ao_c"; +- bias-disable; +- }; +- }; +- +- pwm_ao_c_6_pins: pwm-ao-c-6 { +- mux { +- groups = "pwm_ao_c_6"; +- function = "pwm_ao_c"; +- bias-disable; +- }; +- }; +- +- pwm_ao_d_5_pins: pwm-ao-d-5 { +- mux { +- groups = "pwm_ao_d_5"; +- function = "pwm_ao_d"; +- bias-disable; +- }; +- }; +- +- pwm_ao_d_10_pins: pwm-ao-d-10 { +- mux { +- groups = "pwm_ao_d_10"; +- function = "pwm_ao_d"; +- bias-disable; +- }; +- }; +- +- pwm_ao_d_e_pins: pwm-ao-d-e { +- mux { +- groups = "pwm_ao_d_e"; +- function = "pwm_ao_d"; +- }; +- }; +- +- remote_input_ao_pins: remote-input-ao { +- mux { +- groups = "remote_ao_input"; +- function = "remote_ao_input"; +- bias-disable; +- }; +- }; +- }; +- }; +- +- cec_AO: cec@100 { +- compatible = "amlogic,meson-gx-ao-cec"; +- reg = <0x0 0x00100 0x0 0x14>; +- interrupts = ; +- clocks = <&clkc_AO CLKID_AO_CEC>; +- clock-names = "core"; +- status = "disabled"; +- }; +- +- sec_AO: ao-secure@140 { +- compatible = "amlogic,meson-gx-ao-secure", "syscon"; +- reg = <0x0 0x140 0x0 0x140>; +- amlogic,has-chip-id; +- }; +- +- cecb_AO: cec@280 { +- compatible = "amlogic,meson-g12a-ao-cec"; +- reg = <0x0 0x00280 0x0 0x1c>; +- interrupts = ; +- clocks = <&clkc_AO CLKID_AO_CTS_OSCIN>; +- clock-names = "oscin"; +- status = "disabled"; +- }; +- +- pwm_AO_cd: pwm@2000 { +- compatible = "amlogic,meson-g12a-ao-pwm-cd"; +- reg = <0x0 0x2000 0x0 0x20>; +- #pwm-cells = <3>; +- status = "disabled"; +- }; +- +- uart_AO: serial@3000 { +- compatible = "amlogic,meson-gx-uart", +- "amlogic,meson-ao-uart"; +- reg = <0x0 0x3000 0x0 0x18>; +- interrupts = ; +- clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; +- clock-names = "xtal", "pclk", "baud"; +- status = "disabled"; +- }; +- +- uart_AO_B: serial@4000 { +- compatible = "amlogic,meson-gx-uart", +- "amlogic,meson-ao-uart"; +- reg = <0x0 0x4000 0x0 0x18>; +- interrupts = ; +- clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; +- clock-names = "xtal", "pclk", "baud"; +- status = "disabled"; +- }; +- +- i2c_AO: i2c@5000 { +- compatible = "amlogic,meson-axg-i2c"; +- status = "disabled"; +- reg = <0x0 0x05000 0x0 0x20>; +- interrupts = ; +- #address-cells = <1>; +- #size-cells = <0>; +- clocks = <&clkc CLKID_I2C>; +- }; +- +- pwm_AO_ab: pwm@7000 { +- compatible = "amlogic,meson-g12a-ao-pwm-ab"; +- reg = <0x0 0x7000 0x0 0x20>; +- #pwm-cells = <3>; +- status = "disabled"; +- }; +- +- ir: ir@8000 { +- compatible = "amlogic,meson-gxbb-ir"; +- reg = <0x0 0x8000 0x0 0x20>; +- interrupts = ; +- status = "disabled"; +- }; +- +- saradc: adc@9000 { +- compatible = "amlogic,meson-g12a-saradc", +- "amlogic,meson-saradc"; +- reg = <0x0 0x9000 0x0 0x48>; +- #io-channel-cells = <1>; +- interrupts = ; +- clocks = <&xtal>, +- <&clkc_AO CLKID_AO_SAR_ADC>, +- <&clkc_AO CLKID_AO_SAR_ADC_CLK>, +- <&clkc_AO CLKID_AO_SAR_ADC_SEL>; +- clock-names = "clkin", "core", "adc_clk", "adc_sel"; +- status = "disabled"; +- }; +- }; +- +- vpu: vpu@ff900000 { +- compatible = "amlogic,meson-g12a-vpu"; +- reg = <0x0 0xff900000 0x0 0x100000>, +- <0x0 0xff63c000 0x0 0x1000>; +- reg-names = "vpu", "hhi"; +- interrupts = ; +- #address-cells = <1>; +- #size-cells = <0>; +- amlogic,canvas = <&canvas>; +- power-domains = <&pwrc_vpu>; +- +- /* CVBS VDAC output port */ +- cvbs_vdac_port: port@0 { +- reg = <0>; +- }; +- +- /* HDMI-TX output port */ +- hdmi_tx_port: port@1 { +- reg = <1>; +- +- hdmi_tx_out: endpoint { +- remote-endpoint = <&hdmi_tx_in>; +- }; +- }; +- }; +- +- gic: interrupt-controller@ffc01000 { +- compatible = "arm,gic-400"; +- reg = <0x0 0xffc01000 0 0x1000>, +- <0x0 0xffc02000 0 0x2000>, +- <0x0 0xffc04000 0 0x2000>, +- <0x0 0xffc06000 0 0x2000>; +- interrupt-controller; +- interrupts = ; +- #interrupt-cells = <3>; +- #address-cells = <0>; +- }; +- +- cbus: bus@ffd00000 { +- compatible = "simple-bus"; +- reg = <0x0 0xffd00000 0x0 0x100000>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x100000>; +- +- reset: reset-controller@1004 { +- compatible = "amlogic,meson-g12a-reset", +- "amlogic,meson-axg-reset"; +- reg = <0x0 0x1004 0x0 0x9c>; +- #reset-cells = <1>; +- }; +- +- gpio_intc: interrupt-controller@f080 { +- compatible = "amlogic,meson-g12a-gpio-intc", +- "amlogic,meson-gpio-intc"; +- reg = <0x0 0xf080 0x0 0x10>; +- interrupt-controller; +- #interrupt-cells = <2>; +- amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; +- }; +- +- pwm_ef: pwm@19000 { +- compatible = "amlogic,meson-g12a-ee-pwm"; +- reg = <0x0 0x19000 0x0 0x20>; +- #pwm-cells = <3>; +- status = "disabled"; +- }; +- +- pwm_cd: pwm@1a000 { +- compatible = "amlogic,meson-g12a-ee-pwm"; +- reg = <0x0 0x1a000 0x0 0x20>; +- #pwm-cells = <3>; +- status = "disabled"; +- }; +- +- pwm_ab: pwm@1b000 { +- compatible = "amlogic,meson-g12a-ee-pwm"; +- reg = <0x0 0x1b000 0x0 0x20>; +- #pwm-cells = <3>; +- status = "disabled"; +- }; +- +- i2c3: i2c@1c000 { +- compatible = "amlogic,meson-axg-i2c"; +- status = "disabled"; +- reg = <0x0 0x1c000 0x0 0x20>; +- interrupts = ; +- #address-cells = <1>; +- #size-cells = <0>; +- clocks = <&clkc CLKID_I2C>; +- }; +- +- i2c2: i2c@1d000 { +- compatible = "amlogic,meson-axg-i2c"; +- status = "disabled"; +- reg = <0x0 0x1d000 0x0 0x20>; +- interrupts = ; +- #address-cells = <1>; +- #size-cells = <0>; +- clocks = <&clkc CLKID_I2C>; +- }; +- +- i2c1: i2c@1e000 { +- compatible = "amlogic,meson-axg-i2c"; +- status = "disabled"; +- reg = <0x0 0x1e000 0x0 0x20>; +- interrupts = ; +- #address-cells = <1>; +- #size-cells = <0>; +- clocks = <&clkc CLKID_I2C>; +- }; +- +- i2c0: i2c@1f000 { +- compatible = "amlogic,meson-axg-i2c"; +- status = "disabled"; +- reg = <0x0 0x1f000 0x0 0x20>; +- interrupts = ; +- #address-cells = <1>; +- #size-cells = <0>; +- clocks = <&clkc CLKID_I2C>; +- }; +- +- clk_msr: clock-measure@18000 { +- compatible = "amlogic,meson-g12a-clk-measure"; +- reg = <0x0 0x18000 0x0 0x10>; +- }; +- +- uart_C: serial@22000 { +- compatible = "amlogic,meson-gx-uart"; +- reg = <0x0 0x22000 0x0 0x18>; +- interrupts = ; +- clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; +- clock-names = "xtal", "pclk", "baud"; +- status = "disabled"; +- }; +- +- uart_B: serial@23000 { +- compatible = "amlogic,meson-gx-uart"; +- reg = <0x0 0x23000 0x0 0x18>; +- interrupts = ; +- clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; +- clock-names = "xtal", "pclk", "baud"; +- status = "disabled"; +- }; +- +- uart_A: serial@24000 { +- compatible = "amlogic,meson-gx-uart"; +- reg = <0x0 0x24000 0x0 0x18>; +- interrupts = ; +- clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; +- clock-names = "xtal", "pclk", "baud"; +- status = "disabled"; +- }; +- }; +- +- sd_emmc_a: sd@ffe03000 { +- compatible = "amlogic,meson-axg-mmc"; +- reg = <0x0 0xffe03000 0x0 0x800>; +- interrupts = ; +- status = "disabled"; +- clocks = <&clkc CLKID_SD_EMMC_A>, +- <&clkc CLKID_SD_EMMC_A_CLK0>, +- <&clkc CLKID_FCLK_DIV2>; +- clock-names = "core", "clkin0", "clkin1"; +- resets = <&reset RESET_SD_EMMC_A>; +- amlogic,dram-access-quirk; +- }; +- +- sd_emmc_b: sd@ffe05000 { +- compatible = "amlogic,meson-axg-mmc"; +- reg = <0x0 0xffe05000 0x0 0x800>; +- interrupts = ; +- status = "disabled"; +- clocks = <&clkc CLKID_SD_EMMC_B>, +- <&clkc CLKID_SD_EMMC_B_CLK0>, +- <&clkc CLKID_FCLK_DIV2>; +- clock-names = "core", "clkin0", "clkin1"; +- resets = <&reset RESET_SD_EMMC_B>; +- }; +- +- sd_emmc_c: mmc@ffe07000 { +- compatible = "amlogic,meson-axg-mmc"; +- reg = <0x0 0xffe07000 0x0 0x800>; +- interrupts = ; +- status = "disabled"; +- clocks = <&clkc CLKID_SD_EMMC_C>, +- <&clkc CLKID_SD_EMMC_C_CLK0>, +- <&clkc CLKID_FCLK_DIV2>; +- clock-names = "core", "clkin0", "clkin1"; +- resets = <&reset RESET_SD_EMMC_C>; +- }; +- +- usb: usb@ffe09000 { +- status = "disabled"; +- compatible = "amlogic,meson-g12a-usb-ctrl"; +- reg = <0x0 0xffe09000 0x0 0xa0>; +- interrupts = ; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; +- +- clocks = <&clkc CLKID_USB>; +- resets = <&reset RESET_USB>; +- +- dr_mode = "otg"; +- +- phys = <&usb2_phy0>, <&usb2_phy1>, +- <&usb3_pcie_phy PHY_TYPE_USB3>; +- phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; +- +- dwc2: usb@ff400000 { +- compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; +- reg = <0x0 0xff400000 0x0 0x40000>; +- interrupts = ; +- clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; +- clock-names = "ddr"; +- phys = <&usb2_phy1>; +- phy-names = "usb2-phy"; +- dr_mode = "peripheral"; +- g-rx-fifo-size = <192>; +- g-np-tx-fifo-size = <128>; +- g-tx-fifo-size = <128 128 16 16 16>; +- }; +- +- dwc3: usb@ff500000 { +- compatible = "snps,dwc3"; +- reg = <0x0 0xff500000 0x0 0x100000>; +- interrupts = ; +- dr_mode = "host"; +- snps,dis_u2_susphy_quirk; +- snps,quirk-frame-length-adjustment; +- }; +- }; +- +- mali: gpu@ffe40000 { +- compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; +- reg = <0x0 0xffe40000 0x0 0x40000>; +- interrupt-parent = <&gic>; +- interrupts = , +- , +- ; +- interrupt-names = "gpu", "mmu", "job"; +- clocks = <&clkc CLKID_MALI>; +- resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; +- +- /* +- * Mali clocking is provided by two identical clock paths +- * MALI_0 and MALI_1 muxed to a single clock by a glitch +- * free mux to safely change frequency while running. +- */ +- assigned-clocks = <&clkc CLKID_MALI_0_SEL>, +- <&clkc CLKID_MALI_0>, +- <&clkc CLKID_MALI>; /* Glitch free mux */ +- assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>, +- <0>, /* Do Nothing */ +- <&clkc CLKID_MALI_0>; +- assigned-clock-rates = <0>, /* Do Nothing */ +- <800000000>, +- <0>; /* Do Nothing */ +- }; +- }; +- +- timer { +- compatible = "arm,armv8-timer"; +- interrupts = , +- , +- , +- ; +- }; +- +- xtal: xtal-clk { +- compatible = "fixed-clock"; +- clock-frequency = <24000000>; +- clock-output-names = "xtal"; +- #clock-cells = <0>; +- }; +- ++&sd_emmc_a { ++ amlogic,dram-access-quirk; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +index 9e88e513b22d..d5edbc1a1991 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +@@ -4,12 +4,15 @@ + * Author: Neil Armstrong + */ + +-#include "meson-g12a.dtsi" ++#include "meson-g12-common.dtsi" + + / { + compatible = "amlogic,g12b"; + + cpus { ++ #address-cells = <0x2>; ++ #size-cells = <0x0>; ++ + cpu-map { + cluster0 { + core0 { +@@ -40,8 +43,21 @@ + }; + }; + +- /delete-node/ cpu@2; +- /delete-node/ cpu@3; ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x0 0x0>; ++ enable-method = "psci"; ++ next-level-cache = <&l2>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x0 0x1>; ++ enable-method = "psci"; ++ next-level-cache = <&l2>; ++ }; + + cpu100: cpu@100 { + device_type = "cpu"; +@@ -74,9 +90,17 @@ + enable-method = "psci"; + next-level-cache = <&l2>; + }; ++ ++ l2: l2-cache0 { ++ compatible = "cache"; ++ }; + }; + }; + + &clkc { + compatible = "amlogic,g12b-clkc"; + }; ++ ++&sd_emmc_a { ++ amlogic,dram-access-quirk; ++}; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0023-FROMGIT-arm64-dts-meson-g12-common-add-pwm_a-on-GPIO.patch b/packages/linux/patches/amlogic/amlogic-0023-FROMGIT-arm64-dts-meson-g12-common-add-pwm_a-on-GPIO.patch new file mode 100644 index 0000000000..c03f0f669a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0023-FROMGIT-arm64-dts-meson-g12-common-add-pwm_a-on-GPIO.patch @@ -0,0 +1,40 @@ +From 01ab14ff1351b894986e7796dbddf537cce8805d Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:26:18 +0200 +Subject: [PATCH 023/186] FROMGIT: arm64: dts: meson-g12-common: add pwm_a on + GPIOE_2 pinmux + +Add the ao_pinctrl subnode for the pwm_a function on GPIOE_2. + +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit a902d577cfb6c16f0108ad9d43fcc02cf90cfcda + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 06e186ca41e3..38d70ce1cfc7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -1970,6 +1970,14 @@ + }; + }; + ++ pwm_a_e_pins: pwm-a-e { ++ mux { ++ groups = "pwm_a_e"; ++ function = "pwm_a_e"; ++ bias-disable; ++ }; ++ }; ++ + pwm_ao_a_pins: pwm-ao-a { + mux { + groups = "pwm_ao_a"; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0024-FROMGIT-arm64-dts-meson-g12a-add-cpus-OPP-table.patch b/packages/linux/patches/amlogic/amlogic-0024-FROMGIT-arm64-dts-meson-g12a-add-cpus-OPP-table.patch new file mode 100644 index 0000000000..acf2a0604a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0024-FROMGIT-arm64-dts-meson-g12a-add-cpus-OPP-table.patch @@ -0,0 +1,109 @@ +From 5cf5216d8ccae4337d1c79f1eee1d174a47b92ce Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:26:19 +0200 +Subject: [PATCH 024/186] FROMGIT: arm64: dts: meson-g12a: add cpus OPP table + +Add the OPP table taken from the vendor u200 and u211 DTS. + +The Amlogic G12A SoC seems to available in 3 types : +- low-speed: up to 1,8GHz +- mid-speed: up to 1,908GHz +- high-speed: up to 2.1GHz + +And the S905X2 opp voltages are slightly higher than the S905D2 +OPP voltages for the low-speed table. + +This adds the conservative OPP table with the S905X2 higher voltages +and the maximum low-speed OPP frequency. + +The values were tested to be stable on an Amlogic U200 Reference Board, +SeiRobotics SEI510 and X96 Max Set-Top-Boxes running the arm64 cpuburn +at [1] and cycling between all the possible cpufreq translations and +checking the final frequency using the clock-measurer, script at [2]. + +[1] https://github.com/ssvb/cpuburn-arm/blob/master/cpuburn-a53.S +[2] https://gist.github.com/superna9999/d4de964dbc0f84b7d527e1df2ddea25f + +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit 67444f6c8058e6103de719eb276a8999a18a6ad6 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 60 +++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index ac15967bb7fa..733a9d46fc4b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -48,6 +48,66 @@ + compatible = "cache"; + }; + }; ++ ++ cpu_opp_table: opp-table { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-667000000 { ++ opp-hz = /bits/ 64 <666666666>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <761000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <831000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1800000000 { ++ opp-hz = /bits/ 64 <1800000000>; ++ opp-microvolt = <981000>; ++ }; ++ }; + }; + + &sd_emmc_a { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0025-FROMGIT-arm64-dts-meson-g12a-enable-DVFS-on-G12A-boa.patch b/packages/linux/patches/amlogic/amlogic-0025-FROMGIT-arm64-dts-meson-g12a-enable-DVFS-on-G12A-boa.patch new file mode 100644 index 0000000000..a464aad3bb --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0025-FROMGIT-arm64-dts-meson-g12a-enable-DVFS-on-G12A-boa.patch @@ -0,0 +1,270 @@ +From e4cd8a3f40644976d58426dc829fe65e247073aa Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:26:20 +0200 +Subject: [PATCH 025/186] FROMGIT: arm64: dts: meson-g12a: enable DVFS on G12A + boards + +Enable DVFS for the U200, SEI520 and X96-Max Amlogic G12A based board +by setting the clock, OPP and supply for each CPU cores. + +The CPU cluster power supply can achieve 0.73V to 1.01V using a PWM +output clocked at 800KHz with an inverse duty-cycle. + +DVFS has been tested by running the arm64 cpuburn at [1] and cycling +between all the possible cpufreq translations and checking the final +frequency using the clock-measurer, script at [2]. + +[1] https://github.com/ssvb/cpuburn-arm/blob/master/cpuburn-a53.S +[2] https://gist.github.com/superna9999/d4de964dbc0f84b7d527e1df2ddea25f + +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit 26328b18e2a1cffc92a32cc53c74bbca69ea7f60 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 55 +++++++++++++++++++ + .../boot/dts/amlogic/meson-g12a-u200.dts | 54 ++++++++++++++++++ + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 52 ++++++++++++++++++ + 3 files changed, 161 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 12aa7eaeaf68..c9fa23a56562 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -129,6 +129,25 @@ + enable-active-high; + }; + ++ vddcpu: regulator-vddcpu { ++ /* ++ * SY8120B1ABC DC/DC Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU"; ++ regulator-min-microvolt = <721000>; ++ regulator-max-microvolt = <1022000>; ++ ++ vin-supply = <&dc_in>; ++ ++ pwms = <&pwm_AO_cd 1 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ + vddio_ao1v8: regulator-vddio_ao1v8 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO1V8"; +@@ -297,6 +316,34 @@ + status = "okay"; + }; + ++&cpu0 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu2 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu3 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +@@ -345,6 +392,14 @@ + pinctrl-names = "default"; + }; + ++&pwm_AO_cd { ++ pinctrl-0 = <&pwm_ao_d_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin1"; ++ status = "okay"; ++}; ++ + &pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 8551fbd4a488..2a324f0136e3 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -129,6 +129,24 @@ + regulator-always-on; + }; + ++ vddcpu: regulator-vddcpu { ++ /* ++ * MP8756GD Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU"; ++ regulator-min-microvolt = <721000>; ++ regulator-max-microvolt = <1022000>; ++ ++ vin-supply = <&main_12v>; ++ ++ pwms = <&pwm_AO_cd 1 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; + }; + + &cec_AO { +@@ -145,6 +163,34 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&cpu0 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu2 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu3 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +@@ -197,6 +243,14 @@ + pinctrl-names = "default"; + }; + ++&pwm_AO_cd { ++ pinctrl-0 = <&pwm_ao_d_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin1"; ++ status = "okay"; ++}; ++ + /* SD card */ + &sd_emmc_b { + status = "okay"; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index fe4013cca876..c1e58a69d434 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -132,6 +132,22 @@ + regulator-always-on; + }; + ++ vddcpu: regulator-vddcpu { ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU"; ++ regulator-min-microvolt = <721000>; ++ regulator-max-microvolt = <1022000>; ++ ++ vin-supply = <&dc_in>; ++ ++ pwms = <&pwm_AO_cd 1 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ + sound { + compatible = "amlogic,axg-sound-card"; + model = "G12A-X96-MAX"; +@@ -242,6 +258,34 @@ + status = "okay"; + }; + ++&cpu0 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu2 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu3 { ++ cpu-supply = <&vddcpu>; ++ operating-points-v2 = <&cpu_opp_table>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +@@ -279,6 +323,14 @@ + pinctrl-names = "default"; + }; + ++&pwm_AO_cd { ++ pinctrl-0 = <&pwm_ao_d_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin1"; ++ status = "okay"; ++}; ++ + &ext_mdio { + external_phy: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0026-FROMGIT-arm64-dts-meson-g12b-add-cpus-OPP-tables.patch b/packages/linux/patches/amlogic/amlogic-0026-FROMGIT-arm64-dts-meson-g12b-add-cpus-OPP-tables.patch new file mode 100644 index 0000000000..db59664c03 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0026-FROMGIT-arm64-dts-meson-g12b-add-cpus-OPP-tables.patch @@ -0,0 +1,165 @@ +From 5de757bd182fc25b5bca929b4d1aa031b32aaa0f Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:26:21 +0200 +Subject: [PATCH 026/186] FROMGIT: arm64: dts: meson-g12b: add cpus OPP tables + +Add the OPP table taken from the HardKernel Odroid-N2 DTS. + +The Amlogic G12B SoC seems to available in 2 types : +- low-speed: Cortex-A73 Cluster up to 1,704GHz +- high-speed: Cortex-A73 Cluster up to 2.208GHz + +The Cortex-A73 Cluster can be clocked up to 1,896GHz for both types. + +The Vendor Amlogic A311D OPP table are slighly different, with lower +voltages than the HardKernel S922X tables but seems to be high-speed type. + +This adds the conservative OPP table with the S922X higher voltages +and the maximum low-speed OPP frequency. + +The values were tested to be stable on an HardKernel Odroid-N2 board +running the arm64 cpuburn at [1] and cycling between all the possible +cpufreq translations for both clusters and checking the final frequency +using the clock-measurer, script at [2]. + +[1] https://github.com/ssvb/cpuburn-arm/blob/master/cpuburn-a53.S +[2] https://gist.github.com/superna9999/d4de964dbc0f84b7d527e1df2ddea25f + +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit e53df01cf17faea76e29332b88b30ca02998fb3f + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 115 ++++++++++++++++++++ + 1 file changed, 115 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +index d5edbc1a1991..98ae8a7c8b41 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +@@ -95,6 +95,121 @@ + compatible = "cache"; + }; + }; ++ ++ cpu_opp_table_0: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-666666666 { ++ opp-hz = /bits/ 64 <666666666>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <761000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <831000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1896000000 { ++ opp-hz = /bits/ 64 <1896000000>; ++ opp-microvolt = <981000>; ++ }; ++ }; ++ ++ cpub_opp_table_1: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-666666666 { ++ opp-hz = /bits/ 64 <666666666>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <771000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <821000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <891000>; ++ }; ++ }; + }; + + &clkc { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0027-FROMGIT-arm64-dts-meson-add-ethernet-fifo-sizes.patch b/packages/linux/patches/amlogic/amlogic-0027-FROMGIT-arm64-dts-meson-add-ethernet-fifo-sizes.patch new file mode 100644 index 0000000000..fc0b857f3a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0027-FROMGIT-arm64-dts-meson-add-ethernet-fifo-sizes.patch @@ -0,0 +1,67 @@ +From 0075d60b445f24e817b7a8f45bdc90e8bde42c07 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 18 Jul 2019 11:03:01 +0200 +Subject: [PATCH 027/186] FROMGIT: arm64: dts: meson: add ethernet fifo sizes + +If unspecified in DT, the fifo sizes are not automatically detected by +the dwmac1000 dma driver and the reported fifo sizes default to 0. +Because of this, flow control will be turned off on the device. + +Add the fifo sizes provided by the datasheets in the SoC in DT so +flow control may be enabled if necessary. + +Signed-off-by: Jerome Brunet +Reviewed-by: Martin Blumenstingl +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit af29074f707b7f6d07b2484abc62db35c42c38ec + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 2 ++ + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 2 ++ + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index 6219337033a0..12bf959c17a7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -182,6 +182,8 @@ + <&clkc CLKID_FCLK_DIV2>, + <&clkc CLKID_MPLL2>; + clock-names = "stmmaceth", "clkin0", "clkin1"; ++ rx-fifo-depth = <4096>; ++ tx-fifo-depth = <2048>; + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 38d70ce1cfc7..27bb242dc95d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -106,6 +106,8 @@ + <&clkc CLKID_FCLK_DIV2>, + <&clkc CLKID_MPLL2>; + clock-names = "stmmaceth", "clkin0", "clkin1"; ++ rx-fifo-depth = <4096>; ++ tx-fifo-depth = <2048>; + status = "disabled"; + + mdio0: mdio { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index 74d03fc706be..e62aad5bf867 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -493,6 +493,8 @@ + 0x0 0xc8834540 0x0 0x4>; + interrupts = ; + interrupt-names = "macirq"; ++ rx-fifo-depth = <4096>; ++ tx-fifo-depth = <2048>; + status = "disabled"; + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0028-FROMGIT-dt-bindings-arm-amlogic-add-bindings-for-G12.patch b/packages/linux/patches/amlogic/amlogic-0028-FROMGIT-dt-bindings-arm-amlogic-add-bindings-for-G12.patch new file mode 100644 index 0000000000..e5c32ad41c --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0028-FROMGIT-dt-bindings-arm-amlogic-add-bindings-for-G12.patch @@ -0,0 +1,34 @@ +From bdfc7696b7ad4c394d4bd0c0252706931c55a757 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 31 Jul 2019 14:39:56 +0200 +Subject: [PATCH 028/186] FROMGIT: dt-bindings: arm: amlogic: add bindings for + G12B based S922X SoC + +Add a specific compatible for the Amlogic G12B family based S922X SoC +to differentiate with the A311D SoC from the same family. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit 5d2b173b89a02a6fc52217dc4d585c81b53d1d29 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + Documentation/devicetree/bindings/arm/amlogic.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml +index 325c6fd3566d..3c3bc806cd23 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.yaml ++++ b/Documentation/devicetree/bindings/arm/amlogic.yaml +@@ -139,6 +139,7 @@ properties: + items: + - enum: + - hardkernel,odroid-n2 ++ - const: amlogic,s922x + - const: amlogic,g12b + + ... +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0029-FROMGIT-dt-bindings-arm-amlogic-add-bindings-for-the.patch b/packages/linux/patches/amlogic/amlogic-0029-FROMGIT-dt-bindings-arm-amlogic-add-bindings-for-the.patch new file mode 100644 index 0000000000..2dd5316ccf --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0029-FROMGIT-dt-bindings-arm-amlogic-add-bindings-for-the.patch @@ -0,0 +1,38 @@ +From 37f20443f15463233c86c8db15491242607a64f9 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 31 Jul 2019 14:39:57 +0200 +Subject: [PATCH 029/186] FROMGIT: dt-bindings: arm: amlogic: add bindings for + the Amlogic G12B based A311D SoC + +Add a specific compatible for the Amlogic G12B bases A311D SoC used +in the Khadas VIM3. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit 96561b0c5e4be51bb57df2cc388a1b688a93a036 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + Documentation/devicetree/bindings/arm/amlogic.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml +index 3c3bc806cd23..efa032d12402 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.yaml ++++ b/Documentation/devicetree/bindings/arm/amlogic.yaml +@@ -135,6 +135,11 @@ properties: + - amlogic,u200 + - const: amlogic,g12a + ++ - description: Boards with the Amlogic Meson G12B A311D SoC ++ items: ++ - const: amlogic,a311d ++ - const: amlogic,g12b ++ + - description: Boards with the Amlogic Meson G12B S922X SoC + items: + - enum: +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0030-FROMGIT-dt-bindings-arm-amlogic-add-support-for-the-.patch b/packages/linux/patches/amlogic/amlogic-0030-FROMGIT-dt-bindings-arm-amlogic-add-support-for-the-.patch new file mode 100644 index 0000000000..bb92902ca6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0030-FROMGIT-dt-bindings-arm-amlogic-add-support-for-the-.patch @@ -0,0 +1,61 @@ +From a3f7e2e463ab5f258cfd42f110e135de98a52c70 Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Wed, 31 Jul 2019 14:39:58 +0200 +Subject: [PATCH 030/186] FROMGIT: dt-bindings: arm: amlogic: add support for + the Khadas VIM3 + +The Khadas VIM3 uses the Amlogic S922X or A311S SoC, both based on the +Amlogic G12B SoC family, on a board with the same form factor as the +VIM/VIM2 models. It ships in two variants; basic and +pro which differ in RAM and eMMC size: + +- 2GB (basic) or 4GB (pro) LPDDR4 RAM +- 16GB (basic) or 32GB (pro) eMMC 5.1 storage +- 16MB SPI flash +- 10/100/1000 Base-T Ethernet +- AP6398S Wireless (802.11 a/b/g/n/ac, BT5.0) +- HDMI 2.1 video +- 1x USB 2.0 + 1x USB 3.0 ports +- 1x USB-C (power) with USB 2.0 OTG +- 3x LED's (1x red, 1x blue, 1x white) +- 3x buttons (power, function, reset) +- IR receiver +- M2 socket with PCIe, USB, ADC & I2C +- 40pin GPIO Header +- 1x micro SD card slot + +Signed-off-by: Christian Hewitt +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit edd55c0496b4bea6b2fa4b8f4646d06f47bb02d6 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + Documentation/devicetree/bindings/arm/amlogic.yaml | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml +index efa032d12402..04a2b0ef34c6 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.yaml ++++ b/Documentation/devicetree/bindings/arm/amlogic.yaml +@@ -137,6 +137,8 @@ properties: + + - description: Boards with the Amlogic Meson G12B A311D SoC + items: ++ - enum: ++ - khadas,vim3 + - const: amlogic,a311d + - const: amlogic,g12b + +@@ -144,6 +146,7 @@ properties: + items: + - enum: + - hardkernel,odroid-n2 ++ - khadas,vim3 + - const: amlogic,s922x + - const: amlogic,g12b + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0031-FROMGIT-arm64-dts-meson-g12b-support-a311d-and-s922x.patch b/packages/linux/patches/amlogic/amlogic-0031-FROMGIT-arm64-dts-meson-g12b-support-a311d-and-s922x.patch new file mode 100644 index 0000000000..4469b4a801 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0031-FROMGIT-arm64-dts-meson-g12b-support-a311d-and-s922x.patch @@ -0,0 +1,455 @@ +From b8575810b01ddddc1c1641a35bb7ef468f4a3844 Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Wed, 31 Jul 2019 14:39:59 +0200 +Subject: [PATCH 031/186] FROMGIT: arm64: dts: meson-g12b: support a311d and + s922x cpu operating points + +Meson g12b ships with a low-speed (S922X) and high-speed (A311D) variant +so remove cpu_opp_table nodes in meson-g12b.dtsi and create two new dtsi +that can be included in device-specific dts files. Opp points were taken +from the vendor BSP kernel. + +Also make meson-g12b-odroid-n2.dts include the new meson-g12b-s922x.dtsi. + +Signed-off-by: Christian Hewitt +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Kevin Hilman +(cherry picked from commit 81f58a8b290787e52b4b919050f9093b13c485fa + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.4/dt64) +--- + .../boot/dts/amlogic/meson-g12b-a311d.dtsi | 149 ++++++++++++++++++ + .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 2 +- + .../boot/dts/amlogic/meson-g12b-s922x.dtsi | 124 +++++++++++++++ + arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 115 -------------- + 4 files changed, 274 insertions(+), 116 deletions(-) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi +new file mode 100644 +index 000000000000..d61f43052a34 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++#include "meson-g12b.dtsi" ++ ++/ { ++ cpu_opp_table_0: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-667000000 { ++ opp-hz = /bits/ 64 <667000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <761000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <781000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <811000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <901000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <951000>; ++ }; ++ ++ opp-1800000000 { ++ opp-hz = /bits/ 64 <1800000000>; ++ opp-microvolt = <1001000>; ++ }; ++ }; ++ ++ cpub_opp_table_1: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-667000000 { ++ opp-hz = /bits/ 64 <667000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <771000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <771000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <781000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1800000000 { ++ opp-hz = /bits/ 64 <1800000000>; ++ opp-microvolt = <831000>; ++ }; ++ ++ opp-1908000000 { ++ opp-hz = /bits/ 64 <1908000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-2016000000 { ++ opp-hz = /bits/ 64 <2016000000>; ++ opp-microvolt = <911000>; ++ }; ++ ++ opp-2108000000 { ++ opp-hz = /bits/ 64 <2108000000>; ++ opp-microvolt = <951000>; ++ }; ++ ++ opp-2208000000 { ++ opp-hz = /bits/ 64 <2208000000>; ++ opp-microvolt = <1011000>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index 4e916e1f71f7..237adae0ffae 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -6,7 +6,7 @@ + + /dts-v1/; + +-#include "meson-g12b.dtsi" ++#include "meson-g12b-s922x.dtsi" + #include + #include + #include +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi +new file mode 100644 +index 000000000000..046cc332d07f +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x.dtsi +@@ -0,0 +1,124 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++#include "meson-g12b.dtsi" ++ ++/ { ++ cpu_opp_table_0: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-667000000 { ++ opp-hz = /bits/ 64 <667000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <761000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <831000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1896000000 { ++ opp-hz = /bits/ 64 <1896000000>; ++ opp-microvolt = <981000>; ++ }; ++ }; ++ ++ cpub_opp_table_1: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-667000000 { ++ opp-hz = /bits/ 64 <667000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <771000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <771000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <821000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <891000>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +index 98ae8a7c8b41..d5edbc1a1991 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +@@ -95,121 +95,6 @@ + compatible = "cache"; + }; + }; +- +- cpu_opp_table_0: opp-table-0 { +- compatible = "operating-points-v2"; +- opp-shared; +- +- opp-100000000 { +- opp-hz = /bits/ 64 <100000000>; +- opp-microvolt = <731000>; +- }; +- +- opp-250000000 { +- opp-hz = /bits/ 64 <250000000>; +- opp-microvolt = <731000>; +- }; +- +- opp-500000000 { +- opp-hz = /bits/ 64 <500000000>; +- opp-microvolt = <731000>; +- }; +- +- opp-666666666 { +- opp-hz = /bits/ 64 <666666666>; +- opp-microvolt = <731000>; +- }; +- +- opp-1000000000 { +- opp-hz = /bits/ 64 <1000000000>; +- opp-microvolt = <731000>; +- }; +- +- opp-1200000000 { +- opp-hz = /bits/ 64 <1200000000>; +- opp-microvolt = <731000>; +- }; +- +- opp-1398000000 { +- opp-hz = /bits/ 64 <1398000000>; +- opp-microvolt = <761000>; +- }; +- +- opp-1512000000 { +- opp-hz = /bits/ 64 <1512000000>; +- opp-microvolt = <791000>; +- }; +- +- opp-1608000000 { +- opp-hz = /bits/ 64 <1608000000>; +- opp-microvolt = <831000>; +- }; +- +- opp-1704000000 { +- opp-hz = /bits/ 64 <1704000000>; +- opp-microvolt = <861000>; +- }; +- +- opp-1896000000 { +- opp-hz = /bits/ 64 <1896000000>; +- opp-microvolt = <981000>; +- }; +- }; +- +- cpub_opp_table_1: opp-table-1 { +- compatible = "operating-points-v2"; +- opp-shared; +- +- opp-100000000 { +- opp-hz = /bits/ 64 <100000000>; +- opp-microvolt = <751000>; +- }; +- +- opp-250000000 { +- opp-hz = /bits/ 64 <250000000>; +- opp-microvolt = <751000>; +- }; +- +- opp-500000000 { +- opp-hz = /bits/ 64 <500000000>; +- opp-microvolt = <751000>; +- }; +- +- opp-666666666 { +- opp-hz = /bits/ 64 <666666666>; +- opp-microvolt = <751000>; +- }; +- +- opp-1000000000 { +- opp-hz = /bits/ 64 <1000000000>; +- opp-microvolt = <751000>; +- }; +- +- opp-1200000000 { +- opp-hz = /bits/ 64 <1200000000>; +- opp-microvolt = <771000>; +- }; +- +- opp-1398000000 { +- opp-hz = /bits/ 64 <1398000000>; +- opp-microvolt = <791000>; +- }; +- +- opp-1512000000 { +- opp-hz = /bits/ 64 <1512000000>; +- opp-microvolt = <821000>; +- }; +- +- opp-1608000000 { +- opp-hz = /bits/ 64 <1608000000>; +- opp-microvolt = <861000>; +- }; +- +- opp-1704000000 { +- opp-hz = /bits/ 64 <1704000000>; +- opp-microvolt = <891000>; +- }; +- }; + }; + + &clkc { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0032-FROMGIT-pinctrl-meson-g12a-add-pwm_a-on-GPIOE_2-pinm.patch b/packages/linux/patches/amlogic/amlogic-0032-FROMGIT-pinctrl-meson-g12a-add-pwm_a-on-GPIOE_2-pinm.patch new file mode 100644 index 0000000000..6af8b571f6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0032-FROMGIT-pinctrl-meson-g12a-add-pwm_a-on-GPIOE_2-pinm.patch @@ -0,0 +1,63 @@ +From cb458a02db3f40d6e0dcb0ce24e35d10a804f028 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 14:58:38 +0200 +Subject: [PATCH 032/186] FROMGIT: pinctrl: meson-g12a: add pwm_a on GPIOE_2 + pinmux + +Add the missing pinmux for the pwm_a function on the GPIOE_2 pin. + +Reviewed-by: Kevin Hilman +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +Link: https://lore.kernel.org/r/20190729125838.6498-1-narmstrong@baylibre.com +Signed-off-by: Linus Walleij +(cherry picked from commit 726e8d813771ed9c714d75c9ce58a97b9ddf343d + git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git for-next) +--- + drivers/pinctrl/meson/pinctrl-meson-g12a.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c +index 3475cd7bd2af..582665fd362a 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c ++++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c +@@ -801,6 +801,9 @@ static const unsigned int remote_ao_input_pins[] = { GPIOAO_5 }; + /* ir_out */ + static const unsigned int remote_ao_out_pins[] = { GPIOAO_4 }; + ++/* pwm_a_e */ ++static const unsigned int pwm_a_e_pins[] = { GPIOE_2 }; ++ + /* pwm_ao_a */ + static const unsigned int pwm_ao_a_pins[] = { GPIOAO_11 }; + static const unsigned int pwm_ao_a_hiz_pins[] = { GPIOAO_11 }; +@@ -888,6 +891,7 @@ static struct meson_pmx_group meson_g12a_aobus_groups[] = { + GROUP(i2c_ao_slave_sda, 3), + GROUP(remote_ao_input, 1), + GROUP(remote_ao_out, 1), ++ GROUP(pwm_a_e, 3), + GROUP(pwm_ao_a, 3), + GROUP(pwm_ao_a_hiz, 2), + GROUP(pwm_ao_b, 3), +@@ -1192,6 +1196,10 @@ static const char * const remote_ao_out_groups[] = { + "remote_ao_out", + }; + ++static const char * const pwm_a_e_groups[] = { ++ "pwm_a_e", ++}; ++ + static const char * const pwm_ao_a_groups[] = { + "pwm_ao_a", "pwm_ao_a_hiz", + }; +@@ -1290,6 +1298,7 @@ static struct meson_pmx_func meson_g12a_aobus_functions[] = { + FUNCTION(i2c_ao_slave), + FUNCTION(remote_ao_input), + FUNCTION(remote_ao_out), ++ FUNCTION(pwm_a_e), + FUNCTION(pwm_ao_a), + FUNCTION(pwm_ao_b), + FUNCTION(pwm_ao_c), +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0033-FROMGIT-media-dt-bindings-media-meson-ao-cec-add-SM1.patch b/packages/linux/patches/amlogic/amlogic-0033-FROMGIT-media-dt-bindings-media-meson-ao-cec-add-SM1.patch new file mode 100644 index 0000000000..a3226081b6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0033-FROMGIT-media-dt-bindings-media-meson-ao-cec-add-SM1.patch @@ -0,0 +1,52 @@ +From 8f0744434f0dcfede8faf18e39af73d241236e64 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 1 Jul 2019 06:47:01 -0400 +Subject: [PATCH 033/186] FROMGIT: media: dt-bindings: media: meson-ao-cec: add + SM1 compatible + +Add AO-CEC compatible string for the Amlogic SM1 SoC family, +a derivate of the G12A AO-CECB controller. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 9bef0d1d053de8db30bc07aa132c0ee94a05609c + git://linuxtv.org/media_tree.git master) +--- + Documentation/devicetree/bindings/media/meson-ao-cec.txt | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/media/meson-ao-cec.txt b/Documentation/devicetree/bindings/media/meson-ao-cec.txt +index c67fc41d4aa2..ad92ee41c0dd 100644 +--- a/Documentation/devicetree/bindings/media/meson-ao-cec.txt ++++ b/Documentation/devicetree/bindings/media/meson-ao-cec.txt +@@ -5,10 +5,12 @@ to handle communication between HDMI connected devices over the CEC bus. + + Required properties: + - compatible : value should be following depending on the SoC : +- For GXBB, GXL, GXM and G12A (AO_CEC_A module) : ++ For GXBB, GXL, GXM, G12A and SM1 (AO_CEC_A module) : + "amlogic,meson-gx-ao-cec" + For G12A (AO_CEC_B module) : + "amlogic,meson-g12a-ao-cec" ++ For SM1 (AO_CEC_B module) : ++ "amlogic,meson-sm1-ao-cec" + + - reg : Physical base address of the IP registers and length of memory + mapped region. +@@ -16,9 +18,9 @@ Required properties: + - interrupts : AO-CEC interrupt number to the CPU. + - clocks : from common clock binding: handle to AO-CEC clock. + - clock-names : from common clock binding, must contain : +- For GXBB, GXL, GXM and G12A (AO_CEC_A module) : ++ For GXBB, GXL, GXM, G12A and SM1 (AO_CEC_A module) : + - "core" +- For G12A (AO_CEC_B module) : ++ For G12A, SM1 (AO_CEC_B module) : + - "oscin" + corresponding to entry in the clocks property. + - hdmi-phandle: phandle to the HDMI controller +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0034-FROMGIT-media-platform-meson-ao-cec-g12a-add-support.patch b/packages/linux/patches/amlogic/amlogic-0034-FROMGIT-media-platform-meson-ao-cec-g12a-add-support.patch new file mode 100644 index 0000000000..3c512409e7 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0034-FROMGIT-media-platform-meson-ao-cec-g12a-add-support.patch @@ -0,0 +1,107 @@ +From d50a38211eff6fbb250df2379812d0df2d595280 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 1 Jul 2019 06:47:02 -0400 +Subject: [PATCH 034/186] FROMGIT: media: platform: meson-ao-cec-g12a: add + support for SM1 + +Add support for the Amlogic SM1 SoC Family to the G12A AO-CECB +derivative. + +It only adds a single init register. + +Signed-off-by: Neil Armstrong +[hverkuil-cisco@xs4all.nl: dropped spurious newline] +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit aef5f47c9907ed6bfe9245124279b9c049077fd7 + git://linuxtv.org/media_tree.git master) +--- + drivers/media/platform/meson/ao-cec-g12a.c | 36 +++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c +index fb52e5dd044a..d302eae569b3 100644 +--- a/drivers/media/platform/meson/ao-cec-g12a.c ++++ b/drivers/media/platform/meson/ao-cec-g12a.c +@@ -121,6 +121,9 @@ + #define CECB_CTRL_TYPE_NEXT 2 + + #define CECB_CTRL2 0x01 ++ ++#define CECB_CTRL2_RISE_DEL_MAX GENMASK(4, 0) ++ + #define CECB_INTR_MASK 0x02 + #define CECB_LADD_LOW 0x05 + #define CECB_LADD_HIGH 0x06 +@@ -165,6 +168,11 @@ + + #define CECB_WAKEUPCTRL 0x31 + ++struct meson_ao_cec_g12a_data { ++ /* Setup the internal CECB_CTRL2 register */ ++ bool ctrl2_setup; ++}; ++ + struct meson_ao_cec_g12a_device { + struct platform_device *pdev; + struct regmap *regmap; +@@ -175,6 +183,7 @@ struct meson_ao_cec_g12a_device { + struct cec_msg rx_msg; + struct clk *oscin; + struct clk *core; ++ const struct meson_ao_cec_g12a_data *data; + }; + + static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { +@@ -605,6 +614,10 @@ static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_RESET, 0); + ++ if (ao_cec->data->ctrl2_setup) ++ regmap_write(ao_cec->regmap_cec, CECB_CTRL2, ++ FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX, 2)); ++ + meson_ao_cec_g12a_irq_setup(ao_cec, true); + + return 0; +@@ -632,6 +645,12 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) + if (!ao_cec) + return -ENOMEM; + ++ ao_cec->data = of_device_get_match_data(&pdev->dev); ++ if (!ao_cec->data) { ++ dev_err(&pdev->dev, "failed to get match data\n"); ++ return -ENODEV; ++ } ++ + spin_lock_init(&ao_cec->cec_reg_lock); + ao_cec->pdev = pdev; + +@@ -742,8 +761,23 @@ static int meson_ao_cec_g12a_remove(struct platform_device *pdev) + return 0; + } + ++static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = { ++ .ctrl2_setup = false, ++}; ++ ++static const struct meson_ao_cec_g12a_data ao_cec_sm1_data = { ++ .ctrl2_setup = true, ++}; ++ + static const struct of_device_id meson_ao_cec_g12a_of_match[] = { +- { .compatible = "amlogic,meson-g12a-ao-cec", }, ++ { ++ .compatible = "amlogic,meson-g12a-ao-cec", ++ .data = &ao_cec_g12a_data, ++ }, ++ { ++ .compatible = "amlogic,meson-sm1-ao-cec", ++ .data = &ao_cec_sm1_data, ++ }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0035-FROMGIT-ASoC-add-soc-dai.c.patch b/packages/linux/patches/amlogic/amlogic-0035-FROMGIT-ASoC-add-soc-dai.c.patch new file mode 100644 index 0000000000..81b95bf876 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0035-FROMGIT-ASoC-add-soc-dai.c.patch @@ -0,0 +1,574 @@ +From 962431951c7f46837aa3928dfc378a55a0f87294 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:32:12 +0900 +Subject: [PATCH 035/186] FROMGIT: ASoC: add soc-dai.c + +Current ALSA SoC has many snd_soc_dai_xxx() function which is +using dai->driver->ops->xxx. +But, some of them are implemented as snd_soc_dai_xxx(), +but others are directly using dai->driver->ops->xxx. +Because of it, the code is not easy to read. + +This patch creats new soc-dai.c and moves snd_soc_dai_xxx() +functions into it. +One exception is snd_soc_dai_is_dummy() which is based on +soc-utils local variable. We need to keep it as-is there. + +Others which is directly using dai->driver->ops->xxx will be +implemented at soc-dai.c by incremental patches. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/871ryij1r6.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 06f6e1d41427f394ad3f67ecf06efcd28a46932c + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/Makefile | 2 +- + sound/soc/soc-core.c | 243 ----------------------------------------- + sound/soc/soc-dai.c | 254 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 255 insertions(+), 244 deletions(-) + create mode 100644 sound/soc/soc-dai.c + +diff --git a/sound/soc/Makefile b/sound/soc/Makefile +index d90ce8a32887..919c3c027c62 100644 +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -1,5 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 +-snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o ++snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o + snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o + snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o + +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index 44f899b970c2..a8d2c4ec0ec9 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -2397,26 +2397,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, + } + EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); + +-/** +- * snd_soc_dai_set_sysclk - configure DAI system or master clock. +- * @dai: DAI +- * @clk_id: DAI specific clock ID +- * @freq: new clock frequency in Hz +- * @dir: new clock direction - input/output. +- * +- * Configures the DAI master (MCLK) or system (SYSCLK) clocking. +- */ +-int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, +- unsigned int freq, int dir) +-{ +- if (dai->driver->ops->set_sysclk) +- return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); +- +- return snd_soc_component_set_sysclk(dai->component, clk_id, 0, +- freq, dir); +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); +- + /** + * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. + * @component: COMPONENT +@@ -2439,48 +2419,6 @@ int snd_soc_component_set_sysclk(struct snd_soc_component *component, + } + EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); + +-/** +- * snd_soc_dai_set_clkdiv - configure DAI clock dividers. +- * @dai: DAI +- * @div_id: DAI specific clock divider ID +- * @div: new clock divisor. +- * +- * Configures the clock dividers. This is used to derive the best DAI bit and +- * frame clocks from the system or master clock. It's best to set the DAI bit +- * and frame clocks as low as possible to save system power. +- */ +-int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, +- int div_id, int div) +-{ +- if (dai->driver->ops->set_clkdiv) +- return dai->driver->ops->set_clkdiv(dai, div_id, div); +- else +- return -EINVAL; +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); +- +-/** +- * snd_soc_dai_set_pll - configure DAI PLL. +- * @dai: DAI +- * @pll_id: DAI specific PLL ID +- * @source: DAI specific source for the PLL +- * @freq_in: PLL input clock frequency in Hz +- * @freq_out: requested PLL output clock frequency in Hz +- * +- * Configures and enables PLL to generate output clock based on input clock. +- */ +-int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, +- unsigned int freq_in, unsigned int freq_out) +-{ +- if (dai->driver->ops->set_pll) +- return dai->driver->ops->set_pll(dai, pll_id, source, +- freq_in, freq_out); +- +- return snd_soc_component_set_pll(dai->component, pll_id, source, +- freq_in, freq_out); +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); +- + /* + * snd_soc_component_set_pll - configure component PLL. + * @component: COMPONENT +@@ -2503,187 +2441,6 @@ int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, + } + EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); + +-/** +- * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. +- * @dai: DAI +- * @ratio: Ratio of BCLK to Sample rate. +- * +- * Configures the DAI for a preset BCLK to sample rate ratio. +- */ +-int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +-{ +- if (dai->driver->ops->set_bclk_ratio) +- return dai->driver->ops->set_bclk_ratio(dai, ratio); +- else +- return -EINVAL; +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); +- +-/** +- * snd_soc_dai_set_fmt - configure DAI hardware audio format. +- * @dai: DAI +- * @fmt: SND_SOC_DAIFMT_* format value. +- * +- * Configures the DAI hardware format and clocking. +- */ +-int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +-{ +- if (dai->driver->ops->set_fmt == NULL) +- return -ENOTSUPP; +- return dai->driver->ops->set_fmt(dai, fmt); +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); +- +-/** +- * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. +- * @slots: Number of slots in use. +- * @tx_mask: bitmask representing active TX slots. +- * @rx_mask: bitmask representing active RX slots. +- * +- * Generates the TDM tx and rx slot default masks for DAI. +- */ +-static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, +- unsigned int *tx_mask, +- unsigned int *rx_mask) +-{ +- if (*tx_mask || *rx_mask) +- return 0; +- +- if (!slots) +- return -EINVAL; +- +- *tx_mask = (1 << slots) - 1; +- *rx_mask = (1 << slots) - 1; +- +- return 0; +-} +- +-/** +- * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation +- * @dai: The DAI to configure +- * @tx_mask: bitmask representing active TX slots. +- * @rx_mask: bitmask representing active RX slots. +- * @slots: Number of slots in use. +- * @slot_width: Width in bits for each slot. +- * +- * This function configures the specified DAI for TDM operation. @slot contains +- * the total number of slots of the TDM stream and @slot_with the width of each +- * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the +- * active slots of the TDM stream for the specified DAI, i.e. which slots the +- * DAI should write to or read from. If a bit is set the corresponding slot is +- * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to +- * the first slot, bit 1 to the second slot and so on. The first active slot +- * maps to the first channel of the DAI, the second active slot to the second +- * channel and so on. +- * +- * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, +- * @rx_mask and @slot_width will be ignored. +- * +- * Returns 0 on success, a negative error code otherwise. +- */ +-int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, +- unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) +-{ +- if (dai->driver->ops->xlate_tdm_slot_mask) +- dai->driver->ops->xlate_tdm_slot_mask(slots, +- &tx_mask, &rx_mask); +- else +- snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); +- +- dai->tx_mask = tx_mask; +- dai->rx_mask = rx_mask; +- +- if (dai->driver->ops->set_tdm_slot) +- return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, +- slots, slot_width); +- else +- return -ENOTSUPP; +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); +- +-/** +- * snd_soc_dai_set_channel_map - configure DAI audio channel map +- * @dai: DAI +- * @tx_num: how many TX channels +- * @tx_slot: pointer to an array which imply the TX slot number channel +- * 0~num-1 uses +- * @rx_num: how many RX channels +- * @rx_slot: pointer to an array which imply the RX slot number channel +- * 0~num-1 uses +- * +- * configure the relationship between channel number and TDM slot number. +- */ +-int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, +- unsigned int tx_num, unsigned int *tx_slot, +- unsigned int rx_num, unsigned int *rx_slot) +-{ +- if (dai->driver->ops->set_channel_map) +- return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, +- rx_num, rx_slot); +- else +- return -ENOTSUPP; +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); +- +-/** +- * snd_soc_dai_get_channel_map - Get DAI audio channel map +- * @dai: DAI +- * @tx_num: how many TX channels +- * @tx_slot: pointer to an array which imply the TX slot number channel +- * 0~num-1 uses +- * @rx_num: how many RX channels +- * @rx_slot: pointer to an array which imply the RX slot number channel +- * 0~num-1 uses +- */ +-int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, +- unsigned int *tx_num, unsigned int *tx_slot, +- unsigned int *rx_num, unsigned int *rx_slot) +-{ +- if (dai->driver->ops->get_channel_map) +- return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, +- rx_num, rx_slot); +- else +- return -ENOTSUPP; +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); +- +-/** +- * snd_soc_dai_set_tristate - configure DAI system or master clock. +- * @dai: DAI +- * @tristate: tristate enable +- * +- * Tristates the DAI so that others can use it. +- */ +-int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) +-{ +- if (dai->driver->ops->set_tristate) +- return dai->driver->ops->set_tristate(dai, tristate); +- else +- return -EINVAL; +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); +- +-/** +- * snd_soc_dai_digital_mute - configure DAI system or master clock. +- * @dai: DAI +- * @mute: mute enable +- * @direction: stream to mute +- * +- * Mutes the DAI DAC. +- */ +-int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, +- int direction) +-{ +- if (dai->driver->ops->mute_stream) +- return dai->driver->ops->mute_stream(dai, mute, direction); +- else if (direction == SNDRV_PCM_STREAM_PLAYBACK && +- dai->driver->ops->digital_mute) +- return dai->driver->ops->digital_mute(dai, mute); +- else +- return -ENOTSUPP; +-} +-EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); +- + static int snd_soc_bind_card(struct snd_soc_card *card) + { + struct snd_soc_pcm_runtime *rtd; +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +new file mode 100644 +index 000000000000..a1009ead40de +--- /dev/null ++++ b/sound/soc/soc-dai.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// soc-dai.c ++// ++// Copyright (C) 2019 Renesas Electronics Corp. ++// Kuninori Morimoto ++// ++ ++#include ++#include ++ ++/** ++ * snd_soc_dai_set_sysclk - configure DAI system or master clock. ++ * @dai: DAI ++ * @clk_id: DAI specific clock ID ++ * @freq: new clock frequency in Hz ++ * @dir: new clock direction - input/output. ++ * ++ * Configures the DAI master (MCLK) or system (SYSCLK) clocking. ++ */ ++int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ if (dai->driver->ops->set_sysclk) ++ return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); ++ ++ return snd_soc_component_set_sysclk(dai->component, clk_id, 0, ++ freq, dir); ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); ++ ++/** ++ * snd_soc_dai_set_clkdiv - configure DAI clock dividers. ++ * @dai: DAI ++ * @div_id: DAI specific clock divider ID ++ * @div: new clock divisor. ++ * ++ * Configures the clock dividers. This is used to derive the best DAI bit and ++ * frame clocks from the system or master clock. It's best to set the DAI bit ++ * and frame clocks as low as possible to save system power. ++ */ ++int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, ++ int div_id, int div) ++{ ++ if (dai->driver->ops->set_clkdiv) ++ return dai->driver->ops->set_clkdiv(dai, div_id, div); ++ else ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); ++ ++/** ++ * snd_soc_dai_set_pll - configure DAI PLL. ++ * @dai: DAI ++ * @pll_id: DAI specific PLL ID ++ * @source: DAI specific source for the PLL ++ * @freq_in: PLL input clock frequency in Hz ++ * @freq_out: requested PLL output clock frequency in Hz ++ * ++ * Configures and enables PLL to generate output clock based on input clock. ++ */ ++int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, ++ unsigned int freq_in, unsigned int freq_out) ++{ ++ if (dai->driver->ops->set_pll) ++ return dai->driver->ops->set_pll(dai, pll_id, source, ++ freq_in, freq_out); ++ ++ return snd_soc_component_set_pll(dai->component, pll_id, source, ++ freq_in, freq_out); ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); ++ ++/** ++ * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. ++ * @dai: DAI ++ * @ratio: Ratio of BCLK to Sample rate. ++ * ++ * Configures the DAI for a preset BCLK to sample rate ratio. ++ */ ++int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) ++{ ++ if (dai->driver->ops->set_bclk_ratio) ++ return dai->driver->ops->set_bclk_ratio(dai, ratio); ++ else ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); ++ ++/** ++ * snd_soc_dai_set_fmt - configure DAI hardware audio format. ++ * @dai: DAI ++ * @fmt: SND_SOC_DAIFMT_* format value. ++ * ++ * Configures the DAI hardware format and clocking. ++ */ ++int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ if (dai->driver->ops->set_fmt == NULL) ++ return -ENOTSUPP; ++ return dai->driver->ops->set_fmt(dai, fmt); ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); ++ ++/** ++ * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. ++ * @slots: Number of slots in use. ++ * @tx_mask: bitmask representing active TX slots. ++ * @rx_mask: bitmask representing active RX slots. ++ * ++ * Generates the TDM tx and rx slot default masks for DAI. ++ */ ++static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, ++ unsigned int *tx_mask, ++ unsigned int *rx_mask) ++{ ++ if (*tx_mask || *rx_mask) ++ return 0; ++ ++ if (!slots) ++ return -EINVAL; ++ ++ *tx_mask = (1 << slots) - 1; ++ *rx_mask = (1 << slots) - 1; ++ ++ return 0; ++} ++ ++/** ++ * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation ++ * @dai: The DAI to configure ++ * @tx_mask: bitmask representing active TX slots. ++ * @rx_mask: bitmask representing active RX slots. ++ * @slots: Number of slots in use. ++ * @slot_width: Width in bits for each slot. ++ * ++ * This function configures the specified DAI for TDM operation. @slot contains ++ * the total number of slots of the TDM stream and @slot_with the width of each ++ * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the ++ * active slots of the TDM stream for the specified DAI, i.e. which slots the ++ * DAI should write to or read from. If a bit is set the corresponding slot is ++ * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to ++ * the first slot, bit 1 to the second slot and so on. The first active slot ++ * maps to the first channel of the DAI, the second active slot to the second ++ * channel and so on. ++ * ++ * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, ++ * @rx_mask and @slot_width will be ignored. ++ * ++ * Returns 0 on success, a negative error code otherwise. ++ */ ++int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, ++ unsigned int tx_mask, unsigned int rx_mask, ++ int slots, int slot_width) ++{ ++ if (dai->driver->ops->xlate_tdm_slot_mask) ++ dai->driver->ops->xlate_tdm_slot_mask(slots, ++ &tx_mask, &rx_mask); ++ else ++ snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); ++ ++ dai->tx_mask = tx_mask; ++ dai->rx_mask = rx_mask; ++ ++ if (dai->driver->ops->set_tdm_slot) ++ return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, ++ slots, slot_width); ++ else ++ return -ENOTSUPP; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); ++ ++/** ++ * snd_soc_dai_set_channel_map - configure DAI audio channel map ++ * @dai: DAI ++ * @tx_num: how many TX channels ++ * @tx_slot: pointer to an array which imply the TX slot number channel ++ * 0~num-1 uses ++ * @rx_num: how many RX channels ++ * @rx_slot: pointer to an array which imply the RX slot number channel ++ * 0~num-1 uses ++ * ++ * configure the relationship between channel number and TDM slot number. ++ */ ++int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, ++ unsigned int tx_num, unsigned int *tx_slot, ++ unsigned int rx_num, unsigned int *rx_slot) ++{ ++ if (dai->driver->ops->set_channel_map) ++ return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, ++ rx_num, rx_slot); ++ else ++ return -ENOTSUPP; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); ++ ++/** ++ * snd_soc_dai_get_channel_map - Get DAI audio channel map ++ * @dai: DAI ++ * @tx_num: how many TX channels ++ * @tx_slot: pointer to an array which imply the TX slot number channel ++ * 0~num-1 uses ++ * @rx_num: how many RX channels ++ * @rx_slot: pointer to an array which imply the RX slot number channel ++ * 0~num-1 uses ++ */ ++int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, ++ unsigned int *tx_num, unsigned int *tx_slot, ++ unsigned int *rx_num, unsigned int *rx_slot) ++{ ++ if (dai->driver->ops->get_channel_map) ++ return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, ++ rx_num, rx_slot); ++ else ++ return -ENOTSUPP; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); ++ ++/** ++ * snd_soc_dai_set_tristate - configure DAI system or master clock. ++ * @dai: DAI ++ * @tristate: tristate enable ++ * ++ * Tristates the DAI so that others can use it. ++ */ ++int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) ++{ ++ if (dai->driver->ops->set_tristate) ++ return dai->driver->ops->set_tristate(dai, tristate); ++ else ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); ++ ++/** ++ * snd_soc_dai_digital_mute - configure DAI system or master clock. ++ * @dai: DAI ++ * @mute: mute enable ++ * @direction: stream to mute ++ * ++ * Mutes the DAI DAC. ++ */ ++int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, ++ int direction) ++{ ++ if (dai->driver->ops->mute_stream) ++ return dai->driver->ops->mute_stream(dai, mute, direction); ++ else if (direction == SNDRV_PCM_STREAM_PLAYBACK && ++ dai->driver->ops->digital_mute) ++ return dai->driver->ops->digital_mute(dai, mute); ++ else ++ return -ENOTSUPP; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0036-FROMGIT-ASoC-soc-dai-mv-soc_dai_hw_params-to-soc-dai.patch b/packages/linux/patches/amlogic/amlogic-0036-FROMGIT-ASoC-soc-dai-mv-soc_dai_hw_params-to-soc-dai.patch new file mode 100644 index 0000000000..5870d1e99a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0036-FROMGIT-ASoC-soc-dai-mv-soc_dai_hw_params-to-soc-dai.patch @@ -0,0 +1,179 @@ +From 186c94359b9b259bed211034098424a654502d46 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:33:04 +0900 +Subject: [PATCH 036/186] FROMGIT: ASoC: soc-dai: mv soc_dai_hw_params() to + soc-dai + +Sometimes ALSA SoC naming is very random. +Current soc_dai_hw_params() should use snd_soc_dai_xxx() style. +And then, 1st parameter should be dai. Otherwise it is confusable. + - soc_dai_hw_params(..., dai); + + snd_soc_dai_hw_params(dai, ...); + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87zhl6hn5b.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit aa6166c2ac28392d64f2d8b3acfb56c8fe657147 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 4 ++++ + include/sound/soc.h | 4 ---- + sound/soc/soc-dai.c | 30 ++++++++++++++++++++++++++++++ + sound/soc/soc-dapm.c | 4 ++-- + sound/soc/soc-pcm.c | 35 +++-------------------------------- + 5 files changed, 39 insertions(+), 38 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index f5d70041108f..3773262a1b77 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -145,6 +145,10 @@ int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, + + int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); + ++int snd_soc_dai_hw_params(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params); ++ + struct snd_soc_dai_ops { + /* + * DAI clocking configuration, all optional. +diff --git a/include/sound/soc.h b/include/sound/soc.h +index 4e8071269639..d770606732cd 100644 +--- a/include/sound/soc.h ++++ b/include/sound/soc.h +@@ -505,10 +505,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); + int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, + const struct snd_pcm_hardware *hw); + +-int soc_dai_hw_params(struct snd_pcm_substream *substream, +- struct snd_pcm_hw_params *params, +- struct snd_soc_dai *dai); +- + /* Jack reporting */ + int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, + struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins, +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index a1009ead40de..f883d27d136f 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -252,3 +252,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, + return -ENOTSUPP; + } + EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); ++ ++int snd_soc_dai_hw_params(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ int ret; ++ ++ /* perform any topology hw_params fixups before DAI */ ++ if (rtd->dai_link->be_hw_params_fixup) { ++ ret = rtd->dai_link->be_hw_params_fixup(rtd, params); ++ if (ret < 0) { ++ dev_err(rtd->dev, ++ "ASoC: hw_params topology fixup failed %d\n", ++ ret); ++ return ret; ++ } ++ } ++ ++ if (dai->driver->ops->hw_params) { ++ ret = dai->driver->ops->hw_params(substream, params, dai); ++ if (ret < 0) { ++ dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", ++ dai->name, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index 2790c00735f3..e86a2d8d4f35 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3841,7 +3841,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + } + } + source->active++; +- ret = soc_dai_hw_params(&substream, params, source); ++ ret = snd_soc_dai_hw_params(source, &substream, params); + if (ret < 0) + goto out; + +@@ -3863,7 +3863,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + } + } + sink->active++; +- ret = soc_dai_hw_params(&substream, params, sink); ++ ret = snd_soc_dai_hw_params(sink, &substream, params); + if (ret < 0) + goto out; + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 4878d22ebd8c..420cc94e0a46 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -877,36 +877,6 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, + interval->max = channels; + } + +-int soc_dai_hw_params(struct snd_pcm_substream *substream, +- struct snd_pcm_hw_params *params, +- struct snd_soc_dai *dai) +-{ +- struct snd_soc_pcm_runtime *rtd = substream->private_data; +- int ret; +- +- /* perform any topology hw_params fixups before DAI */ +- if (rtd->dai_link->be_hw_params_fixup) { +- ret = rtd->dai_link->be_hw_params_fixup(rtd, params); +- if (ret < 0) { +- dev_err(rtd->dev, +- "ASoC: hw_params topology fixup failed %d\n", +- ret); +- return ret; +- } +- } +- +- if (dai->driver->ops->hw_params) { +- ret = dai->driver->ops->hw_params(substream, params, dai); +- if (ret < 0) { +- dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", +- dai->name, ret); +- return ret; +- } +- } +- +- return 0; +-} +- + static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_component *last) + { +@@ -989,7 +959,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, + soc_pcm_codec_params_fixup(&codec_params, + codec_dai->rx_mask); + +- ret = soc_dai_hw_params(substream, &codec_params, codec_dai); ++ ret = snd_soc_dai_hw_params(codec_dai, substream, ++ &codec_params); + if(ret < 0) + goto codec_err; + +@@ -1001,7 +972,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, + snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); + } + +- ret = soc_dai_hw_params(substream, params, cpu_dai); ++ ret = snd_soc_dai_hw_params(cpu_dai, substream, params); + if (ret < 0) + goto interface_err; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0037-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_hw_free.patch b/packages/linux/patches/amlogic/amlogic-0037-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_hw_free.patch new file mode 100644 index 0000000000..9fd5397c94 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0037-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_hw_free.patch @@ -0,0 +1,117 @@ +From 739c1209f9e4b78b0a55111fbf341321c5731990 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:33:19 +0900 +Subject: [PATCH 037/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_hw_free() + +Current ALSA SoC is directly using dai->driver->ops->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_hw_free() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87y30qhn4w.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 846faaed9df7899e74311db3aec0a41a2f6bc345 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-dai.c | 7 +++++++ + sound/soc/soc-dapm.c | 7 ++----- + sound/soc/soc-pcm.c | 12 ++++-------- + 4 files changed, 15 insertions(+), 13 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 3773262a1b77..5222b6a758f2 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -148,6 +148,8 @@ int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); + int snd_soc_dai_hw_params(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); ++void snd_soc_dai_hw_free(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index f883d27d136f..39a685e6acd5 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -282,3 +282,10 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai, + + return 0; + } ++ ++void snd_soc_dai_hw_free(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream) ++{ ++ if (dai->driver->ops->hw_free) ++ dai->driver->ops->hw_free(substream, dai); ++} +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index e86a2d8d4f35..a9a717376767 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3900,9 +3900,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + +- if (source->driver->ops->hw_free) +- source->driver->ops->hw_free(&substream, +- source); ++ snd_soc_dai_hw_free(source, &substream); + + source->active--; + if (source->driver->ops->shutdown) +@@ -3914,8 +3912,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + +- if (sink->driver->ops->hw_free) +- sink->driver->ops->hw_free(&substream, sink); ++ snd_soc_dai_hw_free(sink, &substream); + + sink->active--; + if (sink->driver->ops->shutdown) +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 420cc94e0a46..58fc4e98ab59 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1011,8 +1011,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, + component_err: + soc_pcm_components_hw_free(substream, component); + +- if (cpu_dai->driver->ops->hw_free) +- cpu_dai->driver->ops->hw_free(substream, cpu_dai); ++ snd_soc_dai_hw_free(cpu_dai, substream); + cpu_dai->rate = 0; + + interface_err: +@@ -1023,8 +1022,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, + if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) + continue; + +- if (codec_dai->driver->ops->hw_free) +- codec_dai->driver->ops->hw_free(substream, codec_dai); ++ snd_soc_dai_hw_free(codec_dai, substream); + codec_dai->rate = 0; + } + +@@ -1083,12 +1081,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) + if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) + continue; + +- if (codec_dai->driver->ops->hw_free) +- codec_dai->driver->ops->hw_free(substream, codec_dai); ++ snd_soc_dai_hw_free(codec_dai, substream); + } + +- if (cpu_dai->driver->ops->hw_free) +- cpu_dai->driver->ops->hw_free(substream, cpu_dai); ++ snd_soc_dai_hw_free(cpu_dai, substream); + + mutex_unlock(&rtd->pcm_mutex); + return 0; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0038-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_startup.patch b/packages/linux/patches/amlogic/amlogic-0038-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_startup.patch new file mode 100644 index 0000000000..8edda73061 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0038-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_startup.patch @@ -0,0 +1,148 @@ +From 79486aea72e5af750bd0e66ef348b7195d882705 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:33:32 +0900 +Subject: [PATCH 038/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_startup() + +Current ALSA SoC is directly using dai->driver->ops->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_startup() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87wogahn4i.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 5a52a04531486e2ab069b7882432c8b266db36e6 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-dai.c | 11 +++++++++++ + sound/soc/soc-dapm.c | 28 ++++++++++------------------ + sound/soc/soc-pcm.c | 27 +++++++++++---------------- + 4 files changed, 34 insertions(+), 34 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 5222b6a758f2..0d16c5bb20bb 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -150,6 +150,8 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params); + void snd_soc_dai_hw_free(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); ++int snd_soc_dai_startup(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 39a685e6acd5..6e196636e42f 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -289,3 +289,14 @@ void snd_soc_dai_hw_free(struct snd_soc_dai *dai, + if (dai->driver->ops->hw_free) + dai->driver->ops->hw_free(substream, dai); + } ++ ++int snd_soc_dai_startup(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream) ++{ ++ int ret = 0; ++ ++ if (dai->driver->ops->startup) ++ ret = dai->driver->ops->startup(substream, dai); ++ ++ return ret; ++} +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index a9a717376767..07fe331bce94 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3830,15 +3830,11 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + +- if (source->driver->ops->startup) { +- ret = source->driver->ops->startup(&substream, +- source); +- if (ret < 0) { +- dev_err(source->dev, +- "ASoC: startup() failed: %d\n", +- ret); +- goto out; +- } ++ ret = snd_soc_dai_startup(source, &substream); ++ if (ret < 0) { ++ dev_err(source->dev, ++ "ASoC: startup() failed: %d\n", ret); ++ goto out; + } + source->active++; + ret = snd_soc_dai_hw_params(source, &substream, params); +@@ -3852,15 +3848,11 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + +- if (sink->driver->ops->startup) { +- ret = sink->driver->ops->startup(&substream, +- sink); +- if (ret < 0) { +- dev_err(sink->dev, +- "ASoC: startup() failed: %d\n", +- ret); +- goto out; +- } ++ ret = snd_soc_dai_startup(sink, &substream); ++ if (ret < 0) { ++ dev_err(sink->dev, ++ "ASoC: startup() failed: %d\n", ret); ++ goto out; + } + sink->active++; + ret = snd_soc_dai_hw_params(sink, &substream, params); +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 58fc4e98ab59..9c8713a3eef1 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -535,13 +535,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + + /* startup the audio subsystem */ +- if (cpu_dai->driver->ops->startup) { +- ret = cpu_dai->driver->ops->startup(substream, cpu_dai); +- if (ret < 0) { +- dev_err(cpu_dai->dev, "ASoC: can't open interface" +- " %s: %d\n", cpu_dai->name, ret); +- goto out; +- } ++ ret = snd_soc_dai_startup(cpu_dai, substream); ++ if (ret < 0) { ++ dev_err(cpu_dai->dev, "ASoC: can't open interface %s: %d\n", ++ cpu_dai->name, ret); ++ goto out; + } + + ret = soc_pcm_components_open(substream, &component); +@@ -549,15 +547,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) + goto component_err; + + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- if (codec_dai->driver->ops->startup) { +- ret = codec_dai->driver->ops->startup(substream, +- codec_dai); +- if (ret < 0) { +- dev_err(codec_dai->dev, +- "ASoC: can't open codec %s: %d\n", +- codec_dai->name, ret); +- goto codec_dai_err; +- } ++ ret = snd_soc_dai_startup(codec_dai, substream); ++ if (ret < 0) { ++ dev_err(codec_dai->dev, ++ "ASoC: can't open codec %s: %d\n", ++ codec_dai->name, ret); ++ goto codec_dai_err; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0039-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_shutdown.patch b/packages/linux/patches/amlogic/amlogic-0039-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_shutdown.patch new file mode 100644 index 0000000000..466e3735d5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0039-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_shutdown.patch @@ -0,0 +1,119 @@ +From 8e824fedd82f021536a4963d061b3171de15d3c6 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:33:39 +0900 +Subject: [PATCH 039/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_shutdown() + +Current ALSA SoC is directly using dai->driver->ops->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_shutdown() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87v9vuhn4b.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 330fcb5135e0588b1ea3b0bbab587d1317c1cf7b + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-dai.c | 7 +++++++ + sound/soc/soc-dapm.c | 7 ++----- + sound/soc/soc-pcm.c | 18 ++++++------------ + 4 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 0d16c5bb20bb..32545d457b3d 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -152,6 +152,8 @@ void snd_soc_dai_hw_free(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); + int snd_soc_dai_startup(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); ++void snd_soc_dai_shutdown(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 6e196636e42f..67ff6cc1fe02 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -300,3 +300,10 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, + + return ret; + } ++ ++void snd_soc_dai_shutdown(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream) ++{ ++ if (dai->driver->ops->shutdown) ++ dai->driver->ops->shutdown(substream, dai); ++} +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index 07fe331bce94..bf0481df870d 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3895,9 +3895,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + snd_soc_dai_hw_free(source, &substream); + + source->active--; +- if (source->driver->ops->shutdown) +- source->driver->ops->shutdown(&substream, +- source); ++ snd_soc_dai_shutdown(source, &substream); + } + + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; +@@ -3907,8 +3905,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + snd_soc_dai_hw_free(sink, &substream); + + sink->active--; +- if (sink->driver->ops->shutdown) +- sink->driver->ops->shutdown(&substream, sink); ++ snd_soc_dai_shutdown(sink, &substream); + } + break; + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 9c8713a3eef1..ed5ae23c7104 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -641,16 +641,13 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) + i = rtd->num_codecs; + + codec_dai_err: +- for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { +- if (codec_dai->driver->ops->shutdown) +- codec_dai->driver->ops->shutdown(substream, codec_dai); +- } ++ for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) ++ snd_soc_dai_shutdown(codec_dai, substream); + + component_err: + soc_pcm_components_close(substream, component); + +- if (cpu_dai->driver->ops->shutdown) +- cpu_dai->driver->ops->shutdown(substream, cpu_dai); ++ snd_soc_dai_shutdown(cpu_dai, substream); + out: + mutex_unlock(&rtd->pcm_mutex); + +@@ -728,13 +725,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) + + snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); + +- if (cpu_dai->driver->ops->shutdown) +- cpu_dai->driver->ops->shutdown(substream, cpu_dai); ++ snd_soc_dai_shutdown(cpu_dai, substream); + +- for_each_rtd_codec_dai(rtd, i, codec_dai) { +- if (codec_dai->driver->ops->shutdown) +- codec_dai->driver->ops->shutdown(substream, codec_dai); +- } ++ for_each_rtd_codec_dai(rtd, i, codec_dai) ++ snd_soc_dai_shutdown(codec_dai, substream); + + if (rtd->dai_link->ops->shutdown) + rtd->dai_link->ops->shutdown(substream); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0040-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_prepare.patch b/packages/linux/patches/amlogic/amlogic-0040-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_prepare.patch new file mode 100644 index 0000000000..aecc5d6945 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0040-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_prepare.patch @@ -0,0 +1,99 @@ +From 7b837045cc43ffcce0e6166c756680e54ce2f362 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:33:45 +0900 +Subject: [PATCH 040/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_prepare() + +Current ALSA SoC is directly using dai->driver->ops->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_prepare() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87tvbehn46.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 4beb8e109d30d339d44308a767dd6f5614492f3e + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-dai.c | 11 +++++++++++ + sound/soc/soc-pcm.c | 27 +++++++++++---------------- + 3 files changed, 24 insertions(+), 16 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 32545d457b3d..c7dff6a0b5b9 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -154,6 +154,8 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); + void snd_soc_dai_shutdown(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); ++int snd_soc_dai_prepare(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 67ff6cc1fe02..cb810888c563 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -307,3 +307,14 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, + if (dai->driver->ops->shutdown) + dai->driver->ops->shutdown(substream, dai); + } ++ ++int snd_soc_dai_prepare(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream) ++{ ++ int ret = 0; ++ ++ if (dai->driver->ops->prepare) ++ ret = dai->driver->ops->prepare(substream, dai); ++ ++ return ret; ++} +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index ed5ae23c7104..d7611af90dce 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -814,27 +814,22 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) + } + + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- if (codec_dai->driver->ops->prepare) { +- ret = codec_dai->driver->ops->prepare(substream, +- codec_dai); +- if (ret < 0) { +- dev_err(codec_dai->dev, +- "ASoC: codec DAI prepare error: %d\n", +- ret); +- goto out; +- } +- } +- } +- +- if (cpu_dai->driver->ops->prepare) { +- ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); ++ ret = snd_soc_dai_prepare(codec_dai, substream); + if (ret < 0) { +- dev_err(cpu_dai->dev, +- "ASoC: cpu DAI prepare error: %d\n", ret); ++ dev_err(codec_dai->dev, ++ "ASoC: codec DAI prepare error: %d\n", ++ ret); + goto out; + } + } + ++ ret = snd_soc_dai_prepare(cpu_dai, substream); ++ if (ret < 0) { ++ dev_err(cpu_dai->dev, ++ "ASoC: cpu DAI prepare error: %d\n", ret); ++ goto out; ++ } ++ + /* cancel any delayed stream shutdown that is pending */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + rtd->pop_wait) { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0041-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_trigger.patch b/packages/linux/patches/amlogic/amlogic-0041-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_trigger.patch new file mode 100644 index 0000000000..f01ff99537 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0041-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_trigger.patch @@ -0,0 +1,92 @@ +From 657967d6bb1642fcebcebba9f50839158f428130 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:33:51 +0900 +Subject: [PATCH 041/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_trigger() + +Current ALSA SoC is directly using dai->driver->ops->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_trigger() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87sgqyhn40.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 95aef35533844f35544851b0cdc1fc154b603307 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-dai.c | 12 ++++++++++++ + sound/soc/soc-pcm.c | 17 ++++++----------- + 3 files changed, 20 insertions(+), 11 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index c7dff6a0b5b9..72b8e76f1cc4 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -156,6 +156,8 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); + int snd_soc_dai_prepare(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); ++int snd_soc_dai_trigger(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream, int cmd); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index cb810888c563..18c447e169f6 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -318,3 +318,15 @@ int snd_soc_dai_prepare(struct snd_soc_dai *dai, + + return ret; + } ++ ++int snd_soc_dai_trigger(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream, ++ int cmd) ++{ ++ int ret = 0; ++ ++ if (dai->driver->ops->trigger) ++ ret = dai->driver->ops->trigger(substream, cmd, dai); ++ ++ return ret; ++} +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index d7611af90dce..a628b08f966e 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1084,12 +1084,9 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + int i, ret; + + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- if (codec_dai->driver->ops->trigger) { +- ret = codec_dai->driver->ops->trigger(substream, +- cmd, codec_dai); +- if (ret < 0) +- return ret; +- } ++ ret = snd_soc_dai_trigger(codec_dai, substream, cmd); ++ if (ret < 0) ++ return ret; + } + + for_each_rtdcom(rtd, rtdcom) { +@@ -1104,11 +1101,9 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + return ret; + } + +- if (cpu_dai->driver->ops->trigger) { +- ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); +- if (ret < 0) +- return ret; +- } ++ snd_soc_dai_trigger(cpu_dai, substream, cmd); ++ if (ret < 0) ++ return ret; + + if (rtd->dai_link->ops->trigger) { + ret = rtd->dai_link->ops->trigger(substream, cmd); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0042-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_bespoke_trigger.patch b/packages/linux/patches/amlogic/amlogic-0042-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_bespoke_trigger.patch new file mode 100644 index 0000000000..39246c7e0a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0042-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_bespoke_trigger.patch @@ -0,0 +1,88 @@ +From c7fef0a5672740f7fed5b42a16c15b1b6ec96e82 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:33:56 +0900 +Subject: [PATCH 042/186] FROMGIT: ASoC: soc-dai: add + snd_soc_dai_bespoke_trigger() + +Current ALSA SoC is directly using dai->driver->ops->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_bespoke_trigger() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87r26ihn3u.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 5c0769af4caf8fbdad2e9c0051ab0081b8e22b0a + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-dai.c | 12 ++++++++++++ + sound/soc/soc-pcm.c | 16 ++++++---------- + 3 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 72b8e76f1cc4..6a5566d459ad 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -158,6 +158,8 @@ int snd_soc_dai_prepare(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); + int snd_soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); ++int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream, int cmd); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 18c447e169f6..6f466cfcbeef 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -330,3 +330,15 @@ int snd_soc_dai_trigger(struct snd_soc_dai *dai, + + return ret; + } ++ ++int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream, ++ int cmd) ++{ ++ int ret = 0; ++ ++ if (dai->driver->ops->bespoke_trigger) ++ ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai); ++ ++ return ret; ++} +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index a628b08f966e..a10627f1ceff 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1123,19 +1123,15 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, + int i, ret; + + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- if (codec_dai->driver->ops->bespoke_trigger) { +- ret = codec_dai->driver->ops->bespoke_trigger(substream, +- cmd, codec_dai); +- if (ret < 0) +- return ret; +- } +- } +- +- if (cpu_dai->driver->ops->bespoke_trigger) { +- ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); ++ ret = snd_soc_dai_bespoke_trigger(codec_dai, substream, cmd); + if (ret < 0) + return ret; + } ++ ++ snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd); ++ if (ret < 0) ++ return ret; ++ + return 0; + } + /* +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0043-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_delay.patch b/packages/linux/patches/amlogic/amlogic-0043-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_delay.patch new file mode 100644 index 0000000000..6ac7ad6102 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0043-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_delay.patch @@ -0,0 +1,78 @@ +From 7bd44b68e358463510633ef365862b41e5befede Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:34:09 +0900 +Subject: [PATCH 043/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_delay() + +Current ALSA SoC is directly using dai->driver->ops->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_delay() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87o91mhn3i.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 1dea80d4b2bd3b53c58f008ca2bcd73182583711 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-dai.c | 11 +++++++++++ + sound/soc/soc-pcm.c | 9 +++------ + 3 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 6a5566d459ad..7cfed3034511 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -160,6 +160,8 @@ int snd_soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); + int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); ++snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 6f466cfcbeef..5b5b979cd1f3 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -342,3 +342,14 @@ int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + + return ret; + } ++ ++snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, ++ struct snd_pcm_substream *substream) ++{ ++ int delay = 0; ++ ++ if (dai->driver->ops->delay) ++ delay = dai->driver->ops->delay(substream, dai); ++ ++ return delay; ++} +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index a10627f1ceff..f3137723301c 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1169,14 +1169,11 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) + /* base delay if assigned in pointer callback */ + delay = runtime->delay; + +- if (cpu_dai->driver->ops->delay) +- delay += cpu_dai->driver->ops->delay(substream, cpu_dai); ++ delay += snd_soc_dai_delay(cpu_dai, substream); + + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- if (codec_dai->driver->ops->delay) +- codec_delay = max(codec_delay, +- codec_dai->driver->ops->delay(substream, +- codec_dai)); ++ codec_delay = max(codec_delay, ++ snd_soc_dai_delay(codec_dai, substream)); + } + delay += codec_delay; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0044-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_suspend.patch b/packages/linux/patches/amlogic/amlogic-0044-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_suspend.patch new file mode 100644 index 0000000000..3910f37d55 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0044-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_suspend.patch @@ -0,0 +1,76 @@ +From 215effc50526e67beb8744170d9528ab094fee66 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:34:29 +0900 +Subject: [PATCH 044/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_suspend() + +Current ALSA SoC is directly using dai->driver->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_suspend() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87muh6hn2x.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit e0f2262292d0c8160cfd9a8c40425107fb65ab29 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 1 + + sound/soc/soc-core.c | 8 ++++---- + sound/soc/soc-dai.c | 6 ++++++ + 3 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 7cfed3034511..6c5604a7dbc2 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -162,6 +162,7 @@ int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); + snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); ++void snd_soc_dai_suspend(struct snd_soc_dai *dai); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index a8d2c4ec0ec9..1060836b63fb 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -511,8 +511,8 @@ int snd_soc_suspend(struct device *dev) + if (rtd->dai_link->ignore_suspend) + continue; + +- if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) +- cpu_dai->driver->suspend(cpu_dai); ++ if (!cpu_dai->driver->bus_control) ++ snd_soc_dai_suspend(cpu_dai); + } + + /* close any waiting streams */ +@@ -584,8 +584,8 @@ int snd_soc_suspend(struct device *dev) + if (rtd->dai_link->ignore_suspend) + continue; + +- if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) +- cpu_dai->driver->suspend(cpu_dai); ++ if (cpu_dai->driver->bus_control) ++ snd_soc_dai_suspend(cpu_dai); + + /* deactivate pins to sleep state */ + pinctrl_pm_select_sleep_state(cpu_dai->dev); +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 5b5b979cd1f3..3373598e0682 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -353,3 +353,9 @@ snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + + return delay; + } ++ ++void snd_soc_dai_suspend(struct snd_soc_dai *dai) ++{ ++ if (dai->driver->suspend) ++ dai->driver->suspend(dai); ++} +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0045-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_resume.patch b/packages/linux/patches/amlogic/amlogic-0045-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_resume.patch new file mode 100644 index 0000000000..c250967be1 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0045-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_resume.patch @@ -0,0 +1,76 @@ +From b756a9e8916d2c52eff076b01b56337e0cccfb9b Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:34:43 +0900 +Subject: [PATCH 045/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_resume() + +Current ALSA SoC is directly using dai->driver->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_resume() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87lfwqhn2j.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 24b09d051164680f0a1d1910efe21ce36ad5c1ca + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 1 + + sound/soc/soc-core.c | 8 ++++---- + sound/soc/soc-dai.c | 6 ++++++ + 3 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 6c5604a7dbc2..ed78e34a814e 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -163,6 +163,7 @@ int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); + void snd_soc_dai_suspend(struct snd_soc_dai *dai); ++void snd_soc_dai_resume(struct snd_soc_dai *dai); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index 1060836b63fb..c08d4fff01a6 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -631,8 +631,8 @@ static void soc_resume_deferred(struct work_struct *work) + if (rtd->dai_link->ignore_suspend) + continue; + +- if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) +- cpu_dai->driver->resume(cpu_dai); ++ if (cpu_dai->driver->bus_control) ++ snd_soc_dai_resume(cpu_dai); + } + + for_each_card_components(card, component) { +@@ -678,8 +678,8 @@ static void soc_resume_deferred(struct work_struct *work) + if (rtd->dai_link->ignore_suspend) + continue; + +- if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) +- cpu_dai->driver->resume(cpu_dai); ++ if (!cpu_dai->driver->bus_control) ++ snd_soc_dai_resume(cpu_dai); + } + + if (card->resume_post) +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 3373598e0682..ddb6f217c0ed 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -359,3 +359,9 @@ void snd_soc_dai_suspend(struct snd_soc_dai *dai) + if (dai->driver->suspend) + dai->driver->suspend(dai); + } ++ ++void snd_soc_dai_resume(struct snd_soc_dai *dai) ++{ ++ if (dai->driver->resume) ++ dai->driver->resume(dai); ++} +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0046-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_probe.patch b/packages/linux/patches/amlogic/amlogic-0046-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_probe.patch new file mode 100644 index 0000000000..a6c80257e2 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0046-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_probe.patch @@ -0,0 +1,81 @@ +From ce0aa1837af6ec9964c313f381406c72c697965a Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:34:56 +0900 +Subject: [PATCH 046/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_probe() + +Current ALSA SoC is directly using dai->driver->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_probe() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87k1cahn26.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit cfd9b5fbfe1e8763018aea2600aa0d6ff015ebfc + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 1 + + sound/soc/soc-core.c | 15 +++++++-------- + sound/soc/soc-dai.c | 7 +++++++ + 3 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index ed78e34a814e..da8d8b889089 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -164,6 +164,7 @@ snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); + void snd_soc_dai_suspend(struct snd_soc_dai *dai); + void snd_soc_dai_resume(struct snd_soc_dai *dai); ++int snd_soc_dai_probe(struct snd_soc_dai *dai); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index c08d4fff01a6..d78f132174b1 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -1434,18 +1434,17 @@ static int soc_probe_link_components(struct snd_soc_card *card, + + static int soc_probe_dai(struct snd_soc_dai *dai, int order) + { ++ int ret; ++ + if (dai->probed || + dai->driver->probe_order != order) + return 0; + +- if (dai->driver->probe) { +- int ret = dai->driver->probe(dai); +- +- if (ret < 0) { +- dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", +- dai->name, ret); +- return ret; +- } ++ ret = snd_soc_dai_probe(dai); ++ if (ret < 0) { ++ dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", ++ dai->name, ret); ++ return ret; + } + + dai->probed = 1; +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index ddb6f217c0ed..55c1fac99613 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -365,3 +365,10 @@ void snd_soc_dai_resume(struct snd_soc_dai *dai) + if (dai->driver->resume) + dai->driver->resume(dai); + } ++ ++int snd_soc_dai_probe(struct snd_soc_dai *dai) ++{ ++ if (dai->driver->probe) ++ return dai->driver->probe(dai); ++ return 0; ++} +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0047-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_remove.patch b/packages/linux/patches/amlogic/amlogic-0047-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_remove.patch new file mode 100644 index 0000000000..16b6214cc0 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0047-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_remove.patch @@ -0,0 +1,75 @@ +From c94cf46d290db59db9f694a8e761f7876963c802 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:35:05 +0900 +Subject: [PATCH 047/186] FROMGIT: ASoC: soc-dai: add snd_soc_dai_remove() + +Current ALSA SoC is directly using dai->driver->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_remvoe() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87imruhn1x.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit dcdab5820edd6123911dbd767ee1e389008b6a83 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 1 + + sound/soc/soc-core.c | 13 ++++++------- + sound/soc/soc-dai.c | 7 +++++++ + 3 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index da8d8b889089..2a11f177ce01 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -165,6 +165,7 @@ snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + void snd_soc_dai_suspend(struct snd_soc_dai *dai); + void snd_soc_dai_resume(struct snd_soc_dai *dai); + int snd_soc_dai_probe(struct snd_soc_dai *dai); ++int snd_soc_dai_remove(struct snd_soc_dai *dai); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index d78f132174b1..8a55735c4311 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -992,13 +992,12 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) + dai->driver->remove_order != order) + return; + +- if (dai->driver->remove) { +- err = dai->driver->remove(dai); +- if (err < 0) +- dev_err(dai->dev, +- "ASoC: failed to remove %s: %d\n", +- dai->name, err); +- } ++ err = snd_soc_dai_remove(dai); ++ if (err < 0) ++ dev_err(dai->dev, ++ "ASoC: failed to remove %s: %d\n", ++ dai->name, err); ++ + dai->probed = 0; + } + +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 55c1fac99613..384765c747da 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -372,3 +372,10 @@ int snd_soc_dai_probe(struct snd_soc_dai *dai) + return dai->driver->probe(dai); + return 0; + } ++ ++int snd_soc_dai_remove(struct snd_soc_dai *dai) ++{ ++ if (dai->driver->remove) ++ return dai->driver->remove(dai); ++ return 0; ++} +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0048-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_compress_new.patch b/packages/linux/patches/amlogic/amlogic-0048-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_compress_new.patch new file mode 100644 index 0000000000..8b792f1d63 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0048-FROMGIT-ASoC-soc-dai-add-snd_soc_dai_compress_new.patch @@ -0,0 +1,82 @@ +From 97003da8c2d39f2eef55f82b5a226871d6831ae6 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:35:29 +0900 +Subject: [PATCH 048/186] FROMGIT: ASoC: soc-dai: add + snd_soc_dai_compress_new() + +Current ALSA SoC is directly using dai->driver->xxx, +thus, it has deep nested bracket, and it makes code unreadable. +This patch adds new snd_soc_dai_compress_new() and use it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87h87ehn1a.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit b423c4202135f7794e0a9c55a884f5933d8e7156 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 2 ++ + sound/soc/soc-core.c | 15 ++++++++------- + sound/soc/soc-dai.c | 8 ++++++++ + 3 files changed, 18 insertions(+), 7 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 2a11f177ce01..0f8b09520020 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -166,6 +166,8 @@ void snd_soc_dai_suspend(struct snd_soc_dai *dai); + void snd_soc_dai_resume(struct snd_soc_dai *dai); + int snd_soc_dai_probe(struct snd_soc_dai *dai); + int snd_soc_dai_remove(struct snd_soc_dai *dai); ++int snd_soc_dai_compress_new(struct snd_soc_dai *dai, ++ struct snd_soc_pcm_runtime *rtd, int num); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index 8a55735c4311..33df0dfe29f0 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -1548,15 +1548,16 @@ static int soc_probe_link_dais(struct snd_soc_card *card, + num = rtd->dai_link->id; + } + +- if (cpu_dai->driver->compress_new) { +- /* create compress_device" */ +- ret = cpu_dai->driver->compress_new(rtd, num); +- if (ret < 0) { ++ /* create compress_device if possible */ ++ ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); ++ if (ret != -ENOTSUPP) { ++ if (ret < 0) + dev_err(card->dev, "ASoC: can't create compress %s\n", + dai_link->stream_name); +- return ret; +- } +- } else if (!dai_link->params) { ++ return ret; ++ } ++ ++ if (!dai_link->params) { + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index 384765c747da..e6f161b9f975 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -379,3 +379,11 @@ int snd_soc_dai_remove(struct snd_soc_dai *dai) + return dai->driver->remove(dai); + return 0; + } ++ ++int snd_soc_dai_compress_new(struct snd_soc_dai *dai, ++ struct snd_soc_pcm_runtime *rtd, int num) ++{ ++ if (dai->driver->compress_new) ++ return dai->driver->compress_new(rtd, num); ++ return -ENOTSUPP; ++} +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0049-FROMGIT-ASoC-soc-dai-move-snd_soc_dai_stream_valid-t.patch b/packages/linux/patches/amlogic/amlogic-0049-FROMGIT-ASoC-soc-dai-move-snd_soc_dai_stream_valid-t.patch new file mode 100644 index 0000000000..79d0d74e7f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0049-FROMGIT-ASoC-soc-dai-move-snd_soc_dai_stream_valid-t.patch @@ -0,0 +1,172 @@ +From 66ef91fbbccf3e259e77e1a83dcc8717565cb65f Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Mon, 22 Jul 2019 10:36:16 +0900 +Subject: [PATCH 049/186] FROMGIT: ASoC: soc-dai: move + snd_soc_dai_stream_valid() to soc-dai.c + +snd_soc_dai_stream_valid() is function to check stream validity. +But, some code is using it, some code are checking stream->channels_min +directly. Doing samethings by different method is confusable. +This patch uses same funcntion for same purpose. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87ftmyhmzz.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit 467fece8fbc6774a3a3bd0981e1a342fb5022706 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + include/sound/soc-dai.h | 1 + + sound/soc/soc-compress.c | 9 ++++----- + sound/soc/soc-dai.c | 18 ++++++++++++++++++ + sound/soc/soc-pcm.c | 39 ++++++++++----------------------------- + 4 files changed, 33 insertions(+), 34 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 0f8b09520020..dc48fe081a20 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -168,6 +168,7 @@ int snd_soc_dai_probe(struct snd_soc_dai *dai); + int snd_soc_dai_remove(struct snd_soc_dai *dai); + int snd_soc_dai_compress_new(struct snd_soc_dai *dai, + struct snd_soc_pcm_runtime *rtd, int num); ++bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream); + + struct snd_soc_dai_ops { + /* +diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c +index ddef4ff677ce..289211069a1e 100644 +--- a/sound/soc/soc-compress.c ++++ b/sound/soc/soc-compress.c +@@ -872,14 +872,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) + } + + /* check client and interface hw capabilities */ +- if (codec_dai->driver->playback.channels_min) ++ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && ++ snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) + playback = 1; +- if (codec_dai->driver->capture.channels_min) ++ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && ++ snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) + capture = 1; + +- capture = capture && cpu_dai->driver->capture.channels_min; +- playback = playback && cpu_dai->driver->playback.channels_min; +- + /* + * Compress devices are unidirectional so only one of the directions + * should be set, check for that (xor) +diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c +index e6f161b9f975..1c7f63871c1d 100644 +--- a/sound/soc/soc-dai.c ++++ b/sound/soc/soc-dai.c +@@ -387,3 +387,21 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai, + return dai->driver->compress_new(rtd, num); + return -ENOTSUPP; + } ++ ++/* ++ * snd_soc_dai_stream_valid() - check if a DAI supports the given stream ++ * ++ * Returns true if the DAI supports the indicated stream type. ++ */ ++bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir) ++{ ++ struct snd_soc_pcm_stream *stream; ++ ++ if (dir == SNDRV_PCM_STREAM_PLAYBACK) ++ stream = &dai->driver->playback; ++ else ++ stream = &dai->driver->capture; ++ ++ /* If the codec specifies any channels at all, it supports the stream */ ++ return stream->channels_min; ++} +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index f3137723301c..fabeac164a6c 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -29,24 +29,6 @@ + + #define DPCM_MAX_BE_USERS 8 + +-/* +- * snd_soc_dai_stream_valid() - check if a DAI supports the given stream +- * +- * Returns true if the DAI supports the indicated stream type. +- */ +-static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) +-{ +- struct snd_soc_pcm_stream *codec_stream; +- +- if (stream == SNDRV_PCM_STREAM_PLAYBACK) +- codec_stream = &dai->driver->playback; +- else +- codec_stream = &dai->driver->capture; +- +- /* If the codec specifies any channels at all, it supports the stream */ +- return codec_stream->channels_min; +-} +- + /** + * snd_soc_runtime_activate() - Increment active count for PCM runtime components + * @rtd: ASoC PCM runtime that is activated +@@ -2688,8 +2670,8 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) + new ? "new" : "old", fe->dai_link->name); + + /* skip if FE doesn't have playback capability */ +- if (!fe->cpu_dai->driver->playback.channels_min || +- !fe->codec_dai->driver->playback.channels_min) ++ if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK) || ++ !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_PLAYBACK)) + goto capture; + + /* skip if FE isn't currently playing */ +@@ -2719,8 +2701,8 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) + + capture: + /* skip if FE doesn't have capture capability */ +- if (!fe->cpu_dai->driver->capture.channels_min || +- !fe->codec_dai->driver->capture.channels_min) ++ if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE) || ++ !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_CAPTURE)) + return 0; + + /* skip if FE isn't currently capturing */ +@@ -3030,14 +3012,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) + capture = rtd->dai_link->dpcm_capture; + } else { + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- if (codec_dai->driver->playback.channels_min) ++ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && ++ snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) + playback = 1; +- if (codec_dai->driver->capture.channels_min) ++ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && ++ snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) + capture = 1; + } +- +- capture = capture && cpu_dai->driver->capture.channels_min; +- playback = playback && cpu_dai->driver->playback.channels_min; + } + + if (rtd->dai_link->playback_only) { +@@ -3375,11 +3356,11 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, + if (!buf) + return -ENOMEM; + +- if (fe->cpu_dai->driver->playback.channels_min) ++ if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) + offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, + buf + offset, out_count - offset); + +- if (fe->cpu_dai->driver->capture.channels_min) ++ if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) + offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, + buf + offset, out_count - offset); + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0050-FROMGIT-ASoC-codec2codec-run-callbacks-in-order.patch b/packages/linux/patches/amlogic/amlogic-0050-FROMGIT-ASoC-codec2codec-run-callbacks-in-order.patch new file mode 100644 index 0000000000..a4c27e25ec --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0050-FROMGIT-ASoC-codec2codec-run-callbacks-in-order.patch @@ -0,0 +1,93 @@ +From bbb30231a2b10c7f5b76066946a3ee6328e35608 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 25 Jul 2019 18:59:44 +0200 +Subject: [PATCH 050/186] FROMGIT: ASoC: codec2codec: run callbacks in order + +When handling dai_link events on codec to codec links, run all .startup() +callbacks on sinks and sources before running any .hw_params(). Same goes +for hw_free() and shutdown(). This is closer to the behavior of regular +dai links + +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20190725165949.29699-2-jbrunet@baylibre.com +Signed-off-by: Mark Brown +(cherry picked from commit 68c907f10cd816cad2287167a1a1d77914a6d466 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-dapm.c | 36 +++++++++++++++++++++++++++--------- + 1 file changed, 27 insertions(+), 9 deletions(-) + +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index bf0481df870d..6d84aac8b54c 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3837,11 +3837,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + goto out; + } + source->active++; +- ret = snd_soc_dai_hw_params(source, &substream, params); +- if (ret < 0) +- goto out; +- +- dapm_update_dai_unlocked(&substream, params, source); + } + + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; +@@ -3855,6 +3850,23 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + goto out; + } + sink->active++; ++ } ++ ++ substream.stream = SNDRV_PCM_STREAM_CAPTURE; ++ snd_soc_dapm_widget_for_each_source_path(w, path) { ++ source = path->source->priv; ++ ++ ret = snd_soc_dai_hw_params(source, &substream, params); ++ if (ret < 0) ++ goto out; ++ ++ dapm_update_dai_unlocked(&substream, params, source); ++ } ++ ++ substream.stream = SNDRV_PCM_STREAM_PLAYBACK; ++ snd_soc_dapm_widget_for_each_sink_path(w, path) { ++ sink = path->sink->priv; ++ + ret = snd_soc_dai_hw_params(sink, &substream, params); + if (ret < 0) + goto out; +@@ -3891,9 +3903,18 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; +- + snd_soc_dai_hw_free(source, &substream); ++ } ++ ++ substream.stream = SNDRV_PCM_STREAM_PLAYBACK; ++ snd_soc_dapm_widget_for_each_sink_path(w, path) { ++ sink = path->sink->priv; ++ snd_soc_dai_hw_free(sink, &substream); ++ } + ++ substream.stream = SNDRV_PCM_STREAM_CAPTURE; ++ snd_soc_dapm_widget_for_each_source_path(w, path) { ++ source = path->source->priv; + source->active--; + snd_soc_dai_shutdown(source, &substream); + } +@@ -3901,9 +3922,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; +- +- snd_soc_dai_hw_free(sink, &substream); +- + sink->active--; + snd_soc_dai_shutdown(sink, &substream); + } +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0051-FROMGIT-ASoC-codec2codec-name-link-using-stream-dire.patch b/packages/linux/patches/amlogic/amlogic-0051-FROMGIT-ASoC-codec2codec-name-link-using-stream-dire.patch new file mode 100644 index 0000000000..ac29004739 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0051-FROMGIT-ASoC-codec2codec-name-link-using-stream-dire.patch @@ -0,0 +1,77 @@ +From 4073a9679c656970bd3e13045a059045dd81023e Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 25 Jul 2019 18:59:45 +0200 +Subject: [PATCH 051/186] FROMGIT: ASoC: codec2codec: name link using stream + direction + +At the moment, codec to codec dai link widgets are named after the +cpu dai and the 1st codec valid on the link. This might be confusing +if there is multiple valid codecs on the link for one stream +direction. + +Instead, use the dai link name and the stream direction to name the +the dai link widget + +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20190725165949.29699-3-jbrunet@baylibre.com +Signed-off-by: Mark Brown +(cherry picked from commit 054d65004c6a008dfefbdae4fc1b46a3ad4e94c1 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-dapm.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index 6d84aac8b54c..17286bfec258 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -4058,8 +4058,7 @@ snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card, + + static struct snd_soc_dapm_widget * + snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, +- struct snd_soc_dapm_widget *source, +- struct snd_soc_dapm_widget *sink) ++ char *id) + { + struct snd_soc_dapm_widget template; + struct snd_soc_dapm_widget *w; +@@ -4069,7 +4068,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, + int ret; + + link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s", +- source->name, sink->name); ++ rtd->dai_link->name, id); + if (!link_name) + return ERR_PTR(-ENOMEM); + +@@ -4249,15 +4248,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, + } + + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- + /* connect BE DAI playback if widgets are valid */ + codec = codec_dai->playback_widget; + + if (playback_cpu && codec) { + if (!playback) { + playback = snd_soc_dapm_new_dai(card, rtd, +- playback_cpu, +- codec); ++ "playback"); + if (IS_ERR(playback)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", +@@ -4286,8 +4283,7 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, + if (codec && capture_cpu) { + if (!capture) { + capture = snd_soc_dapm_new_dai(card, rtd, +- codec, +- capture_cpu); ++ "capture"); + if (IS_ERR(capture)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0052-FROMGIT-ASoC-codec2codec-deal-with-params-when-neces.patch b/packages/linux/patches/amlogic/amlogic-0052-FROMGIT-ASoC-codec2codec-deal-with-params-when-neces.patch new file mode 100644 index 0000000000..29da8b10f0 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0052-FROMGIT-ASoC-codec2codec-deal-with-params-when-neces.patch @@ -0,0 +1,239 @@ +From ba8f6ce6d234a44e9746735174f3c80b649a4e19 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 25 Jul 2019 18:59:46 +0200 +Subject: [PATCH 052/186] FROMGIT: ASoC: codec2codec: deal with params when + necessary + +When there is an event on codec to codec dai_link, we only need to deal +with params if the event is SND_SOC_DAPM_PRE_PMU, when .hw_params() is +called. For the other events, it is useless. + +Also, dealing with the codec to codec params just before calling +.hw_params() callbacks give change to either party on the link to alter +params content in .startup(), which might be useful in some cases + +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20190725165949.29699-4-jbrunet@baylibre.com +Signed-off-by: Mark Brown +(cherry picked from commit 3dcfb397dad2ad55bf50de3c5d5a57090d35a18a + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-dapm.c | 159 +++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 67 deletions(-) + +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index 17286bfec258..be9bb05b0165 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3766,25 +3766,59 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, + } + EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); + +-static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, +- struct snd_kcontrol *kcontrol, int event) ++static int ++snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, ++ struct snd_pcm_substream *substream) + { + struct snd_soc_dapm_path *path; + struct snd_soc_dai *source, *sink; +- struct snd_soc_pcm_runtime *rtd = w->priv; +- const struct snd_soc_pcm_stream *config; +- struct snd_pcm_substream substream; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_hw_params *params = NULL; +- struct snd_pcm_runtime *runtime = NULL; ++ const struct snd_soc_pcm_stream *config = NULL; + unsigned int fmt; +- int ret = 0; ++ int ret; + +- config = rtd->dai_link->params + rtd->params_select; ++ params = kzalloc(sizeof(*params), GFP_KERNEL); ++ if (!params) ++ return -ENOMEM; + +- if (WARN_ON(!config) || +- WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || +- list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) +- return -EINVAL; ++ substream->stream = SNDRV_PCM_STREAM_CAPTURE; ++ snd_soc_dapm_widget_for_each_source_path(w, path) { ++ source = path->source->priv; ++ ++ ret = snd_soc_dai_startup(source, substream); ++ if (ret < 0) { ++ dev_err(source->dev, ++ "ASoC: startup() failed: %d\n", ret); ++ goto out; ++ } ++ source->active++; ++ } ++ ++ substream->stream = SNDRV_PCM_STREAM_PLAYBACK; ++ snd_soc_dapm_widget_for_each_sink_path(w, path) { ++ sink = path->sink->priv; ++ ++ ret = snd_soc_dai_startup(sink, substream); ++ if (ret < 0) { ++ dev_err(sink->dev, ++ "ASoC: startup() failed: %d\n", ret); ++ goto out; ++ } ++ sink->active++; ++ } ++ ++ /* ++ * Note: getting the config after .startup() gives a chance to ++ * either party on the link to alter the configuration if ++ * necessary ++ */ ++ config = rtd->dai_link->params + rtd->params_select; ++ if (WARN_ON(!config)) { ++ dev_err(w->dapm->dev, "ASoC: link config missing\n"); ++ ret = -EINVAL; ++ goto out; ++ } + + /* Be a little careful as we don't want to overflow the mask array */ + if (config->formats) { +@@ -3792,27 +3826,62 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + } else { + dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", + config->formats); +- fmt = 0; +- } + +- /* Currently very limited parameter selection */ +- params = kzalloc(sizeof(*params), GFP_KERNEL); +- if (!params) { +- ret = -ENOMEM; ++ ret = -EINVAL; + goto out; + } +- snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); + ++ snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = + config->rate_min; + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = + config->rate_max; +- + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min + = config->channels_min; + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max + = config->channels_max; + ++ substream->stream = SNDRV_PCM_STREAM_CAPTURE; ++ snd_soc_dapm_widget_for_each_source_path(w, path) { ++ source = path->source->priv; ++ ++ ret = snd_soc_dai_hw_params(source, substream, params); ++ if (ret < 0) ++ goto out; ++ ++ dapm_update_dai_unlocked(substream, params, source); ++ } ++ ++ substream->stream = SNDRV_PCM_STREAM_PLAYBACK; ++ snd_soc_dapm_widget_for_each_sink_path(w, path) { ++ sink = path->sink->priv; ++ ++ ret = snd_soc_dai_hw_params(sink, substream, params); ++ if (ret < 0) ++ goto out; ++ ++ dapm_update_dai_unlocked(substream, params, sink); ++ } ++ ++out: ++ kfree(params); ++ return 0; ++} ++ ++static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_dapm_path *path; ++ struct snd_soc_dai *source, *sink; ++ struct snd_soc_pcm_runtime *rtd = w->priv; ++ struct snd_pcm_substream substream; ++ struct snd_pcm_runtime *runtime = NULL; ++ int ret = 0; ++ ++ if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || ++ list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) ++ return -EINVAL; ++ + memset(&substream, 0, sizeof(substream)); + + /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ +@@ -3826,53 +3895,10 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: +- substream.stream = SNDRV_PCM_STREAM_CAPTURE; +- snd_soc_dapm_widget_for_each_source_path(w, path) { +- source = path->source->priv; +- +- ret = snd_soc_dai_startup(source, &substream); +- if (ret < 0) { +- dev_err(source->dev, +- "ASoC: startup() failed: %d\n", ret); +- goto out; +- } +- source->active++; +- } +- +- substream.stream = SNDRV_PCM_STREAM_PLAYBACK; +- snd_soc_dapm_widget_for_each_sink_path(w, path) { +- sink = path->sink->priv; +- +- ret = snd_soc_dai_startup(sink, &substream); +- if (ret < 0) { +- dev_err(sink->dev, +- "ASoC: startup() failed: %d\n", ret); +- goto out; +- } +- sink->active++; +- } +- +- substream.stream = SNDRV_PCM_STREAM_CAPTURE; +- snd_soc_dapm_widget_for_each_source_path(w, path) { +- source = path->source->priv; +- +- ret = snd_soc_dai_hw_params(source, &substream, params); +- if (ret < 0) +- goto out; +- +- dapm_update_dai_unlocked(&substream, params, source); +- } +- +- substream.stream = SNDRV_PCM_STREAM_PLAYBACK; +- snd_soc_dapm_widget_for_each_sink_path(w, path) { +- sink = path->sink->priv; +- +- ret = snd_soc_dai_hw_params(sink, &substream, params); +- if (ret < 0) +- goto out; ++ ret = snd_soc_dai_link_event_pre_pmu(w, &substream); ++ if (ret < 0) ++ goto out; + +- dapm_update_dai_unlocked(&substream, params, sink); +- } + break; + + case SND_SOC_DAPM_POST_PMU: +@@ -3934,7 +3960,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + + out: + kfree(runtime); +- kfree(params); + return ret; + } + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0053-FROMGIT-ASoC-meson-g12a-tohdmitx-override-codec2code.patch b/packages/linux/patches/amlogic/amlogic-0053-FROMGIT-ASoC-meson-g12a-tohdmitx-override-codec2code.patch new file mode 100644 index 0000000000..3a98dd2b56 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0053-FROMGIT-ASoC-meson-g12a-tohdmitx-override-codec2code.patch @@ -0,0 +1,96 @@ +From 13440dd12851a643c267aa0b2c64c9552133aea3 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 29 Jul 2019 10:01:39 +0200 +Subject: [PATCH 053/186] FROMGIT: ASoC: meson: g12a-tohdmitx: override + codec2codec params + +So far, forwarding the hw_params of the input to output relied on the +.hw_params() callback of the cpu side of the codec2codec link to be called +first. This is a bit weak. + +Instead, override the stream params of the codec2codec to link to set it up +correctly. + +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20190729080139.32068-1-jbrunet@baylibre.com +Signed-off-by: Mark Brown +(cherry picked from commit 2c4956bc1e9062e5e3c5ea7612294f24e6d4fbdd + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/g12a-tohdmitx.c | 34 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 18 deletions(-) + +diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c +index 707ccb192e4c..9943c807ec5d 100644 +--- a/sound/soc/meson/g12a-tohdmitx.c ++++ b/sound/soc/meson/g12a-tohdmitx.c +@@ -28,7 +28,7 @@ + #define CTRL0_SPDIF_CLK_SEL BIT(0) + + struct g12a_tohdmitx_input { +- struct snd_pcm_hw_params params; ++ struct snd_soc_pcm_stream params; + unsigned int fmt; + }; + +@@ -225,26 +225,17 @@ static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream, + { + struct g12a_tohdmitx_input *data = dai->playback_dma_data; + +- /* Save the stream params for the downstream link */ +- memcpy(&data->params, params, sizeof(*params)); ++ data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params)); ++ data->params.rate_min = params_rate(params); ++ data->params.rate_max = params_rate(params); ++ data->params.formats = 1 << params_format(params); ++ data->params.channels_min = params_channels(params); ++ data->params.channels_max = params_channels(params); ++ data->params.sig_bits = dai->driver->playback.sig_bits; + + return 0; + } + +-static int g12a_tohdmitx_output_hw_params(struct snd_pcm_substream *substream, +- struct snd_pcm_hw_params *params, +- struct snd_soc_dai *dai) +-{ +- struct g12a_tohdmitx_input *in_data = +- g12a_tohdmitx_get_input_data(dai->capture_widget); +- +- if (!in_data) +- return -ENODEV; +- +- memcpy(params, &in_data->params, sizeof(*params)); +- +- return 0; +-} + + static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +@@ -266,6 +257,14 @@ static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream, + if (!in_data) + return -ENODEV; + ++ if (WARN_ON(!rtd->dai_link->params)) { ++ dev_warn(dai->dev, "codec2codec link expected\n"); ++ return -EINVAL; ++ } ++ ++ /* Replace link params with the input params */ ++ rtd->dai_link->params = &in_data->params; ++ + if (!in_data->fmt) + return 0; + +@@ -278,7 +277,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { + }; + + static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { +- .hw_params = g12a_tohdmitx_output_hw_params, + .startup = g12a_tohdmitx_output_startup, + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0054-FROMGIT-ASoC-create-pcm-for-codec2codec-links-as-wel.patch b/packages/linux/patches/amlogic/amlogic-0054-FROMGIT-ASoC-create-pcm-for-codec2codec-links-as-wel.patch new file mode 100644 index 0000000000..f80aba6878 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0054-FROMGIT-ASoC-create-pcm-for-codec2codec-links-as-wel.patch @@ -0,0 +1,175 @@ +From 33b7f3e71853dad5f6739e051b43cadd32f66913 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 25 Jul 2019 18:59:47 +0200 +Subject: [PATCH 054/186] FROMGIT: ASoC: create pcm for codec2codec links as + well + +At the moment, codec to codec links uses an ephemeral variable for +the struct snd_pcm_substream. Also the struct snd_soc_pcm_runtime +does not have real struct snd_pcm. + +This might a problem if the functions used by a codec on codec to +codec link expect these structures to exist, and keep on existing +during the life of the codec. + +For example, it is the case of the hdmi-codec, which uses +snd_pcm_add_chmap_ctls(). For the controls to works, the pcm and +substream must to exist. + +This change is first step, it create pcm (and substreams) for codec +to codec links, in the same way as dpcm backend links. + +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20190725165949.29699-5-jbrunet@baylibre.com +Signed-off-by: Mark Brown +(cherry picked from commit a342031cdd0818cb0fbcb44798211c7a02c7ca27 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-core.c | 42 ++++++++++++------------------------------ + sound/soc/soc-pcm.c | 35 ++++++++++++++++++++++++++++++++--- + 2 files changed, 44 insertions(+), 33 deletions(-) + +diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c +index 33df0dfe29f0..b6ca00b472d6 100644 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -447,16 +447,6 @@ static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) + flush_delayed_work(&rtd->delayed_work); + } + +-static void codec2codec_close_delayed_work(struct work_struct *work) +-{ +- /* +- * Currently nothing to do for c2c links +- * Since c2c links are internal nodes in the DAPM graph and +- * don't interface with the outside world or application layer +- * we don't have to do any special handling on close. +- */ +-} +- + #ifdef CONFIG_PM_SLEEP + /* powers down audio subsystem for suspend */ + int snd_soc_suspend(struct device *dev) +@@ -1557,27 +1547,19 @@ static int soc_probe_link_dais(struct snd_soc_card *card, + return ret; + } + +- if (!dai_link->params) { +- /* create the pcm */ +- ret = soc_new_pcm(rtd, num); +- if (ret < 0) { +- dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", +- dai_link->stream_name, ret); +- return ret; +- } +- ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); +- if (ret < 0) +- return ret; +- ret = soc_link_dai_pcm_new(rtd->codec_dais, +- rtd->num_codecs, rtd); +- if (ret < 0) +- return ret; +- } else { +- INIT_DELAYED_WORK(&rtd->delayed_work, +- codec2codec_close_delayed_work); ++ /* create the pcm */ ++ ret = soc_new_pcm(rtd, num); ++ if (ret < 0) { ++ dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", ++ dai_link->stream_name, ret); ++ return ret; + } +- +- return 0; ++ ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); ++ if (ret < 0) ++ return ret; ++ ret = soc_link_dai_pcm_new(rtd->codec_dais, ++ rtd->num_codecs, rtd); ++ return ret; + } + + static int soc_bind_aux_dev(struct snd_soc_card *card, int num) +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index fabeac164a6c..30264bc592f6 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -678,6 +678,16 @@ static void close_delayed_work(struct work_struct *work) + mutex_unlock(&rtd->pcm_mutex); + } + ++static void codec2codec_close_delayed_work(struct work_struct *work) ++{ ++ /* ++ * Currently nothing to do for c2c links ++ * Since c2c links are internal nodes in the DAPM graph and ++ * don't interface with the outside world or application layer ++ * we don't have to do any special handling on close. ++ */ ++} ++ + /* + * Called by ALSA when a PCM substream is closed. Private data can be + * freed here. The cpu DAI, codec DAI, machine and components are also +@@ -3011,6 +3021,12 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) + playback = rtd->dai_link->dpcm_playback; + capture = rtd->dai_link->dpcm_capture; + } else { ++ /* Adapt stream for codec2codec links */ ++ struct snd_soc_pcm_stream *cpu_capture = rtd->dai_link->params ? ++ &cpu_dai->driver->playback : &cpu_dai->driver->capture; ++ struct snd_soc_pcm_stream *cpu_playback = rtd->dai_link->params ? ++ &cpu_dai->driver->capture : &cpu_dai->driver->playback; ++ + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) +@@ -3019,6 +3035,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) + capture = 1; + } ++ ++ capture = capture && cpu_capture->channels_min; ++ playback = playback && cpu_playback->channels_min; + } + + if (rtd->dai_link->playback_only) { +@@ -3032,7 +3051,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) + } + + /* create the PCM */ +- if (rtd->dai_link->no_pcm) { ++ if (rtd->dai_link->params) { ++ snprintf(new_name, sizeof(new_name), "codec2codec(%s)", ++ rtd->dai_link->stream_name); ++ ++ ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, ++ playback, capture, &pcm); ++ } else if (rtd->dai_link->no_pcm) { + snprintf(new_name, sizeof(new_name), "(%s)", + rtd->dai_link->stream_name); + +@@ -3059,13 +3084,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) + dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); + + /* DAPM dai link stream work */ +- INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); ++ if (rtd->dai_link->params) ++ INIT_DELAYED_WORK(&rtd->delayed_work, ++ codec2codec_close_delayed_work); ++ else ++ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); + + pcm->nonatomic = rtd->dai_link->nonatomic; + rtd->pcm = pcm; + pcm->private_data = rtd; + +- if (rtd->dai_link->no_pcm) { ++ if (rtd->dai_link->no_pcm || rtd->dai_link->params) { + if (playback) + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; + if (capture) +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0055-FROMGIT-ASoC-codec2codec-fix-missing-return-of-error.patch b/packages/linux/patches/amlogic/amlogic-0055-FROMGIT-ASoC-codec2codec-fix-missing-return-of-error.patch new file mode 100644 index 0000000000..07727591ac --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0055-FROMGIT-ASoC-codec2codec-fix-missing-return-of-error.patch @@ -0,0 +1,48 @@ +From 31aecb924149fef3b6bdf4d32cc24d58602f08ab Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Fri, 26 Jul 2019 13:33:27 +0100 +Subject: [PATCH 055/186] FROMGIT: ASoC: codec2codec: fix missing return of + error return code + +Currently in function snd_soc_dai_link_event_pre_pmu the error return +code in variable err is being set but this is not actually being returned, +the function just returns zero even when there are failures. Fix this by +returning the error return code. + +Addresses-Coverity: ("Unused value") +Fixes: 3dcfb397dad2 ("ASoC: codec2codec: deal with params when necessary") +Signed-off-by: Colin Ian King +Link: https://lore.kernel.org/r/20190726123327.10467-1-colin.king@canonical.com +Signed-off-by: Mark Brown +(cherry picked from commit c8415833ec242b9ddf73bf9e1057e12f9b0fcd16 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-dapm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index be9bb05b0165..2d183e2d23de 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3776,7 +3776,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + struct snd_pcm_hw_params *params = NULL; + const struct snd_soc_pcm_stream *config = NULL; + unsigned int fmt; +- int ret; ++ int ret = 0; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) +@@ -3865,7 +3865,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + + out: + kfree(params); +- return 0; ++ return ret; + } + + static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0056-FROMGIT-ASoC-codec2codec-remove-ephemeral-variables.patch b/packages/linux/patches/amlogic/amlogic-0056-FROMGIT-ASoC-codec2codec-remove-ephemeral-variables.patch new file mode 100644 index 0000000000..af7d01d929 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0056-FROMGIT-ASoC-codec2codec-remove-ephemeral-variables.patch @@ -0,0 +1,217 @@ +From 68942bdc85a5e2f96d8c696bf16aa42361f5020a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 25 Jul 2019 18:59:48 +0200 +Subject: [PATCH 056/186] FROMGIT: ASoC: codec2codec: remove ephemeral + variables + +Now that codec to codec links struct snd_soc_pcm_runtime have lasting pcm +and substreams, let's use them. Alsa allocate and keep the +struct snd_pcm_runtime as long as the link is powered. + +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20190725165949.29699-6-jbrunet@baylibre.com +Signed-off-by: Mark Brown +(cherry picked from commit a72706ed8208ac3f72d1c3ebbc6509e368b0dcb0 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-dapm.c | 72 ++++++++++++++++++++++++++------------------ + 1 file changed, 42 insertions(+), 30 deletions(-) + +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index 2d183e2d23de..1c953a1b46ce 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3775,6 +3775,7 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_hw_params *params = NULL; + const struct snd_soc_pcm_stream *config = NULL; ++ struct snd_pcm_runtime *runtime = NULL; + unsigned int fmt; + int ret = 0; + +@@ -3782,6 +3783,14 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + if (!params) + return -ENOMEM; + ++ runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); ++ if (!runtime) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ substream->runtime = runtime; ++ + substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; +@@ -3808,6 +3817,8 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + sink->active++; + } + ++ substream->hw_opened = 1; ++ + /* + * Note: getting the config after .startup() gives a chance to + * either party on the link to alter the configuration if +@@ -3864,6 +3875,9 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + } + + out: ++ if (ret < 0) ++ kfree(runtime); ++ + kfree(params); + return ret; + } +@@ -3873,29 +3887,16 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + { + struct snd_soc_dapm_path *path; + struct snd_soc_dai *source, *sink; +- struct snd_soc_pcm_runtime *rtd = w->priv; +- struct snd_pcm_substream substream; +- struct snd_pcm_runtime *runtime = NULL; +- int ret = 0; ++ struct snd_pcm_substream *substream = w->priv; ++ int ret = 0, saved_stream = substream->stream; + + if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || + list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) + return -EINVAL; + +- memset(&substream, 0, sizeof(substream)); +- +- /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ +- runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); +- if (!runtime) { +- ret = -ENOMEM; +- goto out; +- } +- substream.runtime = runtime; +- substream.private_data = rtd; +- + switch (event) { + case SND_SOC_DAPM_PRE_PMU: +- ret = snd_soc_dai_link_event_pre_pmu(w, &substream); ++ ret = snd_soc_dai_link_event_pre_pmu(w, substream); + if (ret < 0) + goto out; + +@@ -3926,40 +3927,45 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + ret = 0; + } + +- substream.stream = SNDRV_PCM_STREAM_CAPTURE; ++ substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; +- snd_soc_dai_hw_free(source, &substream); ++ snd_soc_dai_hw_free(source, substream); + } + +- substream.stream = SNDRV_PCM_STREAM_PLAYBACK; ++ substream->stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; +- snd_soc_dai_hw_free(sink, &substream); ++ snd_soc_dai_hw_free(sink, substream); + } + +- substream.stream = SNDRV_PCM_STREAM_CAPTURE; ++ substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + source->active--; +- snd_soc_dai_shutdown(source, &substream); ++ snd_soc_dai_shutdown(source, substream); + } + +- substream.stream = SNDRV_PCM_STREAM_PLAYBACK; ++ substream->stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + sink->active--; +- snd_soc_dai_shutdown(sink, &substream); ++ snd_soc_dai_shutdown(sink, substream); + } + break; + ++ case SND_SOC_DAPM_POST_PMD: ++ kfree(substream->runtime); ++ break; ++ + default: + WARN(1, "Unknown event %d\n", event); + ret = -EINVAL; + } + + out: +- kfree(runtime); ++ /* Restore the substream direction */ ++ substream->stream = saved_stream; + return ret; + } + +@@ -4082,9 +4088,11 @@ snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card, + } + + static struct snd_soc_dapm_widget * +-snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, ++snd_soc_dapm_new_dai(struct snd_soc_card *card, ++ struct snd_pcm_substream *substream, + char *id) + { ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dapm_widget template; + struct snd_soc_dapm_widget *w; + const char **w_param_text; +@@ -4103,7 +4111,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, + template.name = link_name; + template.event = snd_soc_dai_link_event; + template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +- SND_SOC_DAPM_PRE_PMD; ++ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD; + template.kcontrol_news = NULL; + + /* allocate memory for control, only in case of multiple configs */ +@@ -4138,7 +4146,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, + goto outfree_kcontrol_news; + } + +- w->priv = rtd; ++ w->priv = substream; + + return w; + +@@ -4260,6 +4268,8 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, + struct snd_soc_dai *codec_dai; + struct snd_soc_dapm_widget *playback = NULL, *capture = NULL; + struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu; ++ struct snd_pcm_substream *substream; ++ struct snd_pcm_str *streams = rtd->pcm->streams; + int i; + + if (rtd->dai_link->params) { +@@ -4278,7 +4288,8 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, + + if (playback_cpu && codec) { + if (!playback) { +- playback = snd_soc_dapm_new_dai(card, rtd, ++ substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; ++ playback = snd_soc_dapm_new_dai(card, substream, + "playback"); + if (IS_ERR(playback)) { + dev_err(rtd->dev, +@@ -4307,7 +4318,8 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, + + if (codec && capture_cpu) { + if (!capture) { +- capture = snd_soc_dapm_new_dai(card, rtd, ++ substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; ++ capture = snd_soc_dapm_new_dai(card, substream, + "capture"); + if (IS_ERR(capture)) { + dev_err(rtd->dev, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0057-FROMGIT-ASoC-codec2codec-fill-some-of-the-runtime-st.patch b/packages/linux/patches/amlogic/amlogic-0057-FROMGIT-ASoC-codec2codec-fill-some-of-the-runtime-st.patch new file mode 100644 index 0000000000..069eb17da7 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0057-FROMGIT-ASoC-codec2codec-fill-some-of-the-runtime-st.patch @@ -0,0 +1,38 @@ +From 83cd39f43df32e2d53679b625bc3a1dd54e97280 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 25 Jul 2019 18:59:49 +0200 +Subject: [PATCH 057/186] FROMGIT: ASoC: codec2codec: fill some of the runtime + stream parameters + +Set the information provided struct snd_soc_pcm_stream in the +struct snd_pcm_runtime of the codec to codec link. + +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20190725165949.29699-7-jbrunet@baylibre.com +Signed-off-by: Mark Brown +(cherry picked from commit 9de98628c895d15427138073986eab1e3ce39cb4 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.4) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-dapm.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index 1c953a1b46ce..e16838e1bda2 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -3874,6 +3874,11 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + dapm_update_dai_unlocked(substream, params, sink); + } + ++ runtime->format = params_format(params); ++ runtime->subformat = params_subformat(params); ++ runtime->channels = params_channels(params); ++ runtime->rate = params_rate(params); ++ + out: + if (ret < 0) + kfree(runtime); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0058-FROMGIT-drm-meson-mask-value-when-writing-bits-relax.patch b/packages/linux/patches/amlogic/amlogic-0058-FROMGIT-drm-meson-mask-value-when-writing-bits-relax.patch new file mode 100644 index 0000000000..80215453f7 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0058-FROMGIT-drm-meson-mask-value-when-writing-bits-relax.patch @@ -0,0 +1,35 @@ +From 61a5ceb0bee36183165ecd9d29943b0b6fd6ce65 Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:47:56 +0200 +Subject: [PATCH 058/186] FROMGIT: drm: meson: mask value when writing bits + relaxed + +The value used in the macro writel_bits_relaxed has to be masked since +we don't want change the bits outside the mask. + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86y31r82fo.fsf@baylibre.com +(cherry picked from commit f237bf2de82eafd224eb981c6c0bca8a9e039af6 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_registers.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index 410e324d6f93..2e6537a21bc4 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -10,7 +10,7 @@ + #define _REG(reg) ((reg) << 2) + + #define writel_bits_relaxed(mask, val, addr) \ +- writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) ++ writel_relaxed((readl_relaxed(addr) & ~(mask)) | ((val) & (mask)), addr) + + /* vpp2 */ + #define VPP2_DUMMY_DATA 0x1900 +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0059-FROMGIT-drm-meson-crtc-use-proper-macros-instead-of-.patch b/packages/linux/patches/amlogic/amlogic-0059-FROMGIT-drm-meson-crtc-use-proper-macros-instead-of-.patch new file mode 100644 index 0000000000..76d58255a3 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0059-FROMGIT-drm-meson-crtc-use-proper-macros-instead-of-.patch @@ -0,0 +1,94 @@ +From da7640c5ed2a9c39b91d423c9195909b7739ab2c Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:48:12 +0200 +Subject: [PATCH 059/186] FROMGIT: drm: meson: crtc: use proper macros instead + of magic constants + +This patch add new macros which describe couple bits field of the +following registers: +- VD1_BLEND_SRC_CTRL +- VPP_SC_MISC + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86wohb82fa.fsf@baylibre.com +(cherry picked from commit 39bf9985b8598f20a3bf49844d2ac538a0d5697f + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_crtc.c | 17 +++++++++++------ + drivers/gpu/drm/meson/meson_registers.h | 16 ++++++++++++++++ + 2 files changed, 27 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c +index aa8ea107524e..6f7d6d258615 100644 +--- a/drivers/gpu/drm/meson/meson_crtc.c ++++ b/drivers/gpu/drm/meson/meson_crtc.c +@@ -267,11 +267,11 @@ static void meson_crtc_enable_vd1(struct meson_drm *priv) + + static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv) + { +- writel_relaxed(((1 << 16) | /* post bld premult*/ +- (1 << 8) | /* post src */ +- (1 << 4) | /* pre bld premult*/ +- (1 << 0)), +- priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); ++ writel_relaxed(VD_BLEND_PREBLD_SRC_VD1 | ++ VD_BLEND_PREBLD_PREMULT_EN | ++ VD_BLEND_POSTBLD_SRC_VD1 | ++ VD_BLEND_POSTBLD_PREMULT_EN, ++ priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); + } + + void meson_crtc_irq(struct meson_drm *priv) +@@ -489,7 +489,12 @@ void meson_crtc_irq(struct meson_drm *priv) + writel_relaxed(priv->viu.vd1_range_map_cr, + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_RANGE_MAP_CR)); +- writel_relaxed(0x78404, ++ writel_relaxed(VPP_VSC_BANK_LENGTH(4) | ++ VPP_HSC_BANK_LENGTH(4) | ++ VPP_SC_VD_EN_ENABLE | ++ VPP_SC_TOP_EN_ENABLE | ++ VPP_SC_HSC_EN_ENABLE | ++ VPP_SC_VSC_EN_ENABLE, + priv->io_base + _REG(VPP_SC_MISC)); + writel_relaxed(priv->viu.vpp_pic_in_height, + priv->io_base + _REG(VPP_PIC_IN_HEIGHT)); +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index 2e6537a21bc4..da31f22fed65 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -360,6 +360,12 @@ + #define VPP_HSC_REGION4_PHASE_SLOPE 0x1d17 + #define VPP_HSC_PHASE_CTRL 0x1d18 + #define VPP_SC_MISC 0x1d19 ++#define VPP_SC_VD_EN_ENABLE BIT(15) ++#define VPP_SC_TOP_EN_ENABLE BIT(16) ++#define VPP_SC_HSC_EN_ENABLE BIT(17) ++#define VPP_SC_VSC_EN_ENABLE BIT(18) ++#define VPP_VSC_BANK_LENGTH(length) (length & 0x7) ++#define VPP_HSC_BANK_LENGTH(length) ((length & 0x7) << 8) + #define VPP_PREBLEND_VD1_H_START_END 0x1d1a + #define VPP_PREBLEND_VD1_V_START_END 0x1d1b + #define VPP_POSTBLEND_VD1_H_START_END 0x1d1c +@@ -1628,6 +1634,16 @@ + #define VPP_SLEEP_CTRL 0x1dfa + #define VD1_BLEND_SRC_CTRL 0x1dfb + #define VD2_BLEND_SRC_CTRL 0x1dfc ++#define VD_BLEND_PREBLD_SRC_VD1 (1 << 0) ++#define VD_BLEND_PREBLD_SRC_VD2 (2 << 0) ++#define VD_BLEND_PREBLD_SRC_OSD1 (3 << 0) ++#define VD_BLEND_PREBLD_SRC_OSD2 (4 << 0) ++#define VD_BLEND_PREBLD_PREMULT_EN BIT(4) ++#define VD_BLEND_POSTBLD_SRC_VD1 (1 << 8) ++#define VD_BLEND_POSTBLD_SRC_VD2 (2 << 8) ++#define VD_BLEND_POSTBLD_SRC_OSD1 (3 << 8) ++#define VD_BLEND_POSTBLD_SRC_OSD2 (4 << 8) ++#define VD_BLEND_POSTBLD_PREMULT_EN BIT(16) + #define OSD1_BLEND_SRC_CTRL 0x1dfd + #define OSD2_BLEND_SRC_CTRL 0x1dfe + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0060-FROMGIT-drm-meson-drv-use-macro-when-initializing-vp.patch b/packages/linux/patches/amlogic/amlogic-0060-FROMGIT-drm-meson-drv-use-macro-when-initializing-vp.patch new file mode 100644 index 0000000000..18a2822b40 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0060-FROMGIT-drm-meson-drv-use-macro-when-initializing-vp.patch @@ -0,0 +1,72 @@ +From ddbb21c5d461141024a792d8f45ffb6dd448e6bb Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:48:27 +0200 +Subject: [PATCH 060/186] FROMGIT: drm: meson: drv: use macro when initializing + vpu + +This patch add new macro which is used to set WRARB/RDARB mode of +the VPU. + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86v9wv82f1.fsf@baylibre.com +(cherry picked from commit bfb86819829e5ed5eaba4b9449ecfe6db4f9f91e + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_drv.c | 26 +++++++++++++++++++++---- + drivers/gpu/drm/meson/meson_registers.h | 1 + + 2 files changed, 23 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index 2310c96fff46..50096697adc3 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -149,10 +149,28 @@ static struct regmap_config meson_regmap_config = { + + static void meson_vpu_init(struct meson_drm *priv) + { +- writel_relaxed(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); +- writel_relaxed(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); +- writel_relaxed(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); +- writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); ++ u32 value; ++ ++ /* ++ * Slave dc0 and dc5 connected to master port 1. ++ * By default other slaves are connected to master port 0. ++ */ ++ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1) | ++ VPU_RDARB_SLAVE_TO_MASTER_PORT(5, 1); ++ writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); ++ ++ /* Slave dc0 connected to master port 1 */ ++ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1); ++ writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); ++ ++ /* Slave dc4 and dc7 connected to master port 1 */ ++ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(4, 1) | ++ VPU_RDARB_SLAVE_TO_MASTER_PORT(7, 1); ++ writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); ++ ++ /* Slave dc1 connected to master port 1 */ ++ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(1, 1); ++ writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); + } + + static void meson_remove_framebuffers(void) +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index da31f22fed65..1c3825978e28 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -1486,6 +1486,7 @@ + #define VPU_RDARB_MODE_L1C2 0x2799 + #define VPU_RDARB_MODE_L2C1 0x279d + #define VPU_WRARB_MODE_L2C1 0x27a2 ++#define VPU_RDARB_SLAVE_TO_MASTER_PORT(dc, port) (port << (16 + dc)) + + /* osd super scale */ + #define OSDSR_HV_SIZEIN 0x3130 +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0061-FROMGIT-drm-meson-vpp-use-proper-macros-instead-of-m.patch b/packages/linux/patches/amlogic/amlogic-0061-FROMGIT-drm-meson-vpp-use-proper-macros-instead-of-m.patch new file mode 100644 index 0000000000..a67ce8809f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0061-FROMGIT-drm-meson-vpp-use-proper-macros-instead-of-m.patch @@ -0,0 +1,145 @@ +From 6cb0f55b098d69138bfb55f304f340b13a4214f9 Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:48:35 +0200 +Subject: [PATCH 061/186] FROMGIT: drm: meson: vpp: use proper macros instead + of magic constants + +This patch add new macros which are used to set the following +registers: +- VPP_OSD_SCALE_COEF_IDX +- VPP_DOLBY_CTRL +- VPP_OFIFO_SIZE +- VPP_HOLD_LINES +- VPP_SC_MISC +- VPP_VADJ_CTRL + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +[narmstrong: put back 0x1020080 in VPP_DUMMY_DATA1 for GXM] +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86tvcf82eu.fsf@baylibre.com +(cherry picked from commit 0ce266d018f4749c7049df76d7f670a675bfa9c6 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_registers.h | 8 ++++++++ + drivers/gpu/drm/meson/meson_vpp.c | 25 ++++++++++++++++--------- + 2 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index 1c3825978e28..fdd946b7ebb6 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -339,6 +339,7 @@ + #define VPP_LINE_IN_LENGTH 0x1d01 + #define VPP_PIC_IN_HEIGHT 0x1d02 + #define VPP_SCALE_COEF_IDX 0x1d03 ++#define VPP_SCALE_HORIZONTAL_COEF BIT(8) + #define VPP_SCALE_COEF 0x1d04 + #define VPP_VSC_REGION12_STARTP 0x1d05 + #define VPP_VSC_REGION34_STARTP 0x1d06 +@@ -375,6 +376,8 @@ + #define VPP_PREBLEND_H_SIZE 0x1d20 + #define VPP_POSTBLEND_H_SIZE 0x1d21 + #define VPP_HOLD_LINES 0x1d22 ++#define VPP_POSTBLEND_HOLD_LINES(lines) (lines & 0xf) ++#define VPP_PREBLEND_HOLD_LINES(lines) ((lines & 0xf) << 8) + #define VPP_BLEND_ONECOLOR_CTRL 0x1d23 + #define VPP_PREBLEND_CURRENT_XY 0x1d24 + #define VPP_POSTBLEND_CURRENT_XY 0x1d25 +@@ -393,6 +396,8 @@ + #define VPP_OSD2_PREBLEND BIT(17) + #define VPP_COLOR_MNG_ENABLE BIT(28) + #define VPP_OFIFO_SIZE 0x1d27 ++#define VPP_OFIFO_SIZE_MASK GENMASK(13, 0) ++#define VPP_OFIFO_SIZE_DEFAULT (0xfff << 20 | 0x1000) + #define VPP_FIFO_STATUS 0x1d28 + #define VPP_SMOKE_CTRL 0x1d29 + #define VPP_SMOKE1_VAL 0x1d2a +@@ -408,6 +413,8 @@ + #define VPP_HSC_PHASE_CTRL1 0x1d34 + #define VPP_HSC_INI_PAT_CTRL 0x1d35 + #define VPP_VADJ_CTRL 0x1d40 ++#define VPP_MINUS_BLACK_LVL_VADJ1_ENABLE BIT(1) ++ + #define VPP_VADJ1_Y 0x1d41 + #define VPP_VADJ1_MA_MB 0x1d42 + #define VPP_VADJ1_MC_MD 0x1d43 +@@ -467,6 +474,7 @@ + #define VPP_PEAKING_VGAIN 0x1d92 + #define VPP_PEAKING_NLP_1 0x1d93 + #define VPP_DOLBY_CTRL 0x1d93 ++#define VPP_PPS_DUMMY_DATA_MODE (1 << 17) + #define VPP_PEAKING_NLP_2 0x1d94 + #define VPP_PEAKING_NLP_3 0x1d95 + #define VPP_PEAKING_NLP_4 0x1d96 +diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c +index bfee30fa6e34..beec199d75e1 100644 +--- a/drivers/gpu/drm/meson/meson_vpp.c ++++ b/drivers/gpu/drm/meson/meson_vpp.c +@@ -57,7 +57,7 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv, + { + int i; + +- writel_relaxed(is_horizontal ? BIT(8) : 0, ++ writel_relaxed(is_horizontal ? VPP_SCALE_HORIZONTAL_COEF : 0, + priv->io_base + _REG(VPP_OSD_SCALE_COEF_IDX)); + for (i = 0; i < 33; i++) + writel_relaxed(coefs[i], +@@ -82,7 +82,7 @@ static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv, + { + int i; + +- writel_relaxed(is_horizontal ? BIT(8) : 0, ++ writel_relaxed(is_horizontal ? VPP_SCALE_HORIZONTAL_COEF : 0, + priv->io_base + _REG(VPP_SCALE_COEF_IDX)); + for (i = 0; i < 33; i++) + writel_relaxed(coefs[i], +@@ -97,7 +97,8 @@ void meson_vpp_init(struct meson_drm *priv) + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu")) { + writel_bits_relaxed(0xff << 16, 0xff << 16, + priv->io_base + _REG(VIU_MISC_CTRL1)); +- writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL)); ++ writel_relaxed(VPP_PPS_DUMMY_DATA_MODE, ++ priv->io_base + _REG(VPP_DOLBY_CTRL)); + writel_relaxed(0x1020080, + priv->io_base + _REG(VPP_DUMMY_DATA1)); + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) +@@ -105,12 +106,13 @@ void meson_vpp_init(struct meson_drm *priv) + + /* Initialize vpu fifo control registers */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) +- writel_relaxed(0xfff << 20 | 0x1000, ++ writel_relaxed(VPP_OFIFO_SIZE_DEFAULT, + priv->io_base + _REG(VPP_OFIFO_SIZE)); + else +- writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | +- 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); +- writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES)); ++ writel_bits_relaxed(VPP_OFIFO_SIZE_MASK, 0x77f, ++ priv->io_base + _REG(VPP_OFIFO_SIZE)); ++ writel_relaxed(VPP_POSTBLEND_HOLD_LINES(4) | VPP_PREBLEND_HOLD_LINES(4), ++ priv->io_base + _REG(VPP_HOLD_LINES)); + + if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { + /* Turn off preblend */ +@@ -138,10 +140,15 @@ void meson_vpp_init(struct meson_drm *priv) + writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); + writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); + writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); +- writel_relaxed(4 | (4 << 8) | BIT(15), ++ ++ /* Set horizontal/vertical bank length and enable video scale out */ ++ writel_relaxed(VPP_VSC_BANK_LENGTH(4) | VPP_HSC_BANK_LENGTH(4) | ++ VPP_SC_VD_EN_ENABLE, + priv->io_base + _REG(VPP_SC_MISC)); + +- writel_relaxed(1, priv->io_base + _REG(VPP_VADJ_CTRL)); ++ /* Enable minus black level for vadj1 */ ++ writel_relaxed(VPP_MINUS_BLACK_LVL_VADJ1_ENABLE, ++ priv->io_base + _REG(VPP_VADJ_CTRL)); + + /* Write in the proper filter coefficients. */ + meson_vpp_write_scaling_filter_coefs(priv, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0062-FROMGIT-drm-meson-viu-use-proper-macros-instead-of-m.patch b/packages/linux/patches/amlogic/amlogic-0062-FROMGIT-drm-meson-viu-use-proper-macros-instead-of-m.patch new file mode 100644 index 0000000000..d321417be6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0062-FROMGIT-drm-meson-viu-use-proper-macros-instead-of-m.patch @@ -0,0 +1,251 @@ +From 4ce8b119069da36aad4676a714a580255e0c8203 Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:48:43 +0200 +Subject: [PATCH 062/186] FROMGIT: drm: meson: viu: use proper macros instead + of magic constants + +This patch add new macros which are used to set the following +registers: +- VIU_SW_RESET +- VIU_OSD1_CTRL_STAT +- VIU_OSD2_CTRL_STAT +- VIU_OSD1_FIFO_CTRL_STAT +- VIU_OSD2_FIFO_CTRL_STAT +- VIU_MISC_CTRL0 +- VIU_OSD_BLEND_CTRL +- OSD1_BLEND_SRC_CTRL +- OSD2_BLEND_SRC_CTRL +- DOLBY_PATH_CTRL + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +[narmstrong: fix OSD1_BLEND_SRC_CTRL register init value for G12A] +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86sgrz82em.fsf@baylibre.com +(cherry picked from commit 147ae1cbaa18429b9450fd47136a29653294aaad + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_plane.c | 2 +- + drivers/gpu/drm/meson/meson_registers.h | 27 ++++++++ + drivers/gpu/drm/meson/meson_viu.c | 82 +++++++++++++------------ + 3 files changed, 72 insertions(+), 39 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index 7a7e88dadd0b..c83471b69a1b 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -332,7 +332,7 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, + + /* Disable OSD1 */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) +- writel_bits_relaxed(3 << 8, 0, ++ writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0, + priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); + else + writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index fdd946b7ebb6..2b4968fd1455 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -136,11 +136,19 @@ + #define VIU_ADDR_START 0x1a00 + #define VIU_ADDR_END 0x1aff + #define VIU_SW_RESET 0x1a01 ++#define VIU_SW_RESET_OSD1 BIT(0) + #define VIU_MISC_CTRL0 0x1a06 ++#define VIU_CTRL0_VD1_AFBC_MASK 0x170000 + #define VIU_MISC_CTRL1 0x1a07 + #define D2D3_INTF_LENGTH 0x1a08 + #define D2D3_INTF_CTRL0 0x1a09 + #define VIU_OSD1_CTRL_STAT 0x1a10 ++#define VIU_OSD1_OSD_BLK_ENABLE BIT(0) ++#define VIU_OSD1_POSTBLD_SRC_VD1 (1 << 8) ++#define VIU_OSD1_POSTBLD_SRC_VD2 (2 << 8) ++#define VIU_OSD1_POSTBLD_SRC_OSD1 (3 << 8) ++#define VIU_OSD1_POSTBLD_SRC_OSD2 (4 << 8) ++#define VIU_OSD1_OSD_ENABLE BIT(21) + #define VIU_OSD1_CTRL_STAT2 0x1a2d + #define VIU_OSD1_COLOR_ADDR 0x1a11 + #define VIU_OSD1_COLOR 0x1a12 +@@ -230,6 +238,12 @@ + #define VIU_OSD3_MALI_UNPACK_CTRL 0x3d9f + #define VIU_OSD3_DIMM_CTRL 0x3da0 + ++#define VIU_OSD_DDR_PRIORITY_URGENT BIT(0) ++#define VIU_OSD_HOLD_FIFO_LINES(lines) ((lines & 0x1f) << 5) ++#define VIU_OSD_FIFO_DEPTH_VAL(val) ((val & 0x7f) << 12) ++#define VIU_OSD_WORDS_PER_BURST(words) (((words & 0x4) >> 1) << 22) ++#define VIU_OSD_FIFO_LIMITS(size) ((size & 0xf) << 24) ++ + #define VD1_IF0_GEN_REG 0x1a50 + #define VD1_IF0_CANVAS0 0x1a51 + #define VD1_IF0_CANVAS1 0x1a52 +@@ -1610,10 +1624,18 @@ + #define VPU_MAFBC_PREFETCH_CFG_S3 0x3a7c + + #define DOLBY_PATH_CTRL 0x1a0c ++#define DOLBY_BYPASS_EN(val) (val & 0xf) + #define OSD_PATH_MISC_CTRL 0x1a0e + #define MALI_AFBCD_TOP_CTRL 0x1a0f + + #define VIU_OSD_BLEND_CTRL 0x39b0 ++#define VIU_OSD_BLEND_REORDER(dest, src) ((src) << (dest * 4)) ++#define VIU_OSD_BLEND_DIN_EN(bits) ((bits & 0xf) << 20) ++#define VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 BIT(24) ++#define VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 BIT(25) ++#define VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 BIT(26) ++#define VIU_OSD_BLEND_BLEN2_PREMULT_EN(input) ((input & 0x3) << 27) ++#define VIU_OSD_BLEND_HOLD_LINES(lines) ((lines & 0x7) << 29) + #define VIU_OSD_BLEND_CTRL1 0x39c0 + #define VIU_OSD_BLEND_DIN0_SCOPE_H 0x39b1 + #define VIU_OSD_BLEND_DIN0_SCOPE_V 0x39b2 +@@ -1655,6 +1677,11 @@ + #define VD_BLEND_POSTBLD_PREMULT_EN BIT(16) + #define OSD1_BLEND_SRC_CTRL 0x1dfd + #define OSD2_BLEND_SRC_CTRL 0x1dfe ++#define OSD_BLEND_POSTBLD_SRC_VD1 (1 << 8) ++#define OSD_BLEND_POSTBLD_SRC_VD2 (2 << 8) ++#define OSD_BLEND_POSTBLD_SRC_OSD1 (3 << 8) ++#define OSD_BLEND_POSTBLD_SRC_OSD2 (4 << 8) ++#define OSD_BLEND_PATH_SEL_ENABLE BIT(20) + + #define VPP_POST_BLEND_BLEND_DUMMY_DATA 0x3968 + #define VPP_POST_BLEND_DUMMY_ALPHA 0x3969 +diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c +index 4b2b3024d371..4b36e4b21b51 100644 +--- a/drivers/gpu/drm/meson/meson_viu.c ++++ b/drivers/gpu/drm/meson/meson_viu.c +@@ -323,9 +323,9 @@ void meson_viu_osd1_reset(struct meson_drm *priv) + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); + + /* Reset OSD1 */ +- writel_bits_relaxed(BIT(0), BIT(0), ++ writel_bits_relaxed(VIU_SW_RESET_OSD1, VIU_SW_RESET_OSD1, + priv->io_base + _REG(VIU_SW_RESET)); +- writel_bits_relaxed(BIT(0), 0, ++ writel_bits_relaxed(VIU_SW_RESET_OSD1, 0, + priv->io_base + _REG(VIU_SW_RESET)); + + /* Rewrite these registers state lost in the reset */ +@@ -338,15 +338,22 @@ void meson_viu_osd1_reset(struct meson_drm *priv) + meson_viu_load_matrix(priv); + } + ++static inline uint32_t meson_viu_osd_burst_length_reg(uint32_t length) ++{ ++ uint32_t val = (((length & 0x80) % 24) / 12); ++ ++ return (((val & 0x3) << 10) | (((val & 0x4) >> 2) << 31)); ++} ++ + void meson_viu_init(struct meson_drm *priv) + { + uint32_t reg; + + /* Disable OSDs */ +- writel_bits_relaxed(BIT(0) | BIT(21), 0, +- priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); +- writel_bits_relaxed(BIT(0) | BIT(21), 0, +- priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); ++ writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, ++ priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); ++ writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, ++ priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); + + /* On GXL/GXM, Use the 10bit HDR conversion matrix */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +@@ -357,19 +364,17 @@ void meson_viu_init(struct meson_drm *priv) + true); + + /* Initialize OSD1 fifo control register */ +- reg = BIT(0) | /* Urgent DDR request priority */ +- (4 << 5); /* hold_fifo_lines */ ++ reg = VIU_OSD_DDR_PRIORITY_URGENT | ++ VIU_OSD_HOLD_FIFO_LINES(4) | ++ VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */ ++ VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */ ++ VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */ ++ + if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) +- reg |= (1 << 10) | /* burst length 32 */ +- (32 << 12) | /* fifo_depth_val: 32*8=256 */ +- (2 << 22) | /* 4 words in 1 burst */ +- (2 << 24) | +- (1 << 31); ++ reg |= meson_viu_osd_burst_length_reg(32); + else +- reg |= (3 << 10) | /* burst length 64 */ +- (32 << 12) | /* fifo_depth_val: 32*8=256 */ +- (2 << 22) | /* 4 words in 1 burst */ +- (2 << 24); ++ reg |= meson_viu_osd_burst_length_reg(64); ++ + writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); + writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); + +@@ -382,12 +387,9 @@ void meson_viu_init(struct meson_drm *priv) + priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); + + /* Disable VD1 AFBC */ +- /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */ +- writel_bits_relaxed(0x7 << 16, 0, +- priv->io_base + _REG(VIU_MISC_CTRL0)); +- /* afbc vd1 set=0 */ +- writel_bits_relaxed(BIT(20), 0, +- priv->io_base + _REG(VIU_MISC_CTRL0)); ++ /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/ ++ writel_bits_relaxed(VIU_CTRL0_VD1_AFBC_MASK, 0, ++ priv->io_base + _REG(VIU_MISC_CTRL0)); + writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); + + writel_relaxed(0x00FF00C0, +@@ -396,27 +398,31 @@ void meson_viu_init(struct meson_drm *priv) + priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { +- writel_relaxed(4 << 29 | +- 1 << 27 | +- 1 << 26 | /* blend_din0 input to blend0 */ +- 1 << 25 | /* blend1_dout to blend2 */ +- 1 << 24 | /* blend1_din3 input to blend1 */ +- 1 << 20 | +- 0 << 16 | +- 1, +- priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); +- writel_relaxed(1 << 20, +- priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); +- writel_relaxed(1 << 20, +- priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); ++ writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) | ++ VIU_OSD_BLEND_REORDER(1, 0) | ++ VIU_OSD_BLEND_REORDER(2, 0) | ++ VIU_OSD_BLEND_REORDER(3, 0) | ++ VIU_OSD_BLEND_DIN_EN(1) | ++ VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 | ++ VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 | ++ VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 | ++ VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) | ++ VIU_OSD_BLEND_HOLD_LINES(4), ++ priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); ++ ++ writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, ++ priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); ++ writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, ++ priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); + writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); + writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); + writel_relaxed(0, + priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); + writel_relaxed(0, + priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); +- writel_bits_relaxed(0x3 << 2, 0x3 << 2, +- priv->io_base + _REG(DOLBY_PATH_CTRL)); ++ ++ writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc), ++ priv->io_base + _REG(DOLBY_PATH_CTRL)); + } + + priv->viu.osd1_enabled = false; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0063-FROMGIT-drm-meson-venc-use-proper-macros-instead-of-.patch b/packages/linux/patches/amlogic/amlogic-0063-FROMGIT-drm-meson-venc-use-proper-macros-instead-of-.patch new file mode 100644 index 0000000000..53a5709920 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0063-FROMGIT-drm-meson-venc-use-proper-macros-instead-of-.patch @@ -0,0 +1,477 @@ +From dab1d5072181becd2214ae1eaf78b664142925b2 Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:48:50 +0200 +Subject: [PATCH 063/186] FROMGIT: drm: meson: venc: use proper macros instead + of magic constants + +This patch add new macros which are used to set the following +registers: +- ENCI_CFILT_CTRL +- ENCI_CFILT_CTRL2 +- ENCI_MACV_MAX_AMP +- ENCI_VIDEO_MODE_ADV +- ENCI_VFIFO2VD_CTL +- ENCI_VIDEO_EN +- ENCP_VIDEO_MODE +- VPU_HDMI_SETTING +- VENC_UPSAMPLE_CTRL0 +- VENC_UPSAMPLE_CTRL1 +- VENC_UPSAMPLE_CTRL2 +- VENC_VDAC_FIFO_CTRL +- VENC_VDAC_DAC0_FILT_CTRL0 +- VENC_INTCTRL + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86r27j82ef.fsf@baylibre.com +(cherry picked from commit 7eef9e6104545e3aed75ac84129ab332e71b6557 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_registers.h | 51 ++++++++ + drivers/gpu/drm/meson/meson_venc.c | 155 +++++++++++++++++++----- + drivers/gpu/drm/meson/meson_venc_cvbs.c | 3 +- + 3 files changed, 177 insertions(+), 32 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index 2b4968fd1455..ec73eaa4a0bf 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -732,6 +732,25 @@ + #define VENC_UPSAMPLE_CTRL0 0x1b64 + #define VENC_UPSAMPLE_CTRL1 0x1b65 + #define VENC_UPSAMPLE_CTRL2 0x1b66 ++#define VENC_UPSAMPLE_CTRL_F0_2_CLK_RATIO BIT(0) ++#define VENC_UPSAMPLE_CTRL_F1_EN BIT(5) ++#define VENC_UPSAMPLE_CTRL_F1_UPSAMPLE_EN BIT(6) ++#define VENC_UPSAMPLE_CTRL_INTERLACE_HIGH_LUMA (0x0 << 12) ++#define VENC_UPSAMPLE_CTRL_CVBS (0x1 << 12) ++#define VENC_UPSAMPLE_CTRL_S_VIDEO_LUMA (0x2 << 12) ++#define VENC_UPSAMPLE_CTRL_S_VIDEO_CHROMA (0x3 << 12) ++#define VENC_UPSAMPLE_CTRL_INTERLACE_PB (0x4 << 12) ++#define VENC_UPSAMPLE_CTRL_INTERLACE_PR (0x5 << 12) ++#define VENC_UPSAMPLE_CTRL_INTERLACE_R (0x6 << 12) ++#define VENC_UPSAMPLE_CTRL_INTERLACE_G (0x7 << 12) ++#define VENC_UPSAMPLE_CTRL_INTERLACE_B (0x8 << 12) ++#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_Y (0x9 << 12) ++#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_PB (0xa << 12) ++#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_PR (0xb << 12) ++#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_R (0xc << 12) ++#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_G (0xd << 12) ++#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_B (0xe << 12) ++#define VENC_UPSAMPLE_CTRL_VDAC_TEST_VALUE (0xf << 12) + #define TCON_INVERT_CTL 0x1b67 + #define VENC_VIDEO_PROG_MODE 0x1b68 + #define VENC_ENCI_LINE 0x1b69 +@@ -740,6 +759,7 @@ + #define VENC_ENCP_PIXEL 0x1b6c + #define VENC_STATA 0x1b6d + #define VENC_INTCTRL 0x1b6e ++#define VENC_INTCTRL_ENCI_LNRST_INT_EN BIT(1) + #define VENC_INTFLAG 0x1b6f + #define VENC_VIDEO_TST_EN 0x1b70 + #define VENC_VIDEO_TST_MDSEL 0x1b71 +@@ -750,6 +770,7 @@ + #define VENC_VIDEO_TST_CLRBAR_WIDTH 0x1b76 + #define VENC_VIDEO_TST_VDCNT_STSET 0x1b77 + #define VENC_VDAC_DACSEL0 0x1b78 ++#define VENC_VDAC_SEL_ATV_DMD BIT(5) + #define VENC_VDAC_DACSEL1 0x1b79 + #define VENC_VDAC_DACSEL2 0x1b7a + #define VENC_VDAC_DACSEL3 0x1b7b +@@ -770,6 +791,7 @@ + #define VENC_VDAC_DAC5_GAINCTRL 0x1bfa + #define VENC_VDAC_DAC5_OFFSET 0x1bfb + #define VENC_VDAC_FIFO_CTRL 0x1bfc ++#define VENC_VDAC_FIFO_EN_ENCI_ENABLE BIT(13) + #define ENCL_TCON_INVERT_CTL 0x1bfd + #define ENCP_VIDEO_EN 0x1b80 + #define ENCP_VIDEO_SYNC_MODE 0x1b81 +@@ -785,6 +807,7 @@ + #define ENCP_VIDEO_SYNC_OFFST 0x1b8b + #define ENCP_VIDEO_MACV_OFFST 0x1b8c + #define ENCP_VIDEO_MODE 0x1b8d ++#define ENCP_VIDEO_MODE_DE_V_HIGH BIT(14) + #define ENCP_VIDEO_MODE_ADV 0x1b8e + #define ENCP_DBG_PX_RST 0x1b90 + #define ENCP_DBG_LN_RST 0x1b91 +@@ -863,6 +886,11 @@ + #define C656_FS_LNED 0x1be7 + #define ENCI_VIDEO_MODE 0x1b00 + #define ENCI_VIDEO_MODE_ADV 0x1b01 ++#define ENCI_VIDEO_MODE_ADV_DMXMD(val) (val & 0x3) ++#define ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 BIT(2) ++#define ENCI_VIDEO_MODE_ADV_YBW_MEDIUM (0 << 4) ++#define ENCI_VIDEO_MODE_ADV_YBW_LOW (0x1 << 4) ++#define ENCI_VIDEO_MODE_ADV_YBW_HIGH (0x2 << 4) + #define ENCI_VIDEO_FSC_ADJ 0x1b02 + #define ENCI_VIDEO_BRIGHT 0x1b03 + #define ENCI_VIDEO_CONT 0x1b04 +@@ -933,13 +961,17 @@ + #define ENCI_DBG_MAXPX 0x1b4c + #define ENCI_DBG_MAXLN 0x1b4d + #define ENCI_MACV_MAX_AMP 0x1b50 ++#define ENCI_MACV_MAX_AMP_ENABLE_CHANGE BIT(15) ++#define ENCI_MACV_MAX_AMP_VAL(val) (val & 0x83ff) + #define ENCI_MACV_PULSE_LO 0x1b51 + #define ENCI_MACV_PULSE_HI 0x1b52 + #define ENCI_MACV_BKP_MAX 0x1b53 + #define ENCI_CFILT_CTRL 0x1b54 ++#define ENCI_CFILT_CMPT_SEL_HIGH BIT(1) + #define ENCI_CFILT7 0x1b55 + #define ENCI_YC_DELAY 0x1b56 + #define ENCI_VIDEO_EN 0x1b57 ++#define ENCI_VIDEO_EN_ENABLE BIT(0) + #define ENCI_DVI_HSO_BEGIN 0x1c00 + #define ENCI_DVI_HSO_END 0x1c01 + #define ENCI_DVI_VSO_BLINE_EVN 0x1c02 +@@ -951,6 +983,10 @@ + #define ENCI_DVI_VSO_END_EVN 0x1c08 + #define ENCI_DVI_VSO_END_ODD 0x1c09 + #define ENCI_CFILT_CTRL2 0x1c0a ++#define ENCI_CFILT_CMPT_CR_DLY(delay) (delay & 0xf) ++#define ENCI_CFILT_CMPT_CB_DLY(delay) ((delay & 0xf) << 4) ++#define ENCI_CFILT_CVBS_CR_DLY(delay) ((delay & 0xf) << 8) ++#define ENCI_CFILT_CVBS_CB_DLY(delay) ((delay & 0xf) << 12) + #define ENCI_DACSEL_0 0x1c0b + #define ENCI_DACSEL_1 0x1c0c + #define ENCP_DACSEL_0 0x1c0d +@@ -965,6 +1001,8 @@ + #define ENCI_TST_CLRBAR_WIDTH 0x1c16 + #define ENCI_TST_VDCNT_STSET 0x1c17 + #define ENCI_VFIFO2VD_CTL 0x1c18 ++#define ENCI_VFIFO2VD_CTL_ENABLE BIT(0) ++#define ENCI_VFIFO2VD_CTL_VD_SEL(val) ((val & 0xff) << 8) + #define ENCI_VFIFO2VD_PIXEL_START 0x1c19 + #define ENCI_VFIFO2VD_PIXEL_END 0x1c1a + #define ENCI_VFIFO2VD_LINE_TOP_START 0x1c1b +@@ -1027,6 +1065,7 @@ + #define VENC_VDAC_DAC5_FILT_CTRL0 0x1c56 + #define VENC_VDAC_DAC5_FILT_CTRL1 0x1c57 + #define VENC_VDAC_DAC0_FILT_CTRL0 0x1c58 ++#define VENC_VDAC_DAC0_FILT_CTRL0_EN BIT(0) + #define VENC_VDAC_DAC0_FILT_CTRL1 0x1c59 + #define VENC_VDAC_DAC1_FILT_CTRL0 0x1c5a + #define VENC_VDAC_DAC1_FILT_CTRL1 0x1c5b +@@ -1432,6 +1471,18 @@ + #define VIU2_SEL_VENC_ENCP (2 << 2) + #define VIU2_SEL_VENC_ENCT (3 << 2) + #define VPU_HDMI_SETTING 0x271b ++#define VPU_HDMI_ENCI_DATA_TO_HDMI BIT(0) ++#define VPU_HDMI_ENCP_DATA_TO_HDMI BIT(1) ++#define VPU_HDMI_INV_HSYNC BIT(2) ++#define VPU_HDMI_INV_VSYNC BIT(3) ++#define VPU_HDMI_OUTPUT_CRYCB (0 << 5) ++#define VPU_HDMI_OUTPUT_YCBCR (1 << 5) ++#define VPU_HDMI_OUTPUT_YCRCB (2 << 5) ++#define VPU_HDMI_OUTPUT_CBCRY (3 << 5) ++#define VPU_HDMI_OUTPUT_CBYCR (4 << 5) ++#define VPU_HDMI_OUTPUT_CRCBY (5 << 5) ++#define VPU_HDMI_WR_RATE(rate) (((rate & 0x1f) - 1) << 8) ++#define VPU_HDMI_RD_RATE(rate) (((rate & 0x1f) - 1) << 12) + #define ENCI_INFO_READ 0x271c + #define ENCP_INFO_READ 0x271d + #define ENCT_INFO_READ 0x271e +diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c +index 7b7a0d8d737c..918df02d2aef 100644 +--- a/drivers/gpu/drm/meson/meson_venc.c ++++ b/drivers/gpu/drm/meson/meson_venc.c +@@ -976,6 +976,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + unsigned int eof_lines; + unsigned int sof_lines; + unsigned int vsync_lines; ++ u32 reg; + + /* Use VENCI for 480i and 576i and double HDMI pixels */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) { +@@ -1048,8 +1049,11 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + unsigned int lines_f1; + + /* CVBS Filter settings */ +- writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); +- writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); ++ writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0x10, ++ priv->io_base + _REG(ENCI_CFILT_CTRL)); ++ writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2) | ++ ENCI_CFILT_CMPT_CB_DLY(1), ++ priv->io_base + _REG(ENCI_CFILT_CTRL2)); + + /* Digital Video Select : Interlace, clk27 clk, external */ + writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); +@@ -1071,8 +1075,9 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); + + /* Macrovision max amplitude change */ +- writel_relaxed(vmode->enci.macv_max_amp, +- priv->io_base + _REG(ENCI_MACV_MAX_AMP)); ++ writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE | ++ ENCI_MACV_MAX_AMP_VAL(vmode->enci.macv_max_amp), ++ priv->io_base + _REG(ENCI_MACV_MAX_AMP)); + + /* Video mode */ + writel_relaxed(vmode->enci.video_prog_mode, +@@ -1088,7 +1093,10 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + * Bypass luma low pass filter + * No macrovision on CSYNC + */ +- writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); ++ writel_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2) | ++ ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 | ++ ENCI_VIDEO_MODE_ADV_YBW_HIGH, ++ priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + + writel(vmode->enci.sch_adjust, + priv->io_base + _REG(ENCI_VIDEO_SCH)); +@@ -1104,8 +1112,17 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + /* UNreset Interlaced TV Encoder */ + writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); + +- /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ +- writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); ++ /* ++ * Enable Vfifo2vd and set Y_Cb_Y_Cr: ++ * Corresponding value: ++ * Y => 00 or 10 ++ * Cb => 01 ++ * Cr => 11 ++ * Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y ++ */ ++ writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE | ++ ENCI_VFIFO2VD_CTL_VD_SEL(0x4e), ++ priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); + + /* Timings */ + writel_relaxed(vmode->enci.pixel_start, +@@ -1127,7 +1144,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); + + /* Interlace video enable */ +- writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); ++ writel_relaxed(ENCI_VIDEO_EN_ENABLE, ++ priv->io_base + _REG(ENCI_VIDEO_EN)); + + lines_f0 = mode->vtotal >> 1; + lines_f1 = lines_f0 + 1; +@@ -1374,7 +1392,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); + + /* Set DE signal’s polarity is active high */ +- writel_bits_relaxed(BIT(14), BIT(14), ++ writel_bits_relaxed(ENCP_VIDEO_MODE_DE_V_HIGH, ++ ENCP_VIDEO_MODE_DE_V_HIGH, + priv->io_base + _REG(ENCP_VIDEO_MODE)); + + /* Program DE timing */ +@@ -1493,13 +1512,39 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCP); + } + +- writel_relaxed((use_enci ? 1 : 2) | +- (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) | +- (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) | +- 4 << 5 | +- (venc_repeat ? 1 << 8 : 0) | +- (hdmi_repeat ? 1 << 12 : 0), +- priv->io_base + _REG(VPU_HDMI_SETTING)); ++ /* Set VPU HDMI setting */ ++ /* Select ENCP or ENCI data to HDMI */ ++ if (use_enci) ++ reg = VPU_HDMI_ENCI_DATA_TO_HDMI; ++ else ++ reg = VPU_HDMI_ENCP_DATA_TO_HDMI; ++ ++ /* Invert polarity of HSYNC from VENC */ ++ if (mode->flags & DRM_MODE_FLAG_PHSYNC) ++ reg |= VPU_HDMI_INV_HSYNC; ++ ++ /* Invert polarity of VSYNC from VENC */ ++ if (mode->flags & DRM_MODE_FLAG_PVSYNC) ++ reg |= VPU_HDMI_INV_VSYNC; ++ ++ /* Output data format: CbYCr */ ++ reg |= VPU_HDMI_OUTPUT_CBYCR; ++ ++ /* ++ * Write rate to the async FIFO between VENC and HDMI. ++ * One write every 2 wr_clk. ++ */ ++ if (venc_repeat) ++ reg |= VPU_HDMI_WR_RATE(2); ++ ++ /* ++ * Read rate to the async FIFO between VENC and HDMI. ++ * One read every 2 wr_clk. ++ */ ++ if (hdmi_repeat) ++ reg |= VPU_HDMI_RD_RATE(2); ++ ++ writel_relaxed(reg, priv->io_base + _REG(VPU_HDMI_SETTING)); + + priv->venc.hdmi_repeat = hdmi_repeat; + priv->venc.venc_repeat = venc_repeat; +@@ -1512,12 +1557,17 @@ EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set); + void meson_venci_cvbs_mode_set(struct meson_drm *priv, + struct meson_cvbs_enci_mode *mode) + { ++ u32 reg; ++ + if (mode->mode_tag == priv->venc.current_mode) + return; + + /* CVBS Filter settings */ +- writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); +- writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); ++ writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0x10, ++ priv->io_base + _REG(ENCI_CFILT_CTRL)); ++ writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2) | ++ ENCI_CFILT_CMPT_CB_DLY(1), ++ priv->io_base + _REG(ENCI_CFILT_CTRL2)); + + /* Digital Video Select : Interlace, clk27 clk, external */ + writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); +@@ -1539,8 +1589,9 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, + priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); + + /* Macrovision max amplitude change */ +- writel_relaxed(0x8100 + mode->macv_max_amp, +- priv->io_base + _REG(ENCI_MACV_MAX_AMP)); ++ writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE | ++ ENCI_MACV_MAX_AMP_VAL(mode->macv_max_amp), ++ priv->io_base + _REG(ENCI_MACV_MAX_AMP)); + + /* Video mode */ + writel_relaxed(mode->video_prog_mode, +@@ -1556,7 +1607,10 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, + * Bypass luma low pass filter + * No macrovision on CSYNC + */ +- writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); ++ writel_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2) | ++ ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 | ++ ENCI_VIDEO_MODE_ADV_YBW_HIGH, ++ priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + + writel(mode->sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH)); + +@@ -1588,16 +1642,50 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, + /* UNreset Interlaced TV Encoder */ + writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); + +- /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ +- writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); ++ /* ++ * Enable Vfifo2vd and set Y_Cb_Y_Cr: ++ * Corresponding value: ++ * Y => 00 or 10 ++ * Cb => 01 ++ * Cr => 11 ++ * Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y ++ */ ++ writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE | ++ ENCI_VFIFO2VD_CTL_VD_SEL(0x4e), ++ priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); + + /* Power UP Dacs */ + writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_SETTING)); + + /* Video Upsampling */ +- writel_relaxed(0x0061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL0)); +- writel_relaxed(0x4061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL1)); +- writel_relaxed(0x5061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL2)); ++ /* ++ * CTRL0, CTRL1 and CTRL2: ++ * Filter0: input data sample every 2 cloks ++ * Filter1: filtering and upsample enable ++ */ ++ reg = VENC_UPSAMPLE_CTRL_F0_2_CLK_RATIO | VENC_UPSAMPLE_CTRL_F1_EN | ++ VENC_UPSAMPLE_CTRL_F1_UPSAMPLE_EN; ++ ++ /* ++ * Upsample CTRL0: ++ * Interlace High Bandwidth Luma ++ */ ++ writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_HIGH_LUMA | reg, ++ priv->io_base + _REG(VENC_UPSAMPLE_CTRL0)); ++ ++ /* ++ * Upsample CTRL1: ++ * Interlace Pb ++ */ ++ writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PB | reg, ++ priv->io_base + _REG(VENC_UPSAMPLE_CTRL1)); ++ ++ /* ++ * Upsample CTRL2: ++ * Interlace R ++ */ ++ writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PR | reg, ++ priv->io_base + _REG(VENC_UPSAMPLE_CTRL2)); + + /* Select Interlace Y DACs */ + writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); +@@ -1611,14 +1699,16 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, + meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); + + /* Enable ENCI FIFO */ +- writel_relaxed(0x2000, priv->io_base + _REG(VENC_VDAC_FIFO_CTRL)); ++ writel_relaxed(VENC_VDAC_FIFO_EN_ENCI_ENABLE, ++ priv->io_base + _REG(VENC_VDAC_FIFO_CTRL)); + + /* Select ENCI DACs 0, 1, 4, and 5 */ + writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_0)); + writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_1)); + + /* Interlace video enable */ +- writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); ++ writel_relaxed(ENCI_VIDEO_EN_ENABLE, ++ priv->io_base + _REG(ENCI_VIDEO_EN)); + + /* Configure Video Saturation / Contrast / Brightness / Hue */ + writel_relaxed(mode->video_saturation, +@@ -1631,7 +1721,8 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, + priv->io_base + _REG(ENCI_VIDEO_HUE)); + + /* Enable DAC0 Filter */ +- writel_relaxed(0x1, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0)); ++ writel_relaxed(VENC_VDAC_DAC0_FILT_CTRL0_EN, ++ priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0)); + writel_relaxed(0xfc48, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL1)); + + /* 0 in Macrovision register 0 */ +@@ -1652,7 +1743,8 @@ unsigned int meson_venci_get_field(struct meson_drm *priv) + + void meson_venc_enable_vsync(struct meson_drm *priv) + { +- writel_relaxed(2, priv->io_base + _REG(VENC_INTCTRL)); ++ writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN, ++ priv->io_base + _REG(VENC_INTCTRL)); + regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25)); + } + +@@ -1680,7 +1772,8 @@ void meson_venc_init(struct meson_drm *priv) + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); + + /* Disable HDMI */ +- writel_bits_relaxed(0x3, 0, ++ writel_bits_relaxed(VPU_HDMI_ENCI_DATA_TO_HDMI | ++ VPU_HDMI_ENCP_DATA_TO_HDMI, 0, + priv->io_base + _REG(VPU_HDMI_SETTING)); + + /* Disable all encoders */ +diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c +index 6313a519f257..7ecc6bb6c8f8 100644 +--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c ++++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c +@@ -172,7 +172,8 @@ static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) + struct meson_drm *priv = meson_venc_cvbs->priv; + + /* VDAC0 source is not from ATV */ +- writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); ++ writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0, ++ priv->io_base + _REG(VENC_VDAC_DACSEL0)); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0064-FROMGIT-drm-meson-global-clean-up.patch b/packages/linux/patches/amlogic/amlogic-0064-FROMGIT-drm-meson-global-clean-up.patch new file mode 100644 index 0000000000..2a1b9c81a2 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0064-FROMGIT-drm-meson-global-clean-up.patch @@ -0,0 +1,209 @@ +From c725303b5df553247fe82b4d5f5b67474b8fadb7 Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:48:57 +0200 +Subject: [PATCH 064/186] FROMGIT: drm: meson: global clean-up + +This patch aims to: +- Add general and TODO comments +- Respect coding style for multi-line comments +- Align macro definitions +- Remove useless macro + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86pnn382e8.fsf@baylibre.com +(cherry picked from commit e1012141242db89259175eeaac36b3de04377664 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 2 ++ + drivers/gpu/drm/meson/meson_dw_hdmi.h | 12 ++++++---- + drivers/gpu/drm/meson/meson_registers.h | 31 +++++++++++-------------- + drivers/gpu/drm/meson/meson_vclk.c | 4 +++- + drivers/gpu/drm/meson/meson_venc.c | 10 ++++---- + 5 files changed, 33 insertions(+), 26 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index df3f9ddd2234..1579ff76c1ed 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -428,6 +428,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, + 0x3, 0x3); ++ ++ /* Enable cec_clk and hdcp22_tmdsclk_en */ + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, + 0x3 << 4, 0x3 << 4); + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h +index 1b2ef043eb5c..08e1c14e4ea0 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.h ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h +@@ -100,7 +100,8 @@ + #define HDMITX_TOP_INTR_RXSENSE_RISE BIT(6) + #define HDMITX_TOP_INTR_RXSENSE_FALL BIT(7) + +-/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; ++/* ++ * Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; + * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. + * Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern + * every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0. +@@ -135,7 +136,8 @@ + /* Bit 9: 0 RW tmds_clk_pttn[29:20]. Default 0. */ + #define HDMITX_TOP_TMDS_CLK_PTTN_23 (0x00B) + +-/* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, ++/* ++ * Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, + * used when TMDS CLK rate = TMDS character rate /4. Default 0. + * Bit 0 R Reserved. Default 0. + * [ 1] shift_tmds_clk_pttn +@@ -143,12 +145,14 @@ + */ + #define HDMITX_TOP_TMDS_CLK_PTTN_CNTL (0x00C) + +-/* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM ++/* ++ * Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM + * failure, write 1 to clear the failure flag. Default 0. + */ + #define HDMITX_TOP_REVOCMEM_STAT (0x00D) + +-/* Bit 1 R filtered RxSense status ++/* ++ * Bit 1 R filtered RxSense status + * Bit 0 R filtered HPD status. + */ + #define HDMITX_TOP_STAT0 (0x00E) +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index ec73eaa4a0bf..cf55723b8f16 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -396,19 +396,19 @@ + #define VPP_PREBLEND_CURRENT_XY 0x1d24 + #define VPP_POSTBLEND_CURRENT_XY 0x1d25 + #define VPP_MISC 0x1d26 +-#define VPP_PREBLEND_ENABLE BIT(6) +-#define VPP_POSTBLEND_ENABLE BIT(7) +-#define VPP_OSD2_ALPHA_PREMULT BIT(8) +-#define VPP_OSD1_ALPHA_PREMULT BIT(9) +-#define VPP_VD1_POSTBLEND BIT(10) +-#define VPP_VD2_POSTBLEND BIT(11) +-#define VPP_OSD1_POSTBLEND BIT(12) +-#define VPP_OSD2_POSTBLEND BIT(13) +-#define VPP_VD1_PREBLEND BIT(14) +-#define VPP_VD2_PREBLEND BIT(15) +-#define VPP_OSD1_PREBLEND BIT(16) +-#define VPP_OSD2_PREBLEND BIT(17) +-#define VPP_COLOR_MNG_ENABLE BIT(28) ++#define VPP_PREBLEND_ENABLE BIT(6) ++#define VPP_POSTBLEND_ENABLE BIT(7) ++#define VPP_OSD2_ALPHA_PREMULT BIT(8) ++#define VPP_OSD1_ALPHA_PREMULT BIT(9) ++#define VPP_VD1_POSTBLEND BIT(10) ++#define VPP_VD2_POSTBLEND BIT(11) ++#define VPP_OSD1_POSTBLEND BIT(12) ++#define VPP_OSD2_POSTBLEND BIT(13) ++#define VPP_VD1_PREBLEND BIT(14) ++#define VPP_VD2_PREBLEND BIT(15) ++#define VPP_OSD1_PREBLEND BIT(16) ++#define VPP_OSD2_PREBLEND BIT(17) ++#define VPP_COLOR_MNG_ENABLE BIT(28) + #define VPP_OFIFO_SIZE 0x1d27 + #define VPP_OFIFO_SIZE_MASK GENMASK(13, 0) + #define VPP_OFIFO_SIZE_DEFAULT (0xfff << 20 | 0x1000) +@@ -619,6 +619,7 @@ + #define OSD34_SCI_WH_M1 0x3d29 + #define OSD34_SCO_H_START_END 0x3d2a + #define OSD34_SCO_V_START_END 0x3d2b ++ + /* viu2 */ + #define VIU2_ADDR_START 0x1e00 + #define VIU2_ADDR_END 0x1eff +@@ -1601,7 +1602,6 @@ + #define OSD1_AFBCD_STATUS 0x31a8 + #define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 + #define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa +-#define VIU_MISC_CTRL1 0x1a07 + + /* add for gxm and 962e dv core2 */ + #define DOLBY_CORE2A_SWAP_CTRL1 0x3434 +@@ -1616,8 +1616,6 @@ + #define VPU_MAFBC_COMMAND 0x3a05 + #define VPU_MAFBC_STATUS 0x3a06 + #define VPU_MAFBC_SURFACE_CFG 0x3a07 +- +-/* osd afbc on g12a */ + #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10 + #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11 + #define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12 +@@ -1738,6 +1736,5 @@ + #define VPP_POST_BLEND_DUMMY_ALPHA 0x3969 + #define VPP_RDARB_MODE 0x3978 + #define VPP_RDARB_REQEN_SLV 0x3979 +-#define VPU_RDARB_MODE_L2C1 0x279d + + #endif /* __MESON_REGISTERS_H */ +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index 26732f038d19..e7c2b439d0f7 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -495,6 +495,7 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m); + + /* Enable and reset */ ++ /* TODO: add specific macro for g12a here */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 0x3 << 28, 0x3 << 28); + +@@ -969,7 +970,8 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + meson_venci_cvbs_clock_config(priv); + return; + } else if (target == MESON_VCLK_TARGET_DMT) { +- /* The DMT clock path is fixed after the PLL: ++ /* ++ * The DMT clock path is fixed after the PLL: + * - automatic PLL freq + OD management + * - vid_pll_div = VID_PLL_DIV_5 + * - vclk_div = 2 +diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c +index 918df02d2aef..2835133ab676 100644 +--- a/drivers/gpu/drm/meson/meson_venc.c ++++ b/drivers/gpu/drm/meson/meson_venc.c +@@ -61,9 +61,9 @@ + /* HHI Registers */ + #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ + #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ +-#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ ++#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbb offset in data sheet */ + #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ +-#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ ++#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbc offset in data sheet */ + #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ + + struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { +@@ -1085,7 +1085,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + writel_relaxed(vmode->enci.video_mode, + priv->io_base + _REG(ENCI_VIDEO_MODE)); + +- /* Advanced Video Mode : ++ /* ++ * Advanced Video Mode : + * Demux shifting 0x2 + * Blank line end at line17/22 + * High bandwidth Luma Filter +@@ -1599,7 +1600,8 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, + writel_relaxed(mode->video_mode, + priv->io_base + _REG(ENCI_VIDEO_MODE)); + +- /* Advanced Video Mode : ++ /* ++ * Advanced Video Mode : + * Demux shifting 0x2 + * Blank line end at line17/22 + * High bandwidth Luma Filter +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0065-FROMGIT-drm-meson-add-macro-used-to-enable-HDMI-PLL.patch b/packages/linux/patches/amlogic/amlogic-0065-FROMGIT-drm-meson-add-macro-used-to-enable-HDMI-PLL.patch new file mode 100644 index 0000000000..b2db4fe394 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0065-FROMGIT-drm-meson-add-macro-used-to-enable-HDMI-PLL.patch @@ -0,0 +1,43 @@ +From e46b2434cf1888101c42895d0213b86b8cee487b Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:49:04 +0200 +Subject: [PATCH 065/186] FROMGIT: drm: meson: add macro used to enable HDMI + PLL + +This patch add new macro HHI_HDMI_PLL_CNTL_EN which is used to enable +HDMI PLL. + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86o92n82e1.fsf@baylibre.com +(cherry picked from commit 0703146060786f972aaa22cad9c877a6067fd47d + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_vclk.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index e7c2b439d0f7..be6e152fc75a 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -96,6 +96,7 @@ + #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ + + #define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ ++#define HHI_HDMI_PLL_CNTL_EN BIT(30) + #define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ + #define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ + #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ +@@ -468,7 +469,7 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, + + /* Enable and unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, +- 0x7 << 28, 0x4 << 28); ++ 0x7 << 28, HHI_HDMI_PLL_CNTL_EN); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0066-FROMGIT-drm-meson-venc-set-the-correct-macrovision-m.patch b/packages/linux/patches/amlogic/amlogic-0066-FROMGIT-drm-meson-venc-set-the-correct-macrovision-m.patch new file mode 100644 index 0000000000..cc55df36ab --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0066-FROMGIT-drm-meson-venc-set-the-correct-macrovision-m.patch @@ -0,0 +1,48 @@ +From 50ad4cbf00bae7102ce79455c07f6725af50b5fe Mon Sep 17 00:00:00 2001 +From: Julien Masson +Date: Mon, 24 Jun 2019 16:49:12 +0200 +Subject: [PATCH 066/186] FROMGIT: drm: meson: venc: set the correct + macrovision max amplitude value + +According to the register description of ENCI_MACV_MAX_AMP, the +macrovision max amplitude value should be: +- hdmi 480i => 0xb +- hdmi 576i => 0x7 + +The max value is 0x7ff (10 bits). + +Signed-off-by: Julien Masson +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/86mui782dt.fsf@baylibre.com +(cherry picked from commit a84ddb83806ed43a67f6fe6a03b0b4695cc314c3 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_venc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c +index 2835133ab676..acad16ff7371 100644 +--- a/drivers/gpu/drm/meson/meson_venc.c ++++ b/drivers/gpu/drm/meson/meson_venc.c +@@ -192,7 +192,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = { + .hso_end = 129, + .vso_even = 3, + .vso_odd = 260, +- .macv_max_amp = 0x810b, ++ .macv_max_amp = 0xb, + .video_prog_mode = 0xf0, + .video_mode = 0x8, + .sch_adjust = 0x20, +@@ -212,7 +212,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = { + .hso_end = 129, + .vso_even = 3, + .vso_odd = 260, +- .macv_max_amp = 8107, ++ .macv_max_amp = 0x7, + .video_prog_mode = 0xff, + .video_mode = 0x13, + .sch_adjust = 0x28, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0067-FROMLIST-clk-meson-g12a-fix-gp0-and-hifi-ranges.patch b/packages/linux/patches/amlogic/amlogic-0067-FROMLIST-clk-meson-g12a-fix-gp0-and-hifi-ranges.patch new file mode 100644 index 0000000000..bb50a73979 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0067-FROMLIST-clk-meson-g12a-fix-gp0-and-hifi-ranges.patch @@ -0,0 +1,39 @@ +From 7223e09063a1bebb60a57fd9541fc8ec80348f96 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:45:31 +0200 +Subject: [PATCH 067/186] FROMLIST: clk: meson: g12a: fix gp0 and hifi ranges + +While some SoC samples are able to lock with a PLL factor of 55, others +samples can't. ATM, a minimum of 60 appears to work on all the samples +I have tried. + +Even with 60, it sometimes takes a long time for the PLL to eventually +lock. The documentation says that the minimum rate of these PLLs DCO +should be 3GHz, a factor of 125. Let's use that to be on the safe side. + +With factor range changed, the PLL seems to lock quickly (enough) so far. +It is still unclear if the range was the only reason for the delay. + +Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index c3f0ffc3280d..e6011d18a719 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -1362,7 +1362,7 @@ static struct clk_regmap g12b_cpub_clk_trace = { + }; + + static const struct pll_mult_range g12a_gp0_pll_mult_range = { +- .min = 55, ++ .min = 125, + .max = 255, + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0068-FROMLIST-arm64-dts-meson-g12b-add-cpus-OPP-tables.patch b/packages/linux/patches/amlogic/amlogic-0068-FROMLIST-arm64-dts-meson-g12b-add-cpus-OPP-tables.patch new file mode 100644 index 0000000000..2fcf7cfdce --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0068-FROMLIST-arm64-dts-meson-g12b-add-cpus-OPP-tables.patch @@ -0,0 +1,161 @@ +From 1730bc1f2e2630a7882f680cb795e1f7229fb470 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:26:21 +0200 +Subject: [PATCH 068/186] FROMLIST: arm64: dts: meson-g12b: add cpus OPP tables + +Add the OPP table taken from the HardKernel Odroid-N2 DTS. + +The Amlogic G12B SoC seems to available in 2 types : +- low-speed: Cortex-A73 Cluster up to 1,704GHz +- high-speed: Cortex-A73 Cluster up to 2.208GHz + +The Cortex-A73 Cluster can be clocked up to 1,896GHz for both types. + +The Vendor Amlogic A311D OPP table are slighly different, with lower +voltages than the HardKernel S922X tables but seems to be high-speed type. + +This adds the conservative OPP table with the S922X higher voltages +and the maximum low-speed OPP frequency. + +The values were tested to be stable on an HardKernel Odroid-N2 board +running the arm64 cpuburn at [1] and cycling between all the possible +cpufreq translations for both clusters and checking the final frequency +using the clock-measurer, script at [2]. + +[1] https://github.com/ssvb/cpuburn-arm/blob/master/cpuburn-a53.S +[2] https://gist.github.com/superna9999/d4de964dbc0f84b7d527e1df2ddea25f + +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 115 ++++++++++++++++++++ + 1 file changed, 115 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +index d5edbc1a1991..98ae8a7c8b41 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +@@ -95,6 +95,121 @@ + compatible = "cache"; + }; + }; ++ ++ cpu_opp_table_0: opp-table-0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-666666666 { ++ opp-hz = /bits/ 64 <666666666>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <731000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <761000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <831000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1896000000 { ++ opp-hz = /bits/ 64 <1896000000>; ++ opp-microvolt = <981000>; ++ }; ++ }; ++ ++ cpub_opp_table_1: opp-table-1 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-250000000 { ++ opp-hz = /bits/ 64 <250000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-666666666 { ++ opp-hz = /bits/ 64 <666666666>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <751000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <771000>; ++ }; ++ ++ opp-1398000000 { ++ opp-hz = /bits/ 64 <1398000000>; ++ opp-microvolt = <791000>; ++ }; ++ ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <821000>; ++ }; ++ ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <861000>; ++ }; ++ ++ opp-1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <891000>; ++ }; ++ }; + }; + + &clkc { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0069-FROMLIST-arm64-dts-meson-g12b-odroid-n2-enable-DVFS.patch b/packages/linux/patches/amlogic/amlogic-0069-FROMLIST-arm64-dts-meson-g12b-odroid-n2-enable-DVFS.patch new file mode 100644 index 0000000000..44c1bcf708 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0069-FROMLIST-arm64-dts-meson-g12b-odroid-n2-enable-DVFS.patch @@ -0,0 +1,152 @@ +From 8a02a40f31fff630ddc0c9c98c9490a29d192baf Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 29 Jul 2019 15:26:22 +0200 +Subject: [PATCH 069/186] FROMLIST: arm64: dts: meson-g12b-odroid-n2: enable + DVFS + +Enable DVFS for the Odroid-N2 by setting the clock, OPP and supply +for each cores of each CPU clusters. + +The first cluster uses the "VDDCPU_B" power supply, and the second +cluster uses the "VDDCPU_A" power supply. + +Each power supply can achieve 0.73V to 1.01V using 2 distinct PWM +outputs clocked at 800KHz with an inverse duty-cycle. + +DVFS has been tested by running the arm64 cpuburn at [1] and cycling +between all the possible cpufreq translations of each cluster and +checking the final frequency using the clock-measurer, script at [2]. + +[1] https://github.com/ssvb/cpuburn-arm/blob/master/cpuburn-a53.S +[2] https://gist.github.com/superna9999/d4de964dbc0f84b7d527e1df2ddea25f + +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 96 +++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index 237adae0ffae..6cfc2c69bb4f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -115,6 +115,44 @@ + /* FIXME: actually controlled by VDDCPU_B_EN */ + }; + ++ vddcpu_a: regulator-vddcpu-a { ++ /* ++ * MP8756GD Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU_A"; ++ regulator-min-microvolt = <721000>; ++ regulator-max-microvolt = <1022000>; ++ ++ vin-supply = <&main_12v>; ++ ++ pwms = <&pwm_ab 0 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vddcpu_b: regulator-vddcpu-b { ++ /* ++ * Silergy SY8120B1ABC Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU_B"; ++ regulator-min-microvolt = <721000>; ++ regulator-max-microvolt = <1022000>; ++ ++ vin-supply = <&main_12v>; ++ ++ pwms = <&pwm_AO_cd 1 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ + hub_5v: regulator-hub_5v { + compatible = "regulator-fixed"; + regulator-name = "HUB_5V"; +@@ -246,6 +284,48 @@ + status = "okay"; + }; + ++&cpu0 { ++ cpu-supply = <&vddcpu_b>; ++ operating-points-v2 = <&cpu_opp_table_0>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vddcpu_b>; ++ operating-points-v2 = <&cpu_opp_table_0>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu100 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu101 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu102 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu103 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ + &ext_mdio { + external_phy: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ +@@ -317,6 +397,22 @@ + pinctrl-names = "default"; + }; + ++&pwm_ab { ++ pinctrl-0 = <&pwm_a_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin0"; ++ status = "okay"; ++}; ++ ++&pwm_AO_cd { ++ pinctrl-0 = <&pwm_ao_d_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin1"; ++ status = "okay"; ++}; ++ + /* SD card */ + &sd_emmc_b { + status = "okay"; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0070-FROMLIST-dt-bindings-thermal-Add-DT-bindings-documen.patch b/packages/linux/patches/amlogic/amlogic-0070-FROMLIST-dt-bindings-thermal-Add-DT-bindings-documen.patch new file mode 100644 index 0000000000..44c13cb0a5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0070-FROMLIST-dt-bindings-thermal-Add-DT-bindings-documen.patch @@ -0,0 +1,80 @@ +From a3b3dc378a10d28451ed5c62b36b39327e7093a6 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Tue, 6 Aug 2019 15:05:01 +0200 +Subject: [PATCH 070/186] FROMLIST: dt-bindings: thermal: Add DT bindings + documentation for Amlogic Thermal + +Adding the devicetree binding documentation for the Amlogic temperature +sensor found in the Amlogic Meson G12 SoCs. +the G12A and G12B SoCs are supported. + +Signed-off-by: Guillaume La Roque +Signed-off-by: Neil Armstrong +--- + .../bindings/thermal/amlogic,thermal.yaml | 54 +++++++++++++++++++ + 1 file changed, 54 insertions(+) + create mode 100644 Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml + +diff --git a/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml b/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml +new file mode 100644 +index 000000000000..d25e59113398 +--- /dev/null ++++ b/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml +@@ -0,0 +1,54 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/thermal/amlogic,thermal.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Amlogic Thermal ++ ++maintainers: ++ - Guillaume La Roque ++ ++description: Binding for Amlogic Thermal Driver ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - amlogic,g12-cpu-thermal ++ - amlogic,g12-ddr-thermal ++ - const: amlogic,g12-thermal ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ amlogic,ao-secure: ++ description: phandle to the ao-secure syscon ++ $ref: '/schemas/types.yaml#/definitions/phandle' ++ ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - amlogic,ao-secure ++ ++examples: ++ - | ++ cpu_temp: temperature-sensor@ff634800 { ++ compatible = "amlogic,g12-cpu-thermal", ++ "amlogic,g12-thermal"; ++ reg = <0xff634800 0x50>; ++ interrupts = <0x0 0x24 0x0>; ++ clocks = <&clk 164>; ++ #thermal-sensor-cells = <0>; ++ amlogic,ao-secure = <&sec_AO>; ++ }; ++... +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0071-FROMLIST-thermal-amlogic-Add-thermal-driver-to-suppo.patch b/packages/linux/patches/amlogic/amlogic-0071-FROMLIST-thermal-amlogic-Add-thermal-driver-to-suppo.patch new file mode 100644 index 0000000000..83266348db --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0071-FROMLIST-thermal-amlogic-Add-thermal-driver-to-suppo.patch @@ -0,0 +1,409 @@ +From 8af417523f35d2daf7257bc359a8c17632d57435 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Tue, 6 Aug 2019 15:05:02 +0200 +Subject: [PATCH 071/186] FROMLIST: thermal: amlogic: Add thermal driver to + support G12 SoCs + +Amlogic G12A and G12B SoCs integrate two thermal sensors +with the same design. +One is located close to the DDR controller and the other one is +located close to the PLLs (between the CPU and GPU). + +The calibration data for each of the thermal sensors instance is +stored in a different location within the AO region. + +Implement reading the temperature from each thermal sensor. + +The IP block has more functionality, which may be added to this driver +in the future: +- chip reset when the temperature exceeds a configurable threshold +- up to four interrupts when the temperature has risen above a +configurable threshold +- up to four interrupts when the temperature has fallen below a +configurable threshold + +Signed-off-by: Guillaume La Roque +Signed-off-by: Neil Armstrong +--- + drivers/thermal/Kconfig | 11 + + drivers/thermal/Makefile | 1 + + drivers/thermal/amlogic_thermal.c | 336 ++++++++++++++++++++++++++++++ + 3 files changed, 348 insertions(+) + create mode 100644 drivers/thermal/amlogic_thermal.c + +diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +index 9966364a6deb..0f31bb4bc372 100644 +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -348,6 +348,17 @@ config MTK_THERMAL + Enable this option if you want to have support for thermal management + controller present in Mediatek SoCs + ++config AMLOGIC_THERMAL ++ tristate "Amlogic Thermal Support" ++ default ARCH_MESON ++ depends on OF && ARCH_MESON ++ help ++ If you say yes here you get support for Amlogic Thermal ++ for G12 SoC Family. ++ ++ This driver can also be built as a module. If so, the module will ++ be called amlogic_thermal. ++ + menu "Intel thermal drivers" + depends on X86 || X86_INTEL_QUARK || COMPILE_TEST + source "drivers/thermal/intel/Kconfig" +diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +index 74a37c7f847a..baeb70bf0568 100644 +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -54,3 +54,4 @@ obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o + obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o + obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o + obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o ++obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o +diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c +new file mode 100644 +index 000000000000..672d11abd8c7 +--- /dev/null ++++ b/drivers/thermal/amlogic_thermal.c +@@ -0,0 +1,336 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Amlogic Thermal Sensor Driver ++ * ++ * Copyright (C) 2017 Huan Biao ++ * Copyright (C) 2019 Guillaume La Roque ++ * ++ * Register value to celsius temperature formulas: ++ * Read_Val m * U ++ * U = ---------, Uptat = --------- ++ * 2^16 1 + n * U ++ * ++ * Temperature = A * ( Uptat + u_efuse / 2^16 )- B ++ * ++ * A B m n : calibration parameters ++ * u_efuse : fused calibration value, it's a signed 16 bits value ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "thermal_core.h" ++ ++#define TSENSOR_CFG_REG1 0x4 ++ #define TSENSOR_CFG_REG1_RSET_VBG BIT(12) ++ #define TSENSOR_CFG_REG1_RSET_ADC BIT(11) ++ #define TSENSOR_CFG_REG1_VCM_EN BIT(10) ++ #define TSENSOR_CFG_REG1_VBG_EN BIT(9) ++ #define TSENSOR_CFG_REG1_OUT_CTL BIT(6) ++ #define TSENSOR_CFG_REG1_FILTER_EN BIT(5) ++ #define TSENSOR_CFG_REG1_DEM_EN BIT(3) ++ #define TSENSOR_CFG_REG1_CH_SEL GENMASK(1, 0) ++ #define TSENSOR_CFG_REG1_ENABLE \ ++ (TSENSOR_CFG_REG1_FILTER_EN | \ ++ TSENSOR_CFG_REG1_VCM_EN | \ ++ TSENSOR_CFG_REG1_VBG_EN | \ ++ TSENSOR_CFG_REG1_DEM_EN | \ ++ TSENSOR_CFG_REG1_CH_SEL) ++ ++#define TSENSOR_STAT0 0x40 ++ ++#define TSENSOR_STAT9 0x64 ++ ++#define TSENSOR_READ_TEMP_MASK GENMASK(15, 0) ++#define TSENSOR_TEMP_MASK GENMASK(11, 0) ++ ++#define TSENSOR_TRIM_SIGN_MASK BIT(15) ++#define TSENSOR_TRIM_TEMP_MASK GENMASK(14, 0) ++#define TSENSOR_TRIM_VERSION_MASK GENMASK(31, 24) ++ ++#define TSENSOR_TRIM_VERSION(_version) \ ++ FIELD_GET(TSENSOR_TRIM_VERSION_MASK, _version) ++ ++#define TSENSOR_TRIM_CALIB_VALID_MASK (GENMASK(3, 2) | BIT(7)) ++ ++#define TSENSOR_CALIB_OFFSET 1 ++#define TSENSOR_CALIB_SHIFT 4 ++ ++/** ++ * struct amlogic_thermal_soc_calib_data ++ * @A, B, m, n: calibration parameters ++ * This structure is required for configuration of amlogic thermal driver. ++ */ ++struct amlogic_thermal_soc_calib_data { ++ int A; ++ int B; ++ int m; ++ int n; ++}; ++ ++/** ++ * struct amlogic_thermal_data ++ * @u_efuse_off: register offset to read fused calibration value ++ * @soc: calibration parameters structure pointer ++ * @regmap_config: regmap config for the device ++ * This structure is required for configuration of amlogic thermal driver. ++ */ ++struct amlogic_thermal_data { ++ int u_efuse_off; ++ const struct amlogic_thermal_soc_calib_data *calibration_parameters; ++ const struct regmap_config *regmap_config; ++}; ++ ++struct amlogic_thermal { ++ struct platform_device *pdev; ++ const struct amlogic_thermal_data *data; ++ struct regmap *regmap; ++ struct regmap *sec_ao_map; ++ struct clk *clk; ++ struct thermal_zone_device *tzd; ++ u32 trim_info; ++ void __iomem *base; ++}; ++ ++/* ++ * Calculate a temperature value from a temperature code. ++ * The unit of the temperature is degree milliCelsius. ++ */ ++static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata, ++ int temp_code) ++{ ++ const struct amlogic_thermal_soc_calib_data *param = ++ pdata->data->calibration_parameters; ++ int temp; ++ s64 factor, Uptat, uefuse; ++ ++ uefuse = pdata->trim_info & TSENSOR_TRIM_SIGN_MASK ? ++ ~(pdata->trim_info & TSENSOR_TRIM_TEMP_MASK) + 1 : ++ (pdata->trim_info & TSENSOR_TRIM_TEMP_MASK); ++ ++ factor = param->n * temp_code; ++ factor = div_s64(factor, 100); ++ ++ Uptat = temp_code * param->m; ++ Uptat = div_s64(Uptat, 100); ++ Uptat = Uptat * BIT(16); ++ Uptat = div_s64(Uptat, BIT(16) + factor); ++ ++ temp = (Uptat + uefuse) * param->A; ++ temp = div_s64(temp, BIT(16)); ++ temp = (temp - param->B) * 100; ++ ++ return temp; ++} ++ ++static int amlogic_thermal_initialize(struct amlogic_thermal *pdata) ++{ ++ int ret = 0; ++ int ver; ++ ++ regmap_read(pdata->sec_ao_map, pdata->data->u_efuse_off, ++ &pdata->trim_info); ++ ++ ver = TSENSOR_TRIM_VERSION(pdata->trim_info); ++ ++ if ((ver & TSENSOR_TRIM_CALIB_VALID_MASK) == 0) { ++ ret = -EINVAL; ++ dev_err(&pdata->pdev->dev, ++ "tsensor thermal calibration not supported: 0x%x!\n", ++ ver); ++ } ++ ++ return ret; ++} ++ ++static int amlogic_thermal_enable(struct amlogic_thermal *data) ++{ ++ int ret; ++ ++ ret = clk_prepare_enable(data->clk); ++ if (ret) ++ return ret; ++ regmap_update_bits(data->regmap, TSENSOR_CFG_REG1, ++ TSENSOR_CFG_REG1_ENABLE, TSENSOR_CFG_REG1_ENABLE); ++ ++ return 0; ++} ++ ++static int amlogic_thermal_disable(struct amlogic_thermal *data) ++{ ++ regmap_update_bits(data->regmap, TSENSOR_CFG_REG1, ++ TSENSOR_CFG_REG1_ENABLE, 0); ++ clk_disable_unprepare(data->clk); ++ ++ return 0; ++} ++ ++static int amlogic_thermal_get_temp(void *data, int *temp) ++{ ++ unsigned int tval; ++ struct amlogic_thermal *pdata = data; ++ ++ if (!data) ++ return -EINVAL; ++ ++ regmap_read(pdata->regmap, TSENSOR_STAT0, &tval); ++ *temp = ++ amlogic_thermal_code_to_millicelsius(pdata, ++ tval & TSENSOR_READ_TEMP_MASK); ++ ++ return 0; ++} ++ ++static const struct thermal_zone_of_device_ops amlogic_thermal_ops = { ++ .get_temp = amlogic_thermal_get_temp, ++}; ++ ++static const struct regmap_config amlogic_thermal_regmap_config_g12 = { ++ .reg_bits = 8, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = TSENSOR_STAT9, ++}; ++ ++static const struct amlogic_thermal_soc_calib_data amlogic_thermal_g12 = { ++ .A = 9411, ++ .B = 3159, ++ .m = 424, ++ .n = 324, ++}; ++ ++static const struct amlogic_thermal_data amlogic_thermal_g12_cpu_param = { ++ .u_efuse_off = 0x128, ++ .calibration_parameters = &amlogic_thermal_g12, ++ .regmap_config = &amlogic_thermal_regmap_config_g12, ++}; ++ ++static const struct amlogic_thermal_data amlogic_thermal_g12_ddr_param = { ++ .u_efuse_off = 0xf0, ++ .calibration_parameters = &amlogic_thermal_g12, ++ .regmap_config = &amlogic_thermal_regmap_config_g12, ++}; ++ ++static const struct of_device_id of_amlogic_thermal_match[] = { ++ { ++ .compatible = "amlogic,g12-ddr-thermal", ++ .data = &amlogic_thermal_g12_ddr_param, ++ }, ++ { ++ .compatible = "amlogic,g12-cpu-thermal", ++ .data = &amlogic_thermal_g12_cpu_param, ++ }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, of_amlogic_thermal_match); ++ ++static int amlogic_thermal_probe(struct platform_device *pdev) ++{ ++ struct amlogic_thermal *pdata; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ int ret; ++ ++ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) ++ return -ENOMEM; ++ ++ pdata->data = of_device_get_match_data(dev); ++ pdata->pdev = pdev; ++ platform_set_drvdata(pdev, pdata); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pdata->base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->base)) { ++ dev_err(dev, "failed to get io address\n"); ++ return PTR_ERR(pdata->base); ++ } ++ ++ pdata->regmap = devm_regmap_init_mmio(dev, pdata->base, ++ pdata->data->regmap_config); ++ if (IS_ERR(pdata->regmap)) ++ return PTR_ERR(pdata->regmap); ++ ++ pdata->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(pdata->clk)) { ++ if (PTR_ERR(pdata->clk) != -EPROBE_DEFER) ++ dev_err(dev, "failed to get clock\n"); ++ return PTR_ERR(pdata->clk); ++ } ++ ++ pdata->sec_ao_map = syscon_regmap_lookup_by_phandle ++ (pdev->dev.of_node, "amlogic,ao-secure"); ++ if (IS_ERR(pdata->sec_ao_map)) { ++ dev_err(dev, "syscon regmap lookup failed.\n"); ++ return PTR_ERR(pdata->sec_ao_map); ++ } ++ ++ pdata->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, ++ 0, ++ pdata, ++ &amlogic_thermal_ops); ++ if (IS_ERR(pdata->tzd)) { ++ ret = PTR_ERR(pdata->tzd); ++ dev_err(dev, "Failed to register tsensor: %d\n", ret); ++ return PTR_ERR(pdata->tzd); ++ } ++ ++ ret = amlogic_thermal_initialize(pdata); ++ if (ret) ++ return ret; ++ ++ ret = amlogic_thermal_enable(pdata); ++ if (ret) ++ clk_disable_unprepare(pdata->clk); ++ ++ return ret; ++} ++ ++static int amlogic_thermal_remove(struct platform_device *pdev) ++{ ++ struct amlogic_thermal *data = platform_get_drvdata(pdev); ++ ++ return amlogic_thermal_disable(data); ++} ++ ++static int __maybe_unused amlogic_thermal_suspend(struct device *dev) ++{ ++ struct amlogic_thermal *data = dev_get_drvdata(dev); ++ ++ return amlogic_thermal_disable(data); ++} ++ ++static int __maybe_unused amlogic_thermal_resume(struct device *dev) ++{ ++ struct amlogic_thermal *data = dev_get_drvdata(dev); ++ ++ return amlogic_thermal_enable(data); ++} ++ ++static SIMPLE_DEV_PM_OPS(amlogic_thermal_pm_ops, ++ amlogic_thermal_suspend, amlogic_thermal_resume); ++ ++static struct platform_driver amlogic_thermal_driver = { ++ .driver = { ++ .name = "amlogic_thermal", ++ .pm = &amlogic_thermal_pm_ops, ++ .of_match_table = of_amlogic_thermal_match, ++ }, ++ .probe = amlogic_thermal_probe, ++ .remove = amlogic_thermal_remove, ++}; ++ ++module_platform_driver(amlogic_thermal_driver); ++ ++MODULE_AUTHOR("Guillaume La Roque "); ++MODULE_DESCRIPTION("Amlogic thermal driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0072-FROMLIST-arm64-dts-amlogic-g12-add-temperature-senso.patch b/packages/linux/patches/amlogic/amlogic-0072-FROMLIST-arm64-dts-amlogic-g12-add-temperature-senso.patch new file mode 100644 index 0000000000..ba7e3ae955 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0072-FROMLIST-arm64-dts-amlogic-g12-add-temperature-senso.patch @@ -0,0 +1,49 @@ +From 48ec22b37703479b32535f7f3e5f070e7a9827fb Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Tue, 6 Aug 2019 15:05:03 +0200 +Subject: [PATCH 072/186] FROMLIST: arm64: dts: amlogic: g12: add temperature + sensor + +Add cpu and ddr temperature sensors for G12 Socs + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12-common.dtsi | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 27bb242dc95d..71fd725dee77 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -1355,6 +1355,26 @@ + }; + }; + ++ cpu_temp: temperature-sensor@34800 { ++ compatible = "amlogic,g12-cpu-thermal", ++ "amlogic,g12-thermal"; ++ reg = <0x0 0x34800 0x0 0x50>; ++ interrupts = ; ++ clocks = <&clkc CLKID_TS>; ++ #thermal-sensor-cells = <0>; ++ amlogic,ao-secure = <&sec_AO>; ++ }; ++ ++ ddr_temp: temperature-sensor@34c00 { ++ compatible = "amlogic,g12-ddr-thermal", ++ "amlogic,g12-thermal"; ++ reg = <0x0 0x34c00 0x0 0x50>; ++ interrupts = ; ++ clocks = <&clkc CLKID_TS>; ++ #thermal-sensor-cells = <0>; ++ amlogic,ao-secure = <&sec_AO>; ++ }; ++ + usb2_phy0: phy@36000 { + compatible = "amlogic,g12a-usb2-phy"; + reg = <0x0 0x36000 0x0 0x2000>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0073-FROMLIST-arm64-dts-meson-sei510-Add-minimal-thermal-.patch b/packages/linux/patches/amlogic/amlogic-0073-FROMLIST-arm64-dts-meson-sei510-Add-minimal-thermal-.patch new file mode 100644 index 0000000000..17be4584b6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0073-FROMLIST-arm64-dts-meson-sei510-Add-minimal-thermal-.patch @@ -0,0 +1,129 @@ +From 25a2ca2aea891043b109daf66e8d7db60f3a2d1c Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Tue, 6 Aug 2019 15:05:04 +0200 +Subject: [PATCH 073/186] FROMLIST: arm64: dts: meson: sei510: Add minimal + thermal zone + +Add minimal thermal zone for two temperature sensor +One is located close to the DDR and the other one is +located close to the PLLs (between the CPU and GPU) + +Signed-off-by: Guillaume La Roque +Acked-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 56 +++++++++++++++++++ + 1 file changed, 56 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index c9fa23a56562..3e8621d7e6a5 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + / { + compatible = "seirobotics,sei510", "amlogic,g12a"; +@@ -33,6 +34,53 @@ + ethernet0 = ðmac; + }; + ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&cpu_temp>; ++ ++ trips { ++ cpu_critical: cpu-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&cpu_critical>; ++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ ++ ddr-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&ddr_temp>; ++ ++ trips { ++ ddr_critical: ddr-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&ddr_critical>; ++ cooling-device = <&mali THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ + mono_dac: audio-codec-0 { + compatible = "maxim,max98357a"; + #sound-dai-cells = <0>; +@@ -321,6 +369,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu1 { +@@ -328,6 +377,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu2 { +@@ -335,6 +385,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu3 { +@@ -342,6 +393,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cvbs_vdac_port { +@@ -368,6 +420,10 @@ + status = "okay"; + }; + ++&mali { ++ #cooling-cells = <2>; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0074-FROMLIST-arm64-dts-amlogic-odroid-n2-add-minimal-the.patch b/packages/linux/patches/amlogic/amlogic-0074-FROMLIST-arm64-dts-amlogic-odroid-n2-add-minimal-the.patch new file mode 100644 index 0000000000..c204ee38f9 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0074-FROMLIST-arm64-dts-amlogic-odroid-n2-add-minimal-the.patch @@ -0,0 +1,147 @@ +From d7ae633f93a5fd454fbbf87b535873f6cd4227a4 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Tue, 6 Aug 2019 15:05:05 +0200 +Subject: [PATCH 074/186] FROMLIST: arm64: dts: amlogic: odroid-n2: add minimal + thermal zone + +Add minimal thermal zone for two temperature sensor +One is located close to the DDR and the other one is +located close to the PLLs (between the CPU and GPU) + +Signed-off-by: Guillaume La Roque +Acked-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 60 +++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index 6cfc2c69bb4f..57c84aa9890c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + / { + compatible = "hardkernel,odroid-n2", "amlogic,g12b"; +@@ -20,6 +21,55 @@ + ethernet0 = ðmac; + }; + ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&cpu_temp>; ++ ++ trips { ++ cpu_critical: cpu-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&cpu_critical>; ++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu101 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu102 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu103 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ ++ ddr-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&ddr_temp>; ++ ++ trips { ++ ddr_critical: ddr-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&ddr_critical>; ++ cooling-device = <&mali THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -289,6 +339,7 @@ + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu1 { +@@ -296,6 +347,7 @@ + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu100 { +@@ -303,6 +355,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu101 { +@@ -310,6 +363,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu102 { +@@ -317,6 +371,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu103 { +@@ -324,6 +379,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &ext_mdio { +@@ -378,6 +434,10 @@ + }; + }; + ++&mali { ++ #cooling-cells = <2>; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0075-FROMLIST-MAINTAINERS-add-entry-for-Amlogic-Thermal-d.patch b/packages/linux/patches/amlogic/amlogic-0075-FROMLIST-MAINTAINERS-add-entry-for-Amlogic-Thermal-d.patch new file mode 100644 index 0000000000..e674c89a73 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0075-FROMLIST-MAINTAINERS-add-entry-for-Amlogic-Thermal-d.patch @@ -0,0 +1,38 @@ +From 5bb34848ae192c1329f5c691e6ccb012cdbe68ff Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Tue, 6 Aug 2019 15:05:06 +0200 +Subject: [PATCH 075/186] FROMLIST: MAINTAINERS: add entry for Amlogic Thermal + driver + +Add myself as maintainer for Amlogic Thermal driver. + +Signed-off-by: Guillaume La Roque +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +--- + MAINTAINERS | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index e7a47b5210fd..adb7eeb9b729 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15940,6 +15940,15 @@ F: Documentation/thermal/cpu-cooling-api.rst + F: drivers/thermal/cpu_cooling.c + F: include/linux/cpu_cooling.h + ++THERMAL DRIVER FOR AMLOGIC SOCS ++M: Guillaume La Roque ++L: linux-pm@vger.kernel.org ++L: linux-amlogic@lists.infradead.org ++W: http://linux-meson.com/ ++S: Supported ++F: drivers/thermal/amlogic_thermal.c ++F: Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml ++ + THINKPAD ACPI EXTRAS DRIVER + M: Henrique de Moraes Holschuh + L: ibm-acpi-devel@lists.sourceforge.net +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0076-FROMLIST-drm-bridge-dw-hdmi-i2s-support-more-i2s-for.patch b/packages/linux/patches/amlogic/amlogic-0076-FROMLIST-drm-bridge-dw-hdmi-i2s-support-more-i2s-for.patch new file mode 100644 index 0000000000..82c00ede61 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0076-FROMLIST-drm-bridge-dw-hdmi-i2s-support-more-i2s-for.patch @@ -0,0 +1,82 @@ +From 69139a81478c0a67920362a180a199914581f327 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:19 +0200 +Subject: [PATCH 076/186] FROMLIST: drm/bridge: dw-hdmi-i2s: support more i2s + format + +The dw-hdmi-i2s supports more formats than just regular i2s. +Add support for left justified, right justified and dsp modes +A and B. + +Reviewed-by: Jonas Karlman +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 26 ++++++++++++++++--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 6 +++-- + 2 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 5cbb71a866d5..2b624cff541d 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -44,9 +44,8 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + u8 inputclkfs = 0; + + /* it cares I2S only */ +- if ((fmt->fmt != HDMI_I2S) || +- (fmt->bit_clk_master | fmt->frame_clk_master)) { +- dev_err(dev, "unsupported format/settings\n"); ++ if (fmt->bit_clk_master | fmt->frame_clk_master) { ++ dev_err(dev, "unsupported clock settings\n"); + return -EINVAL; + } + +@@ -63,6 +62,27 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + break; + } + ++ switch (fmt->fmt) { ++ case HDMI_I2S: ++ conf1 |= HDMI_AUD_CONF1_MODE_I2S; ++ break; ++ case HDMI_RIGHT_J: ++ conf1 |= HDMI_AUD_CONF1_MODE_RIGHT_J; ++ break; ++ case HDMI_LEFT_J: ++ conf1 |= HDMI_AUD_CONF1_MODE_LEFT_J; ++ break; ++ case HDMI_DSP_A: ++ conf1 |= HDMI_AUD_CONF1_MODE_BURST_1; ++ break; ++ case HDMI_DSP_B: ++ conf1 |= HDMI_AUD_CONF1_MODE_BURST_2; ++ break; ++ default: ++ dev_err(dev, "unsupported format\n"); ++ return -EINVAL; ++ } ++ + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); + + hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +index 4e3ec09d3ca4..091d7c28aa17 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +@@ -869,8 +869,10 @@ enum { + + /* AUD_CONF1 field values */ + HDMI_AUD_CONF1_MODE_I2S = 0x00, +- HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02, +- HDMI_AUD_CONF1_MODE_LEFT_J = 0x04, ++ HDMI_AUD_CONF1_MODE_RIGHT_J = 0x20, ++ HDMI_AUD_CONF1_MODE_LEFT_J = 0x40, ++ HDMI_AUD_CONF1_MODE_BURST_1 = 0x60, ++ HDMI_AUD_CONF1_MODE_BURST_2 = 0x80, + HDMI_AUD_CONF1_WIDTH_16 = 0x10, + HDMI_AUD_CONF1_WIDTH_24 = 0x18, + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0077-FROMLIST-drm-bridge-dw-hdmi-move-audio-channel-setup.patch b/packages/linux/patches/amlogic/amlogic-0077-FROMLIST-drm-bridge-dw-hdmi-move-audio-channel-setup.patch new file mode 100644 index 0000000000..7600b2233f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0077-FROMLIST-drm-bridge-dw-hdmi-move-audio-channel-setup.patch @@ -0,0 +1,127 @@ +From 36c54e6514ce3d07f4467b8ed6ccf67772008abc Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:20 +0200 +Subject: [PATCH 077/186] FROMLIST: drm/bridge: dw-hdmi: move audio channel + setup out of ahb + +Part of the channel count setup done in dw-hdmi ahb should +actually be done whatever the interface providing the data. + +Reviewed-by: Jonas Karlman +Let's move it to dw-hdmi driver instead. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../drm/bridge/synopsys/dw-hdmi-ahb-audio.c | 20 +++--------- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 32 +++++++++++++++++++ + include/drm/bridge/dw_hdmi.h | 2 ++ + 3 files changed, 38 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +index a494186ae6ce..2b7539701b42 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +@@ -63,10 +63,6 @@ enum { + HDMI_REVISION_ID = 0x0001, + HDMI_IH_AHBDMAAUD_STAT0 = 0x0109, + HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189, +- HDMI_FC_AUDICONF2 = 0x1027, +- HDMI_FC_AUDSCONF = 0x1063, +- HDMI_FC_AUDSCONF_LAYOUT1 = 1 << 0, +- HDMI_FC_AUDSCONF_LAYOUT0 = 0 << 0, + HDMI_AHB_DMA_CONF0 = 0x3600, + HDMI_AHB_DMA_START = 0x3601, + HDMI_AHB_DMA_STOP = 0x3602, +@@ -403,7 +399,7 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream) + { + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dw_hdmi *dw = substream->private_data; +- u8 threshold, conf0, conf1, layout, ca; ++ u8 threshold, conf0, conf1, ca; + + /* Setup as per 3.0.5 FSL 4.1.0 BSP */ + switch (dw->revision) { +@@ -434,20 +430,12 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream) + conf1 = default_hdmi_channel_config[runtime->channels - 2].conf1; + ca = default_hdmi_channel_config[runtime->channels - 2].ca; + +- /* +- * For >2 channel PCM audio, we need to select layout 1 +- * and set an appropriate channel map. +- */ +- if (runtime->channels > 2) +- layout = HDMI_FC_AUDSCONF_LAYOUT1; +- else +- layout = HDMI_FC_AUDSCONF_LAYOUT0; +- + writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD); + writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0); + writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1); +- writeb_relaxed(layout, dw->data.base + HDMI_FC_AUDSCONF); +- writeb_relaxed(ca, dw->data.base + HDMI_FC_AUDICONF2); ++ ++ dw_hdmi_set_channel_count(dw->data.hdmi, runtime->channels); ++ dw_hdmi_set_channel_allocation(dw->data.hdmi, ca); + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 218a7b2308f7..be6d6819bef4 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -645,6 +645,38 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) + } + EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); + ++void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt) ++{ ++ u8 layout; ++ ++ mutex_lock(&hdmi->audio_mutex); ++ ++ /* ++ * For >2 channel PCM audio, we need to select layout 1 ++ * and set an appropriate channel map. ++ */ ++ if (cnt > 2) ++ layout = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1; ++ else ++ layout = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0; ++ ++ hdmi_modb(hdmi, layout, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK, ++ HDMI_FC_AUDSCONF); ++ ++ mutex_unlock(&hdmi->audio_mutex); ++} ++EXPORT_SYMBOL_GPL(dw_hdmi_set_channel_count); ++ ++void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca) ++{ ++ mutex_lock(&hdmi->audio_mutex); ++ ++ hdmi_writeb(hdmi, ca, HDMI_FC_AUDICONF2); ++ ++ mutex_unlock(&hdmi->audio_mutex); ++} ++EXPORT_SYMBOL_GPL(dw_hdmi_set_channel_allocation); ++ + static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) + { + if (enable) +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index c402364aec0d..cf528c289857 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -155,6 +155,8 @@ void dw_hdmi_resume(struct dw_hdmi *hdmi); + void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); + + void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); ++void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt); ++void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca); + void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); + void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); + void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0078-FROMLIST-drm-bridge-dw-hdmi-set-channel-count-in-the.patch b/packages/linux/patches/amlogic/amlogic-0078-FROMLIST-drm-bridge-dw-hdmi-set-channel-count-in-the.patch new file mode 100644 index 0000000000..7074402976 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0078-FROMLIST-drm-bridge-dw-hdmi-set-channel-count-in-the.patch @@ -0,0 +1,33 @@ +From 40caa46c4072b291ce35afff7fc7db1d84b6e5ac Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:21 +0200 +Subject: [PATCH 078/186] FROMLIST: drm/bridge: dw-hdmi: set channel count in + the infoframes + +Set the number of channel in the infoframes + +Reviewed-by: Jonas Karlman +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index be6d6819bef4..bed4bb017afd 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -663,6 +663,10 @@ void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt) + hdmi_modb(hdmi, layout, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK, + HDMI_FC_AUDSCONF); + ++ /* Set the audio infoframes channel count */ ++ hdmi_modb(hdmi, (cnt - 1) << HDMI_FC_AUDICONF0_CC_OFFSET, ++ HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0); ++ + mutex_unlock(&hdmi->audio_mutex); + } + EXPORT_SYMBOL_GPL(dw_hdmi_set_channel_count); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0079-FROMLIST-drm-bridge-dw-hdmi-i2s-enable-lpcm-multi-ch.patch b/packages/linux/patches/amlogic/amlogic-0079-FROMLIST-drm-bridge-dw-hdmi-i2s-enable-lpcm-multi-ch.patch new file mode 100644 index 0000000000..07797d509b --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0079-FROMLIST-drm-bridge-dw-hdmi-i2s-enable-lpcm-multi-ch.patch @@ -0,0 +1,42 @@ +From cdf38f445651140aefa232d9bc6e62462d04c530 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:22 +0200 +Subject: [PATCH 079/186] FROMLIST: drm/bridge: dw-hdmi-i2s: enable lpcm multi + channels + +Properly setup the channel count and layout in dw-hdmi i2s driver so +we are not limited to 2 channels. + +Also correct the maximum channel reported by the DAI from 6 to 8 ch + +Reviewed-by: Jonas Karlman +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 2b624cff541d..caf8aed78fea 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -84,6 +84,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + } + + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); ++ dw_hdmi_set_channel_count(hdmi, hparms->channels); + + hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); + hdmi_write(audio, conf0, HDMI_AUD_CONF0); +@@ -139,7 +140,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) + + pdata.ops = &dw_hdmi_i2s_ops; + pdata.i2s = 1; +- pdata.max_i2s_channels = 6; ++ pdata.max_i2s_channels = 8; + pdata.data = audio; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0080-FROMLIST-drm-bridge-dw-hdmi-i2s-set-the-channel-allo.patch b/packages/linux/patches/amlogic/amlogic-0080-FROMLIST-drm-bridge-dw-hdmi-i2s-set-the-channel-allo.patch new file mode 100644 index 0000000000..ac7718cee1 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0080-FROMLIST-drm-bridge-dw-hdmi-i2s-set-the-channel-allo.patch @@ -0,0 +1,30 @@ +From 3c3dce088cacdfb13d2289a6fc18fd7cb3884216 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:23 +0200 +Subject: [PATCH 080/186] FROMLIST: drm/bridge: dw-hdmi-i2s: set the channel + allocation + +setup the channel allocation provided by the generic hdmi-codec driver + +Reviewed-by: Jonas Karlman +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index caf8aed78fea..0864dee8d180 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -85,6 +85,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); + dw_hdmi_set_channel_count(hdmi, hparms->channels); ++ dw_hdmi_set_channel_allocation(hdmi, hparms->cea.channel_allocation); + + hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); + hdmi_write(audio, conf0, HDMI_AUD_CONF0); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0081-FROMLIST-drm-bridge-dw-hdmi-i2s-reset-audio-fifo-bef.patch b/packages/linux/patches/amlogic/amlogic-0081-FROMLIST-drm-bridge-dw-hdmi-i2s-reset-audio-fifo-bef.patch new file mode 100644 index 0000000000..266045f0f2 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0081-FROMLIST-drm-bridge-dw-hdmi-i2s-reset-audio-fifo-bef.patch @@ -0,0 +1,59 @@ +From 8e0e3d1efdc1f7125d3c4b7cf4815045809744a1 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:24 +0200 +Subject: [PATCH 081/186] FROMLIST: drm/bridge: dw-hdmi-i2s: reset audio fifo + before applying new params + +When changing the audio hw params, reset the audio fifo to make sure +any old remaining data is flushed. + +The databook mentions that such reset should be followed by a reset of +the i2s block to make sure the samples stay aligned + +Reviewed-by: Jonas Karlman +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 6 ++++-- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 1 + + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 0864dee8d180..41bee0099578 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -49,6 +49,10 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + return -EINVAL; + } + ++ /* Reset the FIFOs before applying new params */ ++ hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); ++ hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); ++ + inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; + conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; + +@@ -102,8 +106,6 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) + struct dw_hdmi *hdmi = audio->hdmi; + + dw_hdmi_audio_disable(hdmi); +- +- hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); + } + + static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +index 091d7c28aa17..a272fa393ae6 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +@@ -940,6 +940,7 @@ enum { + HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1, + + /* MC_SWRSTZ field values */ ++ HDMI_MC_SWRSTZ_I2SSWRST_REQ = 0x08, + HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02, + + /* MC_FLOWCTRL field values */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0082-FROMLIST-drm-bridge-dw-hdmi-i2s-enable-only-the-requ.patch b/packages/linux/patches/amlogic/amlogic-0082-FROMLIST-drm-bridge-dw-hdmi-i2s-enable-only-the-requ.patch new file mode 100644 index 0000000000..6c37e360c0 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0082-FROMLIST-drm-bridge-dw-hdmi-i2s-enable-only-the-requ.patch @@ -0,0 +1,62 @@ +From 4008c7774115d2d69157b461a4940dddeb0bad19 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:25 +0200 +Subject: [PATCH 082/186] FROMLIST: drm/bridge: dw-hdmi-i2s: enable only the + required i2s lanes + +Enable the i2s lanes depending on the number of channel in the stream + +Reviewed-by: Jonas Karlman +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 15 ++++++++++++++- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 6 +++++- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 41bee0099578..b8ece9c1ba2c 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -54,7 +54,20 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); + + inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; +- conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; ++ conf0 = (HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0); ++ ++ /* Enable the required i2s lanes */ ++ switch (hparms->channels) { ++ case 7 ... 8: ++ conf0 |= HDMI_AUD_CONF0_I2S_EN3; ++ /* Fall-thru */ ++ case 5 ... 6: ++ conf0 |= HDMI_AUD_CONF0_I2S_EN2; ++ /* Fall-thru */ ++ case 3 ... 4: ++ conf0 |= HDMI_AUD_CONF0_I2S_EN1; ++ /* Fall-thru */ ++ } + + switch (hparms->sample_width) { + case 16: +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +index a272fa393ae6..6988f12d89d9 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +@@ -865,7 +865,11 @@ enum { + + /* AUD_CONF0 field values */ + HDMI_AUD_CONF0_SW_RESET = 0x80, +- HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F, ++ HDMI_AUD_CONF0_I2S_SELECT = 0x20, ++ HDMI_AUD_CONF0_I2S_EN3 = 0x08, ++ HDMI_AUD_CONF0_I2S_EN2 = 0x04, ++ HDMI_AUD_CONF0_I2S_EN1 = 0x02, ++ HDMI_AUD_CONF0_I2S_EN0 = 0x01, + + /* AUD_CONF1 field values */ + HDMI_AUD_CONF1_MODE_I2S = 0x00, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0083-FROMLIST-drm-bridge-dw-hdmi-i2s-add-.get_eld-support.patch b/packages/linux/patches/amlogic/amlogic-0083-FROMLIST-drm-bridge-dw-hdmi-i2s-add-.get_eld-support.patch new file mode 100644 index 0000000000..eecc126d54 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0083-FROMLIST-drm-bridge-dw-hdmi-i2s-add-.get_eld-support.patch @@ -0,0 +1,82 @@ +From e59971a100c3c6feb1f2bf186dc04fd6793c1a8c Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:07:26 +0200 +Subject: [PATCH 083/186] FROMLIST: drm/bridge: dw-hdmi-i2s: add .get_eld + support + +Provide the eld to the generic hdmi-codec driver. +This will let the driver enforce the maximum channel number and set the +channel allocation depending on the hdmi sink. + +Cc: Jonas Karlman +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 + + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 11 +++++++++++ + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 + + 3 files changed, 13 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +index 63b5756f463b..cb07dc0da5a7 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +@@ -14,6 +14,7 @@ struct dw_hdmi_audio_data { + + struct dw_hdmi_i2s_audio_data { + struct dw_hdmi *hdmi; ++ u8 *eld; + + void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); + u8 (*read)(struct dw_hdmi *hdmi, int offset); +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index b8ece9c1ba2c..1d15cf9b6821 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -10,6 +10,7 @@ + #include + + #include ++#include + + #include + +@@ -121,6 +122,15 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) + dw_hdmi_audio_disable(hdmi); + } + ++static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, uint8_t *buf, ++ size_t len) ++{ ++ struct dw_hdmi_i2s_audio_data *audio = data; ++ ++ memcpy(buf, audio->eld, min_t(size_t, MAX_ELD_BYTES, len)); ++ return 0; ++} ++ + static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + struct device_node *endpoint) + { +@@ -144,6 +154,7 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + static struct hdmi_codec_ops dw_hdmi_i2s_ops = { + .hw_params = dw_hdmi_i2s_hw_params, + .audio_shutdown = dw_hdmi_i2s_audio_shutdown, ++ .get_eld = dw_hdmi_i2s_get_eld, + .get_dai_id = dw_hdmi_i2s_get_dai_id, + }; + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index bed4bb017afd..8df69c9dbfad 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2797,6 +2797,7 @@ __dw_hdmi_probe(struct platform_device *pdev, + struct dw_hdmi_i2s_audio_data audio; + + audio.hdmi = hdmi; ++ audio.eld = hdmi->connector.eld; + audio.write = hdmi_writeb; + audio.read = hdmi_readb; + hdmi->enable_audio = dw_hdmi_i2s_audio_enable; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0084-FROMLIST-dt-bindings-clock-meson-add-resets-to-the-a.patch b/packages/linux/patches/amlogic/amlogic-0084-FROMLIST-dt-bindings-clock-meson-add-resets-to-the-a.patch new file mode 100644 index 0000000000..e1fe254fe3 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0084-FROMLIST-dt-bindings-clock-meson-add-resets-to-the-a.patch @@ -0,0 +1,76 @@ +From 1bb749f7d0c17cf6bc7b2a9c3dcfb718013ee6b2 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:32:52 +0200 +Subject: [PATCH 084/186] FROMLIST: dt-bindings: clock: meson: add resets to + the audio clock controller + +Add the documentation and bindings for the resets provided by the g12a +audio clock controller + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../bindings/clock/amlogic,axg-audio-clkc.txt | 1 + + .../reset/amlogic,meson-g12a-audio-reset.h | 38 +++++++++++++++++++ + 2 files changed, 39 insertions(+) + create mode 100644 include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h + +diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt +index 0f777749f4f1..b3957d10d241 100644 +--- a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt ++++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt +@@ -22,6 +22,7 @@ Required Properties: + components. + - resets : phandle of the internal reset line + - #clock-cells : should be 1. ++- #reset-cells : should be 1 on the g12a (and following) soc family + + 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/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h b/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h +new file mode 100644 +index 000000000000..14b78dabed0e +--- /dev/null ++++ b/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h +@@ -0,0 +1,38 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2019 BayLibre, SAS. ++ * Author: Jerome Brunet ++ * ++ */ ++ ++#ifndef _DT_BINDINGS_AMLOGIC_MESON_G12A_AUDIO_RESET_H ++#define _DT_BINDINGS_AMLOGIC_MESON_G12A_AUDIO_RESET_H ++ ++#define AUD_RESET_PDM 0 ++#define AUD_RESET_TDMIN_A 1 ++#define AUD_RESET_TDMIN_B 2 ++#define AUD_RESET_TDMIN_C 3 ++#define AUD_RESET_TDMIN_LB 4 ++#define AUD_RESET_LOOPBACK 5 ++#define AUD_RESET_TODDR_A 6 ++#define AUD_RESET_TODDR_B 7 ++#define AUD_RESET_TODDR_C 8 ++#define AUD_RESET_FRDDR_A 9 ++#define AUD_RESET_FRDDR_B 10 ++#define AUD_RESET_FRDDR_C 11 ++#define AUD_RESET_TDMOUT_A 12 ++#define AUD_RESET_TDMOUT_B 13 ++#define AUD_RESET_TDMOUT_C 14 ++#define AUD_RESET_SPDIFOUT 15 ++#define AUD_RESET_SPDIFOUT_B 16 ++#define AUD_RESET_SPDIFIN 17 ++#define AUD_RESET_EQDRC 18 ++#define AUD_RESET_RESAMPLE 19 ++#define AUD_RESET_DDRARB 20 ++#define AUD_RESET_POWDET 21 ++#define AUD_RESET_TORAM 22 ++#define AUD_RESET_TOACODEC 23 ++#define AUD_RESET_TOHDMITX 24 ++#define AUD_RESET_CLKTREE 25 ++ ++#endif +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0085-FROMLIST-clk-meson-axg-audio-add-g12a-reset-support.patch b/packages/linux/patches/amlogic/amlogic-0085-FROMLIST-clk-meson-axg-audio-add-g12a-reset-support.patch new file mode 100644 index 0000000000..0a71b4219c --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0085-FROMLIST-clk-meson-axg-audio-add-g12a-reset-support.patch @@ -0,0 +1,186 @@ +From 39e69725d2cdf25c54fbeff6751d324efe1158d8 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 12 Aug 2019 14:32:53 +0200 +Subject: [PATCH 085/186] FROMLIST: clk: meson: axg-audio: add g12a reset + support + +On the g12a, the register space dedicated to the audio clock also +provides some resets. Let the clock controller register a reset +provider as well for this SoC family. + +the axg SoC family does not appear to provide this feature. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/axg-audio.c | 107 +++++++++++++++++++++++++++++++++- + drivers/clk/meson/axg-audio.h | 1 + + 2 files changed, 106 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c +index 741df7e955ca..6be9df1efce5 100644 +--- a/drivers/clk/meson/axg-audio.c ++++ b/drivers/clk/meson/axg-audio.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + + #include "axg-audio.h" +@@ -918,6 +919,84 @@ static int devm_clk_get_enable(struct device *dev, char *id) + return 0; + } + ++struct axg_audio_reset_data { ++ struct reset_controller_dev rstc; ++ struct regmap *map; ++ unsigned int offset; ++}; ++ ++static void axg_audio_reset_reg_and_bit(struct axg_audio_reset_data *rst, ++ unsigned long id, ++ unsigned int *reg, ++ unsigned int *bit) ++{ ++ unsigned int stride = regmap_get_reg_stride(rst->map); ++ ++ *reg = (id / (stride * BITS_PER_BYTE)) * stride; ++ *reg += rst->offset; ++ *bit = id % (stride * BITS_PER_BYTE); ++} ++ ++static int axg_audio_reset_update(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) ++{ ++ struct axg_audio_reset_data *rst = ++ container_of(rcdev, struct axg_audio_reset_data, rstc); ++ unsigned int offset, bit; ++ ++ axg_audio_reset_reg_and_bit(rst, id, &offset, &bit); ++ ++ regmap_update_bits(rst->map, offset, BIT(bit), ++ assert ? BIT(bit) : 0); ++ ++ return 0; ++} ++ ++static int axg_audio_reset_status(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct axg_audio_reset_data *rst = ++ container_of(rcdev, struct axg_audio_reset_data, rstc); ++ unsigned int val, offset, bit; ++ ++ axg_audio_reset_reg_and_bit(rst, id, &offset, &bit); ++ ++ regmap_read(rst->map, offset, &val); ++ ++ return !!(val & BIT(bit)); ++} ++ ++static int axg_audio_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return axg_audio_reset_update(rcdev, id, true); ++} ++ ++static int axg_audio_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return axg_audio_reset_update(rcdev, id, false); ++} ++ ++static int axg_audio_reset_toggle(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ int ret; ++ ++ ret = axg_audio_reset_assert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ return axg_audio_reset_deassert(rcdev, id); ++} ++ ++static const struct reset_control_ops axg_audio_rstc_ops = { ++ .assert = axg_audio_reset_assert, ++ .deassert = axg_audio_reset_deassert, ++ .reset = axg_audio_reset_toggle, ++ .status = axg_audio_reset_status, ++}; ++ + static const struct regmap_config axg_audio_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, +@@ -927,12 +1006,15 @@ static const struct regmap_config axg_audio_regmap_cfg = { + + struct audioclk_data { + struct clk_hw_onecell_data *hw_onecell_data; ++ unsigned int reset_offset; ++ unsigned int reset_num; + }; + + static int axg_audio_clkc_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + const struct audioclk_data *data; ++ struct axg_audio_reset_data *rst; + struct regmap *map; + struct resource *res; + void __iomem *regs; +@@ -984,8 +1066,27 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) + } + } + +- return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, +- data->hw_onecell_data); ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, ++ data->hw_onecell_data); ++ if (ret) ++ return ret; ++ ++ /* Stop here if there is no reset */ ++ if (!data->reset_num) ++ return 0; ++ ++ rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); ++ if (!rst) ++ return -ENOMEM; ++ ++ rst->map = map; ++ rst->offset = data->reset_offset; ++ rst->rstc.nr_resets = data->reset_num; ++ rst->rstc.ops = &axg_audio_rstc_ops; ++ rst->rstc.of_node = dev->of_node; ++ rst->rstc.owner = THIS_MODULE; ++ ++ return devm_reset_controller_register(dev, &rst->rstc); + } + + static const struct audioclk_data axg_audioclk_data = { +@@ -994,6 +1095,8 @@ static const struct audioclk_data axg_audioclk_data = { + + static const struct audioclk_data g12a_audioclk_data = { + .hw_onecell_data = &g12a_audio_hw_onecell_data, ++ .reset_offset = AUDIO_SW_RESET, ++ .reset_num = 26, + }; + + static const struct of_device_id clkc_match_table[] = { +diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h +index 5d972d55d6c7..c00e28b2e1a9 100644 +--- a/drivers/clk/meson/axg-audio.h ++++ b/drivers/clk/meson/axg-audio.h +@@ -22,6 +22,7 @@ + #define AUDIO_MCLK_F_CTRL 0x018 + #define AUDIO_MST_PAD_CTRL0 0x01c + #define AUDIO_MST_PAD_CTRL1 0x020 ++#define AUDIO_SW_RESET 0x024 + #define AUDIO_MST_A_SCLK_CTRL0 0x040 + #define AUDIO_MST_A_SCLK_CTRL1 0x044 + #define AUDIO_MST_B_SCLK_CTRL0 0x048 +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0086-FROMLIST-pinctrl-meson-add-missing-tsin-pinctrl-for-.patch b/packages/linux/patches/amlogic/amlogic-0086-FROMLIST-pinctrl-meson-add-missing-tsin-pinctrl-for-.patch new file mode 100644 index 0000000000..47c8359494 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0086-FROMLIST-pinctrl-meson-add-missing-tsin-pinctrl-for-.patch @@ -0,0 +1,156 @@ +From cf0a4ad88bcb392ced80c8b63a7a64fc73c5e712 Mon Sep 17 00:00:00 2001 +From: Igor Vavro +Date: Sat, 10 Aug 2019 13:55:34 +0000 +Subject: [PATCH 086/186] FROMLIST: pinctrl: meson: add missing tsin pinctrl + for meson gxbb/gxl + +This patch adds missing tsin pinctrl definitions for meson gxbb and gxl/gxm + +Signed-off-by: Igor Vavro +--- + drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 35 ++++++++++++++++++++++ + drivers/pinctrl/meson/pinctrl-meson-gxl.c | 27 +++++++++++++++++ + 2 files changed, 62 insertions(+) + +diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +index 6c640837073e..eaedc8d67900 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c ++++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +@@ -231,10 +231,24 @@ static const unsigned int hdmi_hpd_pins[] = { GPIOH_0 }; + static const unsigned int hdmi_sda_pins[] = { GPIOH_1 }; + static const unsigned int hdmi_scl_pins[] = { GPIOH_2 }; + ++static const unsigned int tsin_a_d_valid_pins[] = { GPIOY_0 }; ++static const unsigned int tsin_a_sop_pins[] = { GPIOY_1 }; ++static const unsigned int tsin_a_clk_pins[] = { GPIOY_2 }; ++static const unsigned int tsin_a_d0_pins[] = { GPIOY_3 }; ++static const unsigned int tsin_a_dp_pins[] = { ++ GPIOY_4, GPIOY_5, GPIOY_6, GPIOY_7, GPIOY_8, GPIOY_9, GPIOY_10 ++}; ++ ++static const unsigned int tsin_a_fail_pins[] = { GPIOY_11 }; + static const unsigned int i2s_out_ch23_y_pins[] = { GPIOY_8 }; + static const unsigned int i2s_out_ch45_y_pins[] = { GPIOY_9 }; + static const unsigned int i2s_out_ch67_y_pins[] = { GPIOY_10 }; + ++static const unsigned int tsin_b_d_valid_pins[] = { GPIOX_6 }; ++static const unsigned int tsin_b_sop_pins[] = { GPIOX_7 }; ++static const unsigned int tsin_b_clk_pins[] = { GPIOX_8 }; ++static const unsigned int tsin_b_d0_pins[] = { GPIOX_9 }; ++ + static const unsigned int spdif_out_y_pins[] = { GPIOY_12 }; + + static const unsigned int gen_clk_out_pins[] = { GPIOY_15 }; +@@ -437,8 +451,18 @@ static struct meson_pmx_group meson_gxbb_periphs_groups[] = { + GROUP(pwm_a_x, 3, 17), + GROUP(pwm_e, 2, 30), + GROUP(pwm_f_x, 3, 18), ++ GROUP(tsin_b_d_valid, 3, 9), ++ GROUP(tsin_b_sop, 3, 8), ++ GROUP(tsin_b_clk, 3, 10), ++ GROUP(tsin_b_d0, 3, 7), + + /* Bank Y */ ++ GROUP(tsin_a_fail, 3, 3), ++ GROUP(tsin_a_d_valid, 3, 2), ++ GROUP(tsin_a_sop, 3, 1), ++ GROUP(tsin_a_clk, 3, 0), ++ GROUP(tsin_a_d0, 3, 4), ++ GROUP(tsin_a_dp, 3, 5), + GROUP(uart_cts_c, 1, 19), + GROUP(uart_rts_c, 1, 18), + GROUP(uart_tx_c, 1, 17), +@@ -601,6 +625,15 @@ static const char * const gpio_periphs_groups[] = { + "GPIOX_20", "GPIOX_21", "GPIOX_22", + }; + ++static const char * const tsin_a_groups[] = { ++ "tsin_a_clk", "tsin_a_sop", "tsin_a_d_valid", "tsin_a_d0", ++ "tsin_a_dp", "tsin_a_fail", ++}; ++ ++static const char * const tsin_b_groups[] = { ++ "tsin_b_clk", "tsin_b_sop", "tsin_b_d_valid", "tsin_b_d0", ++}; ++ + static const char * const emmc_groups[] = { + "emmc_nand_d07", "emmc_clk", "emmc_cmd", "emmc_ds", + }; +@@ -792,6 +825,8 @@ static struct meson_pmx_func meson_gxbb_periphs_functions[] = { + FUNCTION(i2s_out), + FUNCTION(spdif_out), + FUNCTION(gen_clk_out), ++ FUNCTION(tsin_a), ++ FUNCTION(tsin_b), + }; + + static struct meson_pmx_func meson_gxbb_aobus_functions[] = { +diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c +index 72c5373c8dc1..759245e29710 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c ++++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c +@@ -241,6 +241,17 @@ static const unsigned int tsin_a_dp_pins[] = { + GPIODV_1, GPIODV_2, GPIODV_3, GPIODV_4, GPIODV_5, GPIODV_6, GPIODV_7, + }; + ++static const unsigned int tsin_b_clk_pins[] = { GPIOH_6 }; ++static const unsigned int tsin_b_d0_pins[] = { GPIOH_7 }; ++static const unsigned int tsin_b_sop_pins[] = { GPIOH_8 }; ++static const unsigned int tsin_b_d_valid_pins[] = { GPIOH_9 }; ++ ++static const unsigned int tsin_b_fail_z4_pins[] = { GPIOZ_4 }; ++static const unsigned int tsin_b_clk_z3_pins[] = { GPIOZ_3 }; ++static const unsigned int tsin_b_d0_z2_pins[] = { GPIOZ_2 }; ++static const unsigned int tsin_b_sop_z1_pins[] = { GPIOZ_1 }; ++static const unsigned int tsin_b_d_valid_z0_pins[] = { GPIOZ_0 }; ++ + static const struct pinctrl_pin_desc meson_gxl_aobus_pins[] = { + MESON_PIN(GPIOAO_0), + MESON_PIN(GPIOAO_1), +@@ -438,6 +449,11 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = { + GROUP(eth_txd1, 4, 12), + GROUP(eth_txd2, 4, 11), + GROUP(eth_txd3, 4, 10), ++ GROUP(tsin_b_fail_z4, 3, 15), ++ GROUP(tsin_b_clk_z3, 3, 16), ++ GROUP(tsin_b_d0_z2, 3, 17), ++ GROUP(tsin_b_sop_z1, 3, 18), ++ GROUP(tsin_b_d_valid_z0, 3, 19), + GROUP(pwm_c, 3, 20), + GROUP(i2s_out_ch23_z, 3, 26), + GROUP(i2s_out_ch45_z, 3, 25), +@@ -454,6 +470,10 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = { + GROUP(i2s_out_lr_clk, 6, 24), + GROUP(i2s_out_ch01, 6, 23), + GROUP(spdif_out_h, 6, 28), ++ GROUP(tsin_b_d0, 6, 17), ++ GROUP(tsin_b_sop, 6, 18), ++ GROUP(tsin_b_d_valid, 6, 19), ++ GROUP(tsin_b_clk, 6, 20), + + /* Bank DV */ + GROUP(uart_tx_b, 2, 16), +@@ -689,6 +709,12 @@ static const char * const tsin_a_groups[] = { + "tsin_a_dp", "tsin_a_fail", + }; + ++static const char * const tsin_b_groups[] = { ++ "tsin_b_clk", "tsin_b_sop", "tsin_b_d_valid", "tsin_b_d0", ++ "tsin_b_clk_z3", "tsin_b_sop_z1", "tsin_b_d_valid_z0", "tsin_b_d0_z2", ++ "tsin_b_fail_z4", ++}; ++ + static const char * const gpio_aobus_groups[] = { + "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4", + "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9", +@@ -764,6 +790,7 @@ static struct meson_pmx_func meson_gxl_periphs_functions[] = { + FUNCTION(spdif_out), + FUNCTION(eth_led), + FUNCTION(tsin_a), ++ FUNCTION(tsin_b), + }; + + static struct meson_pmx_func meson_gxl_aobus_functions[] = { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0087-FROMLIST-arm64-dts-meson-g12b-khadas-vim3-add-initia.patch b/packages/linux/patches/amlogic/amlogic-0087-FROMLIST-arm64-dts-meson-g12b-khadas-vim3-add-initia.patch new file mode 100644 index 0000000000..5094109aee --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0087-FROMLIST-arm64-dts-meson-g12b-khadas-vim3-add-initia.patch @@ -0,0 +1,647 @@ +From 774508b13d2f4d53608d14b6da6f53f66e765f23 Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Sun, 19 May 2019 14:27:24 +0000 +Subject: [PATCH 087/186] FROMLIST: arm64: dts: meson-g12b-khadas-vim3: add + initial device-tree + +The Khadas VIM3 uses the Amlogic S922X or A311S SoC, both based on the +Amlogic G12B SoC family, on a board with the same form factor as the +VIM/VIM2 models. It ships in two variants; basic and +pro which differ in RAM and eMMC size: + +- 2GB (basic) or 4GB (pro) LPDDR4 RAM +- 16GB (basic) or 32GB (pro) eMMC 5.1 storage +- 16MB SPI flash +- 10/100/1000 Base-T Ethernet +- AP6398S Wireless (802.11 a/b/g/n/ac, BT5.0) +- HDMI 2.1 video +- 1x USB 2.0 + 1x USB 3.0 ports +- 1x USB-C (power) with USB 2.0 OTG +- 3x LED's (1x red, 1x blue, 1x white) +- 3x buttons (power, function, reset) +- IR receiver +- M2 socket with PCIe, USB, ADC & I2C +- 40pin GPIO Header +- 1x micro SD card slot + +A common meson-g12b-khadas-vim3.dtsi is added to support both S922X and +A311D SoCs supported by two variants of the board. + +Signed-off-by: Christian Hewitt +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/Makefile | 2 + + .../amlogic/meson-g12b-a311d-khadas-vim3.dts | 15 + + .../dts/amlogic/meson-g12b-khadas-vim3.dtsi | 542 ++++++++++++++++++ + .../amlogic/meson-g12b-s922x-khadas-vim3.dts | 15 + + 4 files changed, 574 insertions(+) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts + +diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile +index 07b861fe5fa5..ae5e8d0c08da 100644 +--- a/arch/arm64/boot/dts/amlogic/Makefile ++++ b/arch/arm64/boot/dts/amlogic/Makefile +@@ -3,6 +3,8 @@ dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb ++dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb ++dtb-$(CONFIG_ARCH_MESON) += meson-g12b-s922x-khadas-vim3.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts +new file mode 100644 +index 000000000000..73128ed24361 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts +@@ -0,0 +1,15 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ * Copyright (c) 2019 Christian Hewitt ++ */ ++ ++/dts-v1/; ++ ++#include "meson-g12b-a311d.dtsi" ++#include "meson-g12b-khadas-vim3.dtsi" ++ ++/ { ++ compatible = "khadas,vim3", "amlogic,a311d", "amlogic,g12b"; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +new file mode 100644 +index 000000000000..382148ef882a +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +@@ -0,0 +1,542 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ * Copyright (c) 2019 Christian Hewitt ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/ { ++ model = "Khadas VIM3"; ++ ++ aliases { ++ serial0 = &uart_AO; ++ ethernet0 = ðmac; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ ++ adc-keys { ++ compatible = "adc-keys"; ++ io-channels = <&saradc 2>; ++ io-channel-names = "buttons"; ++ keyup-threshold-microvolt = <1710000>; ++ ++ button-function { ++ label = "Function"; ++ linux,code = ; ++ press-threshold-microvolt = <10000>; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ white { ++ label = "vim3:white"; ++ gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ red { ++ label = "vim3:red"; ++ gpios = <&gpio_expander 5 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; ++ }; ++ ++ ++ gpio-keys-polled { ++ compatible = "gpio-keys-polled"; ++ poll-interval = <100>; ++ ++ power-button { ++ label = "power"; ++ linux,code = ; ++ gpios = <&gpio_ao GPIOAO_7 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; ++ ++ dc_in: regulator-dc_in { ++ compatible = "regulator-fixed"; ++ regulator-name = "DC_IN"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vcc_5v: regulator-vcc_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&dc_in>; ++ ++ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; ++ enable-active-high; ++ }; ++ ++ vcc_1v8: regulator-vcc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vsys_3v3>; ++ regulator-always-on; ++ /* FIXME: actually controlled by VDDCPU_B_EN */ ++ }; ++ ++ vddcpu_a: regulator-vddcpu-a { ++ /* ++ * MP8756GD Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU_A"; ++ regulator-min-microvolt = <690000>; ++ regulator-max-microvolt = <1050000>; ++ ++ vin-supply = <&dc_in>; ++ ++ pwms = <&pwm_ab 0 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vddcpu_b: regulator-vddcpu-b { ++ /* ++ * Silergy SY8030DEC Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU_B"; ++ regulator-min-microvolt = <690000>; ++ regulator-max-microvolt = <1050000>; ++ ++ vin-supply = <&vsys_3v3>; ++ ++ pwms = <&pwm_AO_cd 1 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vddao_1v8: regulator-vddao_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_AO1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vsys_3v3>; ++ regulator-always-on; ++ }; ++ ++ emmc_1v8: regulator-emmc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "EMMC_AO1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ vsys_3v3: regulator-vsys_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VSYS_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&dc_in>; ++ regulator-always-on; ++ }; ++ ++ usb_pwr: regulator-usb_pwr { ++ compatible = "regulator-fixed"; ++ regulator-name = "USB_PWR"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc_5v>; ++ ++ gpio = <&gpio GPIOA_6 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ ++ }; ++ ++ sound { ++ compatible = "amlogic,axg-sound-card"; ++ model = "G12A-KHADAS-VIM3"; ++ audio-aux-devs = <&tdmout_b>; ++ audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", ++ "TDMOUT_B IN 1", "FRDDR_B OUT 1", ++ "TDMOUT_B IN 2", "FRDDR_C OUT 1", ++ "TDM_B Playback", "TDMOUT_B OUT"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ status = "okay"; ++ ++ dai-link-0 { ++ sound-dai = <&frddr_a>; ++ }; ++ ++ dai-link-1 { ++ sound-dai = <&frddr_b>; ++ }; ++ ++ dai-link-2 { ++ sound-dai = <&frddr_c>; ++ }; ++ ++ /* 8ch hdmi interface */ ++ dai-link-3 { ++ sound-dai = <&tdmif_b>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ dai-tdm-slot-tx-mask-1 = <1 1>; ++ dai-tdm-slot-tx-mask-2 = <1 1>; ++ dai-tdm-slot-tx-mask-3 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec { ++ sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; ++ }; ++ }; ++ ++ /* hdmi glue */ ++ dai-link-4 { ++ sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++}; ++ ++&arb { ++ status = "okay"; ++}; ++ ++&cec_AO { ++ pinctrl-0 = <&cec_ao_a_h_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ hdmi-phandle = <&hdmi_tx>; ++}; ++ ++&cecb_AO { ++ pinctrl-0 = <&cec_ao_b_h_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ hdmi-phandle = <&hdmi_tx>; ++}; ++ ++&clkc_audio { ++ status = "okay"; ++}; ++ ++&cpu0 { ++ cpu-supply = <&vddcpu_b>; ++ operating-points-v2 = <&cpu_opp_table_0>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vddcpu_b>; ++ operating-points-v2 = <&cpu_opp_table_0>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu100 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu101 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu102 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu103 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&ext_mdio { ++ external_phy: ethernet-phy@0 { ++ /* Realtek RTL8211F (0x001cc916) */ ++ reg = <0>; ++ max-speed = <1000>; ++ }; ++}; ++ ++ðmac { ++ pinctrl-0 = <ð_pins>, <ð_rgmii_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ phy-mode = "rgmii"; ++ phy-handle = <&external_phy>; ++ amlogic,tx-delay-ns = <2>; ++}; ++ ++&frddr_a { ++ status = "okay"; ++}; ++ ++&frddr_b { ++ status = "okay"; ++}; ++ ++&frddr_c { ++ status = "okay"; ++}; ++ ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; ++ pinctrl-names = "default"; ++ hdmi-supply = <&vcc_5v>; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ ++&i2c_AO { ++ status = "okay"; ++ pinctrl-0 = <&i2c_ao_sck_pins>, <&i2c_ao_sda_pins>; ++ pinctrl-names = "default"; ++ ++ gpio_expander: gpio-controller@20 { ++ compatible = "ti,tca6408"; ++ reg = <0x20>; ++ vcc-supply = <&vcc_3v3>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ rtc@51 { ++ compatible = "haoyu,hym8563"; ++ reg = <0x51>; ++ #clock-cells = <0>; ++ }; ++}; ++ ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++ linux,rc-map-name = "rc-khadas"; ++}; ++ ++&pwm_ab { ++ pinctrl-0 = <&pwm_a_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin0"; ++ status = "okay"; ++}; ++ ++&pwm_AO_cd { ++ pinctrl-0 = <&pwm_ao_d_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin1"; ++ status = "okay"; ++}; ++ ++&pwm_ef { ++ status = "okay"; ++ pinctrl-0 = <&pwm_e_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&saradc { ++ status = "okay"; ++ vref-supply = <&vddao_1v8>; ++}; ++ ++/* SDIO */ ++&sd_emmc_a { ++ status = "okay"; ++ pinctrl-0 = <&sdio_pins>; ++ pinctrl-1 = <&sdio_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ sd-uhs-sdr50; ++ max-frequency = <100000000>; ++ ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vsys_3v3>; ++ vqmmc-supply = <&vddao_1v8>; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; ++}; ++ ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ pinctrl-0 = <&sdcard_c_pins>; ++ pinctrl-1 = <&sdcard_clk_gate_c_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ max-frequency = <50000000>; ++ disable-wp; ++ ++ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; ++ vmmc-supply = <&vsys_3v3>; ++ vqmmc-supply = <&vsys_3v3>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; ++ pinctrl-1 = <&emmc_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ mmc-ddr-1_8v; ++ mmc-hs200-1_8v; ++ max-frequency = <200000000>; ++ disable-wp; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&emmc_1v8>; ++}; ++ ++&tdmif_b { ++ status = "okay"; ++}; ++ ++&tdmout_b { ++ status = "okay"; ++}; ++ ++&tohdmitx { ++ status = "okay"; ++}; ++ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ max-speed = <2000000>; ++ clocks = <&wifi32k>; ++ clock-names = "lpo"; ++ }; ++}; ++ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&usb2_phy0 { ++ phy-supply = <&dc_in>; ++}; ++ ++&usb2_phy1 { ++ phy-supply = <&usb_pwr>; ++}; ++ ++&usb3_pcie_phy { ++ phy-supply = <&usb_pwr>; ++}; ++ ++&usb { ++ status = "okay"; ++ dr_mode = "peripheral"; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts +new file mode 100644 +index 000000000000..6bcf972b8bfa +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-khadas-vim3.dts +@@ -0,0 +1,15 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ * Copyright (c) 2019 Christian Hewitt ++ */ ++ ++/dts-v1/; ++ ++#include "meson-g12b-s922x.dtsi" ++#include "meson-g12b-khadas-vim3.dtsi" ++ ++/ { ++ compatible = "khadas,vim3", "amlogic,s922x", "amlogic,g12b"; ++}; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0088-FROMLIST-firmware-meson_sm-Mark-chip-struct-as-stati.patch b/packages/linux/patches/amlogic/amlogic-0088-FROMLIST-firmware-meson_sm-Mark-chip-struct-as-stati.patch new file mode 100644 index 0000000000..77caf37c1a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0088-FROMLIST-firmware-meson_sm-Mark-chip-struct-as-stati.patch @@ -0,0 +1,30 @@ +From 7f4fb59e10f9b3451a0995487122bb3f2807667f Mon Sep 17 00:00:00 2001 +From: Carlo Caione +Date: Sat, 10 Aug 2019 13:40:40 +0000 +Subject: [PATCH 088/186] FROMLIST: firmware: meson_sm: Mark chip struct as + static const + +No need to be a global struct. + +Reviewed-by: Jerome Brunet +Signed-off-by: Carlo Caione +--- + drivers/firmware/meson/meson_sm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c +index 8d908a8e0d20..772ca6726e7b 100644 +--- a/drivers/firmware/meson/meson_sm.c ++++ b/drivers/firmware/meson/meson_sm.c +@@ -35,7 +35,7 @@ struct meson_sm_chip { + struct meson_sm_cmd cmd[]; + }; + +-struct meson_sm_chip gxbb_chip = { ++static const struct meson_sm_chip gxbb_chip = { + .shmem_size = SZ_4K, + .cmd_shmem_in_base = 0x82000020, + .cmd_shmem_out_base = 0x82000021, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0089-FROMLIST-nvmem-meson-efuse-bindings-Add-secure-monit.patch b/packages/linux/patches/amlogic/amlogic-0089-FROMLIST-nvmem-meson-efuse-bindings-Add-secure-monit.patch new file mode 100644 index 0000000000..8d2e2f1ac1 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0089-FROMLIST-nvmem-meson-efuse-bindings-Add-secure-monit.patch @@ -0,0 +1,49 @@ +From 1ebcd7d499b9b06d3ead674d883d18fef2184348 Mon Sep 17 00:00:00 2001 +From: Carlo Caione +Date: Sat, 10 Aug 2019 13:42:08 +0000 +Subject: [PATCH 089/186] FROMLIST: nvmem: meson-efuse: bindings: Add + secure-monitor phandle + +Add a new property to link the nvmem driver to the secure-monitor. The +nvmem driver needs to access the secure-monitor to be able to access the +fuses. + +Signed-off-by: Carlo Caione +--- + Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt b/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt +index 2e0723ab3384..f7b3ed74db54 100644 +--- a/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt ++++ b/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt +@@ -4,6 +4,7 @@ Required properties: + - compatible: should be "amlogic,meson-gxbb-efuse" + - clocks: phandle to the efuse peripheral clock provided by the + clock controller. ++- secure-monitor: phandle to the secure-monitor node + + = Data cells = + Are child nodes of eFuse, bindings of which as described in +@@ -16,6 +17,7 @@ Example: + clocks = <&clkc CLKID_EFUSE>; + #address-cells = <1>; + #size-cells = <1>; ++ secure-monitor = <&sm>; + + sn: sn@14 { + reg = <0x14 0x10>; +@@ -30,6 +32,10 @@ Example: + }; + }; + ++ sm: secure-monitor { ++ compatible = "amlogic,meson-gxbb-sm"; ++ }; ++ + = Data consumers = + Are device nodes which consume nvmem data cells. + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0090-FROMLIST-arm64-dts-meson-Link-nvmem-and-secure-monit.patch b/packages/linux/patches/amlogic/amlogic-0090-FROMLIST-arm64-dts-meson-Link-nvmem-and-secure-monit.patch new file mode 100644 index 0000000000..141857133a --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0090-FROMLIST-arm64-dts-meson-Link-nvmem-and-secure-monit.patch @@ -0,0 +1,54 @@ +From 1438d7d39c0c4a8b8432acf7318da20f09693564 Mon Sep 17 00:00:00 2001 +From: Carlo Caione +Date: Sat, 10 Aug 2019 13:45:41 +0000 +Subject: [PATCH 090/186] FROMLIST: arm64: dts: meson: Link nvmem and + secure-monitor nodes + +The former is going to use the latter to retrieve the efuses data. + +Signed-off-by: Carlo Caione +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 1 + + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 1 + + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index 12bf959c17a7..15a7b7998dd4 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -117,6 +117,7 @@ + #address-cells = <1>; + #size-cells = <1>; + read-only; ++ secure-monitor = <&sm>; + }; + + psci { +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 71fd725dee77..da0dc80b44cb 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -57,6 +57,7 @@ + #address-cells = <1>; + #size-cells = <1>; + read-only; ++ secure-monitor = <&sm>; + }; + + psci { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index e62aad5bf867..209f20bea4a1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -161,6 +161,7 @@ + #address-cells = <1>; + #size-cells = <1>; + read-only; ++ secure-monitor = <&sm>; + + sn: sn@14 { + reg = <0x14 0x10>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0091-FROMLIST-firmware-meson_sm-Rework-driver-as-a-proper.patch b/packages/linux/patches/amlogic/amlogic-0091-FROMLIST-firmware-meson_sm-Rework-driver-as-a-proper.patch new file mode 100644 index 0000000000..4975cbd478 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0091-FROMLIST-firmware-meson_sm-Rework-driver-as-a-proper.patch @@ -0,0 +1,347 @@ +From 1fed41a5fcf6f23238f9c766e4054b73b8d7365f Mon Sep 17 00:00:00 2001 +From: Carlo Caione +Date: Sat, 10 Aug 2019 13:46:54 +0000 +Subject: [PATCH 091/186] FROMLIST: firmware: meson_sm: Rework driver as a + proper platform driver + +The secure monitor driver is currently a frankenstein driver which is +registered as a platform driver but its functionality goes through a +global struct accessed by the consumer drivers using exported helper +functions. + +Try to tidy up the driver moving the firmware struct into the driver +data and make the consumer drivers referencing the secure-monitor using +a new property in the DT. + +Currently only the nvmem driver is using this API so we can fix it in +the same commit. + +Reviewed-by: Jerome Brunet +Signed-off-by: Carlo Caione +--- + drivers/firmware/meson/meson_sm.c | 94 +++++++++++++++++-------- + drivers/nvmem/meson-efuse.c | 24 ++++++- + include/linux/firmware/meson/meson_sm.h | 15 ++-- + 3 files changed, 94 insertions(+), 39 deletions(-) + +diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c +index 772ca6726e7b..2e36a2aa274c 100644 +--- a/drivers/firmware/meson/meson_sm.c ++++ b/drivers/firmware/meson/meson_sm.c +@@ -54,8 +54,6 @@ struct meson_sm_firmware { + void __iomem *sm_shmem_out_base; + }; + +-static struct meson_sm_firmware fw; +- + static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip, + unsigned int cmd_index) + { +@@ -90,6 +88,7 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size) + /** + * meson_sm_call - generic SMC32 call to the secure-monitor + * ++ * @fw: Pointer to secure-monitor firmware + * @cmd_index: Index of the SMC32 function ID + * @ret: Returned value + * @arg0: SMC32 Argument 0 +@@ -100,15 +99,15 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size) + * + * Return: 0 on success, a negative value on error + */ +-int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, +- u32 arg1, u32 arg2, u32 arg3, u32 arg4) ++int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index, ++ u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) + { + u32 cmd, lret; + +- if (!fw.chip) ++ if (!fw->chip) + return -ENOENT; + +- cmd = meson_sm_get_cmd(fw.chip, cmd_index); ++ cmd = meson_sm_get_cmd(fw->chip, cmd_index); + if (!cmd) + return -EINVAL; + +@@ -124,6 +123,7 @@ EXPORT_SYMBOL(meson_sm_call); + /** + * meson_sm_call_read - retrieve data from secure-monitor + * ++ * @fw: Pointer to secure-monitor firmware + * @buffer: Buffer to store the retrieved data + * @bsize: Size of the buffer + * @cmd_index: Index of the SMC32 function ID +@@ -137,22 +137,23 @@ EXPORT_SYMBOL(meson_sm_call); + * When 0 is returned there is no guarantee about the amount of + * data read and bsize bytes are copied in buffer. + */ +-int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index, +- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) ++int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer, ++ unsigned int bsize, unsigned int cmd_index, u32 arg0, ++ u32 arg1, u32 arg2, u32 arg3, u32 arg4) + { + u32 size; + int ret; + +- if (!fw.chip) ++ if (!fw->chip) + return -ENOENT; + +- if (!fw.chip->cmd_shmem_out_base) ++ if (!fw->chip->cmd_shmem_out_base) + return -EINVAL; + +- if (bsize > fw.chip->shmem_size) ++ if (bsize > fw->chip->shmem_size) + return -EINVAL; + +- if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) ++ if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) + return -EINVAL; + + if (size > bsize) +@@ -164,7 +165,7 @@ int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index, + size = bsize; + + if (buffer) +- memcpy(buffer, fw.sm_shmem_out_base, size); ++ memcpy(buffer, fw->sm_shmem_out_base, size); + + return ret; + } +@@ -173,6 +174,7 @@ EXPORT_SYMBOL(meson_sm_call_read); + /** + * meson_sm_call_write - send data to secure-monitor + * ++ * @fw: Pointer to secure-monitor firmware + * @buffer: Buffer containing data to send + * @size: Size of the data to send + * @cmd_index: Index of the SMC32 function ID +@@ -184,23 +186,24 @@ EXPORT_SYMBOL(meson_sm_call_read); + * + * Return: size of sent data on success, a negative value on error + */ +-int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index, +- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) ++int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer, ++ unsigned int size, unsigned int cmd_index, u32 arg0, ++ u32 arg1, u32 arg2, u32 arg3, u32 arg4) + { + u32 written; + +- if (!fw.chip) ++ if (!fw->chip) + return -ENOENT; + +- if (size > fw.chip->shmem_size) ++ if (size > fw->chip->shmem_size) + return -EINVAL; + +- if (!fw.chip->cmd_shmem_in_base) ++ if (!fw->chip->cmd_shmem_in_base) + return -EINVAL; + +- memcpy(fw.sm_shmem_in_base, buffer, size); ++ memcpy(fw->sm_shmem_in_base, buffer, size); + +- if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0) ++ if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0) + return -EINVAL; + + if (!written) +@@ -210,6 +213,24 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index, + } + EXPORT_SYMBOL(meson_sm_call_write); + ++/** ++ * meson_sm_get - get pointer to meson_sm_firmware structure. ++ * ++ * @sm_node: Pointer to the secure-monitor Device Tree node. ++ * ++ * Return: NULL is the secure-monitor device is not ready. ++ */ ++struct meson_sm_firmware *meson_sm_get(struct device_node *sm_node) ++{ ++ struct platform_device *pdev = of_find_device_by_node(sm_node); ++ ++ if (!pdev) ++ return NULL; ++ ++ return platform_get_drvdata(pdev); ++} ++EXPORT_SYMBOL_GPL(meson_sm_get); ++ + #define SM_CHIP_ID_LENGTH 119 + #define SM_CHIP_ID_OFFSET 4 + #define SM_CHIP_ID_SIZE 12 +@@ -217,14 +238,18 @@ EXPORT_SYMBOL(meson_sm_call_write); + static ssize_t serial_show(struct device *dev, struct device_attribute *attr, + char *buf) + { ++ struct platform_device *pdev = to_platform_device(dev); ++ struct meson_sm_firmware *fw; + uint8_t *id_buf; + int ret; + ++ fw = platform_get_drvdata(pdev); ++ + id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL); + if (!id_buf) + return -ENOMEM; + +- ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID, ++ ret = meson_sm_call_read(fw, id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID, + 0, 0, 0, 0, 0); + if (ret < 0) { + kfree(id_buf); +@@ -268,25 +293,34 @@ static const struct of_device_id meson_sm_ids[] = { + + static int __init meson_sm_probe(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; + const struct meson_sm_chip *chip; ++ struct meson_sm_firmware *fw; ++ ++ fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); ++ if (!fw) ++ return -ENOMEM; + +- chip = of_match_device(meson_sm_ids, &pdev->dev)->data; ++ chip = of_match_device(meson_sm_ids, dev)->data; + + if (chip->cmd_shmem_in_base) { +- fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base, +- chip->shmem_size); +- if (WARN_ON(!fw.sm_shmem_in_base)) ++ fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base, ++ chip->shmem_size); ++ if (WARN_ON(!fw->sm_shmem_in_base)) + goto out; + } + + if (chip->cmd_shmem_out_base) { +- fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base, +- chip->shmem_size); +- if (WARN_ON(!fw.sm_shmem_out_base)) ++ fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base, ++ chip->shmem_size); ++ if (WARN_ON(!fw->sm_shmem_out_base)) + goto out_in_base; + } + +- fw.chip = chip; ++ fw->chip = chip; ++ ++ platform_set_drvdata(pdev, fw); ++ + pr_info("secure-monitor enabled\n"); + + if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group)) +@@ -295,7 +329,7 @@ static int __init meson_sm_probe(struct platform_device *pdev) + return 0; + + out_in_base: +- iounmap(fw.sm_shmem_in_base); ++ iounmap(fw->sm_shmem_in_base); + out: + return -EINVAL; + } +diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c +index 39bd76306033..d6b533497ce1 100644 +--- a/drivers/nvmem/meson-efuse.c ++++ b/drivers/nvmem/meson-efuse.c +@@ -17,14 +17,18 @@ + static int meson_efuse_read(void *context, unsigned int offset, + void *val, size_t bytes) + { +- return meson_sm_call_read((u8 *)val, bytes, SM_EFUSE_READ, offset, ++ struct meson_sm_firmware *fw = context; ++ ++ return meson_sm_call_read(fw, (u8 *)val, bytes, SM_EFUSE_READ, offset, + bytes, 0, 0, 0); + } + + static int meson_efuse_write(void *context, unsigned int offset, + void *val, size_t bytes) + { +- return meson_sm_call_write((u8 *)val, bytes, SM_EFUSE_WRITE, offset, ++ struct meson_sm_firmware *fw = context; ++ ++ return meson_sm_call_write(fw, (u8 *)val, bytes, SM_EFUSE_WRITE, offset, + bytes, 0, 0, 0); + } + +@@ -37,12 +41,25 @@ MODULE_DEVICE_TABLE(of, meson_efuse_match); + static int meson_efuse_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ struct meson_sm_firmware *fw; ++ struct device_node *sm_np; + struct nvmem_device *nvmem; + struct nvmem_config *econfig; + struct clk *clk; + unsigned int size; + int ret; + ++ sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0); ++ if (!sm_np) { ++ dev_err(&pdev->dev, "no secure-monitor node\n"); ++ return -ENODEV; ++ } ++ ++ fw = meson_sm_get(sm_np); ++ of_node_put(sm_np); ++ if (!fw) ++ return -EPROBE_DEFER; ++ + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); +@@ -65,7 +82,7 @@ static int meson_efuse_probe(struct platform_device *pdev) + return ret; + } + +- if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) { ++ if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) { + dev_err(dev, "failed to get max user"); + return -EINVAL; + } +@@ -81,6 +98,7 @@ static int meson_efuse_probe(struct platform_device *pdev) + econfig->reg_read = meson_efuse_read; + econfig->reg_write = meson_efuse_write; + econfig->size = size; ++ econfig->priv = fw; + + nvmem = devm_nvmem_register(&pdev->dev, econfig); + +diff --git a/include/linux/firmware/meson/meson_sm.h b/include/linux/firmware/meson/meson_sm.h +index 7613bf7c9442..6669e2a1d5fd 100644 +--- a/include/linux/firmware/meson/meson_sm.h ++++ b/include/linux/firmware/meson/meson_sm.h +@@ -16,11 +16,14 @@ enum { + + struct meson_sm_firmware; + +-int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, u32 arg1, +- u32 arg2, u32 arg3, u32 arg4); +-int meson_sm_call_write(void *buffer, unsigned int b_size, unsigned int cmd_index, +- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); +-int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index, +- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); ++int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index, ++ u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); ++int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer, ++ unsigned int b_size, unsigned int cmd_index, u32 arg0, ++ u32 arg1, u32 arg2, u32 arg3, u32 arg4); ++int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer, ++ unsigned int bsize, unsigned int cmd_index, u32 arg0, ++ u32 arg1, u32 arg2, u32 arg3, u32 arg4); ++struct meson_sm_firmware *meson_sm_get(struct device_node *firmware_node); + + #endif /* _MESON_SM_FW_H_ */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0092-FROMLIST-arm64-dts-meson-g12a-audio-clock-controller.patch b/packages/linux/patches/amlogic/amlogic-0092-FROMLIST-arm64-dts-meson-g12a-audio-clock-controller.patch new file mode 100644 index 0000000000..a9099d593b --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0092-FROMLIST-arm64-dts-meson-g12a-audio-clock-controller.patch @@ -0,0 +1,29 @@ +From 5ef9c6efe2ab55a2b8d8ab478d9ba43337fe6996 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 20 Aug 2019 15:02:29 +0000 +Subject: [PATCH 092/186] FROMLIST: arm64: dts: meson: g12a: audio clock + controller provides resets + +The clock controller dedicated to audio clocks also provides reset lines +on the g12 SoC family + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index da0dc80b44cb..f90d681c28bd 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -1455,6 +1455,7 @@ + compatible = "amlogic,g12a-audio-clkc"; + reg = <0x0 0x0 0x0 0xb4>; + #clock-cells = <1>; ++ #reset-cells = <1>; + + clocks = <&clkc CLKID_AUDIO>, + <&clkc CLKID_MPLL0>, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0093-FROMLIST-arm64-dts-meson-g12a-add-reset-to-tdm-forma.patch b/packages/linux/patches/amlogic/amlogic-0093-FROMLIST-arm64-dts-meson-g12a-add-reset-to-tdm-forma.patch new file mode 100644 index 0000000000..0e9ad96003 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0093-FROMLIST-arm64-dts-meson-g12a-add-reset-to-tdm-forma.patch @@ -0,0 +1,85 @@ +From a52df786c1877dd433765142d4483e1767a7640f Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 20 Aug 2019 15:07:17 +0000 +Subject: [PATCH 093/186] FROMLIST: arm64: dts: meson: g12a: add reset to tdm + formatters + +Add the reset to the TDM formatters of the g12a. This helps +with channel mapping when a playback/capture uses more than 1 lane. + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index f90d681c28bd..2fa4b43f2dad 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + + / { +@@ -1564,6 +1565,7 @@ + "amlogic,axg-tdmin"; + reg = <0x0 0x300 0x0 0x40>; + sound-name-prefix = "TDMIN_A"; ++ resets = <&clkc_audio AUD_RESET_TDMIN_A>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_A>, + <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>, +@@ -1579,6 +1581,7 @@ + "amlogic,axg-tdmin"; + reg = <0x0 0x340 0x0 0x40>; + sound-name-prefix = "TDMIN_B"; ++ resets = <&clkc_audio AUD_RESET_TDMIN_B>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_B>, + <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>, +@@ -1594,6 +1597,7 @@ + "amlogic,axg-tdmin"; + reg = <0x0 0x380 0x0 0x40>; + sound-name-prefix = "TDMIN_C"; ++ resets = <&clkc_audio AUD_RESET_TDMIN_C>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_C>, + <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>, +@@ -1609,6 +1613,7 @@ + "amlogic,axg-tdmin"; + reg = <0x0 0x3c0 0x0 0x40>; + sound-name-prefix = "TDMIN_LB"; ++ resets = <&clkc_audio AUD_RESET_TDMIN_LB>; + clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>, + <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>, + <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>, +@@ -1648,6 +1653,7 @@ + compatible = "amlogic,g12a-tdmout"; + reg = <0x0 0x500 0x0 0x40>; + sound-name-prefix = "TDMOUT_A"; ++ resets = <&clkc_audio AUD_RESET_TDMOUT_A>; + clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, + <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, +@@ -1662,6 +1668,7 @@ + compatible = "amlogic,g12a-tdmout"; + reg = <0x0 0x540 0x0 0x40>; + sound-name-prefix = "TDMOUT_B"; ++ resets = <&clkc_audio AUD_RESET_TDMOUT_B>; + clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>, + <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>, +@@ -1676,6 +1683,7 @@ + compatible = "amlogic,g12a-tdmout"; + reg = <0x0 0x580 0x0 0x40>; + sound-name-prefix = "TDMOUT_C"; ++ resets = <&clkc_audio AUD_RESET_TDMOUT_C>; + clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>, + <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0094-FROMLIST-ASoC-meson-axg-tdm-formatter-free-reset-on-.patch b/packages/linux/patches/amlogic/amlogic-0094-FROMLIST-ASoC-meson-axg-tdm-formatter-free-reset-on-.patch new file mode 100644 index 0000000000..08417d5a7c --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0094-FROMLIST-ASoC-meson-axg-tdm-formatter-free-reset-on-.patch @@ -0,0 +1,31 @@ +From 600ca9000107683458570dc8b2cc6c73d318e83c Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 20 Aug 2019 15:09:58 +0000 +Subject: [PATCH 094/186] FROMLIST: ASoC: meson: axg-tdm-formatter: free reset + on device removal + +Use the devm variant to get the formatter reset so it is properly freed +on device removal + +Fixes: 751bd5db5260 ("ASoC: meson: axg-tdm-formatter: add reset") +Signed-off-by: Jerome Brunet +--- + sound/soc/meson/axg-tdm-formatter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c +index 2e498201139f..1a0bf9d3836d 100644 +--- a/sound/soc/meson/axg-tdm-formatter.c ++++ b/sound/soc/meson/axg-tdm-formatter.c +@@ -327,7 +327,7 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) + } + + /* Formatter dedicated reset line */ +- formatter->reset = reset_control_get_optional_exclusive(dev, NULL); ++ formatter->reset = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(formatter->reset)) { + ret = PTR_ERR(formatter->reset); + if (ret != -EPROBE_DEFER) +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0095-FROMLIST-ASoC-meson-g12a-tohdmitx-require-regmap-mmi.patch b/packages/linux/patches/amlogic/amlogic-0095-FROMLIST-ASoC-meson-g12a-tohdmitx-require-regmap-mmi.patch new file mode 100644 index 0000000000..8b6e86189f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0095-FROMLIST-ASoC-meson-g12a-tohdmitx-require-regmap-mmi.patch @@ -0,0 +1,29 @@ +From 329151cbf8444d19f39e23968c24fb1d81578738 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 20 Aug 2019 15:12:11 +0000 +Subject: [PATCH 095/186] FROMLIST: ASoC: meson: g12a-tohdmitx: require regmap + mmio + +The tohdmitx glue uses regmap MMIO so it should require it. + +Fixes: c8609f3870f7 ("ASoC: meson: add g12a tohdmitx control") +Signed-off-by: Jerome Brunet +--- + sound/soc/meson/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig +index 63b38c123103..2e3676147cea 100644 +--- a/sound/soc/meson/Kconfig ++++ b/sound/soc/meson/Kconfig +@@ -87,6 +87,7 @@ config SND_MESON_AXG_PDM + + config SND_MESON_G12A_TOHDMITX + tristate "Amlogic G12A To HDMI TX Control Support" ++ select REGMAP_MMIO + imply SND_SOC_HDMI_CODEC + help + Select Y or M to add support for HDMI audio on the g12a SoC +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0096-FROMLIST-drm-meson-vclk-use-the-correct-G12A-frac-ma.patch b/packages/linux/patches/amlogic/amlogic-0096-FROMLIST-drm-meson-vclk-use-the-correct-G12A-frac-ma.patch new file mode 100644 index 0000000000..ff96a01645 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0096-FROMLIST-drm-meson-vclk-use-the-correct-G12A-frac-ma.patch @@ -0,0 +1,47 @@ +From 5922d7ec7001093e7236bcd3d37d86a788c8432e Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 28 Aug 2019 13:29:48 +0000 +Subject: [PATCH 096/186] FROMLIST: drm/meson: vclk: use the correct G12A frac + max value + +When calculating the HDMI PLL settings for a DMT mode PHY frequency, +use the correct max fractional PLL value for G12A VPU. + +With this fix, we can finally setup the 1024x768-60 mode. + +Fixes: 202b9808f8ed ("drm/meson: Add G12A Video Clock setup") +Signed-off-by: Neil Armstrong +--- +Fixed typo in commit log, 1024x76 => 1024x768 +--- + drivers/gpu/drm/meson/meson_vclk.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index be6e152fc75a..08c4f82c820d 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -637,13 +637,18 @@ static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, + if (frac >= HDMI_FRAC_MAX_GXBB) + return false; + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + /* Empiric supported min/max dividers */ + if (m < 106 || m > 247) + return false; + if (frac >= HDMI_FRAC_MAX_GXL) + return false; ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ /* Empiric supported min/max dividers */ ++ if (m < 106 || m > 247) ++ return false; ++ if (frac >= HDMI_FRAC_MAX_G12A) ++ return false; + } + + return true; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0097-TEMP-drm-panfrost-add-support-for-custom-soft-reset-.patch b/packages/linux/patches/amlogic/amlogic-0097-TEMP-drm-panfrost-add-support-for-custom-soft-reset-.patch new file mode 100644 index 0000000000..5bb7f9b5c0 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0097-TEMP-drm-panfrost-add-support-for-custom-soft-reset-.patch @@ -0,0 +1,62 @@ +From 34ff8f36e6f144166303271a8fa38c1976e7aec9 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 09:37:38 +0100 +Subject: [PATCH 097/186] TEMP: drm/panfrost: add support for custom soft-reset + on Amlogic GXM + +(cherry picked from commit 2e5230c1bf9cf01f035da72291cc460cb3b37096) +--- + drivers/gpu/drm/panfrost/panfrost_gpu.c | 13 ++++++++++++- + drivers/gpu/drm/panfrost/panfrost_regs.h | 4 ++++ + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c +index 20ab333fc925..2e1c6955efac 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c ++++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c +@@ -7,7 +7,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + +@@ -59,7 +61,16 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) + + gpu_write(pfdev, GPU_INT_MASK, 0); + gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); +- gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); ++ ++ if (of_device_is_compatible(pfdev->dev->of_node, "amlogic,meson-gxm-mali")) { ++ reset_control_assert(pfdev->rstc); ++ udelay(10); ++ reset_control_deassert(pfdev->rstc); ++ ++ gpu_write(pfdev, GPU_PWR_KEY, 0x2968A819); ++ gpu_write(pfdev, GPU_PWR_OVERRIDE1, 0xfff | (0x20 << 16)); ++ } else ++ gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); + + ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, + val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000); +diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h +index ea38ac60581c..7a0cfa629760 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_regs.h ++++ b/drivers/gpu/drm/panfrost/panfrost_regs.h +@@ -69,6 +69,10 @@ + #define GPU_PRFCNT_TILER_EN 0x74 + #define GPU_PRFCNT_MMU_L2_EN 0x7c + ++#define GPU_PWR_KEY 0x050 /* (WO) Power manager key register */ ++#define GPU_PWR_OVERRIDE0 0x054 /* (RW) Power manager override settings */ ++#define GPU_PWR_OVERRIDE1 0x058 /* (RW) Power manager override settings */ ++ + #define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ + #define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ + #define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0098-TEMP-drm-panfrost-kernel-driver-fix-1-2.patch b/packages/linux/patches/amlogic/amlogic-0098-TEMP-drm-panfrost-kernel-driver-fix-1-2.patch new file mode 100644 index 0000000000..9f8d03fd46 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0098-TEMP-drm-panfrost-kernel-driver-fix-1-2.patch @@ -0,0 +1,29 @@ +From d0a03a1870329ebd76ab6affcfa3f103183ea771 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 12 Jul 2019 21:20:38 +0000 +Subject: [PATCH 098/186] TEMP: drm/panfrost: kernel driver fix 1/2 + +https://lkml.org/lkml/2019/5/29/786 + +Signed-off-by: Christian Hewitt +--- + drivers/iommu/io-pgtable-arm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c +index 161a7d56264d..c1048e741c66 100644 +--- a/drivers/iommu/io-pgtable-arm.c ++++ b/drivers/iommu/io-pgtable-arm.c +@@ -1022,7 +1022,9 @@ arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) + iop = arm_64_lpae_alloc_pgtable_s1(cfg, cookie); + if (iop) { + u64 mair, ttbr; ++ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(&iop->ops); + ++ data->levels = 4; + /* Copy values as union fields overlap */ + mair = cfg->arm_lpae_s1_cfg.mair[0]; + ttbr = cfg->arm_lpae_s1_cfg.ttbr[0]; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0099-TEMP-drm-panfrost-kernel-driver-fix-2-2.patch b/packages/linux/patches/amlogic/amlogic-0099-TEMP-drm-panfrost-kernel-driver-fix-2-2.patch new file mode 100644 index 0000000000..cd8b08d036 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0099-TEMP-drm-panfrost-kernel-driver-fix-2-2.patch @@ -0,0 +1,28 @@ +From 5c46c60ef67f0d417ea29602e21f435b5da19a3e Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 12 Jul 2019 21:36:32 +0000 +Subject: [PATCH 099/186] TEMP: drm/panfrost: kernel driver fix 2/2 + +https://patchwork.kernel.org/patch/10954241/ + +Signed-off-by: Christian Hewitt +--- + drivers/iommu/io-pgtable-arm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c +index c1048e741c66..a69b9b5d0f0f 100644 +--- a/drivers/iommu/io-pgtable-arm.c ++++ b/drivers/iommu/io-pgtable-arm.c +@@ -1015,7 +1015,7 @@ arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) + { + struct io_pgtable *iop; + +- if (cfg->ias != 48 || cfg->oas > 40) ++ if (cfg->ias > 48 || cfg->oas > 40) + return NULL; + + cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0100-TEMP-ARM64-defconfig-enable-CEC-support.patch b/packages/linux/patches/amlogic/amlogic-0100-TEMP-ARM64-defconfig-enable-CEC-support.patch new file mode 100644 index 0000000000..9e79b23993 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0100-TEMP-ARM64-defconfig-enable-CEC-support.patch @@ -0,0 +1,47 @@ +From 4b0808ab45f174fd7ebcc3d20a8daeb83330a377 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 Nov 2017 12:09:40 +0100 +Subject: [PATCH 100/186] TEMP: ARM64: defconfig: enable CEC support + +Turn on CONFIG_CEC_SUPPORT and CONFIG_CEC_PLATFORM_DRIVERS +Turn on CONFIG_VIDEO_MESON_AO_CEC as module +Turn on CONFIG_DRM_DW_HDMI_CEC as module + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/configs/defconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig +index 0e58ef02880c..1053815f20cc 100644 +--- a/arch/arm64/configs/defconfig ++++ b/arch/arm64/configs/defconfig +@@ -493,6 +493,7 @@ CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y + CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y ++CONFIG_MEDIA_CEC_SUPPORT=y + CONFIG_MEDIA_CONTROLLER=y + CONFIG_VIDEO_V4L2_SUBDEV_API=y + # CONFIG_DVB_NET is not set +@@ -506,6 +507,8 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m + CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m + CONFIG_VIDEO_RENESAS_FCP=m + CONFIG_VIDEO_RENESAS_VSP1=m ++CONFIG_CEC_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MESON_AO_CEC=m + CONFIG_DRM=m + CONFIG_DRM_I2C_NXP_TDA998X=m + CONFIG_DRM_NOUVEAU=m +@@ -530,6 +533,7 @@ CONFIG_DRM_TEGRA=m + CONFIG_DRM_PANEL_SIMPLE=m + CONFIG_DRM_SII902X=m + CONFIG_DRM_I2C_ADV7511=m ++CONFIG_DRM_DW_HDMI_CEC=m + CONFIG_DRM_VC4=m + CONFIG_DRM_HISI_HIBMC=m + CONFIG_DRM_HISI_KIRIN=m +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0101-TEMP-ASoC-meson-add-meson-audio-core-driver.patch b/packages/linux/patches/amlogic/amlogic-0101-TEMP-ASoC-meson-add-meson-audio-core-driver.patch new file mode 100644 index 0000000000..a5100d3fd2 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0101-TEMP-ASoC-meson-add-meson-audio-core-driver.patch @@ -0,0 +1,303 @@ +From 7d7d3f4b97c32fab990320576fe4b1ef93705a83 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 11:49:55 +0200 +Subject: [PATCH 101/186] TEMP: ASoC: meson: add meson audio core driver + +This patch adds support for the audio core driver for the Amlogic Meson SoC +family. The purpose of this driver is to properly reset the audio block and +provide register access for the different devices scattered in this address +space. This includes output and input DMAs, pcm, i2s and spdif dai, card +level routing, internal codec for the gxl variant + +For more information, please refer to the section 5 of the public datasheet +of the S905 (gxbb). This datasheet is available here: [0]. + +[0]: http://dn.odroid.com/S905/DataSheet/S905_Public_Datasheet_V1.1.4.pdf + +Signed-off-by: Jerome Brunet +--- + sound/soc/Kconfig | 1 + + sound/soc/Makefile | 1 + + sound/soc/meson-gx/Kconfig | 11 ++ + sound/soc/meson-gx/Makefile | 3 + + sound/soc/meson-gx/audio-core.c | 180 ++++++++++++++++++++++++++++++++ + sound/soc/meson-gx/audio-core.h | 28 +++++ + 6 files changed, 224 insertions(+) + create mode 100644 sound/soc/meson-gx/Kconfig + create mode 100644 sound/soc/meson-gx/Makefile + create mode 100644 sound/soc/meson-gx/audio-core.c + create mode 100644 sound/soc/meson-gx/audio-core.h + +diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig +index dc86e4073001..0148a95fd1ce 100644 +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -57,6 +57,7 @@ source "sound/soc/img/Kconfig" + source "sound/soc/intel/Kconfig" + source "sound/soc/mediatek/Kconfig" + source "sound/soc/meson/Kconfig" ++source "sound/soc/meson-gx/Kconfig" + source "sound/soc/mxs/Kconfig" + source "sound/soc/pxa/Kconfig" + source "sound/soc/qcom/Kconfig" +diff --git a/sound/soc/Makefile b/sound/soc/Makefile +index 919c3c027c62..9f1f4b0f45eb 100644 +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += img/ + obj-$(CONFIG_SND_SOC) += intel/ + obj-$(CONFIG_SND_SOC) += mediatek/ + obj-$(CONFIG_SND_SOC) += meson/ ++obj-$(CONFIG_SND_SOC) += meson-gx/ + obj-$(CONFIG_SND_SOC) += mxs/ + obj-$(CONFIG_SND_SOC) += nuc900/ + obj-$(CONFIG_SND_SOC) += kirkwood/ +diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig +new file mode 100644 +index 000000000000..280e49e7c16f +--- /dev/null ++++ b/sound/soc/meson-gx/Kconfig +@@ -0,0 +1,11 @@ ++menuconfig SND_SOC_MESON_GX ++ tristate "ASoC WIP support for Amlogic GX SoCs" ++ depends on ARCH_MESON ++ select MFD_CORE ++ select REGMAP_MMIO ++ help ++ Say Y or M if you want to add support for codecs attached to ++ the Amlogic Meson SoCs Audio interfaces. You will also need to ++ select the audio interfaces to support below. This WIP drivers ++ are kept separated from the actual upstream amlogic ASoC driver ++ to minimize conflicts until support is submitted and merged +diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile +new file mode 100644 +index 000000000000..6f124c31a85c +--- /dev/null ++++ b/sound/soc/meson-gx/Makefile +@@ -0,0 +1,3 @@ ++snd-soc-meson-audio-core-objs := audio-core.o ++ ++obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o +diff --git a/sound/soc/meson-gx/audio-core.c b/sound/soc/meson-gx/audio-core.c +new file mode 100644 +index 000000000000..68f7e0e58f5f +--- /dev/null ++++ b/sound/soc/meson-gx/audio-core.c +@@ -0,0 +1,180 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "audio-core.h" ++ ++#define DRV_NAME "meson-gx-audio-core" ++ ++static const char * const acore_clock_names[] = { "aiu_top", ++ "aiu_glue", ++ "audin" }; ++ ++static int meson_acore_init_clocks(struct device *dev) ++{ ++ struct clk *clock; ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(acore_clock_names); i++) { ++ clock = devm_clk_get(dev, acore_clock_names[i]); ++ if (IS_ERR(clock)) { ++ if (PTR_ERR(clock) != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get %s clock\n", ++ acore_clock_names[i]); ++ return PTR_ERR(clock); ++ } ++ ++ ret = clk_prepare_enable(clock); ++ if (ret) { ++ dev_err(dev, "Failed to enable %s clock\n", ++ acore_clock_names[i]); ++ return ret; ++ } ++ ++ ret = devm_add_action_or_reset(dev, ++ (void(*)(void *))clk_disable_unprepare, ++ clock); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const char * const acore_reset_names[] = { "aiu", ++ "audin" }; ++ ++static int meson_acore_init_resets(struct device *dev) ++{ ++ struct reset_control *reset; ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(acore_reset_names); i++) { ++ reset = devm_reset_control_get_exclusive(dev, ++ acore_reset_names[i]); ++ if (IS_ERR(reset)) { ++ if (PTR_ERR(reset) != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get %s reset\n", ++ acore_reset_names[i]); ++ return PTR_ERR(reset); ++ } ++ ++ ret = reset_control_reset(reset); ++ if (ret) { ++ dev_err(dev, "Failed to pulse %s reset\n", ++ acore_reset_names[i]); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct regmap_config meson_acore_regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++}; ++ ++static const struct mfd_cell meson_acore_devs[] = { ++ { ++ .name = "meson-aiu-i2s", ++ .of_compatible = "amlogic,meson-aiu-i2s", ++ }, ++ { ++ .name = "meson-aiu-spdif", ++ .of_compatible = "amlogic,meson-aiu-spdif", ++ }, ++}; ++ ++static int meson_acore_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct meson_audio_core_data *data; ++ struct resource *res; ++ void __iomem *regs; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, data); ++ ++ ret = meson_acore_init_clocks(dev); ++ if (ret) ++ return ret; ++ ++ ret = meson_acore_init_resets(dev); ++ if (ret) ++ return ret; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aiu"); ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ data->aiu = devm_regmap_init_mmio(dev, regs, ++ &meson_acore_regmap_config); ++ if (IS_ERR(data->aiu)) { ++ dev_err(dev, "Couldn't create the AIU regmap\n"); ++ return PTR_ERR(data->aiu); ++ } ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audin"); ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ data->audin = devm_regmap_init_mmio(dev, regs, ++ &meson_acore_regmap_config); ++ if (IS_ERR(data->audin)) { ++ dev_err(dev, "Couldn't create the AUDIN regmap\n"); ++ return PTR_ERR(data->audin); ++ } ++ ++ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, meson_acore_devs, ++ ARRAY_SIZE(meson_acore_devs), NULL, 0, ++ NULL); ++} ++ ++static const struct of_device_id meson_acore_of_match[] = { ++ { .compatible = "amlogic,meson-gx-audio-core", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, meson_acore_of_match); ++ ++static struct platform_driver meson_acore_pdrv = { ++ .probe = meson_acore_probe, ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = meson_acore_of_match, ++ }, ++}; ++module_platform_driver(meson_acore_pdrv); ++ ++MODULE_DESCRIPTION("Meson Audio Core Driver"); ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/meson-gx/audio-core.h b/sound/soc/meson-gx/audio-core.h +new file mode 100644 +index 000000000000..6e7a24cdc4a9 +--- /dev/null ++++ b/sound/soc/meson-gx/audio-core.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef _MESON_AUDIO_CORE_H_ ++#define _MESON_AUDIO_CORE_H_ ++ ++struct meson_audio_core_data { ++ struct regmap *aiu; ++ struct regmap *audin; ++}; ++ ++#endif /* _MESON_AUDIO_CORE_H_ */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0102-TEMP-ASoC-meson-add-register-definitions.patch b/packages/linux/patches/amlogic/amlogic-0102-TEMP-ASoC-meson-add-register-definitions.patch new file mode 100644 index 0000000000..8b0f941de6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0102-TEMP-ASoC-meson-add-register-definitions.patch @@ -0,0 +1,360 @@ +From d3646a85ea7df097098353b1f5ab1f9fa3470e05 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 12:00:10 +0200 +Subject: [PATCH 102/186] TEMP: ASoC: meson: add register definitions + +Add the register definition for the AIU and AUDIN blocks + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/aiu-regs.h | 182 ++++++++++++++++++++++++++++++++ + sound/soc/meson-gx/audin-regs.h | 148 ++++++++++++++++++++++++++ + 2 files changed, 330 insertions(+) + create mode 100644 sound/soc/meson-gx/aiu-regs.h + create mode 100644 sound/soc/meson-gx/audin-regs.h + +diff --git a/sound/soc/meson-gx/aiu-regs.h b/sound/soc/meson-gx/aiu-regs.h +new file mode 100644 +index 000000000000..67391e64fe1c +--- /dev/null ++++ b/sound/soc/meson-gx/aiu-regs.h +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef _AIU_REGS_H_ ++#define _AIU_REGS_H_ ++ ++#define AIU_958_BPF 0x000 ++#define AIU_958_BRST 0x004 ++#define AIU_958_LENGTH 0x008 ++#define AIU_958_PADDSIZE 0x00C ++#define AIU_958_MISC 0x010 ++#define AIU_958_FORCE_LEFT 0x014 /* Unknown */ ++#define AIU_958_DISCARD_NUM 0x018 ++#define AIU_958_DCU_FF_CTRL 0x01C ++#define AIU_958_CHSTAT_L0 0x020 ++#define AIU_958_CHSTAT_L1 0x024 ++#define AIU_958_CTRL 0x028 ++#define AIU_958_RPT 0x02C ++#define AIU_I2S_MUTE_SWAP 0x030 ++#define AIU_I2S_SOURCE_DESC 0x034 ++#define AIU_I2S_MED_CTRL 0x038 ++#define AIU_I2S_MED_THRESH 0x03C ++#define AIU_I2S_DAC_CFG 0x040 ++#define AIU_I2S_SYNC 0x044 /* Unknown */ ++#define AIU_I2S_MISC 0x048 ++#define AIU_I2S_OUT_CFG 0x04C ++#define AIU_I2S_FF_CTRL 0x050 /* Unknown */ ++#define AIU_RST_SOFT 0x054 ++#define AIU_CLK_CTRL 0x058 ++#define AIU_MIX_ADCCFG 0x05C ++#define AIU_MIX_CTRL 0x060 ++#define AIU_CLK_CTRL_MORE 0x064 ++#define AIU_958_POP 0x068 ++#define AIU_MIX_GAIN 0x06C ++#define AIU_958_SYNWORD1 0x070 ++#define AIU_958_SYNWORD2 0x074 ++#define AIU_958_SYNWORD3 0x078 ++#define AIU_958_SYNWORD1_MASK 0x07C ++#define AIU_958_SYNWORD2_MASK 0x080 ++#define AIU_958_SYNWORD3_MASK 0x084 ++#define AIU_958_FFRDOUT_THD 0x088 ++#define AIU_958_LENGTH_PER_PAUSE 0x08C ++#define AIU_958_PAUSE_NUM 0x090 ++#define AIU_958_PAUSE_PAYLOAD 0x094 ++#define AIU_958_AUTO_PAUSE 0x098 ++#define AIU_958_PAUSE_PD_LENGTH 0x09C ++#define AIU_CODEC_DAC_LRCLK_CTRL 0x0A0 ++#define AIU_CODEC_ADC_LRCLK_CTRL 0x0A4 ++#define AIU_HDMI_CLK_DATA_CTRL 0x0A8 ++#define AIU_CODEC_CLK_DATA_CTRL 0x0AC ++#define AIU_ACODEC_CTRL 0x0B0 ++#define AIU_958_CHSTAT_R0 0x0C0 ++#define AIU_958_CHSTAT_R1 0x0C4 ++#define AIU_958_VALID_CTRL 0x0C8 ++#define AIU_AUDIO_AMP_REG0 0x0F0 /* Unknown */ ++#define AIU_AUDIO_AMP_REG1 0x0F4 /* Unknown */ ++#define AIU_AUDIO_AMP_REG2 0x0F8 /* Unknown */ ++#define AIU_AUDIO_AMP_REG3 0x0FC /* Unknown */ ++#define AIU_AIFIFO2_CTRL 0x100 ++#define AIU_AIFIFO2_STATUS 0x104 ++#define AIU_AIFIFO2_GBIT 0x108 ++#define AIU_AIFIFO2_CLB 0x10C ++#define AIU_CRC_CTRL 0x110 ++#define AIU_CRC_STATUS 0x114 ++#define AIU_CRC_SHIFT_REG 0x118 ++#define AIU_CRC_IREG 0x11C ++#define AIU_CRC_CAL_REG1 0x120 ++#define AIU_CRC_CAL_REG0 0x124 ++#define AIU_CRC_POLY_COEF1 0x128 ++#define AIU_CRC_POLY_COEF0 0x12C ++#define AIU_CRC_BIT_SIZE1 0x130 ++#define AIU_CRC_BIT_SIZE0 0x134 ++#define AIU_CRC_BIT_CNT1 0x138 ++#define AIU_CRC_BIT_CNT0 0x13C ++#define AIU_AMCLK_GATE_HI 0x140 ++#define AIU_AMCLK_GATE_LO 0x144 ++#define AIU_AMCLK_MSR 0x148 ++#define AIU_AUDAC_CTRL0 0x14C /* Unknown */ ++#define AIU_DELTA_SIGMA0 0x154 /* Unknown */ ++#define AIU_DELTA_SIGMA1 0x158 /* Unknown */ ++#define AIU_DELTA_SIGMA2 0x15C /* Unknown */ ++#define AIU_DELTA_SIGMA3 0x160 /* Unknown */ ++#define AIU_DELTA_SIGMA4 0x164 /* Unknown */ ++#define AIU_DELTA_SIGMA5 0x168 /* Unknown */ ++#define AIU_DELTA_SIGMA6 0x16C /* Unknown */ ++#define AIU_DELTA_SIGMA7 0x170 /* Unknown */ ++#define AIU_DELTA_SIGMA_LCNTS 0x174 /* Unknown */ ++#define AIU_DELTA_SIGMA_RCNTS 0x178 /* Unknown */ ++#define AIU_MEM_I2S_START_PTR 0x180 ++#define AIU_MEM_I2S_RD_PTR 0x184 ++#define AIU_MEM_I2S_END_PTR 0x188 ++#define AIU_MEM_I2S_MASKS 0x18C ++#define AIU_MEM_I2S_CONTROL 0x190 ++#define AIU_MEM_IEC958_START_PTR 0x194 ++#define AIU_MEM_IEC958_RD_PTR 0x198 ++#define AIU_MEM_IEC958_END_PTR 0x19C ++#define AIU_MEM_IEC958_MASKS 0x1A0 ++#define AIU_MEM_IEC958_CONTROL 0x1A4 ++#define AIU_MEM_AIFIFO2_START_PTR 0x1A8 ++#define AIU_MEM_AIFIFO2_CURR_PTR 0x1AC ++#define AIU_MEM_AIFIFO2_END_PTR 0x1B0 ++#define AIU_MEM_AIFIFO2_BYTES_AVAIL 0x1B4 ++#define AIU_MEM_AIFIFO2_CONTROL 0x1B8 ++#define AIU_MEM_AIFIFO2_MAN_WP 0x1BC ++#define AIU_MEM_AIFIFO2_MAN_RP 0x1C0 ++#define AIU_MEM_AIFIFO2_LEVEL 0x1C4 ++#define AIU_MEM_AIFIFO2_BUF_CNTL 0x1C8 ++#define AIU_MEM_I2S_MAN_WP 0x1CC ++#define AIU_MEM_I2S_MAN_RP 0x1D0 ++#define AIU_MEM_I2S_LEVEL 0x1D4 ++#define AIU_MEM_I2S_BUF_CNTL 0x1D8 ++#define AIU_MEM_I2S_BUF_WRAP_COUNT 0x1DC ++#define AIU_MEM_I2S_MEM_CTL 0x1E0 ++#define AIU_MEM_IEC958_MEM_CTL 0x1E4 ++#define AIU_MEM_IEC958_WRAP_COUNT 0x1E8 ++#define AIU_MEM_IEC958_IRQ_LEVEL 0x1EC ++#define AIU_MEM_IEC958_MAN_WP 0x1F0 ++#define AIU_MEM_IEC958_MAN_RP 0x1F4 ++#define AIU_MEM_IEC958_LEVEL 0x1F8 ++#define AIU_MEM_IEC958_BUF_CNTL 0x1FC ++#define AIU_AIFIFO_CTRL 0x200 ++#define AIU_AIFIFO_STATUS 0x204 ++#define AIU_AIFIFO_GBIT 0x208 ++#define AIU_AIFIFO_CLB 0x20C ++#define AIU_MEM_AIFIFO_START_PTR 0x210 ++#define AIU_MEM_AIFIFO_CURR_PTR 0x214 ++#define AIU_MEM_AIFIFO_END_PTR 0x218 ++#define AIU_MEM_AIFIFO_BYTES_AVAIL 0x21C ++#define AIU_MEM_AIFIFO_CONTROL 0x220 ++#define AIU_MEM_AIFIFO_MAN_WP 0x224 ++#define AIU_MEM_AIFIFO_MAN_RP 0x228 ++#define AIU_MEM_AIFIFO_LEVEL 0x22C ++#define AIU_MEM_AIFIFO_BUF_CNTL 0x230 ++#define AIU_MEM_AIFIFO_BUF_WRAP_COUNT 0x234 ++#define AIU_MEM_AIFIFO2_BUF_WRAP_COUNT 0x238 ++#define AIU_MEM_AIFIFO_MEM_CTL 0x23C ++#define AIFIFO_TIME_STAMP_CNTL 0x240 ++#define AIFIFO_TIME_STAMP_SYNC_0 0x244 ++#define AIFIFO_TIME_STAMP_SYNC_1 0x248 ++#define AIFIFO_TIME_STAMP_0 0x24C ++#define AIFIFO_TIME_STAMP_1 0x250 ++#define AIFIFO_TIME_STAMP_2 0x254 ++#define AIFIFO_TIME_STAMP_3 0x258 ++#define AIFIFO_TIME_STAMP_LENGTH 0x25C ++#define AIFIFO2_TIME_STAMP_CNTL 0x260 ++#define AIFIFO2_TIME_STAMP_SYNC_0 0x264 ++#define AIFIFO2_TIME_STAMP_SYNC_1 0x268 ++#define AIFIFO2_TIME_STAMP_0 0x26C ++#define AIFIFO2_TIME_STAMP_1 0x270 ++#define AIFIFO2_TIME_STAMP_2 0x274 ++#define AIFIFO2_TIME_STAMP_3 0x278 ++#define AIFIFO2_TIME_STAMP_LENGTH 0x27C ++#define IEC958_TIME_STAMP_CNTL 0x280 ++#define IEC958_TIME_STAMP_SYNC_0 0x284 ++#define IEC958_TIME_STAMP_SYNC_1 0x288 ++#define IEC958_TIME_STAMP_0 0x28C ++#define IEC958_TIME_STAMP_1 0x290 ++#define IEC958_TIME_STAMP_2 0x294 ++#define IEC958_TIME_STAMP_3 0x298 ++#define IEC958_TIME_STAMP_LENGTH 0x29C ++#define AIU_MEM_AIFIFO2_MEM_CTL 0x2A0 ++#define AIU_I2S_CBUS_DDR_CNTL 0x2A4 ++#define AIU_I2S_CBUS_DDR_WDATA 0x2A8 ++#define AIU_I2S_CBUS_DDR_ADDR 0x2AC ++ ++#endif /* _AIU_REGS_H_ */ +diff --git a/sound/soc/meson-gx/audin-regs.h b/sound/soc/meson-gx/audin-regs.h +new file mode 100644 +index 000000000000..f224610e80e7 +--- /dev/null ++++ b/sound/soc/meson-gx/audin-regs.h +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef _AUDIN_REGS_H_ ++#define _AUDIN_REGS_H_ ++ ++/* ++ * Note : ++ * Datasheet issue page 196 ++ * AUDIN_MUTE_VAL 0x35 => impossible: Already assigned to AUDIN_FIFO1_PTR ++ * AUDIN_FIFO1_PTR is more likely to be correct here since surrounding registers ++ * also deal with AUDIN_FIFO1 ++ * ++ * Clarification needed from Amlogic ++ */ ++ ++#define AUDIN_SPDIF_MODE 0x000 ++#define AUDIN_SPDIF_FS_CLK_RLTN 0x004 ++#define AUDIN_SPDIF_CHNL_STS_A 0x008 ++#define AUDIN_SPDIF_CHNL_STS_B 0x00C ++#define AUDIN_SPDIF_MISC 0x010 ++#define AUDIN_SPDIF_NPCM_PCPD 0x014 ++#define AUDIN_SPDIF_END 0x03C /* Unknown */ ++#define AUDIN_I2SIN_CTRL 0x040 ++#define AUDIN_SOURCE_SEL 0x044 ++#define AUDIN_DECODE_FORMAT 0x048 ++#define AUDIN_DECODE_CONTROL_STATUS 0x04C ++#define AUDIN_DECODE_CHANNEL_STATUS_A_0 0x050 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_1 0x054 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_2 0x058 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_3 0x05C ++#define AUDIN_DECODE_CHANNEL_STATUS_A_4 0x060 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_5 0x064 ++#define AUDIN_FIFO0_START 0x080 ++#define AUDIN_FIFO0_END 0x084 ++#define AUDIN_FIFO0_PTR 0x088 ++#define AUDIN_FIFO0_INTR 0x08C ++#define AUDIN_FIFO0_RDPTR 0x090 ++#define AUDIN_FIFO0_CTRL 0x094 ++#define AUDIN_FIFO0_CTRL1 0x098 ++#define AUDIN_FIFO0_LVL0 0x09C ++#define AUDIN_FIFO0_LVL1 0x0A0 ++#define AUDIN_FIFO0_LVL2 0x0A4 ++#define AUDIN_FIFO0_REQID 0x0C0 ++#define AUDIN_FIFO0_WRAP 0x0C4 ++#define AUDIN_FIFO1_START 0x0CC ++#define AUDIN_FIFO1_END 0x0D0 ++#define AUDIN_FIFO1_PTR 0x0D4 ++#define AUDIN_FIFO1_INTR 0x0D8 ++#define AUDIN_FIFO1_RDPTR 0x0DC ++#define AUDIN_FIFO1_CTRL 0x0E0 ++#define AUDIN_FIFO1_CTRL1 0x0E4 ++#define AUDIN_FIFO1_LVL0 0x100 ++#define AUDIN_FIFO1_LVL1 0x104 ++#define AUDIN_FIFO1_LVL2 0x108 ++#define AUDIN_FIFO1_REQID 0x10C ++#define AUDIN_FIFO1_WRAP 0x110 ++#define AUDIN_FIFO2_START 0x114 ++#define AUDIN_FIFO2_END 0x118 ++#define AUDIN_FIFO2_PTR 0x11C ++#define AUDIN_FIFO2_INTR 0x120 ++#define AUDIN_FIFO2_RDPTR 0x124 ++#define AUDIN_FIFO2_CTRL 0x128 ++#define AUDIN_FIFO2_CTRL1 0x12C ++#define AUDIN_FIFO2_LVL0 0x130 ++#define AUDIN_FIFO2_LVL1 0x134 ++#define AUDIN_FIFO2_LVL2 0x138 ++#define AUDIN_FIFO2_REQID 0x13C ++#define AUDIN_FIFO2_WRAP 0x140 ++#define AUDIN_INT_CTRL 0x144 ++#define AUDIN_FIFO_INT 0x148 ++#define PCMIN_CTRL0 0x180 ++#define PCMIN_CTRL1 0x184 ++#define PCMIN1_CTRL0 0x188 ++#define PCMIN1_CTRL1 0x18C ++#define PCMOUT_CTRL0 0x1C0 ++#define PCMOUT_CTRL1 0x1C4 ++#define PCMOUT_CTRL2 0x1C8 ++#define PCMOUT_CTRL3 0x1CC ++#define PCMOUT1_CTRL0 0x1D0 ++#define PCMOUT1_CTRL1 0x1D4 ++#define PCMOUT1_CTRL2 0x1D8 ++#define PCMOUT1_CTRL3 0x1DC ++#define AUDOUT_CTRL 0x200 ++#define AUDOUT_CTRL1 0x204 ++#define AUDOUT_BUF0_STA 0x208 ++#define AUDOUT_BUF0_EDA 0x20C ++#define AUDOUT_BUF0_WPTR 0x210 ++#define AUDOUT_BUF1_STA 0x214 ++#define AUDOUT_BUF1_EDA 0x218 ++#define AUDOUT_BUF1_WPTR 0x21C ++#define AUDOUT_FIFO_RPTR 0x220 ++#define AUDOUT_INTR_PTR 0x224 ++#define AUDOUT_FIFO_STS 0x228 ++#define AUDOUT1_CTRL 0x240 ++#define AUDOUT1_CTRL1 0x244 ++#define AUDOUT1_BUF0_STA 0x248 ++#define AUDOUT1_BUF0_EDA 0x24C ++#define AUDOUT1_BUF0_WPTR 0x250 ++#define AUDOUT1_BUF1_STA 0x254 ++#define AUDOUT1_BUF1_EDA 0x258 ++#define AUDOUT1_BUF1_WPTR 0x25C ++#define AUDOUT1_FIFO_RPTR 0x260 ++#define AUDOUT1_INTR_PTR 0x264 ++#define AUDOUT1_FIFO_STS 0x268 ++#define AUDIN_HDMI_MEAS_CTRL 0x280 ++#define AUDIN_HDMI_MEAS_CYCLES_M1 0x284 ++#define AUDIN_HDMI_MEAS_INTR_MASKN 0x288 ++#define AUDIN_HDMI_MEAS_INTR_STAT 0x28C ++#define AUDIN_HDMI_REF_CYCLES_STAT_0 0x290 ++#define AUDIN_HDMI_REF_CYCLES_STAT_1 0x294 ++#define AUDIN_HDMIRX_AFIFO_STAT 0x298 ++#define AUDIN_FIFO0_PIO_STS 0x2C0 ++#define AUDIN_FIFO0_PIO_RDL 0x2C4 ++#define AUDIN_FIFO0_PIO_RDH 0x2C8 ++#define AUDIN_FIFO1_PIO_STS 0x2CC ++#define AUDIN_FIFO1_PIO_RDL 0x2D0 ++#define AUDIN_FIFO1_PIO_RDH 0x2D4 ++#define AUDIN_FIFO2_PIO_STS 0x2D8 ++#define AUDIN_FIFO2_PIO_RDL 0x2DC ++#define AUDIN_FIFO2_PIO_RDH 0x2E0 ++#define AUDOUT_FIFO_PIO_STS 0x2E4 ++#define AUDOUT_FIFO_PIO_WRL 0x2E8 ++#define AUDOUT_FIFO_PIO_WRH 0x2EC ++#define AUDOUT1_FIFO_PIO_STS 0x2F0 /* Unknown */ ++#define AUDOUT1_FIFO_PIO_WRL 0x2F4 /* Unknown */ ++#define AUDOUT1_FIFO_PIO_WRH 0x2F8 /* Unknown */ ++#define AUD_RESAMPLE_CTRL0 0x2FC ++#define AUD_RESAMPLE_CTRL1 0x300 ++#define AUD_RESAMPLE_STATUS 0x304 ++ ++#endif /* _AUDIN_REGS_H_ */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0103-TEMP-ASoC-meson-add-initial-aiu-i2s-support.patch b/packages/linux/patches/amlogic/amlogic-0103-TEMP-ASoC-meson-add-initial-aiu-i2s-support.patch new file mode 100644 index 0000000000..d00a80287b --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0103-TEMP-ASoC-meson-add-initial-aiu-i2s-support.patch @@ -0,0 +1,802 @@ +From 04202a577fa74bf5000902c601f50631fdb934ec Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 12:17:27 +0200 +Subject: [PATCH 103/186] TEMP: ASoC: meson: add initial aiu i2s support + +Add support for the aiu i2s found on Amlogic Meson SoC family. +With this initial implementation, only playback is supported. +Capture will be part of furture work. + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/Kconfig | 8 + + sound/soc/meson-gx/Makefile | 3 + + sound/soc/meson-gx/aiu-i2s.c | 749 +++++++++++++++++++++++++++++++++++ + 3 files changed, 760 insertions(+) + create mode 100644 sound/soc/meson-gx/aiu-i2s.c + +diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig +index 280e49e7c16f..8ec683cdf327 100644 +--- a/sound/soc/meson-gx/Kconfig ++++ b/sound/soc/meson-gx/Kconfig +@@ -9,3 +9,11 @@ menuconfig SND_SOC_MESON_GX + select the audio interfaces to support below. This WIP drivers + are kept separated from the actual upstream amlogic ASoC driver + to minimize conflicts until support is submitted and merged ++ ++config SND_SOC_MESON_GX_I2S ++ tristate "Meson i2s interface" ++ depends on SND_SOC_MESON_GX ++ help ++ Say Y or M if you want to add support for i2s driver for Amlogic ++ Meson SoCs. ++ +diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile +index 6f124c31a85c..02f9c4df6348 100644 +--- a/sound/soc/meson-gx/Makefile ++++ b/sound/soc/meson-gx/Makefile +@@ -1,3 +1,6 @@ + snd-soc-meson-audio-core-objs := audio-core.o ++snd-soc-meson-aiu-i2s-objs := aiu-i2s.o + + obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o ++obj-$(CONFIG_SND_SOC_MESON_GX_I2S) += snd-soc-meson-aiu-i2s.o ++ +diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c +new file mode 100644 +index 000000000000..63d7821c2c72 +--- /dev/null ++++ b/sound/soc/meson-gx/aiu-i2s.c +@@ -0,0 +1,749 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "aiu-regs.h" ++#include "audio-core.h" ++ ++#define DRV_NAME "meson-aiu-i2s" ++ ++struct meson_aiu_i2s { ++ struct meson_audio_core_data *core; ++ struct clk *mclk; ++ struct clk *bclks; ++ struct clk *iface; ++ struct clk *fast; ++ bool bclks_idle; ++ int irq; ++}; ++ ++#define AIU_MEM_I2S_BUF_CNTL_INIT BIT(0) ++#define AIU_MEM_I2S_CONTROL_INIT BIT(0) ++#define AIU_MEM_I2S_CONTROL_FILL_EN BIT(1) ++#define AIU_MEM_I2S_CONTROL_EMPTY_EN BIT(2) ++#define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6) ++#define AIU_MEM_I2S_CONTROL_BUSY BIT(7) ++#define AIU_MEM_I2S_CONTROL_DATA_READY BIT(8) ++#define AIU_MEM_I2S_CONTROL_LEVEL_CNTL BIT(9) ++#define AIU_MEM_I2S_MASKS_IRQ_BLOCK_MASK GENMASK(31, 16) ++#define AIU_MEM_I2S_MASKS_IRQ_BLOCK(n) ((n) << 16) ++#define AIU_MEM_I2S_MASKS_CH_MEM_MASK GENMASK(15, 8) ++#define AIU_MEM_I2S_MASKS_CH_MEM(ch) ((ch) << 8) ++#define AIU_MEM_I2S_MASKS_CH_RD_MASK GENMASK(7, 0) ++#define AIU_MEM_I2S_MASKS_CH_RD(ch) ((ch) << 0) ++#define AIU_RST_SOFT_I2S_FAST_DOMAIN BIT(0) ++#define AIU_RST_SOFT_I2S_SLOW_DOMAIN BIT(1) ++ ++/* ++ * The DMA works by i2s "blocks" (or DMA burst). The burst size and the memory ++ * layout expected depends on the mode of operation. ++ * ++ * - Normal mode: The channels are expected to be packed in 32 bytes groups ++ * interleaved the buffer. AIU_MEM_I2S_MASKS_CH_MEM is a bitfield representing ++ * the channels present in memory. AIU_MEM_I2S_MASKS_CH_MEM represents the ++ * channels read by the DMA. This is very flexible but the unsual memory layout ++ * makes it less easy to deal with. The burst size is 32 bytes times the number ++ * of channels read. ++ * ++ * - Split mode: ++ * Classical channel interleaved frame organisation. In this mode, ++ * AIU_MEM_I2S_MASKS_CH_MEM and AIU_MEM_I2S_MASKS_CH_MEM must be set to 0xff and ++ * the burst size is fixed to 256 bytes. The input can be either 2 or 8 ++ * channels. ++ * ++ * The following driver implements the split mode. ++ */ ++ ++#define AIU_I2S_DMA_BURST 256 ++ ++static struct snd_pcm_hardware meson_aiu_i2s_dma_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_PAUSE), ++ ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE), ++ ++ /* ++ * TODO: The DMA can change the endianness, the msb position ++ * and deal with unsigned - support this later on ++ */ ++ ++ .rate_min = 8000, ++ .rate_max = 192000, ++ .channels_min = 2, ++ .channels_max = 8, ++ .period_bytes_min = AIU_I2S_DMA_BURST, ++ .period_bytes_max = AIU_I2S_DMA_BURST * 65535, ++ .periods_min = 2, ++ .periods_max = UINT_MAX, ++ .buffer_bytes_max = 1 * 1024 * 1024, ++ .fifo_size = 0, ++}; ++ ++static struct meson_aiu_i2s *meson_aiu_i2s_dma_priv(struct snd_pcm_substream *s) ++{ ++ struct snd_soc_pcm_runtime *rtd = s->private_data; ++ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); ++ ++ return snd_soc_component_get_drvdata(component); ++} ++ ++static snd_pcm_uframes_t ++meson_aiu_i2s_dma_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ unsigned int addr; ++ int ret; ++ ++ ret = regmap_read(priv->core->aiu, AIU_MEM_I2S_RD_PTR, ++ &addr); ++ if (ret) ++ return 0; ++ ++ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); ++} ++ ++static void __dma_enable(struct meson_aiu_i2s *priv, bool enable) ++{ ++ unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN | ++ AIU_MEM_I2S_CONTROL_EMPTY_EN); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask, ++ enable ? en_mask : 0); ++ ++} ++ ++static int meson_aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __dma_enable(priv, true); ++ break; ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_STOP: ++ __dma_enable(priv, false); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void __dma_init_mem(struct meson_aiu_i2s *priv) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, ++ AIU_MEM_I2S_CONTROL_INIT, ++ AIU_MEM_I2S_CONTROL_INIT); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL, ++ AIU_MEM_I2S_BUF_CNTL_INIT, ++ AIU_MEM_I2S_BUF_CNTL_INIT); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, ++ AIU_MEM_I2S_CONTROL_INIT, ++ 0); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL, ++ AIU_MEM_I2S_BUF_CNTL_INIT, ++ 0); ++} ++ ++static int meson_aiu_i2s_dma_prepare(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ ++ __dma_init_mem(priv); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ int ret; ++ u32 burst_num, mem_ctl; ++ dma_addr_t end_ptr; ++ ++ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); ++ if (ret < 0) ++ return ret; ++ ++ /* Setup memory layout */ ++ if (params_physical_width(params) == 16) ++ mem_ctl = AIU_MEM_I2S_CONTROL_MODE_16BIT; ++ else ++ mem_ctl = 0; ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, ++ AIU_MEM_I2S_CONTROL_MODE_16BIT, ++ mem_ctl); ++ ++ /* Initialize memory pointers */ ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_START_PTR, runtime->dma_addr); ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_RD_PTR, runtime->dma_addr); ++ ++ /* The end pointer is the address of the last valid block */ ++ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_I2S_DMA_BURST; ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_END_PTR, end_ptr); ++ ++ /* Memory masks */ ++ burst_num = params_period_bytes(params) / AIU_I2S_DMA_BURST; ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_MASKS, ++ AIU_MEM_I2S_MASKS_CH_RD(0xff) | ++ AIU_MEM_I2S_MASKS_CH_MEM(0xff) | ++ AIU_MEM_I2S_MASKS_IRQ_BLOCK(burst_num)); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dma_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++ ++static irqreturn_t meson_aiu_i2s_dma_irq_block(int irq, void *dev_id) ++{ ++ struct snd_pcm_substream *playback = dev_id; ++ ++ snd_pcm_period_elapsed(playback); ++ ++ return IRQ_HANDLED; ++} ++ ++static int meson_aiu_i2s_dma_open(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ int ret; ++ ++ snd_soc_set_runtime_hwparams(substream, &meson_aiu_i2s_dma_hw); ++ ++ /* ++ * Make sure the buffer and period size are multiple of the DMA burst ++ * size ++ */ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, ++ AIU_I2S_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ AIU_I2S_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ /* Request the I2S DDR irq */ ++ ret = request_irq(priv->irq, meson_aiu_i2s_dma_irq_block, 0, ++ DRV_NAME, substream); ++ if (ret) ++ return ret; ++ ++ /* Power up the i2s fast domain - can't write the registers w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ return ret; ++ ++ /* Make sure the dma is initially disabled */ ++ __dma_enable(priv, false); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dma_close(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ ++ clk_disable_unprepare(priv->fast); ++ free_irq(priv->irq, substream); ++ ++ return 0; ++} ++ ++static const struct snd_pcm_ops meson_aiu_i2s_dma_ops = { ++ .open = meson_aiu_i2s_dma_open, ++ .close = meson_aiu_i2s_dma_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = meson_aiu_i2s_dma_hw_params, ++ .hw_free = meson_aiu_i2s_dma_hw_free, ++ .prepare = meson_aiu_i2s_dma_prepare, ++ .pointer = meson_aiu_i2s_dma_pointer, ++ .trigger = meson_aiu_i2s_dma_trigger, ++}; ++ ++static int meson_aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_card *card = rtd->card->snd_card; ++ size_t size = meson_aiu_i2s_dma_hw.buffer_bytes_max; ++ ++ snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, ++ SNDRV_DMA_TYPE_DEV, ++ card->dev, size, size); ++ ++ return 0; ++} ++ ++#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0) ++#define AIU_CLK_CTRL_I2S_DIV_MASK GENMASK(3, 2) ++#define AIU_CLK_CTRL_AOCLK_POLARITY_MASK BIT(6) ++#define AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL (0 << 6) ++#define AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED (1 << 6) ++#define AIU_CLK_CTRL_ALRCLK_POLARITY_MASK BIT(7) ++#define AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL (0 << 7) ++#define AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED (1 << 7) ++#define AIU_CLK_CTRL_ALRCLK_SKEW_MASK GENMASK(9, 8) ++#define AIU_CLK_CTRL_ALRCLK_LEFT_J (0 << 8) ++#define AIU_CLK_CTRL_ALRCLK_I2S (1 << 8) ++#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8) ++#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0) ++#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0) ++#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0) ++#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0) ++#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0) ++#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0) ++#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0) ++#define AIU_I2S_DAC_CFG_AOCLK_64 (3 << 0) ++#define AIU_I2S_MISC_HOLD_EN BIT(2) ++#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) ++#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) ++#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) ++#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11) ++ ++static void __hold(struct meson_aiu_i2s *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_MISC, ++ AIU_I2S_MISC_HOLD_EN, ++ enable ? AIU_I2S_MISC_HOLD_EN : 0); ++} ++ ++static void __divider_enable(struct meson_aiu_i2s *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_I2S_DIV_EN, ++ enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0); ++} ++ ++static void __playback_start(struct meson_aiu_i2s *priv) ++{ ++ __divider_enable(priv, true); ++ __hold(priv, false); ++} ++ ++static void __playback_stop(struct meson_aiu_i2s *priv, bool clk_force) ++{ ++ __hold(priv, true); ++ /* Disable the bit clks if necessary */ ++ if (clk_force || !priv->bclks_idle) ++ __divider_enable(priv, false); ++} ++ ++static int meson_aiu_i2s_dai_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ bool clk_force_stop = false; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __playback_start(priv); ++ return 0; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ clk_force_stop = true; ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ __playback_stop(priv, clk_force_stop); ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int __bclks_set_rate(struct meson_aiu_i2s *priv, unsigned int srate, ++ unsigned int width) ++{ ++ unsigned int fs; ++ ++ /* Get the oversampling factor */ ++ fs = DIV_ROUND_CLOSEST(clk_get_rate(priv->mclk), srate); ++ ++ /* ++ * This DAI is usually connected to the dw-hdmi which does not support ++ * bclk being 32 * lrclk or 48 * lrclk ++ * Restrict to blck = 64 * lrclk ++ */ ++ if (fs % 64) ++ return -EINVAL; ++ ++ /* Set the divider between lrclk and bclk */ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_DAC_CFG, ++ AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK, ++ AIU_I2S_DAC_CFG_AOCLK_64); ++ ++ regmap_update_bits(priv->core->aiu, AIU_CODEC_DAC_LRCLK_CTRL, ++ AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK, ++ AIU_CODEC_DAC_LRCLK_CTRL_DIV(64)); ++ ++ /* Use CLK_MORE for the i2s divider */ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_I2S_DIV_MASK, ++ 0); ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE, ++ AIU_CLK_CTRL_MORE_I2S_DIV_MASK, ++ AIU_CLK_CTRL_MORE_I2S_DIV(fs / 64)); ++ ++ return 0; ++} ++ ++static int __setup_desc(struct meson_aiu_i2s *priv, unsigned int width, ++ unsigned int channels) ++{ ++ u32 desc = 0; ++ ++ switch (width) { ++ case 24: ++ /* ++ * For some reason, 24 bits wide audio don't play well ++ * if the 32 bits mode is not set ++ */ ++ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT | ++ AIU_I2S_SOURCE_DESC_MODE_32BIT); ++ break; ++ case 16: ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ switch (channels) { ++ case 2: /* Nothing to do */ ++ break; ++ case 8: ++ /* TODO: Still requires testing ... */ ++ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC, ++ AIU_I2S_SOURCE_DESC_MODE_8CH | ++ AIU_I2S_SOURCE_DESC_MODE_24BIT | ++ AIU_I2S_SOURCE_DESC_MODE_32BIT, ++ desc); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ unsigned int width = params_width(params); ++ unsigned int channels = params_channels(params); ++ unsigned int rate = params_rate(params); ++ int ret; ++ ++ ret = __setup_desc(priv, width, channels); ++ if (ret) { ++ dev_err(dai->dev, "Unable set to set i2s description\n"); ++ return ret; ++ } ++ ++ ret = __bclks_set_rate(priv, rate, width); ++ if (ret) { ++ dev_err(dai->dev, "Unable set to the i2s clock rates\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ u32 val; ++ ++ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) ++ return -EINVAL; ++ ++ /* DAI output mode */ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ val = AIU_CLK_CTRL_ALRCLK_I2S; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ val = AIU_CLK_CTRL_ALRCLK_LEFT_J; ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ val = AIU_CLK_CTRL_ALRCLK_RIGHT_J; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_ALRCLK_SKEW_MASK, ++ val); ++ ++ /* DAI clock polarity */ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_IB_IF: ++ /* Invert both clocks */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED | ++ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ /* Invert bit clock */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL | ++ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED; ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ /* Invert frame clock */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED | ++ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL; ++ break; ++ case SND_SOC_DAIFMT_NB_NF: ++ /* Normal clocks */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL | ++ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_ALRCLK_POLARITY_MASK | ++ AIU_CLK_CTRL_AOCLK_POLARITY_MASK, ++ val); ++ ++ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { ++ case SND_SOC_DAIFMT_CONT: ++ priv->bclks_idle = true; ++ break; ++ case SND_SOC_DAIFMT_GATED: ++ priv->bclks_idle = false; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ if (WARN_ON(clk_id != 0)) ++ return -EINVAL; ++ ++ if (dir == SND_SOC_CLOCK_IN) ++ return 0; ++ ++ ret = clk_set_rate(priv->mclk, freq); ++ if (ret) { ++ dev_err(dai->dev, "Failed to set sysclk to %uHz", freq); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ /* Power up the i2s fast domain - can't write the registers w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ goto out_clk_fast; ++ ++ /* Make sure nothing gets out of the DAI yet */ ++ __hold(priv, true); ++ ++ /* I2S encoder needs the mixer interface gate */ ++ ret = clk_prepare_enable(priv->iface); ++ if (ret) ++ goto out_clk_iface; ++ ++ /* Enable the i2s master clock */ ++ ret = clk_prepare_enable(priv->mclk); ++ if (ret) ++ goto out_mclk; ++ ++ /* Enable the bit clock gate */ ++ ret = clk_prepare_enable(priv->bclks); ++ if (ret) ++ goto out_bclks; ++ ++ /* Make sure the interface expect a memory layout we can work with */ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC, ++ AIU_I2S_SOURCE_DESC_MODE_SPLIT, ++ AIU_I2S_SOURCE_DESC_MODE_SPLIT); ++ ++ return 0; ++ ++out_bclks: ++ clk_disable_unprepare(priv->mclk); ++out_mclk: ++ clk_disable_unprepare(priv->iface); ++out_clk_iface: ++ clk_disable_unprepare(priv->fast); ++out_clk_fast: ++ return ret; ++} ++ ++static void meson_aiu_i2s_dai_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ ++ clk_disable_unprepare(priv->bclks); ++ clk_disable_unprepare(priv->mclk); ++ clk_disable_unprepare(priv->iface); ++ clk_disable_unprepare(priv->fast); ++} ++ ++static const struct snd_soc_dai_ops meson_aiu_i2s_dai_ops = { ++ .startup = meson_aiu_i2s_dai_startup, ++ .shutdown = meson_aiu_i2s_dai_shutdown, ++ .trigger = meson_aiu_i2s_dai_trigger, ++ .hw_params = meson_aiu_i2s_dai_hw_params, ++ .set_fmt = meson_aiu_i2s_dai_set_fmt, ++ .set_sysclk = meson_aiu_i2s_dai_set_sysclk, ++}; ++ ++static struct snd_soc_dai_driver meson_aiu_i2s_dai = { ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE) ++ }, ++ .ops = &meson_aiu_i2s_dai_ops, ++}; ++ ++static const struct snd_soc_component_driver meson_aiu_i2s_component = { ++ .ops = &meson_aiu_i2s_dma_ops, ++ .pcm_new = meson_aiu_i2s_dma_new, ++ .name = DRV_NAME, ++}; ++ ++static int meson_aiu_i2s_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct meson_aiu_i2s *priv; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, priv); ++ priv->core = dev_get_drvdata(dev->parent); ++ ++ priv->fast = devm_clk_get(dev, "fast"); ++ if (IS_ERR(priv->fast)) { ++ if (PTR_ERR(priv->fast) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get the i2s fast domain clock\n"); ++ return PTR_ERR(priv->fast); ++ } ++ ++ priv->iface = devm_clk_get(dev, "iface"); ++ if (IS_ERR(priv->iface)) { ++ if (PTR_ERR(priv->iface) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get i2s dai clock gate\n"); ++ return PTR_ERR(priv->iface); ++ } ++ ++ priv->bclks = devm_clk_get(dev, "bclks"); ++ if (IS_ERR(priv->bclks)) { ++ if (PTR_ERR(priv->bclks) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get bit clocks gate\n"); ++ return PTR_ERR(priv->bclks); ++ } ++ ++ priv->mclk = devm_clk_get(dev, "mclk"); ++ if (IS_ERR(priv->mclk)) { ++ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER) ++ dev_err(dev, "failed to get the i2s master clock\n"); ++ return PTR_ERR(priv->mclk); ++ } ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (priv->irq <= 0) { ++ dev_err(dev, "Can't get i2s ddr irq\n"); ++ return priv->irq; ++ } ++ ++ return devm_snd_soc_register_component(dev, &meson_aiu_i2s_component, ++ &meson_aiu_i2s_dai, 1); ++} ++ ++static const struct of_device_id meson_aiu_i2s_of_match[] = { ++ { .compatible = "amlogic,meson-aiu-i2s", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, meson_aiu_i2s_of_match); ++ ++static struct platform_driver meson_aiu_i2s_pdrv = { ++ .probe = meson_aiu_i2s_probe, ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = meson_aiu_i2s_of_match, ++ }, ++}; ++module_platform_driver(meson_aiu_i2s_pdrv); ++ ++MODULE_DESCRIPTION("Meson AIU i2s ASoC Driver"); ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_LICENSE("GPL v2"); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0104-TEMP-ASoC-meson-add-initial-spdif-support.patch b/packages/linux/patches/amlogic/amlogic-0104-TEMP-ASoC-meson-add-initial-spdif-support.patch new file mode 100644 index 0000000000..a9552a5c82 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0104-TEMP-ASoC-meson-add-initial-spdif-support.patch @@ -0,0 +1,726 @@ +From f385bec4a40fbc8413fc89d7ff852e329bc9f27a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 13:46:03 +0200 +Subject: [PATCH 104/186] TEMP: ASoC: meson: add initial spdif support + +Add support for the spdif found on Amlogic Meson SoC family. +With this initial implementation, only uncompressed pcm playback +from the spdif dma is supported. Future work will add compressed +support, pcm playback from i2s dma and capture. + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/Kconfig | 7 + + sound/soc/meson-gx/Makefile | 3 +- + sound/soc/meson-gx/aiu-spdif.c | 671 +++++++++++++++++++++++++++++++++ + 3 files changed, 680 insertions(+), 1 deletion(-) + create mode 100644 sound/soc/meson-gx/aiu-spdif.c + +diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig +index 8ec683cdf327..141afabfacea 100644 +--- a/sound/soc/meson-gx/Kconfig ++++ b/sound/soc/meson-gx/Kconfig +@@ -17,3 +17,10 @@ config SND_SOC_MESON_GX_I2S + Say Y or M if you want to add support for i2s driver for Amlogic + Meson SoCs. + ++config SND_SOC_MESON_GX_SPDIF ++ tristate "Meson spdif interface" ++ depends on SND_SOC_MESON_GX ++ select SND_PCM_IEC958 ++ help ++ Say Y or M if you want to add support for spdif driver for Amlogic ++ Meson SoCs. +diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile +index 02f9c4df6348..d37672ebe57b 100644 +--- a/sound/soc/meson-gx/Makefile ++++ b/sound/soc/meson-gx/Makefile +@@ -1,6 +1,7 @@ + snd-soc-meson-audio-core-objs := audio-core.o + snd-soc-meson-aiu-i2s-objs := aiu-i2s.o ++snd-soc-meson-aiu-spdif-objs := aiu-spdif.o + + obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o + obj-$(CONFIG_SND_SOC_MESON_GX_I2S) += snd-soc-meson-aiu-i2s.o +- ++obj-$(CONFIG_SND_SOC_MESON_GX_SPDIF) += snd-soc-meson-aiu-spdif.o +diff --git a/sound/soc/meson-gx/aiu-spdif.c b/sound/soc/meson-gx/aiu-spdif.c +new file mode 100644 +index 000000000000..748a9b1d680c +--- /dev/null ++++ b/sound/soc/meson-gx/aiu-spdif.c +@@ -0,0 +1,671 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "aiu-regs.h" ++#include "audio-core.h" ++ ++#define DRV_NAME "meson-aiu-spdif" ++ ++struct meson_aiu_spdif { ++ struct meson_audio_core_data *core; ++ struct clk *iface; ++ struct clk *fast; ++ struct clk *mclk_i958; ++ struct clk *mclk; ++ int irq; ++}; ++ ++ ++#define AIU_958_DCU_FF_CTRL_EN BIT(0) ++#define AIU_958_DCU_FF_CTRL_AUTO_DISABLE BIT(1) ++#define AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK GENMASK(3, 2) ++#define AIU_958_DCU_FF_CTRL_IRQ_OUT_THD BIT(2) ++#define AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ BIT(3) ++#define AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN BIT(4) ++#define AIU_958_DCU_FF_CTRL_BYTE_SEEK BIT(5) ++#define AIU_958_DCU_FF_CTRL_CONTINUE BIT(6) ++#define AIU_MEM_IEC958_BUF_CNTL_INIT BIT(0) ++#define AIU_MEM_IEC958_CONTROL_INIT BIT(0) ++#define AIU_MEM_IEC958_CONTROL_FILL_EN BIT(1) ++#define AIU_MEM_IEC958_CONTROL_EMPTY_EN BIT(2) ++#define AIU_MEM_IEC958_CONTROL_ENDIAN_MASK GENMASK(5, 3) ++#define AIU_MEM_IEC958_CONTROL_RD_DDR BIT(6) ++#define AIU_MEM_IEC958_CONTROL_MODE_16BIT BIT(7) ++#define AIU_MEM_IEC958_MASKS_CH_MEM_MASK GENMASK(15, 8) ++#define AIU_MEM_IEC958_MASKS_CH_MEM(ch) ((ch) << 8) ++#define AIU_MEM_IEC958_MASKS_CH_RD_MASK GENMASK(7, 0) ++#define AIU_MEM_IEC958_MASKS_CH_RD(ch) ((ch) << 0) ++ ++#define AIU_SPDIF_DMA_BURST 8 ++#define AIU_SPDIF_BPF_MAX USHRT_MAX ++ ++static struct snd_pcm_hardware meson_aiu_spdif_dma_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_PAUSE), ++ ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE), ++ ++ .rates = (SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_192000), ++ /* ++ * TODO: The DMA can change the endianness, the msb position ++ * and deal with unsigned - support this later on ++ */ ++ ++ .channels_min = 2, ++ .channels_max = 2, ++ .period_bytes_min = AIU_SPDIF_DMA_BURST, ++ .period_bytes_max = AIU_SPDIF_BPF_MAX, ++ .periods_min = 2, ++ .periods_max = UINT_MAX, ++ .buffer_bytes_max = 1 * 1024 * 1024, ++ .fifo_size = 0, ++}; ++ ++static struct meson_aiu_spdif *meson_aiu_spdif_dma_priv(struct snd_pcm_substream *s) ++{ ++ struct snd_soc_pcm_runtime *rtd = s->private_data; ++ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); ++ ++ return snd_soc_component_get_drvdata(component); ++} ++ ++static snd_pcm_uframes_t ++meson_aiu_spdif_dma_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ unsigned int addr; ++ int ret; ++ ++ ret = regmap_read(priv->core->aiu, AIU_MEM_IEC958_RD_PTR, ++ &addr); ++ if (ret) ++ return 0; ++ ++ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); ++} ++ ++static void __dma_enable(struct meson_aiu_spdif *priv, bool enable) ++{ ++ unsigned int en_mask = (AIU_MEM_IEC958_CONTROL_FILL_EN | ++ AIU_MEM_IEC958_CONTROL_EMPTY_EN); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, en_mask, ++ enable ? en_mask : 0); ++} ++ ++static void __dcu_fifo_enable(struct meson_aiu_spdif *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL, ++ AIU_958_DCU_FF_CTRL_EN, ++ enable ? AIU_958_DCU_FF_CTRL_EN : 0); ++} ++ ++static int meson_aiu_spdif_dma_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __dcu_fifo_enable(priv, true); ++ __dma_enable(priv, true); ++ break; ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_STOP: ++ __dma_enable(priv, false); ++ __dcu_fifo_enable(priv, false); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void __dma_init_mem(struct meson_aiu_spdif *priv) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_INIT, ++ AIU_MEM_IEC958_CONTROL_INIT); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL, ++ AIU_MEM_IEC958_BUF_CNTL_INIT, ++ AIU_MEM_IEC958_BUF_CNTL_INIT); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_INIT, ++ 0); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL, ++ AIU_MEM_IEC958_BUF_CNTL_INIT, ++ 0); ++} ++ ++static int meson_aiu_spdif_dma_prepare(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ ++ __dma_init_mem(priv); ++ ++ return 0; ++} ++ ++static int __setup_memory_layout(struct meson_aiu_spdif *priv, ++ unsigned int width) ++{ ++ u32 mem_ctl = AIU_MEM_IEC958_CONTROL_RD_DDR; ++ ++ if (width == 16) ++ mem_ctl |= AIU_MEM_IEC958_CONTROL_MODE_16BIT; ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_ENDIAN_MASK | ++ AIU_MEM_IEC958_CONTROL_MODE_16BIT | ++ AIU_MEM_IEC958_CONTROL_RD_DDR, ++ mem_ctl); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dma_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ int ret; ++ dma_addr_t end_ptr; ++ ++ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __setup_memory_layout(priv, params_physical_width(params)); ++ if (ret) ++ return ret; ++ ++ /* Initialize memory pointers */ ++ regmap_write(priv->core->aiu, ++ AIU_MEM_IEC958_START_PTR, runtime->dma_addr); ++ regmap_write(priv->core->aiu, ++ AIU_MEM_IEC958_RD_PTR, runtime->dma_addr); ++ ++ /* The end pointer is the address of the last valid block */ ++ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_SPDIF_DMA_BURST; ++ regmap_write(priv->core->aiu, AIU_MEM_IEC958_END_PTR, end_ptr); ++ ++ /* Memory masks */ ++ regmap_write(priv->core->aiu, AIU_MEM_IEC958_MASKS, ++ AIU_MEM_IEC958_MASKS_CH_RD(0xff) | ++ AIU_MEM_IEC958_MASKS_CH_MEM(0xff)); ++ ++ /* Setup the number bytes read by the FIFO between each IRQ */ ++ regmap_write(priv->core->aiu, AIU_958_BPF, params_period_bytes(params)); ++ ++ /* ++ * AUTO_DISABLE and SYNC_HEAD are enabled by default but ++ * this should be disabled in PCM (uncompressed) mode ++ */ ++ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL, ++ AIU_958_DCU_FF_CTRL_AUTO_DISABLE | ++ AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK | ++ AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN, ++ AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dma_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++static irqreturn_t meson_aiu_spdif_dma_irq(int irq, void *dev_id) ++{ ++ struct snd_pcm_substream *playback = dev_id; ++ ++ snd_pcm_period_elapsed(playback); ++ ++ return IRQ_HANDLED; ++} ++ ++static int meson_aiu_spdif_dma_open(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ int ret; ++ ++ snd_soc_set_runtime_hwparams(substream, &meson_aiu_spdif_dma_hw); ++ ++ /* ++ * Make sure the buffer and period size are multiple of the DMA burst ++ * size ++ */ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, ++ AIU_SPDIF_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ AIU_SPDIF_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ /* Request the SPDIF DDR irq */ ++ ret = request_irq(priv->irq, meson_aiu_spdif_dma_irq, 0, ++ DRV_NAME, substream); ++ if (ret) ++ return ret; ++ ++ /* Power up the spdif fast domain - can't write the register w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ return ret; ++ ++ /* Make sure the dma is initially halted */ ++ __dma_enable(priv, false); ++ __dcu_fifo_enable(priv, false); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dma_close(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ ++ clk_disable_unprepare(priv->fast); ++ free_irq(priv->irq, substream); ++ ++ return 0; ++} ++ ++static const struct snd_pcm_ops meson_aiu_spdif_dma_ops = { ++ .open = meson_aiu_spdif_dma_open, ++ .close = meson_aiu_spdif_dma_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = meson_aiu_spdif_dma_hw_params, ++ .hw_free = meson_aiu_spdif_dma_hw_free, ++ .prepare = meson_aiu_spdif_dma_prepare, ++ .pointer = meson_aiu_spdif_dma_pointer, ++ .trigger = meson_aiu_spdif_dma_trigger, ++}; ++ ++static int meson_aiu_spdif_dma_new(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_card *card = rtd->card->snd_card; ++ size_t size = meson_aiu_spdif_dma_hw.buffer_bytes_max; ++ ++ snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, ++ SNDRV_DMA_TYPE_DEV, ++ card->dev, size, size); ++ ++ return 0; ++} ++ ++#define AIU_CLK_CTRL_958_DIV_EN BIT(1) ++#define AIU_CLK_CTRL_958_DIV_MASK GENMASK(5, 4) ++#define AIU_CLK_CTRL_958_DIV_MORE BIT(12) ++#define AIU_MEM_IEC958_CONTROL_MODE_LINEAR BIT(8) ++#define AIU_958_CTRL_HOLD_EN BIT(0) ++#define AIU_958_MISC_NON_PCM BIT(0) ++#define AIU_958_MISC_MODE_16BITS BIT(1) ++#define AIU_958_MISC_16BITS_ALIGN_MASK GENMASK(6, 5) ++#define AIU_958_MISC_16BITS_ALIGN(val) ((val) << 5) ++#define AIU_958_MISC_MODE_32BITS BIT(7) ++#define AIU_958_MISC_32BITS_SHIFT_MASK GENMASK(10, 8) ++#define AIU_958_MISC_32BITS_SHIFT(val) ((val) << 8) ++#define AIU_958_MISC_U_FROM_STREAM BIT(12) ++#define AIU_958_MISC_FORCE_LR BIT(13) ++ ++#define AIU_CS_WORD_LEN 4 ++ ++static void __hold(struct meson_aiu_spdif *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_958_CTRL, ++ AIU_958_CTRL_HOLD_EN, ++ enable ? AIU_958_CTRL_HOLD_EN : 0); ++} ++ ++static void __divider_enable(struct meson_aiu_spdif *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_958_DIV_EN, ++ enable ? AIU_CLK_CTRL_958_DIV_EN : 0); ++} ++ ++static void __playback_start(struct meson_aiu_spdif *priv) ++{ ++ __divider_enable(priv, true); ++ __hold(priv, false); ++} ++ ++static void __playback_stop(struct meson_aiu_spdif *priv) ++{ ++ __hold(priv, true); ++ __divider_enable(priv, false); ++} ++ ++static int meson_aiu_spdif_dai_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __playback_start(priv); ++ return 0; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ __playback_stop(priv); ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int __setup_spdif_clk(struct meson_aiu_spdif *priv, unsigned int rate) ++{ ++ unsigned int mrate; ++ ++ /* Leave the internal divisor alone */ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_958_DIV_MASK | ++ AIU_CLK_CTRL_958_DIV_MORE, ++ 0); ++ ++ /* 2 * 32bits per subframe * 2 channels = 128 */ ++ mrate = rate * 128; ++ return clk_set_rate(priv->mclk, mrate); ++} ++ ++static int __setup_cs_word(struct meson_aiu_spdif *priv, ++ struct snd_pcm_hw_params *params) ++{ ++ u8 cs[AIU_CS_WORD_LEN]; ++ u32 val; ++ int ret; ++ ++ ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, ++ AIU_CS_WORD_LEN); ++ if (ret < 0) ++ return -EINVAL; ++ ++ /* Write the 1st half word */ ++ val = cs[1] | cs[0] << 8; ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L0, val); ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R0, val); ++ ++ /* Write the 2nd half word */ ++ val = cs[3] | cs[2] << 8; ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L1, val); ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R1, val); ++ ++ return 0; ++} ++ ++static int __setup_pcm_fmt(struct meson_aiu_spdif *priv, ++ unsigned int width) ++{ ++ u32 val = 0; ++ ++ switch (width) { ++ case 16: ++ val |= AIU_958_MISC_MODE_16BITS; ++ val |= AIU_958_MISC_16BITS_ALIGN(2); ++ break; ++ case 32: ++ case 24: ++ /* ++ * Looks like this should only be set for 32bits mode, but the ++ * vendor kernel sets it like this for 24bits as well, let's ++ * try and see ++ */ ++ val |= AIU_958_MISC_MODE_32BITS; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* No idea what this actually does, copying the vendor kernel for now */ ++ val |= AIU_958_MISC_FORCE_LR; ++ val |= AIU_958_MISC_U_FROM_STREAM; ++ ++ regmap_update_bits(priv->core->aiu, AIU_958_MISC, ++ AIU_958_MISC_NON_PCM | ++ AIU_958_MISC_MODE_16BITS | ++ AIU_958_MISC_16BITS_ALIGN_MASK | ++ AIU_958_MISC_MODE_32BITS | ++ AIU_958_MISC_FORCE_LR, ++ val); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dai_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ ret = __setup_spdif_clk(priv, params_rate(params)); ++ if (ret) { ++ dev_err(dai->dev, "Unable to set the spdif clock\n"); ++ return ret; ++ } ++ ++ ret = __setup_cs_word(priv, params); ++ if (ret) { ++ dev_err(dai->dev, "Unable to set the channel status word\n"); ++ return ret; ++ } ++ ++ ret = __setup_pcm_fmt(priv, params_width(params)); ++ if (ret) { ++ dev_err(dai->dev, "Unable to set the pcm format\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dai_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ /* Power up the spdif fast domain - can't write the registers w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ goto out_clk_fast; ++ ++ /* Make sure nothing gets out of the DAI yet*/ ++ __hold(priv, true); ++ ++ ret = clk_set_parent(priv->mclk, priv->mclk_i958); ++ if (ret) ++ return ret; ++ ++ /* Enable the clock gate */ ++ ret = clk_prepare_enable(priv->iface); ++ if (ret) ++ goto out_clk_iface; ++ ++ /* Enable the spdif clock */ ++ ret = clk_prepare_enable(priv->mclk); ++ if (ret) ++ goto out_mclk; ++ ++ /* ++ * Make sure the interface expect a memory layout we can work with ++ * MEM prefixed register usually belong to the DMA, but when the spdif ++ * DAI takes data from the i2s buffer, we need to make sure it works in ++ * split mode and not the "normal mode" (channel samples packed in ++ * 32 bytes groups) ++ */ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_MODE_LINEAR, ++ AIU_MEM_IEC958_CONTROL_MODE_LINEAR); ++ ++ return 0; ++ ++out_mclk: ++ clk_disable_unprepare(priv->iface); ++out_clk_iface: ++ clk_disable_unprepare(priv->fast); ++out_clk_fast: ++ return ret; ++} ++ ++static void meson_aiu_spdif_dai_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ ++ clk_disable_unprepare(priv->iface); ++ clk_disable_unprepare(priv->mclk); ++ clk_disable_unprepare(priv->fast); ++} ++ ++static const struct snd_soc_dai_ops meson_aiu_spdif_dai_ops = { ++ .startup = meson_aiu_spdif_dai_startup, ++ .shutdown = meson_aiu_spdif_dai_shutdown, ++ .trigger = meson_aiu_spdif_dai_trigger, ++ .hw_params = meson_aiu_spdif_dai_hw_params, ++}; ++ ++static struct snd_soc_dai_driver meson_aiu_spdif_dai = { ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = (SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_192000), ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE) ++ }, ++ .ops = &meson_aiu_spdif_dai_ops, ++}; ++ ++static const struct snd_soc_component_driver meson_aiu_spdif_component = { ++ .ops = &meson_aiu_spdif_dma_ops, ++ .pcm_new = meson_aiu_spdif_dma_new, ++ .name = DRV_NAME, ++}; ++ ++static int meson_aiu_spdif_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct meson_aiu_spdif *priv; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, priv); ++ priv->core = dev_get_drvdata(dev->parent); ++ ++ priv->fast = devm_clk_get(dev, "fast"); ++ if (IS_ERR(priv->fast)) { ++ if (PTR_ERR(priv->fast) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get spdif fast domain clockt\n"); ++ return PTR_ERR(priv->fast); ++ } ++ ++ priv->iface = devm_clk_get(dev, "iface"); ++ if (IS_ERR(priv->iface)) { ++ if (PTR_ERR(priv->iface) != -EPROBE_DEFER) ++ dev_err(dev, ++ "Can't get the dai clock gate\n"); ++ return PTR_ERR(priv->iface); ++ } ++ ++ priv->mclk_i958 = devm_clk_get(dev, "mclk_i958"); ++ if (IS_ERR(priv->mclk_i958)) { ++ if (PTR_ERR(priv->mclk_i958) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get the spdif master clock\n"); ++ return PTR_ERR(priv->mclk_i958); ++ } ++ ++ /* ++ * TODO: the spdif dai can also get its data from the i2s fifo. ++ * For this use-case, the DAI driver will need to get the i2s master ++ * clock in order to reparent the spdif clock from cts_mclk_i958 to ++ * cts_amclk ++ */ ++ ++ priv->mclk = devm_clk_get(dev, "mclk"); ++ if (IS_ERR(priv->mclk)) { ++ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get the spdif input mux clock\n"); ++ return PTR_ERR(priv->mclk); ++ } ++ ++ return devm_snd_soc_register_component(dev, &meson_aiu_spdif_component, ++ &meson_aiu_spdif_dai, 1); ++} ++ ++static const struct of_device_id meson_aiu_spdif_of_match[] = { ++ { .compatible = "amlogic,meson-aiu-spdif", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, meson_aiu_spdif_of_match); ++ ++static struct platform_driver meson_aiu_spdif_pdrv = { ++ .probe = meson_aiu_spdif_probe, ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = meson_aiu_spdif_of_match, ++ }, ++}; ++module_platform_driver(meson_aiu_spdif_pdrv); ++ ++MODULE_DESCRIPTION("Meson AIU spdif ASoC Driver"); ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_LICENSE("GPL v2"); +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0105-TEMP-ARM64-defconfig-enable-audio-support-for-meson-.patch b/packages/linux/patches/amlogic/amlogic-0105-TEMP-ARM64-defconfig-enable-audio-support-for-meson-.patch new file mode 100644 index 0000000000..aa2e7f6e26 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0105-TEMP-ARM64-defconfig-enable-audio-support-for-meson-.patch @@ -0,0 +1,31 @@ +From 70db85c6544e175a73cb3756c7d87b17f9eb6689 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 31 Mar 2017 15:55:03 +0200 +Subject: [PATCH 105/186] TEMP: ARM64: defconfig: enable audio support for + meson SoCs as module + +Add audio support for meson SoCs. This includes the audio core +driver and the i2s and spdif output interfaces + +Signed-off-by: Jerome Brunet +--- + arch/arm64/configs/defconfig | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig +index 1053815f20cc..407e25b22c41 100644 +--- a/arch/arm64/configs/defconfig ++++ b/arch/arm64/configs/defconfig +@@ -556,6 +556,9 @@ CONFIG_SND_HDA_CODEC_HDMI=m + CONFIG_SND_SOC=y + CONFIG_SND_BCM2835_SOC_I2S=m + CONFIG_SND_MESON_AXG_SOUND_CARD=m ++CONFIG_SND_SOC_MESON_GX=m ++CONFIG_SND_SOC_MESON_GX_I2S=m ++CONFIG_SND_SOC_MESON_GX_SPDIF=m + CONFIG_SND_SOC_ROCKCHIP=m + CONFIG_SND_SOC_ROCKCHIP_SPDIF=m + CONFIG_SND_SOC_ROCKCHIP_RT5645=m +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0106-TEMP-ARM64-dts-meson-gx-add-audio-controller-nodes.patch b/packages/linux/patches/amlogic/amlogic-0106-TEMP-ARM64-dts-meson-gx-add-audio-controller-nodes.patch new file mode 100644 index 0000000000..9f56a3afbd --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0106-TEMP-ARM64-dts-meson-gx-add-audio-controller-nodes.patch @@ -0,0 +1,146 @@ +From dd151cecb2cf220267c53d01cf93307cac51e557 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 15:19:04 +0200 +Subject: [PATCH 106/186] TEMP: ARM64: dts: meson-gx: add audio controller + nodes + +Add audio controller nodes for Amlogic meson gxbb and gxl. +This includes the audio-core node, the i2s and spdif DAIs + +Audio on this SoC family is still a work in progress. More nodes are likely +to be added later on (pcm DAIs, input DMAs, etc ...) + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 23 ++++++++++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 27 +++++++++++++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 27 +++++++++++++++++++++ + 3 files changed, 77 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index 209f20bea4a1..ed6ab86d3e7e 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -226,6 +226,29 @@ + #reset-cells = <1>; + }; + ++ audio: audio@5400 { ++ compatible = "amlogic,meson-gx-audio-core"; ++ reg = <0x0 0x5400 0x0 0x2ac>, ++ <0x0 0xa000 0x0 0x304>; ++ reg-names = "aiu", "audin"; ++ status = "disabled"; ++ ++ aiu_i2s: audio-controller-0 { ++ #sound-dai-cells = <0>; ++ compatible = "amlogic,meson-aiu-i2s"; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ aiu_spdif: audio-controller-1 { ++ #sound-dai-cells = <0>; ++ compatible = "amlogic,meson-aiu-spdif"; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ }; ++ + uart_A: serial@84c0 { + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x84c0 0x0 0x18>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index f734faaf7b78..7316e8b171f2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -724,6 +724,24 @@ + }; + }; + ++&audio { ++ clocks = <&clkc CLKID_AIU>, ++ <&clkc CLKID_AIU_GLUE>, ++ <&clkc CLKID_I2S_SPDIF>; ++ clock-names = "aiu_top", "aiu_glue", "audin"; ++ resets = <&reset RESET_AIU>, ++ <&reset RESET_AUDIN>; ++ reset-names = "aiu", "audin"; ++}; ++ ++&aiu_i2s { ++ clocks = <&clkc CLKID_I2S_OUT>, ++ <&clkc CLKID_MIXER_IFACE>, ++ <&clkc CLKID_AOCLK_GATE>, ++ <&clkc CLKID_CTS_AMCLK>; ++ clock-names = "fast", "iface", "bclks", "mclk"; ++}; ++ + &pwrc_vpu { + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, +@@ -812,6 +830,15 @@ + num-cs = <1>; + }; + ++&aiu_spdif { ++ clocks = <&clkc CLKID_IEC958>, ++ <&clkc CLKID_IEC958_GATE>, ++ <&clkc CLKID_CTS_MCLK_I958>, ++ <&clkc CLKID_CTS_AMCLK>, ++ <&clkc CLKID_CTS_I958>; ++ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk"; ++}; ++ + &spifc { + clocks = <&clkc CLKID_SPI>; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index c959456bacc6..2fa1cc8ea0b0 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -727,6 +727,24 @@ + }; + }; + ++&audio { ++ clocks = <&clkc CLKID_AIU>, ++ <&clkc CLKID_AIU_GLUE>, ++ <&clkc CLKID_I2S_SPDIF>; ++ clock-names = "aiu_top", "aiu_glue", "audin"; ++ resets = <&reset RESET_AIU>, ++ <&reset RESET_AUDIN>; ++ reset-names = "aiu", "audin"; ++}; ++ ++&aiu_i2s { ++ clocks = <&clkc CLKID_I2S_OUT>, ++ <&clkc CLKID_MIXER_IFACE>, ++ <&clkc CLKID_AOCLK_GATE>, ++ <&clkc CLKID_CTS_AMCLK>; ++ clock-names = "fast", "iface", "bclks", "mclk"; ++}; ++ + &pwrc_vpu { + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, +@@ -815,6 +833,15 @@ + num-cs = <1>; + }; + ++&aiu_spdif { ++ clocks = <&clkc CLKID_IEC958>, ++ <&clkc CLKID_IEC958_GATE>, ++ <&clkc CLKID_CTS_MCLK_I958>, ++ <&clkc CLKID_CTS_AMCLK>, ++ <&clkc CLKID_CTS_I958>; ++ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk"; ++}; ++ + &spifc { + clocks = <&clkc CLKID_SPI>; + }; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0107-TEMP-snd-meson-activate-HDMI-audio-path.patch b/packages/linux/patches/amlogic/amlogic-0107-TEMP-snd-meson-activate-HDMI-audio-path.patch new file mode 100644 index 0000000000..8737eba1b5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0107-TEMP-snd-meson-activate-HDMI-audio-path.patch @@ -0,0 +1,55 @@ +From 9f28cd6351879adb8a3e949c956fd3b964c5bc39 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 7 Jul 2017 17:39:21 +0200 +Subject: [PATCH 107/186] TEMP: snd: meson: activate HDMI audio path + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/aiu-i2s.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c +index 63d7821c2c72..c6bfd5d8c808 100644 +--- a/sound/soc/meson-gx/aiu-i2s.c ++++ b/sound/soc/meson-gx/aiu-i2s.c +@@ -334,8 +334,19 @@ static int meson_aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd) + #define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8) + #define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0) + #define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0) ++#define AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK BIT(6) ++#define AIU_CLK_CTRL_MORE_HDMI_TX_I958_CLK (0 << 6) ++#define AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK (1 << 6) + #define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0) + #define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK GENMASK(1, 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_DISABLE (0 << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_PCM (1 << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_I2S (2 << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK GENMASK(5, 4) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_MUTE (0 << 4) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_PCM (1 << 4) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_I2S (2 << 4) + #define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0) + #define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0) + #define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0) +@@ -499,6 +510,17 @@ static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, + return ret; + } + ++ /* Quick and dirty hack for HDMI */ ++ regmap_update_bits(priv->core->aiu, AIU_HDMI_CLK_DATA_CTRL, ++ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK | ++ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK, ++ AIU_HDMI_CLK_DATA_CTRL_CLK_I2S | ++ AIU_HDMI_CLK_DATA_CTRL_DATA_I2S); ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE, ++ AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK, ++ AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK); ++ + return 0; + } + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0108-TEMP-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-.patch b/packages/linux/patches/amlogic/amlogic-0108-TEMP-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-.patch new file mode 100644 index 0000000000..5e67364e85 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0108-TEMP-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-.patch @@ -0,0 +1,39 @@ +From 69c2de4aa84b57b47a55e5ebf84da7b7aa06bddf Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 20 Sep 2017 18:01:26 +0200 +Subject: [PATCH 108/186] TEMP: ARM64: dts: meson-gx: add sound-dai-cells to + HDMI node + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 + + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index 7316e8b171f2..30dbc3753045 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -330,6 +330,7 @@ + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; ++ #sound-dai-cells = <0>; + }; + + &sysctrl { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index 2fa1cc8ea0b0..a76e5b603da9 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -280,6 +280,7 @@ + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; ++ #sound-dai-cells = <0>; + }; + + &sysctrl { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0109-TEMP-ARM64-dts-meson-activate-hdmi-audio-HDMI-enable.patch b/packages/linux/patches/amlogic/amlogic-0109-TEMP-ARM64-dts-meson-activate-hdmi-audio-HDMI-enable.patch new file mode 100644 index 0000000000..a0caae57e2 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0109-TEMP-ARM64-dts-meson-activate-hdmi-audio-HDMI-enable.patch @@ -0,0 +1,685 @@ +From 0a2bf870a0120e3ecb22fa6458fc9f5d983a9177 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 20 Sep 2017 18:10:08 +0200 +Subject: [PATCH 109/186] TEMP: ARM64: dts: meson: activate hdmi audio HDMI + enabled boards + +This patch activate audio over HDMI on selected boards + +Please note that this audio support is based on WIP changes +This should be considered as preview and it does not reflect +the audio I expect to see merged + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 37 +++++++++++++++++++ + .../dts/amlogic/meson-gxbb-nexbox-a95x.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-odroidc2.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-p20x.dtsi | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-wetek.dtsi | 37 +++++++++++++++++++ + .../amlogic/meson-gxl-s905x-khadas-vim.dts | 37 +++++++++++++++++++ + .../amlogic/meson-gxl-s905x-libretech-cc.dts | 37 +++++++++++++++++++ + .../amlogic/meson-gxl-s905x-nexbox-a95x.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 37 +++++++++++++++++++ + .../dts/amlogic/meson-gxm-khadas-vim2.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 37 +++++++++++++++++++ + 12 files changed, 444 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +index a9b778571cf5..05673221dcc3 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +@@ -102,6 +102,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -111,6 +140,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +index c34c1c90ccb6..e555612a6612 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +@@ -88,6 +88,35 @@ + clock-names = "ext_clock"; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + vcc1v8: regulator-vcc1v8 { + compatible = "regulator-fixed"; + regulator-name = "VCC1.8V"; +@@ -131,6 +160,14 @@ + }; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cec_AO { + status = "okay"; + pinctrl-0 = <&ao_cec_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +index b636912a2715..905e4bb70df9 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +@@ -119,6 +119,35 @@ + clock-names = "ext_clock"; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + cvbs-connector { + compatible = "composite-video-connector"; + +@@ -154,6 +183,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + ðmac { + status = "okay"; + pinctrl-0 = <ð_rmii_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +index 9972b1515da6..2facdf49f8ff 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +@@ -110,6 +110,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -119,6 +148,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + ðmac { + status = "okay"; + pinctrl-0 = <ð_rgmii_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +index e8f925871edf..3245859f7d2a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +@@ -113,6 +113,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -122,6 +151,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +index 4c539881fbb7..6b7ac033ce22 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +@@ -112,6 +112,43 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++}; ++ ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; + }; + + &cec_AO { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +index 5499e8de5c74..bf3453f549dc 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +@@ -65,6 +65,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -74,6 +103,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +index 4b8ce738e213..969ee02e7429 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +@@ -84,6 +84,35 @@ + regulator-always-on; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + vcc_3v3: regulator-vcc_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC_3V3"; +@@ -132,6 +161,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +index 26907ac82930..93e1fbbe9438 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +@@ -102,6 +102,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -111,6 +140,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts +index 2602940c2077..78c3060c5d56 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts +@@ -32,6 +32,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -41,6 +70,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index 989d33ac6eae..f560eca12067 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -82,6 +82,35 @@ + }; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + pwmleds { + compatible = "pwm-leds"; + +@@ -198,6 +227,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cpu0 { + #cooling-cells = <2>; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +index c2bd4dbbf38c..b6519bbdaadb 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +@@ -75,6 +75,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -84,6 +113,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0110-TEMP-drm-dw-hdmi-call-hdmi_set_cts_n-after-clock-is-.patch b/packages/linux/patches/amlogic/amlogic-0110-TEMP-drm-dw-hdmi-call-hdmi_set_cts_n-after-clock-is-.patch new file mode 100644 index 0000000000..df1a69e440 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0110-TEMP-drm-dw-hdmi-call-hdmi_set_cts_n-after-clock-is-.patch @@ -0,0 +1,29 @@ +From 2b83ba83b25410119107b2c2ee4163a76db538a5 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 9 Jul 2018 21:25:15 +0200 +Subject: [PATCH 110/186] TEMP: drm: dw-hdmi: call hdmi_set_cts_n after clock + is enabled + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 8df69c9dbfad..d9297b20771d 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -688,6 +688,11 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) + else + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_AUDCLK_DISABLE; + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); ++ ++ if (enable) { ++ hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0); ++ hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); ++ } + } + + static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0111-TEMP-fix-chmap_idx.patch b/packages/linux/patches/amlogic/amlogic-0111-TEMP-fix-chmap_idx.patch new file mode 100644 index 0000000000..255cfafdcb --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0111-TEMP-fix-chmap_idx.patch @@ -0,0 +1,26 @@ +From b65693688acd0a5539dac2f9f88457d115879638 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 23 Dec 2018 02:24:38 +0100 +Subject: [PATCH 111/186] TEMP: fix chmap_idx + +--- + sound/soc/codecs/hdmi-codec.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 0bf1c8cad108..bc300bb123e0 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -369,7 +369,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = info->private_data; + +- map = info->chmap[hcp->chmap_idx].map; ++ if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN) ++ map = info->chmap[hcp->chmap_idx].map; + + for (i = 0; i < info->max_channels; i++) { + if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0112-TEMP-ASoC-hdmi-codec-reorder-channel-allocation-list.patch b/packages/linux/patches/amlogic/amlogic-0112-TEMP-ASoC-hdmi-codec-reorder-channel-allocation-list.patch new file mode 100644 index 0000000000..5074199a93 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0112-TEMP-ASoC-hdmi-codec-reorder-channel-allocation-list.patch @@ -0,0 +1,171 @@ +From 8122ce863a30c8c0dc6a40a004c04a5fe4411b12 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 25 Mar 2018 22:17:06 +0200 +Subject: [PATCH 112/186] TEMP: ASoC: hdmi-codec: reorder channel allocation + list + +Wrong channel allocation is selected by hdmi_codec_get_ch_alloc_table_idx(). + +E.g when ELD reports FL|FR|LFE|FC|RL|RR or FL|FR|LFE|FC|RL|RR|RC|RLC|RRC + +ca_id 0x01 with speaker mask FL|FR|LFE gets selected instead of +ca_id 0x03 with speaker mask FL|FR|LFE|FC for 4 channels + +and + +ca_id 0x04 with speaker mask FL|FR|RC gets selected instead of +ca_id 0x0b with speaker mask FL|FR|LFE|FC|RL|RR for 6 channels + +Fix this by reorder the channel allocation list with +most specific speaker mask at the top. + +Signed-off-by: Jonas Karlman +--- + sound/soc/codecs/hdmi-codec.c | 115 ++++++++++++++++------------------ + 1 file changed, 53 insertions(+), 62 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index bc300bb123e0..3b253589a012 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -188,84 +188,75 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { + /* + * hdmi_codec_channel_alloc: speaker configuration available for CEA + * +- * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct ++ * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps + * The preceding ones have better chances to be selected by + * hdmi_codec_get_ch_alloc_table_idx(). + */ + static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { + { .ca_id = 0x00, .n_ch = 2, +- .mask = FL | FR}, +- /* 2.1 */ +- { .ca_id = 0x01, .n_ch = 4, +- .mask = FL | FR | LFE}, +- /* Dolby Surround */ ++ .mask = FL | FR }, ++ { .ca_id = 0x03, .n_ch = 4, ++ .mask = FL | FR | LFE | FC }, + { .ca_id = 0x02, .n_ch = 4, + .mask = FL | FR | FC }, +- /* surround51 */ ++ { .ca_id = 0x01, .n_ch = 4, ++ .mask = FL | FR | LFE }, + { .ca_id = 0x0b, .n_ch = 6, +- .mask = FL | FR | LFE | FC | RL | RR}, +- /* surround40 */ +- { .ca_id = 0x08, .n_ch = 6, +- .mask = FL | FR | RL | RR }, +- /* surround41 */ +- { .ca_id = 0x09, .n_ch = 6, +- .mask = FL | FR | LFE | RL | RR }, +- /* surround50 */ ++ .mask = FL | FR | LFE | FC | RL | RR }, + { .ca_id = 0x0a, .n_ch = 6, + .mask = FL | FR | FC | RL | RR }, +- /* 6.1 */ +- { .ca_id = 0x0f, .n_ch = 8, +- .mask = FL | FR | LFE | FC | RL | RR | RC }, +- /* surround71 */ ++ { .ca_id = 0x09, .n_ch = 6, ++ .mask = FL | FR | LFE | RL | RR }, ++ { .ca_id = 0x08, .n_ch = 6, ++ .mask = FL | FR | RL | RR }, ++ { .ca_id = 0x07, .n_ch = 6, ++ .mask = FL | FR | LFE | FC | RC }, ++ { .ca_id = 0x06, .n_ch = 6, ++ .mask = FL | FR | FC | RC }, ++ { .ca_id = 0x05, .n_ch = 6, ++ .mask = FL | FR | LFE | RC }, ++ { .ca_id = 0x04, .n_ch = 6, ++ .mask = FL | FR | RC }, + { .ca_id = 0x13, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, +- /* others */ +- { .ca_id = 0x03, .n_ch = 8, +- .mask = FL | FR | LFE | FC }, +- { .ca_id = 0x04, .n_ch = 8, +- .mask = FL | FR | RC}, +- { .ca_id = 0x05, .n_ch = 8, +- .mask = FL | FR | LFE | RC }, +- { .ca_id = 0x06, .n_ch = 8, +- .mask = FL | FR | FC | RC }, +- { .ca_id = 0x07, .n_ch = 8, +- .mask = FL | FR | LFE | FC | RC }, +- { .ca_id = 0x0c, .n_ch = 8, +- .mask = FL | FR | RC | RL | RR }, +- { .ca_id = 0x0d, .n_ch = 8, +- .mask = FL | FR | LFE | RL | RR | RC }, +- { .ca_id = 0x0e, .n_ch = 8, +- .mask = FL | FR | FC | RL | RR | RC }, +- { .ca_id = 0x10, .n_ch = 8, +- .mask = FL | FR | RL | RR | RLC | RRC }, +- { .ca_id = 0x11, .n_ch = 8, +- .mask = FL | FR | LFE | RL | RR | RLC | RRC }, ++ { .ca_id = 0x1f, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x12, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RLC | RRC }, +- { .ca_id = 0x14, .n_ch = 8, +- .mask = FL | FR | FLC | FRC }, +- { .ca_id = 0x15, .n_ch = 8, +- .mask = FL | FR | LFE | FLC | FRC }, +- { .ca_id = 0x16, .n_ch = 8, +- .mask = FL | FR | FC | FLC | FRC }, +- { .ca_id = 0x17, .n_ch = 8, +- .mask = FL | FR | LFE | FC | FLC | FRC }, +- { .ca_id = 0x18, .n_ch = 8, +- .mask = FL | FR | RC | FLC | FRC }, +- { .ca_id = 0x19, .n_ch = 8, +- .mask = FL | FR | LFE | RC | FLC | FRC }, +- { .ca_id = 0x1a, .n_ch = 8, +- .mask = FL | FR | RC | FC | FLC | FRC }, +- { .ca_id = 0x1b, .n_ch = 8, +- .mask = FL | FR | LFE | RC | FC | FLC | FRC }, +- { .ca_id = 0x1c, .n_ch = 8, +- .mask = FL | FR | RL | RR | FLC | FRC }, +- { .ca_id = 0x1d, .n_ch = 8, +- .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x1e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | FLC | FRC }, +- { .ca_id = 0x1f, .n_ch = 8, +- .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, ++ { .ca_id = 0x11, .n_ch = 8, ++ .mask = FL | FR | LFE | RL | RR | RLC | RRC }, ++ { .ca_id = 0x1d, .n_ch = 8, ++ .mask = FL | FR | LFE | RL | RR | FLC | FRC }, ++ { .ca_id = 0x10, .n_ch = 8, ++ .mask = FL | FR | RL | RR | RLC | RRC }, ++ { .ca_id = 0x1c, .n_ch = 8, ++ .mask = FL | FR | RL | RR | FLC | FRC }, ++ { .ca_id = 0x0f, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | RL | RR | RC }, ++ { .ca_id = 0x1b, .n_ch = 8, ++ .mask = FL | FR | LFE | RC | FC | FLC | FRC }, ++ { .ca_id = 0x0e, .n_ch = 8, ++ .mask = FL | FR | FC | RL | RR | RC }, ++ { .ca_id = 0x1a, .n_ch = 8, ++ .mask = FL | FR | RC | FC | FLC | FRC }, ++ { .ca_id = 0x0d, .n_ch = 8, ++ .mask = FL | FR | LFE | RL | RR | RC }, ++ { .ca_id = 0x19, .n_ch = 8, ++ .mask = FL | FR | LFE | RC | FLC | FRC }, ++ { .ca_id = 0x0c, .n_ch = 8, ++ .mask = FL | FR | RC | RL | RR }, ++ { .ca_id = 0x18, .n_ch = 8, ++ .mask = FL | FR | RC | FLC | FRC }, ++ { .ca_id = 0x17, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | FLC | FRC }, ++ { .ca_id = 0x16, .n_ch = 8, ++ .mask = FL | FR | FC | FLC | FRC }, ++ { .ca_id = 0x15, .n_ch = 8, ++ .mask = FL | FR | LFE | FLC | FRC }, ++ { .ca_id = 0x14, .n_ch = 8, ++ .mask = FL | FR | FLC | FRC }, + }; + + struct hdmi_codec_priv { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0113-TEMP-multi-channel-GX-audio-hack.patch b/packages/linux/patches/amlogic/amlogic-0113-TEMP-multi-channel-GX-audio-hack.patch new file mode 100644 index 0000000000..f574bbad7f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0113-TEMP-multi-channel-GX-audio-hack.patch @@ -0,0 +1,197 @@ +From 91a654ab0b786f341e81b897fc1349a853580e1b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 1 Jun 2019 16:42:33 +0000 +Subject: [PATCH 113/186] TEMP: multi-channel GX audio hack + +--- + .../drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 2 + + sound/soc/codecs/hdmi-codec.c | 24 +++++++- + sound/soc/meson-gx/aiu-i2s.c | 56 ++++++++++++++++++- + 3 files changed, 79 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 1d15cf9b6821..63ca25dfc129 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -57,6 +57,8 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; + conf0 = (HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0); + ++ dev_info(dev, "channels=%d sample_width=%d sample_rate=%d\n", hparms->channels, hparms->sample_width, hparms->sample_rate); ++ + /* Enable the required i2s lanes */ + switch (hparms->channels) { + case 7 ... 8: +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 3b253589a012..608c3638741f 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -257,6 +257,28 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { + .mask = FL | FR | LFE | FLC | FRC }, + { .ca_id = 0x14, .n_ch = 8, + .mask = FL | FR | FLC | FRC }, ++ { .ca_id = 0x0b, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | RL | RR }, ++ { .ca_id = 0x0a, .n_ch = 8, ++ .mask = FL | FR | FC | RL | RR }, ++ { .ca_id = 0x09, .n_ch = 8, ++ .mask = FL | FR | LFE | RL | RR }, ++ { .ca_id = 0x08, .n_ch = 8, ++ .mask = FL | FR | RL | RR }, ++ { .ca_id = 0x07, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | RC }, ++ { .ca_id = 0x06, .n_ch = 8, ++ .mask = FL | FR | FC | RC }, ++ { .ca_id = 0x05, .n_ch = 8, ++ .mask = FL | FR | LFE | RC }, ++ { .ca_id = 0x04, .n_ch = 8, ++ .mask = FL | FR | RC }, ++ { .ca_id = 0x03, .n_ch = 8, ++ .mask = FL | FR | LFE | FC }, ++ { .ca_id = 0x02, .n_ch = 8, ++ .mask = FL | FR | FC }, ++ { .ca_id = 0x01, .n_ch = 8, ++ .mask = FL | FR | LFE }, + }; + + struct hdmi_codec_priv { +@@ -439,7 +461,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, + }; + int ret, idx; + +- dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, ++ dev_info(dai->dev, "%s() width %d rate %d channels %d\n", __func__, + params_width(params), params_rate(params), + params_channels(params)); + +diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c +index c6bfd5d8c808..ef800b53ab95 100644 +--- a/sound/soc/meson-gx/aiu-i2s.c ++++ b/sound/soc/meson-gx/aiu-i2s.c +@@ -86,6 +86,7 @@ static struct snd_pcm_hardware meson_aiu_i2s_dma_hw = { + .info = (SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE), + + .formats = (SNDRV_PCM_FMTBIT_S16_LE | +@@ -137,10 +138,22 @@ static void __dma_enable(struct meson_aiu_i2s *priv, bool enable) + { + unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN | + AIU_MEM_I2S_CONTROL_EMPTY_EN); ++ unsigned int val; ++ ++ pr_info("%s: enable=%d\n", __func__, enable); ++ ++ if (enable) { ++ regmap_write(priv->core->aiu, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST_DOMAIN); ++ regmap_read(priv->core->aiu, AIU_I2S_SYNC, &val); ++ } + + regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask, + enable ? en_mask : 0); + ++ if (!enable) { ++ regmap_write(priv->core->aiu, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST_DOMAIN); ++ regmap_read(priv->core->aiu, AIU_I2S_SYNC, &val); ++ } + } + + static int meson_aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cmd) +@@ -167,6 +180,8 @@ static int meson_aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cm + + static void __dma_init_mem(struct meson_aiu_i2s *priv) + { ++ pr_info("%s\n", __func__); ++ + regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, + AIU_MEM_I2S_CONTROL_INIT, + AIU_MEM_I2S_CONTROL_INIT); +@@ -199,6 +214,9 @@ static int meson_aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream, + int ret; + u32 burst_num, mem_ctl; + dma_addr_t end_ptr; ++ unsigned int val; ++ ++ pr_info("%s: physical_width=%d buffer_bytes=%d period_bytes=%d\n", __func__, params_physical_width(params), params_buffer_bytes(params), params_period_bytes(params)); + + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (ret < 0) +@@ -229,6 +247,10 @@ static int meson_aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream, + AIU_MEM_I2S_MASKS_CH_MEM(0xff) | + AIU_MEM_I2S_MASKS_IRQ_BLOCK(burst_num)); + ++ regmap_write(priv->core->aiu, AIU_RST_SOFT, ++ AIU_RST_SOFT_I2S_FAST_DOMAIN); ++ regmap_read(priv->core->aiu, AIU_I2S_SYNC, &val); ++ + return 0; + } + +@@ -247,6 +269,16 @@ static irqreturn_t meson_aiu_i2s_dma_irq_block(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static const unsigned int channels_2_8[] = { ++ 2, 8 ++}; ++ ++static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = { ++ .count = ARRAY_SIZE(channels_2_8), ++ .list = channels_2_8, ++ .mask = 0, ++}; ++ + static int meson_aiu_i2s_dma_open(struct snd_pcm_substream *substream) + { + struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); +@@ -254,6 +286,10 @@ static int meson_aiu_i2s_dma_open(struct snd_pcm_substream *substream) + + snd_soc_set_runtime_hwparams(substream, &meson_aiu_i2s_dma_hw); + ++ snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_CHANNELS, ++ &hw_constraints_2_8_channels); ++ + /* + * Make sure the buffer and period size are multiple of the DMA burst + * size +@@ -359,9 +395,20 @@ static int meson_aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd) + + static void __hold(struct meson_aiu_i2s *priv, bool enable) + { ++ unsigned int val; ++ pr_info("%s: enable=%d\n", __func__, enable); ++ ++ if (enable) { + regmap_update_bits(priv->core->aiu, AIU_I2S_MISC, +- AIU_I2S_MISC_HOLD_EN, +- enable ? AIU_I2S_MISC_HOLD_EN : 0); ++ AIU_I2S_MISC_HOLD_EN | BIT(4), ++ AIU_I2S_MISC_HOLD_EN); ++ } else { ++ regmap_write(priv->core->aiu, AIU_I2S_MUTE_SWAP, 0xFF); ++ regmap_update_bits(priv->core->aiu, AIU_I2S_MISC, ++ AIU_I2S_MISC_HOLD_EN | BIT(4), ++ BIT(4)); ++ regmap_read(priv->core->aiu, AIU_I2S_SYNC, &val); ++ } + } + + static void __divider_enable(struct meson_aiu_i2s *priv, bool enable) +@@ -479,6 +526,11 @@ static int __setup_desc(struct meson_aiu_i2s *priv, unsigned int width, + return -EINVAL; + } + ++ pr_info("%s: width=%d channels=%d desc=%u\n", __func__, width, channels, desc); ++ ++ regmap_write(priv->core->aiu, AIU_I2S_SOURCE_DESC, ++ AIU_I2S_SOURCE_DESC_MODE_SPLIT); ++ + regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC, + AIU_I2S_SOURCE_DESC_MODE_8CH | + AIU_I2S_SOURCE_DESC_MODE_24BIT | +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0114-TEMP-silence-multi-channel-GX-log-spam.patch b/packages/linux/patches/amlogic/amlogic-0114-TEMP-silence-multi-channel-GX-log-spam.patch new file mode 100644 index 0000000000..224417a161 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0114-TEMP-silence-multi-channel-GX-log-spam.patch @@ -0,0 +1,40 @@ +From 73cbd516cdad4f3f2a3efb275b5d89c3d227b539 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Tue, 13 Aug 2019 09:13:44 +0000 +Subject: [PATCH 114/186] TEMP: silence multi-channel GX log spam + +Signed-off-by: Christian Hewitt +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 2 +- + sound/soc/codecs/hdmi-codec.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 63ca25dfc129..73d63c4dd01d 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -57,7 +57,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; + conf0 = (HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0); + +- dev_info(dev, "channels=%d sample_width=%d sample_rate=%d\n", hparms->channels, hparms->sample_width, hparms->sample_rate); ++ dev_dbg(dev, "channels=%d sample_width=%d sample_rate=%d\n", hparms->channels, hparms->sample_width, hparms->sample_rate); + + /* Enable the required i2s lanes */ + switch (hparms->channels) { +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 608c3638741f..862ebb01cc8d 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -461,7 +461,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, + }; + int ret, idx; + +- dev_info(dai->dev, "%s() width %d rate %d channels %d\n", __func__, ++ dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, + params_width(params), params_rate(params), + params_channels(params)); + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0115-TEMP-arm64-dts-meson-gx-add-vdec-entry.patch b/packages/linux/patches/amlogic/amlogic-0115-TEMP-arm64-dts-meson-gx-add-vdec-entry.patch new file mode 100644 index 0000000000..51a53fe817 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0115-TEMP-arm64-dts-meson-gx-add-vdec-entry.patch @@ -0,0 +1,40 @@ +From 8e15bf64aa8f1ac4a4036767fe2b262091d42270 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:24:02 +0200 +Subject: [PATCH 115/186] TEMP: arm64: dts: meson-gx: add vdec entry + +Add the video decoder dts entry + +Signed-off-by: Maxime Jourdan +--- + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index ed6ab86d3e7e..65155abbe082 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -461,6 +461,20 @@ + }; + }; + ++ vdec: video-decoder@c8820000 { ++ compatible = "amlogic,gx-vdec"; ++ reg = <0x0 0xc8820000 0x0 0x10000>, ++ <0x0 0xc110a580 0x0 0xe4>; ++ reg-names = "dos", "esparser"; ++ ++ interrupts = , ++ ; ++ interrupt-names = "vdec", "esparser"; ++ ++ amlogic,ao-sysctrl = <&sysctrl_AO>; ++ amlogic,canvas = <&canvas>; ++ }; ++ + periphs: periphs@c8834000 { + compatible = "simple-bus"; + reg = <0x0 0xc8834000 0x0 0x2000>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0116-TEMP-arm64-dts-meson-add-vdec-entries.patch b/packages/linux/patches/amlogic/amlogic-0116-TEMP-arm64-dts-meson-add-vdec-entries.patch new file mode 100644 index 0000000000..7e15280b76 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0116-TEMP-arm64-dts-meson-add-vdec-entries.patch @@ -0,0 +1,67 @@ +From b2353cb4fd2d518d434c8737c230f8c52f03abc9 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:24:22 +0200 +Subject: [PATCH 116/186] TEMP: arm64: dts: meson: add vdec entries + +This enables the video decoder for gxbb, gxl and gxm chips + +Signed-off-by: Maxime Jourdan +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 11 +++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 11 +++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 4 ++++ + 3 files changed, 26 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index 30dbc3753045..d432398a5150 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -873,3 +873,14 @@ + compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; + power-domains = <&pwrc_vpu>; + }; ++ ++&vdec { ++ compatible = "amlogic,gxbb-vdec"; ++ clocks = <&clkc CLKID_DOS_PARSER>, ++ <&clkc CLKID_DOS>, ++ <&clkc CLKID_VDEC_1>, ++ <&clkc CLKID_VDEC_HEVC>; ++ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; ++ resets = <&reset RESET_PARSER>; ++ reset-names = "esparser"; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index a76e5b603da9..d8814fc30e78 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -876,3 +876,14 @@ + compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu"; + power-domains = <&pwrc_vpu>; + }; ++ ++&vdec { ++ compatible = "amlogic,gxl-vdec"; ++ clocks = <&clkc CLKID_DOS_PARSER>, ++ <&clkc CLKID_DOS>, ++ <&clkc CLKID_VDEC_1>, ++ <&clkc CLKID_VDEC_HEVC>; ++ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; ++ resets = <&reset RESET_PARSER>; ++ reset-names = "esparser"; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +index 7a85a82bf65d..13e76d4136c0 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +@@ -144,3 +144,7 @@ + &dwc3 { + phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>; + }; ++ ++&vdec { ++ compatible = "amlogic,gxm-vdec"; ++}; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0117-TEMP-arm64-dts-meson-g12a-add-video-decoder-node.patch b/packages/linux/patches/amlogic/amlogic-0117-TEMP-arm64-dts-meson-g12a-add-video-decoder-node.patch new file mode 100644 index 0000000000..f2c1bfea5f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0117-TEMP-arm64-dts-meson-g12a-add-video-decoder-node.patch @@ -0,0 +1,47 @@ +From 1926f99b542169f7b90724cb4450f3d625201950 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Mon, 26 Aug 2019 05:12:45 +0000 +Subject: [PATCH 117/186] TEMP: arm64: dts: meson-g12a: add video decoder node + +Signed-off-by: Maxime Jourdan +--- + .../boot/dts/amlogic/meson-g12-common.dtsi | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index 2fa4b43f2dad..e4aa4a3b06bd 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -2165,6 +2165,29 @@ + }; + }; + ++ vdec: video-decoder@ff620000 { ++ compatible = "amlogic,g12a-vdec"; ++ reg = <0x0 0xff620000 0x0 0x10000>, ++ <0x0 0xffd0e180 0x0 0xe4>; ++ reg-names = "dos", "esparser"; ++ ++ interrupts = , ++ ; ++ interrupt-names = "vdec", "esparser"; ++ ++ amlogic,ao-sysctrl = <&rti>; ++ amlogic,canvas = <&canvas>; ++ ++ clocks = <&clkc CLKID_PARSER>, ++ <&clkc CLKID_DOS>, ++ <&clkc CLKID_VDEC_1>, ++ <&clkc CLKID_VDEC_HEVC>, ++ <&clkc CLKID_VDEC_HEVCF>; ++ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc", "vdec_hevcf"; ++ resets = <&reset RESET_PARSER>; ++ reset-names = "esparser"; ++ }; ++ + vpu: vpu@ff900000 { + compatible = "amlogic,meson-g12a-vpu"; + reg = <0x0 0xff900000 0x0 0x100000>, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0118-TEMP-media-meson-vdec-add-H.264-decoding-support.patch b/packages/linux/patches/amlogic/amlogic-0118-TEMP-media-meson-vdec-add-H.264-decoding-support.patch new file mode 100644 index 0000000000..45babf9f79 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0118-TEMP-media-meson-vdec-add-H.264-decoding-support.patch @@ -0,0 +1,594 @@ +From 44376592ee03c0a6593e4889fe3d9fc1a199f80c Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:42:56 +0200 +Subject: [PATCH 118/186] TEMP: media: meson: vdec: add H.264 decoding support + +Add support for V4L2_PIX_FMT_H264 + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/Makefile | 2 +- + drivers/staging/media/meson/vdec/codec_h264.c | 478 ++++++++++++++++++ + drivers/staging/media/meson/vdec/codec_h264.h | 13 + + .../staging/media/meson/vdec/vdec_platform.c | 31 ++ + 4 files changed, 523 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/media/meson/vdec/codec_h264.c + create mode 100644 drivers/staging/media/meson/vdec/codec_h264.h + +diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile +index 6bea129084b7..711d990c760e 100644 +--- a/drivers/staging/media/meson/vdec/Makefile ++++ b/drivers/staging/media/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/staging/media/meson/vdec/codec_h264.c b/drivers/staging/media/meson/vdec/codec_h264.c +new file mode 100644 +index 000000000000..6ac0115afaa3 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_h264.c +@@ -0,0 +1,478 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++#define SIZE_EXT_FW (20 * SZ_1K) ++#define SIZE_WORKSPACE 0x1ee000 ++#define SIZE_SEI (8 * SZ_1K) ++ ++/* Offset added by the firmware which must be substracted ++ * from the workspace phyaddr ++ */ ++#define WORKSPACE_BUF_OFFSET 0x1000000 ++ ++/* ISR status */ ++#define CMD_MASK GENMASK(7, 0) ++#define CMD_SRC_CHANGE 1 ++#define CMD_FRAMES_READY 2 ++#define CMD_FATAL_ERROR 6 ++#define CMD_BAD_WIDTH 7 ++#define CMD_BAD_HEIGHT 8 ++ ++#define SEI_DATA_READY BIT(15) ++ ++/* Picture type */ ++#define PIC_TOP_BOT 5 ++#define PIC_BOT_TOP 6 ++ ++/* Size of Motion Vector per macroblock */ ++#define MB_MV_SIZE 96 ++ ++/* Frame status data */ ++#define PIC_STRUCT_BIT 5 ++#define PIC_STRUCT_MASK GENMASK(2, 0) ++#define BUF_IDX_MASK GENMASK(4, 0) ++#define ERROR_FLAG BIT(9) ++#define OFFSET_BIT 16 ++#define OFFSET_MASK GENMASK(15, 0) ++ ++/* Bitstream parsed data */ ++#define MB_TOTAL_BIT 8 ++#define MB_TOTAL_MASK GENMASK(15, 0) ++#define MB_WIDTH_MASK GENMASK(7, 0) ++#define MAX_REF_BIT 24 ++#define MAX_REF_MASK GENMASK(6, 0) ++#define AR_IDC_BIT 16 ++#define AR_IDC_MASK GENMASK(7, 0) ++#define AR_PRESENT_FLAG BIT(0) ++#define AR_EXTEND 0xff ++ ++/* Buffer to send to the ESPARSER to signal End Of Stream for H.264. ++ * This is a 16x16 encoded picture that will trigger drain firmware-side. ++ * There is no known alternative. ++ */ ++static const u8 eos_sequence[SZ_1K] = { ++ 0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd, ++ 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, ++ 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, ++ 0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37, ++ 0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, ++ 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, ++ 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, ++ 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, ++ 0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, ++ 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, ++ 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, ++ 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, ++ 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65, ++ 0x66, 0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d, ++ 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, ++ 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, ++ 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, ++ 0x3d, 0x36, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, ++ 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, ++ 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, ++ 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, ++ 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, ++ 0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, ++ 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, ++ 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68, ++ 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, ++ 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, ++ 0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, ++ 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66, ++ 0x66, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, ++ 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, ++ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, ++ 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, ++ 0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69, ++ 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x20, 0x72, 0x61, 0x74, ++ 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f, ++ 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, ++ 0x6e, 0x3d, 0x31, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35, ++ 0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69, ++ 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30, ++ 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20, ++ 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x51, 0xe2, 0x44, 0xd4, ++ 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01, ++ 0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6, ++ 0x57, 0xae, 0x49, 0x30, 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4, ++ 0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb, 0xd6, 0xbe, 0x5c, 0xd7, ++ 0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09, ++ 0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66, ++ 0xba, 0x9b, 0x82, 0x29, 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b ++}; ++ ++static const u8 *codec_h264_eos_sequence(u32 *len) ++{ ++ *len = ARRAY_SIZE(eos_sequence); ++ return eos_sequence; ++} ++ ++struct codec_h264 { ++ /* H.264 decoder requires an extended firmware */ ++ void *ext_fw_vaddr; ++ dma_addr_t ext_fw_paddr; ++ ++ /* Buffer for the H.264 Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++ ++ /* Buffer for the H.264 references MV */ ++ void *ref_vaddr; ++ dma_addr_t ref_paddr; ++ u32 ref_size; ++ ++ /* Buffer for parsed SEI data */ ++ void *sei_vaddr; ++ dma_addr_t sei_paddr; ++ ++ u32 mb_width; ++ u32 mb_height; ++ u32 max_refs; ++}; ++ ++static int codec_h264_can_recycle(struct amvdec_core *core) ++{ ++ return !amvdec_read_dos(core, AV_SCRATCH_7) || ++ !amvdec_read_dos(core, AV_SCRATCH_8); ++} ++ ++static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx) ++{ ++ /* Tell the decoder he can recycle this buffer. ++ * AV_SCRATCH_8 serves the same purpose. ++ */ ++ if (!amvdec_read_dos(core, AV_SCRATCH_7)) ++ amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1); ++ else ++ amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1); ++} ++ ++static int codec_h264_start(struct amvdec_session *sess) { ++ u32 workspace_offset; ++ struct amvdec_core *core = sess->core; ++ struct codec_h264 *h264 = sess->priv; ++ ++ /* Allocate some memory for the H.264 decoder's state */ ++ h264->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &h264->workspace_paddr, GFP_KERNEL); ++ if (!h264->workspace_vaddr) { ++ dev_err(core->dev, "Failed to alloc H.264 Workspace\n"); ++ return -ENOMEM; ++ } ++ ++ /* Allocate some memory for the H.264 SEI dump */ ++ h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI, ++ &h264->sei_paddr, GFP_KERNEL); ++ if (!h264->sei_vaddr) { ++ dev_err(core->dev, "Failed to alloc H.264 SEI\n"); ++ return -ENOMEM; ++ } ++ ++ amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6)); ++ ++ workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET; ++ amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset); ++ amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr); ++ amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr - workspace_offset); ++ ++ /* Enable "error correction" */ ++ amvdec_write_dos(core, AV_SCRATCH_F, ++ (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) | ++ BIT(4) | BIT(7)); ++ ++ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa); ++ ++ return 0; ++} ++ ++static int codec_h264_stop(struct amvdec_session *sess) ++{ ++ struct codec_h264 *h264 = sess->priv; ++ struct amvdec_core *core = sess->core; ++ ++ if (h264->ext_fw_vaddr) ++ dma_free_coherent(core->dev, SIZE_EXT_FW, ++ h264->ext_fw_vaddr, h264->ext_fw_paddr); ++ ++ if (h264->workspace_vaddr) ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ h264->workspace_vaddr, h264->workspace_paddr); ++ ++ if (h264->ref_vaddr) ++ dma_free_coherent(core->dev, h264->ref_size, ++ h264->ref_vaddr, h264->ref_paddr); ++ ++ if (h264->sei_vaddr) ++ dma_free_coherent(core->dev, SIZE_SEI, ++ h264->sei_vaddr, h264->sei_paddr); ++ ++ return 0; ++} ++ ++static int codec_h264_load_extended_firmware(struct amvdec_session *sess, ++ const u8 *data, u32 len) ++{ ++ struct codec_h264 *h264; ++ struct amvdec_core *core = sess->core; ++ ++ if (len < SIZE_EXT_FW) ++ return -EINVAL; ++ ++ h264 = kzalloc(sizeof(*h264), GFP_KERNEL); ++ if (!h264) ++ return -ENOMEM; ++ ++ h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW, ++ &h264->ext_fw_paddr, GFP_KERNEL); ++ if (!h264->ext_fw_vaddr) { ++ dev_err(core->dev, "Failed to alloc H.264 extended fw\n"); ++ kfree(h264); ++ return -ENOMEM; ++ } ++ ++ memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW); ++ sess->priv = h264; ++ ++ return 0; ++} ++ ++static const struct v4l2_fract par_table[] = { ++ { 1, 1 }, { 1, 1 }, { 12, 11 }, { 10, 11 }, ++ { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 }, ++ { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 }, ++ { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 }, ++ { 2, 1 } ++}; ++ ++static void codec_h264_set_par(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2); ++ u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK; ++ ++ if (!(seq_info & AR_PRESENT_FLAG)) ++ return; ++ ++ if (ar_idc == AR_EXTEND) { ++ u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3); ++ sess->pixelaspect.numerator = ar_info & 0xffff; ++ sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff; ++ return; ++ } ++ ++ if (ar_idc >= ARRAY_SIZE(par_table)) ++ return; ++ ++ sess->pixelaspect = par_table[ar_idc]; ++} ++ ++static void codec_h264_resume(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_h264 *h264 = sess->priv; ++ u32 mb_width, mb_height, mb_total; ++ ++ amvdec_set_canvases(sess, (u32[]){ ANC0_CANVAS_ADDR, 0 }, ++ (u32[]){ 24, 0 }); ++ ++ dev_dbg(core->dev, ++ "max_refs = %u; actual_dpb_size = %u\n", ++ h264->max_refs, sess->num_dst_bufs); ++ ++ /* Align to a multiple of 4 macroblocks */ ++ mb_width = ALIGN(h264->mb_width, 4); ++ mb_height = ALIGN(h264->mb_height, 4); ++ mb_total = mb_width * mb_height; ++ ++ h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs; ++ h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size, ++ &h264->ref_paddr, GFP_KERNEL); ++ if (!h264->ref_vaddr) { ++ dev_err(core->dev, "Failed to alloc refs (%u)\n", ++ h264->ref_size); ++ amvdec_abort(sess); ++ return; ++ } ++ ++ /* Address to store the references' MVs */ ++ amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr); ++ /* End of ref MV */ ++ amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size); ++ ++ amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) | ++ (sess->num_dst_bufs << 16) | ++ ((h264->max_refs - 1) << 8)); ++} ++ ++/* Configure the H.264 decoder when the parser detected a parameter set change ++ */ ++static void codec_h264_src_change(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_h264 *h264 = sess->priv; ++ u32 parsed_info, mb_total; ++ u32 crop_infor, crop_bottom, crop_right; ++ u32 frame_width, frame_height; ++ ++ sess->keyframe_found = 1; ++ ++ parsed_info = amvdec_read_dos(core, AV_SCRATCH_1); ++ ++ /* Total number of 16x16 macroblocks */ ++ mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK; ++ /* Number of macroblocks per line */ ++ h264->mb_width = parsed_info & MB_WIDTH_MASK; ++ /* Number of macroblock lines */ ++ h264->mb_height = mb_total / h264->mb_width; ++ ++ h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1; ++ ++ crop_infor = amvdec_read_dos(core, AV_SCRATCH_6); ++ crop_bottom = (crop_infor & 0xff); ++ crop_right = (crop_infor >> 16) & 0xff; ++ ++ frame_width = h264->mb_width * 16 - crop_right; ++ frame_height = h264->mb_height * 16 - crop_bottom; ++ ++ dev_info(core->dev, "frame: %ux%u; crop: %u %u\n", ++ frame_width, frame_height, crop_right, crop_bottom); ++ ++ codec_h264_set_par(sess); ++ amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5); ++} ++ ++/** ++ * The offset is split in half in 2 different registers ++ */ ++static u32 get_offset_msb(struct amvdec_core *core, int frame_num) ++{ ++ int take_msb = frame_num % 2; ++ int reg_offset = (frame_num / 2) * 4; ++ u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset); ++ ++ if (take_msb) ++ return offset_msb & 0xffff0000; ++ ++ return (offset_msb & 0x0000ffff) << 16; ++} ++ ++static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status) ++{ ++ struct amvdec_core *core = sess->core; ++ int error_count; ++ int num_frames; ++ int i; ++ ++ error_count = amvdec_read_dos(core, AV_SCRATCH_D); ++ num_frames = (status >> 8) & 0xff; ++ if (error_count) { ++ dev_warn(core->dev, ++ "decoder error(s) happened, count %d\n", error_count); ++ amvdec_write_dos(core, AV_SCRATCH_D, 0); ++ } ++ ++ for (i = 0; i < num_frames; i++) { ++ u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4); ++ u32 buffer_index = frame_status & BUF_IDX_MASK; ++ u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) & ++ PIC_STRUCT_MASK; ++ u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK; ++ u32 field = V4L2_FIELD_NONE; ++ ++ /* A buffer decode error means it was decoded, ++ * but part of the picture will have artifacts. ++ * Typical reason is a temporarily corrupted bitstream ++ */ ++ if (frame_status & ERROR_FLAG) ++ dev_dbg(core->dev, "Buffer %d decode error\n", ++ buffer_index); ++ ++ if (pic_struct == PIC_TOP_BOT) ++ field = V4L2_FIELD_INTERLACED_TB; ++ else if (pic_struct == PIC_BOT_TOP) ++ field = V4L2_FIELD_INTERLACED_BT; ++ ++ offset |= get_offset_msb(core, i); ++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field); ++ } ++} ++ ++static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 status; ++ u32 size; ++ u8 cmd; ++ ++ status = amvdec_read_dos(core, AV_SCRATCH_0); ++ cmd = status & CMD_MASK; ++ ++ switch (cmd) { ++ case CMD_SRC_CHANGE: ++ codec_h264_src_change(sess); ++ break; ++ case CMD_FRAMES_READY: ++ codec_h264_frames_ready(sess, status); ++ break; ++ case CMD_FATAL_ERROR: ++ dev_err(core->dev, "H.264 decoder fatal error\n"); ++ goto abort; ++ case CMD_BAD_WIDTH: ++ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; ++ dev_err(core->dev, "Unsupported video width: %u\n", size); ++ goto abort; ++ case CMD_BAD_HEIGHT: ++ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; ++ dev_err(core->dev, "Unsupported video height: %u\n", size); ++ goto abort; ++ case 0: /* Unused but not worth printing for */ ++ case 9: ++ break; ++ default: ++ dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd); ++ break; ++ } ++ ++ if (cmd && cmd != CMD_SRC_CHANGE) ++ amvdec_write_dos(core, AV_SCRATCH_0, 0); ++ ++ /* Decoder has some SEI data for us ; ignore */ ++ if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY) ++ amvdec_write_dos(core, AV_SCRATCH_J, 0); ++ ++ return IRQ_HANDLED; ++abort: ++ amvdec_abort(sess); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t codec_h264_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ ++ return IRQ_WAKE_THREAD; ++} ++ ++struct amvdec_codec_ops codec_h264_ops = { ++ .start = codec_h264_start, ++ .stop = codec_h264_stop, ++ .load_extended_firmware = codec_h264_load_extended_firmware, ++ .isr = codec_h264_isr, ++ .threaded_isr = codec_h264_threaded_isr, ++ .can_recycle = codec_h264_can_recycle, ++ .recycle = codec_h264_recycle, ++ .eos_sequence = codec_h264_eos_sequence, ++ .resume = codec_h264_resume, ++}; +diff --git a/drivers/staging/media/meson/vdec/codec_h264.h b/drivers/staging/media/meson/vdec/codec_h264.h +new file mode 100644 +index 000000000000..9211a11b452c +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_h264.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_H264_H_ ++#define __MESON_VDEC_CODEC_H264_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_h264_ops; ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c +index 824dbc7f46f5..579d3e48f0b2 100644 +--- a/drivers/staging/media/meson/vdec/vdec_platform.c ++++ b/drivers/staging/media/meson/vdec/vdec_platform.c +@@ -9,9 +9,20 @@ + + #include "vdec_1.h" + #include "codec_mpeg12.h" ++#include "codec_h264.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/gxbb/vh264_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, +@@ -36,6 +47,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/gxl/vh264_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, +@@ -60,6 +81,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/gxm/vh264_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0119-TEMP-media-meson-vdec-add-MPEG4-decoding-support.patch b/packages/linux/patches/amlogic/amlogic-0119-TEMP-media-meson-vdec-add-MPEG4-decoding-support.patch new file mode 100644 index 0000000000..e4b650d85d --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0119-TEMP-media-meson-vdec-add-MPEG4-decoding-support.patch @@ -0,0 +1,316 @@ +From ed7bca3cf19c099cfefbef039310bed818d98a8c Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 16:01:55 +0200 +Subject: [PATCH 119/186] TEMP: media: meson: vdec: add MPEG4 decoding support + +Add support for V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID and +V4L2_PIX_FMT_H.263 + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/Makefile | 2 +- + .../staging/media/meson/vdec/codec_mpeg4.c | 139 ++++++++++++++++++ + .../staging/media/meson/vdec/codec_mpeg4.h | 13 ++ + .../staging/media/meson/vdec/vdec_platform.c | 91 ++++++++++++ + 4 files changed, 244 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/media/meson/vdec/codec_mpeg4.c + create mode 100644 drivers/staging/media/meson/vdec/codec_mpeg4.h + +diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile +index 711d990c760e..f167a61acb36 100644 +--- a/drivers/staging/media/meson/vdec/Makefile ++++ b/drivers/staging/media/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/staging/media/meson/vdec/codec_mpeg4.c b/drivers/staging/media/meson/vdec/codec_mpeg4.c +new file mode 100644 +index 000000000000..1d574e576112 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_mpeg4.c +@@ -0,0 +1,139 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++#define SIZE_WORKSPACE SZ_1M ++/* Offset added by firmware, to substract from workspace paddr */ ++#define DCAC_BUFF_START_IP 0x02b00000 ++ ++/* map firmware registers to known MPEG4 functions */ ++#define MREG_BUFFERIN AV_SCRATCH_8 ++#define MREG_BUFFEROUT AV_SCRATCH_9 ++#define MP4_NOT_CODED_CNT AV_SCRATCH_A ++#define MP4_OFFSET_REG AV_SCRATCH_C ++#define MEM_OFFSET_REG AV_SCRATCH_F ++#define MREG_FATAL_ERROR AV_SCRATCH_L ++ ++#define BUF_IDX_MASK GENMASK(2, 0) ++#define INTERLACE_FLAG BIT(7) ++#define TOP_FIELD_FIRST_FLAG BIT(6) ++ ++struct codec_mpeg4 { ++ /* Buffer for the MPEG4 Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++}; ++ ++static int codec_mpeg4_can_recycle(struct amvdec_core *core) ++{ ++ return !amvdec_read_dos(core, MREG_BUFFERIN); ++} ++ ++static void codec_mpeg4_recycle(struct amvdec_core *core, u32 buf_idx) ++{ ++ amvdec_write_dos(core, MREG_BUFFERIN, ~BIT(buf_idx)); ++} ++ ++static int codec_mpeg4_start(struct amvdec_session *sess) { ++ struct amvdec_core *core = sess->core; ++ struct codec_mpeg4 *mpeg4 = sess->priv; ++ int ret; ++ ++ mpeg4 = kzalloc(sizeof(*mpeg4), GFP_KERNEL); ++ if (!mpeg4) ++ return -ENOMEM; ++ ++ /* Allocate some memory for the MPEG4 decoder's state */ ++ mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &mpeg4->workspace_paddr, ++ GFP_KERNEL); ++ if (!mpeg4->workspace_vaddr) { ++ dev_err(core->dev, "Failed to request MPEG4 Workspace\n"); ++ ret = -ENOMEM; ++ goto free_mpeg4; ++ } ++ ++ /* Canvas regs: AV_SCRATCH_0-AV_SCRATCH_4;AV_SCRATCH_G-AV_SCRATCH_J */ ++ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, AV_SCRATCH_G, 0 }, ++ (u32[]){ 4, 4, 0 }); ++ ++ amvdec_write_dos(core, MEM_OFFSET_REG, ++ mpeg4->workspace_paddr - DCAC_BUFF_START_IP); ++ amvdec_write_dos(core, PSCALE_CTRL, 0); ++ amvdec_write_dos(core, MP4_NOT_CODED_CNT, 0); ++ amvdec_write_dos(core, MREG_BUFFERIN, 0); ++ amvdec_write_dos(core, MREG_BUFFEROUT, 0); ++ amvdec_write_dos(core, MREG_FATAL_ERROR, 0); ++ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa); ++ ++ sess->keyframe_found = 1; ++ sess->priv = mpeg4; ++ ++ return 0; ++ ++free_mpeg4: ++ kfree(mpeg4); ++ return ret; ++} ++ ++static int codec_mpeg4_stop(struct amvdec_session *sess) ++{ ++ struct codec_mpeg4 *mpeg4 = sess->priv; ++ struct amvdec_core *core = sess->core; ++ ++ if (mpeg4->workspace_vaddr) { ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ mpeg4->workspace_vaddr, ++ mpeg4->workspace_paddr); ++ mpeg4->workspace_vaddr = 0; ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t codec_mpeg4_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 reg; ++ u32 buffer_index; ++ u32 field = V4L2_FIELD_NONE; ++ ++ reg = amvdec_read_dos(core, MREG_FATAL_ERROR); ++ if (reg == 1) { ++ dev_err(core->dev, "mpeg4 fatal error\n"); ++ amvdec_abort(sess); ++ return IRQ_HANDLED; ++ } ++ ++ reg = amvdec_read_dos(core, MREG_BUFFEROUT); ++ if (!reg) ++ goto end; ++ ++ buffer_index = reg & BUF_IDX_MASK; ++ if (reg & INTERLACE_FLAG) ++ field = (reg & TOP_FIELD_FIRST_FLAG) ? ++ V4L2_FIELD_INTERLACED_TB : ++ V4L2_FIELD_INTERLACED_BT; ++ ++ amvdec_dst_buf_done_idx(sess, buffer_index, -1, field); ++ amvdec_write_dos(core, MREG_BUFFEROUT, 0); ++ ++end: ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ return IRQ_HANDLED; ++} ++ ++struct amvdec_codec_ops codec_mpeg4_ops = { ++ .start = codec_mpeg4_start, ++ .stop = codec_mpeg4_stop, ++ .isr = codec_mpeg4_isr, ++ .can_recycle = codec_mpeg4_can_recycle, ++ .recycle = codec_mpeg4_recycle, ++}; +diff --git a/drivers/staging/media/meson/vdec/codec_mpeg4.h b/drivers/staging/media/meson/vdec/codec_mpeg4.h +new file mode 100644 +index 000000000000..8dcdcc51fad4 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_mpeg4.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_MPEG4_H_ ++#define __MESON_VDEC_CODEC_MPEG4_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_mpeg4_ops; ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c +index 579d3e48f0b2..be307bf5bccd 100644 +--- a/drivers/staging/media/meson/vdec/vdec_platform.c ++++ b/drivers/staging/media/meson/vdec/vdec_platform.c +@@ -10,9 +10,40 @@ + #include "vdec_1.h" + #include "codec_mpeg12.h" + #include "codec_h264.h" ++#include "codec_mpeg4.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/h263_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_H264, + .min_buffers = 2, + .max_buffers = 24, +@@ -47,6 +78,36 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/h263_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_H264, + .min_buffers = 2, + .max_buffers = 24, +@@ -81,6 +142,36 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/h263_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_H264, + .min_buffers = 2, + .max_buffers = 24, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0120-TEMP-media-meson-vdec-add-MJPEG-decoding-support.patch b/packages/linux/patches/amlogic/amlogic-0120-TEMP-media-meson-vdec-add-MJPEG-decoding-support.patch new file mode 100644 index 0000000000..d63de2f6d0 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0120-TEMP-media-meson-vdec-add-MJPEG-decoding-support.patch @@ -0,0 +1,256 @@ +From 0966bbfd430f66f545055606e407ebfaeb8d31c1 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Sun, 21 Oct 2018 15:14:27 +0200 +Subject: [PATCH 120/186] TEMP: media: meson: vdec: add MJPEG decoding support + +Add support for V4L2_PIX_FMT_MJPEG + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/Makefile | 2 +- + .../staging/media/meson/vdec/codec_mjpeg.c | 140 ++++++++++++++++++ + .../staging/media/meson/vdec/codec_mjpeg.h | 13 ++ + .../staging/media/meson/vdec/vdec_platform.c | 31 ++++ + 4 files changed, 185 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/media/meson/vdec/codec_mjpeg.c + create mode 100644 drivers/staging/media/meson/vdec/codec_mjpeg.h + +diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile +index f167a61acb36..20c23f9015eb 100644 +--- a/drivers/staging/media/meson/vdec/Makefile ++++ b/drivers/staging/media/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/staging/media/meson/vdec/codec_mjpeg.c b/drivers/staging/media/meson/vdec/codec_mjpeg.c +new file mode 100644 +index 000000000000..abea9e3f944c +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_mjpeg.c +@@ -0,0 +1,140 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++/* map FW registers to known MJPEG functions */ ++#define MREG_DECODE_PARAM AV_SCRATCH_2 ++#define MREG_TO_AMRISC AV_SCRATCH_8 ++#define MREG_FROM_AMRISC AV_SCRATCH_9 ++#define MREG_FRAME_OFFSET AV_SCRATCH_A ++ ++static int codec_mjpeg_can_recycle(struct amvdec_core *core) ++{ ++ return !amvdec_read_dos(core, MREG_TO_AMRISC); ++} ++ ++static void codec_mjpeg_recycle(struct amvdec_core *core, u32 buf_idx) ++{ ++ amvdec_write_dos(core, MREG_TO_AMRISC, buf_idx + 1); ++} ++ ++/* 4 point triangle */ ++static const uint32_t filt_coef[] = { ++ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101, ++ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303, ++ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505, ++ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707, ++ 0x18382808, 0x18382808, 0x17372909, 0x17372909, ++ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b, ++ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d, ++ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f, ++ 0x10303010 ++}; ++ ++static void codec_mjpeg_init_scaler(struct amvdec_core *core) ++{ ++ int i; ++ ++ /* PSCALE cbus bmem enable */ ++ amvdec_write_dos(core, PSCALE_CTRL, 0xc000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 0); ++ for (i = 0; i < ARRAY_SIZE(filt_coef); ++i) { ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, filt_coef[i]); ++ } ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 74); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 82); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 78); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 86); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 73); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 81); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 77); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 85); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ ++ amvdec_write_dos(core, PSCALE_RST, 0x7); ++ amvdec_write_dos(core, PSCALE_RST, 0); ++} ++ ++static int codec_mjpeg_start(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ amvdec_write_dos(core, AV_SCRATCH_0, 12); ++ amvdec_write_dos(core, AV_SCRATCH_1, 0x031a); ++ ++ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_4, 0 }, ++ (u32[]){ 4, 0 }); ++ codec_mjpeg_init_scaler(core); ++ ++ amvdec_write_dos(core, MREG_TO_AMRISC, 0); ++ amvdec_write_dos(core, MREG_FROM_AMRISC, 0); ++ amvdec_write_dos(core, MCPU_INTR_MSK, 0xffff); ++ amvdec_write_dos(core, MREG_DECODE_PARAM, ++ (sess->height << 4) | 0x8000); ++ amvdec_write_dos(core, VDEC_ASSIST_AMR1_INT8, 8); ++ ++ /* Intra-only codec */ ++ sess->keyframe_found = 1; ++ ++ return 0; ++} ++ ++static int codec_mjpeg_stop(struct amvdec_session *sess) ++{ ++ return 0; ++} ++ ++static irqreturn_t codec_mjpeg_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 reg; ++ u32 buffer_index; ++ u32 offset; ++ ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ ++ reg = amvdec_read_dos(core, MREG_FROM_AMRISC); ++ if (!(reg & 0x7)) ++ return IRQ_HANDLED; ++ ++ buffer_index = ((reg & 0x7) - 1) & 3; ++ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET); ++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, V4L2_FIELD_NONE); ++ ++ amvdec_write_dos(core, MREG_FROM_AMRISC, 0); ++ return IRQ_HANDLED; ++} ++ ++struct amvdec_codec_ops codec_mjpeg_ops = { ++ .start = codec_mjpeg_start, ++ .stop = codec_mjpeg_stop, ++ .isr = codec_mjpeg_isr, ++ .can_recycle = codec_mjpeg_can_recycle, ++ .recycle = codec_mjpeg_recycle, ++}; +diff --git a/drivers/staging/media/meson/vdec/codec_mjpeg.h b/drivers/staging/media/meson/vdec/codec_mjpeg.h +new file mode 100644 +index 000000000000..364fa7ee6d9e +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_mjpeg.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_MJPEG_H_ ++#define __MESON_VDEC_CODEC_MJPEG_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_mjpeg_ops; ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c +index be307bf5bccd..fb714d74753f 100644 +--- a/drivers/staging/media/meson/vdec/vdec_platform.c ++++ b/drivers/staging/media/meson/vdec/vdec_platform.c +@@ -11,9 +11,20 @@ + #include "codec_mpeg12.h" + #include "codec_h264.h" + #include "codec_mpeg4.h" ++#include "codec_mjpeg.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/gx/vmjpeg_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .min_buffers = 8, + .max_buffers = 8, +@@ -78,6 +89,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/gx/vmjpeg_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .min_buffers = 8, + .max_buffers = 8, +@@ -142,6 +163,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/gx/vmjpeg_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .min_buffers = 8, + .max_buffers = 8, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0121-TEMP-media-videodev2.h-Add-Amlogic-compressed-format.patch b/packages/linux/patches/amlogic/amlogic-0121-TEMP-media-videodev2.h-Add-Amlogic-compressed-format.patch new file mode 100644 index 0000000000..ab38aee30b --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0121-TEMP-media-videodev2.h-Add-Amlogic-compressed-format.patch @@ -0,0 +1,45 @@ +From 6d6d12fac85ceaa771f41beeaa8031230fb0f6e0 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Sun, 21 Oct 2018 15:14:49 +0200 +Subject: [PATCH 121/186] TEMP: media: videodev2.h: Add Amlogic compressed + format + +Add V4L2_PIX_FMT_AM21C which is a lossless, compressed framebuffer +format. + +It is used by the video decoding and the display IP on many Amlogic +SoCs. + +Signed-off-by: Maxime Jourdan +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 1 + + include/uapi/linux/videodev2.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index b1f4b991dba6..74abce874fe8 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1355,6 +1355,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; + case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; + case V4L2_PIX_FMT_SUNXI_TILED_NV12: descr = "Sunxi Tiled NV12 Format"; break; ++ case V4L2_PIX_FMT_AM21C: descr = "Amlogic Compressed Format"; break; + default: + if (fmt->description[0]) + return; +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index 2427bc4d8eba..1e1ae481e42e 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -724,6 +724,7 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */ + #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ + #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ ++#define V4L2_PIX_FMT_AM21C v4l2_fourcc('A', 'M', '2', '1') /* Amlogic compressed block mode */ + #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ + #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ + #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0122-TEMP-media-meson-vdec-add-support-for-V4L2_PIX_FMT_A.patch b/packages/linux/patches/amlogic/amlogic-0122-TEMP-media-meson-vdec-add-support-for-V4L2_PIX_FMT_A.patch new file mode 100644 index 0000000000..f27127e962 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0122-TEMP-media-meson-vdec-add-support-for-V4L2_PIX_FMT_A.patch @@ -0,0 +1,126 @@ +From 17645614a47cdc65352ed4db5c37c393fb851860 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Sun, 21 Oct 2018 15:15:26 +0200 +Subject: [PATCH 122/186] TEMP: media: meson: vdec: add support for + V4L2_PIX_FMT_AM21C + +Support the lossless framebuffer compression format. + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/vdec.c | 12 +++++++ + .../staging/media/meson/vdec/vdec_helpers.c | 31 +++++++++++++++++++ + .../staging/media/meson/vdec/vdec_helpers.h | 4 +++ + 3 files changed, 47 insertions(+) + +diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c +index 0a1a04fd5d13..c3415db2b15b 100644 +--- a/drivers/staging/media/meson/vdec/vdec.c ++++ b/drivers/staging/media/meson/vdec/vdec.c +@@ -187,6 +187,7 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + { + struct amvdec_session *sess = vb2_get_drv_priv(q); + u32 output_size = amvdec_get_output_size(sess); ++ u32 am21c_size = amvdec_am21c_size(sess->width, sess->height); + + if (*num_planes) { + switch (q->type) { +@@ -209,6 +210,10 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + sizes[2] < output_size / 4) + return -EINVAL; + break; ++ case V4L2_PIX_FMT_AM21C: ++ if (*num_planes != 1 || sizes[0] < am21c_size) ++ return -EINVAL; ++ break; + default: + return -EINVAL; + } +@@ -238,6 +243,9 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + sizes[2] = output_size / 4; + *num_planes = 3; + break; ++ case V4L2_PIX_FMT_AM21C: ++ sizes[0] = am21c_size; ++ *num_planes = 1; + default: + return -EINVAL; + } +@@ -518,6 +526,10 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size, + get_output_size(pixmp->width, pixmp->height) / 4; + pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2; + pixmp->num_planes = 3; ++ } else if (pixmp->pixelformat == V4L2_PIX_FMT_AM21C) { ++ pfmt[0].sizeimage = ++ amvdec_am21c_size(pixmp->width, pixmp->height); ++ pfmt[0].bytesperline = 0; + } + } else { + return NULL; +diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c +index f16948bdbf2f..2b554f21e3c1 100644 +--- a/drivers/staging/media/meson/vdec/vdec_helpers.c ++++ b/drivers/staging/media/meson/vdec/vdec_helpers.c +@@ -50,6 +50,33 @@ void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val) + } + EXPORT_SYMBOL_GPL(amvdec_write_parser); + ++/* 4 KiB per 64x32 block */ ++u32 amvdec_am21c_body_size(u32 width, u32 height) ++{ ++ u32 width_64 = ALIGN(width, 64) / 64; ++ u32 height_32 = ALIGN(height, 32) / 32; ++ ++ return SZ_4K * width_64 * height_32; ++} ++EXPORT_SYMBOL_GPL(amvdec_am21c_body_size); ++ ++/* 32 bytes per 128x64 block */ ++u32 amvdec_am21c_head_size(u32 width, u32 height) ++{ ++ u32 width_128 = ALIGN(width, 128) / 128; ++ u32 height_64 = ALIGN(height, 64) / 64; ++ ++ return 32 * width_128 * height_64; ++} ++EXPORT_SYMBOL_GPL(amvdec_am21c_head_size); ++ ++u32 amvdec_am21c_size(u32 width, u32 height) ++{ ++ return ALIGN(amvdec_am21c_body_size(width, height) + ++ amvdec_am21c_head_size(width, height), SZ_64K); ++} ++EXPORT_SYMBOL_GPL(amvdec_am21c_size); ++ + static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id) + { + int ret; +@@ -267,6 +294,10 @@ static void dst_buf_done(struct amvdec_session *sess, + vbuf->vb2_buf.planes[1].bytesused = output_size / 4; + vbuf->vb2_buf.planes[2].bytesused = output_size / 4; + break; ++ case V4L2_PIX_FMT_AM21C: ++ vbuf->vb2_buf.planes[0].bytesused = ++ amvdec_am21c_size(sess->width, sess->height); ++ break; + } + + vbuf->vb2_buf.timestamp = timestamp; +diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h +index a455a9ee1cc2..94d2c1ecfe14 100644 +--- a/drivers/staging/media/meson/vdec/vdec_helpers.h ++++ b/drivers/staging/media/meson/vdec/vdec_helpers.h +@@ -27,6 +27,10 @@ void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val); + u32 amvdec_read_parser(struct amvdec_core *core, u32 reg); + void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val); + ++u32 amvdec_am21c_body_size(u32 width, u32 height); ++u32 amvdec_am21c_head_size(u32 width, u32 height); ++u32 amvdec_am21c_size(u32 width, u32 height); ++ + /** + * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding + * +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0123-TEMP-media-meson-vdec-add-HEVC-decoding-support.patch b/packages/linux/patches/amlogic/amlogic-0123-TEMP-media-meson-vdec-add-HEVC-decoding-support.patch new file mode 100644 index 0000000000..5eb6cf60f9 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0123-TEMP-media-meson-vdec-add-HEVC-decoding-support.patch @@ -0,0 +1,2202 @@ +From 60e6b0cec5d7f041113d568b9a84d33802a98a65 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 18:48:35 +0200 +Subject: [PATCH 123/186] TEMP: media: meson: vdec: add HEVC decoding support + +Add support for V4L2_PIX_FMT_HEVC + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/Makefile | 4 +- + drivers/staging/media/meson/vdec/codec_hevc.c | 1357 +++++++++++++++++ + drivers/staging/media/meson/vdec/codec_hevc.h | 13 + + .../media/meson/vdec/codec_hevc_common.c | 188 +++ + .../media/meson/vdec/codec_hevc_common.h | 49 + + drivers/staging/media/meson/vdec/hevc_regs.h | 205 +++ + drivers/staging/media/meson/vdec/vdec.h | 7 +- + drivers/staging/media/meson/vdec/vdec_hevc.c | 191 +++ + drivers/staging/media/meson/vdec/vdec_hevc.h | 22 + + .../staging/media/meson/vdec/vdec_platform.c | 32 + + 10 files changed, 2065 insertions(+), 3 deletions(-) + create mode 100644 drivers/staging/media/meson/vdec/codec_hevc.c + create mode 100644 drivers/staging/media/meson/vdec/codec_hevc.h + create mode 100644 drivers/staging/media/meson/vdec/codec_hevc_common.c + create mode 100644 drivers/staging/media/meson/vdec/codec_hevc_common.h + create mode 100644 drivers/staging/media/meson/vdec/hevc_regs.h + create mode 100644 drivers/staging/media/meson/vdec/vdec_hevc.c + create mode 100644 drivers/staging/media/meson/vdec/vdec_hevc.h + +diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile +index 20c23f9015eb..900dde088da0 100644 +--- a/drivers/staging/media/meson/vdec/Makefile ++++ b/drivers/staging/media/meson/vdec/Makefile +@@ -2,7 +2,7 @@ + # Makefile for Amlogic meson video decoder driver + + meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o +-meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o ++meson-vdec-objs += vdec_1.o vdec_hevc.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/staging/media/meson/vdec/codec_hevc.c b/drivers/staging/media/meson/vdec/codec_hevc.c +new file mode 100644 +index 000000000000..03f00f969f02 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_hevc.c +@@ -0,0 +1,1357 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. ++ */ ++ ++#include ++#include ++ ++#include "codec_hevc.h" ++#include "dos_regs.h" ++#include "hevc_regs.h" ++#include "vdec_helpers.h" ++#include "codec_hevc_common.h" ++ ++/* HEVC reg mapping */ ++#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 ++ #define HEVC_ACTION_DONE 0xff ++#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 ++#define HEVC_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2 ++#define HEVC_VPS_BUFFER HEVC_ASSIST_SCRATCH_3 ++#define HEVC_SPS_BUFFER HEVC_ASSIST_SCRATCH_4 ++#define HEVC_PPS_BUFFER HEVC_ASSIST_SCRATCH_5 ++#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6 ++#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 ++#define H265_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7 ++#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 ++#define HEVC_sao_mem_unit HEVC_ASSIST_SCRATCH_9 ++#define HEVC_SAO_ABV HEVC_ASSIST_SCRATCH_A ++#define HEVC_sao_vb_size HEVC_ASSIST_SCRATCH_B ++#define HEVC_SAO_VB HEVC_ASSIST_SCRATCH_C ++#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D ++#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E ++#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F ++#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F ++#define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G ++#define HEVC_DECODE_MODE2 HEVC_ASSIST_SCRATCH_H ++#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I ++#define HEVC_DECODE_MODE HEVC_ASSIST_SCRATCH_J ++ #define DECODE_MODE_SINGLE 0 ++#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K ++#define HEVC_AUX_ADR HEVC_ASSIST_SCRATCH_L ++#define HEVC_AUX_DATA_SIZE HEVC_ASSIST_SCRATCH_M ++#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N ++ ++#define AMRISC_MAIN_REQ 0x04 ++ ++/* HEVC Constants */ ++#define MAX_REF_PIC_NUM 24 ++#define MAX_REF_ACTIVE 16 ++#define MAX_TILE_COL_NUM 10 ++#define MAX_TILE_ROW_NUM 20 ++#define MAX_SLICE_NUM 800 ++#define INVALID_POC 0x80000000 ++ ++/* HEVC Workspace layout */ ++#define MPRED_MV_BUF_SIZE 0x120000 ++ ++#define IPP_SIZE 0x4000 ++#define SAO_ABV_SIZE 0x30000 ++#define SAO_VB_SIZE 0x30000 ++#define SH_TM_RPS_SIZE 0x800 ++#define VPS_SIZE 0x800 ++#define SPS_SIZE 0x800 ++#define PPS_SIZE 0x2000 ++#define SAO_UP_SIZE 0x2800 ++#define SWAP_BUF_SIZE 0x800 ++#define SWAP_BUF2_SIZE 0x800 ++#define SCALELUT_SIZE 0x8000 ++#define DBLK_PARA_SIZE 0x20000 ++#define DBLK_DATA_SIZE 0x40000 ++#define MMU_VBH_SIZE 0x5000 ++#define MPRED_ABV_SIZE 0x8000 ++#define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) ++#define RPM_BUF_SIZE 0x100 ++#define LMEM_SIZE 0xA00 ++ ++#define IPP_OFFSET 0x00 ++#define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) ++#define SAO_VB_OFFSET (SAO_ABV_OFFSET + SAO_ABV_SIZE) ++#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + SAO_VB_SIZE) ++#define VPS_OFFSET (SH_TM_RPS_OFFSET + SH_TM_RPS_SIZE) ++#define SPS_OFFSET (VPS_OFFSET + VPS_SIZE) ++#define PPS_OFFSET (SPS_OFFSET + SPS_SIZE) ++#define SAO_UP_OFFSET (PPS_OFFSET + PPS_SIZE) ++#define SWAP_BUF_OFFSET (SAO_UP_OFFSET + SAO_UP_SIZE) ++#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + SWAP_BUF_SIZE) ++#define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) ++#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) ++#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) ++#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) ++#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) ++#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) ++#define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) ++ ++/* ISR decode status */ ++#define HEVC_DEC_IDLE 0x0 ++#define HEVC_NAL_UNIT_VPS 0x1 ++#define HEVC_NAL_UNIT_SPS 0x2 ++#define HEVC_NAL_UNIT_PPS 0x3 ++#define HEVC_NAL_UNIT_CODED_SLICE_SEGMENT 0x4 ++#define HEVC_CODED_SLICE_SEGMENT_DAT 0x5 ++#define HEVC_SLICE_DECODING 0x6 ++#define HEVC_NAL_UNIT_SEI 0x7 ++#define HEVC_SLICE_SEGMENT_DONE 0x8 ++#define HEVC_NAL_SEARCH_DONE 0x9 ++#define HEVC_DECPIC_DATA_DONE 0xa ++#define HEVC_DECPIC_DATA_ERROR 0xb ++#define HEVC_SEI_DAT 0xc ++#define HEVC_SEI_DAT_DONE 0xd ++ ++/* RPM misc_flag0 */ ++#define PCM_LOOP_FILTER_DISABLED_FLAG_BIT 0 ++#define PCM_ENABLE_FLAG_BIT 1 ++#define LOOP_FILER_ACROSS_TILES_ENABLED_FLAG_BIT 2 ++#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 3 ++#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT 4 ++#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 5 ++#define DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT 6 ++#define SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 7 ++#define SLICE_SAO_LUMA_FLAG_BIT 8 ++#define SLICE_SAO_CHROMA_FLAG_BIT 9 ++#define SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 10 ++ ++/* Constants for HEVC_MPRED_CTRL1 */ ++#define AMVP_MAX_NUM_CANDS_MEM 3 ++#define AMVP_MAX_NUM_CANDS 2 ++#define NUM_CHROMA_MODE 5 ++#define DM_CHROMA_IDX 36 ++ ++/* Buffer sizes */ ++#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + LMEM_SIZE, 64 * SZ_1K) ++#define SIZE_AUX (SZ_1K * 16) ++#define SIZE_FRAME_MMU (0x1200 * 4) ++#define RPM_SIZE 0x80 ++#define RPS_USED_BIT 14 ++ ++/* Data received from the HW in this form, do not rearrange */ ++union rpm_param { ++ struct { ++ u16 data[RPM_SIZE]; ++ } l; ++ struct { ++ u16 CUR_RPS[MAX_REF_ACTIVE]; ++ u16 num_ref_idx_l0_active; ++ u16 num_ref_idx_l1_active; ++ u16 slice_type; ++ u16 slice_temporal_mvp_enable_flag; ++ u16 dependent_slice_segment_flag; ++ u16 slice_segment_address; ++ u16 num_title_rows_minus1; ++ u16 pic_width_in_luma_samples; ++ u16 pic_height_in_luma_samples; ++ u16 log2_min_coding_block_size_minus3; ++ u16 log2_diff_max_min_coding_block_size; ++ u16 log2_max_pic_order_cnt_lsb_minus4; ++ u16 POClsb; ++ u16 collocated_from_l0_flag; ++ u16 collocated_ref_idx; ++ u16 log2_parallel_merge_level; ++ u16 five_minus_max_num_merge_cand; ++ u16 sps_num_reorder_pics_0; ++ u16 modification_flag; ++ u16 tiles_flags; ++ u16 num_tile_columns_minus1; ++ u16 num_tile_rows_minus1; ++ u16 tile_width[8]; ++ u16 tile_height[8]; ++ u16 misc_flag0; ++ u16 pps_beta_offset_div2; ++ u16 pps_tc_offset_div2; ++ u16 slice_beta_offset_div2; ++ u16 slice_tc_offset_div2; ++ u16 pps_cb_qp_offset; ++ u16 pps_cr_qp_offset; ++ u16 first_slice_segment_in_pic_flag; ++ u16 m_temporalId; ++ u16 m_nalUnitType; ++ u16 vui_num_units_in_tick_hi; ++ u16 vui_num_units_in_tick_lo; ++ u16 vui_time_scale_hi; ++ u16 vui_time_scale_lo; ++ u16 bit_depth; ++ u16 profile_etc; ++ u16 sei_frame_field_info; ++ u16 video_signal_type; ++ u16 modification_list[0x20]; ++ u16 conformance_window_flag; ++ u16 conf_win_left_offset; ++ u16 conf_win_right_offset; ++ u16 conf_win_top_offset; ++ u16 conf_win_bottom_offset; ++ u16 chroma_format_idc; ++ u16 color_description; ++ u16 aspect_ratio_idc; ++ u16 sar_width; ++ u16 sar_height; ++ } p; ++}; ++ ++enum nal_unit_type { ++ NAL_UNIT_CODED_SLICE_BLA = 16, ++ NAL_UNIT_CODED_SLICE_BLANT = 17, ++ NAL_UNIT_CODED_SLICE_BLA_N_LP = 18, ++ NAL_UNIT_CODED_SLICE_IDR = 19, ++ NAL_UNIT_CODED_SLICE_IDR_N_LP = 20, ++}; ++ ++enum slice_type { ++ B_SLICE = 0, ++ P_SLICE = 1, ++ I_SLICE = 2, ++}; ++ ++/* A frame being decoded */ ++struct hevc_frame { ++ struct list_head list; ++ struct vb2_v4l2_buffer *vbuf; ++ u32 offset; ++ u32 poc; ++ ++ int referenced; ++ u32 num_reorder_pic; ++ ++ u32 cur_slice_idx; ++ u32 cur_slice_type; ++ ++ /* 2 lists (L0/L1) ; 800 slices ; 16 refs */ ++ u32 ref_poc_list[2][MAX_SLICE_NUM][MAX_REF_ACTIVE]; ++ u32 ref_num[2]; ++}; ++ ++struct codec_hevc { ++ struct mutex lock; ++ ++ /* Buffer for the HEVC Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++ ++ /* AUX buffer */ ++ void *aux_vaddr; ++ dma_addr_t aux_paddr; ++ ++ /* Contains many information parsed from the bitstream */ ++ union rpm_param rpm_param; ++ ++ /* Information computed from the RPM */ ++ u32 lcu_size; // Largest Coding Unit ++ u32 lcu_x_num; ++ u32 lcu_y_num; ++ u32 lcu_total; ++ ++ /* Current Frame being handled */ ++ struct hevc_frame *cur_frame; ++ u32 curr_poc; ++ /* Collocated Reference Picture */ ++ struct hevc_frame *col_frame; ++ u32 col_poc; ++ ++ /* All ref frames used by the HW at a given time */ ++ struct list_head ref_frames_list; ++ u32 frames_num; ++ ++ /* Coded resolution reported by the hardware */ ++ u32 width, height; ++ /* Resolution minus the conformance window offsets */ ++ u32 dst_width, dst_height; ++ ++ u32 prev_tid0_poc; ++ u32 slice_segment_addr; ++ u32 slice_addr; ++ u32 ldc_flag; ++ ++ /* Whether we detected the bitstream as 10-bit */ ++ int is_10bit; ++}; ++ ++static u32 codec_hevc_num_pending_bufs(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc; ++ u32 ret; ++ ++ hevc = sess->priv; ++ if (!hevc) ++ return 0; ++ ++ mutex_lock(&hevc->lock); ++ ret = hevc->frames_num; ++ mutex_unlock(&hevc->lock); ++ ++ return ret; ++} ++ ++/* Update the L0 and L1 reference lists for a given frame */ ++static void codec_hevc_update_frame_refs(struct amvdec_session *sess, struct hevc_frame *frame) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *params = &hevc->rpm_param; ++ int i; ++ int num_neg = 0; ++ int num_pos = 0; ++ int total_num; ++ int num_ref_idx_l0_active = ++ (params->p.num_ref_idx_l0_active > MAX_REF_ACTIVE) ? ++ MAX_REF_ACTIVE : params->p.num_ref_idx_l0_active; ++ int num_ref_idx_l1_active = ++ (params->p.num_ref_idx_l1_active > MAX_REF_ACTIVE) ? ++ MAX_REF_ACTIVE : params->p.num_ref_idx_l1_active; ++ int ref_picset0[MAX_REF_ACTIVE] = { 0 }; ++ int ref_picset1[MAX_REF_ACTIVE] = { 0 }; ++ ++ for (i = 0; i < MAX_REF_ACTIVE; i++) { ++ frame->ref_poc_list[0][frame->cur_slice_idx][i] = 0; ++ frame->ref_poc_list[1][frame->cur_slice_idx][i] = 0; ++ } ++ ++ for (i = 0; i < MAX_REF_ACTIVE; i++) { ++ u16 cur_rps = params->p.CUR_RPS[i]; ++ int delt = cur_rps & ((1 << (RPS_USED_BIT - 1)) - 1); ++ ++ if (cur_rps & 0x8000) ++ break; ++ ++ if (!((cur_rps >> RPS_USED_BIT) & 1)) ++ continue; ++ ++ if ((cur_rps >> (RPS_USED_BIT - 1)) & 1) { ++ ref_picset0[num_neg] = ++ frame->poc - ((1 << (RPS_USED_BIT - 1)) - delt); ++ num_neg++; ++ } else { ++ ref_picset1[num_pos] = frame->poc + delt; ++ num_pos++; ++ } ++ } ++ ++ total_num = num_neg + num_pos; ++ ++ if (total_num <= 0) ++ goto end; ++ ++ for (i = 0; i < num_ref_idx_l0_active; i++) { ++ int cidx; ++ if (params->p.modification_flag & 0x1) ++ cidx = params->p.modification_list[i]; ++ else ++ cidx = i % total_num; ++ ++ frame->ref_poc_list[0][frame->cur_slice_idx][i] = ++ cidx >= num_neg ? ref_picset1[cidx - num_neg] : ++ ref_picset0[cidx]; ++ } ++ ++ if (params->p.slice_type != B_SLICE) ++ goto end; ++ ++ if (params->p.modification_flag & 0x2) { ++ for (i = 0; i < num_ref_idx_l1_active; i++) { ++ int cidx; ++ if (params->p.modification_flag & 0x1) ++ cidx = ++ params->p.modification_list[num_ref_idx_l0_active + i]; ++ else ++ cidx = params->p.modification_list[i]; ++ ++ frame->ref_poc_list[1][frame->cur_slice_idx][i] = ++ (cidx >= num_pos) ? ref_picset0[cidx - num_pos] ++ : ref_picset1[cidx]; ++ } ++ } else { ++ for (i = 0; i < num_ref_idx_l1_active; i++) { ++ int cidx = i % total_num; ++ frame->ref_poc_list[1][frame->cur_slice_idx][i] = ++ cidx >= num_pos ? ref_picset0[cidx - num_pos] : ++ ref_picset1[cidx]; ++ } ++ } ++ ++end: ++ frame->ref_num[0] = num_ref_idx_l0_active; ++ frame->ref_num[1] = num_ref_idx_l1_active; ++ ++ dev_dbg(sess->core->dev, ++ "Frame %u; slice %u; slice_type %u; num_l0 %u; num_l1 %u\n", ++ frame->poc, frame->cur_slice_idx, params->p.slice_type, ++ frame->ref_num[0], frame->ref_num[1]); ++} ++ ++static void codec_hevc_update_ldc_flag(struct codec_hevc *hevc) ++{ ++ struct hevc_frame *frame = hevc->cur_frame; ++ u32 slice_type = frame->cur_slice_type; ++ u32 slice_idx = frame->cur_slice_idx; ++ int i; ++ ++ hevc->ldc_flag = 0; ++ ++ if (slice_type == I_SLICE) ++ return; ++ ++ hevc->ldc_flag = 1; ++ for (i = 0; (i < frame->ref_num[0]) && hevc->ldc_flag; i++) { ++ if (frame->ref_poc_list[0][slice_idx][i] > frame->poc) { ++ hevc->ldc_flag = 0; ++ break; ++ } ++ } ++ ++ if (slice_type == P_SLICE) ++ return; ++ ++ for (i = 0; (i < frame->ref_num[1]) && hevc->ldc_flag; i++) { ++ if (frame->ref_poc_list[1][slice_idx][i] > frame->poc) { ++ hevc->ldc_flag = 0; ++ break; ++ } ++ } ++} ++ ++/* Tag "old" frames that are no longer referenced */ ++static void codec_hevc_update_referenced(struct codec_hevc *hevc) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ struct hevc_frame *frame; ++ int i; ++ u32 curr_poc = hevc->curr_poc; ++ ++ list_for_each_entry(frame, &hevc->ref_frames_list, list) { ++ int is_referenced = 0; ++ u32 poc_tmp; ++ ++ if (!frame->referenced) ++ continue; ++ ++ for (i = 0; i < MAX_REF_ACTIVE; i++) { ++ int delt; ++ if (param->p.CUR_RPS[i] & 0x8000) ++ break; ++ ++ delt = param->p.CUR_RPS[i] & ((1 << (RPS_USED_BIT - 1)) - 1); ++ if (param->p.CUR_RPS[i] & (1 << (RPS_USED_BIT - 1))) { ++ poc_tmp = curr_poc - ((1 << (RPS_USED_BIT - 1)) - delt); ++ } else ++ poc_tmp = curr_poc + delt; ++ if (poc_tmp == frame->poc) { ++ is_referenced = 1; ++ break; ++ } ++ } ++ ++ frame->referenced = is_referenced; ++ } ++} ++ ++static struct hevc_frame * ++codec_hevc_get_lowest_poc_frame(struct codec_hevc *hevc) ++{ ++ struct hevc_frame *tmp, *ret = NULL; ++ u32 poc = INT_MAX; ++ ++ list_for_each_entry(tmp, &hevc->ref_frames_list, list) { ++ if (tmp->poc < poc) { ++ ret = tmp; ++ poc = tmp->poc; ++ } ++ } ++ ++ return ret; ++} ++ ++/* Try to output as many frames as possible */ ++static void codec_hevc_output_frames(struct amvdec_session *sess) ++{ ++ struct hevc_frame *tmp; ++ struct codec_hevc *hevc = sess->priv; ++ ++ while ((tmp = codec_hevc_get_lowest_poc_frame(hevc))) { ++ if (hevc->curr_poc && ++ (tmp->referenced || ++ tmp->num_reorder_pic >= hevc->frames_num)) ++ break; ++ ++ dev_dbg(sess->core->dev, "DONE frame poc %u; vbuf %u\n", ++ tmp->poc, tmp->vbuf->vb2_buf.index); ++ amvdec_dst_buf_done_offset(sess, tmp->vbuf, tmp->offset, ++ V4L2_FIELD_NONE, false); ++ list_del(&tmp->list); ++ kfree(tmp); ++ hevc->frames_num--; ++ } ++} ++ ++ ++static int ++codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) ++{ ++ dma_addr_t wkaddr; ++ ++ /* Allocate some memory for the HEVC decoder's state */ ++ hevc->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &wkaddr, GFP_KERNEL); ++ if (!hevc->workspace_vaddr) { ++ dev_err(core->dev, "Failed to allocate HEVC Workspace\n"); ++ return -ENOMEM; ++ } ++ ++ hevc->workspace_paddr = wkaddr; ++ ++ amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); ++ amvdec_write_dos(core, HEVC_RPM_BUFFER, wkaddr + RPM_OFFSET); ++ amvdec_write_dos(core, HEVC_SHORT_TERM_RPS, wkaddr + SH_TM_RPS_OFFSET); ++ amvdec_write_dos(core, HEVC_VPS_BUFFER, wkaddr + VPS_OFFSET); ++ amvdec_write_dos(core, HEVC_SPS_BUFFER, wkaddr + SPS_OFFSET); ++ amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET); ++ amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET); ++ ++ /* No MMU */ ++ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, ++ wkaddr + SWAP_BUF_OFFSET); ++ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, ++ wkaddr + SWAP_BUF2_OFFSET); ++ amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); ++ ++ return 0; ++} ++ ++static int codec_hevc_start(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc; ++ u32 val; ++ int i; ++ int ret; ++ ++ hevc = kzalloc(sizeof(*hevc), GFP_KERNEL); ++ if (!hevc) ++ return -ENOMEM; ++ ++ INIT_LIST_HEAD(&hevc->ref_frames_list); ++ hevc->curr_poc = INVALID_POC; ++ ++ ret = codec_hevc_setup_workspace(core, hevc); ++ if (ret) ++ goto free_hevc; ++ ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ ++ val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; ++ val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | ++ BIT(0); ++ amvdec_write_dos(core, HEVC_PARSER_INT_CONTROL, val); ++ amvdec_write_dos_bits(core, HEVC_SHIFT_STATUS, BIT(1) | BIT(0)); ++ amvdec_write_dos(core, HEVC_SHIFT_CONTROL, ++ (3 << 6) | BIT(5) | BIT(2) | BIT(0)); ++ amvdec_write_dos(core, HEVC_CABAC_CONTROL, 1); ++ amvdec_write_dos(core, HEVC_PARSER_CORE_CONTROL, 1); ++ amvdec_write_dos(core, HEVC_DEC_STATUS_REG, 0); ++ ++ amvdec_write_dos(core, HEVC_IQIT_SCALELUT_WR_ADDR, 0); ++ for (i = 0; i < 1024; ++i) ++ amvdec_write_dos(core, HEVC_IQIT_SCALELUT_DATA, 0); ++ ++ amvdec_write_dos(core, HEVC_DECODE_SIZE, 0); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); ++ for (i = 0; i < ARRAY_SIZE(vdec_hevc_parser_cmd); ++i) ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, ++ vdec_hevc_parser_cmd[i]); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2); ++ amvdec_write_dos(core, HEVC_PARSER_IF_CONTROL, ++ BIT(5) | BIT(2) | BIT(0)); ++ ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(0)); ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(1)); ++ ++ amvdec_write_dos(core, HEVC_WAIT_FLAG, 1); ++ ++ /* clear mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_CLR_REG, 1); ++ /* enable mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 1); ++ /* disable PSCALE for hardware sharing */ ++ amvdec_write_dos(core, HEVC_PSCALE_CTRL, 0); ++ /* Let the uCode do all the parsing */ ++ amvdec_write_dos(core, NAL_SEARCH_CTL, 0xc); ++ ++ amvdec_write_dos(core, DECODE_STOP_POS, 0); ++ amvdec_write_dos(core, HEVC_DECODE_MODE, DECODE_MODE_SINGLE); ++ amvdec_write_dos(core, HEVC_DECODE_MODE2, 0); ++ ++ /* AUX buffers */ ++ hevc->aux_vaddr = dma_alloc_coherent(core->dev, SIZE_AUX, ++ &hevc->aux_paddr, GFP_KERNEL); ++ if (!hevc->aux_vaddr) { ++ dev_err(core->dev, "Failed to request HEVC AUX\n"); ++ ret = -ENOMEM; ++ goto free_hevc; ++ } ++ ++ amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); ++ amvdec_write_dos(core, HEVC_AUX_DATA_SIZE, ++ (((SIZE_AUX) >> 4) << 16) | 0); ++ mutex_init(&hevc->lock); ++ sess->priv = hevc; ++ ++ return 0; ++ ++free_hevc: ++ kfree(hevc); ++ return ret; ++} ++ ++static void codec_hevc_flush_output(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct hevc_frame *tmp; ++ ++ while (!list_empty(&hevc->ref_frames_list)) { ++ tmp = codec_hevc_get_lowest_poc_frame(hevc); ++ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); ++ list_del(&tmp->list); ++ kfree(tmp); ++ hevc->frames_num--; ++ } ++} ++ ++static int codec_hevc_stop(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct amvdec_core *core = sess->core; ++ ++ mutex_lock(&hevc->lock); ++ codec_hevc_flush_output(sess); ++ ++ if (hevc->workspace_vaddr) ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ hevc->workspace_vaddr, ++ hevc->workspace_paddr); ++ ++ if (hevc->aux_vaddr) ++ dma_free_coherent(core->dev, SIZE_AUX, ++ hevc->aux_vaddr, hevc->aux_paddr); ++ ++ codec_hevc_free_fbc_buffers(sess); ++ mutex_unlock(&hevc->lock); ++ mutex_destroy(&hevc->lock); ++ ++ return 0; ++} ++ ++static struct hevc_frame * ++codec_hevc_get_frame_by_poc(struct codec_hevc *hevc, u32 poc) ++{ ++ struct hevc_frame *tmp; ++ ++ list_for_each_entry(tmp, &hevc->ref_frames_list, list) { ++ if (tmp->poc == poc) ++ return tmp; ++ } ++ ++ return NULL; ++} ++ ++static struct hevc_frame * ++codec_hevc_prepare_new_frame(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct hevc_frame *new_frame = NULL; ++ struct codec_hevc *hevc = sess->priv; ++ struct vb2_v4l2_buffer *vbuf; ++ union rpm_param *params = &hevc->rpm_param; ++ ++ new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL); ++ if (!new_frame) ++ return NULL; ++ ++ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); ++ if (!vbuf) { ++ dev_err(sess->core->dev, "No dst buffer available\n"); ++ return NULL; ++ } ++ ++ new_frame->vbuf = vbuf; ++ new_frame->referenced = 1; ++ new_frame->poc = hevc->curr_poc; ++ new_frame->cur_slice_type = params->p.slice_type; ++ new_frame->num_reorder_pic = params->p.sps_num_reorder_pics_0; ++ new_frame->offset = amvdec_read_dos(core, HEVC_SHIFT_BYTE_COUNT); ++ ++ list_add_tail(&new_frame->list, &hevc->ref_frames_list); ++ hevc->frames_num++; ++ ++ return new_frame; ++} ++ ++static void ++codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 pic_height_cu = ++ (hevc->height + hevc->lcu_size - 1) / hevc->lcu_size; ++ u32 sao_mem_unit = (hevc->lcu_size == 16 ? 9 : ++ hevc->lcu_size == 32 ? 14 : 24) << 4; ++ u32 sao_vb_size = (sao_mem_unit + (2 << 4)) * pic_height_cu; ++ u32 misc_flag0 = param->p.misc_flag0; ++ dma_addr_t buf_y_paddr; ++ dma_addr_t buf_u_v_paddr; ++ u32 slice_deblocking_filter_disabled_flag; ++ u32 val, val_2; ++ ++ val = (amvdec_read_dos(core, HEVC_SAO_CTRL0) & ~0xf) | ++ ilog2(hevc->lcu_size); ++ amvdec_write_dos(core, HEVC_SAO_CTRL0, val); ++ ++ amvdec_write_dos(core, HEVC_SAO_PIC_SIZE, ++ hevc->width | (hevc->height << 16)); ++ amvdec_write_dos(core, HEVC_SAO_PIC_SIZE_LCU, ++ (hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit)) ++ buf_y_paddr = ++ sess->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; ++ else ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); ++ } ++ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); ++ buf_u_v_paddr = ++ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 1); ++ amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr); ++ amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); ++ } ++ ++ amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, ++ amvdec_get_output_size(sess)); ++ amvdec_write_dos(core, HEVC_SAO_C_LENGTH, ++ (amvdec_get_output_size(sess) / 2)); ++ ++ if (frame->cur_slice_idx == 0) { ++ amvdec_write_dos(core, HEVC_DBLK_CFG2, ++ hevc->width | (hevc->height << 16)); ++ ++ val = 0; ++ if ((misc_flag0 >> PCM_ENABLE_FLAG_BIT) & 0x1) ++ val |= ((misc_flag0 >> PCM_LOOP_FILTER_DISABLED_FLAG_BIT) & 0x1) << 3; ++ ++ val |= (param->p.pps_cb_qp_offset & 0x1f) << 4; ++ val |= (param->p.pps_cr_qp_offset & 0x1f) << 9; ++ val |= (hevc->lcu_size == 64) ? 0 : ((hevc->lcu_size == 32) ? 1 : 2); ++ amvdec_write_dos(core, HEVC_DBLK_CFG1, val); ++ } ++ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; ++ val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ ++ amvdec_write_dos(core, HEVC_SAO_CTRL1, val); ++ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { ++ /* no downscale for NV12 */ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ } ++ ++ val = amvdec_read_dos(core, HEVCD_IPP_AXIIF_CONFIG) & ~0x30; ++ val |= 0xf; ++ amvdec_write_dos(core, HEVCD_IPP_AXIIF_CONFIG, val); ++ ++ val = 0; ++ val_2 = amvdec_read_dos(core, HEVC_SAO_CTRL0); ++ val_2 &= (~0x300); ++ ++ slice_deblocking_filter_disabled_flag = (misc_flag0 >> ++ SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1; ++ if ((misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT)) ++ && (misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT))) { ++ val |= slice_deblocking_filter_disabled_flag << 2; ++ ++ if (!slice_deblocking_filter_disabled_flag) { ++ val |= (param->p.slice_beta_offset_div2 & 0xf) << 3; ++ val |= (param->p.slice_tc_offset_div2 & 0xf) << 7; ++ } ++ } else { ++ val |= ++ ((misc_flag0 >> ++ PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1) << 2; ++ ++ if (((misc_flag0 >> PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & ++ 0x1) == 0) { ++ val |= (param->p.pps_beta_offset_div2 & 0xf) << 3; ++ val |= (param->p.pps_tc_offset_div2 & 0xf) << 7; ++ } ++ } ++ if ((misc_flag0 & (1 << PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)) ++ && ((misc_flag0 & (1 << SLICE_SAO_LUMA_FLAG_BIT)) ++ || (misc_flag0 & (1 << SLICE_SAO_CHROMA_FLAG_BIT)) ++ || (!slice_deblocking_filter_disabled_flag))) { ++ val |= ++ ((misc_flag0 >> ++ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 1; ++ val_2 |= ++ ((misc_flag0 >> ++ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 9; ++ } else { ++ val |= ++ ((misc_flag0 >> ++ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 1; ++ val_2 |= ++ ((misc_flag0 >> ++ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 9; ++ } ++ ++ amvdec_write_dos(core, HEVC_DBLK_CFG9, val); ++ amvdec_write_dos(core, HEVC_SAO_CTRL0, val_2); ++ ++ amvdec_write_dos(core, HEVC_sao_mem_unit, sao_mem_unit); ++ amvdec_write_dos(core, HEVC_SAO_ABV, ++ hevc->workspace_paddr + SAO_ABV_OFFSET); ++ amvdec_write_dos(core, HEVC_sao_vb_size, sao_vb_size); ++ amvdec_write_dos(core, HEVC_SAO_VB, ++ hevc->workspace_paddr + SAO_VB_OFFSET); ++} ++ ++static dma_addr_t codec_hevc_get_frame_mv_paddr(struct codec_hevc *hevc, ++ struct hevc_frame *frame) ++{ ++ return hevc->workspace_paddr + MPRED_MV_OFFSET + ++ (frame->vbuf->vb2_buf.index * MPRED_MV_BUF_SIZE); ++} ++ ++static void ++codec_hevc_set_mpred_ctrl(struct amvdec_core *core, struct codec_hevc *hevc) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ u32 slice_type = param->p.slice_type; ++ u32 lcu_size_log2 = ilog2(hevc->lcu_size); ++ u32 val; ++ ++ val = slice_type | ++ MPRED_CTRL0_ABOVE_EN | ++ MPRED_CTRL0_MV_WR_EN | ++ MPRED_CTRL0_BUF_LINEAR | ++ (lcu_size_log2 << 16) | ++ (3 << 20) | /* cu_size_log2 */ ++ (param->p.log2_parallel_merge_level << 24); ++ ++ if (slice_type != I_SLICE) ++ val |= MPRED_CTRL0_MV_RD_EN; ++ ++ if (param->p.collocated_from_l0_flag) ++ val |= MPRED_CTRL0_COL_FROM_L0; ++ ++ if (param->p.slice_temporal_mvp_enable_flag) ++ val |= MPRED_CTRL0_TMVP; ++ ++ if (hevc->ldc_flag) ++ val |= MPRED_CTRL0_LDC; ++ ++ if (param->p.dependent_slice_segment_flag) ++ val |= MPRED_CTRL0_NEW_SLI_SEG; ++ ++ if (param->p.slice_segment_address == 0) ++ val |= MPRED_CTRL0_NEW_PIC | ++ MPRED_CTRL0_NEW_TILE; ++ ++ amvdec_write_dos(core, HEVC_MPRED_CTRL0, val); ++ ++ val = (5 - param->p.five_minus_max_num_merge_cand) | ++ (AMVP_MAX_NUM_CANDS << 4) | ++ (AMVP_MAX_NUM_CANDS_MEM << 8) | ++ (NUM_CHROMA_MODE << 12) | ++ (DM_CHROMA_IDX << 16); ++ amvdec_write_dos(core, HEVC_MPRED_CTRL1, val); ++} ++ ++static void codec_hevc_set_mpred_mv(struct amvdec_core *core, ++ struct codec_hevc *hevc, ++ struct hevc_frame *frame, ++ struct hevc_frame *col_frame) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ u32 lcu_size_log2 = ilog2(hevc->lcu_size); ++ u32 mv_mem_unit = lcu_size_log2 == 6 ? 0x200 : ++ lcu_size_log2 == 5 ? 0x80 : 0x20; ++ dma_addr_t col_mv_rd_start_addr, col_mv_rd_ptr, col_mv_rd_end_addr; ++ dma_addr_t mpred_mv_wr_ptr; ++ u32 val; ++ ++ val = amvdec_read_dos(core, HEVC_MPRED_CURR_LCU); ++ ++ col_mv_rd_start_addr = codec_hevc_get_frame_mv_paddr(hevc, col_frame); ++ mpred_mv_wr_ptr = codec_hevc_get_frame_mv_paddr(hevc, frame) + ++ (hevc->slice_addr * mv_mem_unit); ++ col_mv_rd_ptr = col_mv_rd_start_addr + ++ (hevc->slice_addr * mv_mem_unit); ++ col_mv_rd_end_addr = col_mv_rd_start_addr + ++ (hevc->lcu_total * mv_mem_unit); ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_WR_START_ADDR, ++ codec_hevc_get_frame_mv_paddr(hevc, frame)); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_START_ADDR, ++ col_mv_rd_start_addr); ++ ++ if (param->p.slice_segment_address == 0) { ++ amvdec_write_dos(core, HEVC_MPRED_ABV_START_ADDR, ++ hevc->workspace_paddr + MPRED_ABV_OFFSET); ++ amvdec_write_dos(core, HEVC_MPRED_MV_WPTR, mpred_mv_wr_ptr); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, ++ col_mv_rd_start_addr); ++ } else { ++ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, col_mv_rd_ptr); ++ } ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_END_ADDR, col_mv_rd_end_addr); ++} ++ ++/* Update motion prediction with the current slice */ ++static void codec_hevc_set_mpred(struct amvdec_session *sess, ++ struct hevc_frame *frame, ++ struct hevc_frame *col_frame) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ u32 *ref_num = frame->ref_num; ++ u32 *ref_poc_l0 = frame->ref_poc_list[0][frame->cur_slice_idx]; ++ u32 *ref_poc_l1 = frame->ref_poc_list[1][frame->cur_slice_idx]; ++ u32 val; ++ int i; ++ ++ codec_hevc_set_mpred_ctrl(core, hevc); ++ codec_hevc_set_mpred_mv(core, hevc, frame, col_frame); ++ ++ amvdec_write_dos(core, HEVC_MPRED_PIC_SIZE, ++ hevc->width | (hevc->height << 16)); ++ ++ val = ((hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); ++ amvdec_write_dos(core, HEVC_MPRED_PIC_SIZE_LCU, val); ++ ++ amvdec_write_dos(core, HEVC_MPRED_REF_NUM, ++ (ref_num[1] << 8) | ref_num[0]); ++ amvdec_write_dos(core, HEVC_MPRED_REF_EN_L0, (1 << ref_num[0]) - 1); ++ amvdec_write_dos(core, HEVC_MPRED_REF_EN_L1, (1 << ref_num[1]) - 1); ++ ++ amvdec_write_dos(core, HEVC_MPRED_CUR_POC, hevc->curr_poc); ++ amvdec_write_dos(core, HEVC_MPRED_COL_POC, hevc->col_poc); ++ ++ for (i = 0; i < MAX_REF_ACTIVE; ++i) { ++ amvdec_write_dos(core, HEVC_MPRED_L0_REF00_POC + i * 4, ++ ref_poc_l0[i]); ++ amvdec_write_dos(core, HEVC_MPRED_L1_REF00_POC + i * 4, ++ ref_poc_l1[i]); ++ } ++} ++ ++/* motion compensation reference cache controller */ ++static void codec_hevc_set_mcrcc(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ u32 val, val_2; ++ int l0_cnt = 0; ++ int l1_cnt = 0x7fff; ++ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { ++ l0_cnt = hevc->cur_frame->ref_num[0]; ++ l1_cnt = hevc->cur_frame->ref_num[1]; ++ } ++ ++ if (hevc->cur_frame->cur_slice_type == I_SLICE) { ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL1, 0); ++ return; ++ } ++ ++ if (hevc->cur_frame->cur_slice_type == P_SLICE) { ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, ++ BIT(1)); ++ val = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val &= 0xffff; ++ val |= (val << 16); ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL2, val); ++ ++ if (l0_cnt == 1) { ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); ++ } else { ++ val = amvdec_read_dos(core, ++ HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val &= 0xffff; ++ val |= (val << 16); ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); ++ } ++ } else { /* B_SLICE */ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 0); ++ val = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val &= 0xffff; ++ val |= (val << 16); ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL2, val); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, ++ BIT(12) | BIT(1)); ++ val_2 = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val_2 &= 0xffff; ++ val_2 |= (val_2 << 16); ++ if (val == val_2 && l1_cnt > 1) { ++ val_2 = amvdec_read_dos(core, ++ HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val_2 &= 0xffff; ++ val_2 |= (val_2 << 16); ++ } ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); ++ } ++ ++ /* enable mcrcc progressive-mode */ ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL1, 0xff0); ++} ++ ++static void codec_hevc_set_ref_list(struct amvdec_session *sess, ++ u32 ref_num, u32 *ref_poc_list) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct hevc_frame *ref_frame; ++ struct amvdec_core *core = sess->core; ++ int i; ++ u32 buf_id_y; ++ u32 buf_id_uv; ++ ++ for (i = 0; i < ref_num; i++) { ++ ref_frame = codec_hevc_get_frame_by_poc(hevc, ref_poc_list[i]); ++ ++ if (!ref_frame) { ++ dev_warn(core->dev, "Couldn't find ref. frame %u\n", ++ ref_poc_list[i]); ++ continue; ++ } ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { ++ buf_id_y = buf_id_uv = ref_frame->vbuf->vb2_buf.index; ++ } else { ++ buf_id_y = ref_frame->vbuf->vb2_buf.index * 2; ++ buf_id_uv = buf_id_y + 1; ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, ++ (buf_id_uv << 16) | ++ (buf_id_uv << 8) | ++ buf_id_y); ++ } ++} ++ ++static void codec_hevc_set_mc(struct amvdec_session *sess, struct hevc_frame *frame) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ if (frame->cur_slice_type == I_SLICE) ++ return; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ codec_hevc_set_ref_list(sess, frame->ref_num[0], ++ frame->ref_poc_list[0][frame->cur_slice_idx]); ++ ++ if (frame->cur_slice_type == P_SLICE) ++ return; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, ++ BIT(12) | BIT(0)); ++ codec_hevc_set_ref_list(sess, frame->ref_num[1], ++ frame->ref_poc_list[1][frame->cur_slice_idx]); ++} ++ ++static void codec_hevc_update_col_frame(struct codec_hevc *hevc) ++{ ++ struct hevc_frame *cur_frame = hevc->cur_frame; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 list_no = 0; ++ u32 col_ref = param->p.collocated_ref_idx; ++ u32 col_from_l0 = param->p.collocated_from_l0_flag; ++ ++ if (cur_frame->cur_slice_type == B_SLICE) ++ list_no = 1 - col_from_l0; ++ ++ if (col_ref >= cur_frame->ref_num[list_no]) ++ hevc->col_poc = INVALID_POC; ++ else ++ hevc->col_poc = cur_frame->ref_poc_list[list_no][cur_frame->cur_slice_idx][col_ref]; ++ ++ if (cur_frame->cur_slice_type == I_SLICE) ++ goto end; ++ ++ if (hevc->col_poc != INVALID_POC) ++ hevc->col_frame = codec_hevc_get_frame_by_poc(hevc, hevc->col_poc); ++ else ++ hevc->col_frame = hevc->cur_frame; ++ ++end: ++ if (!hevc->col_frame) ++ hevc->col_frame = hevc->cur_frame; ++} ++ ++static void codec_hevc_update_pocs(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 nal_unit_type = param->p.m_nalUnitType; ++ u32 temporal_id = param->p.m_temporalId & 0x7; ++ int max_poc_lsb = ++ 1 << (param->p.log2_max_pic_order_cnt_lsb_minus4 + 4); ++ int prev_poc_lsb; ++ int prev_poc_msb; ++ int poc_msb; ++ int poc_lsb = param->p.POClsb; ++ ++ if (nal_unit_type == NAL_UNIT_CODED_SLICE_IDR || ++ nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) { ++ hevc->curr_poc = 0; ++ if ((temporal_id - 1) == 0) ++ hevc->prev_tid0_poc = hevc->curr_poc; ++ ++ return; ++ } ++ ++ prev_poc_lsb = hevc->prev_tid0_poc % max_poc_lsb; ++ prev_poc_msb = hevc->prev_tid0_poc - prev_poc_lsb; ++ ++ if ((poc_lsb < prev_poc_lsb) && ++ ((prev_poc_lsb - poc_lsb) >= (max_poc_lsb / 2))) ++ poc_msb = prev_poc_msb + max_poc_lsb; ++ else if ((poc_lsb > prev_poc_lsb) && ++ ((poc_lsb - prev_poc_lsb) > (max_poc_lsb / 2))) ++ poc_msb = prev_poc_msb - max_poc_lsb; ++ else ++ poc_msb = prev_poc_msb; ++ ++ if (nal_unit_type == NAL_UNIT_CODED_SLICE_BLA || ++ nal_unit_type == NAL_UNIT_CODED_SLICE_BLANT || ++ nal_unit_type == NAL_UNIT_CODED_SLICE_BLA_N_LP) ++ poc_msb = 0; ++ ++ hevc->curr_poc = (poc_msb + poc_lsb); ++ if ((temporal_id - 1) == 0) ++ hevc->prev_tid0_poc = hevc->curr_poc; ++} ++ ++static void codec_hevc_process_segment_header(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *param = &hevc->rpm_param; ++ ++ if (param->p.first_slice_segment_in_pic_flag == 0) { ++ hevc->slice_segment_addr = param->p.slice_segment_address; ++ if (!param->p.dependent_slice_segment_flag) ++ hevc->slice_addr = hevc->slice_segment_addr; ++ } else { ++ hevc->slice_segment_addr = 0; ++ hevc->slice_addr = 0; ++ } ++ ++ codec_hevc_update_pocs(sess); ++} ++ ++static int codec_hevc_process_segment(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct amvdec_core *core = sess->core; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 slice_segment_address = param->p.slice_segment_address; ++ ++ /* First slice: new frame */ ++ if (slice_segment_address == 0) { ++ codec_hevc_update_referenced(hevc); ++ codec_hevc_output_frames(sess); ++ ++ hevc->cur_frame = codec_hevc_prepare_new_frame(sess); ++ if (!hevc->cur_frame) ++ return -1; ++ } else { ++ hevc->cur_frame->cur_slice_idx++; ++ } ++ ++ codec_hevc_update_frame_refs(sess, hevc->cur_frame); ++ codec_hevc_update_col_frame(hevc); ++ codec_hevc_update_ldc_flag(hevc); ++ codec_hevc_set_mc(sess, hevc->cur_frame); ++ codec_hevc_set_mcrcc(sess); ++ codec_hevc_set_mpred(sess, hevc->cur_frame, hevc->col_frame); ++ codec_hevc_set_sao(sess, hevc->cur_frame); ++ ++ amvdec_write_dos_bits(core, HEVC_WAIT_FLAG, BIT(1)); ++ amvdec_write_dos(core, HEVC_DEC_STATUS_REG, ++ HEVC_CODED_SLICE_SEGMENT_DAT); ++ ++ /* Interrupt the firmware's processor */ ++ amvdec_write_dos(core, HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ); ++ ++ return 0; ++} ++ ++static int codec_hevc_process_rpm(struct codec_hevc *hevc) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ int src_changed = 0; ++ u32 dst_width, dst_height; ++ u32 lcu_size; ++ u32 is_10bit; ++ ++ if (param->p.slice_segment_address || ++ !param->p.pic_width_in_luma_samples || ++ !param->p.pic_height_in_luma_samples) ++ return 0; ++ ++ if (param->p.bit_depth) ++ is_10bit = 1; ++ ++ hevc->width = param->p.pic_width_in_luma_samples; ++ hevc->height = param->p.pic_height_in_luma_samples; ++ dst_width = hevc->width; ++ dst_height = hevc->height; ++ ++ lcu_size = 1 << (param->p.log2_min_coding_block_size_minus3 + ++ 3 + param->p.log2_diff_max_min_coding_block_size); ++ ++ hevc->lcu_x_num = (hevc->width + lcu_size - 1) / lcu_size; ++ hevc->lcu_y_num = (hevc->height + lcu_size - 1) / lcu_size; ++ hevc->lcu_total = hevc->lcu_x_num * hevc->lcu_y_num; ++ ++ if (param->p.conformance_window_flag) { ++ u32 sub_width = 1, sub_height = 1; ++ ++ switch (param->p.chroma_format_idc) { ++ case 1: ++ sub_height = 2; ++ case 2: ++ sub_width = 2; ++ break; ++ } ++ ++ dst_width -= sub_width * ++ (param->p.conf_win_left_offset + ++ param->p.conf_win_right_offset); ++ dst_height -= sub_height * ++ (param->p.conf_win_top_offset + ++ param->p.conf_win_bottom_offset); ++ } ++ ++ if (dst_width != hevc->dst_width || ++ dst_height != hevc->dst_height || ++ lcu_size != hevc->lcu_size || ++ is_10bit != hevc->is_10bit) ++ src_changed = 1; ++ ++ hevc->dst_width = dst_width; ++ hevc->dst_height = dst_height; ++ hevc->lcu_size = lcu_size; ++ hevc->is_10bit = is_10bit; ++ ++ return src_changed; ++} ++ ++/* The RPM section within the workspace contains ++ * many information regarding the parsed bitstream ++ */ ++static void codec_hevc_fetch_rpm(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ u16 *rpm_vaddr = hevc->workspace_vaddr + RPM_OFFSET; ++ int i, j; ++ ++ for (i = 0; i < RPM_SIZE; i += 4) ++ for (j = 0; j < 4; j++) ++ hevc->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j]; ++} ++ ++static void codec_hevc_resume(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ ++ if (codec_hevc_setup_buffers(sess, hevc->is_10bit)) { ++ amvdec_abort(sess); ++ return; ++ } ++ ++ codec_hevc_setup_decode_head(sess, hevc->is_10bit); ++ codec_hevc_process_segment_header(sess); ++ if (codec_hevc_process_segment(sess)) ++ amvdec_abort(sess); ++} ++ ++static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG); ++ ++ if (!hevc) ++ return IRQ_HANDLED; ++ ++ mutex_lock(&hevc->lock); ++ if (dec_status != HEVC_SLICE_SEGMENT_DONE) { ++ dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n", ++ dec_status); ++ amvdec_abort(sess); ++ goto unlock; ++ } ++ ++ sess->keyframe_found = 1; ++ codec_hevc_fetch_rpm(sess); ++ if (codec_hevc_process_rpm(hevc)) { ++ amvdec_src_change(sess, hevc->dst_width, hevc->dst_height, 16); ++ goto unlock; ++ } ++ ++ codec_hevc_process_segment_header(sess); ++ if (codec_hevc_process_segment(sess)) ++ amvdec_abort(sess); ++ ++unlock: ++ mutex_unlock(&hevc->lock); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t codec_hevc_isr(struct amvdec_session *sess) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++struct amvdec_codec_ops codec_hevc_ops = { ++ .start = codec_hevc_start, ++ .stop = codec_hevc_stop, ++ .isr = codec_hevc_isr, ++ .threaded_isr = codec_hevc_threaded_isr, ++ .num_pending_bufs = codec_hevc_num_pending_bufs, ++ .drain = codec_hevc_flush_output, ++ .resume = codec_hevc_resume, ++}; +diff --git a/drivers/staging/media/meson/vdec/codec_hevc.h b/drivers/staging/media/meson/vdec/codec_hevc.h +new file mode 100644 +index 000000000000..f2f9b2464df1 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_hevc.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_HEVC_H_ ++#define __MESON_VDEC_CODEC_HEVC_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_hevc_ops; ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c +new file mode 100644 +index 000000000000..2b296beb5d88 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_hevc_common.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "codec_hevc_common.h" ++#include "vdec_helpers.h" ++#include "hevc_regs.h" ++ ++/* Configure decode head read mode */ ++void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); ++ u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); ++ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { ++ /* Enable 2-plane reference read mode */ ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); ++ return; ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); ++ amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); ++ amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); ++ amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); ++} ++EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); ++ ++static void ++codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ struct v4l2_m2m_buffer *buf; ++ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ u32 idx = 0; ++ u32 val; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ idx = buf->vb.vb2_buf.index; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) ++ buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ else ++ buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { ++ val = buf_y_paddr | (idx << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ } else { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ val = buf_y_paddr | ((idx * 2) << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ } ++ } ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) ++ val = buf_y_paddr | (idx << 8) | 1; ++ else ++ val = buf_y_paddr | ((idx * 2) << 8) | 1; ++ ++ /* Fill the remaining unused slots with the last buffer's Y addr */ ++ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ for (i = 0; i < 32; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); ++} ++ ++static void ++codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ struct v4l2_m2m_buffer *buf; ++ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, ++ BIT(2) | BIT(1)); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) ++ buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ else ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_y_paddr >> 5); ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_uv_paddr >> 5); ++ } ++ } ++ ++ /* Fill the remaining unused slots with the last buffer's Y addr */ ++ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_y_paddr >> 5); ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_uv_paddr >> 5); ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ for (i = 0; i < 32; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); ++} ++ ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) ++{ ++ struct device *dev = sess->core->dev; ++ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); ++ int i; ++ ++ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { ++ if (sess->fbc_buffer_vaddr[i]) { ++ dma_free_coherent(dev, am21_size, ++ sess->fbc_buffer_vaddr[i], ++ sess->fbc_buffer_paddr[i]); ++ sess->fbc_buffer_vaddr[i] = NULL; ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); ++ ++static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) ++{ ++ struct device *dev = sess->core->dev; ++ struct v4l2_m2m_buffer *buf; ++ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ dma_addr_t paddr; ++ void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, ++ GFP_KERNEL); ++ if (!vaddr) { ++ dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); ++ codec_hevc_free_fbc_buffers(sess); ++ return -ENOMEM; ++ } ++ ++ sess->fbc_buffer_vaddr[idx] = vaddr; ++ sess->fbc_buffer_paddr[idx] = paddr; ++ } ++ ++ return 0; ++} ++ ++int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ int ret; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) { ++ ret = codec_hevc_alloc_fbc_buffers(sess); ++ if (ret) ++ return ret; ++ } ++ ++ if (core->platform->revision == VDEC_REVISION_GXBB) ++ codec_hevc_setup_buffers_gxbb(sess, is_10bit); ++ else ++ codec_hevc_setup_buffers_gxl(sess, is_10bit); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); +\ No newline at end of file +diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.h b/drivers/staging/media/meson/vdec/codec_hevc_common.h +new file mode 100644 +index 000000000000..7c8891529ac8 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_hevc_common.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_HEVC_COMMON_H_ ++#define __MESON_VDEC_HEVC_COMMON_H_ ++ ++#include "vdec.h" ++ ++#define PARSER_CMD_SKIP_CFG_0 0x0000090b ++#define PARSER_CMD_SKIP_CFG_1 0x1b14140f ++#define PARSER_CMD_SKIP_CFG_2 0x001b1910 ++static const u16 vdec_hevc_parser_cmd[] = { ++ 0x0401, 0x8401, 0x0800, 0x0402, ++ 0x9002, 0x1423, 0x8CC3, 0x1423, ++ 0x8804, 0x9825, 0x0800, 0x04FE, ++ 0x8406, 0x8411, 0x1800, 0x8408, ++ 0x8409, 0x8C2A, 0x9C2B, 0x1C00, ++ 0x840F, 0x8407, 0x8000, 0x8408, ++ 0x2000, 0xA800, 0x8410, 0x04DE, ++ 0x840C, 0x840D, 0xAC00, 0xA000, ++ 0x08C0, 0x08E0, 0xA40E, 0xFC00, ++ 0x7C00 ++}; ++ ++/* Returns 1 if we must use framebuffer compression */ ++static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit) ++{ ++ return pixfmt == V4L2_PIX_FMT_AM21C || is_10bit; ++} ++ ++/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ ++static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit) ++{ ++ return pixfmt == V4L2_PIX_FMT_NV12M && is_10bit; ++} ++ ++/** ++ * Configure decode head read mode ++ */ ++void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit); ++ ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess); ++ ++int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit); ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h +new file mode 100644 +index 000000000000..ba49f906be5a +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/hevc_regs.h +@@ -0,0 +1,205 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. ++ */ ++ ++#ifndef __MESON_VDEC_HEVC_REGS_H_ ++#define __MESON_VDEC_HEVC_REGS_H_ ++ ++#define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4 ++#define HEVC_ASSIST_MBOX1_MASK 0xc1d8 ++ ++#define HEVC_ASSIST_SCRATCH_0 0xc300 ++#define HEVC_ASSIST_SCRATCH_1 0xc304 ++#define HEVC_ASSIST_SCRATCH_2 0xc308 ++#define HEVC_ASSIST_SCRATCH_3 0xc30c ++#define HEVC_ASSIST_SCRATCH_4 0xc310 ++#define HEVC_ASSIST_SCRATCH_5 0xc314 ++#define HEVC_ASSIST_SCRATCH_6 0xc318 ++#define HEVC_ASSIST_SCRATCH_7 0xc31c ++#define HEVC_ASSIST_SCRATCH_8 0xc320 ++#define HEVC_ASSIST_SCRATCH_9 0xc324 ++#define HEVC_ASSIST_SCRATCH_A 0xc328 ++#define HEVC_ASSIST_SCRATCH_B 0xc32c ++#define HEVC_ASSIST_SCRATCH_C 0xc330 ++#define HEVC_ASSIST_SCRATCH_D 0xc334 ++#define HEVC_ASSIST_SCRATCH_E 0xc338 ++#define HEVC_ASSIST_SCRATCH_F 0xc33c ++#define HEVC_ASSIST_SCRATCH_G 0xc340 ++#define HEVC_ASSIST_SCRATCH_H 0xc344 ++#define HEVC_ASSIST_SCRATCH_I 0xc348 ++#define HEVC_ASSIST_SCRATCH_J 0xc34c ++#define HEVC_ASSIST_SCRATCH_K 0xc350 ++#define HEVC_ASSIST_SCRATCH_L 0xc354 ++#define HEVC_ASSIST_SCRATCH_M 0xc358 ++#define HEVC_ASSIST_SCRATCH_N 0xc35c ++ ++#define HEVC_PARSER_VERSION 0xc400 ++#define HEVC_STREAM_CONTROL 0xc404 ++#define HEVC_STREAM_START_ADDR 0xc408 ++#define HEVC_STREAM_END_ADDR 0xc40c ++#define HEVC_STREAM_WR_PTR 0xc410 ++#define HEVC_STREAM_RD_PTR 0xc414 ++#define HEVC_STREAM_LEVEL 0xc418 ++#define HEVC_STREAM_FIFO_CTL 0xc41c ++#define HEVC_SHIFT_CONTROL 0xc420 ++#define HEVC_SHIFT_STARTCODE 0xc424 ++#define HEVC_SHIFT_EMULATECODE 0xc428 ++#define HEVC_SHIFT_STATUS 0xc42c ++#define HEVC_SHIFTED_DATA 0xc430 ++#define HEVC_SHIFT_BYTE_COUNT 0xc434 ++#define HEVC_SHIFT_COMMAND 0xc438 ++#define HEVC_ELEMENT_RESULT 0xc43c ++#define HEVC_CABAC_CONTROL 0xc440 ++#define HEVC_PARSER_SLICE_INFO 0xc444 ++#define HEVC_PARSER_CMD_WRITE 0xc448 ++#define HEVC_PARSER_CORE_CONTROL 0xc44c ++#define HEVC_PARSER_CMD_FETCH 0xc450 ++#define HEVC_PARSER_CMD_STATUS 0xc454 ++#define HEVC_PARSER_LCU_INFO 0xc458 ++#define HEVC_PARSER_HEADER_INFO 0xc45c ++#define HEVC_PARSER_INT_CONTROL 0xc480 ++#define HEVC_PARSER_INT_STATUS 0xc484 ++#define HEVC_PARSER_IF_CONTROL 0xc488 ++#define HEVC_PARSER_PICTURE_SIZE 0xc48c ++#define HEVC_PARSER_LCU_START 0xc490 ++#define HEVC_PARSER_HEADER_INFO2 0xc494 ++#define HEVC_PARSER_QUANT_READ 0xc498 ++#define HEVC_PARSER_RESERVED_27 0xc49c ++#define HEVC_PARSER_CMD_SKIP_0 0xc4a0 ++#define HEVC_PARSER_CMD_SKIP_1 0xc4a4 ++#define HEVC_PARSER_CMD_SKIP_2 0xc4a8 ++#define HEVC_SAO_IF_STATUS 0xc4c0 ++#define HEVC_SAO_IF_DATA_Y 0xc4c4 ++#define HEVC_SAO_IF_DATA_U 0xc4c8 ++#define HEVC_SAO_IF_DATA_V 0xc4cc ++#define HEVC_STREAM_SWAP_ADDR 0xc4d0 ++#define HEVC_STREAM_SWAP_CTRL 0xc4d4 ++#define HEVC_IQIT_IF_WAIT_CNT 0xc4d8 ++#define HEVC_MPRED_IF_WAIT_CNT 0xc4dc ++#define HEVC_SAO_IF_WAIT_CNT 0xc4e0 ++ ++#define HEVC_MPRED_VERSION 0xc800 ++#define HEVC_MPRED_CTRL0 0xc804 ++ #define MPRED_CTRL0_NEW_PIC BIT(2) ++ #define MPRED_CTRL0_NEW_TILE BIT(3) ++ #define MPRED_CTRL0_NEW_SLI_SEG BIT(4) ++ #define MPRED_CTRL0_TMVP BIT(5) ++ #define MPRED_CTRL0_LDC BIT(6) ++ #define MPRED_CTRL0_COL_FROM_L0 BIT(7) ++ #define MPRED_CTRL0_ABOVE_EN BIT(9) ++ #define MPRED_CTRL0_MV_WR_EN BIT(10) ++ #define MPRED_CTRL0_MV_RD_EN BIT(11) ++ #define MPRED_CTRL0_BUF_LINEAR BIT(13) ++#define HEVC_MPRED_CTRL1 0xc808 ++#define HEVC_MPRED_INT_EN 0xc80c ++#define HEVC_MPRED_INT_STATUS 0xc810 ++#define HEVC_MPRED_PIC_SIZE 0xc814 ++#define HEVC_MPRED_PIC_SIZE_LCU 0xc818 ++#define HEVC_MPRED_TILE_START 0xc81c ++#define HEVC_MPRED_TILE_SIZE_LCU 0xc820 ++#define HEVC_MPRED_REF_NUM 0xc824 ++#define HEVC_MPRED_REF_EN_L0 0xc830 ++#define HEVC_MPRED_REF_EN_L1 0xc834 ++#define HEVC_MPRED_COLREF_EN_L0 0xc838 ++#define HEVC_MPRED_COLREF_EN_L1 0xc83c ++#define HEVC_MPRED_AXI_WCTRL 0xc840 ++#define HEVC_MPRED_AXI_RCTRL 0xc844 ++#define HEVC_MPRED_ABV_START_ADDR 0xc848 ++#define HEVC_MPRED_MV_WR_START_ADDR 0xc84c ++#define HEVC_MPRED_MV_RD_START_ADDR 0xc850 ++#define HEVC_MPRED_MV_WPTR 0xc854 ++#define HEVC_MPRED_MV_RPTR 0xc858 ++#define HEVC_MPRED_MV_WR_ROW_JUMP 0xc85c ++#define HEVC_MPRED_MV_RD_ROW_JUMP 0xc860 ++#define HEVC_MPRED_CURR_LCU 0xc864 ++#define HEVC_MPRED_ABV_WPTR 0xc868 ++#define HEVC_MPRED_ABV_RPTR 0xc86c ++#define HEVC_MPRED_CTRL2 0xc870 ++#define HEVC_MPRED_CTRL3 0xc874 ++#define HEVC_MPRED_L0_REF00_POC 0xc880 ++#define HEVC_MPRED_L1_REF00_POC 0xc8c0 ++ ++#define HEVC_MPRED_CUR_POC 0xc980 ++#define HEVC_MPRED_COL_POC 0xc984 ++#define HEVC_MPRED_MV_RD_END_ADDR 0xc988 ++ ++#define HEVC_MSP 0xcc00 ++#define HEVC_MPSR 0xcc04 ++#define HEVC_MCPU_INTR_MSK 0xcc10 ++#define HEVC_MCPU_INTR_REQ 0xcc14 ++#define HEVC_CPSR 0xcc84 ++ ++#define HEVC_IMEM_DMA_CTRL 0xcd00 ++#define HEVC_IMEM_DMA_ADR 0xcd04 ++#define HEVC_IMEM_DMA_COUNT 0xcd08 ++ ++#define HEVCD_IPP_TOP_CNTL 0xd000 ++#define HEVCD_IPP_LINEBUFF_BASE 0xd024 ++#define HEVCD_IPP_AXIIF_CONFIG 0xd02c ++ ++#define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180 ++#define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184 ++#define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190 ++ ++#define HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR 0xd300 ++#define HEVCD_MPP_ANC_CANVAS_DATA_ADDR 0xd304 ++#define HEVCD_MPP_DECOMP_CTL1 0xd308 ++#define HEVCD_MPP_DECOMP_CTL2 0xd30c ++#define HEVCD_MCRCC_CTL1 0xd3c0 ++#define HEVCD_MCRCC_CTL2 0xd3c4 ++#define HEVCD_MCRCC_CTL3 0xd3c8 ++ ++#define HEVC_DBLK_CFG0 0xd400 ++#define HEVC_DBLK_CFG1 0xd404 ++#define HEVC_DBLK_CFG2 0xd408 ++#define HEVC_DBLK_CFG3 0xd40c ++#define HEVC_DBLK_CFG4 0xd410 ++#define HEVC_DBLK_CFG5 0xd414 ++#define HEVC_DBLK_CFG6 0xd418 ++#define HEVC_DBLK_CFG7 0xd41c ++#define HEVC_DBLK_CFG8 0xd420 ++#define HEVC_DBLK_CFG9 0xd424 ++#define HEVC_DBLK_CFGA 0xd428 ++#define HEVC_DBLK_STS0 0xd42c ++#define HEVC_DBLK_STS1 0xd430 ++ ++#define HEVC_SAO_VERSION 0xd800 ++#define HEVC_SAO_CTRL0 0xd804 ++#define HEVC_SAO_CTRL1 0xd808 ++#define HEVC_SAO_PIC_SIZE 0xd814 ++#define HEVC_SAO_PIC_SIZE_LCU 0xd818 ++#define HEVC_SAO_TILE_START 0xd81c ++#define HEVC_SAO_TILE_SIZE_LCU 0xd820 ++#define HEVC_SAO_Y_START_ADDR 0xd82c ++#define HEVC_SAO_Y_LENGTH 0xd830 ++#define HEVC_SAO_C_START_ADDR 0xd834 ++#define HEVC_SAO_C_LENGTH 0xd838 ++#define HEVC_SAO_Y_WPTR 0xd83c ++#define HEVC_SAO_C_WPTR 0xd840 ++#define HEVC_SAO_ABV_START_ADDR 0xd844 ++#define HEVC_SAO_VB_WR_START_ADDR 0xd848 ++#define HEVC_SAO_VB_RD_START_ADDR 0xd84c ++#define HEVC_SAO_ABV_WPTR 0xd850 ++#define HEVC_SAO_ABV_RPTR 0xd854 ++#define HEVC_SAO_VB_WPTR 0xd858 ++#define HEVC_SAO_VB_RPTR 0xd85c ++#define HEVC_SAO_CTRL2 0xd880 ++#define HEVC_SAO_CTRL3 0xd884 ++#define HEVC_SAO_CTRL4 0xd888 ++#define HEVC_SAO_CTRL5 0xd88c ++#define HEVC_SAO_CTRL6 0xd890 ++#define HEVC_SAO_CTRL7 0xd894 ++#define HEVC_CM_BODY_START_ADDR 0xd898 ++#define HEVC_CM_BODY_LENGTH 0xd89c ++#define HEVC_CM_HEADER_LENGTH 0xd8a4 ++#define HEVC_CM_HEADER_OFFSET 0xd8ac ++ ++#define HEVC_IQIT_CLK_RST_CTRL 0xdc00 ++#define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08 ++#define HEVC_IQIT_SCALELUT_RD_ADDR 0xdc0c ++#define HEVC_IQIT_SCALELUT_DATA 0xdc10 ++ ++#define HEVC_PSCALE_CTRL 0xe444 ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h +index d811e7976519..210ab4b755fe 100644 +--- a/drivers/staging/media/meson/vdec/vdec.h ++++ b/drivers/staging/media/meson/vdec/vdec.h +@@ -18,7 +18,9 @@ + #include "vdec_platform.h" + + /* 32 buffers in 3-plane YUV420 */ +-#define MAX_CANVAS (32 * 3) ++#define MAX_CANVAS (32 * 3) ++ ++#define MAX_REF_PIC_NUM 24 + + struct amvdec_buffer { + struct list_head list; +@@ -258,6 +260,9 @@ struct amvdec_session { + u32 wrap_count; + u32 fw_idx_to_vb2_idx[32]; + ++ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; ++ + enum amvdec_status status; + void *priv; + }; +diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c +new file mode 100644 +index 000000000000..b1406a5638da +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/vdec_hevc.c +@@ -0,0 +1,191 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * ++ * VDEC_HEVC is a video decoding block that allows decoding of ++ * HEVC, VP9 ++ */ ++ ++#include ++#include ++ ++#include "vdec_1.h" ++#include "vdec_helpers.h" ++#include "hevc_regs.h" ++#include "dos_regs.h" ++ ++/* AO Registers */ ++#define AO_RTI_GEN_PWR_SLEEP0 0xe8 ++#define AO_RTI_GEN_PWR_ISO0 0xec ++ #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6)) ++ ++#define MC_SIZE (4096 * 4) ++ ++static int vdec_hevc_load_firmware(struct amvdec_session *sess, const char* fwname) ++{ ++ struct amvdec_core *core = sess->core; ++ struct device *dev = core->dev_dec; ++ const struct firmware *fw; ++ static void *mc_addr; ++ static dma_addr_t mc_addr_map; ++ int ret; ++ u32 i = 100; ++ ++ ret = request_firmware(&fw, fwname, dev); ++ if (ret < 0) { ++ dev_err(dev, "Unable to request firmware %s\n", fwname); ++ return ret; ++ } ++ ++ if (fw->size < MC_SIZE) { ++ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", ++ fw->size, MC_SIZE); ++ ret = -EINVAL; ++ goto release_firmware; ++ } ++ ++ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map, GFP_KERNEL); ++ if (!mc_addr) { ++ dev_err(dev, "Failed allocating memory for firmware loading\n"); ++ ret = -ENOMEM; ++ goto release_firmware; ++ } ++ ++ memcpy(mc_addr, fw->data, MC_SIZE); ++ ++ amvdec_write_dos(core, HEVC_MPSR, 0); ++ amvdec_write_dos(core, HEVC_CPSR, 0); ++ ++ amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map); ++ amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4); ++ amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); ++ ++ while (--i && readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000) { } ++ ++ if (i == 0) { ++ dev_err(dev, "Firmware load fail (DMA hang?)\n"); ++ ret = -ENODEV; ++ } ++ ++ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); ++release_firmware: ++ release_firmware(fw); ++ return ret; ++} ++ ++static void vdec_hevc_stbuf_init(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1); ++ amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr); ++ amvdec_write_dos(core, HEVC_STREAM_END_ADDR, sess->vififo_paddr + sess->vififo_size); ++ amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr); ++ amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr); ++} ++ ++/* VDEC_HEVC specific ESPARSER configuration */ ++static void vdec_hevc_conf_esparser(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ /* set vififo_vbuf_rp_sel=>vdec_hevc */ ++ amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1); ++ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3)); ++ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1); ++ amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL, amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29)); ++} ++ ++static u32 vdec_hevc_vififo_level(struct amvdec_session *sess) ++{ ++ return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL); ++} ++ ++static int vdec_hevc_stop(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ /* Disable interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0); ++ /* Disable firmware processor */ ++ amvdec_write_dos(core, HEVC_MPSR, 0); ++ ++ if (sess->priv) ++ codec_ops->stop(sess); ++ ++ /* Enable VDEC_HEVC Isolation */ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0xc00); ++ ++ /* VDEC_HEVC Memories */ ++ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL); ++ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); ++ ++ clk_disable_unprepare(core->vdec_hevc_clk); ++ ++ return 0; ++} ++ ++static int vdec_hevc_start(struct amvdec_session *sess) ++{ ++ int ret; ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ clk_set_rate(core->vdec_hevc_clk, 666666666); ++ ret = clk_prepare_enable(core->vdec_hevc_clk); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VDEC_HEVC, 0); ++ udelay(10); ++ ++ /* Reset VDEC_HEVC*/ ++ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); ++ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); ++ ++ amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff); ++ ++ /* VDEC_HEVC Memories */ ++ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000); ++ ++ /* Remove VDEC_HEVC Isolation */ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0); ++ ++ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); ++ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); ++ ++ vdec_hevc_stbuf_init(sess); ++ ++ ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path); ++ if (ret) ++ goto stop; ++ ++ ret = codec_ops->start(sess); ++ if (ret) ++ goto stop; ++ ++ amvdec_write_dos(core, DOS_SW_RESET3, BIT(12)|BIT(11)); ++ amvdec_write_dos(core, DOS_SW_RESET3, 0); ++ amvdec_read_dos(core, DOS_SW_RESET3); ++ ++ amvdec_write_dos(core, HEVC_MPSR, 1); ++ /* Let the firmware settle */ ++ udelay(10); ++ ++ return 0; ++ ++stop: ++ vdec_hevc_stop(sess); ++ return ret; ++} ++ ++struct amvdec_ops vdec_hevc_ops = { ++ .start = vdec_hevc_start, ++ .stop = vdec_hevc_stop, ++ .conf_esparser = vdec_hevc_conf_esparser, ++ .vififo_level = vdec_hevc_vififo_level, ++}; +diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.h b/drivers/staging/media/meson/vdec/vdec_hevc.h +new file mode 100644 +index 000000000000..54a611aded16 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/vdec_hevc.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * 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 __MESON_VDEC_VDEC_HEVC_H_ ++#define __MESON_VDEC_VDEC_HEVC_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_ops vdec_hevc_ops; ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c +index fb714d74753f..7318d7102874 100644 +--- a/drivers/staging/media/meson/vdec/vdec_platform.c ++++ b/drivers/staging/media/meson/vdec/vdec_platform.c +@@ -8,13 +8,25 @@ + #include "vdec.h" + + #include "vdec_1.h" ++#include "vdec_hevc.h" + #include "codec_mpeg12.h" + #include "codec_h264.h" + #include "codec_mpeg4.h" + #include "codec_mjpeg.h" ++#include "codec_hevc.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/gx/vh265_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MJPEG, + .min_buffers = 4, + .max_buffers = 4, +@@ -89,6 +101,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/gx/vh265_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MJPEG, + .min_buffers = 4, + .max_buffers = 4, +@@ -163,6 +185,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/gx/vh265_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MJPEG, + .min_buffers = 4, + .max_buffers = 4, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0124-TEMP-media-meson-vdec-add-VP9-input-support.patch b/packages/linux/patches/amlogic/amlogic-0124-TEMP-media-meson-vdec-add-VP9-input-support.patch new file mode 100644 index 0000000000..304c734f03 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0124-TEMP-media-meson-vdec-add-VP9-input-support.patch @@ -0,0 +1,155 @@ +From 46bf62b5b9e5b628cb6db164eef7a05c873f1ec4 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 17 Jan 2019 16:59:11 +0100 +Subject: [PATCH 124/186] TEMP: media: meson: vdec: add VP9 input support + +Amlogic VP9 decoder requires an additional 16-byte payload before every +frame header. + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/esparser.c | 101 +++++++++++++++++++- + 1 file changed, 97 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c +index 3a21a8cec799..97a4cd409c5f 100644 +--- a/drivers/staging/media/meson/vdec/esparser.c ++++ b/drivers/staging/media/meson/vdec/esparser.c +@@ -52,6 +52,7 @@ + #define PARSER_VIDEO_HOLE 0x90 + + #define SEARCH_PATTERN_LEN 512 ++#define VP9_HEADER_SIZE 16 + + static DECLARE_WAIT_QUEUE_HEAD(wq); + static int search_done; +@@ -74,14 +75,103 @@ static irqreturn_t esparser_isr(int irq, void *dev) + return IRQ_HANDLED; + } + ++/** ++ * VP9 frame headers need to be appended by a 16-byte long ++ * Amlogic custom header ++ */ ++static int vp9_update_header(struct vb2_buffer *buf) ++{ ++ uint8_t *dp; ++ uint8_t marker; ++ int dsize; ++ int num_frames, cur_frame; ++ int cur_mag, mag, mag_ptr; ++ int frame_size[8], tot_frame_size[8]; ++ int total_datasize = 0; ++ int new_frame_size; ++ unsigned char *old_header = NULL; ++ ++ dp = (uint8_t *) vb2_plane_vaddr(buf, 0); ++ dsize = vb2_get_plane_payload(buf, 0); ++ ++ marker = dp[dsize - 1]; ++ if ((marker & 0xe0) == 0xc0) { ++ num_frames = (marker & 0x7) + 1; ++ mag = ((marker >> 3) & 0x3) + 1; ++ mag_ptr = dsize - mag * num_frames - 2; ++ if (dp[mag_ptr] != marker) { ++ return 0; ++ } ++ mag_ptr++; ++ for (cur_frame = 0; cur_frame < num_frames; cur_frame++) { ++ frame_size[cur_frame] = 0; ++ for (cur_mag = 0; cur_mag < mag; cur_mag++) { ++ frame_size[cur_frame] |= (dp[mag_ptr] << (cur_mag * 8)); ++ mag_ptr++; ++ } ++ if (cur_frame == 0) ++ tot_frame_size[cur_frame] = frame_size[cur_frame]; ++ else ++ tot_frame_size[cur_frame] = tot_frame_size[cur_frame - 1] + frame_size[cur_frame]; ++ total_datasize += frame_size[cur_frame]; ++ } ++ } else { ++ num_frames = 1; ++ frame_size[0] = dsize; ++ tot_frame_size[0] = dsize; ++ total_datasize = dsize; ++ } ++ ++ new_frame_size = total_datasize + num_frames * VP9_HEADER_SIZE; ++ ++ for (cur_frame = num_frames - 1; cur_frame >= 0; cur_frame--) { ++ int framesize = frame_size[cur_frame]; ++ int framesize_header = framesize + 4; ++ int oldframeoff = tot_frame_size[cur_frame] - framesize; ++ int outheaderoff = oldframeoff + cur_frame * VP9_HEADER_SIZE; ++ uint8_t *fdata = dp + outheaderoff; ++ uint8_t *old_framedata = dp + oldframeoff; ++ ++ memmove(fdata + VP9_HEADER_SIZE, old_framedata, framesize); ++ ++ fdata[0] = (framesize_header >> 24) & 0xff; ++ fdata[1] = (framesize_header >> 16) & 0xff; ++ fdata[2] = (framesize_header >> 8) & 0xff; ++ fdata[3] = (framesize_header >> 0) & 0xff; ++ fdata[4] = ((framesize_header >> 24) & 0xff) ^0xff; ++ fdata[5] = ((framesize_header >> 16) & 0xff) ^0xff; ++ fdata[6] = ((framesize_header >> 8) & 0xff) ^0xff; ++ fdata[7] = ((framesize_header >> 0) & 0xff) ^0xff; ++ fdata[8] = 0; ++ fdata[9] = 0; ++ fdata[10] = 0; ++ fdata[11] = 1; ++ fdata[12] = 'A'; ++ fdata[13] = 'M'; ++ fdata[14] = 'L'; ++ fdata[15] = 'V'; ++ ++ if (!old_header) { ++ /* nothing */ ++ } else if (old_header > fdata + 16 + framesize) { ++ printk("data has gaps, setting to 0\n"); ++ memset(fdata + 16 + framesize, 0, (old_header - fdata + 16 + framesize)); ++ } else if (old_header < fdata + 16 + framesize) { ++ printk("data overwritten\n"); ++ } ++ old_header = fdata; ++ } ++ ++ return new_frame_size; ++} ++ + /* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger + * ISRs. + * Also append a start code 000001ff at the end to trigger + * the ESPARSER interrupt. + */ +-static u32 esparser_pad_start_code(struct vb2_buffer *vb) ++static u32 esparser_pad_start_code(struct vb2_buffer *vb, u32 payload_size) + { +- u32 payload_size = vb2_get_plane_payload(vb, 0); + u32 pad_size = 0; + u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size; + +@@ -190,7 +280,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) + if (codec_ops->num_pending_bufs) + num_dst_bufs = codec_ops->num_pending_bufs(sess); + +- num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx) - 1; + + if (esparser_vififo_get_free_space(sess) < payload_size || + atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) +@@ -204,7 +294,10 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) + dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n", + vb->timestamp, payload_size, offset); + +- pad_size = esparser_pad_start_code(vb); ++ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) ++ payload_size = vp9_update_header(vb); ++ ++ pad_size = esparser_pad_start_code(vb, payload_size); + ret = esparser_write_data(core, phy, payload_size + pad_size); + + if (ret <= 0) { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0125-TEMP-media-meson-vdec-add-VP9-support.patch b/packages/linux/patches/amlogic/amlogic-0125-TEMP-media-meson-vdec-add-VP9-support.patch new file mode 100644 index 0000000000..89ef1d229f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0125-TEMP-media-meson-vdec-add-VP9-support.patch @@ -0,0 +1,1235 @@ +From ef22bb6759186ef2b649de4def805e807de6c653 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 17 Jan 2019 17:00:11 +0100 +Subject: [PATCH 125/186] TEMP: media: meson: vdec: add VP9 support + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/Makefile | 2 +- + drivers/staging/media/meson/vdec/codec_vp9.c | 1083 +++++++++++++++++ + drivers/staging/media/meson/vdec/codec_vp9.h | 13 + + drivers/staging/media/meson/vdec/esparser.c | 4 +- + drivers/staging/media/meson/vdec/hevc_regs.h | 7 + + .../staging/media/meson/vdec/vdec_platform.c | 23 + + 6 files changed, 1130 insertions(+), 2 deletions(-) + create mode 100644 drivers/staging/media/meson/vdec/codec_vp9.c + create mode 100644 drivers/staging/media/meson/vdec/codec_vp9.h + +diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile +index 900dde088da0..aaa9c4310150 100644 +--- a/drivers/staging/media/meson/vdec/Makefile ++++ b/drivers/staging/media/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o vdec_hevc.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o codec_vp9.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/staging/media/meson/vdec/codec_vp9.c b/drivers/staging/media/meson/vdec/codec_vp9.c +new file mode 100644 +index 000000000000..731119b9ee17 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_vp9.c +@@ -0,0 +1,1083 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. ++ */ ++ ++#include ++#include ++ ++#include "codec_hevc.h" ++#include "dos_regs.h" ++#include "hevc_regs.h" ++#include "vdec_helpers.h" ++#include "codec_hevc_common.h" ++ ++/* HEVC reg mapping */ ++#define VP9_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 ++ #define VP9_10B_DECODE_SLICE 5 ++ #define VP9_HEAD_PARSER_DONE 0xf0 ++#define VP9_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 ++#define VP9_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2 ++#define VP9_ADAPT_PROB_REG HEVC_ASSIST_SCRATCH_3 ++#define VP9_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_4 ++#define VP9_PPS_BUFFER HEVC_ASSIST_SCRATCH_5 ++#define VP9_SAO_UP HEVC_ASSIST_SCRATCH_6 ++#define VP9_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 ++#define VP9_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 ++#define VP9_PROB_SWAP_BUFFER HEVC_ASSIST_SCRATCH_9 ++#define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A ++#define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B ++#define VP9_SCALELUT HEVC_ASSIST_SCRATCH_D ++#define VP9_WAIT_FLAG HEVC_ASSIST_SCRATCH_E ++#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F ++#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I ++#define VP9_DECODE_MODE HEVC_ASSIST_SCRATCH_J ++ #define DECODE_MODE_SINGLE 0 ++#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K ++#define HEVC_DECODE_COUNT HEVC_ASSIST_SCRATCH_M ++#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N ++ ++/* VP9 Constants */ ++#define LCU_SIZE 64 ++#define MAX_REF_PIC_NUM 24 ++#define REFS_PER_FRAME 3 ++#define REF_FRAMES 8 ++#define MV_MEM_UNIT 0x240 ++ ++enum FRAME_TYPE { ++ KEY_FRAME = 0, ++ INTER_FRAME = 1, ++ FRAME_TYPES, ++}; ++ ++/* VP9 Workspace layout */ ++#define MPRED_MV_BUF_SIZE 0x120000 ++ ++#define IPP_SIZE 0x4000 ++#define SAO_ABV_SIZE 0x30000 ++#define SAO_VB_SIZE 0x30000 ++#define SH_TM_RPS_SIZE 0x800 ++#define VPS_SIZE 0x800 ++#define SPS_SIZE 0x800 ++#define PPS_SIZE 0x2000 ++#define SAO_UP_SIZE 0x2800 ++#define SWAP_BUF_SIZE 0x800 ++#define SWAP_BUF2_SIZE 0x800 ++#define SCALELUT_SIZE 0x8000 ++#define DBLK_PARA_SIZE 0x80000 ++#define DBLK_DATA_SIZE 0x80000 ++#define SEG_MAP_SIZE 0xd800 ++#define PROB_SIZE 0x5000 ++#define COUNT_SIZE 0x3000 ++#define MMU_VBH_SIZE 0x5000 ++#define MPRED_ABV_SIZE 0x10000 ++#define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) ++#define RPM_BUF_SIZE 0x100 ++#define LMEM_SIZE 0x800 ++ ++#define IPP_OFFSET 0x00 ++#define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) ++#define SAO_VB_OFFSET (SAO_ABV_OFFSET + SAO_ABV_SIZE) ++#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + SAO_VB_SIZE) ++#define VPS_OFFSET (SH_TM_RPS_OFFSET + SH_TM_RPS_SIZE) ++#define SPS_OFFSET (VPS_OFFSET + VPS_SIZE) ++#define PPS_OFFSET (SPS_OFFSET + SPS_SIZE) ++#define SAO_UP_OFFSET (PPS_OFFSET + PPS_SIZE) ++#define SWAP_BUF_OFFSET (SAO_UP_OFFSET + SAO_UP_SIZE) ++#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + SWAP_BUF_SIZE) ++#define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) ++#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) ++#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) ++#define SEG_MAP_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) ++#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) ++#define MMU_VBH_OFFSET (COUNT_OFFSET + COUNT_SIZE) ++#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) ++#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) ++#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) ++#define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) ++ ++#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + LMEM_SIZE, 64 * SZ_1K) ++ ++#define NONE -1 ++#define INTRA_FRAME 0 ++#define LAST_FRAME 1 ++#define GOLDEN_FRAME 2 ++#define ALTREF_FRAME 3 ++#define MAX_REF_FRAMES 4 ++ ++/* ++ * Defines, declarations, sub-functions for vp9 de-block loop ++ filter Thr/Lvl table update ++ * - struct segmentation is for loop filter only (removed something) ++ * - function "vp9_loop_filter_init" and "vp9_loop_filter_frame_init" will ++ be instantiated in C_Entry ++ * - vp9_loop_filter_init run once before decoding start ++ * - vp9_loop_filter_frame_init run before every frame decoding start ++ * - set video format to VP9 is in vp9_loop_filter_init ++ */ ++#define MAX_LOOP_FILTER 63 ++#define MAX_REF_LF_DELTAS 4 ++#define MAX_MODE_LF_DELTAS 2 ++#define SEGMENT_DELTADATA 0 ++#define SEGMENT_ABSDATA 1 ++#define MAX_SEGMENTS 8 ++ ++union rpm_param { ++ struct { ++ u16 data[RPM_BUF_SIZE]; ++ } l; ++ struct { ++ u16 profile; ++ u16 show_existing_frame; ++ u16 frame_to_show_idx; ++ u16 frame_type; /*1 bit*/ ++ u16 show_frame; /*1 bit*/ ++ u16 error_resilient_mode; /*1 bit*/ ++ u16 intra_only; /*1 bit*/ ++ u16 display_size_present; /*1 bit*/ ++ u16 reset_frame_context; ++ u16 refresh_frame_flags; ++ u16 width; ++ u16 height; ++ u16 display_width; ++ u16 display_height; ++ u16 ref_info; ++ u16 same_frame_size; ++ u16 mode_ref_delta_enabled; ++ u16 ref_deltas[4]; ++ u16 mode_deltas[2]; ++ u16 filter_level; ++ u16 sharpness_level; ++ u16 bit_depth; ++ u16 seg_quant_info[8]; ++ u16 seg_enabled; ++ u16 seg_abs_delta; ++ /* bit 15: feature enabled; bit 8, sign; bit[5:0], data */ ++ u16 seg_lf_info[8]; ++ } p; ++}; ++ ++enum SEG_LVL_FEATURES { ++ SEG_LVL_ALT_Q = 0, /* Use alternate Quantizer */ ++ SEG_LVL_ALT_LF = 1, /* Use alternate loop filter value */ ++ SEG_LVL_REF_FRAME = 2, /* Optional Segment reference frame */ ++ SEG_LVL_SKIP = 3, /* Optional Segment (0,0) + skip mode */ ++ SEG_LVL_MAX = 4 /* Number of features supported */ ++}; ++ ++struct segmentation { ++ uint8_t enabled; ++ uint8_t update_map; ++ uint8_t update_data; ++ uint8_t abs_delta; ++ uint8_t temporal_update; ++ int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX]; ++ unsigned int feature_mask[MAX_SEGMENTS]; ++}; ++ ++struct loop_filter_thresh { ++ uint8_t mblim; ++ uint8_t lim; ++ uint8_t hev_thr; ++}; ++ ++struct loop_filter_info_n { ++ struct loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1]; ++ uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS]; ++}; ++ ++struct loopfilter { ++ int filter_level; ++ ++ int sharpness_level; ++ int last_sharpness_level; ++ ++ uint8_t mode_ref_delta_enabled; ++ uint8_t mode_ref_delta_update; ++ ++ /*0 = Intra, Last, GF, ARF*/ ++ signed char ref_deltas[MAX_REF_LF_DELTAS]; ++ signed char last_ref_deltas[MAX_REF_LF_DELTAS]; ++ ++ /*0 = ZERO_MV, MV*/ ++ signed char mode_deltas[MAX_MODE_LF_DELTAS]; ++ signed char last_mode_deltas[MAX_MODE_LF_DELTAS]; ++}; ++ ++struct vp9_frame { ++ struct list_head list; ++ struct vb2_v4l2_buffer *vbuf; ++ int index; ++ int intra_only; ++ int show; ++ int type; ++ int done; ++}; ++ ++struct codec_vp9 { ++ struct mutex lock; ++ ++ /* Buffer for the VP9 Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++ ++ /* Contains many information parsed from the bitstream */ ++ union rpm_param rpm_param; ++ ++ /* Whether we detected the bitstream as 10-bit */ ++ int is_10bit; ++ ++ /* Coded resolution reported by the hardware */ ++ u32 width, height; ++ ++ /* All ref frames used by the HW at a given time */ ++ struct list_head ref_frames_list; ++ u32 frames_num; ++ ++ /* In case of downsampling (decoding with FBC but outputting in NV12M), ++ * we need to allocate additional buffers for FBC. ++ */ ++ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; ++ ++ int ref_frame_map[REF_FRAMES]; ++ int next_ref_frame_map[REF_FRAMES]; ++ struct vp9_frame* frame_refs[REFS_PER_FRAME]; ++ ++ u32 lcu_total; ++ ++ /* loop filter */ ++ int default_filt_lvl; ++ struct loop_filter_info_n lfi; ++ struct loopfilter lf; ++ struct segmentation seg_4lf; ++ ++ struct vp9_frame *cur_frame; ++ struct vp9_frame *prev_frame; ++}; ++ ++static int vp9_clamp(int value, int low, int high) ++{ ++ return value < low ? low : (value > high ? high : value); ++} ++ ++static int segfeature_active(struct segmentation *seg, ++ int segment_id, ++ enum SEG_LVL_FEATURES feature_id) ++{ ++ return seg->enabled && ++ (seg->feature_mask[segment_id] & (1 << feature_id)); ++} ++ ++static int get_segdata(struct segmentation *seg, int segment_id, ++ enum SEG_LVL_FEATURES feature_id) ++{ ++ return seg->feature_data[segment_id][feature_id]; ++} ++ ++static void vp9_update_sharpness(struct loop_filter_info_n *lfi, ++ int sharpness_lvl) ++{ ++ int lvl; ++ /*For each possible value for the loop filter fill out limits*/ ++ for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) { ++ /*Set loop filter parameters that control sharpness.*/ ++ int block_inside_limit = lvl >> ((sharpness_lvl > 0) + ++ (sharpness_lvl > 4)); ++ ++ if (sharpness_lvl > 0) { ++ if (block_inside_limit > (9 - sharpness_lvl)) ++ block_inside_limit = (9 - sharpness_lvl); ++ } ++ ++ if (block_inside_limit < 1) ++ block_inside_limit = 1; ++ ++ lfi->lfthr[lvl].lim = (uint8_t)block_inside_limit; ++ lfi->lfthr[lvl].mblim = (uint8_t)(2 * (lvl + 2) + ++ block_inside_limit); ++ } ++} ++ ++/*instantiate this function once when decode is started*/ ++static void ++vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9) ++{ ++ struct loop_filter_info_n *lfi = &vp9->lfi; ++ struct loopfilter *lf = &vp9->lf; ++ struct segmentation *seg_4lf = &vp9->seg_4lf; ++ int i; ++ ++ memset(lfi, 0, sizeof(struct loop_filter_info_n)); ++ memset(lf, 0, sizeof(struct loopfilter)); ++ memset(seg_4lf, 0, sizeof(struct segmentation)); ++ lf->sharpness_level = 0; ++ vp9_update_sharpness(lfi, lf->sharpness_level); ++ lf->last_sharpness_level = lf->sharpness_level; ++ ++ for (i = 0; i < 32; i++) { ++ unsigned int thr; ++ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f)<<8) | ++ (lfi->lfthr[i * 2 + 1].mblim & 0xff); ++ thr = (thr<<16) | ((lfi->lfthr[i*2].lim & 0x3f)<<8) | ++ (lfi->lfthr[i * 2].mblim & 0xff); ++ amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); ++ } ++ ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); ++} ++ ++static void ++vp9_loop_filter_frame_init(struct amvdec_core *core, struct segmentation *seg, ++ struct loop_filter_info_n *lfi, ++ struct loopfilter *lf, int default_filt_lvl) ++{ ++ int i; ++ int seg_id; ++ /*n_shift is the multiplier for lf_deltas ++ the multiplier is 1 for when filter_lvl is between 0 and 31; ++ 2 when filter_lvl is between 32 and 63*/ ++ const int scale = 1 << (default_filt_lvl >> 5); ++ ++ /*update limits if sharpness has changed*/ ++ if (lf->last_sharpness_level != lf->sharpness_level) { ++ vp9_update_sharpness(lfi, lf->sharpness_level); ++ lf->last_sharpness_level = lf->sharpness_level; ++ ++ /*Write to register*/ ++ for (i = 0; i < 32; i++) { ++ unsigned int thr; ++ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f) << 8) ++ | (lfi->lfthr[i * 2 + 1].mblim & 0xff); ++ thr = (thr << 16) | ((lfi->lfthr[i * 2].lim & 0x3f) << 8) ++ | (lfi->lfthr[i * 2].mblim & 0xff); ++ amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); ++ } ++ } ++ ++ for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {/*MAX_SEGMENTS = 8*/ ++ int lvl_seg = default_filt_lvl; ++ if (segfeature_active(seg, seg_id, SEG_LVL_ALT_LF)) { ++ const int data = get_segdata(seg, seg_id, ++ SEG_LVL_ALT_LF); ++ lvl_seg = vp9_clamp(seg->abs_delta == SEGMENT_ABSDATA ? ++ data : default_filt_lvl + data, ++ 0, MAX_LOOP_FILTER); ++ } ++ ++ if (!lf->mode_ref_delta_enabled) { ++ /*we could get rid of this if we assume that deltas are set to ++ zero when not in use; encoder always uses deltas*/ ++ memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id])); ++ } else { ++ int ref, mode; ++ const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] ++ * scale; ++ lfi->lvl[seg_id][INTRA_FRAME][0] = ++ vp9_clamp(intra_lvl, 0, MAX_LOOP_FILTER); ++ ++ for (ref = LAST_FRAME; ref < MAX_REF_FRAMES; ++ref) { ++ /* LAST_FRAME = 1, MAX_REF_FRAMES = 4*/ ++ for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) { ++ /*MAX_MODE_LF_DELTAS = 2*/ ++ const int inter_lvl = ++ lvl_seg + lf->ref_deltas[ref] * scale ++ + lf->mode_deltas[mode] * scale; ++ lfi->lvl[seg_id][ref][mode] = ++ vp9_clamp(inter_lvl, 0, ++ MAX_LOOP_FILTER); ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i < 16; i++) { ++ unsigned int level; ++ level = ((lfi->lvl[i >> 1][3][i & 1] & 0x3f) << 24) | ++ ((lfi->lvl[i >> 1][2][i & 1] & 0x3f) << 16) | ++ ((lfi->lvl[i >> 1][1][i & 1] & 0x3f) << 8) | ++ (lfi->lvl[i >> 1][0][i & 1] & 0x3f); ++ if (!default_filt_lvl) ++ level = 0; ++ amvdec_write_dos(core, HEVC_DBLK_CFGA, level); ++ } ++} ++ ++static void codec_vp9_flush_output(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ struct vp9_frame *tmp, *n; ++ ++ list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) { ++ if (!tmp->done) { ++ if (tmp->show) ++ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); ++ else ++ v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf); ++ vp9->frames_num--; ++ } ++ ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++} ++ ++static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ if (!vp9) ++ return 0; ++ ++ return vp9->frames_num; ++} ++ ++static int ++codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) ++{ ++ dma_addr_t wkaddr; ++ ++ /* Allocate some memory for the VP9 decoder's state */ ++ vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &wkaddr, GFP_KERNEL); ++ if (!vp9->workspace_vaddr) { ++ dev_err(core->dev, "Failed to allocate VP9 Workspace\n"); ++ return -ENOMEM; ++ } ++ ++ vp9->workspace_paddr = wkaddr; ++ ++ amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); ++ amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET); ++ amvdec_write_dos(core, VP9_SHORT_TERM_RPS, wkaddr + SH_TM_RPS_OFFSET); ++ amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET); ++ amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET); ++ ++ /* No MMU */ ++ amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER, ++ wkaddr + SWAP_BUF_OFFSET); ++ amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, ++ wkaddr + SWAP_BUF2_OFFSET); ++ amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); ++ amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET); ++ amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET); ++ amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); ++ ++ return 0; ++} ++ ++static int codec_vp9_start(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9; ++ u32 val; ++ int i; ++ int ret; ++ ++ vp9 = kzalloc(sizeof(*vp9), GFP_KERNEL); ++ if (!vp9) ++ return -ENOMEM; ++ ++ ret = codec_vp9_setup_workspace(core, vp9); ++ if (ret) ++ goto free_vp9; ++ ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ ++ val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff; ++ val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0); ++ amvdec_write_dos(core, HEVC_PARSER_INT_CONTROL, val); ++ amvdec_write_dos_bits(core, HEVC_SHIFT_STATUS, BIT(0)); ++ amvdec_write_dos(core, HEVC_SHIFT_CONTROL, BIT(10) | BIT(9) | ++ (3 << 6) | BIT(5) | BIT(2) | BIT(1) | BIT(0)); ++ amvdec_write_dos(core, HEVC_CABAC_CONTROL, BIT(0)); ++ amvdec_write_dos(core, HEVC_PARSER_CORE_CONTROL, BIT(0)); ++ amvdec_write_dos(core, HEVC_SHIFT_STARTCODE, 0x00000001); ++ ++ amvdec_write_dos(core, VP9_DEC_STATUS_REG, 0); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); ++ for (i = 0; i < ARRAY_SIZE(vdec_hevc_parser_cmd); ++i) ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, ++ vdec_hevc_parser_cmd[i]); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2); ++ amvdec_write_dos(core, HEVC_PARSER_IF_CONTROL, ++ BIT(5) | BIT(2) | BIT(0)); ++ ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(0)); ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(1)); ++ ++ amvdec_write_dos(core, VP9_WAIT_FLAG, 1); ++ ++ /* clear mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_CLR_REG, 1); ++ /* enable mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 1); ++ /* disable PSCALE for hardware sharing */ ++ amvdec_write_dos(core, HEVC_PSCALE_CTRL, 0); ++ /* Let the uCode do all the parsing */ ++ amvdec_write_dos(core, NAL_SEARCH_CTL, 0x8); ++ ++ amvdec_write_dos(core, DECODE_STOP_POS, 0); ++ amvdec_write_dos(core, VP9_DECODE_MODE, DECODE_MODE_SINGLE); ++ ++ printk("decode_count: %u; decode_size: %u\n", amvdec_read_dos(core, HEVC_DECODE_COUNT), amvdec_read_dos(core, HEVC_DECODE_SIZE)); ++ ++ vp9_loop_filter_init(core, vp9); ++ ++ INIT_LIST_HEAD(&vp9->ref_frames_list); ++ mutex_init(&vp9->lock); ++ memset(&vp9->ref_frame_map, -1, sizeof(vp9->ref_frame_map)); ++ memset(&vp9->next_ref_frame_map, -1, sizeof(vp9->next_ref_frame_map)); ++ sess->priv = vp9; ++ ++ return 0; ++ ++free_vp9: ++ kfree(vp9); ++ return ret; ++} ++ ++static int codec_vp9_stop(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ if (vp9->workspace_vaddr) ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ vp9->workspace_vaddr, ++ vp9->workspace_paddr); ++ ++ codec_hevc_free_fbc_buffers(sess); ++ return 0; ++} ++ ++static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ dma_addr_t buf_y_paddr; ++ dma_addr_t buf_u_v_paddr; ++ u32 val; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit)) ++ buf_y_paddr = ++ sess->fbc_buffer_paddr[vb->index]; ++ else ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(vb, 0); ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); ++ } ++ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(vb, 0); ++ buf_u_v_paddr = ++ vb2_dma_contig_plane_dma_addr(vb, 1); ++ amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr); ++ amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); ++ } ++ ++ amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, ++ amvdec_get_output_size(sess)); ++ amvdec_write_dos(core, HEVC_SAO_C_LENGTH, ++ (amvdec_get_output_size(sess) / 2)); ++ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; ++ val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ ++ amvdec_write_dos(core, HEVC_SAO_CTRL1, val); ++ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { ++ /* no downscale for NV12 */ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ } ++ ++ val = amvdec_read_dos(core, HEVCD_IPP_AXIIF_CONFIG) & ~0x30; ++ val |= 0xf; ++ amvdec_write_dos(core, HEVCD_IPP_AXIIF_CONFIG, val); ++} ++ ++static dma_addr_t codec_vp9_get_frame_mv_paddr(struct codec_vp9 *vp9, ++ struct vp9_frame *frame) ++{ ++ return vp9->workspace_paddr + MPRED_MV_OFFSET + ++ (frame->index * MPRED_MV_BUF_SIZE); ++} ++ ++static void codec_vp9_set_mpred_mv(struct amvdec_core *core, ++ struct codec_vp9 *vp9) ++{ ++ int mpred_mv_rd_end_addr; ++ int use_prev_frame_mvs = !vp9->prev_frame->intra_only && ++ vp9->prev_frame->show && ++ vp9->prev_frame->type != KEY_FRAME; ++ ++ amvdec_write_dos(core, HEVC_MPRED_CTRL3, 0x24122412); ++ amvdec_write_dos(core, HEVC_MPRED_ABV_START_ADDR, ++ vp9->workspace_paddr + MPRED_ABV_OFFSET); ++ ++ amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); ++ if (use_prev_frame_mvs) ++ amvdec_write_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_WR_START_ADDR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame)); ++ amvdec_write_dos(core, HEVC_MPRED_MV_WPTR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame)); ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_START_ADDR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame)); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame)); ++ ++ mpred_mv_rd_end_addr = codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame) ++ + (vp9->lcu_total * MV_MEM_UNIT); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr); ++} ++ ++static void codec_vp9_update_next_ref(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ u32 buf_idx = vp9->cur_frame->index; ++ int ref_index = 0; ++ int refresh_frame_flags; ++ int mask; ++ ++ refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ? 0xff : ++ param->p.refresh_frame_flags; ++ ++ for (mask = refresh_frame_flags; mask; mask >>= 1) { ++ //printk("mask=%08X; ref_index=%d\n", mask, ref_index); ++ if (mask & 1) ++ vp9->next_ref_frame_map[ref_index] = buf_idx; ++ else ++ vp9->next_ref_frame_map[ref_index] = ++ vp9->ref_frame_map[ref_index]; ++ ++ ++ref_index; ++ } ++ ++ for (; ref_index < REF_FRAMES; ++ref_index) ++ vp9->next_ref_frame_map[ref_index] = ++ vp9->ref_frame_map[ref_index]; ++} ++ ++static void codec_vp9_update_ref(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int ref_index = 0; ++ int mask; ++ int refresh_frame_flags; ++ ++ if (!vp9->cur_frame) ++ return; ++ ++ refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ? ++ 0xff : ++ param->p.refresh_frame_flags; ++ ++ for (mask = refresh_frame_flags; mask; mask >>= 1) { ++ vp9->ref_frame_map[ref_index] = ++ vp9->next_ref_frame_map[ref_index]; ++ ++ref_index; ++ } ++ ++ if (param->p.show_existing_frame) ++ return; ++ ++ for (; ref_index < REF_FRAMES; ++ref_index) ++ vp9->ref_frame_map[ref_index] = ++ vp9->next_ref_frame_map[ref_index]; ++} ++ ++static struct vp9_frame * codec_vp9_get_frame_by_idx(struct codec_vp9 *vp9, int idx) ++{ ++ struct vp9_frame *frame; ++ ++ list_for_each_entry(frame, &vp9->ref_frames_list, list) { ++ if (frame->index == idx) ++ return frame; ++ } ++ ++ return NULL; ++} ++ ++static void codec_vp9_sync_ref(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int i; ++ ++ for (i = 0; i < REFS_PER_FRAME; ++i) { ++ const int ref = (param->p.ref_info >> ++ (((REFS_PER_FRAME-i-1)*4)+1)) & 0x7; ++ const int idx = vp9->ref_frame_map[ref]; ++ ++ vp9->frame_refs[i] = codec_vp9_get_frame_by_idx(vp9, idx); ++ } ++} ++ ++static void codec_vp9_set_refs(struct amvdec_session *sess, ++ struct codec_vp9 *vp9) ++{ ++ struct amvdec_core *core = sess->core; ++ int i; ++ ++ for (i = 0; i < REFS_PER_FRAME; ++i) { ++ struct vp9_frame *frame = vp9->frame_refs[i]; ++ int id_y; ++ int id_u_v; ++ ++ if (!frame) ++ continue; ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { ++ id_y = frame->index; ++ id_u_v = id_y; ++ } else { ++ id_y = frame->index * 2; ++ id_u_v = id_y + 1; ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, ++ (id_u_v << 16) | (id_u_v << 8) | id_y); ++ } ++} ++ ++static void codec_vp9_set_mc(struct amvdec_session *sess, ++ struct codec_vp9 *vp9) ++{ ++ struct amvdec_core *core = sess->core; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ codec_vp9_set_refs(sess, vp9); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (16 << 8) | 1); ++ codec_vp9_set_refs(sess, vp9); ++ ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_TBL_ACCCONFIG, BIT(2)); ++ for (i = 0; i < REFS_PER_FRAME; ++i) { ++ if (!vp9->frame_refs[i]) ++ continue; ++ ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, vp9->width); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, vp9->height); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, ++ (vp9->width << 14) / vp9->width); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, ++ (vp9->height << 14) / vp9->height); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, ++ amvdec_am21c_body_size(vp9->width, vp9->height) >> 5); ++ } ++ ++ amvdec_write_dos(core, VP9D_MPP_REF_SCALE_ENBL, 0); ++} ++ ++static struct vp9_frame *codec_vp9_get_new_frame(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ union rpm_param *param = &vp9->rpm_param; ++ struct vb2_v4l2_buffer *vbuf; ++ struct vp9_frame *new_frame; ++ ++ new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL); ++ if (!new_frame) ++ return NULL; ++ ++ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); ++ if (!vbuf) { ++ dev_err(sess->core->dev, "No dst buffer available\n"); ++ kfree(new_frame); ++ return NULL; ++ } ++ ++ while (codec_vp9_get_frame_by_idx(vp9, vbuf->vb2_buf.index)) { ++ struct vb2_v4l2_buffer *old_vbuf = vbuf; ++ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); ++ v4l2_m2m_buf_queue(sess->m2m_ctx, old_vbuf); ++ if (!vbuf) { ++ dev_err(sess->core->dev, "No dst buffer available\n"); ++ kfree(new_frame); ++ return NULL; ++ } ++ } ++ ++ new_frame->vbuf = vbuf; ++ new_frame->index = vbuf->vb2_buf.index; ++ new_frame->intra_only = param->p.intra_only; ++ new_frame->show = param->p.show_frame; ++ new_frame->type = param->p.frame_type; ++ list_add_tail(&new_frame->list, &vp9->ref_frames_list); ++ vp9->frames_num++; ++ ++ return new_frame; ++} ++ ++static void codec_vp9_show_existing_frame(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ ++ if (!param->p.show_existing_frame) ++ return; ++ ++ printk("showing frame %u\n", param->p.frame_to_show_idx); ++} ++ ++static void codec_vp9_rm_noshow_frame(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ struct vp9_frame *tmp; ++ ++ list_for_each_entry(tmp, &vp9->ref_frames_list, list) { ++ if (tmp->show) ++ continue; ++ ++ printk("rm noshow: %u\n", tmp->index); ++ v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf); ++ list_del(&tmp->list); ++ kfree(tmp); ++ vp9->frames_num--; ++ return; ++ } ++} ++ ++static void codec_vp9_process_frame(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ union rpm_param *param = &vp9->rpm_param; ++ int intra_only; ++ ++ if (!param->p.show_frame) ++ codec_vp9_rm_noshow_frame(sess); ++ ++ vp9->cur_frame = codec_vp9_get_new_frame(sess); ++ if (!vp9->cur_frame) ++ return; ++ ++ printk("frame type: %08X; show_exist: %u; show: %u, intra_only: %u\n", param->p.frame_type, param->p.show_existing_frame, param->p.show_frame, param->p.intra_only); ++ codec_vp9_sync_ref(vp9); ++ codec_vp9_update_next_ref(vp9); ++ codec_vp9_show_existing_frame(vp9); ++ ++ intra_only = param->p.show_frame ? 0 : param->p.intra_only; ++ /* clear mpred (for keyframe only) */ ++ if (param->p.frame_type != KEY_FRAME && !intra_only) { ++ codec_vp9_set_mc(sess, vp9); ++ codec_vp9_set_mpred_mv(core, vp9); ++ } else { ++ amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); ++ } ++ ++ amvdec_write_dos(core, HEVC_PARSER_PICTURE_SIZE, ++ (vp9->height << 16) | vp9->width); ++ codec_vp9_set_sao(sess, &vp9->cur_frame->vbuf->vb2_buf); ++ ++ vp9_loop_filter_frame_init(core, &vp9->seg_4lf, ++ &vp9->lfi, &vp9->lf, vp9->default_filt_lvl); ++ ++ /* ask uCode to start decoding */ ++ amvdec_write_dos(core, VP9_DEC_STATUS_REG, VP9_10B_DECODE_SLICE); ++} ++ ++static void codec_vp9_process_lf(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int i; ++ ++ vp9->lf.mode_ref_delta_enabled = param->p.mode_ref_delta_enabled; ++ vp9->lf.sharpness_level = param->p.sharpness_level; ++ vp9->default_filt_lvl = param->p.filter_level; ++ vp9->seg_4lf.enabled = param->p.seg_enabled; ++ vp9->seg_4lf.abs_delta = param->p.seg_abs_delta; ++ ++ for (i = 0; i < 4; i++) ++ vp9->lf.ref_deltas[i] = param->p.ref_deltas[i]; ++ ++ for (i = 0; i < 2; i++) ++ vp9->lf.mode_deltas[i] = param->p.mode_deltas[i]; ++ ++ for (i = 0; i < MAX_SEGMENTS; i++) ++ vp9->seg_4lf.feature_mask[i] = (param->p.seg_lf_info[i] & ++ 0x8000) ? (1 << SEG_LVL_ALT_LF) : 0; ++ ++ for (i = 0; i < MAX_SEGMENTS; i++) ++ vp9->seg_4lf.feature_data[i][SEG_LVL_ALT_LF] ++ = (param->p.seg_lf_info[i] ++ & 0x100) ? -(param->p.seg_lf_info[i] ++ & 0x3f) : (param->p.seg_lf_info[i] & 0x3f); ++} ++ ++static void codec_vp9_resume(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ if (codec_hevc_setup_buffers(sess, vp9->is_10bit)) { ++ amvdec_abort(sess); ++ return; ++ } ++ ++ codec_hevc_setup_decode_head(sess, vp9->is_10bit); ++ codec_vp9_process_lf(vp9); ++ codec_vp9_process_frame(sess); ++} ++ ++/** ++ * The RPM section within the workspace contains ++ * many information regarding the parsed bitstream ++ */ ++static void codec_vp9_fetch_rpm(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ u16 *rpm_vaddr = vp9->workspace_vaddr + RPM_OFFSET; ++ int i, j; ++ ++ for (i = 0; i < RPM_BUF_SIZE; i += 4) ++ for (j = 0; j < 4; j++) ++ vp9->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j]; ++} ++ ++static int codec_vp9_process_rpm(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int src_changed = 0; ++ int is_10bit = 0; ++ int pic_width_64 = ALIGN(param->p.width, 64); ++ int pic_height_32 = ALIGN(param->p.height, 32); ++ int pic_width_lcu = (pic_width_64 % LCU_SIZE) ? ++ pic_width_64 / LCU_SIZE + 1 ++ : pic_width_64 / LCU_SIZE; ++ int pic_height_lcu = (pic_height_32 % LCU_SIZE) ? ++ pic_height_32 / LCU_SIZE + 1 ++ : pic_height_32 / LCU_SIZE; ++ vp9->lcu_total = pic_width_lcu * pic_height_lcu; ++ ++ if (param->p.bit_depth == 10) ++ is_10bit = 1; ++ ++ if (vp9->width != param->p.width || ++ vp9->height != param->p.height || ++ vp9->is_10bit != is_10bit) ++ src_changed = 1; ++ ++ vp9->width = param->p.width; ++ vp9->height = param->p.height; ++ vp9->is_10bit = is_10bit; ++ ++ printk("width: %u; height: %u; is_10bit: %d; src_changed: %d\n", vp9->width, vp9->height, is_10bit, src_changed); ++ return src_changed; ++} ++ ++static bool codec_vp9_is_ref(struct codec_vp9 *vp9, struct vp9_frame *frame) ++{ ++ int i; ++ ++ for (i = 0; i < REFS_PER_FRAME; ++i) ++ if (vp9->frame_refs[i] == frame) ++ return true; ++ ++ return false; ++} ++ ++static void codec_vp9_show_frame(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ struct vp9_frame *tmp, *n; ++ ++ list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) { ++ if (!tmp->show || tmp == vp9->cur_frame) ++ continue; ++ ++ if (!tmp->done) { ++ printk("Doning %u\n", tmp->index); ++ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); ++ tmp->done = 1; ++ vp9->frames_num--; ++ } ++ ++ if (codec_vp9_is_ref(vp9, tmp)) ++ continue; ++ ++ printk("deleting %d\n", tmp->index); ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++} ++ ++static irqreturn_t codec_vp9_threaded_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ u32 dec_status = amvdec_read_dos(core, VP9_DEC_STATUS_REG); ++ u32 prob_status = amvdec_read_dos(core, VP9_ADAPT_PROB_REG); ++ int i; ++ ++ if (!vp9) ++ return IRQ_HANDLED; ++ ++ mutex_lock(&vp9->lock); ++ if (dec_status != VP9_HEAD_PARSER_DONE) { ++ dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n", ++ dec_status); ++ amvdec_abort(sess); ++ goto unlock; ++ } ++ ++ printk("ISR: %08X;%08X\n", dec_status, prob_status); ++ sess->keyframe_found = 1; ++ ++ /* Invalidate first 3 refs */ ++ for (i = 0; i < 3; ++i) ++ vp9->frame_refs[i] = NULL; ++ ++ vp9->prev_frame = vp9->cur_frame; ++ codec_vp9_update_ref(vp9); ++ ++ codec_vp9_fetch_rpm(sess); ++ if (codec_vp9_process_rpm(vp9)) { ++ amvdec_src_change(sess, vp9->width, vp9->height, 16); ++ goto unlock; ++ } ++ ++ codec_vp9_process_lf(vp9); ++ codec_vp9_process_frame(sess); ++ codec_vp9_show_frame(sess); ++ ++unlock: ++ mutex_unlock(&vp9->lock); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t codec_vp9_isr(struct amvdec_session *sess) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++struct amvdec_codec_ops codec_vp9_ops = { ++ .start = codec_vp9_start, ++ .stop = codec_vp9_stop, ++ .isr = codec_vp9_isr, ++ .threaded_isr = codec_vp9_threaded_isr, ++ .num_pending_bufs = codec_vp9_num_pending_bufs, ++ .drain = codec_vp9_flush_output, ++ .resume = codec_vp9_resume, ++}; +diff --git a/drivers/staging/media/meson/vdec/codec_vp9.h b/drivers/staging/media/meson/vdec/codec_vp9.h +new file mode 100644 +index 000000000000..62db65a2b939 +--- /dev/null ++++ b/drivers/staging/media/meson/vdec/codec_vp9.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_VP9_H_ ++#define __MESON_VDEC_CODEC_VP9_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_vp9_ops; ++ ++#endif +diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c +index 97a4cd409c5f..12c26d98bd65 100644 +--- a/drivers/staging/media/meson/vdec/esparser.c ++++ b/drivers/staging/media/meson/vdec/esparser.c +@@ -280,7 +280,9 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) + if (codec_ops->num_pending_bufs) + num_dst_bufs = codec_ops->num_pending_bufs(sess); + +- num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx) - 1; ++ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) ++ num_dst_bufs -= 2; + + if (esparser_vififo_get_free_space(sess) < payload_size || + atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) +diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h +index ba49f906be5a..c80479d7c9c3 100644 +--- a/drivers/staging/media/meson/vdec/hevc_regs.h ++++ b/drivers/staging/media/meson/vdec/hevc_regs.h +@@ -120,6 +120,8 @@ + #define HEVC_MPRED_L0_REF00_POC 0xc880 + #define HEVC_MPRED_L1_REF00_POC 0xc8c0 + ++#define HEVC_MPRED_CTRL4 0xc930 ++ + #define HEVC_MPRED_CUR_POC 0xc980 + #define HEVC_MPRED_COL_POC 0xc984 + #define HEVC_MPRED_MV_RD_END_ADDR 0xc988 +@@ -138,6 +140,10 @@ + #define HEVCD_IPP_LINEBUFF_BASE 0xd024 + #define HEVCD_IPP_AXIIF_CONFIG 0xd02c + ++#define VP9D_MPP_REF_SCALE_ENBL 0xd104 ++#define VP9D_MPP_REFINFO_TBL_ACCCONFIG 0xd108 ++#define VP9D_MPP_REFINFO_DATA 0xd10c ++ + #define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180 + #define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184 + #define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190 +@@ -162,6 +168,7 @@ + #define HEVC_DBLK_CFG9 0xd424 + #define HEVC_DBLK_CFGA 0xd428 + #define HEVC_DBLK_STS0 0xd42c ++#define HEVC_DBLK_CFGB 0xd42c + #define HEVC_DBLK_STS1 0xd430 + + #define HEVC_SAO_VERSION 0xd800 +diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c +index 7318d7102874..3c51bf991a3b 100644 +--- a/drivers/staging/media/meson/vdec/vdec_platform.c ++++ b/drivers/staging/media/meson/vdec/vdec_platform.c +@@ -14,6 +14,7 @@ + #include "codec_mpeg4.h" + #include "codec_mjpeg.h" + #include "codec_hevc.h" ++#include "codec_vp9.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { +@@ -100,6 +101,17 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + }; + + static const struct amvdec_format vdec_formats_gxl[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_VP9, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_vp9_ops, ++ .firmware_path = "meson/gx/vvp9_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, + { + .pixfmt = V4L2_PIX_FMT_HEVC, + .min_buffers = 16, +@@ -184,6 +196,17 @@ static const struct amvdec_format vdec_formats_gxl[] = { + }; + + static const struct amvdec_format vdec_formats_gxm[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_VP9, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_vp9_ops, ++ .firmware_path = "meson/gx/vvp9_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, + { + .pixfmt = V4L2_PIX_FMT_HEVC, + .min_buffers = 16, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0126-TEMP-media-meson-vdec-add-g12a-platform.patch b/packages/linux/patches/amlogic/amlogic-0126-TEMP-media-meson-vdec-add-g12a-platform.patch new file mode 100644 index 0000000000..02d07ee2e5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0126-TEMP-media-meson-vdec-add-g12a-platform.patch @@ -0,0 +1,458 @@ +From e4e68531b714bce056617e30a37190aac9931463 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 7 Feb 2019 17:37:34 +0100 +Subject: [PATCH 126/186] TEMP: media: meson: vdec: add g12a platform + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/codec_hevc.c | 38 +++++-- + .../media/meson/vdec/codec_hevc_common.c | 9 -- + drivers/staging/media/meson/vdec/codec_vp9.c | 54 ++++++++-- + drivers/staging/media/meson/vdec/hevc_regs.h | 1 + + drivers/staging/media/meson/vdec/vdec.c | 13 ++- + drivers/staging/media/meson/vdec/vdec.h | 1 + + drivers/staging/media/meson/vdec/vdec_hevc.c | 9 ++ + .../staging/media/meson/vdec/vdec_platform.c | 101 ++++++++++++++++++ + .../staging/media/meson/vdec/vdec_platform.h | 2 + + 9 files changed, 204 insertions(+), 24 deletions(-) + +diff --git a/drivers/staging/media/meson/vdec/codec_hevc.c b/drivers/staging/media/meson/vdec/codec_hevc.c +index 03f00f969f02..e16e937d56e8 100644 +--- a/drivers/staging/media/meson/vdec/codec_hevc.c ++++ b/drivers/staging/media/meson/vdec/codec_hevc.c +@@ -68,7 +68,8 @@ + #define SWAP_BUF2_SIZE 0x800 + #define SCALELUT_SIZE 0x8000 + #define DBLK_PARA_SIZE 0x20000 +-#define DBLK_DATA_SIZE 0x40000 ++#define DBLK_DATA_SIZE 0x80000 ++#define DBLK_DATA2_SIZE 0x80000 + #define MMU_VBH_SIZE 0x5000 + #define MPRED_ABV_SIZE 0x8000 + #define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) +@@ -88,7 +89,8 @@ + #define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) + #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) + #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) +-#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define DBLK_DATA2_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define MMU_VBH_OFFSET (DBLK_DATA2_OFFSET + DBLK_DATA2_SIZE) + #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) + #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) + #define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) +@@ -523,6 +525,7 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) + amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); + + return 0; + } +@@ -547,6 +550,8 @@ static int codec_hevc_start(struct amvdec_session *sess) + goto free_hevc; + + amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, (0xf << 25)); + + val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; + val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | +@@ -755,6 +760,25 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + (amvdec_get_output_size(sess) / 2)); + + if (frame->cur_slice_idx == 0) { ++ if (core->platform->revision >= VDEC_REVISION_G12A) { ++ val = 0x54 << 8; ++ ++ /* enable first, compressed write */ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) ++ val |= BIT(8); ++ ++ /* enable second, uncompressed write */ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) ++ val |= BIT(9); ++ ++ /* dblk pipeline mode=1 for performance */ ++ if (hevc->width >= 1280) ++ val |= BIT(4); ++ ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, val); ++ amvdec_write_dos(core, HEVC_DBLK_STS1 + 4, BIT(28)); ++ } ++ + amvdec_write_dos(core, HEVC_DBLK_CFG2, + hevc->width | (hevc->height << 16)); + +@@ -770,10 +794,12 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; + val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) +- val |= BIT(0); /* disable cm compression */ +- else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) +- val |= BIT(1); /* Disable double write */ ++ if (core->platform->revision < VDEC_REVISION_G12A) { ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ } + + amvdec_write_dos(core, HEVC_SAO_CTRL1, val); + +diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c +index 2b296beb5d88..5c372a9b0f03 100644 +--- a/drivers/staging/media/meson/vdec/codec_hevc_common.c ++++ b/drivers/staging/media/meson/vdec/codec_hevc_common.c +@@ -111,15 +111,6 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) + } + } + +- /* Fill the remaining unused slots with the last buffer's Y addr */ +- for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_y_paddr >> 5); +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_uv_paddr >> 5); +- } +- + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); + for (i = 0; i < 32; ++i) +diff --git a/drivers/staging/media/meson/vdec/codec_vp9.c b/drivers/staging/media/meson/vdec/codec_vp9.c +index 731119b9ee17..39e8eb5937bf 100644 +--- a/drivers/staging/media/meson/vdec/codec_vp9.c ++++ b/drivers/staging/media/meson/vdec/codec_vp9.c +@@ -90,8 +90,8 @@ enum FRAME_TYPE { + #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) + #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) + #define SEG_MAP_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) +-#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) +-#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) ++#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) ++#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) + #define MMU_VBH_OFFSET (COUNT_OFFSET + COUNT_SIZE) + #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) + #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) +@@ -326,7 +326,11 @@ vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); + } + +- amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ /* VP9 video format */ ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, (0x54 << 8) | BIT(0)); ++ else ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); + } + + static void +@@ -447,6 +451,13 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + return -ENOMEM; + } + ++ memset(vp9->workspace_vaddr + DBLK_PARA_OFFSET, 0, DBLK_PARA_SIZE); ++ memset(vp9->workspace_vaddr + COUNT_OFFSET, 0, COUNT_SIZE); ++ memset(vp9->workspace_vaddr + PROB_OFFSET, 0, PROB_SIZE); ++ ++ printk("Workspace: %08X-%08X\n", wkaddr, wkaddr + SIZE_WORKSPACE); ++ printk("DBLK_PARA: %08X\n", wkaddr + DBLK_PARA_OFFSET); ++ + vp9->workspace_paddr = wkaddr; + + amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); +@@ -461,11 +472,17 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, + wkaddr + SWAP_BUF2_OFFSET); + amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET); ++ ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_DBLK_CFGE, ++ wkaddr + DBLK_PARA_OFFSET); ++ + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); + amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET); + amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET); + amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); ++ amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); + + return 0; + } +@@ -487,6 +504,9 @@ static int codec_vp9_start(struct amvdec_session *sess) + goto free_vp9; + + amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ // stream_fifo_hole ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ amvdec_write_dos_bits(core, HEVC_STREAM_FIFO_CTL, BIT(29)); + + val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff; + val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0); +@@ -597,14 +617,34 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + amvdec_write_dos(core, HEVC_SAO_C_LENGTH, + (amvdec_get_output_size(sess) / 2)); + ++ if (core->platform->revision >= VDEC_REVISION_G12A) { ++ amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, BIT(4) | BIT(5) | BIT(8) | BIT(9)); ++ /* enable first, compressed write */ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) ++ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8)); ++ ++ /* enable second, uncompressed write */ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) ++ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(9)); ++ ++ /* dblk pipeline mode=1 for performance */ ++ if (sess->width >= 1280) ++ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4)); ++ ++ printk("HEVC_DBLK_CFGB: %08X\n", amvdec_read_dos(core, HEVC_DBLK_CFGB)); ++ } ++ + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; + val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) +- val |= BIT(0); /* disable cm compression */ +- else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) +- val |= BIT(1); /* Disable double write */ ++ if (core->platform->revision < VDEC_REVISION_G12A) { ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ } + + amvdec_write_dos(core, HEVC_SAO_CTRL1, val); ++ printk("HEVC_SAO_CTRL1: %08X\n", val); + + if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { + /* no downscale for NV12 */ +diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h +index c80479d7c9c3..dc2c2e085b05 100644 +--- a/drivers/staging/media/meson/vdec/hevc_regs.h ++++ b/drivers/staging/media/meson/vdec/hevc_regs.h +@@ -170,6 +170,7 @@ + #define HEVC_DBLK_STS0 0xd42c + #define HEVC_DBLK_CFGB 0xd42c + #define HEVC_DBLK_STS1 0xd430 ++#define HEVC_DBLK_CFGE 0xd438 + + #define HEVC_SAO_VERSION 0xd800 + #define HEVC_SAO_CTRL0 0xd804 +diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c +index c3415db2b15b..4b4c252a62e8 100644 +--- a/drivers/staging/media/meson/vdec/vdec.c ++++ b/drivers/staging/media/meson/vdec/vdec.c +@@ -968,6 +968,8 @@ static const struct of_device_id vdec_dt_match[] = { + .data = &vdec_platform_gxm }, + { .compatible = "amlogic,gxl-vdec", + .data = &vdec_platform_gxl }, ++ { .compatible = "amlogic,g12a-vdec", ++ .data = &vdec_platform_g12a }, + {} + }; + MODULE_DEVICE_TABLE(of, vdec_dt_match); +@@ -1015,6 +1017,15 @@ static int vdec_probe(struct platform_device *pdev) + if (IS_ERR(core->canvas)) + return PTR_ERR(core->canvas); + ++ of_id = of_match_node(vdec_dt_match, dev->of_node); ++ core->platform = of_id->data; ++ ++ if (core->platform->revision == VDEC_REVISION_G12A) { ++ core->vdec_hevcf_clk = devm_clk_get(dev, "vdec_hevcf"); ++ if (IS_ERR(core->vdec_hevcf_clk)) ++ return -EPROBE_DEFER; ++ } ++ + core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); + if (IS_ERR(core->dos_parser_clk)) + return -EPROBE_DEFER; +@@ -1057,8 +1068,6 @@ static int vdec_probe(struct platform_device *pdev) + goto err_vdev_release; + } + +- of_id = of_match_node(vdec_dt_match, dev->of_node); +- core->platform = of_id->data; + core->vdev_dec = vdev; + core->dev_dec = dev; + mutex_init(&core->lock); +diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h +index 210ab4b755fe..95415212b282 100644 +--- a/drivers/staging/media/meson/vdec/vdec.h ++++ b/drivers/staging/media/meson/vdec/vdec.h +@@ -76,6 +76,7 @@ struct amvdec_core { + struct clk *dos_clk; + struct clk *vdec_1_clk; + struct clk *vdec_hevc_clk; ++ struct clk *vdec_hevcf_clk; + + struct reset_control *esparser_reset; + +diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c +index b1406a5638da..730ecd771643 100644 +--- a/drivers/staging/media/meson/vdec/vdec_hevc.c ++++ b/drivers/staging/media/meson/vdec/vdec_hevc.c +@@ -123,6 +123,8 @@ static int vdec_hevc_stop(struct amvdec_session *sess) + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); + ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ clk_disable_unprepare(core->vdec_hevcf_clk); + clk_disable_unprepare(core->vdec_hevc_clk); + + return 0; +@@ -139,6 +141,13 @@ static int vdec_hevc_start(struct amvdec_session *sess) + if (ret) + return ret; + ++ if (core->platform->revision == VDEC_REVISION_G12A) { ++ clk_set_rate(core->vdec_hevcf_clk, 666666666); ++ ret = clk_prepare_enable(core->vdec_hevcf_clk); ++ if (ret) ++ return ret; ++ } ++ + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, 0); + udelay(10); +diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c +index 3c51bf991a3b..a1812520421b 100644 +--- a/drivers/staging/media/meson/vdec/vdec_platform.c ++++ b/drivers/staging/media/meson/vdec/vdec_platform.c +@@ -290,6 +290,101 @@ static const struct amvdec_format vdec_formats_gxm[] = { + }, + }; + ++static const struct amvdec_format vdec_formats_g12a[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_VP9, ++ .min_buffers = 4, ++ .max_buffers = 16, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_vp9_ops, ++ .firmware_path = "meson/vdec/g12a_vp9.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, ++ { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/vdec/g12a_hevc.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/vdec/gxl_mjpeg.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/vdec/gxl_h263.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/vdec/g12a_h264.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG1, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG2, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, ++}; ++ + const struct vdec_platform vdec_platform_gxbb = { + .formats = vdec_formats_gxbb, + .num_formats = ARRAY_SIZE(vdec_formats_gxbb), +@@ -307,3 +402,9 @@ const struct vdec_platform vdec_platform_gxm = { + .num_formats = ARRAY_SIZE(vdec_formats_gxm), + .revision = VDEC_REVISION_GXM, + }; ++ ++const struct vdec_platform vdec_platform_g12a = { ++ .formats = vdec_formats_g12a, ++ .num_formats = ARRAY_SIZE(vdec_formats_g12a), ++ .revision = VDEC_REVISION_G12A, ++}; +diff --git a/drivers/staging/media/meson/vdec/vdec_platform.h b/drivers/staging/media/meson/vdec/vdec_platform.h +index f6025326db1d..7c61b941b39f 100644 +--- a/drivers/staging/media/meson/vdec/vdec_platform.h ++++ b/drivers/staging/media/meson/vdec/vdec_platform.h +@@ -15,6 +15,7 @@ enum vdec_revision { + VDEC_REVISION_GXBB, + VDEC_REVISION_GXL, + VDEC_REVISION_GXM, ++ VDEC_REVISION_G12A, + }; + + struct vdec_platform { +@@ -26,5 +27,6 @@ struct vdec_platform { + extern const struct vdec_platform vdec_platform_gxbb; + extern const struct vdec_platform vdec_platform_gxm; + extern const struct vdec_platform vdec_platform_gxl; ++extern const struct vdec_platform vdec_platform_g12a; + + #endif +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0127-TEMP-media-meson-vp9-add-IOMMU-support.patch b/packages/linux/patches/amlogic/amlogic-0127-TEMP-media-meson-vp9-add-IOMMU-support.patch new file mode 100644 index 0000000000..1d5ef82884 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0127-TEMP-media-meson-vp9-add-IOMMU-support.patch @@ -0,0 +1,773 @@ +From 8da4faf104bb4c5d7120505186caf5f277e3688d Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Fri, 1 Mar 2019 12:41:03 +0100 +Subject: [PATCH 127/186] TEMP: media: meson: vp9: add IOMMU support + +Starting with GXL (S905X), the HEVC/VP9 decoder hardware supports an +IOMMU to access the decoded frames. This IOMMU is controlled by writing +the buffer's page IDs to the firmware, which then does the actual work. + +This commit adds support for using the IOMMU with VP9/HEVC on G12A, the +first SoC on which it becomes mandatory. + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/codec_hevc.c | 35 ++-- + .../media/meson/vdec/codec_hevc_common.c | 177 ++++++++++++++---- + .../media/meson/vdec/codec_hevc_common.h | 31 ++- + drivers/staging/media/meson/vdec/codec_vp9.c | 71 ++++--- + drivers/staging/media/meson/vdec/hevc_regs.h | 5 + + drivers/staging/media/meson/vdec/vdec.h | 5 - + drivers/staging/media/meson/vdec/vdec_hevc.c | 14 +- + 7 files changed, 255 insertions(+), 83 deletions(-) + +diff --git a/drivers/staging/media/meson/vdec/codec_hevc.c b/drivers/staging/media/meson/vdec/codec_hevc.c +index e16e937d56e8..65d2ad4d8345 100644 +--- a/drivers/staging/media/meson/vdec/codec_hevc.c ++++ b/drivers/staging/media/meson/vdec/codec_hevc.c +@@ -75,6 +75,7 @@ + #define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) + #define RPM_BUF_SIZE 0x100 + #define LMEM_SIZE 0xA00 ++#define MMU_MAP_SIZE 0x4800 + + #define IPP_OFFSET 0x00 + #define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) +@@ -95,6 +96,7 @@ + #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) + #define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) + #define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) ++#define MMU_MAP_OFFSET (LMEM_OFFSET + LMEM_SIZE) + + /* ISR decode status */ + #define HEVC_DEC_IDLE 0x0 +@@ -236,6 +238,9 @@ struct hevc_frame { + struct codec_hevc { + struct mutex lock; + ++ /* Common part of the HEVC decoder */ ++ struct codec_hevc_common common; ++ + /* Buffer for the HEVC Workspace */ + void *workspace_vaddr; + dma_addr_t workspace_paddr; +@@ -517,15 +522,20 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) + amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET); + amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET); + ++ if (core->platform->revision >= VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, ++ wkaddr + MMU_MAP_OFFSET); ++ + /* No MMU */ +- amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, ++ /*amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, + wkaddr + SWAP_BUF_OFFSET); + amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, +- wkaddr + SWAP_BUF2_OFFSET); ++ wkaddr + SWAP_BUF2_OFFSET);*/ + amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); ++ amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); + + return 0; + } +@@ -549,9 +559,10 @@ static int codec_hevc_start(struct amvdec_session *sess) + if (ret) + goto free_hevc; + +- amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); +- if (core->platform->revision == VDEC_REVISION_G12A) +- amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, (0xf << 25)); ++ val = BIT(0); /* stream_fetch_enable */ ++ if (core->platform->revision >= VDEC_REVISION_G12A) ++ val |= (0xf << 25); /* arwlen_axi_max */ ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, val); + + val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; + val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | +@@ -608,9 +619,9 @@ static int codec_hevc_start(struct amvdec_session *sess) + goto free_hevc; + } + +- amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); ++ /*amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); + amvdec_write_dos(core, HEVC_AUX_DATA_SIZE, +- (((SIZE_AUX) >> 4) << 16) | 0); ++ (((SIZE_AUX) >> 4) << 16) | 0);*/ + mutex_init(&hevc->lock); + sess->priv = hevc; + +@@ -652,7 +663,7 @@ static int codec_hevc_stop(struct amvdec_session *sess) + dma_free_coherent(core->dev, SIZE_AUX, + hevc->aux_vaddr, hevc->aux_paddr); + +- codec_hevc_free_fbc_buffers(sess); ++ codec_hevc_free_fbc_buffers(sess, &hevc->common); + mutex_unlock(&hevc->lock); + mutex_destroy(&hevc->lock); + +@@ -732,7 +743,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + + if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit)) + buf_y_paddr = +- sess->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; ++ hevc->common.fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; + else + buf_y_paddr = + vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); +@@ -776,7 +787,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + val |= BIT(4); + + amvdec_write_dos(core, HEVC_DBLK_CFGB, val); +- amvdec_write_dos(core, HEVC_DBLK_STS1 + 4, BIT(28)); ++ amvdec_write_dos(core, HEVC_DBLK_STS1 + 16, BIT(28)); + } + + amvdec_write_dos(core, HEVC_DBLK_CFG2, +@@ -1323,7 +1334,7 @@ static void codec_hevc_resume(struct amvdec_session *sess) + { + struct codec_hevc *hevc = sess->priv; + +- if (codec_hevc_setup_buffers(sess, hevc->is_10bit)) { ++ if (codec_hevc_setup_buffers(sess, &hevc->common, hevc->is_10bit)) { + amvdec_abort(sess); + return; + } +@@ -1340,6 +1351,8 @@ static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess) + struct codec_hevc *hevc = sess->priv; + u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG); + ++ printk("ISR!\n"); ++ + if (!hevc) + return IRQ_HANDLED; + +diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c +index 5c372a9b0f03..de7eb6cfbe85 100644 +--- a/drivers/staging/media/meson/vdec/codec_hevc_common.c ++++ b/drivers/staging/media/meson/vdec/codec_hevc_common.c +@@ -10,6 +10,9 @@ + #include "vdec_helpers.h" + #include "hevc_regs.h" + ++#define MMU_COMPRESS_HEADER_SIZE 0x48000 ++#define MMU_MAP_SIZE 0x4800 ++ + /* Configure decode head read mode */ + void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) + { +@@ -23,7 +26,12 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) + return; + } + +- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); ++ if (codec_hevc_use_mmu(core->platform->revision, ++ sess->pixfmt_cap, is_10bit)) ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4)); ++ else ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); ++ + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); + amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); + amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); +@@ -31,8 +39,9 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) + } + EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); + +-static void +-codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) ++static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit) + { + struct amvdec_core *core = sess->core; + struct v4l2_m2m_buffer *buf; +@@ -46,22 +55,26 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); + + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +- idx = buf->vb.vb2_buf.index; ++ struct vb2_buffer *vb = &buf->vb.vb2_buf; ++ idx = vb->index; + + if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) +- buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ buf_y_paddr = comm->fbc_buffer_paddr[idx]; + else +- buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); + + if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { + val = buf_y_paddr | (idx << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, ++ val); + } else { +- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); + val = buf_y_paddr | ((idx * 2) << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, ++ val); + val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, ++ val); + } + } + +@@ -80,32 +93,37 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); + } + +-static void +-codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) ++static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit) + { + struct amvdec_core *core = sess->core; + struct v4l2_m2m_buffer *buf; +- u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); +- dma_addr_t buf_y_paddr = 0; +- dma_addr_t buf_uv_paddr = 0; ++ u32 revision = core->platform->revision; ++ u32 pixfmt_cap = sess->pixfmt_cap; + int i; + + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, + BIT(2) | BIT(1)); + + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +- u32 idx = buf->vb.vb2_buf.index; ++ struct vb2_buffer *vb = &buf->vb.vb2_buf; ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ u32 idx = vb->index; + +- if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) +- buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit)) ++ buf_y_paddr = comm->mmu_header_paddr[idx]; ++ else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit)) ++ buf_y_paddr = comm->fbc_buffer_paddr[idx]; + else +- buf_y_paddr = +- vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); + + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, + buf_y_paddr >> 5); +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { +- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ ++ if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, + buf_uv_paddr >> 5); + } +@@ -117,24 +135,26 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); + } + +-void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) + { + struct device *dev = sess->core->dev; + u32 am21_size = amvdec_am21c_size(sess->width, sess->height); + int i; + + for (i = 0; i < MAX_REF_PIC_NUM; ++i) { +- if (sess->fbc_buffer_vaddr[i]) { ++ if (comm->fbc_buffer_vaddr[i]) { + dma_free_coherent(dev, am21_size, +- sess->fbc_buffer_vaddr[i], +- sess->fbc_buffer_paddr[i]); +- sess->fbc_buffer_vaddr[i] = NULL; ++ comm->fbc_buffer_vaddr[i], ++ comm->fbc_buffer_paddr[i]); ++ comm->fbc_buffer_vaddr[i] = NULL; + } + } + } + EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); + +-static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) ++static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) + { + struct device *dev = sess->core->dev; + struct v4l2_m2m_buffer *buf; +@@ -147,33 +167,118 @@ static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) + GFP_KERNEL); + if (!vaddr) { + dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); +- codec_hevc_free_fbc_buffers(sess); ++ codec_hevc_free_fbc_buffers(sess, comm); ++ return -ENOMEM; ++ } ++ ++ comm->fbc_buffer_vaddr[idx] = vaddr; ++ comm->fbc_buffer_paddr[idx] = paddr; ++ } ++ ++ return 0; ++} ++ ++void codec_hevc_free_mmu_headers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) ++{ ++ struct device *dev = sess->core->dev; ++ int i; ++ ++ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { ++ if (comm->mmu_header_vaddr[i]) { ++ dma_free_coherent(dev, MMU_COMPRESS_HEADER_SIZE, ++ comm->mmu_header_vaddr[i], ++ comm->mmu_header_paddr[i]); ++ comm->mmu_header_vaddr[i] = NULL; ++ } ++ } ++ ++ if (comm->mmu_map_vaddr) { ++ dma_free_coherent(dev, MMU_MAP_SIZE, ++ comm->mmu_map_vaddr, ++ comm->mmu_map_paddr); ++ comm->mmu_map_vaddr = NULL; ++ } ++} ++EXPORT_SYMBOL_GPL(codec_hevc_free_mmu_headers); ++ ++static int codec_hevc_alloc_mmu_headers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) ++{ ++ struct device *dev = sess->core->dev; ++ struct v4l2_m2m_buffer *buf; ++ ++ comm->mmu_map_vaddr = dma_alloc_coherent(dev, MMU_MAP_SIZE, ++ &comm->mmu_map_paddr, ++ GFP_KERNEL); ++ if (!comm->mmu_map_vaddr) ++ return -ENOMEM; ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ dma_addr_t paddr; ++ void *vaddr = dma_alloc_coherent(dev, MMU_COMPRESS_HEADER_SIZE, ++ &paddr, GFP_KERNEL); ++ if (!vaddr) { ++ dev_err(dev, "Couldn't allocate MMU header %u\n", idx); ++ codec_hevc_free_mmu_headers(sess, comm); + return -ENOMEM; + } + +- sess->fbc_buffer_vaddr[idx] = vaddr; +- sess->fbc_buffer_paddr[idx] = paddr; ++ comm->mmu_header_vaddr[idx] = vaddr; ++ comm->mmu_header_paddr[idx] = paddr; + } + + return 0; + } + +-int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit) ++int codec_hevc_setup_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit) + { + struct amvdec_core *core = sess->core; + int ret; + + if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) { +- ret = codec_hevc_alloc_fbc_buffers(sess); ++ ret = codec_hevc_alloc_fbc_buffers(sess, comm); + if (ret) + return ret; + } + ++ if (codec_hevc_use_mmu(core->platform->revision, ++ sess->pixfmt_cap, is_10bit)) { ++ ret = codec_hevc_alloc_mmu_headers(sess, comm); ++ if (ret) { ++ codec_hevc_free_fbc_buffers(sess, comm); ++ return ret; ++ } ++ } ++ + if (core->platform->revision == VDEC_REVISION_GXBB) +- codec_hevc_setup_buffers_gxbb(sess, is_10bit); ++ codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit); + else +- codec_hevc_setup_buffers_gxl(sess, is_10bit); ++ codec_hevc_setup_buffers_gxl(sess, comm, is_10bit); + + return 0; + } +-EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); +\ No newline at end of file ++EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); ++ ++void codec_hevc_fill_mmu_map(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ struct vb2_buffer *vb) ++{ ++ u32 size = amvdec_am21c_size(sess->width, sess->height); ++ u32 nb_pages = size / PAGE_SIZE; ++ u32 *mmu_map = comm->mmu_map_vaddr; ++ u32 first_page; ++ u32 i; ++ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) ++ first_page = comm->fbc_buffer_paddr[vb->index] >> PAGE_SHIFT; ++ else ++ first_page = vb2_dma_contig_plane_dma_addr(vb, 0) >> PAGE_SHIFT; ++ ++ for (i = 0; i < nb_pages; ++i) ++ mmu_map[i] = first_page + i; ++} ++EXPORT_SYMBOL_GPL(codec_hevc_fill_mmu_map); +diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.h b/drivers/staging/media/meson/vdec/codec_hevc_common.h +index 7c8891529ac8..89c8b61f8a94 100644 +--- a/drivers/staging/media/meson/vdec/codec_hevc_common.h ++++ b/drivers/staging/media/meson/vdec/codec_hevc_common.h +@@ -25,6 +25,19 @@ static const u16 vdec_hevc_parser_cmd[] = { + 0x7C00 + }; + ++#define MAX_REF_PIC_NUM 24 ++ ++struct codec_hevc_common { ++ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; ++ ++ void *mmu_header_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t mmu_header_paddr[MAX_REF_PIC_NUM]; ++ ++ void *mmu_map_vaddr; ++ dma_addr_t mmu_map_paddr; ++}; ++ + /* Returns 1 if we must use framebuffer compression */ + static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit) + { +@@ -37,13 +50,27 @@ static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit) + return pixfmt == V4L2_PIX_FMT_NV12M && is_10bit; + } + ++/* Returns 1 if we are decoding using the IOMMU */ ++static inline int codec_hevc_use_mmu(u32 revision, u32 pixfmt, int is_10bit) ++{ ++ return revision >= VDEC_REVISION_G12A && ++ codec_hevc_use_fbc(pixfmt, is_10bit); ++} ++ + /** + * Configure decode head read mode + */ + void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit); + +-void codec_hevc_free_fbc_buffers(struct amvdec_session *sess); ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm); ++ ++int codec_hevc_setup_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit); + +-int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit); ++void codec_hevc_fill_mmu_map(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ struct vb2_buffer *vb); + + #endif +diff --git a/drivers/staging/media/meson/vdec/codec_vp9.c b/drivers/staging/media/meson/vdec/codec_vp9.c +index 39e8eb5937bf..b1643cc01f68 100644 +--- a/drivers/staging/media/meson/vdec/codec_vp9.c ++++ b/drivers/staging/media/meson/vdec/codec_vp9.c +@@ -219,6 +219,9 @@ struct vp9_frame { + struct codec_vp9 { + struct mutex lock; + ++ /* Common part with the HEVC decoder */ ++ struct codec_hevc_common common; ++ + /* Buffer for the VP9 Workspace */ + void *workspace_vaddr; + dma_addr_t workspace_paddr; +@@ -438,27 +441,26 @@ static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess) + return vp9->frames_num; + } + +-static int +-codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) ++static int codec_vp9_alloc_workspace(struct amvdec_core *core, ++ struct codec_vp9 *vp9) + { +- dma_addr_t wkaddr; +- + /* Allocate some memory for the VP9 decoder's state */ + vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, +- &wkaddr, GFP_KERNEL); ++ &vp9->workspace_paddr, GFP_KERNEL); + if (!vp9->workspace_vaddr) { + dev_err(core->dev, "Failed to allocate VP9 Workspace\n"); + return -ENOMEM; + } + +- memset(vp9->workspace_vaddr + DBLK_PARA_OFFSET, 0, DBLK_PARA_SIZE); +- memset(vp9->workspace_vaddr + COUNT_OFFSET, 0, COUNT_SIZE); +- memset(vp9->workspace_vaddr + PROB_OFFSET, 0, PROB_SIZE); +- +- printk("Workspace: %08X-%08X\n", wkaddr, wkaddr + SIZE_WORKSPACE); +- printk("DBLK_PARA: %08X\n", wkaddr + DBLK_PARA_OFFSET); ++ return 0; ++} + +- vp9->workspace_paddr = wkaddr; ++static void codec_vp9_setup_workspace(struct amvdec_session *sess, ++ struct codec_vp9 *vp9) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 revision = core->platform->revision; ++ dma_addr_t wkaddr = vp9->workspace_paddr; + + amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); + amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET); +@@ -466,7 +468,6 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET); + amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET); + +- /* No MMU */ + amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER, + wkaddr + SWAP_BUF_OFFSET); + amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, +@@ -484,7 +485,19 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); + amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); + +- return 0; ++ if (codec_hevc_use_mmu(revision, sess->pixfmt_cap, vp9->is_10bit)) { ++ amvdec_write_dos(core, HEVC_SAO_MMU_VH0_ADDR, ++ wkaddr + MMU_VBH_OFFSET); ++ amvdec_write_dos(core, HEVC_SAO_MMU_VH1_ADDR, ++ wkaddr + MMU_VBH_OFFSET + (MMU_VBH_SIZE / 2)); ++ ++ if (revision >= VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, ++ vp9->common.mmu_map_paddr); ++ else ++ amvdec_write_dos(core, VP9_MMU_MAP_BUFFER, ++ vp9->common.mmu_map_paddr); ++ } + } + + static int codec_vp9_start(struct amvdec_session *sess) +@@ -499,10 +512,11 @@ static int codec_vp9_start(struct amvdec_session *sess) + if (!vp9) + return -ENOMEM; + +- ret = codec_vp9_setup_workspace(core, vp9); ++ ret = codec_vp9_alloc_workspace(core, vp9); + if (ret) + goto free_vp9; + ++ codec_vp9_setup_workspace(sess, vp9); + amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); + // stream_fifo_hole + if (core->platform->revision == VDEC_REVISION_G12A) +@@ -575,7 +589,7 @@ static int codec_vp9_stop(struct amvdec_session *sess) + vp9->workspace_vaddr, + vp9->workspace_paddr); + +- codec_hevc_free_fbc_buffers(sess); ++ codec_hevc_free_fbc_buffers(sess, &vp9->common); + return 0; + } + +@@ -590,7 +604,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + + if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit)) + buf_y_paddr = +- sess->fbc_buffer_paddr[vb->index]; ++ vp9->common.fbc_buffer_paddr[vb->index]; + else + buf_y_paddr = + vb2_dma_contig_plane_dma_addr(vb, 0); +@@ -601,6 +615,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); + } + ++ + if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { + buf_y_paddr = + vb2_dma_contig_plane_dma_addr(vb, 0); +@@ -612,13 +627,22 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); + } + ++ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap, ++ vp9->is_10bit)) { ++ amvdec_write_dos(core, HEVC_CM_HEADER_START_ADDR, ++ vp9->common.mmu_header_paddr[vb->index]); ++ /* use HEVC_CM_HEADER_START_ADDR */ ++ amvdec_write_dos_bits(core, HEVC_SAO_CTRL5, BIT(10)); ++ } ++ + amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, + amvdec_get_output_size(sess)); + amvdec_write_dos(core, HEVC_SAO_C_LENGTH, + (amvdec_get_output_size(sess) / 2)); + + if (core->platform->revision >= VDEC_REVISION_G12A) { +- amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, BIT(4) | BIT(5) | BIT(8) | BIT(9)); ++ amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, ++ BIT(4) | BIT(5) | BIT(8) | BIT(9)); + /* enable first, compressed write */ + if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) + amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8)); +@@ -630,8 +654,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + /* dblk pipeline mode=1 for performance */ + if (sess->width >= 1280) + amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4)); +- +- printk("HEVC_DBLK_CFGB: %08X\n", amvdec_read_dos(core, HEVC_DBLK_CFGB)); + } + + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; +@@ -644,7 +666,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + } + + amvdec_write_dos(core, HEVC_SAO_CTRL1, val); +- printk("HEVC_SAO_CTRL1: %08X\n", val); + + if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { + /* no downscale for NV12 */ +@@ -919,6 +940,11 @@ static void codec_vp9_process_frame(struct amvdec_session *sess) + codec_vp9_update_next_ref(vp9); + codec_vp9_show_existing_frame(vp9); + ++ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap, ++ vp9->is_10bit)) ++ codec_hevc_fill_mmu_map(sess, &vp9->common, ++ &vp9->cur_frame->vbuf->vb2_buf); ++ + intra_only = param->p.show_frame ? 0 : param->p.intra_only; + /* clear mpred (for keyframe only) */ + if (param->p.frame_type != KEY_FRAME && !intra_only) { +@@ -971,11 +997,12 @@ static void codec_vp9_resume(struct amvdec_session *sess) + { + struct codec_vp9 *vp9 = sess->priv; + +- if (codec_hevc_setup_buffers(sess, vp9->is_10bit)) { ++ if (codec_hevc_setup_buffers(sess, &vp9->common, vp9->is_10bit)) { + amvdec_abort(sess); + return; + } + ++ codec_vp9_setup_workspace(sess, vp9); + codec_hevc_setup_decode_head(sess, vp9->is_10bit); + codec_vp9_process_lf(vp9); + codec_vp9_process_frame(sess); +diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h +index dc2c2e085b05..0392f41a1eed 100644 +--- a/drivers/staging/media/meson/vdec/hevc_regs.h ++++ b/drivers/staging/media/meson/vdec/hevc_regs.h +@@ -6,6 +6,8 @@ + #ifndef __MESON_VDEC_HEVC_REGS_H_ + #define __MESON_VDEC_HEVC_REGS_H_ + ++#define HEVC_ASSIST_MMU_MAP_ADDR 0xc024 ++ + #define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4 + #define HEVC_ASSIST_MBOX1_MASK 0xc1d8 + +@@ -200,8 +202,11 @@ + #define HEVC_SAO_CTRL7 0xd894 + #define HEVC_CM_BODY_START_ADDR 0xd898 + #define HEVC_CM_BODY_LENGTH 0xd89c ++#define HEVC_CM_HEADER_START_ADDR 0xd8a0 + #define HEVC_CM_HEADER_LENGTH 0xd8a4 + #define HEVC_CM_HEADER_OFFSET 0xd8ac ++#define HEVC_SAO_MMU_VH0_ADDR 0xd8e8 ++#define HEVC_SAO_MMU_VH1_ADDR 0xd8ec + + #define HEVC_IQIT_CLK_RST_CTRL 0xdc00 + #define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08 +diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h +index 95415212b282..95b4c5761a27 100644 +--- a/drivers/staging/media/meson/vdec/vdec.h ++++ b/drivers/staging/media/meson/vdec/vdec.h +@@ -20,8 +20,6 @@ + /* 32 buffers in 3-plane YUV420 */ + #define MAX_CANVAS (32 * 3) + +-#define MAX_REF_PIC_NUM 24 +- + struct amvdec_buffer { + struct list_head list; + struct vb2_buffer *vb; +@@ -261,9 +259,6 @@ struct amvdec_session { + u32 wrap_count; + u32 fw_idx_to_vb2_idx[32]; + +- void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; +- dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; +- + enum amvdec_status status; + void *priv; + }; +diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c +index 730ecd771643..70db09c052c3 100644 +--- a/drivers/staging/media/meson/vdec/vdec_hevc.c ++++ b/drivers/staging/media/meson/vdec/vdec_hevc.c +@@ -123,9 +123,9 @@ static int vdec_hevc_stop(struct amvdec_session *sess) + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); + ++ clk_disable_unprepare(core->vdec_hevc_clk); + if (core->platform->revision == VDEC_REVISION_G12A) + clk_disable_unprepare(core->vdec_hevcf_clk); +- clk_disable_unprepare(core->vdec_hevc_clk); + + return 0; + } +@@ -136,11 +136,6 @@ static int vdec_hevc_start(struct amvdec_session *sess) + struct amvdec_core *core = sess->core; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + +- clk_set_rate(core->vdec_hevc_clk, 666666666); +- ret = clk_prepare_enable(core->vdec_hevc_clk); +- if (ret) +- return ret; +- + if (core->platform->revision == VDEC_REVISION_G12A) { + clk_set_rate(core->vdec_hevcf_clk, 666666666); + ret = clk_prepare_enable(core->vdec_hevcf_clk); +@@ -148,6 +143,11 @@ static int vdec_hevc_start(struct amvdec_session *sess) + return ret; + } + ++ clk_set_rate(core->vdec_hevc_clk, 666666666); ++ ret = clk_prepare_enable(core->vdec_hevc_clk); ++ if (ret) ++ return ret; ++ + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, 0); + udelay(10); +@@ -177,7 +177,7 @@ static int vdec_hevc_start(struct amvdec_session *sess) + if (ret) + goto stop; + +- amvdec_write_dos(core, DOS_SW_RESET3, BIT(12)|BIT(11)); ++ amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11)); + amvdec_write_dos(core, DOS_SW_RESET3, 0); + amvdec_read_dos(core, DOS_SW_RESET3); + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0128-TEMP-media-meson-vdec-WIP-HEVC-IOMMU-support.patch b/packages/linux/patches/amlogic/amlogic-0128-TEMP-media-meson-vdec-WIP-HEVC-IOMMU-support.patch new file mode 100644 index 0000000000..dab69bed56 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0128-TEMP-media-meson-vdec-WIP-HEVC-IOMMU-support.patch @@ -0,0 +1,138 @@ +From 51c7740b927c223c2a2aca84f643a3e016eb1d90 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 5 Jun 2019 16:14:36 +0200 +Subject: [PATCH 128/186] TEMP: media: meson: vdec: [WIP] HEVC IOMMU support + +Signed-off-by: Maxime Jourdan +--- + drivers/staging/media/meson/vdec/codec_hevc.c | 59 +++++++++++++------ + 1 file changed, 41 insertions(+), 18 deletions(-) + +diff --git a/drivers/staging/media/meson/vdec/codec_hevc.c b/drivers/staging/media/meson/vdec/codec_hevc.c +index 65d2ad4d8345..20bee7689dbd 100644 +--- a/drivers/staging/media/meson/vdec/codec_hevc.c ++++ b/drivers/staging/media/meson/vdec/codec_hevc.c +@@ -500,8 +500,11 @@ static void codec_hevc_output_frames(struct amvdec_session *sess) + + + static int +-codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) ++codec_hevc_setup_workspace(struct amvdec_session *sess, ++ struct codec_hevc *hevc) + { ++ struct amvdec_core *core = sess->core; ++ u32 revision = core->platform->revision; + dma_addr_t wkaddr; + + /* Allocate some memory for the HEVC decoder's state */ +@@ -522,19 +525,32 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) + amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET); + amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET); + +- if (core->platform->revision >= VDEC_REVISION_G12A) +- amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, +- wkaddr + MMU_MAP_OFFSET); +- +- /* No MMU */ +- /*amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, +- wkaddr + SWAP_BUF_OFFSET); +- amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, +- wkaddr + SWAP_BUF2_OFFSET);*/ ++ if (codec_hevc_use_mmu(revision, sess->pixfmt_cap, hevc->is_10bit)) { ++ amvdec_write_dos(core, HEVC_SAO_MMU_VH0_ADDR, ++ wkaddr + MMU_VBH_OFFSET); ++ amvdec_write_dos(core, HEVC_SAO_MMU_VH1_ADDR, ++ wkaddr + MMU_VBH_OFFSET + (MMU_VBH_SIZE / 2)); ++ ++ if (revision >= VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, ++ hevc->common.mmu_map_paddr); ++ else ++ amvdec_write_dos(core, H265_MMU_MAP_BUFFER, ++ hevc->common.mmu_map_paddr); ++ } else if (revision < VDEC_REVISION_G12A) { ++ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, ++ wkaddr + SWAP_BUF_OFFSET); ++ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, ++ wkaddr + SWAP_BUF2_OFFSET); ++ } ++ + amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); +- amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); ++ if (revision >= VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_DBLK_CFGE, ++ wkaddr + DBLK_DATA2_OFFSET); ++ + amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); + + return 0; +@@ -555,7 +571,7 @@ static int codec_hevc_start(struct amvdec_session *sess) + INIT_LIST_HEAD(&hevc->ref_frames_list); + hevc->curr_poc = INVALID_POC; + +- ret = codec_hevc_setup_workspace(core, hevc); ++ ret = codec_hevc_setup_workspace(sess, hevc); + if (ret) + goto free_hevc; + +@@ -720,6 +736,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + { + struct amvdec_core *core = sess->core; + struct codec_hevc *hevc = sess->priv; ++ struct vb2_buffer *vb = &frame->vbuf->vb2_buf; + union rpm_param *param = &hevc->rpm_param; + u32 pic_height_cu = + (hevc->height + hevc->lcu_size - 1) / hevc->lcu_size; +@@ -743,10 +760,10 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + + if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit)) + buf_y_paddr = +- hevc->common.fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; ++ hevc->common.fbc_buffer_paddr[vb->index]; + else + buf_y_paddr = +- vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); ++ vb2_dma_contig_plane_dma_addr(vb, 0); + + if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { + val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; +@@ -756,15 +773,23 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + + if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { + buf_y_paddr = +- vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); ++ vb2_dma_contig_plane_dma_addr(vb, 0); + buf_u_v_paddr = +- vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 1); ++ vb2_dma_contig_plane_dma_addr(vb, 1); + amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr); + amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr); + amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr); + amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); + } + ++ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap, ++ hevc->is_10bit)) { ++ amvdec_write_dos(core, HEVC_CM_HEADER_START_ADDR, ++ hevc->common.mmu_header_paddr[vb->index]); ++ /* use HEVC_CM_HEADER_START_ADDR */ ++ amvdec_write_dos_bits(core, HEVC_SAO_CTRL5, BIT(10)); ++ } ++ + amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, + amvdec_get_output_size(sess)); + amvdec_write_dos(core, HEVC_SAO_C_LENGTH, +@@ -1351,8 +1376,6 @@ static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess) + struct codec_hevc *hevc = sess->priv; + u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG); + +- printk("ISR!\n"); +- + if (!hevc) + return IRQ_HANDLED; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0129-HACK-set-meson-g12-cma-pool-to-896MB.patch b/packages/linux/patches/amlogic/amlogic-0129-HACK-set-meson-g12-cma-pool-to-896MB.patch new file mode 100644 index 0000000000..0aa76fa613 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0129-HACK-set-meson-g12-cma-pool-to-896MB.patch @@ -0,0 +1,28 @@ +From 613226496d86a48d895cd9e66e4ffb3d87f86669 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Wed, 14 Aug 2019 19:58:14 +0000 +Subject: [PATCH 129/186] HACK: set meson-g12 cma pool to 896MB + +This change sets the CMA pool to a larger 896MB! value for (WIP) vdec use + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +index e4aa4a3b06bd..a006c712074f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +@@ -80,7 +80,7 @@ + linux,cma { + compatible = "shared-dma-pool"; + reusable; +- size = <0x0 0x10000000>; ++ size = <0x0 0x38000000>; + alignment = <0x0 0x400000>; + linux,cma-default; + }; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0001-HACK-set-cma-pool-to-896MB.patch b/packages/linux/patches/amlogic/amlogic-0130-HACK-set-meson-gx-cma-pool-to-896MB.patch similarity index 81% rename from projects/Amlogic/patches/linux/e-0001-HACK-set-cma-pool-to-896MB.patch rename to packages/linux/patches/amlogic/amlogic-0130-HACK-set-meson-gx-cma-pool-to-896MB.patch index dd67db81fb..40b8b90bf4 100644 --- a/projects/Amlogic/patches/linux/e-0001-HACK-set-cma-pool-to-896MB.patch +++ b/packages/linux/patches/amlogic/amlogic-0130-HACK-set-meson-gx-cma-pool-to-896MB.patch @@ -1,7 +1,7 @@ -From 78a5fa8623ffbc3a4f661d42aaea172c7d80cc9d Mon Sep 17 00:00:00 2001 +From 38f987e2b2532dfd609683998158260be92005a5 Mon Sep 17 00:00:00 2001 From: chewitt Date: Sat, 13 Apr 2019 05:41:51 +0000 -Subject: [PATCH 01/37] HACK: set cma pool to 896MB +Subject: [PATCH 130/186] HACK: set meson-gx cma pool to 896MB This change sets the CMA pool to a larger 896MB! value for (WIP) vdec use @@ -11,7 +11,7 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -index 8238f55666e7..46cb715de241 100644 +index 65155abbe082..0ed78e10ce98 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi @@ -44,7 +44,7 @@ diff --git a/projects/Amlogic/patches/linux/e-0002-HACK-fix-Kodi-sysinfo-CPU-information.patch b/packages/linux/patches/amlogic/amlogic-0131-HACK-fix-Kodi-sysinfo-CPU-information.patch similarity index 78% rename from projects/Amlogic/patches/linux/e-0002-HACK-fix-Kodi-sysinfo-CPU-information.patch rename to packages/linux/patches/amlogic/amlogic-0131-HACK-fix-Kodi-sysinfo-CPU-information.patch index e8d0ecf237..999448a2a7 100644 --- a/projects/Amlogic/patches/linux/e-0002-HACK-fix-Kodi-sysinfo-CPU-information.patch +++ b/packages/linux/patches/amlogic/amlogic-0131-HACK-fix-Kodi-sysinfo-CPU-information.patch @@ -1,7 +1,7 @@ -From 42a2fa4e82892cb9089b6870f41dc84c595f8df4 Mon Sep 17 00:00:00 2001 +From 64d2c68aa01e34be8e6cb588188d7f6d8cbe337b Mon Sep 17 00:00:00 2001 From: chewitt Date: Sat, 13 Apr 2019 05:45:18 +0000 -Subject: [PATCH 02/37] HACK: fix Kodi sysinfo CPU information +Subject: [PATCH 131/186] HACK: fix Kodi sysinfo CPU information This allows the CPU information to show in the Kodi sysinfo screen, e.g. @@ -13,10 +13,10 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c -index ca0685f33900..e1a26a315733 100644 +index 876055e37352..b6e158430fe1 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c -@@ -140,8 +140,7 @@ static int c_show(struct seq_file *m, void *v) +@@ -139,8 +139,7 @@ static int c_show(struct seq_file *m, void *v) * "processor". Give glibc what it expects. */ seq_printf(m, "processor\t: %d\n", i); diff --git a/packages/linux/patches/amlogic/amlogic-0132-HACK-silence-PFNs-busy-log-spam.patch b/packages/linux/patches/amlogic/amlogic-0132-HACK-silence-PFNs-busy-log-spam.patch new file mode 100644 index 0000000000..1b462766fb --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0132-HACK-silence-PFNs-busy-log-spam.patch @@ -0,0 +1,29 @@ +From 4f88198aaf07293bad5c0db651b372f75635132b Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 06:23:01 +0000 +Subject: [PATCH 132/186] HACK: silence "PFNs busy" log spam + +Even with ratelimiting in https://lore.kernel.org/patchwork/patch/816616/ lots +of "PFNs busy" messages spam the system log, so silence the message. + +Signed-off-by: Christian Hewitt +--- + mm/page_alloc.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 9c9194959271..8a16fde7d939 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -8434,8 +8434,6 @@ int alloc_contig_range(unsigned long start, unsigned long end, + + /* Make sure the range is really isolated. */ + if (test_pages_isolated(outer_start, end, false)) { +- pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n", +- __func__, outer_start, end); + ret = -EBUSY; + goto done; + } +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0004-HACK-silence-meson-ir-warn-once-log-spam.patch b/packages/linux/patches/amlogic/amlogic-0133-HACK-silence-meson-ir-warn-once-log-spam.patch similarity index 75% rename from projects/Amlogic/patches/linux/e-0004-HACK-silence-meson-ir-warn-once-log-spam.patch rename to packages/linux/patches/amlogic/amlogic-0133-HACK-silence-meson-ir-warn-once-log-spam.patch index fc21061876..2c3c054a47 100644 --- a/projects/Amlogic/patches/linux/e-0004-HACK-silence-meson-ir-warn-once-log-spam.patch +++ b/packages/linux/patches/amlogic/amlogic-0133-HACK-silence-meson-ir-warn-once-log-spam.patch @@ -1,7 +1,7 @@ -From 2585e9b6e91d529c2ac27133f1219761726a643c Mon Sep 17 00:00:00 2001 +From 87ba8a729688da9e7ddb0fd855af6a87a28fc3b0 Mon Sep 17 00:00:00 2001 From: chewitt Date: Sat, 13 Apr 2019 06:27:33 +0000 -Subject: [PATCH 04/37] HACK: silence meson-ir warn once log spam +Subject: [PATCH 133/186] HACK: silence meson-ir warn once log spam This silences another warning message that spams the system log. @@ -11,10 +11,10 @@ Signed-off-by: Christian Hewitt 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c -index 9914c83fecb9..ba2f3fb92889 100644 +index 72a7bbbf6b1f..a65853a929dc 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c -@@ -97,7 +97,8 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) +@@ -91,7 +91,8 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) status = readl_relaxed(ir->reg + IR_DEC_STATUS); rawir.pulse = !!(status & STATUS_IR_DEC_IN); diff --git a/projects/Amlogic/patches/linux/e-0005-HACK-silence-hrtimer-log-spam.patch b/packages/linux/patches/amlogic/amlogic-0134-HACK-silence-hrtimer-log-spam.patch similarity index 73% rename from projects/Amlogic/patches/linux/e-0005-HACK-silence-hrtimer-log-spam.patch rename to packages/linux/patches/amlogic/amlogic-0134-HACK-silence-hrtimer-log-spam.patch index 60c01a3fa1..a76589304f 100644 --- a/projects/Amlogic/patches/linux/e-0005-HACK-silence-hrtimer-log-spam.patch +++ b/packages/linux/patches/amlogic/amlogic-0134-HACK-silence-hrtimer-log-spam.patch @@ -1,7 +1,7 @@ -From 48b392bb606eb916a0a2fc0a3d318c4bde92bd2b Mon Sep 17 00:00:00 2001 +From 1ca993891726a9d8c47f14d07d20defbf39be510 Mon Sep 17 00:00:00 2001 From: chewitt Date: Sat, 13 Apr 2019 06:35:17 +0000 -Subject: [PATCH 05/37] HACK: silence hrtimer log spam +Subject: [PATCH 134/186] HACK: silence hrtimer log spam This silences another annoying system log message @@ -11,10 +11,10 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c -index 41dfff23c1f9..bb6d137388ca 100644 +index 5ee77f1a8a92..1ea645a874a5 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c -@@ -905,7 +905,7 @@ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) +@@ -904,7 +904,7 @@ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) if (delta < 0) return 0; diff --git a/projects/Amlogic/patches/linux/e-0006-HACK-Bluetooth-Fix-spurious-error-message.patch b/packages/linux/patches/amlogic/amlogic-0135-HACK-Bluetooth-Fix-spurious-error-message.patch similarity index 82% rename from projects/Amlogic/patches/linux/e-0006-HACK-Bluetooth-Fix-spurious-error-message.patch rename to packages/linux/patches/amlogic/amlogic-0135-HACK-Bluetooth-Fix-spurious-error-message.patch index e7dd9cd3fe..94a75ca57a 100644 --- a/projects/Amlogic/patches/linux/e-0006-HACK-Bluetooth-Fix-spurious-error-message.patch +++ b/packages/linux/patches/amlogic/amlogic-0135-HACK-Bluetooth-Fix-spurious-error-message.patch @@ -1,7 +1,7 @@ -From e0f59e98b6603924e5b44a276a6939b7893c86e1 Mon Sep 17 00:00:00 2001 +From 8b6b342e094922fee7ef28efd84ff04667fcd39c Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Thu, 29 Mar 2018 11:41:17 +0200 -Subject: [PATCH 06/37] HACK: Bluetooth: Fix spurious error message +Subject: [PATCH 135/186] HACK: Bluetooth: Fix spurious error message This message was debug message before 2064ee332e4c1b7495cf68b. Looks like it was changed by accident in that patch. This is causing some @@ -19,10 +19,10 @@ Signed-off-by: Szymon Janc 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c -index 609fd6871c5a..3cac7023aa95 100644 +index cdb00c2ef242..337ee162d2ef 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c -@@ -5718,8 +5718,7 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, +@@ -5807,8 +5807,7 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, return false; if (hdr->evt != HCI_EV_CMD_COMPLETE) { diff --git a/projects/Amlogic/patches/linux/f-0001-ARM64-dts-meson-gx-add-ATF-BL32-reserved-memory-regi.patch b/packages/linux/patches/amlogic/amlogic-0136-HACK-arm64-dts-meson-gx-add-ATF-BL32-reserved-memory.patch similarity index 57% rename from projects/Amlogic/patches/linux/f-0001-ARM64-dts-meson-gx-add-ATF-BL32-reserved-memory-regi.patch rename to packages/linux/patches/amlogic/amlogic-0136-HACK-arm64-dts-meson-gx-add-ATF-BL32-reserved-memory.patch index aa00a276e6..d76ecf2079 100644 --- a/projects/Amlogic/patches/linux/f-0001-ARM64-dts-meson-gx-add-ATF-BL32-reserved-memory-regi.patch +++ b/packages/linux/patches/amlogic/amlogic-0136-HACK-arm64-dts-meson-gx-add-ATF-BL32-reserved-memory.patch @@ -1,21 +1,22 @@ -From 20f45db7f0cbe5523f0b6618d533f9e40cb6d051 Mon Sep 17 00:00:00 2001 +From a1eb1563c2cf8c2308ac1558e1c4ae8fb2210b2c Mon Sep 17 00:00:00 2001 From: kszaq -Date: Mon, 29 Apr 2019 22:42:13 +0200 -Subject: [PATCH] ARM64: dts: meson-gx: add ATF BL32 reserved memory region +Date: Sat, 6 Jul 2019 07:54:44 +0000 +Subject: [PATCH 136/186] HACK: arm64: dts: meson-gx: add ATF BL32 reserved + memory region -Vendor firmware/uboot has an additional reserved region -for BL32 trusted firmware. If a board uses BL32 firmware, -booting kernel without knowledge of this region would cause -an immediate kernel panic on SError Interrupt. +Vendor firmware/uboot has an additional reserved region for BL32 trusted +firmware. If a board uses BL32 firmware, booting kernel without knowledge +of this region would cause an immediate kernel panic on SError Interrupt. TODO: This should be enabled only for boards actually requiring it. +Signed-off-by: kszaq --- arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -index 8238f55..17e8d37 100644 +index 0ed78e10ce98..5a5cfaad3f5f 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi @@ -41,6 +41,12 @@ @@ -32,5 +33,5 @@ index 8238f55..17e8d37 100644 compatible = "shared-dma-pool"; reusable; -- -2.7.4 +2.17.1 diff --git a/projects/Amlogic/patches/linux/f-0002-media-rc-add-keymap-for-Amediatech-X96-MAX-remote.patch b/packages/linux/patches/amlogic/amlogic-0137-FROMGIT-media-rc-add-keymap-for-Amediatech-X96-MAX-r.patch similarity index 86% rename from projects/Amlogic/patches/linux/f-0002-media-rc-add-keymap-for-Amediatech-X96-MAX-remote.patch rename to packages/linux/patches/amlogic/amlogic-0137-FROMGIT-media-rc-add-keymap-for-Amediatech-X96-MAX-r.patch index 7c27880743..a129fbc2ce 100644 --- a/projects/Amlogic/patches/linux/f-0002-media-rc-add-keymap-for-Amediatech-X96-MAX-remote.patch +++ b/packages/linux/patches/amlogic/amlogic-0137-FROMGIT-media-rc-add-keymap-for-Amediatech-X96-MAX-r.patch @@ -1,7 +1,8 @@ -From 87585a9b61475fb44bdba734124ce6071191b201 Mon Sep 17 00:00:00 2001 +From 9b8bdc1f6534d28c22b4e4524444d6da98abf983 Mon Sep 17 00:00:00 2001 From: chewitt Date: Sun, 7 Apr 2019 04:20:56 +0000 -Subject: [PATCH 2/6] media: rc: add keymap for Amediatech X96-MAX remote +Subject: [PATCH 137/186] FROMGIT: media: rc: add keymap for Amediatech X96-MAX + remote This is a simple NEC remote control device shipped with the Amediatech X96 MAX Android 'TV Box' device. The remote contains a programmable TV @@ -17,10 +18,10 @@ Signed-off-by: Christian Hewitt create mode 100644 drivers/media/rc/keymaps/rc-x96max.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 03fbac32befb..f757305eacb2 100644 +index 5b1399af6b3a..b88c4e76cdc6 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile -@@ -118,4 +118,5 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ +@@ -117,4 +117,5 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-winfast-usbii-deluxe.o \ rc-su3000.o \ rc-xbox-dvd.o \ @@ -28,7 +29,7 @@ index 03fbac32befb..f757305eacb2 100644 rc-zx-irdec.o diff --git a/drivers/media/rc/keymaps/rc-x96max.c b/drivers/media/rc/keymaps/rc-x96max.c new file mode 100644 -index 000000000000..cea5c1c7bf36 +index 000000000000..d947e4652c92 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-x96max.c @@ -0,0 +1,85 @@ @@ -47,7 +48,7 @@ index 000000000000..cea5c1c7bf36 + + { 0x140, KEY_POWER }, + -+ // ** TV CONTROLS ** ++ // ** TV CONTROL ** + // SET + // AV/TV + // POWER @@ -57,9 +58,9 @@ index 000000000000..cea5c1c7bf36 + { 0x118, KEY_VOLUMEUP }, + { 0x110, KEY_VOLUMEDOWN }, + -+ { 0x143, KEY_CONFIG }, ++ { 0x143, KEY_MUTE }, // CONFIG + -+ { 0x100, KEY_INFO }, // MOUSE ++ { 0x100, KEY_EPG }, // MOUSE + { 0x119, KEY_BACK }, + + { 0x116, KEY_UP }, @@ -118,10 +119,10 @@ index 000000000000..cea5c1c7bf36 +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt Date: Mon, 1 Apr 2019 04:22:30 +0400 -Subject: [PATCH 27/37] media: rc: add keymap for HardKernel ODROID remote +Subject: [PATCH 138/186] FROMGIT: media: rc: add keymap for HardKernel ODROID + remote This is a simple NEC remote controll device shipped with the HardKernel ODROID range of ARM Single Board Computer (SBC) devices. @@ -15,7 +16,7 @@ Signed-off-by: Christian Hewitt create mode 100644 drivers/media/rc/keymaps/rc-odroid.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 5b1399af6b3a..03fbac32befb 100644 +index b88c4e76cdc6..f757305eacb2 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ @@ -84,10 +85,10 @@ index 000000000000..e95aab608c5a +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt Date: Mon, 29 Apr 2019 03:23:38 +0000 -Subject: [PATCH 28/37] media: rc: add keymap for Khadas VIM/EDGE remote +Subject: [PATCH 139/186] FROMGIT: media: rc: add keymap for Khadas VIM/EDGE + remote This is a simple NEC remote control device shipped with the Khadas VIM and EDGE range of ARM Single Board Computer (SBC) devices. It includes @@ -12,22 +13,21 @@ brand. Signed-off-by: Christian Hewitt --- - drivers/media/rc/keymaps/Makefile | 2 + + drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-khadas.c | 56 ++++++++++++++++++++++++++++ - include/media/rc-map.h | 2 + - 3 files changed, 60 insertions(+) + include/media/rc-map.h | 1 + + 3 files changed, 58 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-khadas.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 03fbac32befb..7cd930b43e9b 100644 +index f757305eacb2..e539d1e48e8a 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile -@@ -58,6 +58,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ +@@ -58,6 +58,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-it913x-v1.o \ rc-it913x-v2.o \ rc-kaiomy.o \ + rc-khadas.o \ -+ rc-khamsin.o \ rc-kworld-315u.o \ rc-kworld-pc150u.o \ rc-kworld-plus-tv-analog.o \ @@ -94,15 +94,14 @@ index 000000000000..bb183ed90d69 +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index 771e9e2cca50..2e4b83be000c 100644 +index c66ab0249a96..3c58ae3b6625 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h -@@ -226,6 +226,8 @@ struct rc_map *rc_map_get(const char *name); +@@ -224,6 +224,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_IT913X_V1 "rc-it913x-v1" #define RC_MAP_IT913X_V2 "rc-it913x-v2" #define RC_MAP_KAIOMY "rc-kaiomy" +#define RC_MAP_KHADAS "rc-khadas" -+#define RC_MAP_KHAMSIN "rc-khamsin" #define RC_MAP_KWORLD_315U "rc-kworld-315u" #define RC_MAP_KWORLD_PC150U "rc-kworld-pc150u" #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" diff --git a/projects/Amlogic/patches/linux/e-0031-media-rc-add-keymap-for-Tanix-TX3-mini-remote.patch b/packages/linux/patches/amlogic/amlogic-0140-FROMGIT-media-rc-add-keymap-for-Tanix-TX3-mini-remot.patch similarity index 90% rename from projects/Amlogic/patches/linux/e-0031-media-rc-add-keymap-for-Tanix-TX3-mini-remote.patch rename to packages/linux/patches/amlogic/amlogic-0140-FROMGIT-media-rc-add-keymap-for-Tanix-TX3-mini-remot.patch index a1dc9026b0..177916c53a 100644 --- a/projects/Amlogic/patches/linux/e-0031-media-rc-add-keymap-for-Tanix-TX3-mini-remote.patch +++ b/packages/linux/patches/amlogic/amlogic-0140-FROMGIT-media-rc-add-keymap-for-Tanix-TX3-mini-remot.patch @@ -1,7 +1,8 @@ -From 68be11762925f08a53f2e0ea4064550540d3d7e6 Mon Sep 17 00:00:00 2001 +From e22c63c49fbab925c4d46f6b031adfe9a16873da Mon Sep 17 00:00:00 2001 From: chewitt Date: Mon, 15 Apr 2019 02:44:48 +0000 -Subject: [PATCH 31/37] media: rc: add keymap for Tanix TX3 mini remote +Subject: [PATCH 140/186] FROMGIT: media: rc: add keymap for Tanix TX3 mini + remote This is a simple NEC remote control device shipped with the Tanix TX3 Android STB device. @@ -15,10 +16,10 @@ Signed-off-by: Christian Hewitt create mode 100644 drivers/media/rc/keymaps/rc-tanix-tx3mini.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index b29353476d0d..23382bbfb3da 100644 +index e539d1e48e8a..0d4a211a62ea 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile -@@ -98,6 +98,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ +@@ -96,6 +96,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ rc-tango.o \ @@ -112,10 +113,10 @@ index 000000000000..e5013981fdc4 +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index bd7738bf197f..30513f5d764a 100644 +index 3c58ae3b6625..ccedb96b9525 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h -@@ -267,6 +267,7 @@ struct rc_map *rc_map_get(const char *name); +@@ -263,6 +263,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" #define RC_MAP_TANGO "rc-tango" diff --git a/packages/linux/patches/amlogic/amlogic-0141-FROMGIT-media-rc-add-keymap-for-Tanix-TX5-max-remote.patch b/packages/linux/patches/amlogic/amlogic-0141-FROMGIT-media-rc-add-keymap-for-Tanix-TX5-max-remote.patch new file mode 100644 index 0000000000..f3a6e5b156 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0141-FROMGIT-media-rc-add-keymap-for-Tanix-TX5-max-remote.patch @@ -0,0 +1,118 @@ +From 585cec50beec0be33a88eec2ff65ac030c0aa418 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 12 Jul 2019 23:20:23 +0000 +Subject: [PATCH 141/186] FROMGIT: media: rc: add keymap for Tanix TX5 max + remote + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-tanix-tx5max.c | 71 ++++++++++++++++++++++ + include/media/rc-map.h | 1 + + 3 files changed, 73 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-tanix-tx5max.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 0d4a211a62ea..d675dcbaea8e 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -97,6 +97,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-streamzap.o \ + rc-tango.o \ + rc-tanix-tx3mini.o \ ++ rc-tanix-tx5max.o \ + rc-tbs-nec.o \ + rc-technisat-ts35.o \ + rc-technisat-usb2.o \ +diff --git a/drivers/media/rc/keymaps/rc-tanix-tx5max.c b/drivers/media/rc/keymaps/rc-tanix-tx5max.c +new file mode 100644 +index 000000000000..43f467f66171 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-tanix-tx5max.c +@@ -0,0 +1,71 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2018 Christian Hewitt ++ ++#include ++#include ++ ++/* ++ * This keymap is used with the Oranth Tanix TX5 max ++ * and other Android STB devices. ++ */ ++ ++static struct rc_map_table tanix_tx5max[] = { ++ ++ { 0x40404d, KEY_POWER }, ++ { 0x404043, KEY_MUTE }, ++ ++ { 0x404017, KEY_VOLUMEDOWN }, ++ { 0x404018, KEY_VOLUMEUP }, ++ ++ { 0x40400b, KEY_UP }, ++ { 0x404010, KEY_LEFT }, ++ { 0x404011, KEY_RIGHT }, ++ { 0x40400e, KEY_DOWN }, ++ { 0x40400d, KEY_OK }, ++ ++ { 0x40401a, KEY_HOME }, ++ { 0x404045, KEY_MENU }, ++ { 0x404042, KEY_BACK }, ++ ++ { 0x404001, KEY_1 }, ++ { 0x404002, KEY_2 }, ++ { 0x404003, KEY_3 }, ++ ++ { 0x404004, KEY_4 }, ++ { 0x404005, KEY_5 }, ++ { 0x404006, KEY_6 }, ++ ++ { 0x404007, KEY_7 }, ++ { 0x404008, KEY_8 }, ++ { 0x404009, KEY_9 }, ++ ++ { 0x404047, KEY_MUTE }, // mouse ++ { 0x404000, KEY_0 }, ++ { 0x40400c, KEY_DELETE }, ++ ++}; ++ ++static struct rc_map_list tanix_tx5max_map = { ++ .map = { ++ .scan = tanix_tx5max, ++ .size = ARRAY_SIZE(tanix_tx5max), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_TANIX_TX5MAX, ++ } ++}; ++ ++static int __init init_rc_map_tanix_tx5max(void) ++{ ++ return rc_map_register(&tanix_tx5max_map); ++} ++ ++static void __exit exit_rc_map_tanix_tx5max(void) ++{ ++ rc_map_unregister(&tanix_tx5max_map); ++} ++ ++module_init(init_rc_map_tanix_tx5max) ++module_exit(exit_rc_map_tanix_tx5max) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt "); +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index ccedb96b9525..0c505edf74d1 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -264,6 +264,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_STREAMZAP "rc-streamzap" + #define RC_MAP_TANGO "rc-tango" + #define RC_MAP_TANIX_TX3MINI "rc-tanix-tx3mini" ++#define RC_MAP_TANIX_TX5MAX "rc-tanix-tx5max" + #define RC_MAP_TBS_NEC "rc-tbs-nec" + #define RC_MAP_TECHNISAT_TS35 "rc-technisat-ts35" + #define RC_MAP_TECHNISAT_USB2 "rc-technisat-usb2" +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0032-media-rc-add-keymap-for-WeTek-Hub-remote.patch b/packages/linux/patches/amlogic/amlogic-0142-FROMGIT-media-rc-add-keymap-for-WeTek-Hub-remote.patch similarity index 88% rename from projects/Amlogic/patches/linux/e-0032-media-rc-add-keymap-for-WeTek-Hub-remote.patch rename to packages/linux/patches/amlogic/amlogic-0142-FROMGIT-media-rc-add-keymap-for-WeTek-Hub-remote.patch index 758d8065f7..28d1961f7b 100644 --- a/projects/Amlogic/patches/linux/e-0032-media-rc-add-keymap-for-WeTek-Hub-remote.patch +++ b/packages/linux/patches/amlogic/amlogic-0142-FROMGIT-media-rc-add-keymap-for-WeTek-Hub-remote.patch @@ -1,7 +1,7 @@ -From cb88289d080823bb33f162d05304724190b88763 Mon Sep 17 00:00:00 2001 +From 3a06ba41cb11169a1a0d16354b5546de90e63d05 Mon Sep 17 00:00:00 2001 From: chewitt Date: Mon, 15 Apr 2019 04:37:44 +0000 -Subject: [PATCH 32/37] media: rc: add keymap for WeTek Hub remote +Subject: [PATCH 142/186] FROMGIT: media: rc: add keymap for WeTek Hub remote This is a simple RC5 remote control device shipped with the WeTek Hub Android STB device. @@ -15,10 +15,10 @@ Signed-off-by: Christian Hewitt create mode 100644 drivers/media/rc/keymaps/rc-wetek-hub.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 23382bbfb3da..32f93942c3b2 100644 +index d675dcbaea8e..670a9e2f702a 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile -@@ -118,6 +118,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ +@@ -117,6 +117,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-videomate-m1f.o \ rc-videomate-s350.o \ rc-videomate-tv-pvr.o \ @@ -88,10 +88,10 @@ index 000000000000..8d114ae59669 +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index 30513f5d764a..034bd38dffe7 100644 +index 0c505edf74d1..a21a59a6f1fd 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h -@@ -287,6 +287,7 @@ struct rc_map *rc_map_get(const char *name); +@@ -284,6 +284,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100" #define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350" #define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" diff --git a/projects/Amlogic/patches/linux/e-0033-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch b/packages/linux/patches/amlogic/amlogic-0143-FROMGIT-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch similarity index 91% rename from projects/Amlogic/patches/linux/e-0033-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch rename to packages/linux/patches/amlogic/amlogic-0143-FROMGIT-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch index 4e0ca8db95..c0a8e18e9c 100644 --- a/projects/Amlogic/patches/linux/e-0033-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch +++ b/packages/linux/patches/amlogic/amlogic-0143-FROMGIT-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch @@ -1,7 +1,8 @@ -From 316e5b987b9e72138eb2270d5f3c41118b61152b Mon Sep 17 00:00:00 2001 +From cbef7b376760c5c9f5ba705c1252bd3734995dde Mon Sep 17 00:00:00 2001 From: chewitt Date: Sun, 21 Apr 2019 02:24:07 +0000 -Subject: [PATCH 33/37] media: rc: add keymap for WeTeK Play 2 remote +Subject: [PATCH 143/186] FROMGIT: media: rc: add keymap for WeTeK Play 2 + remote Signed-off-by: Christian Hewitt --- @@ -12,10 +13,10 @@ Signed-off-by: Christian Hewitt create mode 100644 drivers/media/rc/keymaps/rc-wetek-play2.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 32f93942c3b2..b2c13dac1755 100644 +index 670a9e2f702a..a56fc634d2d6 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile -@@ -119,6 +119,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ +@@ -118,6 +118,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-videomate-s350.o \ rc-videomate-tv-pvr.o \ rc-wetek-hub.o \ @@ -125,10 +126,10 @@ index 000000000000..77504f207578 +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt +Date: Sun, 9 Jun 2019 01:18:39 +0000 +Subject: [PATCH 144/186] FROMLIST: dt-bindings: Add vendor prefix for Ugoos + +Ugoos Industrial Co., Ltd. are a manufacturer of ARM based TV Boxes/Dongles, +Digital Signage and Advertisement Solutions [0]. + +[0] (https://ugoos.com) + +Signed-off-by: Christian Hewitt +--- + Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml +index 6992bbbbffab..d962be989b5d 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml ++++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml +@@ -965,6 +965,8 @@ patternProperties: + description: Ubiquiti Networks + "^udoo,.*": + description: Udoo ++ "^ugoos,.*": ++ description: Ugoos Industrial Co., Ltd. + "^uniwest,.*": + description: United Western Technologies Corp (UniWest) + "^upisemi,.*": +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0145-FROMLIST-dt-bindings-arm-amlogic-Add-support-for-the.patch b/packages/linux/patches/amlogic/amlogic-0145-FROMLIST-dt-bindings-arm-amlogic-Add-support-for-the.patch new file mode 100644 index 0000000000..0e0eba1c0e --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0145-FROMLIST-dt-bindings-arm-amlogic-Add-support-for-the.patch @@ -0,0 +1,41 @@ +From b4af1c6908d5a7e6f533081a0b50991a24b5d379 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 9 Jun 2019 01:24:14 +0000 +Subject: [PATCH 145/186] FROMLIST: dt-bindings: arm: amlogic: Add support for + the Ugoos AM6 + +The Ugoos AM6 is based on the Amlogic W400 reference design using the S922X +chipset. Hardware specifications: + +- 2GB LPDDR4 RAM +- 16GB eMMC storage +- 10/100/1000 Base-T Ethernet using External RGMII PHY +- 802.11 a/b/g/b/ac + BT 5.0 sdio wireless (Ampak 6398S) +- HDMI 2.0 (4k@60p) video +- Composite video + 2-channel audio output on 3.5mm jack +- S/PDIF audio output +- Aux input +- 1x USB 3.0 +- 3x USB 2.0 +- 1x micro SD card slot + +Signed-off-by: Christian Hewitt +--- + Documentation/devicetree/bindings/arm/amlogic.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml +index 04a2b0ef34c6..c1658ec57482 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.yaml ++++ b/Documentation/devicetree/bindings/arm/amlogic.yaml +@@ -147,6 +147,7 @@ properties: + - enum: + - hardkernel,odroid-n2 + - khadas,vim3 ++ - ugoos,am6 + - const: amlogic,s922x + - const: amlogic,g12b + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0146-FROMLIST-arm64-dts-meson-g12b-ugoos-am6-add-initial-.patch b/packages/linux/patches/amlogic/amlogic-0146-FROMLIST-arm64-dts-meson-g12b-ugoos-am6-add-initial-.patch new file mode 100644 index 0000000000..7225ba42ae --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0146-FROMLIST-arm64-dts-meson-g12b-ugoos-am6-add-initial-.patch @@ -0,0 +1,591 @@ +From 2c8c9e960f12e1668dc1d849524d28f89dbc02c0 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 9 Jun 2019 01:39:20 +0000 +Subject: [PATCH 146/186] FROMLIST: arm64: dts: meson-g12b-ugoos-am6: add + initial device-tree + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/Makefile | 1 + + .../boot/dts/amlogic/meson-g12b-ugoos-am6.dts | 557 ++++++++++++++++++ + 2 files changed, 558 insertions(+) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts + +diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile +index ae5e8d0c08da..cb4dafc137c4 100644 +--- a/arch/arm64/boot/dts/amlogic/Makefile ++++ b/arch/arm64/boot/dts/amlogic/Makefile +@@ -6,6 +6,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12b-s922x-khadas-vim3.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb ++dtb-$(CONFIG_ARCH_MESON) += meson-g12b-ugoos-am6.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-odroidc2.dtb +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts +new file mode 100644 +index 000000000000..585c42f949c1 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts +@@ -0,0 +1,557 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ * Copyright (c) 2019 Christian Hewitt ++ */ ++ ++/dts-v1/; ++ ++#include "meson-g12b.dtsi" ++#include "meson-g12b-s922x.dtsi" ++#include ++#include ++#include ++ ++/ { ++ compatible = "ugoos,am6", "amlogic,g12b"; ++ model = "Ugoos AM6"; ++ ++ aliases { ++ serial0 = &uart_AO; ++ ethernet0 = ðmac; ++ }; ++ ++ spdif_dit: audio-codec-1 { ++ #sound-dai-cells = <0>; ++ compatible = "linux,spdif-dit"; ++ status = "okay"; ++ sound-name-prefix = "DIT"; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; ++ }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; ++ ++ flash_1v8: regulator-flash_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "FLASH_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ main_12v: regulator-main_12v { ++ compatible = "regulator-fixed"; ++ regulator-name = "12V"; ++ regulator-min-microvolt = <12000000>; ++ regulator-max-microvolt = <12000000>; ++ regulator-always-on; ++ }; ++ ++ vcc_5v: regulator-vcc_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&main_12v>; ++ ++ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; ++ enable-active-high; ++ }; ++ ++ vcc_1v8: regulator-vcc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ /* FIXME: actually controlled by VDDCPU_B_EN */ ++ }; ++ ++ vddcpu_a: regulator-vddcpu-a { ++ /* ++ * MP8756GD Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU_A"; ++ regulator-min-microvolt = <721000>; ++ regulator-max-microvolt = <1022000>; ++ ++ vin-supply = <&main_12v>; ++ ++ pwms = <&pwm_ab 0 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vddcpu_b: regulator-vddcpu-b { ++ /* ++ * Silergy SY8120B1ABC Regulator. ++ */ ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VDDCPU_B"; ++ regulator-min-microvolt = <721000>; ++ regulator-max-microvolt = <1022000>; ++ ++ vin-supply = <&main_12v>; ++ ++ pwms = <&pwm_AO_cd 1 1250 0>; ++ pwm-dutycycle-range = <100 0>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ usb1_pow: regulator-usb1_pow { ++ compatible = "regulator-fixed"; ++ regulator-name = "USB1_POW"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc_5v>; ++ ++ gpio = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ usb_pwr_en: regulator-usb_pwr_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "USB_PWR_EN"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc_5v>; ++ ++ gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ vddao_1v8: regulator-vddao_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ }; ++ ++ vddao_3v3: regulator-vddao_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&main_12v>; ++ regulator-always-on; ++ }; ++ ++ cvbs-connector { ++ compatible = "composite-video-connector"; ++ ++ port { ++ cvbs_connector_in: endpoint { ++ remote-endpoint = <&cvbs_vdac_out>; ++ }; ++ }; ++ }; ++ ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ ++ sound { ++ compatible = "amlogic,axg-sound-card"; ++ model = "G12B-UGOOS-AM6"; ++ audio-aux-devs = <&tdmout_b>; ++ audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", ++ "TDMOUT_B IN 1", "FRDDR_B OUT 1", ++ "TDMOUT_B IN 2", "FRDDR_C OUT 1", ++ "TDM_B Playback", "TDMOUT_B OUT", ++ "SPDIFOUT IN 0", "FRDDR_A OUT 3", ++ "SPDIFOUT IN 1", "FRDDR_B OUT 3", ++ "SPDIFOUT IN 2", "FRDDR_C OUT 3"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ status = "okay"; ++ ++ dai-link-0 { ++ sound-dai = <&frddr_a>; ++ }; ++ ++ dai-link-1 { ++ sound-dai = <&frddr_b>; ++ }; ++ ++ dai-link-2 { ++ sound-dai = <&frddr_c>; ++ }; ++ ++ /* 8ch hdmi interface */ ++ dai-link-3 { ++ sound-dai = <&tdmif_b>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ dai-tdm-slot-tx-mask-1 = <1 1>; ++ dai-tdm-slot-tx-mask-2 = <1 1>; ++ dai-tdm-slot-tx-mask-3 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec { ++ sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; ++ }; ++ }; ++ ++ /* spdif hdmi or toslink interface */ ++ dai-link-4 { ++ sound-dai = <&spdifout>; ++ ++ codec-0 { ++ sound-dai = <&spdif_dit>; ++ }; ++ ++ codec-1 { ++ sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_A>; ++ }; ++ }; ++ ++ /* spdif hdmi interface */ ++ dai-link-5 { ++ sound-dai = <&spdifout_b>; ++ ++ codec { ++ sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_B>; ++ }; ++ }; ++ ++ /* hdmi glue */ ++ dai-link-6 { ++ sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ ++ }; ++}; ++ ++&arb { ++ status = "okay"; ++}; ++ ++&cec_AO { ++ pinctrl-0 = <&cec_ao_a_h_pins>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ hdmi-phandle = <&hdmi_tx>; ++}; ++ ++&cecb_AO { ++ pinctrl-0 = <&cec_ao_b_h_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ hdmi-phandle = <&hdmi_tx>; ++}; ++ ++&clkc_audio { ++ status = "okay"; ++}; ++ ++&cpu0 { ++ cpu-supply = <&vddcpu_b>; ++ operating-points-v2 = <&cpu_opp_table_0>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vddcpu_b>; ++ operating-points-v2 = <&cpu_opp_table_0>; ++ clocks = <&clkc CLKID_CPU_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu100 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu101 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu102 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cpu103 { ++ cpu-supply = <&vddcpu_a>; ++ operating-points-v2 = <&cpub_opp_table_1>; ++ clocks = <&clkc CLKID_CPUB_CLK>; ++ clock-latency = <50000>; ++}; ++ ++&cvbs_vdac_port { ++ cvbs_vdac_out: endpoint { ++ remote-endpoint = <&cvbs_connector_in>; ++ }; ++}; ++ ++&ext_mdio { ++ external_phy: ethernet-phy@0 { ++ /* Realtek RTL8211F (0x001cc916) */ ++ reg = <0>; ++ max-speed = <1000>; ++ ++ reset-assert-us = <10000>; ++ reset-deassert-us = <30000>; ++ reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; ++ ++ interrupt-parent = <&gpio_intc>; ++ /* MAC_INTR on GPIOZ_14 */ ++ interrupts = <26 IRQ_TYPE_LEVEL_LOW>; ++ }; ++}; ++ ++ðmac { ++ pinctrl-0 = <ð_pins>, <ð_rgmii_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ phy-mode = "rgmii"; ++ phy-handle = <&external_phy>; ++ amlogic,tx-delay-ns = <2>; ++}; ++ ++&frddr_a { ++ status = "okay"; ++}; ++ ++&frddr_b { ++ status = "okay"; ++}; ++ ++&frddr_c { ++ status = "okay"; ++}; ++ ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; ++ pinctrl-names = "default"; ++ hdmi-supply = <&vcc_5v>; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++ linux,rc-map-name = "rc-khadas"; ++}; ++ ++&pwm_ab { ++ pinctrl-0 = <&pwm_a_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin0"; ++ status = "okay"; ++}; ++ ++&pwm_AO_cd { ++ pinctrl-0 = <&pwm_ao_d_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin1"; ++ status = "okay"; ++}; ++ ++&pwm_ef { ++ pinctrl-0 = <&pwm_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>; ++ clock-names = "clkin0"; ++ status = "okay"; ++}; ++ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ max-speed = <2000000>; ++ clocks = <&wifi32k>; ++ clock-names = "lpo"; ++ }; ++}; ++ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&usb { ++ status = "okay"; ++ dr_mode = "host"; ++ vbus-regulator = <&usb_pwr_en>; ++}; ++ ++&usb2_phy0 { ++ phy-supply = <&usb1_pow>; ++}; ++ ++&usb2_phy1 { ++ phy-supply = <&usb1_pow>; ++}; ++ ++/* SDIO */ ++&sd_emmc_a { ++ status = "okay"; ++ pinctrl-0 = <&sdio_pins>; ++ pinctrl-1 = <&sdio_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ sd-uhs-sdr50; ++ max-frequency = <100000000>; ++ ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddao_1v8>; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; ++}; ++ ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ pinctrl-0 = <&sdcard_c_pins>; ++ pinctrl-1 = <&sdcard_clk_gate_c_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ max-frequency = <50000000>; ++ disable-wp; ++ ++ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddao_3v3>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; ++ pinctrl-1 = <&emmc_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ mmc-ddr-1_8v; ++ mmc-hs200-1_8v; ++ max-frequency = <200000000>; ++ disable-wp; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&flash_1v8>; ++}; ++ ++&spdifout { ++ pinctrl-0 = <&spdif_out_h_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&spdifout_b { ++ status = "okay"; ++}; ++ ++&tdmif_b { ++ status = "okay"; ++}; ++ ++&tdmout_b { ++ status = "okay"; ++}; ++ ++&tohdmitx { ++ status = "okay"; ++}; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0147-WIP-arm64-dts-meson-g12b-ugoos-am6-use-common-audio-.patch b/packages/linux/patches/amlogic/amlogic-0147-WIP-arm64-dts-meson-g12b-ugoos-am6-use-common-audio-.patch new file mode 100644 index 0000000000..3800bfe807 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0147-WIP-arm64-dts-meson-g12b-ugoos-am6-use-common-audio-.patch @@ -0,0 +1,29 @@ +From b1715315ec3ea3c373fda45c9d4f5f25f39ec5a4 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Tue, 2 Jul 2019 06:17:51 +0000 +Subject: [PATCH 147/186] WIP: arm64: dts: meson-g12b-ugoos-am6: use common + audio-card-name + +Change to AMLG12 to use the common AMLG12 alsa configuration. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts +index 585c42f949c1..e42c22804da2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts +@@ -198,7 +198,7 @@ + + sound { + compatible = "amlogic,axg-sound-card"; +- model = "G12B-UGOOS-AM6"; ++ model = "AMLG12"; + audio-aux-devs = <&tdmout_b>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0148-WIP-arm64-dts-meson-g12b-ugoos-am6-add-minimal-therm.patch b/packages/linux/patches/amlogic/amlogic-0148-WIP-arm64-dts-meson-g12b-ugoos-am6-add-minimal-therm.patch new file mode 100644 index 0000000000..ab28a72053 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0148-WIP-arm64-dts-meson-g12b-ugoos-am6-add-minimal-therm.patch @@ -0,0 +1,141 @@ +From a7d9aa310926b4f65a17a5cf3cd3a458c6115f4e Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Thu, 22 Aug 2019 14:17:29 +0000 +Subject: [PATCH 148/186] WIP: arm64: dts: meson-g12b-ugoos-am6: add minimal + thermal zone + +Signed-off-by: Christian Hewitt +--- + .../boot/dts/amlogic/meson-g12b-ugoos-am6.dts | 60 +++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts +index e42c22804da2..267e13fac579 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + / { + compatible = "ugoos,am6", "amlogic,g12b"; +@@ -29,6 +30,55 @@ + sound-name-prefix = "DIT"; + }; + ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&cpu_temp>; ++ ++ trips { ++ cpu_critical: cpu-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&cpu_critical>; ++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu101 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu102 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu103 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ ++ ddr-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&ddr_temp>; ++ ++ trips { ++ ddr_critical: ddr-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&ddr_critical>; ++ cooling-device = <&mali THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -311,6 +361,7 @@ + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu1 { +@@ -318,6 +369,7 @@ + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu100 { +@@ -325,6 +377,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu101 { +@@ -332,6 +385,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu102 { +@@ -339,6 +393,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu103 { +@@ -346,6 +401,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cvbs_vdac_port { +@@ -411,6 +467,10 @@ + linux,rc-map-name = "rc-khadas"; + }; + ++&mali { ++ #cooling-cells = <2>; ++}; ++ + &pwm_ab { + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0149-WIP-arm64-dts-meson-g12b-khadas-vim3-add-minimal-the.patch b/packages/linux/patches/amlogic/amlogic-0149-WIP-arm64-dts-meson-g12b-khadas-vim3-add-minimal-the.patch new file mode 100644 index 0000000000..aed39d7105 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0149-WIP-arm64-dts-meson-g12b-khadas-vim3-add-minimal-the.patch @@ -0,0 +1,143 @@ +From 3b067bf34f3f787a6fbec32fe4136b0e119d84ab Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 11 Aug 2019 03:08:17 +0000 +Subject: [PATCH 149/186] WIP: arm64: dts: meson-g12b-khadas-vim3: add minimal + thermal zone + +Add minimal thermal zone for DDR and CPU sensor + +Signed-off-by: Christian Hewitt +--- + .../dts/amlogic/meson-g12b-khadas-vim3.dtsi | 60 +++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +index 382148ef882a..3e86356834ed 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + / { + model = "Khadas VIM3"; +@@ -18,6 +19,55 @@ + ethernet0 = ðmac; + }; + ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&cpu_temp>; ++ ++ trips { ++ cpu_critical: cpu-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&cpu_critical>; ++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu101 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu102 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu103 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ ++ ddr-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&ddr_temp>; ++ ++ trips { ++ ddr_critical: ddr-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&ddr_critical>; ++ cooling-device = <&mali THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -294,6 +344,7 @@ + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu1 { +@@ -301,6 +352,7 @@ + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu100 { +@@ -308,6 +360,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu101 { +@@ -315,6 +368,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu102 { +@@ -322,6 +376,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu103 { +@@ -329,6 +384,7 @@ + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &ext_mdio { +@@ -400,6 +456,10 @@ + linux,rc-map-name = "rc-khadas"; + }; + ++&mali { ++ #cooling-cells = <2>; ++}; ++ + &pwm_ab { + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0150-WIP-arm64-dts-meson-g12b-khadas-vim3-add-the-Etherne.patch b/packages/linux/patches/amlogic/amlogic-0150-WIP-arm64-dts-meson-g12b-khadas-vim3-add-the-Etherne.patch new file mode 100644 index 0000000000..e985901116 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0150-WIP-arm64-dts-meson-g12b-khadas-vim3-add-the-Etherne.patch @@ -0,0 +1,33 @@ +From 3ec88b0b92b400530b177cfa157248c0e05290b8 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 11 Aug 2019 10:01:25 +0000 +Subject: [PATCH 150/186] WIP: arm64: dts: meson-g12b-khadas-vim3: add the + Ethernet PHY interrupt line + +apply the same change as [0] to VIM3. + +[0] https://github.com/torvalds/linux/commit/98ba71c94eaff1c3af6170bce9fe63c93dd32f2f + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +index 3e86356834ed..6d49550dca34 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +@@ -392,6 +392,10 @@ + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + max-speed = <1000>; ++ ++ interrupt-parent = <&gpio_intc>; ++ /* MAC_INTR on GPIOZ_14 */ ++ interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + }; + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0151-WIP-arm64-dts-meson-g12b-khadas-vim3-add-acceleromet.patch b/packages/linux/patches/amlogic/amlogic-0151-WIP-arm64-dts-meson-g12b-khadas-vim3-add-acceleromet.patch new file mode 100644 index 0000000000..06b07338c6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0151-WIP-arm64-dts-meson-g12b-khadas-vim3-add-acceleromet.patch @@ -0,0 +1,63 @@ +From 20d00e0eda02f98a735814c7d3fbb99eda10a95a Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 12 Aug 2019 03:14:54 +0000 +Subject: [PATCH 151/186] WIP: arm64: dts: meson-g12b-khadas-vim3: add + accelerometer and usb-c port + +Signed-off-by: Christian Hewitt +--- + .../dts/amlogic/meson-g12b-khadas-vim3.dtsi | 24 ++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +index 6d49550dca34..5a84185c4e9a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +@@ -110,7 +110,6 @@ + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; + }; + +- + gpio-keys-polled { + compatible = "gpio-keys-polled"; + poll-interval = <100>; +@@ -438,6 +437,13 @@ + pinctrl-0 = <&i2c_ao_sck_pins>, <&i2c_ao_sda_pins>; + pinctrl-names = "default"; + ++ sensor@e { ++ compatible = "kionix,kxtj21009"; ++ reg = <0xe>; ++ interrupt-parent = <&gpio_intc>; ++ interrupts = <9 IRQ_TYPE_LEVEL_LOW>; ++ }; ++ + gpio_expander: gpio-controller@20 { + compatible = "ti,tca6408"; + reg = <0x20>; +@@ -446,6 +452,22 @@ + #gpio-cells = <2>; + }; + ++ fusb302: typec-portc@22 { ++ compatible = "fcs,fusb302"; ++ reg = <0x22>; ++ interrupt-parent = <&gpio_intc>; ++ interrupts = <8 IRQ_TYPE_LEVEL_LOW>; ++ ++ usb_con: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C"; ++ power-role = "sink"; ++ data-role = "dual"; ++ sink-pdos = ; ++ op-sink-microwatt = <10000000>; ++ }; ++ }; ++ + rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0152-WIP-arm64-dts-meson-g12b-khadas-vim3-disable-LED-hea.patch b/packages/linux/patches/amlogic/amlogic-0152-WIP-arm64-dts-meson-g12b-khadas-vim3-disable-LED-hea.patch new file mode 100644 index 0000000000..f633b49c3b --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0152-WIP-arm64-dts-meson-g12b-khadas-vim3-disable-LED-hea.patch @@ -0,0 +1,29 @@ +From e8a162ef075d31208b74b8602c43c040984dab0a Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 10 Aug 2019 19:19:00 +0000 +Subject: [PATCH 152/186] WIP: arm64: dts: meson-g12b-khadas-vim3: disable LED + heartbeat + +The constantly flashing white LED heartbeat is annoying for an HTPC device +so remove the heartbeat line. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +index 5a84185c4e9a..0cac7bb18678 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +@@ -96,7 +96,6 @@ + white { + label = "vim3:white"; + gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>; +- linux,default-trigger = "heartbeat"; + }; + + red { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0153-WIP-arm64-dts-meson-g12b-khadas-vim3-set-AMLG12-audi.patch b/packages/linux/patches/amlogic/amlogic-0153-WIP-arm64-dts-meson-g12b-khadas-vim3-set-AMLG12-audi.patch new file mode 100644 index 0000000000..674200e647 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0153-WIP-arm64-dts-meson-g12b-khadas-vim3-set-AMLG12-audi.patch @@ -0,0 +1,27 @@ +From bff2617b44e9985eb88b8ce7187788579cdd9b15 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 10 Aug 2019 18:47:19 +0000 +Subject: [PATCH 153/186] WIP: arm64: dts: meson-g12b-khadas-vim3: set AMLG12 + audio card name + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +index 0cac7bb18678..b63de6571551 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi +@@ -261,7 +261,7 @@ + + sound { + compatible = "amlogic,axg-sound-card"; +- model = "G12A-KHADAS-VIM3"; ++ model = "AMLG12"; + audio-aux-devs = <&tdmout_b>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/f-0003-arm64-dts-meson-g12b-odroid-n2-add-rc-odroid-ir-keym.patch b/packages/linux/patches/amlogic/amlogic-0154-FROMGIT-arm64-dts-meson-g12b-odroid-n2-add-rc-odroid.patch similarity index 68% rename from projects/Amlogic/patches/linux/f-0003-arm64-dts-meson-g12b-odroid-n2-add-rc-odroid-ir-keym.patch rename to packages/linux/patches/amlogic/amlogic-0154-FROMGIT-arm64-dts-meson-g12b-odroid-n2-add-rc-odroid.patch index c604ff939d..d8996e0440 100644 --- a/projects/Amlogic/patches/linux/f-0003-arm64-dts-meson-g12b-odroid-n2-add-rc-odroid-ir-keym.patch +++ b/packages/linux/patches/amlogic/amlogic-0154-FROMGIT-arm64-dts-meson-g12b-odroid-n2-add-rc-odroid.patch @@ -1,7 +1,8 @@ -From 827fdc48e582dad1a78b14ed800de8ddc614ea5b Mon Sep 17 00:00:00 2001 +From 435286b67ee5c72f9126dba2c1becbaba998fc7a Mon Sep 17 00:00:00 2001 From: chewitt -Date: Sat, 20 Apr 2019 23:51:04 +0000 -Subject: [PATCH 3/6] arm64: dts: meson-g12b-odroid-n2: add rc-odroid ir keymap +Date: Sat, 10 Aug 2019 14:28:14 +0000 +Subject: [PATCH 154/186] FROMGIT: arm64: dts: meson-g12b-odroid-n2: add + rc-odroid ir keymap Signed-off-by: Christian Hewitt --- @@ -9,17 +10,17 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts -index 380b5cebb21d..9ab68ff0cca3 100644 +index 57c84aa9890c..9d9850235f21 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts -@@ -228,6 +228,7 @@ +@@ -455,6 +455,7 @@ status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default"; + linux,rc-map-name = "rc-odroid"; }; - /* SD card */ + &pwm_ab { -- 2.17.1 diff --git a/packages/linux/patches/amlogic/amlogic-0155-WIP-arm64-dts-meson-g12b-odroid-n2-add-battery-rtc-s.patch b/packages/linux/patches/amlogic/amlogic-0155-WIP-arm64-dts-meson-g12b-odroid-n2-add-battery-rtc-s.patch new file mode 100644 index 0000000000..408cffea07 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0155-WIP-arm64-dts-meson-g12b-odroid-n2-add-battery-rtc-s.patch @@ -0,0 +1,70 @@ +From 1a96236b7bf711655795d6e93e51da0a539fd2e2 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 12 Aug 2019 02:55:09 +0000 +Subject: [PATCH 155/186] WIP: arm64: dts: meson-g12b-odroid-n2: add battery + rtc support + +Changes suggested in Odroid forum [0] to enable battery RTC support + +[0] https://forum.odroid.com/viewtopic.php?f=176&t=33993&start=300#p262877 + +Signed-off-by: Christian Hewitt +--- + .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 41 +++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index 9d9850235f21..2f9247b5ac17 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -458,6 +458,47 @@ + linux,rc-map-name = "rc-odroid"; + }; + ++&i2c3_sda_a_pins { ++ mux { ++ groups = "i2c3_sda_a"; ++ function = "i2c3"; ++ bias-pull-up; ++ drive-strength-microamp = <3000>; ++ }; ++}; ++ ++&i2c3_sck_a_pins { ++ mux { ++ groups = "i2c3_sck_a"; ++ function = "i2c3"; ++ bias-pull-up; ++ drive-strength-microamp = <3000>; ++ }; ++}; ++ ++&i2c3 { ++ status = "okay"; ++ pinctrl-names = "default","gpio_periphs"; ++ pinctrl-0 = <&i2c3_sck_a_pins &i2c3_sda_a_pins>; ++ pinctrl-1 = <&i2c3_to_gpioa>; ++ clock-frequency = <100000>; /* default 100k */ ++ ++ pcf8563: rtc@51 { /*I2C-bus slave address: read A3h and write A2h*/ ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; ++}; ++ ++&periphs_pinctrl { ++ i2c3_to_gpioa:i2c3_gpioa { ++ mux { ++ groups = "GPIOA_14", "GPIOA_15"; ++ function = "gpio_periphs"; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++}; ++ + &pwm_ab { + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0156-WIP-arm64-dts-meson-g12b-odroid-n2-disable-LED-heart.patch b/packages/linux/patches/amlogic/amlogic-0156-WIP-arm64-dts-meson-g12b-odroid-n2-disable-LED-heart.patch new file mode 100644 index 0000000000..084ee5424c --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0156-WIP-arm64-dts-meson-g12b-odroid-n2-disable-LED-heart.patch @@ -0,0 +1,29 @@ +From 07894fb13420bfa3ecd0b3a2c6291d55a8542ace Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 11 Aug 2019 09:45:04 +0000 +Subject: [PATCH 156/186] WIP: arm64: dts: meson-g12b-odroid-n2: disable LED + heartbeat + +The constantly flashing blue LED heartbeat is annoying for an HTPC device +so remove the heartbeat line. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index 2f9247b5ac17..a8f47fd1cf69 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -90,7 +90,6 @@ + blue { + label = "n2:blue"; + gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "heartbeat"; + }; + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0157-WIP-arm64-dts-meson-g12b-odroid-n2-set-AMLG12-audio-.patch b/packages/linux/patches/amlogic/amlogic-0157-WIP-arm64-dts-meson-g12b-odroid-n2-set-AMLG12-audio-.patch new file mode 100644 index 0000000000..8518ffaf76 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0157-WIP-arm64-dts-meson-g12b-odroid-n2-set-AMLG12-audio-.patch @@ -0,0 +1,27 @@ +From e8ddf0d3f2214d92469b29cf51031f826d49d387 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 10 Aug 2019 18:48:54 +0000 +Subject: [PATCH 157/186] WIP: arm64: dts: meson-g12b-odroid-n2: set AMLG12 + audio card name + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index a8f47fd1cf69..e45d964e6d84 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -257,7 +257,7 @@ + + sound { + compatible = "amlogic,axg-sound-card"; +- model = "G12A-ODROIDN2"; ++ model = "AMLG12"; + audio-aux-devs = <&tdmout_b>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0158-WIP-arm64-dts-meson-g12a-sei510-set-AMLG12-audio-car.patch b/packages/linux/patches/amlogic/amlogic-0158-WIP-arm64-dts-meson-g12a-sei510-set-AMLG12-audio-car.patch new file mode 100644 index 0000000000..e79d4ccba9 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0158-WIP-arm64-dts-meson-g12a-sei510-set-AMLG12-audio-car.patch @@ -0,0 +1,27 @@ +From 4b7b3835dd376f536f682aebfa951ece46259f00 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 10 Aug 2019 18:42:54 +0000 +Subject: [PATCH 158/186] WIP: arm64: dts: meson-g12a-sei510: set AMLG12 audio + card name + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 3e8621d7e6a5..967699bf0ec1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -229,7 +229,7 @@ + + sound { + compatible = "amlogic,axg-sound-card"; +- model = "G12A-SEI510"; ++ model = "AMLG12"; + audio-aux-devs = <&tdmout_a>, <&tdmout_b>, + <&tdmin_a>, <&tdmin_b>; + audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0159-WIP-arm64-dts-meson-g12a-u200-add-minimal-thermal-zo.patch b/packages/linux/patches/amlogic/amlogic-0159-WIP-arm64-dts-meson-g12a-u200-add-minimal-thermal-zo.patch new file mode 100644 index 0000000000..f5ad95de34 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0159-WIP-arm64-dts-meson-g12a-u200-add-minimal-thermal-zo.patch @@ -0,0 +1,125 @@ +From 67634e63c2c6c0599860afe2f3add4053b17c8d5 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 11 Aug 2019 03:09:33 +0000 +Subject: [PATCH 159/186] WIP: arm64: dts: meson-g12a-u200: add minimal thermal + zone + +Add minimal thermal zone for DDR and CPU sensor + +Signed-off-by: Christian Hewitt +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 56 +++++++++++++++++++ + 1 file changed, 56 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 2a324f0136e3..96dc6da95e22 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -8,6 +8,7 @@ + #include "meson-g12a.dtsi" + #include + #include ++#include + + / { + compatible = "amlogic,u200", "amlogic,g12a"; +@@ -18,6 +19,53 @@ + ethernet0 = ðmac; + }; + ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&cpu_temp>; ++ ++ trips { ++ cpu_critical: cpu-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&cpu_critical>; ++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ ++ ddr-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&ddr_temp>; ++ ++ trips { ++ ddr_critical: ddr-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&ddr_critical>; ++ cooling-device = <&mali THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -168,6 +216,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu1 { +@@ -175,6 +224,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu2 { +@@ -182,6 +232,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu3 { +@@ -189,6 +240,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cvbs_vdac_port { +@@ -243,6 +295,10 @@ + pinctrl-names = "default"; + }; + ++&mali { ++ #cooling-cells = <2>; ++}; ++ + &pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0160-WIP-arm64-dts-meson-g12a-u200-add-sound-card.patch b/packages/linux/patches/amlogic/amlogic-0160-WIP-arm64-dts-meson-g12a-u200-add-sound-card.patch new file mode 100644 index 0000000000..711cd88a97 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0160-WIP-arm64-dts-meson-g12a-u200-add-sound-card.patch @@ -0,0 +1,189 @@ +From 5955678ac7af004b4fc21a3fe5656e8fe80b2100 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Thu, 15 Aug 2019 08:26:34 +0000 +Subject: [PATCH 160/186] WIP: arm64: dts: meson-g12a-u200: add sound card + +Signed-off-by: chewitt +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 130 ++++++++++++++++++ + 1 file changed, 130 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 96dc6da95e22..70a6161d2f41 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -8,6 +8,7 @@ + #include "meson-g12a.dtsi" + #include + #include ++#include + #include + + / { +@@ -66,6 +67,13 @@ + }; + }; + ++ spdif_dit: audio-codec-1 { ++ #sound-dai-cells = <0>; ++ compatible = "linux,spdif-dit"; ++ status = "okay"; ++ sound-name-prefix = "DIT"; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -195,6 +203,90 @@ + regulator-boot-on; + regulator-always-on; + }; ++ ++ sound { ++ compatible = "amlogic,axg-sound-card"; ++ model = "G12A-U200"; ++ audio-aux-devs = <&tdmout_b>; ++ audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", ++ "TDMOUT_B IN 1", "FRDDR_B OUT 1", ++ "TDMOUT_B IN 2", "FRDDR_C OUT 1", ++ "TDM_B Playback", "TDMOUT_B OUT", ++ "SPDIFOUT IN 0", "FRDDR_A OUT 3", ++ "SPDIFOUT IN 1", "FRDDR_B OUT 3", ++ "SPDIFOUT IN 2", "FRDDR_C OUT 3"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ status = "okay"; ++ ++ dai-link-0 { ++ sound-dai = <&frddr_a>; ++ }; ++ ++ dai-link-1 { ++ sound-dai = <&frddr_b>; ++ }; ++ ++ dai-link-2 { ++ sound-dai = <&frddr_c>; ++ }; ++ ++ /* 8ch hdmi interface */ ++ dai-link-3 { ++ sound-dai = <&tdmif_b>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ dai-tdm-slot-tx-mask-1 = <1 1>; ++ dai-tdm-slot-tx-mask-2 = <1 1>; ++ dai-tdm-slot-tx-mask-3 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec { ++ sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; ++ }; ++ }; ++ ++ /* spdif hdmi or toslink interface */ ++ dai-link-4 { ++ sound-dai = <&spdifout>; ++ ++ codec-0 { ++ sound-dai = <&spdif_dit>; ++ }; ++ ++ codec-1 { ++ sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_A>; ++ }; ++ }; ++ ++ /* spdif hdmi interface */ ++ dai-link-5 { ++ sound-dai = <&spdifout_b>; ++ ++ codec { ++ sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_B>; ++ }; ++ }; ++ ++ /* hdmi glue */ ++ dai-link-6 { ++ sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++}; ++ ++&arb { ++ status = "okay"; + }; + + &cec_AO { +@@ -243,6 +335,10 @@ + #cooling-cells = <2>; + }; + ++&clkc_audio { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +@@ -255,6 +351,18 @@ + phy-mode = "rmii"; + }; + ++&frddr_a { ++ status = "okay"; ++}; ++ ++&frddr_b { ++ status = "okay"; ++}; ++ ++&frddr_c { ++ status = "okay"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; +@@ -344,6 +452,28 @@ + vqmmc-supply = <&flash_1v8>; + }; + ++&spdifout { ++ pinctrl-0 = <&spdif_out_h_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&spdifout_b { ++ status = "okay"; ++}; ++ ++&tdmif_b { ++ status = "okay"; ++}; ++ ++&tdmout_b { ++ status = "okay"; ++}; ++ ++&tohdmitx { ++ status = "okay"; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0161-WIP-arm64-dts-meson-g12a-x96-max-add-minimal-thermal.patch b/packages/linux/patches/amlogic/amlogic-0161-WIP-arm64-dts-meson-g12a-x96-max-add-minimal-thermal.patch new file mode 100644 index 0000000000..b13cf40ce8 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0161-WIP-arm64-dts-meson-g12a-x96-max-add-minimal-thermal.patch @@ -0,0 +1,125 @@ +From 5b95f1144ce2c7c697aebb6a200786b759b7eb63 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 11 Aug 2019 03:10:13 +0000 +Subject: [PATCH 161/186] WIP: arm64: dts: meson-g12a-x96-max: add minimal + thermal zone + +Add minimal thermal zone for DDR and CPU sensor + +Signed-off-by: Christian Hewitt +--- + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 56 +++++++++++++++++++ + 1 file changed, 56 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index c1e58a69d434..e1e9195e14d6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + / { + compatible = "amediatech,x96-max", "amlogic,u200", "amlogic,g12a"; +@@ -26,6 +27,53 @@ + sound-name-prefix = "DIT"; + }; + ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&cpu_temp>; ++ ++ trips { ++ cpu_critical: cpu-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&cpu_critical>; ++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, ++ <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ ++ ddr-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <100>; ++ thermal-sensors = <&ddr_temp>; ++ ++ trips { ++ ddr_critical: ddr-critical { ++ temperature = <110000>; /* millicelsius */ ++ hysteresis = <2000>; /* millicelsius */ ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map { ++ trip = <&ddr_critical>; ++ cooling-device = <&mali THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -263,6 +311,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu1 { +@@ -270,6 +319,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu2 { +@@ -277,6 +327,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cpu3 { +@@ -284,6 +335,7 @@ + operating-points-v2 = <&cpu_opp_table>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; ++ #cooling-cells = <2>; + }; + + &cvbs_vdac_port { +@@ -323,6 +375,10 @@ + pinctrl-names = "default"; + }; + ++&mali { ++ #cooling-cells = <2>; ++}; ++ + &pwm_AO_cd { + pinctrl-0 = <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/f-0004-arm64-dts-meson-g12a-x96-max-add-rc-x96max-ir-keymap.patch b/packages/linux/patches/amlogic/amlogic-0162-FROMGIT-arm64-dts-meson-g12a-x96-max-add-rc-x96max-i.patch similarity index 73% rename from projects/Amlogic/patches/linux/f-0004-arm64-dts-meson-g12a-x96-max-add-rc-x96max-ir-keymap.patch rename to packages/linux/patches/amlogic/amlogic-0162-FROMGIT-arm64-dts-meson-g12a-x96-max-add-rc-x96max-i.patch index 818762ab94..e71a66b602 100644 --- a/projects/Amlogic/patches/linux/f-0004-arm64-dts-meson-g12a-x96-max-add-rc-x96max-ir-keymap.patch +++ b/packages/linux/patches/amlogic/amlogic-0162-FROMGIT-arm64-dts-meson-g12a-x96-max-add-rc-x96max-i.patch @@ -1,7 +1,8 @@ -From 8337a65c09a0252ac8d25e1c5720cafd8c635252 Mon Sep 17 00:00:00 2001 +From 0fb5c4aae32c3d92a3e08fc95bad2937457f109c Mon Sep 17 00:00:00 2001 From: chewitt Date: Sat, 20 Apr 2019 23:52:15 +0000 -Subject: [PATCH 4/6] arm64: dts: meson-g12a-x96-max: add rc-x96max ir keymap +Subject: [PATCH 162/186] FROMGIT: arm64: dts: meson-g12a-x96-max: add + rc-x96max ir keymap Signed-off-by: Christian Hewitt --- @@ -9,17 +10,17 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 648b7deed22d..3ad4db440fbd 100644 +index e1e9195e14d6..8078a7f3c80a 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -168,6 +168,7 @@ +@@ -373,6 +373,7 @@ status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default"; + linux,rc-map-name = "rc-x96max"; }; - &ext_mdio { + &mali { -- 2.17.1 diff --git a/packages/linux/patches/amlogic/amlogic-0163-WIP-arm64-dts-meson-g12a-x96-max-set-AMLG12-audio-ca.patch b/packages/linux/patches/amlogic/amlogic-0163-WIP-arm64-dts-meson-g12a-x96-max-set-AMLG12-audio-ca.patch new file mode 100644 index 0000000000..1eb4aa54ad --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0163-WIP-arm64-dts-meson-g12a-x96-max-set-AMLG12-audio-ca.patch @@ -0,0 +1,30 @@ +From acb5faed3f2474cddc1f819738e71dc0bff95f87 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 18 May 2019 08:11:40 +0000 +Subject: [PATCH 163/186] WIP: arm64: dts: meson-g12a-x96-max: set AMLG12 audio + card name + +The audio card name needs to match a generic alsa .conf shared by all +G12A/B devices so change the name to AMLG12. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 8078a7f3c80a..ec63fdd3823e 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -198,7 +198,7 @@ + + sound { + compatible = "amlogic,axg-sound-card"; +- model = "G12A-X96-MAX"; ++ model = "AMLG12"; + audio-aux-devs = <&tdmout_b>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0164-WIP-arm64-dts-meson-gxbb-gxl-gxm-set-audio-card-name.patch b/packages/linux/patches/amlogic/amlogic-0164-WIP-arm64-dts-meson-gxbb-gxl-gxm-set-audio-card-name.patch new file mode 100644 index 0000000000..360713d8bb --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0164-WIP-arm64-dts-meson-gxbb-gxl-gxm-set-audio-card-name.patch @@ -0,0 +1,181 @@ +From 04813b68d8de4ac537a695694db85c1f8d9300d0 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 08:00:18 +0000 +Subject: [PATCH 164/186] WIP: arm64: dts: meson gxbb/gxl/gxm: set audio card + name to AMLGX + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 2 +- + arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 2 +- + 12 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +index 05673221dcc3..ad5456a87183 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +@@ -105,7 +105,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +index e555612a6612..58ce0ef3a680 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +@@ -90,7 +90,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +index 905e4bb70df9..5a708cf1a2a1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +@@ -121,7 +121,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +index 2facdf49f8ff..fbfd2da305b1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +@@ -113,7 +113,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +index 3245859f7d2a..c2faf342a04a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +@@ -116,7 +116,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +index 6b7ac033ce22..53e950f0b8cf 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +@@ -115,7 +115,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +index bf3453f549dc..dc514031ff87 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +@@ -68,7 +68,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +index 969ee02e7429..82a8620040dc 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +@@ -86,7 +86,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +index 93e1fbbe9438..7b861b25bf7c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +@@ -105,7 +105,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts +index 78c3060c5d56..952352891250 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts +@@ -35,7 +35,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index f560eca12067..150a6cee8fdd 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -84,7 +84,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +index b6519bbdaadb..81ce29ec39db 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +@@ -78,7 +78,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0015-arm64-dts-meson-gxbb-odroid-set-blue-led-to-on.patch b/packages/linux/patches/amlogic/amlogic-0165-WIP-arm64-dts-meson-gxbb-odroid-disable-LED-heartbea.patch similarity index 77% rename from projects/Amlogic/patches/linux/e-0015-arm64-dts-meson-gxbb-odroid-set-blue-led-to-on.patch rename to packages/linux/patches/amlogic/amlogic-0165-WIP-arm64-dts-meson-gxbb-odroid-disable-LED-heartbea.patch index 1dac753e78..5dcb2dac83 100644 --- a/projects/Amlogic/patches/linux/e-0015-arm64-dts-meson-gxbb-odroid-set-blue-led-to-on.patch +++ b/packages/linux/patches/amlogic/amlogic-0165-WIP-arm64-dts-meson-gxbb-odroid-disable-LED-heartbea.patch @@ -1,10 +1,11 @@ -From eff5b2f4af16279259e7dbb2b61b915f5dc1f519 Mon Sep 17 00:00:00 2001 +From 070ced64b3b8696878c6aa3a947ca0e45313ff27 Mon Sep 17 00:00:00 2001 From: chewitt Date: Wed, 24 Apr 2019 03:40:16 +0000 -Subject: [PATCH 15/37] arm64: dts: meson-gxbb-odroid: set blue led to on +Subject: [PATCH 165/186] WIP: arm64: dts: meson-gxbb-odroid: disable LED + heartbeat The constantly flashing blue LED heartbeat is annoying for an HTPC device -so remove the heartbeat and simply default to on. +so remove the heartbeat line. Signed-off-by: Christian Hewitt --- @@ -12,7 +13,7 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts -index 80a7d47160e9..88816c20800f 100644 +index fbfd2da305b1..7431da27e475 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts @@ -45,8 +45,7 @@ diff --git a/projects/Amlogic/patches/linux/e-0017-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir-key.patch b/packages/linux/patches/amlogic/amlogic-0166-WIP-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir.patch similarity index 74% rename from projects/Amlogic/patches/linux/e-0017-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir-key.patch rename to packages/linux/patches/amlogic/amlogic-0166-WIP-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir.patch index 8428bac6a8..aa8225a4f2 100644 --- a/projects/Amlogic/patches/linux/e-0017-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir-key.patch +++ b/packages/linux/patches/amlogic/amlogic-0166-WIP-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir.patch @@ -1,8 +1,8 @@ -From 761f9019c724644a2b41f7860182429f96eecdae Mon Sep 17 00:00:00 2001 +From 0d4eb0fc8ab610f30a4a2042e203a405bfa080a6 Mon Sep 17 00:00:00 2001 From: chewitt Date: Fri, 26 Apr 2019 08:43:58 +0000 -Subject: [PATCH 17/37] arm64: dts: meson-gxbb-vega-s95: set rc-vega-s95 ir - keymap +Subject: [PATCH 166/186] WIP: arm64: dts: meson-gxbb-vega-s95: set rc-vega-s95 + ir keymap Signed-off-by: Christian Hewitt --- @@ -10,10 +10,10 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi -index 58aaa196d576..795a1e78873d 100644 +index 43b11e3dfe11..1d38a3ecb654 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi -@@ -191,6 +191,7 @@ +@@ -152,6 +152,7 @@ status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default"; diff --git a/packages/linux/patches/amlogic/amlogic-0167-WIP-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-m.patch b/packages/linux/patches/amlogic/amlogic-0167-WIP-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-m.patch new file mode 100644 index 0000000000..96d7179ff8 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0167-WIP-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-m.patch @@ -0,0 +1,102 @@ +From e0c0a1217940057e4795af645932fea91b55fdfd Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 06:18:39 +0000 +Subject: [PATCH 167/186] WIP: arm64: dts: meson-gxbb-vega-s95: update dtsi + with many changes + +Signed-off-by: Christian Hewitt +--- + .../boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 43 ++++++++++++++++++- + 1 file changed, 41 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +index 1d38a3ecb654..5b55ce8b6e94 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +@@ -4,12 +4,15 @@ + */ + + #include "meson-gxbb.dtsi" ++#include ++#include + + / { + compatible = "tronsmart,vega-s95", "amlogic,meson-gxbb"; + + aliases { + serial0 = &uart_AO; ++ serial1 = &uart_A; + ethernet0 = ðmac; + }; + +@@ -91,6 +94,35 @@ + }; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "AMLGX"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <128>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; +@@ -99,6 +131,14 @@ + }; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cec_AO { + status = "okay"; + pinctrl-0 = <&ao_cec_pins>; +@@ -124,7 +164,6 @@ + eth_phy0: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; +- + reset-assert-us = <10000>; + reset-deassert-us = <30000>; + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; +@@ -144,7 +183,7 @@ + + &hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { +- remote-endpoint = <&hdmi_connector_in>; ++ remote-endpoint = <&hdmi_connector_in>; + }; + }; + +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0018-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch b/packages/linux/patches/amlogic/amlogic-0168-FROMGIT-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-.patch similarity index 81% rename from projects/Amlogic/patches/linux/e-0018-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch rename to packages/linux/patches/amlogic/amlogic-0168-FROMGIT-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-.patch index af81dc26ff..47381d4c8a 100644 --- a/projects/Amlogic/patches/linux/e-0018-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch +++ b/packages/linux/patches/amlogic/amlogic-0168-FROMGIT-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-.patch @@ -1,8 +1,8 @@ -From 7d2742b632882567076501490110d92d7fad8d4e Mon Sep 17 00:00:00 2001 +From abf2e95800cbcef2b8ec73123975bc0060d987eb Mon Sep 17 00:00:00 2001 From: chewitt Date: Mon, 15 Apr 2019 04:40:25 +0000 -Subject: [PATCH 18/37] arm64: dts: meson-gxbb-wetek-hub: set rc-wetek-hub ir - keymap +Subject: [PATCH 168/186] FROMGIT: arm64: dts: meson-gxbb-wetek-hub: set + rc-wetek-hub ir keymap Signed-off-by: Christian Hewitt --- diff --git a/projects/Amlogic/patches/linux/e-0019-arm64-dts-meson-gxbb-wetek-play2-set-rc-wetek-play2-.patch b/packages/linux/patches/amlogic/amlogic-0169-FROMGIT-arm64-dts-meson-gxbb-wetek-play2-set-rc-wete.patch similarity index 79% rename from projects/Amlogic/patches/linux/e-0019-arm64-dts-meson-gxbb-wetek-play2-set-rc-wetek-play2-.patch rename to packages/linux/patches/amlogic/amlogic-0169-FROMGIT-arm64-dts-meson-gxbb-wetek-play2-set-rc-wete.patch index 7d41422151..82d61cde18 100644 --- a/projects/Amlogic/patches/linux/e-0019-arm64-dts-meson-gxbb-wetek-play2-set-rc-wetek-play2-.patch +++ b/packages/linux/patches/amlogic/amlogic-0169-FROMGIT-arm64-dts-meson-gxbb-wetek-play2-set-rc-wete.patch @@ -1,8 +1,8 @@ -From 7b15154d606081d14c64d84b61840d695fbba75c Mon Sep 17 00:00:00 2001 +From b822d199d43845d3603fbcb64ad6197a513997e9 Mon Sep 17 00:00:00 2001 From: chewitt Date: Sun, 21 Apr 2019 02:27:40 +0000 -Subject: [PATCH 19/37] arm64: dts: meson-gxbb-wetek-play2: set rc-wetek-play2 - ir keymap +Subject: [PATCH 169/186] FROMGIT: arm64: dts: meson-gxbb-wetek-play2: set + rc-wetek-play2 ir keymap Signed-off-by: Christian Hewitt --- diff --git a/projects/Amlogic/patches/linux/e-0020-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-khadas-r.patch b/packages/linux/patches/amlogic/amlogic-0170-FROMGIT-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-.patch similarity index 84% rename from projects/Amlogic/patches/linux/e-0020-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-khadas-r.patch rename to packages/linux/patches/amlogic/amlogic-0170-FROMGIT-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-.patch index 2dfaf202e6..b8c82037c8 100644 --- a/projects/Amlogic/patches/linux/e-0020-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-khadas-r.patch +++ b/packages/linux/patches/amlogic/amlogic-0170-FROMGIT-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-.patch @@ -1,8 +1,8 @@ -From 133ba868862509bcd50dfd2ebaf942552e0399b1 Mon Sep 17 00:00:00 2001 +From b9c57ff4fab7828c5db195d1efbece2070a0a3b3 Mon Sep 17 00:00:00 2001 From: chewitt Date: Mon, 29 Apr 2019 03:37:28 +0000 -Subject: [PATCH 20/37] arm64: dts: meson-gxl-s905x-khadas-vim: use rc-khadas - remote not rc-geekbox +Subject: [PATCH 170/186] FROMGIT: arm64: dts: meson-gxl-s905x-khadas-vim: use + rc-khadas remote Khadas shipped the first batch of VIM devices with the 'geekbox' remote from another of their brands. All further shipments have used a 'khadas' branded @@ -17,7 +17,7 @@ Signed-off-by: Christian Hewitt 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts -index b2493e9dfd08..5d87649aedf1 100644 +index dc514031ff87..2cb377e756ea 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts @@ -147,7 +147,7 @@ diff --git a/projects/Amlogic/patches/linux/e-0021-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address-siz.patch b/packages/linux/patches/amlogic/amlogic-0171-WIP-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address.patch similarity index 84% rename from projects/Amlogic/patches/linux/e-0021-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address-siz.patch rename to packages/linux/patches/amlogic/amlogic-0171-WIP-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address.patch index 53c1365d34..168375eb1c 100644 --- a/projects/Amlogic/patches/linux/e-0021-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address-siz.patch +++ b/packages/linux/patches/amlogic/amlogic-0171-WIP-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address.patch @@ -1,7 +1,7 @@ -From 9f1e034f25ee294bee0a636f0b0ecd571fc40d17 Mon Sep 17 00:00:00 2001 +From 8cc0eb4bda8efc8011f5814ec64d3afd16004403 Mon Sep 17 00:00:00 2001 From: chewitt Date: Tue, 16 Apr 2019 13:06:08 +0000 -Subject: [PATCH 21/37] arm64: dts: meson-gxl-s905x-khadas-vim: fix +Subject: [PATCH 171/186] WIP: arm64: dts: meson-gxl-s905x-khadas-vim: fix address/size cells dtc warnings Fix DTC warnings: @@ -16,7 +16,7 @@ Signed-off-by: Christian Hewitt 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts -index 5d87649aedf1..fccea95297e2 100644 +index 2cb377e756ea..36aea60be6b9 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts @@ -33,8 +33,6 @@ diff --git a/packages/linux/patches/amlogic/amlogic-0172-WIP-arm64-dts-meson-gxl-s905x-khadas-vim-add-bluetoo.patch b/packages/linux/patches/amlogic/amlogic-0172-WIP-arm64-dts-meson-gxl-s905x-khadas-vim-add-bluetoo.patch new file mode 100644 index 0000000000..41265db5df --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0172-WIP-arm64-dts-meson-gxl-s905x-khadas-vim-add-bluetoo.patch @@ -0,0 +1,28 @@ +From 8ef230b84c82abd8df3bbfdc85b6379ad8b857f2 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Jul 2019 09:20:51 +0000 +Subject: [PATCH 172/186] WIP: arm64: dts: meson-gxl-s905x-khadas-vim: add + bluetooth nodes + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +index 36aea60be6b9..374c49bb0672 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +@@ -227,6 +227,9 @@ + bluetooth { + compatible = "brcm,bcm43438-bt"; + shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ max-speed = <2000000>; ++ clocks = <&wifi32k>; ++ clock-names = "lpo"; + }; + }; + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0173-WIP-arm64-dts-meson-gxl-s905x-p212-add-bluetooth-nod.patch b/packages/linux/patches/amlogic/amlogic-0173-WIP-arm64-dts-meson-gxl-s905x-p212-add-bluetooth-nod.patch new file mode 100644 index 0000000000..6a4ee3c011 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0173-WIP-arm64-dts-meson-gxl-s905x-p212-add-bluetooth-nod.patch @@ -0,0 +1,41 @@ +From 4ac9adca451da85a4b2579905405d1f414f17a91 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Jul 2019 09:45:17 +0000 +Subject: [PATCH 173/186] WIP: arm64: dts: meson-gxl-s905x-p212: add bluetooth + nodes + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi +index e3c16f50814b..2863f34cba10 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi +@@ -15,7 +15,6 @@ + / { + aliases { + serial0 = &uart_AO; +- serial1 = &uart_A; + ethernet0 = ðmac; + }; + +@@ -177,6 +176,14 @@ + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; + uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ max-speed = <2000000>; ++ clocks = <&wifi32k>; ++ clock-names = "lpo"; ++ }; + }; + + &uart_AO { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0022-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch b/packages/linux/patches/amlogic/amlogic-0174-FROMGIT-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx.patch similarity index 81% rename from projects/Amlogic/patches/linux/e-0022-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch rename to packages/linux/patches/amlogic/amlogic-0174-FROMGIT-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx.patch index d07df00904..3f69569520 100644 --- a/projects/Amlogic/patches/linux/e-0022-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch +++ b/packages/linux/patches/amlogic/amlogic-0174-FROMGIT-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx.patch @@ -1,8 +1,8 @@ -From 58677981f9e080fb42f329273e94a7e0c5d2b09b Mon Sep 17 00:00:00 2001 +From d65a44b707fd5b1876b8823da657ee3f4fad22ff Mon Sep 17 00:00:00 2001 From: chewitt Date: Mon, 15 Apr 2019 02:58:24 +0000 -Subject: [PATCH 22/37] arm64: dts: meson-gxl-s905w-tx3-mini: set rc-tx3mini ir - keymap +Subject: [PATCH 174/186] FROMGIT: arm64: dts: meson-gxl-s905w-tx3-mini: set + rc-tx3mini ir keymap Signed-off-by: Christian Hewitt --- diff --git a/packages/linux/patches/amlogic/amlogic-0175-WIP-arm64-dts-meson-gx-p23x-q20x-add-bluetooth-nodes.patch b/packages/linux/patches/amlogic/amlogic-0175-WIP-arm64-dts-meson-gx-p23x-q20x-add-bluetooth-nodes.patch new file mode 100644 index 0000000000..7f043b7e6f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0175-WIP-arm64-dts-meson-gx-p23x-q20x-add-bluetooth-nodes.patch @@ -0,0 +1,53 @@ +From 2bceb64be9d570ee7ada09375749ff30c4149d6b Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Jul 2019 09:50:08 +0000 +Subject: [PATCH 175/186] WIP: arm64: dts: meson-gx-p23x-q20x: add bluetooth + nodes + +Signed-off-by: Christian Hewitt +--- + .../boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 21 +++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +index ad5456a87183..b1e9257e4d22 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +@@ -210,6 +210,11 @@ + + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddio_boot>; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; + }; + + /* SD card */ +@@ -250,6 +255,22 @@ + vqmmc-supply = <&vddio_boot>; + }; + ++/* This UART is connected to the Bluetooth module */ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ max-speed = <2000000>; ++ clocks = <&wifi32k>; ++ clock-names = "lpo"; ++ }; ++}; ++ + /* This UART is brought out to the DB9 connector */ + &uart_AO { + status = "okay"; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0176-FROMGIT-arm64-dts-meson-gxm-khadas-vim2-use-rc-khada.patch b/packages/linux/patches/amlogic/amlogic-0176-FROMGIT-arm64-dts-meson-gxm-khadas-vim2-use-rc-khada.patch new file mode 100644 index 0000000000..d45c0b3a43 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0176-FROMGIT-arm64-dts-meson-gxm-khadas-vim2-use-rc-khada.patch @@ -0,0 +1,34 @@ +From 96dcc5280323c8cb474e0f25356e9cebf3c6201b Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 12 Jul 2019 20:37:37 +0000 +Subject: [PATCH 176/186] FROMGIT: arm64: dts: meson-gxm-khadas-vim2: use + rc-khadas remote + +Khadas shipped the first batch of VIM devices with the 'geekbox' remote from +another of their brands. All further shipments have used a 'khadas' branded +remote that provides an Android mouse function instead of KEY_SCREEN. As the +IR keycode for the geekbox screen button is different to the khadas mouse +button KEY_SCREEN doesn't work on the Khadas remote, so swap to the rc-khadas +keymap to gain an extra button mapped to KEY_MUTE. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index 150a6cee8fdd..08727564643d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -336,7 +336,7 @@ + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; +- linux,rc-map-name = "rc-geekbox"; ++ linux,rc-map-name = "rc-khadas"; + }; + + &pwm_AO_ab { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0177-WIP-arm64-dts-meson-gxm-khadas-vim2-fix-uart_A-bluet.patch b/packages/linux/patches/amlogic/amlogic-0177-WIP-arm64-dts-meson-gxm-khadas-vim2-fix-uart_A-bluet.patch new file mode 100644 index 0000000000..ecb7c79670 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0177-WIP-arm64-dts-meson-gxm-khadas-vim2-fix-uart_A-bluet.patch @@ -0,0 +1,28 @@ +From 69d223fcd8cf9b981f72180ac39bc5e18f57a048 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Jul 2019 08:31:42 +0000 +Subject: [PATCH 177/186] WIP: arm64: dts: meson-gxm-khadas-vim2: fix uart_A + bluetooth node + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index 08727564643d..dc211d19c7ea 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -446,6 +446,9 @@ + bluetooth { + compatible = "brcm,bcm43438-bt"; + shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ max-speed = <2000000>; ++ clocks = <&wifi32k>; ++ clock-names = "lpo"; + }; + }; + +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0026-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-keym.patch b/packages/linux/patches/amlogic/amlogic-0178-WIP-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-.patch similarity index 83% rename from projects/Amlogic/patches/linux/e-0026-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-keym.patch rename to packages/linux/patches/amlogic/amlogic-0178-WIP-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-.patch index f1928f56ca..ac247bcbcf 100644 --- a/projects/Amlogic/patches/linux/e-0026-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-keym.patch +++ b/packages/linux/patches/amlogic/amlogic-0178-WIP-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-.patch @@ -1,8 +1,8 @@ -From ee8c2d72348e6e882775bafb7e1e2a6c6bcdd0ad Mon Sep 17 00:00:00 2001 +From 1512a197ad099a73787624d35f5e882f3b0ee4cf Mon Sep 17 00:00:00 2001 From: chewitt Date: Fri, 26 Apr 2019 08:47:22 +0000 -Subject: [PATCH 26/37] arm64: dts: meson-gxm-vega-s96: set rc-vega-s95 ir - keymap +Subject: [PATCH 178/186] WIP: arm64: dts: meson-gxm-vega-s96: set rc-vega-s95 + ir keymap S96 uses the same remote as the S95 series devices. diff --git a/packages/linux/patches/amlogic/amlogic-0179-WIP-experimental-ELD-changes-from-kwiboo.patch b/packages/linux/patches/amlogic/amlogic-0179-WIP-experimental-ELD-changes-from-kwiboo.patch new file mode 100644 index 0000000000..0fdd70aea9 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0179-WIP-experimental-ELD-changes-from-kwiboo.patch @@ -0,0 +1,134 @@ +From 20b3ca24a557afa4e1996a1ec4961d1b4dba6e7f Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Thu, 15 Aug 2019 11:27:55 +0000 +Subject: [PATCH 179/186] WIP: experimental ELD changes from @kwiboo + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 55 ++++++++++++++--------- + drivers/gpu/drm/drm_edid.c | 3 +- + include/drm/drm_edid.h | 1 + + 3 files changed, 37 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index d9297b20771d..d92400414c7a 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2161,22 +2161,8 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) + hdmi->rxsense); + } + +-static enum drm_connector_status +-dw_hdmi_connector_detect(struct drm_connector *connector, bool force) +-{ +- struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +- connector); +- +- mutex_lock(&hdmi->mutex); +- hdmi->force = DRM_FORCE_UNSPECIFIED; +- dw_hdmi_update_power(hdmi); +- dw_hdmi_update_phy_mask(hdmi); +- mutex_unlock(&hdmi->mutex); +- +- return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); +-} +- +-static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++static int dw_hdmi_connector_update_edid(struct drm_connector *connector, ++ bool add_modes) + { + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); +@@ -2195,7 +2181,10 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) + hdmi->sink_has_audio = drm_detect_monitor_audio(edid); + drm_connector_update_edid_property(connector, edid); + cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); +- ret = drm_add_edid_modes(connector, edid); ++ if (add_modes) ++ ret = drm_add_edid_modes(connector, edid); ++ else ++ drm_edid_to_eld(connector, edid); + kfree(edid); + } else { + dev_dbg(hdmi->dev, "failed to get edid\n"); +@@ -2204,6 +2193,34 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) + return ret; + } + ++static enum drm_connector_status ++dw_hdmi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ enum drm_connector_status status; ++ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, ++ connector); ++ ++ mutex_lock(&hdmi->mutex); ++ hdmi->force = DRM_FORCE_UNSPECIFIED; ++ dw_hdmi_update_power(hdmi); ++ dw_hdmi_update_phy_mask(hdmi); ++ mutex_unlock(&hdmi->mutex); ++ ++ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); ++ ++ if (status == connector_status_connected) ++ dw_hdmi_connector_update_edid(connector, false); ++ else ++ cec_notifier_phys_addr_invalidate(hdmi->cec_notifier); ++ ++ return status; ++} ++ ++static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++{ ++ return dw_hdmi_connector_update_edid(connector, true); ++} ++ + static void dw_hdmi_connector_force(struct drm_connector *connector) + { + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +@@ -2411,10 +2428,6 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) + dw_hdmi_setup_rx_sense(hdmi, + phy_stat & HDMI_PHY_HPD, + phy_stat & HDMI_PHY_RX_SENSE); +- +- if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0) +- cec_notifier_set_phys_addr(hdmi->cec_notifier, +- CEC_PHYS_ADDR_INVALID); + } + + if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index 82a4ceed3fcf..4965b49ab8d2 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -4077,7 +4077,7 @@ static void clear_eld(struct drm_connector *connector) + * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The + * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. + */ +-static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) ++void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) + { + uint8_t *eld = connector->eld; + u8 *cea; +@@ -4162,6 +4162,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) + DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", + drm_eld_size(eld), total_sad_count); + } ++EXPORT_SYMBOL(drm_edid_to_eld); + + /** + * drm_edid_to_sad - extracts SADs from EDID +diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h +index b9719418c3d2..49987818fe23 100644 +--- a/include/drm/drm_edid.h ++++ b/include/drm/drm_edid.h +@@ -337,6 +337,7 @@ struct drm_connector; + struct drm_connector_state; + struct drm_display_mode; + ++void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid); + int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads); + int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb); + int drm_av_sync_delay(struct drm_connector *connector, +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0180-FROMLIST-drm-meson-init-g12a-osd2-yuv2rgb-instead-of.patch b/packages/linux/patches/amlogic/amlogic-0180-FROMLIST-drm-meson-init-g12a-osd2-yuv2rgb-instead-of.patch new file mode 100644 index 0000000000..d606fd4e7f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0180-FROMLIST-drm-meson-init-g12a-osd2-yuv2rgb-instead-of.patch @@ -0,0 +1,77 @@ +From 04689592d02475a6700d72d8a5fadcb2a6adfdb8 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 19 Aug 2019 16:20:17 +0200 +Subject: [PATCH 180/186] FROMLIST: drm/meson: init g12a osd2 yuv2rgb instead + of osd1 + +Following vendor change, to avoid: +> green line displayed when osd alpha 0xff/0x00 continuos +replace yuv2rgb of osd1 for osd2 for G12A & compatible SoCs. + +Fixes: 728883948b0d ("drm/meson: Add G12A Support for VIU setup") +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/meson/meson_viu.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c +index 4b36e4b21b51..4e769954703c 100644 +--- a/drivers/gpu/drm/meson/meson_viu.c ++++ b/drivers/gpu/drm/meson/meson_viu.c +@@ -78,32 +78,32 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { + EOTF_COEFF_RIGHTSHIFT /* right shift */ + }; + +-static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, ++static void meson_viu_set_g12a_osd2_matrix(struct meson_drm *priv, + int *m, bool csc_on) + { +- /* VPP WRAP OSD1 matrix */ ++ /* VPP WRAP OSD2 matrix */ + writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1)); + writel(m[2] & 0xfff, +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2)); + writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF00_01)); + writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF02_10)); + writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF11_12)); + writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF20_21)); + writel((m[11] & 0x1fff) << 16, +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF22)); + + writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff), +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_OFFSET0_1)); + writel(m[20] & 0xfff, +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_OFFSET2)); + + writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, +- priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); ++ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_EN_CTRL)); + } + + static void meson_viu_set_osd_matrix(struct meson_drm *priv, +@@ -360,7 +360,7 @@ void meson_viu_init(struct meson_drm *priv) + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_viu_load_matrix(priv); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) +- meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff, ++ meson_viu_set_g12a_osd2_matrix(priv, RGB709_to_YUV709l_coeff, + true); + + /* Initialize OSD1 fifo control register */ +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0181-WIP-arm64-dts-meson-libretech-ac-update-model-and-co.patch b/packages/linux/patches/amlogic/amlogic-0181-WIP-arm64-dts-meson-libretech-ac-update-model-and-co.patch new file mode 100644 index 0000000000..52ea6864a6 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0181-WIP-arm64-dts-meson-libretech-ac-update-model-and-co.patch @@ -0,0 +1,33 @@ +From b0f5e81e6487cc2acefa3bdf071d34bed5af1de4 Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Mon, 26 Aug 2019 02:32:41 +0000 +Subject: [PATCH 181/186] WIP: arm64: dts: meson: libretech-ac: update model + and compatible + +Shorten the model description and change the compatible to LaFrite, which is +what everyone calls the board. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts +index 82b1c4851147..bc7138b7fdc6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts +@@ -12,9 +12,9 @@ + #include "meson-gxl-s905x.dtsi" + + / { +- compatible = "libretech,aml-s805x-ac", "amlogic,s805x", ++ compatible = "libretech,lafrite", "amlogic,s805x", + "amlogic,meson-gxl"; +- model = "Libre Computer Board AML-S805X-AC"; ++ model = "Libre Computer AML-S805X-AC"; + + aliases { + serial0 = &uart_AO; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0182-WIP-arm64-dts-meson-libretech-cc-update-model-and-co.patch b/packages/linux/patches/amlogic/amlogic-0182-WIP-arm64-dts-meson-libretech-cc-update-model-and-co.patch new file mode 100644 index 0000000000..4913766d8f --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0182-WIP-arm64-dts-meson-libretech-cc-update-model-and-co.patch @@ -0,0 +1,33 @@ +From 2f762f7276e328defcd16175fc7a1cef921caee1 Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Mon, 26 Aug 2019 02:37:17 +0000 +Subject: [PATCH 182/186] WIP: arm64: dts: meson: libretech-cc: update model + and compatible + +Shorten the model description and change the compatible to LePotato, which +is what everyone calls the board. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +index 82a8620040dc..9d7a451c9589 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +@@ -12,8 +12,9 @@ + #include "meson-gxl-s905x.dtsi" + + / { +- compatible = "libretech,cc", "amlogic,s905x", "amlogic,meson-gxl"; +- model = "Libre Computer Board AML-S905X-CC"; ++ compatible = "libretech,lepotato", "amlogic,s905x", ++ "amlogic,meson-gxl"; ++ model = "Libre Computer AML-S905X-CC"; + + aliases { + serial0 = &uart_AO; +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0183-WIP-dt-bindings-arm-amlogic-change-LaFrite-compatibl.patch b/packages/linux/patches/amlogic/amlogic-0183-WIP-dt-bindings-arm-amlogic-change-LaFrite-compatibl.patch new file mode 100644 index 0000000000..5489b8b2fe --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0183-WIP-dt-bindings-arm-amlogic-change-LaFrite-compatibl.patch @@ -0,0 +1,27 @@ +From 01e943ac7d4a9a5c276a5d44af463f53e3864823 Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Mon, 26 Aug 2019 02:40:56 +0000 +Subject: [PATCH 183/186] WIP: dt-bindings: arm: amlogic: change LaFrite + compatible + +Signed-off-by: Christian Hewitt +--- + Documentation/devicetree/bindings/arm/amlogic.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml +index c1658ec57482..49db2767b02b 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.yaml ++++ b/Documentation/devicetree/bindings/arm/amlogic.yaml +@@ -76,7 +76,7 @@ properties: + items: + - enum: + - amlogic,p241 +- - libretech,aml-s805x-ac ++ - libretech,lafrite + - const: amlogic,s805x + - const: amlogic,meson-gxl + +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0184-WIP-dt-bindings-arm-amlogic-change-LePotato-compatib.patch b/packages/linux/patches/amlogic/amlogic-0184-WIP-dt-bindings-arm-amlogic-change-LePotato-compatib.patch new file mode 100644 index 0000000000..9f21724d6e --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0184-WIP-dt-bindings-arm-amlogic-change-LePotato-compatib.patch @@ -0,0 +1,27 @@ +From 971d695996b16fff4409aaeb687e5b1897339813 Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Mon, 26 Aug 2019 02:42:56 +0000 +Subject: [PATCH 184/186] WIP: dt-bindings: arm: amlogic: change LePotato + compatible + +Signed-off-by: Christian Hewitt +--- + Documentation/devicetree/bindings/arm/amlogic.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml +index 49db2767b02b..420626b2de7f 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.yaml ++++ b/Documentation/devicetree/bindings/arm/amlogic.yaml +@@ -95,7 +95,7 @@ properties: + - amlogic,p212 + - hwacom,amazetv + - khadas,vim +- - libretech,cc ++ - libretech,lepotato + - nexbox,a95x + - seirobotics,sei510 + - const: amlogic,s905x +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0185-lafrite-audio.patch b/packages/linux/patches/amlogic/amlogic-0185-lafrite-audio.patch new file mode 100644 index 0000000000..a8cce976e5 --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0185-lafrite-audio.patch @@ -0,0 +1,60 @@ +From 655861580dc442e5023e17c7cada9cc004840760 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 24 Aug 2019 12:25:01 +0000 +Subject: [PATCH 185/186] lafrite audio + +--- + .../amlogic/meson-gxl-s805x-libretech-ac.dts | 37 +++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts +index bc7138b7fdc6..43757f327a89 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts +@@ -105,6 +105,43 @@ + vin-supply = <&vcc_3v3>; + regulator-always-on; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++}; ++ ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; + }; + + &cec_AO { +-- +2.17.1 + diff --git a/packages/linux/patches/amlogic/amlogic-0186-lafrite-AMLGX.patch b/packages/linux/patches/amlogic/amlogic-0186-lafrite-AMLGX.patch new file mode 100644 index 0000000000..5cce630b1c --- /dev/null +++ b/packages/linux/patches/amlogic/amlogic-0186-lafrite-AMLGX.patch @@ -0,0 +1,25 @@ +From 5753ecf537b15696d3caad38380bc3005bd78206 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 24 Aug 2019 12:26:01 +0000 +Subject: [PATCH 186/186] lafrite AMLGX + +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts +index 43757f327a89..f21e015150a6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dts +@@ -108,7 +108,7 @@ + + sound { + compatible = "simple-audio-card"; +- simple-audio-card,name = "meson-gx-audio"; ++ simple-audio-card,name = "AMLGX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/README.md b/projects/Amlogic/patches/linux/README.md deleted file mode 100644 index f300c25f23..0000000000 --- a/projects/Amlogic/patches/linux/README.md +++ /dev/null @@ -1,11 +0,0 @@ -### A - -https://github.com/torvalds/linux/compare/v5.1...superna9999:linux-5.1-le-amlogic-v2.patch - -### C -** from rockchip-5.1-patches-for-libreelec-v5.1 branch, remove 09/16 ** - -https://github.com/Kwiboo/linux-rockchip/compare/43e542a1432b200f589e589320a885b5640d1f45...d6b6f0ca3df105f4d84b7cbaca8e5a3cfbf2ad42 - -### E-F -** misc patches to go upstream ** diff --git a/projects/Amlogic/patches/linux/a-meson-integ.patch b/projects/Amlogic/patches/linux/a-meson-integ.patch deleted file mode 100644 index 2705b641ef..0000000000 --- a/projects/Amlogic/patches/linux/a-meson-integ.patch +++ /dev/null @@ -1,47496 +0,0 @@ -From 57a9585034000d61b241d87855d6895011da9b2c Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 12 Feb 2019 15:02:58 +0100 -Subject: [PATCH 001/249] FROMGIT: vendor-prefixes: Add prefix for Shenzhen SEI - Robotics Co., Ltd - -Add vendor prefix for the Shenzhen SEI Robotics Co., Ltd, a chinese ODM -specialized in Android TV HDMI Stick, OTT Box, Hybrid STB, -Smart Home Gateway & more. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 6917de8a6c4d05737dded7053a66be3c7e6779c2 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) -Signed-off-by: Neil Armstrong ---- - Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt -index 8162b0eb4b506..bb6f6e8a2eeea 100644 ---- a/Documentation/devicetree/bindings/vendor-prefixes.txt -+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt -@@ -353,6 +353,7 @@ sandisk Sandisk Corporation - sbs Smart Battery System - schindler Schindler - seagate Seagate Technology PLC -+seirobotics Shenzhen SEI Robotics Co., Ltd - semtech Semtech Corporation - sensirion Sensirion AG - sff Small Form Factor Committee - -From 7732905e42684a6214ddde58f9eb6f5d0975faae Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 12 Feb 2019 15:02:59 +0100 -Subject: [PATCH 002/249] FROMGIT: arm64: dts: Add SEI Robotics SEI510 Board - -The SEI Robotics SEI510 Board is based on the Amlogic G12A S905X2 -and has the following features : -- Amlogic G12A S905X2 SoC -- 10/100 Ethernet -- USB2 + USB3 ports -- Micro SDCard Port -- Audio + CVBS AV Jack port -- HDMI 2.1 + CEC Port -- ADC Touch Button -- Far-Field Microphone Array + Mono HP -- IR Sensor -- IR Emmiter LED Array -- RGB Led - -Signed-off-by: Neil Armstrong -[khilman: sorted Makefile entry alphabetcially] -Signed-off-by: Kevin Hilman -(cherry picked from commit b7be144932a8376fbb886115ce908a1a1818940b - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) -Signed-off-by: Neil Armstrong ---- - .../devicetree/bindings/arm/amlogic.txt | 1 + - arch/arm64/boot/dts/amlogic/Makefile | 1 + - .../boot/dts/amlogic/meson-g12a-sei510.dts | 38 +++++++++++++++++++ - 3 files changed, 40 insertions(+) - create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts - -diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt -index 7f40cb5f490bd..061f7b98a07f1 100644 ---- a/Documentation/devicetree/bindings/arm/amlogic.txt -+++ b/Documentation/devicetree/bindings/arm/amlogic.txt -@@ -110,6 +110,7 @@ Board compatible values (alphabetically, grouped by SoC): - - - "amlogic,u200" (Meson g12a s905d2) - - "amediatech,x96-max" (Meson g12a s905x2) -+ - "seirobotics,sei510" (Meson g12a s905x2) - - Amlogic Meson Firmware registers Interface - ------------------------------------------ -diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile -index 0821fed4c0749..e129c03ced140 100644 ---- a/arch/arm64/boot/dts/amlogic/Makefile -+++ b/arch/arm64/boot/dts/amlogic/Makefile -@@ -1,5 +1,6 @@ - # SPDX-License-Identifier: GPL-2.0 - dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb -+dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -new file mode 100644 -index 0000000000000..6a7c3241862af ---- /dev/null -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2019 BayLibre SAS. All rights reserved. -+ */ -+ -+/dts-v1/; -+ -+#include "meson-g12a.dtsi" -+ -+/ { -+ compatible = "seirobotics,sei510", "amlogic,g12a"; -+ model = "SEI Robotics SEI510"; -+ -+ aliases { -+ serial0 = &uart_AO; -+ }; -+ -+ chosen { -+ stdout-path = "serial0:115200n8"; -+ }; -+ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x0 0x0 0x40000000>; -+ }; -+ -+ reserved-memory { -+ /* TEE Reserved Memory */ -+ bl32_reserved: bl32@5000000 { -+ reg = <0x0 0x05300000 0x0 0x2000000>; -+ no-map; -+ }; -+ }; -+}; -+ -+&uart_AO { -+ status = "okay"; -+}; - -From 4d4ca52f504bb200ff243b8a945f7da066a0d028 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 7 Mar 2019 15:01:47 +0100 -Subject: [PATCH 003/249] FROMGIT: arm64: dts: meson-g12a: Add AO Secure node - -This adds the Always-On ao-secure system control registers node, -which is used by the meson-gx-socinfo driver to detect the SoC IDs. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 0fa724c51e31cc814af9e44c019fb4d570422b02 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 17c6217f8a849..31ddf9444b3e3 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -122,6 +122,12 @@ - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; - -+ sec_AO: ao-secure@140 { -+ compatible = "amlogic,meson-gx-ao-secure", "syscon"; -+ reg = <0x0 0x140 0x0 0x140>; -+ amlogic,has-chip-id; -+ }; -+ - uart_AO: serial@3000 { - compatible = "amlogic,meson-gx-uart", - "amlogic,meson-ao-uart"; - -From caa45a70bd62537de06587db18fa4b805cd06079 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 15 Mar 2019 14:42:43 +0100 -Subject: [PATCH 004/249] FROMGIT: arm64: dts: meson: g12a: add secure monitor - -Add the interface to the secure monitor on g12a - -Signed-off-by: Jerome Brunet -Signed-off-by: Kevin Hilman -(cherry picked from commit bd39515284120fc806fd0bea86fecd39908e18dc - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 31ddf9444b3e3..92ee8c895ba68 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -72,6 +72,10 @@ - }; - }; - -+ sm: secure-monitor { -+ compatible = "amlogic,meson-gxbb-sm"; -+ }; -+ - soc { - compatible = "simple-bus"; - #address-cells = <2>; - -From 345369aee7b3c60ee88a835362ca5d09cc5de6fe Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 15 Mar 2019 14:42:44 +0100 -Subject: [PATCH 005/249] FROMGIT: arm64: dts: meson: g12a: add efuse - -Add the g12a SoC efuse device - -Signed-off-by: Jerome Brunet -Signed-off-by: Kevin Hilman -(cherry picked from commit 965c827ac37e71f76d3ac55c75ac08909f2a4eed - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 92ee8c895ba68..dcc821cf35bb8 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -4,6 +4,7 @@ - */ - - #include -+#include - #include - #include - -@@ -55,6 +56,14 @@ - }; - }; - -+ efuse: efuse { -+ compatible = "amlogic,meson-gxbb-efuse"; -+ clocks = <&clkc CLKID_EFUSE>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ read-only; -+ }; -+ - psci { - compatible = "arm,psci-1.0"; - method = "smc"; - -From cca0a2b4f97728bf46ab8d3c95c4c29f1f4f9c34 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 18 Mar 2019 10:58:44 +0100 -Subject: [PATCH 006/249] FROMGIT: arm64: dts: meson: g12a: Add AO Clock + - Reset Controller support - -Add nodes and properties for the AO Clocks and Resets. - -Signed-off-by: Neil Armstrong -Signed-off-by: Jerome Brunet -Signed-off-by: Kevin Hilman -(cherry picked from commit b019f4a4199f865b054262ff78f606ca70f7b981 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index dcc821cf35bb8..abfa167751afc 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -135,6 +135,23 @@ - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; - -+ rti: sys-ctrl@0 { -+ compatible = "amlogic,meson-gx-ao-sysctrl", -+ "simple-mfd", "syscon"; -+ reg = <0x0 0x0 0x0 0x100>; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges = <0x0 0x0 0x0 0x0 0x0 0x100>; -+ -+ clkc_AO: clock-controller { -+ compatible = "amlogic,meson-g12a-aoclkc"; -+ #clock-cells = <1>; -+ #reset-cells = <1>; -+ clocks = <&xtal>, <&clkc CLKID_CLK81>; -+ clock-names = "xtal", "mpeg-clk"; -+ }; -+ }; -+ - sec_AO: ao-secure@140 { - compatible = "amlogic,meson-gx-ao-secure", "syscon"; - reg = <0x0 0x140 0x0 0x140>; - -From e93e552de459029885814f21f55bb428d429ec0d Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 18 Mar 2019 10:58:45 +0100 -Subject: [PATCH 007/249] FROMGIT: arm64: dts: meson: g12a: add pinctrl support - controllers - -Add the peripheral and always-on pinctrl controllers to the g12a soc. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 11a7bea17c9e0a36daab934d83e15a760f402147 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 42 +++++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index abfa167751afc..5e07e4ca3f4bb 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -104,6 +104,29 @@ - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0x34400 0x0 0x400>; -+ -+ periphs_pinctrl: pinctrl@40 { -+ compatible = "amlogic,meson-g12a-periphs-pinctrl"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ gpio: bank@40 { -+ reg = <0x0 0x40 0x0 0x4c>, -+ <0x0 0xe8 0x0 0x18>, -+ <0x0 0x120 0x0 0x18>, -+ <0x0 0x2c0 0x0 0x40>, -+ <0x0 0x340 0x0 0x1c>; -+ reg-names = "gpio", -+ "pull", -+ "pull-enable", -+ "mux", -+ "ds"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ gpio-ranges = <&periphs_pinctrl 0 0 86>; -+ }; -+ }; - }; - - hiu: bus@3c000 { -@@ -150,6 +173,25 @@ - clocks = <&xtal>, <&clkc CLKID_CLK81>; - clock-names = "xtal", "mpeg-clk"; - }; -+ -+ ao_pinctrl: pinctrl@14 { -+ compatible = "amlogic,meson-g12a-aobus-pinctrl"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ gpio_ao: bank@14 { -+ reg = <0x0 0x14 0x0 0x8>, -+ <0x0 0x1c 0x0 0x8>, -+ <0x0 0x24 0x0 0x14>; -+ reg-names = "mux", -+ "ds", -+ "gpio"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ gpio-ranges = <&ao_pinctrl 0 0 15>; -+ }; -+ }; - }; - - sec_AO: ao-secure@140 { - -From c1204940694189c11ec4de20a4201666ce9603df Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 18 Mar 2019 10:58:46 +0100 -Subject: [PATCH 008/249] FROMGIT: arm64: dts: meson: g12a: add uart_ao_a - pinctrl - -Add the always on UART pinctrl setting to the g12a soc DT. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit e92546c226ec16005994d2798c8ad6470bcda1b1 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 5e07e4ca3f4bb..3784b94c5df7d 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -191,6 +191,24 @@ - #gpio-cells = <2>; - gpio-ranges = <&ao_pinctrl 0 0 15>; - }; -+ -+ uart_ao_a_pins: uart-a-ao { -+ mux { -+ groups = "uart_ao_a_tx", -+ "uart_ao_a_rx"; -+ function = "uart_ao_a"; -+ bias-disable; -+ }; -+ }; -+ -+ uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts { -+ mux { -+ groups = "uart_ao_a_cts", -+ "uart_ao_a_rts"; -+ function = "uart_ao_a"; -+ bias-disable; -+ }; -+ }; - }; - }; - - -From 969c73356f29fa0f0d004ddb51e89a5ad65aa32a Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 18 Mar 2019 10:58:47 +0100 -Subject: [PATCH 009/249] FROMGIT: arm64: dts: meson: g12a: add reset - controller - -Add the reset controller device of g12a SoC family - -Signed-off-by: Jerome Brunet -Reviewed-by: Martin Blumenstingl -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 7ab41c4741253f8f33a1af60b9839cfcd62ee455 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 3784b94c5df7d..1d3e5083c4411 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -259,6 +259,13 @@ - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x100000>; - -+ reset: reset-controller@1004 { -+ compatible = "amlogic,meson-g12a-reset", -+ "amlogic,meson-axg-reset"; -+ reg = <0x0 0x1004 0x0 0x9c>; -+ #reset-cells = <1>; -+ }; -+ - clk_msr: clock-measure@18000 { - compatible = "amlogic,meson-g12a-clk-measure"; - reg = <0x0 0x18000 0x0 0x10>; - -From 5da88cae989eae6e3d9844d466db673304068857 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 18 Mar 2019 10:58:48 +0100 -Subject: [PATCH 010/249] FROMGIT: arm64: dts: meson: g12a: Add UART A, B & C - nodes and pins - -This patch adds the 3 UART nodes in the EE power domain with the corresponding -pinctrl nodes. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit ff4f8b6cab5885ebc2c6b21fd058db8544e2eebb - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 72 +++++++++++++++++++++ - 1 file changed, 72 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 1d3e5083c4411..4d04742b05c2c 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -126,6 +126,51 @@ - #gpio-cells = <2>; - gpio-ranges = <&periphs_pinctrl 0 0 86>; - }; -+ -+ uart_a_pins: uart-a { -+ mux { -+ groups = "uart_a_tx", -+ "uart_a_rx"; -+ function = "uart_a"; -+ bias-disable; -+ }; -+ }; -+ -+ uart_a_cts_rts_pins: uart-a-cts-rts { -+ mux { -+ groups = "uart_a_cts", -+ "uart_a_rts"; -+ function = "uart_a"; -+ bias-disable; -+ }; -+ }; -+ -+ uart_b_pins: uart-b { -+ mux { -+ groups = "uart_b_tx", -+ "uart_b_rx"; -+ function = "uart_b"; -+ bias-disable; -+ }; -+ }; -+ -+ uart_c_pins: uart-c { -+ mux { -+ groups = "uart_c_tx", -+ "uart_c_rx"; -+ function = "uart_c"; -+ bias-disable; -+ }; -+ }; -+ -+ uart_c_cts_rts_pins: uart-c-cts-rts { -+ mux { -+ groups = "uart_c_cts", -+ "uart_c_rts"; -+ function = "uart_c"; -+ bias-disable; -+ }; -+ }; - }; - }; - -@@ -270,6 +315,33 @@ - compatible = "amlogic,meson-g12a-clk-measure"; - reg = <0x0 0x18000 0x0 0x10>; - }; -+ -+ uart_C: serial@22000 { -+ compatible = "amlogic,meson-gx-uart"; -+ reg = <0x0 0x22000 0x0 0x18>; -+ interrupts = ; -+ clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; -+ clock-names = "xtal", "pclk", "baud"; -+ status = "disabled"; -+ }; -+ -+ uart_B: serial@23000 { -+ compatible = "amlogic,meson-gx-uart"; -+ reg = <0x0 0x23000 0x0 0x18>; -+ interrupts = ; -+ clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; -+ clock-names = "xtal", "pclk", "baud"; -+ status = "disabled"; -+ }; -+ -+ uart_A: serial@24000 { -+ compatible = "amlogic,meson-gx-uart"; -+ reg = <0x0 0x24000 0x0 0x18>; -+ interrupts = ; -+ clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; -+ clock-names = "xtal", "pclk", "baud"; -+ status = "disabled"; -+ }; - }; - }; - - -From 83acbbf7e77041d36765a2900074ebafe8282aed Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 18 Mar 2019 11:04:48 +0100 -Subject: [PATCH 011/249] FROMGIT: arm64: dts: meson-g12a-u200: add uart_AO - pinctrl - -Add pinctrl on the always-enabled debug UART AO. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 638914212ace84264accaa41578cf80a18797d91 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index c44dbdddf2cf6..f2afd0bf3e28b 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -25,5 +25,7 @@ - - &uart_AO { - status = "okay"; -+ pinctrl-0 = <&uart_ao_a_pins>; -+ pinctrl-names = "default"; - }; - - -From bc35401805db14683fc99a8954c51ce7bc6db8f1 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 18 Mar 2019 11:04:49 +0100 -Subject: [PATCH 012/249] FROMGIT: arm64: dts: meson-g12a-sei510: add uart_AO - pinctrl - -Add pinctrl on the always-enabled debug UART AO. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 51d215c14341a1e769828f9f1ff14f95c7ad35e3 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 6a7c3241862af..63c515fe49966 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -35,4 +35,6 @@ - - &uart_AO { - status = "okay"; -+ pinctrl-0 = <&uart_ao_a_pins>; -+ pinctrl-names = "default"; - }; - -From 292328f856c04b213d9cf7d5ec3fdc70f8245cb9 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 18 Mar 2019 11:04:50 +0100 -Subject: [PATCH 013/249] FROMGIT: arm64: dts: meson-g12a-x96-max: add uart_AO - pinctrl - -Add pinctrl on the always-enabled debug UART AO. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 0b7aed337ff0f4ff82c3d920a9d022a34c246b6f - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index c62d3d5706ff1..0edbd00b358fd 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -25,4 +25,6 @@ - - &uart_AO { - status = "okay"; -+ pinctrl-0 = <&uart_ao_a_pins>; -+ pinctrl-names = "default"; - }; - -From e5d7028bff190d70d74bcf372d2bdb7f9abf7d2d Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 18 Mar 2019 11:04:52 +0100 -Subject: [PATCH 014/249] FROMGIT: arm64: dts: meson-g12a-sei510: add - regulators - -Add some regulators. Still missing -* VDD_EE (0.8V - PWM controlled) -* VDD_CPU(PWM controlled) -* VDDQ1_5 - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -Acked-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 2297c33c19af6a90a03c5144836c2a088e74c7b3 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../boot/dts/amlogic/meson-g12a-sei510.dts | 57 +++++++++++++++++++ - 1 file changed, 57 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 63c515fe49966..43d57e20294a0 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -6,6 +6,8 @@ - /dts-v1/; - - #include "meson-g12a.dtsi" -+#include -+#include - - / { - compatible = "seirobotics,sei510", "amlogic,g12a"; -@@ -15,10 +17,36 @@ - serial0 = &uart_AO; - }; - -+ ao_5v: regulator-ao_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "AO_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&dc_in>; -+ regulator-always-on; -+ }; -+ - chosen { - stdout-path = "serial0:115200n8"; - }; - -+ dc_in: regulator-dc_in { -+ compatible = "regulator-fixed"; -+ regulator-name = "DC_IN"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ }; -+ -+ emmc_1v8: regulator-emmc_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "EMMC_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ - memory@0 { - device_type = "memory"; - reg = <0x0 0x0 0x0 0x40000000>; -@@ -31,6 +59,35 @@ - no-map; - }; - }; -+ -+ vddao_3v3: regulator-vddao_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&dc_in>; -+ regulator-always-on; -+ }; -+ -+ vddao_3v3_t: regultor-vddao_3v3_t { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3_T"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vddao_3v3>; -+ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; -+ enable-active-high; -+ }; -+ -+ vddio_ao1v8: regulator-vddio_ao1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDIO_AO1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ - }; - - &uart_AO { - -From 5c6544d93c8f1a0ba0d074e01881d584b010c2f7 Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Mon, 25 Mar 2019 11:14:48 +0100 -Subject: [PATCH 015/249] FROMGIT: arm64: dts: meson-g12a-x96-max: add - regulators - -Add system regulators for the X96 Max Set-Top-Box. - -Still missing -* VDD_EE (0.8V - PWM controlled) -* VDD_CPU (PWM controlled) - -Signed-off-by: Guillaume La Roque -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit c9206b42ccbe339e1c72481cf9fefd3b26d79345 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../boot/dts/amlogic/meson-g12a-x96-max.dts | 67 +++++++++++++++++++ - 1 file changed, 67 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 0edbd00b358fd..0ba28491e2b0b 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -6,6 +6,8 @@ - /dts-v1/; - - #include "meson-g12a.dtsi" -+#include -+#include - - / { - compatible = "amediatech,x96-max", "amlogic,u200", "amlogic,g12a"; -@@ -21,6 +23,71 @@ - device_type = "memory"; - reg = <0x0 0x0 0x0 0x40000000>; - }; -+ -+ flash_1v8: regulator-flash_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "FLASH_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ -+ dc_in: regulator-dc_in { -+ compatible = "regulator-fixed"; -+ regulator-name = "DC_IN"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ }; -+ -+ vcc_1v8: regulator-vcc_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ -+ vcc_3v3: regulator-vcc_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ /* FIXME: actually controlled by VDDCPU_B_EN */ -+ }; -+ -+ vcc_5v: regulator-vcc_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&dc_in>; -+ -+ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; -+ enable-active-low; -+ }; -+ -+ vddao_1v8: regulator-vddao_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ -+ vddao_3v3: regulator-vddao_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&dc_in>; -+ regulator-always-on; -+ }; - }; - - &uart_AO { - -From 36fe8d6ff81eb295457b58a57cd39a8816d8a278 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:14:49 +0100 -Subject: [PATCH 016/249] FROMGIT: arm64: dts: meson-g12a-x96-max: Enable BT - Module - -Enable the Bluetooth Module on the X96 Max Set-Top-Box. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit c5c9c7cff2692d75a24761b081d717a78ad535c8 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 0ba28491e2b0b..0a6919523ba94 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -90,6 +90,18 @@ - }; - }; - -+&uart_A { -+ status = "okay"; -+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; -+ pinctrl-names = "default"; -+ uart-has-rtscts; -+ -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; -+ }; -+}; -+ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From f278831ec5fc28f19d1f00370d6b2ff91818a9f9 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 27 Mar 2019 11:21:57 +0100 -Subject: [PATCH 017/249] FROMGIT: arm64: dts: meson-g12a: Add CMA reserved - memory - -In order to handle Video Output and later on Video decoding, -add a reserved CMA pool with a similar 256MiB size as other SoCs. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit e2cffeb398f4830b004774444809ee256b9bc653 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 4d04742b05c2c..d6ca0bbd8f74a 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -79,6 +79,14 @@ - reg = <0x0 0x05000000 0x0 0x300000>; - no-map; - }; -+ -+ linux,cma { -+ compatible = "shared-dma-pool"; -+ reusable; -+ size = <0x0 0x10000000>; -+ alignment = <0x0 0x400000>; -+ linux,cma-default; -+ }; - }; - - sm: secure-monitor { - -From 2de04645e134d5c2456144677f065b56e90a3991 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 7 Mar 2019 15:01:45 +0100 -Subject: [PATCH 018/249] FROMGIT: soc: amlogic: gx-socinfo: Add mask for each - SoC packages - -When updated IDs on f842c41adc04 ("amlogic: meson-gx-socinfo: Update soc ids") -we introduced packages ids using the full 8bit value, but in the function -socinfo_to_package_id() the id was filtered with the 0xf0 mask. - -While the 0xf0 mask is valid for most board, it filters out the lower -4 bits which encodes some characteristics of the chip. - -This patch moves the mask into the meson_gx_package_id table to be applied -on each package name independently and add the correct mask for some -specific entries. - -An example is the S905, in the vendor code the S905 is package_id -different from 0x20, and S905M is exactly 0x20. - -Another example are the The Wetek Hub & Play2 boards using a S905-H -variant, which is the S905 SoC with some licence bits enabled. -These licence bits are encoded in the lower 4bits, so to detect -the -H variant, we must detect the id == 0x3 with the 0xf mask. - -Fixes: f842c41adc04 ("amlogic: meson-gx-socinfo: Update soc ids") -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit dce47aed20c7de3ee2011b7a63e67f08e9dcfb5e - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) ---- - drivers/soc/amlogic/meson-gx-socinfo.c | 32 ++++++++++++++------------ - 1 file changed, 17 insertions(+), 15 deletions(-) - -diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c -index 37ea0a1c24c82..1ae339f5eadbd 100644 ---- a/drivers/soc/amlogic/meson-gx-socinfo.c -+++ b/drivers/soc/amlogic/meson-gx-socinfo.c -@@ -43,20 +43,21 @@ static const struct meson_gx_package_id { - const char *name; - unsigned int major_id; - unsigned int pack_id; -+ unsigned int pack_mask; - } soc_packages[] = { -- { "S905", 0x1f, 0 }, -- { "S905H", 0x1f, 0x13 }, -- { "S905M", 0x1f, 0x20 }, -- { "S905D", 0x21, 0 }, -- { "S905X", 0x21, 0x80 }, -- { "S905W", 0x21, 0xa0 }, -- { "S905L", 0x21, 0xc0 }, -- { "S905M2", 0x21, 0xe0 }, -- { "S912", 0x22, 0 }, -- { "962X", 0x24, 0x10 }, -- { "962E", 0x24, 0x20 }, -- { "A113X", 0x25, 0x37 }, -- { "A113D", 0x25, 0x22 }, -+ { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */ -+ { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */ -+ { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */ -+ { "S905D", 0x21, 0, 0xf0 }, -+ { "S905X", 0x21, 0x80, 0xf0 }, -+ { "S905W", 0x21, 0xa0, 0xf0 }, -+ { "S905L", 0x21, 0xc0, 0xf0 }, -+ { "S905M2", 0x21, 0xe0, 0xf0 }, -+ { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ -+ { "962X", 0x24, 0x10, 0xf0 }, -+ { "962E", 0x24, 0x20, 0xf0 }, -+ { "A113X", 0x25, 0x37, 0xff }, -+ { "A113D", 0x25, 0x22, 0xff }, - }; - - static inline unsigned int socinfo_to_major(u32 socinfo) -@@ -81,13 +82,14 @@ static inline unsigned int socinfo_to_misc(u32 socinfo) - - static const char *socinfo_to_package_id(u32 socinfo) - { -- unsigned int pack = socinfo_to_pack(socinfo) & 0xf0; -+ unsigned int pack = socinfo_to_pack(socinfo); - unsigned int major = socinfo_to_major(socinfo); - int i; - - for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) { - if (soc_packages[i].major_id == major && -- soc_packages[i].pack_id == pack) -+ soc_packages[i].pack_id == -+ (pack & soc_packages[i].pack_mask)) - return soc_packages[i].name; - } - - -From 0a8f350d721f0261d337b5ed8673066b90874372 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 7 Mar 2019 15:01:46 +0100 -Subject: [PATCH 019/249] FROMGIT: soc: amlogic: gx-socinfo: Add new SoC IDs - and Packages IDs - -This adds the: -- G12A SoC ID and S905X2, S905D2 package IDs, found booting the - X96 Max and U200 Reference Board -- G12B SoC ID and S922X package ID, found booting the Odroid-N2 -- S805X, S805Y package IDs found in the vendor U-Boot source - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 65f80df58eb770b2b687c35142c113d1ad6fa415 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) ---- - drivers/soc/amlogic/meson-gx-socinfo.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c -index 1ae339f5eadbd..c8d138d85f34b 100644 ---- a/drivers/soc/amlogic/meson-gx-socinfo.c -+++ b/drivers/soc/amlogic/meson-gx-socinfo.c -@@ -37,6 +37,8 @@ static const struct meson_gx_soc_id { - { "AXG", 0x25 }, - { "GXLX", 0x26 }, - { "TXHD", 0x27 }, -+ { "G12A", 0x28 }, -+ { "G12B", 0x29 }, - }; - - static const struct meson_gx_package_id { -@@ -53,11 +55,16 @@ static const struct meson_gx_package_id { - { "S905W", 0x21, 0xa0, 0xf0 }, - { "S905L", 0x21, 0xc0, 0xf0 }, - { "S905M2", 0x21, 0xe0, 0xf0 }, -+ { "S805X", 0x21, 0x30, 0xf0 }, -+ { "S805Y", 0x21, 0xb0, 0xf0 }, - { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ - { "962X", 0x24, 0x10, 0xf0 }, - { "962E", 0x24, 0x20, 0xf0 }, - { "A113X", 0x25, 0x37, 0xff }, - { "A113D", 0x25, 0x22, 0xff }, -+ { "S905D2", 0x28, 0x10, 0xf0 }, -+ { "S905X2", 0x28, 0x40, 0xf0 }, -+ { "S922X", 0x29, 0x40, 0xf0 }, - }; - - static inline unsigned int socinfo_to_major(u32 socinfo) - -From 235e355fc478c0d52b745d843dd60255e51bdbfa Mon Sep 17 00:00:00 2001 -From: Julia Lawall -Date: Sat, 23 Feb 2019 14:20:40 +0100 -Subject: [PATCH 020/249] FROMGIT: meson-gx-socinfo: add missing of_node_put - after of_device_is_available - -Add an of_node_put when a tested device node is not available. - -The semantic patch that fixes this problem is as follows -(http://coccinelle.lip6.fr): - -// -@@ -identifier f; -local idexpression e; -expression x; -@@ - -e = f(...); -... when != of_node_put(e) - when != x = e - when != e = x - when any -if (<+...of_device_is_available(e)...+>) { - ... when != of_node_put(e) -( - return e; -| -+ of_node_put(e); - return ...; -) -} -// - -Fixes: a9daaba2965e8 ("soc: Add Amlogic SoC Information driver") -Signed-off-by: Julia Lawall -Signed-off-by: Kevin Hilman -(cherry picked from commit fdda0a6adc33536ad468f07db27325423703c5bc - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) -Signed-off-by: Neil Armstrong ---- - drivers/soc/amlogic/meson-gx-socinfo.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c -index c8d138d85f34b..bca34954518ec 100644 ---- a/drivers/soc/amlogic/meson-gx-socinfo.c -+++ b/drivers/soc/amlogic/meson-gx-socinfo.c -@@ -132,8 +132,10 @@ static int __init meson_gx_socinfo_init(void) - return -ENODEV; - - /* check if interface is enabled */ -- if (!of_device_is_available(np)) -+ if (!of_device_is_available(np)) { -+ of_node_put(np); - return -ENODEV; -+ } - - /* check if chip-id is available */ - if (!of_property_read_bool(np, "amlogic,has-chip-id")) - -From b3352f1172cce07aac6be6c6fbd7d966d5630687 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 4 Mar 2019 12:12:16 +0100 -Subject: [PATCH 021/249] FROMGIT: dt-bindings: iio: adc: document the Meson - G12A support - -Update the documentation to explicitly support the Meson-G12A SoC. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Jonathan Cameron -(cherry picked from commit a29b8657d322daef2b9fd3fd7c03f5f5bebfde86 - git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git iio-for-5.2a-2) ---- - .../devicetree/bindings/iio/adc/amlogic,meson-saradc.txt | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt -index 75c7759541024..d57e9df25f4fa 100644 ---- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt -+++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt -@@ -9,6 +9,7 @@ Required properties: - - "amlogic,meson-gxl-saradc" for GXL - - "amlogic,meson-gxm-saradc" for GXM - - "amlogic,meson-axg-saradc" for AXG -+ - "amlogic,meson-g12a-saradc" for AXG - along with the generic "amlogic,meson-saradc" - - reg: the physical base address and length of the registers - - interrupts: the interrupt indicating end of sampling - -From a7e431394ee50de7f4c3ee054d8d078511c914b0 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 4 Mar 2019 12:12:17 +0100 -Subject: [PATCH 022/249] FROMGIT: iio: adc: meson-saradc: add support for - Meson G12A - -Add the SAR ADC driver for the Amlogic Meson-G12A SoC. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Jonathan Cameron -(cherry picked from commit e415a1659ec9f04cda81875cd7e7acb73da16e89 - git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git iio-for-5.2a-2) ---- - drivers/iio/adc/meson_saradc.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c -index f8600fbcdfe37..510d8b7ef3a06 100644 ---- a/drivers/iio/adc/meson_saradc.c -+++ b/drivers/iio/adc/meson_saradc.c -@@ -1150,6 +1150,11 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = { - .name = "meson-axg-saradc", - }; - -+static const struct meson_sar_adc_data meson_sar_adc_g12a_data = { -+ .param = &meson_sar_adc_gxl_param, -+ .name = "meson-g12a-saradc", -+}; -+ - static const struct of_device_id meson_sar_adc_of_match[] = { - { - .compatible = "amlogic,meson8-saradc", -@@ -1175,6 +1180,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { - }, { - .compatible = "amlogic,meson-axg-saradc", - .data = &meson_sar_adc_axg_data, -+ }, { -+ .compatible = "amlogic,meson-g12a-saradc", -+ .data = &meson_sar_adc_g12a_data, - }, - {}, - }; - -From d9c37fc7244d366d55fd6b5b9a47d1b8e006f569 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 4 Mar 2019 14:11:28 +0100 -Subject: [PATCH 023/249] FROMGIT: clk: meson-g12a: add cpu clock bindings - -Add Amlogic G12A Family CPU clocks bindings, only export CPU_CLK since -it should be the only ID used. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Acked-by: Jerome Brunet -Link: https://lkml.kernel.org/r/20190304131129.7762-2-narmstrong@baylibre.com -(cherry picked from commit 58b5c8acba12fdf375dd30074c07730e67b97c3f - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - include/dt-bindings/clock/g12a-clkc.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h -index 83b657038d1ea..d7bf0830c87df 100644 ---- a/include/dt-bindings/clock/g12a-clkc.h -+++ b/include/dt-bindings/clock/g12a-clkc.h -@@ -131,5 +131,6 @@ - #define CLKID_MALI_1 174 - #define CLKID_MALI 175 - #define CLKID_MPLL_5OM 177 -+#define CLKID_CPU_CLK 187 - - #endif /* __G12A_CLKC_H */ - -From 96591cc2644b1f13ee7d58c2e161708b59feea25 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 4 Mar 2019 11:53:58 +0100 -Subject: [PATCH 024/249] FROMGIT: clk: g12a-aoclk: re-export - CLKID_AO_SAR_ADC_SEL clock id - -When submitted v2 of the G12A AO-CLK IDs, the SAR_ADC_SEL ID was moved -to the internal non-exported bindings, but this clock is necessary and -mandatory for the SAR ADC bindings. - -Export it back to the public bindings. - -Fixes: be3d960b0aeb ("dt-bindings: clk: add G12A AO Clock and Reset Bindings") -Signed-off-by: Neil Armstrong -Acked-by: Jerome Brunet -Link: https://lkml.kernel.org/r/20190304105358.4987-1-narmstrong@baylibre.com -(cherry picked from commit dc6276f57617344c9e78332c682ea1e982527e09 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/g12a-aoclk.h | 1 - - include/dt-bindings/clock/g12a-aoclkc.h | 1 + - 2 files changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a-aoclk.h b/drivers/clk/meson/g12a-aoclk.h -index 04b0d55066412..666b4493822cc 100644 ---- a/drivers/clk/meson/g12a-aoclk.h -+++ b/drivers/clk/meson/g12a-aoclk.h -@@ -16,7 +16,6 @@ - * to expose, such as the internal muxes and dividers of composite clocks, - * will remain defined here. - */ --#define CLKID_AO_SAR_ADC_SEL 16 - #define CLKID_AO_SAR_ADC_DIV 17 - #define CLKID_AO_CTS_OSCIN 19 - #define CLKID_AO_32K_PRE 20 -diff --git a/include/dt-bindings/clock/g12a-aoclkc.h b/include/dt-bindings/clock/g12a-aoclkc.h -index 8db01ffbeb063..5ac66a2eee0f7 100644 ---- a/include/dt-bindings/clock/g12a-aoclkc.h -+++ b/include/dt-bindings/clock/g12a-aoclkc.h -@@ -26,6 +26,7 @@ - #define CLKID_AO_M4_FCLK 13 - #define CLKID_AO_M4_HCLK 14 - #define CLKID_AO_CLK81 15 -+#define CLKID_AO_SAR_ADC_SEL 16 - #define CLKID_AO_SAR_ADC_CLK 18 - #define CLKID_AO_32K 23 - #define CLKID_AO_CEC 27 - -From 4b6fc482482f7c4e3fc73e871eabde1f7ec6b1eb Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 7 Mar 2019 15:14:54 +0100 -Subject: [PATCH 025/249] FROMGIT: dt-bindings: clk: g12a-clkc: add PCIE PLL - clock ID - -Add a clock ID for the reference clock feeding the USB3+PCIe Combo PHY. - -Signed-off-by: Neil Armstrong -Acked-by: Jerome Brunet -Link: https://lkml.kernel.org/r/20190307141455.23879-3-narmstrong@baylibre.com -(cherry picked from commit 17750f5218764a06172a294b23275a950e2adce9 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - include/dt-bindings/clock/g12a-clkc.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h -index d7bf0830c87df..30303728fe096 100644 ---- a/include/dt-bindings/clock/g12a-clkc.h -+++ b/include/dt-bindings/clock/g12a-clkc.h -@@ -132,5 +132,6 @@ - #define CLKID_MALI 175 - #define CLKID_MPLL_5OM 177 - #define CLKID_CPU_CLK 187 -+#define CLKID_PCIE_PLL 201 - - #endif /* __G12A_CLKC_H */ - -From 302a43357dc8cade7480508aefc3dd30a1133842 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Wed, 13 Feb 2019 10:58:35 +0100 -Subject: [PATCH 026/249] FROMGIT: dt-bindings: clock: axg-audio: unexpose - controller inputs - -Remove the bindings ID of the clock input of the controller. These -clocks are purely internal to the controller, exposing them was a -mistake. Actually, these should not even be in the provider and have -IDs to begin with. - -Unexpose these IDs before: - * someone starts using them (even if there no valid reason to do so) - * the actual clocks are removed. The fact that they exist is just the - result of an ugly hack. This will be resolved in CCF when we can - reference DT directly in parent table. - -Signed-off-by: Jerome Brunet -Acked-by: Maxime Jourdan -Reviewed-by: Rob Herring -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190213095835.17448-1-jbrunet@baylibre.com -(cherry picked from commit e4c1e95facf9ddf70bb1a737f8ab1c7d38acd234 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/axg-audio.h | 20 ++++++++++++++++++++ - include/dt-bindings/clock/axg-audio-clkc.h | 20 -------------------- - 2 files changed, 20 insertions(+), 20 deletions(-) - -diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h -index 7191b39c9d650..644f0b0fddf25 100644 ---- a/drivers/clk/meson/axg-audio.h -+++ b/drivers/clk/meson/axg-audio.h -@@ -60,6 +60,26 @@ - #define AUD_CLKID_MST5 6 - #define AUD_CLKID_MST6 7 - #define AUD_CLKID_MST7 8 -+#define AUD_CLKID_SLV_SCLK0 9 -+#define AUD_CLKID_SLV_SCLK1 10 -+#define AUD_CLKID_SLV_SCLK2 11 -+#define AUD_CLKID_SLV_SCLK3 12 -+#define AUD_CLKID_SLV_SCLK4 13 -+#define AUD_CLKID_SLV_SCLK5 14 -+#define AUD_CLKID_SLV_SCLK6 15 -+#define AUD_CLKID_SLV_SCLK7 16 -+#define AUD_CLKID_SLV_SCLK8 17 -+#define AUD_CLKID_SLV_SCLK9 18 -+#define AUD_CLKID_SLV_LRCLK0 19 -+#define AUD_CLKID_SLV_LRCLK1 20 -+#define AUD_CLKID_SLV_LRCLK2 21 -+#define AUD_CLKID_SLV_LRCLK3 22 -+#define AUD_CLKID_SLV_LRCLK4 23 -+#define AUD_CLKID_SLV_LRCLK5 24 -+#define AUD_CLKID_SLV_LRCLK6 25 -+#define AUD_CLKID_SLV_LRCLK7 26 -+#define AUD_CLKID_SLV_LRCLK8 27 -+#define AUD_CLKID_SLV_LRCLK9 28 - #define AUD_CLKID_MST_A_MCLK_SEL 59 - #define AUD_CLKID_MST_B_MCLK_SEL 60 - #define AUD_CLKID_MST_C_MCLK_SEL 61 -diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h -index fd9c362099d9b..eafb0de8466bb 100644 ---- a/include/dt-bindings/clock/axg-audio-clkc.h -+++ b/include/dt-bindings/clock/axg-audio-clkc.h -@@ -7,26 +7,6 @@ - #ifndef __AXG_AUDIO_CLKC_BINDINGS_H - #define __AXG_AUDIO_CLKC_BINDINGS_H - --#define AUD_CLKID_SLV_SCLK0 9 --#define AUD_CLKID_SLV_SCLK1 10 --#define AUD_CLKID_SLV_SCLK2 11 --#define AUD_CLKID_SLV_SCLK3 12 --#define AUD_CLKID_SLV_SCLK4 13 --#define AUD_CLKID_SLV_SCLK5 14 --#define AUD_CLKID_SLV_SCLK6 15 --#define AUD_CLKID_SLV_SCLK7 16 --#define AUD_CLKID_SLV_SCLK8 17 --#define AUD_CLKID_SLV_SCLK9 18 --#define AUD_CLKID_SLV_LRCLK0 19 --#define AUD_CLKID_SLV_LRCLK1 20 --#define AUD_CLKID_SLV_LRCLK2 21 --#define AUD_CLKID_SLV_LRCLK3 22 --#define AUD_CLKID_SLV_LRCLK4 23 --#define AUD_CLKID_SLV_LRCLK5 24 --#define AUD_CLKID_SLV_LRCLK6 25 --#define AUD_CLKID_SLV_LRCLK7 26 --#define AUD_CLKID_SLV_LRCLK8 27 --#define AUD_CLKID_SLV_LRCLK9 28 - #define AUD_CLKID_DDR_ARB 29 - #define AUD_CLKID_PDM 30 - #define AUD_CLKID_TDMIN_A 31 - -From 2a66552919d35e5abad8ba9ff4b6670538af6dde Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Tue, 19 Mar 2019 11:11:37 +0100 -Subject: [PATCH 027/249] FROMGIT: dt-bindings: clk: g12a-clkc: add VDEC clock - IDs - -Expose the three clocks related to the video decoder. - -Signed-off-by: Maxime Jourdan -Reviewed-by: Rob Herring -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190319101138.27520-2-mjourdan@baylibre.com -(cherry picked from commit 19478907951afef2249506acc8afec89c3133d9d - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - include/dt-bindings/clock/g12a-clkc.h | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h -index 30303728fe096..82c9e0c020b21 100644 ---- a/include/dt-bindings/clock/g12a-clkc.h -+++ b/include/dt-bindings/clock/g12a-clkc.h -@@ -133,5 +133,8 @@ - #define CLKID_MPLL_5OM 177 - #define CLKID_CPU_CLK 187 - #define CLKID_PCIE_PLL 201 -+#define CLKID_VDEC_1 204 -+#define CLKID_VDEC_HEVC 207 -+#define CLKID_VDEC_HEVCF 210 - - #endif /* __G12A_CLKC_H */ - -From 24c6f2bd0a457a79ff09e41d1ba6dc828f3a627a Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 4 Mar 2019 14:11:29 +0100 -Subject: [PATCH 028/249] FROMGIT: clk: meson: g12a: add cpu clocks - -Add the Amlogic G12A Family CPU Clock tree in read/only for now. - -The CPU clock can either use the SYS_PLL for > 1GHz frequencies or -use a couple of div+mux from 1GHz/667MHz/24MHz source with 2 non-glitch -muxes. - -Proper DVFS support will come in a second time. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Acked-by: Jerome Brunet -[narmstrong: fixed cpu clocks namings] -Link: https://lkml.kernel.org/r/20190304131129.7762-3-narmstrong@baylibre.com -(cherry picked from commit 370294e2667fa1648eb05aab6c4657419634ff83 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/g12a.c | 350 +++++++++++++++++++++++++++++++++++++++ - drivers/clk/meson/g12a.h | 22 ++- - 2 files changed, 371 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index f7b11e1eeebe8..292ccb1f7c79d 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -150,6 +150,318 @@ static struct clk_regmap g12a_sys_pll = { - }, - }; - -+static struct clk_regmap g12a_sys_pll_div16_en = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .bit_idx = 24, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "sys_pll_div16_en", -+ .ops = &clk_regmap_gate_ro_ops, -+ .parent_names = (const char *[]){ "sys_pll" }, -+ .num_parents = 1, -+ /* -+ * This clock is used to debug the sys_pll range -+ * Linux should not change it at runtime -+ */ -+ }, -+}; -+ -+static struct clk_fixed_factor g12a_sys_pll_div16 = { -+ .mult = 1, -+ .div = 16, -+ .hw.init = &(struct clk_init_data){ -+ .name = "sys_pll_div16", -+ .ops = &clk_fixed_factor_ops, -+ .parent_names = (const char *[]){ "sys_pll_div16_en" }, -+ .num_parents = 1, -+ }, -+}; -+ -+/* Datasheet names this field as "premux0" */ -+static struct clk_regmap g12a_cpu_clk_premux0 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .mask = 0x3, -+ .shift = 0, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_dyn0_sel", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ IN_PREFIX "xtal", -+ "fclk_div2", -+ "fclk_div3" }, -+ .num_parents = 3, -+ }, -+}; -+ -+/* Datasheet names this field as "mux0_divn_tcnt" */ -+static struct clk_regmap g12a_cpu_clk_mux0_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .shift = 4, -+ .width = 6, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_dyn0_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_dyn0_sel" }, -+ .num_parents = 1, -+ }, -+}; -+ -+/* Datasheet names this field as "postmux0" */ -+static struct clk_regmap g12a_cpu_clk_postmux0 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .mask = 0x1, -+ .shift = 2, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_dyn0", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_dyn0_sel", -+ "cpu_clk_dyn0_div" }, -+ .num_parents = 2, -+ }, -+}; -+ -+/* Datasheet names this field as "premux1" */ -+static struct clk_regmap g12a_cpu_clk_premux1 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .mask = 0x3, -+ .shift = 16, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_dyn1_sel", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ IN_PREFIX "xtal", -+ "fclk_div2", -+ "fclk_div3" }, -+ .num_parents = 3, -+ }, -+}; -+ -+/* Datasheet names this field as "Mux1_divn_tcnt" */ -+static struct clk_regmap g12a_cpu_clk_mux1_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .shift = 20, -+ .width = 6, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_dyn1_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_dyn1_sel" }, -+ .num_parents = 1, -+ }, -+}; -+ -+/* Datasheet names this field as "postmux1" */ -+static struct clk_regmap g12a_cpu_clk_postmux1 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .mask = 0x1, -+ .shift = 18, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_dyn1", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_dyn1_sel", -+ "cpu_clk_dyn1_div" }, -+ .num_parents = 2, -+ }, -+}; -+ -+/* Datasheet names this field as "Final_dyn_mux_sel" */ -+static struct clk_regmap g12a_cpu_clk_dyn = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .mask = 0x1, -+ .shift = 10, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_dyn", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_dyn0", -+ "cpu_clk_dyn1" }, -+ .num_parents = 2, -+ }, -+}; -+ -+/* Datasheet names this field as "Final_mux_sel" */ -+static struct clk_regmap g12a_cpu_clk = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .mask = 0x1, -+ .shift = 11, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_dyn", -+ "sys_pll" }, -+ .num_parents = 2, -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_div16_en = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .bit_idx = 1, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "cpu_clk_div16_en", -+ .ops = &clk_regmap_gate_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk" }, -+ .num_parents = 1, -+ /* -+ * This clock is used to debug the cpu_clk range -+ * Linux should not change it at runtime -+ */ -+ }, -+}; -+ -+static struct clk_fixed_factor g12a_cpu_clk_div16 = { -+ .mult = 1, -+ .div = 16, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_div16", -+ .ops = &clk_fixed_factor_ops, -+ .parent_names = (const char *[]){ "cpu_clk_div16_en" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_apb_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .shift = 3, -+ .width = 3, -+ .flags = CLK_DIVIDER_POWER_OF_TWO, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_apb_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_apb = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .bit_idx = 1, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "cpu_clk_apb", -+ .ops = &clk_regmap_gate_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_apb_div" }, -+ .num_parents = 1, -+ /* -+ * This clock is set by the ROM monitor code, -+ * Linux should not change it at runtime -+ */ -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_atb_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .shift = 6, -+ .width = 3, -+ .flags = CLK_DIVIDER_POWER_OF_TWO, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_atb_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_atb = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .bit_idx = 17, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "cpu_clk_atb", -+ .ops = &clk_regmap_gate_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_atb_div" }, -+ .num_parents = 1, -+ /* -+ * This clock is set by the ROM monitor code, -+ * Linux should not change it at runtime -+ */ -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_axi_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .shift = 9, -+ .width = 3, -+ .flags = CLK_DIVIDER_POWER_OF_TWO, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_axi_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_axi = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .bit_idx = 18, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "cpu_clk_axi", -+ .ops = &clk_regmap_gate_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_axi_div" }, -+ .num_parents = 1, -+ /* -+ * This clock is set by the ROM monitor code, -+ * Linux should not change it at runtime -+ */ -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_trace_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .shift = 20, -+ .width = 3, -+ .flags = CLK_DIVIDER_POWER_OF_TWO, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk_trace_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_regmap g12a_cpu_clk_trace = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL1, -+ .bit_idx = 23, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "cpu_clk_trace", -+ .ops = &clk_regmap_gate_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_trace_div" }, -+ .num_parents = 1, -+ /* -+ * This clock is set by the ROM monitor code, -+ * Linux should not change it at runtime -+ */ -+ }, -+}; -+ - static const struct pll_mult_range g12a_gp0_pll_mult_range = { - .min = 55, - .max = 255, -@@ -2167,6 +2479,26 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { - [CLKID_MALI] = &g12a_mali.hw, - [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw, - [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw, -+ [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, -+ [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, -+ [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, -+ [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, -+ [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, -+ [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, -+ [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, -+ [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, -+ [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, -+ [CLKID_CPU_CLK] = &g12a_cpu_clk.hw, -+ [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, -+ [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, -+ [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, -+ [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, -+ [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, -+ [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, -+ [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, -+ [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, -+ [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, -+ [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, - [NR_CLKS] = NULL, - }, - .num = NR_CLKS, -@@ -2335,6 +2667,24 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { - &g12a_mali_1, - &g12a_mali, - &g12a_mpll_50m, -+ &g12a_sys_pll_div16_en, -+ &g12a_cpu_clk_premux0, -+ &g12a_cpu_clk_mux0_div, -+ &g12a_cpu_clk_postmux0, -+ &g12a_cpu_clk_premux1, -+ &g12a_cpu_clk_mux1_div, -+ &g12a_cpu_clk_postmux1, -+ &g12a_cpu_clk_dyn, -+ &g12a_cpu_clk, -+ &g12a_cpu_clk_div16_en, -+ &g12a_cpu_clk_apb_div, -+ &g12a_cpu_clk_apb, -+ &g12a_cpu_clk_atb_div, -+ &g12a_cpu_clk_atb, -+ &g12a_cpu_clk_axi_div, -+ &g12a_cpu_clk_axi, -+ &g12a_cpu_clk_trace_div, -+ &g12a_cpu_clk_trace, - }; - - static const struct meson_eeclkc_data g12a_clkc_data = { -diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h -index f399dfe1401cd..70aa469ca1cfc 100644 ---- a/drivers/clk/meson/g12a.h -+++ b/drivers/clk/meson/g12a.h -@@ -50,6 +50,7 @@ - #define HHI_GCLK_MPEG2 0x148 - #define HHI_GCLK_OTHER 0x150 - #define HHI_GCLK_OTHER2 0x154 -+#define HHI_SYS_CPU_CLK_CNTL1 0x15c - #define HHI_VID_CLK_DIV 0x164 - #define HHI_MPEG_CLK_CNTL 0x174 - #define HHI_AUD_CLK_CNTL 0x178 -@@ -166,8 +167,27 @@ - #define CLKID_MALI_0_DIV 170 - #define CLKID_MALI_1_DIV 173 - #define CLKID_MPLL_5OM_DIV 176 -+#define CLKID_SYS_PLL_DIV16_EN 178 -+#define CLKID_SYS_PLL_DIV16 179 -+#define CLKID_CPU_CLK_DYN0_SEL 180 -+#define CLKID_CPU_CLK_DYN0_DIV 181 -+#define CLKID_CPU_CLK_DYN0 182 -+#define CLKID_CPU_CLK_DYN1_SEL 183 -+#define CLKID_CPU_CLK_DYN1_DIV 184 -+#define CLKID_CPU_CLK_DYN1 185 -+#define CLKID_CPU_CLK_DYN 186 -+#define CLKID_CPU_CLK_DIV16_EN 188 -+#define CLKID_CPU_CLK_DIV16 189 -+#define CLKID_CPU_CLK_APB_DIV 190 -+#define CLKID_CPU_CLK_APB 191 -+#define CLKID_CPU_CLK_ATB_DIV 192 -+#define CLKID_CPU_CLK_ATB 193 -+#define CLKID_CPU_CLK_AXI_DIV 194 -+#define CLKID_CPU_CLK_AXI 195 -+#define CLKID_CPU_CLK_TRACE_DIV 196 -+#define CLKID_CPU_CLK_TRACE 197 - --#define NR_CLKS 178 -+#define NR_CLKS 198 - - /* include the CLKIDs that have been made part of the DT binding */ - #include - -From 9c1d0c7fa83a3d2ecd5bf41f0568153541994ed8 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 7 Mar 2019 15:14:53 +0100 -Subject: [PATCH 029/249] FROMGIT: clk: meson-pll: add reduced specific clk_ops - for G12A PCIe PLL - -The Meson G12A PCIE PLL is fined tuned to deliver a very precise -100MHz reference clock for the PCIe Analog PHY, and thus requires -a strict register sequence to enable the PLL. -To simplify, use the _init() op to enable the PLL and keep -the other ops except set_rate since the rate is fixed. - -Signed-off-by: Neil Armstrong -Acked-by: Jerome Brunet -Link: https://lkml.kernel.org/r/20190307141455.23879-2-narmstrong@baylibre.com -(cherry picked from commit 39b8500283b45252e2f9ad9d60992f2c0d3a1659 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/clk-pll.c | 26 ++++++++++++++++++++++++++ - drivers/clk/meson/clk-pll.h | 1 + - 2 files changed, 27 insertions(+) - -diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c -index 7a14ac9b2fecf..ddb1e56347395 100644 ---- a/drivers/clk/meson/clk-pll.c -+++ b/drivers/clk/meson/clk-pll.c -@@ -303,6 +303,16 @@ static int meson_clk_pll_is_enabled(struct clk_hw *hw) - return 1; - } - -+static int meson_clk_pcie_pll_enable(struct clk_hw *hw) -+{ -+ meson_clk_pll_init(hw); -+ -+ if (meson_clk_pll_wait_lock(hw)) -+ return -EIO; -+ -+ return 0; -+} -+ - static int meson_clk_pll_enable(struct clk_hw *hw) - { - struct clk_regmap *clk = to_clk_regmap(hw); -@@ -387,6 +397,22 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, - return 0; - } - -+/* -+ * The Meson G12A PCIE PLL is fined tuned to deliver a very precise -+ * 100MHz reference clock for the PCIe Analog PHY, and thus requires -+ * a strict register sequence to enable the PLL. -+ * To simplify, re-use the _init() op to enable the PLL and keep -+ * the other ops except set_rate since the rate is fixed. -+ */ -+const struct clk_ops meson_clk_pcie_pll_ops = { -+ .recalc_rate = meson_clk_pll_recalc_rate, -+ .round_rate = meson_clk_pll_round_rate, -+ .is_enabled = meson_clk_pll_is_enabled, -+ .enable = meson_clk_pcie_pll_enable, -+ .disable = meson_clk_pll_disable -+}; -+EXPORT_SYMBOL_GPL(meson_clk_pcie_pll_ops); -+ - const struct clk_ops meson_clk_pll_ops = { - .init = meson_clk_pll_init, - .recalc_rate = meson_clk_pll_recalc_rate, -diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h -index 55af2e285b1b0..367efd0f6410c 100644 ---- a/drivers/clk/meson/clk-pll.h -+++ b/drivers/clk/meson/clk-pll.h -@@ -45,5 +45,6 @@ struct meson_clk_pll_data { - - extern const struct clk_ops meson_clk_pll_ro_ops; - extern const struct clk_ops meson_clk_pll_ops; -+extern const struct clk_ops meson_clk_pcie_pll_ops; - - #endif /* __MESON_CLK_PLL_H */ - -From 62980b27c3547abe86ea616b4d57bd46f674b5a8 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 21 Mar 2019 10:20:10 +0100 -Subject: [PATCH 030/249] FROMGIT: dt-bindings: clock: g12a-aoclk: expose - CLKID_AO_CTS_OSCIN - -When submitted v2 of the G12A AO-CLK IDs, the CLKID_AO_CTS_OSCIN was moved -to the internal non-exported bindings, but this clock is necessary for -the second AO-CEC-B module since it embeds the 32768Hz dual-divider -clock generator unlike the AO-CEC-A module. - -Export it back to the public bindings. - -Fixes: be3d960b0aeb ("dt-bindings: clk: add G12A AO Clock and Reset Bindings") -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring -Link: https://lkml.kernel.org/r/20190321092010.14382-1-narmstrong@baylibre.com -(cherry picked from commit 133bb341b99d096d332108f412234d0cf641c15d - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/g12a-aoclk.h | 1 - - include/dt-bindings/clock/g12a-aoclkc.h | 1 + - 2 files changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a-aoclk.h b/drivers/clk/meson/g12a-aoclk.h -index 666b4493822cc..a67c8a7cd7c47 100644 ---- a/drivers/clk/meson/g12a-aoclk.h -+++ b/drivers/clk/meson/g12a-aoclk.h -@@ -17,7 +17,6 @@ - * will remain defined here. - */ - #define CLKID_AO_SAR_ADC_DIV 17 --#define CLKID_AO_CTS_OSCIN 19 - #define CLKID_AO_32K_PRE 20 - #define CLKID_AO_32K_DIV 21 - #define CLKID_AO_32K_SEL 22 -diff --git a/include/dt-bindings/clock/g12a-aoclkc.h b/include/dt-bindings/clock/g12a-aoclkc.h -index 5ac66a2eee0f7..e916e49ff2884 100644 ---- a/include/dt-bindings/clock/g12a-aoclkc.h -+++ b/include/dt-bindings/clock/g12a-aoclkc.h -@@ -28,6 +28,7 @@ - #define CLKID_AO_CLK81 15 - #define CLKID_AO_SAR_ADC_SEL 16 - #define CLKID_AO_SAR_ADC_CLK 18 -+#define CLKID_AO_CTS_OSCIN 19 - #define CLKID_AO_32K 23 - #define CLKID_AO_CEC 27 - #define CLKID_AO_CTS_RTC_OSCIN 28 - -From ae5582ebc4391e414246889312963d6756fd1f65 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 7 Mar 2019 15:14:55 +0100 -Subject: [PATCH 031/249] FROMGIT: clk: meson-g12a: add PCIE PLL clocks - -Add the PCIe reference clock feeding the USB3 + PCIE combo PHY. - -This PLL needs a very precise register sequence to permit to be locked, -thus using the specific clk-pll pcie ops. - -The PLL is then followed by : -- a fixed /2 divider -- a 5-bit 1-based divider -- a final /2 divider - -This reference clock is fixed to 100MHz, thus only a single PLL setup -is added. - -Signed-off-by: Neil Armstrong -Acked-by: Jerome Brunet -Link: https://lkml.kernel.org/r/20190307141455.23879-4-narmstrong@baylibre.com -(cherry picked from commit 34775209ba37bff3b4e60ddee0a2d69966146a5d - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/g12a.c | 118 +++++++++++++++++++++++++++++++++++++++ - drivers/clk/meson/g12a.h | 5 +- - 2 files changed, 122 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index 292ccb1f7c79d..ecbfd4f38a255 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -614,6 +614,118 @@ static struct clk_regmap g12a_hifi_pll = { - }, - }; - -+/* -+ * The Meson G12A PCIE PLL is fined tuned to deliver a very precise -+ * 100MHz reference clock for the PCIe Analog PHY, and thus requires -+ * a strict register sequence to enable the PLL. -+ */ -+static const struct reg_sequence g12a_pcie_pll_init_regs[] = { -+ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x20090496 }, -+ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x30090496 }, -+ { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x00000000 }, -+ { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001100 }, -+ { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x10058e00 }, -+ { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x000100c0 }, -+ { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000048 }, -+ { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000068, .delay_us = 20 }, -+ { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x008100c0, .delay_us = 10 }, -+ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x34090496 }, -+ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x14090496, .delay_us = 10 }, -+ { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001000 }, -+}; -+ -+/* Keep a single entry table for recalc/round_rate() ops */ -+static const struct pll_params_table g12a_pcie_pll_table[] = { -+ PLL_PARAMS(150, 1), -+ {0, 0}, -+}; -+ -+static struct clk_regmap g12a_pcie_pll_dco = { -+ .data = &(struct meson_clk_pll_data){ -+ .en = { -+ .reg_off = HHI_PCIE_PLL_CNTL0, -+ .shift = 28, -+ .width = 1, -+ }, -+ .m = { -+ .reg_off = HHI_PCIE_PLL_CNTL0, -+ .shift = 0, -+ .width = 8, -+ }, -+ .n = { -+ .reg_off = HHI_PCIE_PLL_CNTL0, -+ .shift = 10, -+ .width = 5, -+ }, -+ .frac = { -+ .reg_off = HHI_PCIE_PLL_CNTL1, -+ .shift = 0, -+ .width = 12, -+ }, -+ .l = { -+ .reg_off = HHI_PCIE_PLL_CNTL0, -+ .shift = 31, -+ .width = 1, -+ }, -+ .rst = { -+ .reg_off = HHI_PCIE_PLL_CNTL0, -+ .shift = 29, -+ .width = 1, -+ }, -+ .table = g12a_pcie_pll_table, -+ .init_regs = g12a_pcie_pll_init_regs, -+ .init_count = ARRAY_SIZE(g12a_pcie_pll_init_regs), -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "pcie_pll_dco", -+ .ops = &meson_clk_pcie_pll_ops, -+ .parent_names = (const char *[]){ IN_PREFIX "xtal" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { -+ .mult = 1, -+ .div = 2, -+ .hw.init = &(struct clk_init_data){ -+ .name = "pcie_pll_dco_div2", -+ .ops = &clk_fixed_factor_ops, -+ .parent_names = (const char *[]){ "pcie_pll_dco" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_pcie_pll_od = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_PCIE_PLL_CNTL0, -+ .shift = 16, -+ .width = 5, -+ .flags = CLK_DIVIDER_ROUND_CLOSEST | -+ CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "pcie_pll_od", -+ .ops = &clk_regmap_divider_ops, -+ .parent_names = (const char *[]){ "pcie_pll_dco_div2" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_fixed_factor g12a_pcie_pll = { -+ .mult = 1, -+ .div = 2, -+ .hw.init = &(struct clk_init_data){ -+ .name = "pcie_pll_pll", -+ .ops = &clk_fixed_factor_ops, -+ .parent_names = (const char *[]){ "pcie_pll_od" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ - static struct clk_regmap g12a_hdmi_pll_dco = { - .data = &(struct meson_clk_pll_data){ - .en = { -@@ -2499,6 +2611,10 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { - [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, - [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, - [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, -+ [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, -+ [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, -+ [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, -+ [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, - [NR_CLKS] = NULL, - }, - .num = NR_CLKS, -@@ -2685,6 +2801,8 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { - &g12a_cpu_clk_axi, - &g12a_cpu_clk_trace_div, - &g12a_cpu_clk_trace, -+ &g12a_pcie_pll_od, -+ &g12a_pcie_pll_dco, - }; - - static const struct meson_eeclkc_data g12a_clkc_data = { -diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h -index 70aa469ca1cfc..1393a09730a6b 100644 ---- a/drivers/clk/meson/g12a.h -+++ b/drivers/clk/meson/g12a.h -@@ -186,8 +186,11 @@ - #define CLKID_CPU_CLK_AXI 195 - #define CLKID_CPU_CLK_TRACE_DIV 196 - #define CLKID_CPU_CLK_TRACE 197 -+#define CLKID_PCIE_PLL_DCO 198 -+#define CLKID_PCIE_PLL_DCO_DIV2 199 -+#define CLKID_PCIE_PLL_OD 200 - --#define NR_CLKS 198 -+#define NR_CLKS 202 - - /* include the CLKIDs that have been made part of the DT binding */ - #include - -From 6c9abc2a14e119cb48a26869f3e2093bff6c801b Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Tue, 19 Mar 2019 11:11:38 +0100 -Subject: [PATCH 032/249] FROMGIT: clk: meson-g12a: add video decoder clocks - -Add the necessary clock parts for: - - - VDEC_1: used to feed VDEC_1 - - VDEC_HEVC: the "back" part of the VDEC_HEVC block - - VDEC_HEVCF: the "front" part of the VDEC_HEVC block - -In previous SoC generations (GXL, GXBB), there was only one VDEC_HEVC -clock, which got split in two parts for G12A. - -Signed-off-by: Maxime Jourdan -Acked-by: Neil Armstrong -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190319101138.27520-2-mjourdan@baylibre.com -(cherry picked from commit 4b0f73055acaced436d5de909b26d001ea7f667c - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/g12a.c | 163 +++++++++++++++++++++++++++++++++++++++ - drivers/clk/meson/g12a.h | 8 +- - 2 files changed, 170 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index ecbfd4f38a255..739f64fdf1e3b 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -1495,6 +1495,151 @@ static struct clk_regmap g12a_vpu = { - }, - }; - -+/* VDEC clocks */ -+ -+static const char * const g12a_vdec_parent_names[] = { -+ "fclk_div2p5", "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7", -+ "hifi_pll", "gp0_pll", -+}; -+ -+static struct clk_regmap g12a_vdec_1_sel = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_VDEC_CLK_CNTL, -+ .mask = 0x7, -+ .shift = 9, -+ .flags = CLK_MUX_ROUND_CLOSEST, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "vdec_1_sel", -+ .ops = &clk_regmap_mux_ops, -+ .parent_names = g12a_vdec_parent_names, -+ .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_1_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_VDEC_CLK_CNTL, -+ .shift = 0, -+ .width = 7, -+ .flags = CLK_DIVIDER_ROUND_CLOSEST, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "vdec_1_div", -+ .ops = &clk_regmap_divider_ops, -+ .parent_names = (const char *[]){ "vdec_1_sel" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_1 = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_VDEC_CLK_CNTL, -+ .bit_idx = 8, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "vdec_1", -+ .ops = &clk_regmap_gate_ops, -+ .parent_names = (const char *[]){ "vdec_1_div" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_hevcf_sel = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_VDEC2_CLK_CNTL, -+ .mask = 0x7, -+ .shift = 9, -+ .flags = CLK_MUX_ROUND_CLOSEST, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "vdec_hevcf_sel", -+ .ops = &clk_regmap_mux_ops, -+ .parent_names = g12a_vdec_parent_names, -+ .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_hevcf_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_VDEC2_CLK_CNTL, -+ .shift = 0, -+ .width = 7, -+ .flags = CLK_DIVIDER_ROUND_CLOSEST, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "vdec_hevcf_div", -+ .ops = &clk_regmap_divider_ops, -+ .parent_names = (const char *[]){ "vdec_hevcf_sel" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_hevcf = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_VDEC2_CLK_CNTL, -+ .bit_idx = 8, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "vdec_hevcf", -+ .ops = &clk_regmap_gate_ops, -+ .parent_names = (const char *[]){ "vdec_hevcf_div" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_hevc_sel = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_VDEC2_CLK_CNTL, -+ .mask = 0x7, -+ .shift = 25, -+ .flags = CLK_MUX_ROUND_CLOSEST, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "vdec_hevc_sel", -+ .ops = &clk_regmap_mux_ops, -+ .parent_names = g12a_vdec_parent_names, -+ .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_hevc_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_VDEC2_CLK_CNTL, -+ .shift = 16, -+ .width = 7, -+ .flags = CLK_DIVIDER_ROUND_CLOSEST, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "vdec_hevc_div", -+ .ops = &clk_regmap_divider_ops, -+ .parent_names = (const char *[]){ "vdec_hevc_sel" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ -+static struct clk_regmap g12a_vdec_hevc = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_VDEC2_CLK_CNTL, -+ .bit_idx = 24, -+ }, -+ .hw.init = &(struct clk_init_data) { -+ .name = "vdec_hevc", -+ .ops = &clk_regmap_gate_ops, -+ .parent_names = (const char *[]){ "vdec_hevc_div" }, -+ .num_parents = 1, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+}; -+ - /* VAPB Clock */ - - static const char * const g12a_vapb_parent_names[] = { -@@ -2615,6 +2760,15 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { - [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, - [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, - [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, -+ [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, -+ [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, -+ [CLKID_VDEC_1] = &g12a_vdec_1.hw, -+ [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, -+ [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, -+ [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, -+ [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, -+ [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, -+ [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, - [NR_CLKS] = NULL, - }, - .num = NR_CLKS, -@@ -2803,6 +2957,15 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { - &g12a_cpu_clk_trace, - &g12a_pcie_pll_od, - &g12a_pcie_pll_dco, -+ &g12a_vdec_1_sel, -+ &g12a_vdec_1_div, -+ &g12a_vdec_1, -+ &g12a_vdec_hevc_sel, -+ &g12a_vdec_hevc_div, -+ &g12a_vdec_hevc, -+ &g12a_vdec_hevcf_sel, -+ &g12a_vdec_hevcf_div, -+ &g12a_vdec_hevcf, - }; - - static const struct meson_eeclkc_data g12a_clkc_data = { -diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h -index 1393a09730a6b..39c41af708044 100644 ---- a/drivers/clk/meson/g12a.h -+++ b/drivers/clk/meson/g12a.h -@@ -189,8 +189,14 @@ - #define CLKID_PCIE_PLL_DCO 198 - #define CLKID_PCIE_PLL_DCO_DIV2 199 - #define CLKID_PCIE_PLL_OD 200 -+#define CLKID_VDEC_1_SEL 202 -+#define CLKID_VDEC_1_DIV 203 -+#define CLKID_VDEC_HEVC_SEL 205 -+#define CLKID_VDEC_HEVC_DIV 206 -+#define CLKID_VDEC_HEVCF_SEL 208 -+#define CLKID_VDEC_HEVCF_DIV 209 - --#define NR_CLKS 202 -+#define NR_CLKS 211 - - /* include the CLKIDs that have been made part of the DT binding */ - #include - -From b2508cc758bbc0513d7c9181d910de12f2c0bb07 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 29 Mar 2019 17:06:46 +0100 -Subject: [PATCH 033/249] FROMGIT: dt-bindings: clk: axg-audio: add g12a - support - -Add a new compatible string and additional clock ids for audio clock -controller of the g12a SoC family. - -Signed-off-by: Jerome Brunet -Reviewed-by: Rob Herring -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190329160649.31603-2-jbrunet@baylibre.com -(cherry picked from commit 8554926b3fcb703a788018d5eba0ddd377abeecd - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - .../bindings/clock/amlogic,axg-audio-clkc.txt | 3 ++- - include/dt-bindings/clock/axg-audio-clkc.h | 10 ++++++++++ - 2 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt -index 61777ad24f61c..0f777749f4f1e 100644 ---- a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt -+++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt -@@ -6,7 +6,8 @@ devices. - - Required Properties: - --- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D -+- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D, -+ "amlogic,g12a-audio-clkc" for G12A. - - reg : physical base address of the clock controller and length of - memory mapped region. - - clocks : a list of phandle + clock-specifier pairs for the clocks listed -diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h -index eafb0de8466bb..75901c636893c 100644 ---- a/include/dt-bindings/clock/axg-audio-clkc.h -+++ b/include/dt-bindings/clock/axg-audio-clkc.h -@@ -70,5 +70,15 @@ - #define AUD_CLKID_TDMOUT_A_LRCLK 134 - #define AUD_CLKID_TDMOUT_B_LRCLK 135 - #define AUD_CLKID_TDMOUT_C_LRCLK 136 -+#define AUD_CLKID_SPDIFOUT_B 151 -+#define AUD_CLKID_SPDIFOUT_B_CLK 152 -+#define AUD_CLKID_TDM_MCLK_PAD0 155 -+#define AUD_CLKID_TDM_MCLK_PAD1 156 -+#define AUD_CLKID_TDM_LRCLK_PAD0 157 -+#define AUD_CLKID_TDM_LRCLK_PAD1 158 -+#define AUD_CLKID_TDM_LRCLK_PAD2 159 -+#define AUD_CLKID_TDM_SCLK_PAD0 160 -+#define AUD_CLKID_TDM_SCLK_PAD1 161 -+#define AUD_CLKID_TDM_SCLK_PAD2 162 - - #endif /* __AXG_AUDIO_CLKC_BINDINGS_H */ - -From 6167833a050ffb1ba90cfe109721eacb70b64596 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 29 Mar 2019 17:06:47 +0100 -Subject: [PATCH 034/249] FROMGIT: clk: meson: axg_audio: replace prefix axg by - aud - -The audio clock controller is compatible with axg and g12a SoC family. -Having each clock name prefixed with "axg_" looks weird on the g12a. -This change replace the "axg_" by "aud_" in fron the clock names. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190329160649.31603-3-jbrunet@baylibre.com -(cherry picked from commit b18819c4acf16ac3273192b79c53f3b833b9a1f8 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/axg-audio.c | 964 +++++++++++++++++----------------- - 1 file changed, 482 insertions(+), 482 deletions(-) - -diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c -index 7ab200b6c3bff..38fccffc171ea 100644 ---- a/drivers/clk/meson/axg-audio.c -+++ b/drivers/clk/meson/axg-audio.c -@@ -20,18 +20,18 @@ - #include "clk-phase.h" - #include "sclk-div.h" - --#define AXG_MST_IN_COUNT 8 --#define AXG_SLV_SCLK_COUNT 10 --#define AXG_SLV_LRCLK_COUNT 10 -+#define AUD_MST_IN_COUNT 8 -+#define AUD_SLV_SCLK_COUNT 10 -+#define AUD_SLV_LRCLK_COUNT 10 - --#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ --struct clk_regmap axg_##_name = { \ -+#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ -+struct clk_regmap aud_##_name = { \ - .data = &(struct clk_regmap_gate_data){ \ - .offset = (_reg), \ - .bit_idx = (_bit), \ - }, \ - .hw.init = &(struct clk_init_data) { \ -- .name = "axg_"#_name, \ -+ .name = "aud_"#_name, \ - .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ _pname }, \ - .num_parents = 1, \ -@@ -39,8 +39,8 @@ struct clk_regmap axg_##_name = { \ - }, \ - } - --#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ --struct clk_regmap axg_##_name = { \ -+#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ -+struct clk_regmap aud_##_name = { \ - .data = &(struct clk_regmap_mux_data){ \ - .offset = (_reg), \ - .mask = (_mask), \ -@@ -48,7 +48,7 @@ struct clk_regmap axg_##_name = { \ - .flags = (_dflags), \ - }, \ - .hw.init = &(struct clk_init_data){ \ -- .name = "axg_"#_name, \ -+ .name = "aud_"#_name, \ - .ops = &clk_regmap_mux_ops, \ - .parent_names = (_pnames), \ - .num_parents = ARRAY_SIZE(_pnames), \ -@@ -56,8 +56,8 @@ struct clk_regmap axg_##_name = { \ - }, \ - } - --#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ --struct clk_regmap axg_##_name = { \ -+#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ -+struct clk_regmap aud_##_name = { \ - .data = &(struct clk_regmap_div_data){ \ - .offset = (_reg), \ - .shift = (_shift), \ -@@ -65,7 +65,7 @@ struct clk_regmap axg_##_name = { \ - .flags = (_dflags), \ - }, \ - .hw.init = &(struct clk_init_data){ \ -- .name = "axg_"#_name, \ -+ .name = "aud_"#_name, \ - .ops = &clk_regmap_divider_ops, \ - .parent_names = (const char *[]) { _pname }, \ - .num_parents = 1, \ -@@ -73,109 +73,109 @@ struct clk_regmap axg_##_name = { \ - }, \ - } - --#define AXG_PCLK_GATE(_name, _bit) \ -- AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0) -+#define AUD_PCLK_GATE(_name, _bit) \ -+ AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "audio_pclk", 0) - - /* Audio peripheral clocks */ --static AXG_PCLK_GATE(ddr_arb, 0); --static AXG_PCLK_GATE(pdm, 1); --static AXG_PCLK_GATE(tdmin_a, 2); --static AXG_PCLK_GATE(tdmin_b, 3); --static AXG_PCLK_GATE(tdmin_c, 4); --static AXG_PCLK_GATE(tdmin_lb, 5); --static AXG_PCLK_GATE(tdmout_a, 6); --static AXG_PCLK_GATE(tdmout_b, 7); --static AXG_PCLK_GATE(tdmout_c, 8); --static AXG_PCLK_GATE(frddr_a, 9); --static AXG_PCLK_GATE(frddr_b, 10); --static AXG_PCLK_GATE(frddr_c, 11); --static AXG_PCLK_GATE(toddr_a, 12); --static AXG_PCLK_GATE(toddr_b, 13); --static AXG_PCLK_GATE(toddr_c, 14); --static AXG_PCLK_GATE(loopback, 15); --static AXG_PCLK_GATE(spdifin, 16); --static AXG_PCLK_GATE(spdifout, 17); --static AXG_PCLK_GATE(resample, 18); --static AXG_PCLK_GATE(power_detect, 19); -+static AUD_PCLK_GATE(ddr_arb, 0); -+static AUD_PCLK_GATE(pdm, 1); -+static AUD_PCLK_GATE(tdmin_a, 2); -+static AUD_PCLK_GATE(tdmin_b, 3); -+static AUD_PCLK_GATE(tdmin_c, 4); -+static AUD_PCLK_GATE(tdmin_lb, 5); -+static AUD_PCLK_GATE(tdmout_a, 6); -+static AUD_PCLK_GATE(tdmout_b, 7); -+static AUD_PCLK_GATE(tdmout_c, 8); -+static AUD_PCLK_GATE(frddr_a, 9); -+static AUD_PCLK_GATE(frddr_b, 10); -+static AUD_PCLK_GATE(frddr_c, 11); -+static AUD_PCLK_GATE(toddr_a, 12); -+static AUD_PCLK_GATE(toddr_b, 13); -+static AUD_PCLK_GATE(toddr_c, 14); -+static AUD_PCLK_GATE(loopback, 15); -+static AUD_PCLK_GATE(spdifin, 16); -+static AUD_PCLK_GATE(spdifout, 17); -+static AUD_PCLK_GATE(resample, 18); -+static AUD_PCLK_GATE(power_detect, 19); - - /* Audio Master Clocks */ - static const char * const mst_mux_parent_names[] = { -- "axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3", -- "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", -+ "aud_mst_in0", "aud_mst_in1", "aud_mst_in2", "aud_mst_in3", -+ "aud_mst_in4", "aud_mst_in5", "aud_mst_in6", "aud_mst_in7", - }; - --#define AXG_MST_MUX(_name, _reg, _flag) \ -- AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ -- mst_mux_parent_names, CLK_SET_RATE_PARENT) -- --#define AXG_MST_MCLK_MUX(_name, _reg) \ -- AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) -- --#define AXG_MST_SYS_MUX(_name, _reg) \ -- AXG_MST_MUX(_name, _reg, 0) -- --static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); --static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); --static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); --static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); --static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); --static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); --static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); --static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); --static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); --static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -- --#define AXG_MST_DIV(_name, _reg, _flag) \ -- AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ -- "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ -- --#define AXG_MST_MCLK_DIV(_name, _reg) \ -- AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) -- --#define AXG_MST_SYS_DIV(_name, _reg) \ -- AXG_MST_DIV(_name, _reg, 0) -- --static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); --static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); --static AXG_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); --static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); --static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); --static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); --static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); --static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); --static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); --static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -- --#define AXG_MST_MCLK_GATE(_name, _reg) \ -- AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ -- CLK_SET_RATE_PARENT) -- --static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); --static AXG_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); --static AXG_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); --static AXG_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); --static AXG_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); --static AXG_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); --static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); --static AXG_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); --static AXG_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); --static AXG_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -+#define AUD_MST_MUX(_name, _reg, _flag) \ -+ AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ -+ mst_mux_parent_names, CLK_SET_RATE_PARENT) -+ -+#define AUD_MST_MCLK_MUX(_name, _reg) \ -+ AUD_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) -+ -+#define AUD_MST_SYS_MUX(_name, _reg) \ -+ AUD_MST_MUX(_name, _reg, 0) -+ -+static AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); -+static AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); -+static AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); -+static AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); -+static AUD_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); -+static AUD_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); -+static AUD_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -+static AUD_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -+static AUD_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); -+static AUD_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -+ -+#define AUD_MST_DIV(_name, _reg, _flag) \ -+ AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ -+ "aud_"#_name"_sel", CLK_SET_RATE_PARENT) \ -+ -+#define AUD_MST_MCLK_DIV(_name, _reg) \ -+ AUD_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) -+ -+#define AUD_MST_SYS_DIV(_name, _reg) \ -+ AUD_MST_DIV(_name, _reg, 0) -+ -+static AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); -+static AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); -+static AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); -+static AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); -+static AUD_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); -+static AUD_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); -+static AUD_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -+static AUD_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -+static AUD_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); -+static AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -+ -+#define AUD_MST_MCLK_GATE(_name, _reg) \ -+ AUD_GATE(_name, _reg, 31, "aud_"#_name"_div", \ -+ CLK_SET_RATE_PARENT) -+ -+static AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); -+static AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); -+static AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); -+static AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); -+static AUD_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); -+static AUD_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); -+static AUD_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -+static AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); -+static AUD_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -+static AUD_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); - - /* Sample Clocks */ --#define AXG_MST_SCLK_PRE_EN(_name, _reg) \ -- AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ -- "axg_mst_"#_name"_mclk", 0) -- --static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); --static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); --static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); --static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); --static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); --static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); -- --#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ -+#define AUD_MST_SCLK_PRE_EN(_name, _reg) \ -+ AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ -+ "aud_mst_"#_name"_mclk", 0) -+ -+static AUD_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); -+static AUD_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); -+static AUD_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); -+static AUD_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); -+static AUD_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); -+static AUD_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); -+ -+#define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ - _hi_shift, _hi_width, _pname, _iflags) \ --struct clk_regmap axg_##_name = { \ -+struct clk_regmap aud_##_name = { \ - .data = &(struct meson_sclk_div_data) { \ - .div = { \ - .reg_off = (_reg), \ -@@ -189,7 +189,7 @@ struct clk_regmap axg_##_name = { \ - }, \ - }, \ - .hw.init = &(struct clk_init_data) { \ -- .name = "axg_"#_name, \ -+ .name = "aud_"#_name, \ - .ops = &meson_sclk_div_ops, \ - .parent_names = (const char *[]) { _pname }, \ - .num_parents = 1, \ -@@ -197,32 +197,32 @@ struct clk_regmap axg_##_name = { \ - }, \ - } - --#define AXG_MST_SCLK_DIV(_name, _reg) \ -- AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ -- "axg_mst_"#_name"_sclk_pre_en", \ -- CLK_SET_RATE_PARENT) -- --static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); --static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); --static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); --static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); --static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); --static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); -- --#define AXG_MST_SCLK_POST_EN(_name, _reg) \ -- AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ -- "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) -- --static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); --static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); --static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); --static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); --static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); --static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); -- --#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ -+#define AUD_MST_SCLK_DIV(_name, _reg) \ -+ AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ -+ "aud_mst_"#_name"_sclk_pre_en", \ -+ CLK_SET_RATE_PARENT) -+ -+static AUD_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); -+static AUD_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); -+static AUD_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); -+static AUD_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); -+static AUD_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); -+static AUD_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); -+ -+#define AUD_MST_SCLK_POST_EN(_name, _reg) \ -+ AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ -+ "aud_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) -+ -+static AUD_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); -+static AUD_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); -+static AUD_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); -+static AUD_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); -+static AUD_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); -+static AUD_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); -+ -+#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ - _pname, _iflags) \ --struct clk_regmap axg_##_name = { \ -+struct clk_regmap aud_##_name = { \ - .data = &(struct meson_clk_triphase_data) { \ - .ph0 = { \ - .reg_off = (_reg), \ -@@ -241,7 +241,7 @@ struct clk_regmap axg_##_name = { \ - }, \ - }, \ - .hw.init = &(struct clk_init_data) { \ -- .name = "axg_"#_name, \ -+ .name = "aud_"#_name, \ - .ops = &meson_clk_triphase_ops, \ - .parent_names = (const char *[]) { _pname }, \ - .num_parents = 1, \ -@@ -249,87 +249,87 @@ struct clk_regmap axg_##_name = { \ - }, \ - } - --#define AXG_MST_SCLK(_name, _reg) \ -- AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ -- "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) -- --static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); --static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); --static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); --static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); --static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); --static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); -- --#define AXG_MST_LRCLK_DIV(_name, _reg) \ -- AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ -- "axg_mst_"#_name"_sclk_post_en", 0) \ -- --static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); --static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); --static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); --static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); --static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); --static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); -- --#define AXG_MST_LRCLK(_name, _reg) \ -- AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ -- "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) -- --static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); --static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); --static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); --static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); --static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); --static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); -+#define AUD_MST_SCLK(_name, _reg) \ -+ AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ -+ "aud_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) -+ -+static AUD_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); -+static AUD_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); -+static AUD_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); -+static AUD_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); -+static AUD_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); -+static AUD_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); -+ -+#define AUD_MST_LRCLK_DIV(_name, _reg) \ -+ AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ -+ "aud_mst_"#_name"_sclk_post_en", 0) \ -+ -+static AUD_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); -+static AUD_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); -+static AUD_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); -+static AUD_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); -+static AUD_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); -+static AUD_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); -+ -+#define AUD_MST_LRCLK(_name, _reg) \ -+ AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ -+ "aud_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) -+ -+static AUD_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); -+static AUD_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); -+static AUD_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); -+static AUD_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); -+static AUD_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); -+static AUD_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); - - static const char * const tdm_sclk_parent_names[] = { -- "axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk", -- "axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk", -- "axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2", -- "axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5", -- "axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8", -- "axg_slv_sclk9" -+ "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", -+ "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", -+ "aud_slv_sclk0", "aud_slv_sclk1", "aud_slv_sclk2", -+ "aud_slv_sclk3", "aud_slv_sclk4", "aud_slv_sclk5", -+ "aud_slv_sclk6", "aud_slv_sclk7", "aud_slv_sclk8", -+ "aud_slv_sclk9" - }; - --#define AXG_TDM_SCLK_MUX(_name, _reg) \ -- AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ -+#define AUD_TDM_SCLK_MUX(_name, _reg) \ -+ AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ - CLK_MUX_ROUND_CLOSEST, \ - tdm_sclk_parent_names, 0) - --static AXG_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); --static AXG_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); --static AXG_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); --static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); --static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); --static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); --static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -- --#define AXG_TDM_SCLK_PRE_EN(_name, _reg) \ -- AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ -- "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) -- --static AXG_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); --static AXG_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); --static AXG_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); --static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); --static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); --static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); --static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -- --#define AXG_TDM_SCLK_POST_EN(_name, _reg) \ -- AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ -- "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) -- --static AXG_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); --static AXG_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); --static AXG_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); --static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); --static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); --static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); --static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -- --#define AXG_TDM_SCLK(_name, _reg) \ -- struct clk_regmap axg_tdm##_name##_sclk = { \ -+static AUD_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); -+static AUD_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); -+static AUD_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); -+static AUD_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -+static AUD_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -+static AUD_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -+static AUD_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -+ -+#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \ -+ AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ -+ "aud_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) -+ -+static AUD_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); -+static AUD_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); -+static AUD_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); -+static AUD_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -+static AUD_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -+static AUD_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -+static AUD_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -+ -+#define AUD_TDM_SCLK_POST_EN(_name, _reg) \ -+ AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ -+ "aud_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) -+ -+static AUD_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); -+static AUD_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); -+static AUD_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); -+static AUD_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -+static AUD_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -+static AUD_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -+static AUD_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -+ -+#define AUD_TDM_SCLK(_name, _reg) \ -+ struct clk_regmap aud_tdm##_name##_sclk = { \ - .data = &(struct meson_clk_phase_data) { \ - .ph = { \ - .reg_off = (_reg), \ -@@ -338,44 +338,44 @@ static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - }, \ - }, \ - .hw.init = &(struct clk_init_data) { \ -- .name = "axg_tdm"#_name"_sclk", \ -+ .name = "aud_tdm"#_name"_sclk", \ - .ops = &meson_clk_phase_ops, \ - .parent_names = (const char *[]) \ -- { "axg_tdm"#_name"_sclk_post_en" }, \ -+ { "aud_tdm"#_name"_sclk_post_en" }, \ - .num_parents = 1, \ - .flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \ - }, \ - } - --static AXG_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); --static AXG_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); --static AXG_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); --static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); --static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); --static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); --static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -+static AUD_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); -+static AUD_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); -+static AUD_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); -+static AUD_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -+static AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -+static AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -+static AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - - static const char * const tdm_lrclk_parent_names[] = { -- "axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk", -- "axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk", -- "axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2", -- "axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5", -- "axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8", -- "axg_slv_lrclk9" -+ "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", -+ "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", -+ "aud_slv_lrclk0", "aud_slv_lrclk1", "aud_slv_lrclk2", -+ "aud_slv_lrclk3", "aud_slv_lrclk4", "aud_slv_lrclk5", -+ "aud_slv_lrclk6", "aud_slv_lrclk7", "aud_slv_lrclk8", -+ "aud_slv_lrclk9" - }; - --#define AXG_TDM_LRLCK(_name, _reg) \ -- AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ -- CLK_MUX_ROUND_CLOSEST, \ -- tdm_lrclk_parent_names, 0) -+#define AUD_TDM_LRLCK(_name, _reg) \ -+ AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ -+ CLK_MUX_ROUND_CLOSEST, \ -+ tdm_lrclk_parent_names, 0) - --static AXG_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); --static AXG_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); --static AXG_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); --static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); --static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); --static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); --static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); -+static AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); -+static AUD_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); -+static AUD_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); -+static AUD_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -+static AUD_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -+static AUD_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -+static AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - - /* - * Array of all clocks provided by this provider -@@ -383,255 +383,255 @@ static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - */ - static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { - .hws = { -- [AUD_CLKID_DDR_ARB] = &axg_ddr_arb.hw, -- [AUD_CLKID_PDM] = &axg_pdm.hw, -- [AUD_CLKID_TDMIN_A] = &axg_tdmin_a.hw, -- [AUD_CLKID_TDMIN_B] = &axg_tdmin_b.hw, -- [AUD_CLKID_TDMIN_C] = &axg_tdmin_c.hw, -- [AUD_CLKID_TDMIN_LB] = &axg_tdmin_lb.hw, -- [AUD_CLKID_TDMOUT_A] = &axg_tdmout_a.hw, -- [AUD_CLKID_TDMOUT_B] = &axg_tdmout_b.hw, -- [AUD_CLKID_TDMOUT_C] = &axg_tdmout_c.hw, -- [AUD_CLKID_FRDDR_A] = &axg_frddr_a.hw, -- [AUD_CLKID_FRDDR_B] = &axg_frddr_b.hw, -- [AUD_CLKID_FRDDR_C] = &axg_frddr_c.hw, -- [AUD_CLKID_TODDR_A] = &axg_toddr_a.hw, -- [AUD_CLKID_TODDR_B] = &axg_toddr_b.hw, -- [AUD_CLKID_TODDR_C] = &axg_toddr_c.hw, -- [AUD_CLKID_LOOPBACK] = &axg_loopback.hw, -- [AUD_CLKID_SPDIFIN] = &axg_spdifin.hw, -- [AUD_CLKID_SPDIFOUT] = &axg_spdifout.hw, -- [AUD_CLKID_RESAMPLE] = &axg_resample.hw, -- [AUD_CLKID_POWER_DETECT] = &axg_power_detect.hw, -- [AUD_CLKID_MST_A_MCLK_SEL] = &axg_mst_a_mclk_sel.hw, -- [AUD_CLKID_MST_B_MCLK_SEL] = &axg_mst_b_mclk_sel.hw, -- [AUD_CLKID_MST_C_MCLK_SEL] = &axg_mst_c_mclk_sel.hw, -- [AUD_CLKID_MST_D_MCLK_SEL] = &axg_mst_d_mclk_sel.hw, -- [AUD_CLKID_MST_E_MCLK_SEL] = &axg_mst_e_mclk_sel.hw, -- [AUD_CLKID_MST_F_MCLK_SEL] = &axg_mst_f_mclk_sel.hw, -- [AUD_CLKID_MST_A_MCLK_DIV] = &axg_mst_a_mclk_div.hw, -- [AUD_CLKID_MST_B_MCLK_DIV] = &axg_mst_b_mclk_div.hw, -- [AUD_CLKID_MST_C_MCLK_DIV] = &axg_mst_c_mclk_div.hw, -- [AUD_CLKID_MST_D_MCLK_DIV] = &axg_mst_d_mclk_div.hw, -- [AUD_CLKID_MST_E_MCLK_DIV] = &axg_mst_e_mclk_div.hw, -- [AUD_CLKID_MST_F_MCLK_DIV] = &axg_mst_f_mclk_div.hw, -- [AUD_CLKID_MST_A_MCLK] = &axg_mst_a_mclk.hw, -- [AUD_CLKID_MST_B_MCLK] = &axg_mst_b_mclk.hw, -- [AUD_CLKID_MST_C_MCLK] = &axg_mst_c_mclk.hw, -- [AUD_CLKID_MST_D_MCLK] = &axg_mst_d_mclk.hw, -- [AUD_CLKID_MST_E_MCLK] = &axg_mst_e_mclk.hw, -- [AUD_CLKID_MST_F_MCLK] = &axg_mst_f_mclk.hw, -- [AUD_CLKID_SPDIFOUT_CLK_SEL] = &axg_spdifout_clk_sel.hw, -- [AUD_CLKID_SPDIFOUT_CLK_DIV] = &axg_spdifout_clk_div.hw, -- [AUD_CLKID_SPDIFOUT_CLK] = &axg_spdifout_clk.hw, -- [AUD_CLKID_SPDIFIN_CLK_SEL] = &axg_spdifin_clk_sel.hw, -- [AUD_CLKID_SPDIFIN_CLK_DIV] = &axg_spdifin_clk_div.hw, -- [AUD_CLKID_SPDIFIN_CLK] = &axg_spdifin_clk.hw, -- [AUD_CLKID_PDM_DCLK_SEL] = &axg_pdm_dclk_sel.hw, -- [AUD_CLKID_PDM_DCLK_DIV] = &axg_pdm_dclk_div.hw, -- [AUD_CLKID_PDM_DCLK] = &axg_pdm_dclk.hw, -- [AUD_CLKID_PDM_SYSCLK_SEL] = &axg_pdm_sysclk_sel.hw, -- [AUD_CLKID_PDM_SYSCLK_DIV] = &axg_pdm_sysclk_div.hw, -- [AUD_CLKID_PDM_SYSCLK] = &axg_pdm_sysclk.hw, -- [AUD_CLKID_MST_A_SCLK_PRE_EN] = &axg_mst_a_sclk_pre_en.hw, -- [AUD_CLKID_MST_B_SCLK_PRE_EN] = &axg_mst_b_sclk_pre_en.hw, -- [AUD_CLKID_MST_C_SCLK_PRE_EN] = &axg_mst_c_sclk_pre_en.hw, -- [AUD_CLKID_MST_D_SCLK_PRE_EN] = &axg_mst_d_sclk_pre_en.hw, -- [AUD_CLKID_MST_E_SCLK_PRE_EN] = &axg_mst_e_sclk_pre_en.hw, -- [AUD_CLKID_MST_F_SCLK_PRE_EN] = &axg_mst_f_sclk_pre_en.hw, -- [AUD_CLKID_MST_A_SCLK_DIV] = &axg_mst_a_sclk_div.hw, -- [AUD_CLKID_MST_B_SCLK_DIV] = &axg_mst_b_sclk_div.hw, -- [AUD_CLKID_MST_C_SCLK_DIV] = &axg_mst_c_sclk_div.hw, -- [AUD_CLKID_MST_D_SCLK_DIV] = &axg_mst_d_sclk_div.hw, -- [AUD_CLKID_MST_E_SCLK_DIV] = &axg_mst_e_sclk_div.hw, -- [AUD_CLKID_MST_F_SCLK_DIV] = &axg_mst_f_sclk_div.hw, -- [AUD_CLKID_MST_A_SCLK_POST_EN] = &axg_mst_a_sclk_post_en.hw, -- [AUD_CLKID_MST_B_SCLK_POST_EN] = &axg_mst_b_sclk_post_en.hw, -- [AUD_CLKID_MST_C_SCLK_POST_EN] = &axg_mst_c_sclk_post_en.hw, -- [AUD_CLKID_MST_D_SCLK_POST_EN] = &axg_mst_d_sclk_post_en.hw, -- [AUD_CLKID_MST_E_SCLK_POST_EN] = &axg_mst_e_sclk_post_en.hw, -- [AUD_CLKID_MST_F_SCLK_POST_EN] = &axg_mst_f_sclk_post_en.hw, -- [AUD_CLKID_MST_A_SCLK] = &axg_mst_a_sclk.hw, -- [AUD_CLKID_MST_B_SCLK] = &axg_mst_b_sclk.hw, -- [AUD_CLKID_MST_C_SCLK] = &axg_mst_c_sclk.hw, -- [AUD_CLKID_MST_D_SCLK] = &axg_mst_d_sclk.hw, -- [AUD_CLKID_MST_E_SCLK] = &axg_mst_e_sclk.hw, -- [AUD_CLKID_MST_F_SCLK] = &axg_mst_f_sclk.hw, -- [AUD_CLKID_MST_A_LRCLK_DIV] = &axg_mst_a_lrclk_div.hw, -- [AUD_CLKID_MST_B_LRCLK_DIV] = &axg_mst_b_lrclk_div.hw, -- [AUD_CLKID_MST_C_LRCLK_DIV] = &axg_mst_c_lrclk_div.hw, -- [AUD_CLKID_MST_D_LRCLK_DIV] = &axg_mst_d_lrclk_div.hw, -- [AUD_CLKID_MST_E_LRCLK_DIV] = &axg_mst_e_lrclk_div.hw, -- [AUD_CLKID_MST_F_LRCLK_DIV] = &axg_mst_f_lrclk_div.hw, -- [AUD_CLKID_MST_A_LRCLK] = &axg_mst_a_lrclk.hw, -- [AUD_CLKID_MST_B_LRCLK] = &axg_mst_b_lrclk.hw, -- [AUD_CLKID_MST_C_LRCLK] = &axg_mst_c_lrclk.hw, -- [AUD_CLKID_MST_D_LRCLK] = &axg_mst_d_lrclk.hw, -- [AUD_CLKID_MST_E_LRCLK] = &axg_mst_e_lrclk.hw, -- [AUD_CLKID_MST_F_LRCLK] = &axg_mst_f_lrclk.hw, -- [AUD_CLKID_TDMIN_A_SCLK_SEL] = &axg_tdmin_a_sclk_sel.hw, -- [AUD_CLKID_TDMIN_B_SCLK_SEL] = &axg_tdmin_b_sclk_sel.hw, -- [AUD_CLKID_TDMIN_C_SCLK_SEL] = &axg_tdmin_c_sclk_sel.hw, -- [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &axg_tdmin_lb_sclk_sel.hw, -- [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &axg_tdmout_a_sclk_sel.hw, -- [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &axg_tdmout_b_sclk_sel.hw, -- [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &axg_tdmout_c_sclk_sel.hw, -- [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &axg_tdmin_a_sclk_pre_en.hw, -- [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &axg_tdmin_b_sclk_pre_en.hw, -- [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &axg_tdmin_c_sclk_pre_en.hw, -- [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw, -- [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw, -- [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw, -- [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw, -- [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw, -- [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw, -- [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw, -- [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw, -- [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw, -- [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw, -- [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw, -- [AUD_CLKID_TDMIN_A_SCLK] = &axg_tdmin_a_sclk.hw, -- [AUD_CLKID_TDMIN_B_SCLK] = &axg_tdmin_b_sclk.hw, -- [AUD_CLKID_TDMIN_C_SCLK] = &axg_tdmin_c_sclk.hw, -- [AUD_CLKID_TDMIN_LB_SCLK] = &axg_tdmin_lb_sclk.hw, -- [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw, -- [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw, -- [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw, -- [AUD_CLKID_TDMIN_A_LRCLK] = &axg_tdmin_a_lrclk.hw, -- [AUD_CLKID_TDMIN_B_LRCLK] = &axg_tdmin_b_lrclk.hw, -- [AUD_CLKID_TDMIN_C_LRCLK] = &axg_tdmin_c_lrclk.hw, -- [AUD_CLKID_TDMIN_LB_LRCLK] = &axg_tdmin_lb_lrclk.hw, -- [AUD_CLKID_TDMOUT_A_LRCLK] = &axg_tdmout_a_lrclk.hw, -- [AUD_CLKID_TDMOUT_B_LRCLK] = &axg_tdmout_b_lrclk.hw, -- [AUD_CLKID_TDMOUT_C_LRCLK] = &axg_tdmout_c_lrclk.hw, -+ [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw, -+ [AUD_CLKID_PDM] = &aud_pdm.hw, -+ [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw, -+ [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw, -+ [AUD_CLKID_TDMIN_C] = &aud_tdmin_c.hw, -+ [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw, -+ [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw, -+ [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw, -+ [AUD_CLKID_TDMOUT_C] = &aud_tdmout_c.hw, -+ [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw, -+ [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw, -+ [AUD_CLKID_FRDDR_C] = &aud_frddr_c.hw, -+ [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw, -+ [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw, -+ [AUD_CLKID_TODDR_C] = &aud_toddr_c.hw, -+ [AUD_CLKID_LOOPBACK] = &aud_loopback.hw, -+ [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw, -+ [AUD_CLKID_SPDIFOUT] = &aud_spdifout.hw, -+ [AUD_CLKID_RESAMPLE] = &aud_resample.hw, -+ [AUD_CLKID_POWER_DETECT] = &aud_power_detect.hw, -+ [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw, -+ [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw, -+ [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw, -+ [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw, -+ [AUD_CLKID_MST_E_MCLK_SEL] = &aud_mst_e_mclk_sel.hw, -+ [AUD_CLKID_MST_F_MCLK_SEL] = &aud_mst_f_mclk_sel.hw, -+ [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw, -+ [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw, -+ [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw, -+ [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw, -+ [AUD_CLKID_MST_E_MCLK_DIV] = &aud_mst_e_mclk_div.hw, -+ [AUD_CLKID_MST_F_MCLK_DIV] = &aud_mst_f_mclk_div.hw, -+ [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw, -+ [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw, -+ [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw, -+ [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw, -+ [AUD_CLKID_MST_E_MCLK] = &aud_mst_e_mclk.hw, -+ [AUD_CLKID_MST_F_MCLK] = &aud_mst_f_mclk.hw, -+ [AUD_CLKID_SPDIFOUT_CLK_SEL] = &aud_spdifout_clk_sel.hw, -+ [AUD_CLKID_SPDIFOUT_CLK_DIV] = &aud_spdifout_clk_div.hw, -+ [AUD_CLKID_SPDIFOUT_CLK] = &aud_spdifout_clk.hw, -+ [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw, -+ [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw, -+ [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw, -+ [AUD_CLKID_PDM_DCLK_SEL] = &aud_pdm_dclk_sel.hw, -+ [AUD_CLKID_PDM_DCLK_DIV] = &aud_pdm_dclk_div.hw, -+ [AUD_CLKID_PDM_DCLK] = &aud_pdm_dclk.hw, -+ [AUD_CLKID_PDM_SYSCLK_SEL] = &aud_pdm_sysclk_sel.hw, -+ [AUD_CLKID_PDM_SYSCLK_DIV] = &aud_pdm_sysclk_div.hw, -+ [AUD_CLKID_PDM_SYSCLK] = &aud_pdm_sysclk.hw, -+ [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw, -+ [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw, -+ [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw, -+ [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw, -+ [AUD_CLKID_MST_E_SCLK_PRE_EN] = &aud_mst_e_sclk_pre_en.hw, -+ [AUD_CLKID_MST_F_SCLK_PRE_EN] = &aud_mst_f_sclk_pre_en.hw, -+ [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw, -+ [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw, -+ [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw, -+ [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw, -+ [AUD_CLKID_MST_E_SCLK_DIV] = &aud_mst_e_sclk_div.hw, -+ [AUD_CLKID_MST_F_SCLK_DIV] = &aud_mst_f_sclk_div.hw, -+ [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw, -+ [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw, -+ [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw, -+ [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw, -+ [AUD_CLKID_MST_E_SCLK_POST_EN] = &aud_mst_e_sclk_post_en.hw, -+ [AUD_CLKID_MST_F_SCLK_POST_EN] = &aud_mst_f_sclk_post_en.hw, -+ [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw, -+ [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw, -+ [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw, -+ [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw, -+ [AUD_CLKID_MST_E_SCLK] = &aud_mst_e_sclk.hw, -+ [AUD_CLKID_MST_F_SCLK] = &aud_mst_f_sclk.hw, -+ [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw, -+ [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw, -+ [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw, -+ [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw, -+ [AUD_CLKID_MST_E_LRCLK_DIV] = &aud_mst_e_lrclk_div.hw, -+ [AUD_CLKID_MST_F_LRCLK_DIV] = &aud_mst_f_lrclk_div.hw, -+ [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw, -+ [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw, -+ [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw, -+ [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw, -+ [AUD_CLKID_MST_E_LRCLK] = &aud_mst_e_lrclk.hw, -+ [AUD_CLKID_MST_F_LRCLK] = &aud_mst_f_lrclk.hw, -+ [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_C_SCLK_SEL] = &aud_tdmin_c_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &aud_tdmout_c_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &aud_tdmin_c_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &aud_tdmout_c_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &aud_tdmin_c_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &aud_tdmout_c_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw, -+ [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw, -+ [AUD_CLKID_TDMIN_C_SCLK] = &aud_tdmin_c_sclk.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK] = &aud_tdmout_c_sclk.hw, -+ [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw, -+ [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw, -+ [AUD_CLKID_TDMIN_C_LRCLK] = &aud_tdmin_c_lrclk.hw, -+ [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw, -+ [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw, -+ [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw, -+ [AUD_CLKID_TDMOUT_C_LRCLK] = &aud_tdmout_c_lrclk.hw, - [NR_CLKS] = NULL, - }, - .num = NR_CLKS, - }; - - /* Convenience table to populate regmap in .probe() */ --static struct clk_regmap *const axg_audio_clk_regmaps[] = { -- &axg_ddr_arb, -- &axg_pdm, -- &axg_tdmin_a, -- &axg_tdmin_b, -- &axg_tdmin_c, -- &axg_tdmin_lb, -- &axg_tdmout_a, -- &axg_tdmout_b, -- &axg_tdmout_c, -- &axg_frddr_a, -- &axg_frddr_b, -- &axg_frddr_c, -- &axg_toddr_a, -- &axg_toddr_b, -- &axg_toddr_c, -- &axg_loopback, -- &axg_spdifin, -- &axg_spdifout, -- &axg_resample, -- &axg_power_detect, -- &axg_mst_a_mclk_sel, -- &axg_mst_b_mclk_sel, -- &axg_mst_c_mclk_sel, -- &axg_mst_d_mclk_sel, -- &axg_mst_e_mclk_sel, -- &axg_mst_f_mclk_sel, -- &axg_mst_a_mclk_div, -- &axg_mst_b_mclk_div, -- &axg_mst_c_mclk_div, -- &axg_mst_d_mclk_div, -- &axg_mst_e_mclk_div, -- &axg_mst_f_mclk_div, -- &axg_mst_a_mclk, -- &axg_mst_b_mclk, -- &axg_mst_c_mclk, -- &axg_mst_d_mclk, -- &axg_mst_e_mclk, -- &axg_mst_f_mclk, -- &axg_spdifout_clk_sel, -- &axg_spdifout_clk_div, -- &axg_spdifout_clk, -- &axg_spdifin_clk_sel, -- &axg_spdifin_clk_div, -- &axg_spdifin_clk, -- &axg_pdm_dclk_sel, -- &axg_pdm_dclk_div, -- &axg_pdm_dclk, -- &axg_pdm_sysclk_sel, -- &axg_pdm_sysclk_div, -- &axg_pdm_sysclk, -- &axg_mst_a_sclk_pre_en, -- &axg_mst_b_sclk_pre_en, -- &axg_mst_c_sclk_pre_en, -- &axg_mst_d_sclk_pre_en, -- &axg_mst_e_sclk_pre_en, -- &axg_mst_f_sclk_pre_en, -- &axg_mst_a_sclk_div, -- &axg_mst_b_sclk_div, -- &axg_mst_c_sclk_div, -- &axg_mst_d_sclk_div, -- &axg_mst_e_sclk_div, -- &axg_mst_f_sclk_div, -- &axg_mst_a_sclk_post_en, -- &axg_mst_b_sclk_post_en, -- &axg_mst_c_sclk_post_en, -- &axg_mst_d_sclk_post_en, -- &axg_mst_e_sclk_post_en, -- &axg_mst_f_sclk_post_en, -- &axg_mst_a_sclk, -- &axg_mst_b_sclk, -- &axg_mst_c_sclk, -- &axg_mst_d_sclk, -- &axg_mst_e_sclk, -- &axg_mst_f_sclk, -- &axg_mst_a_lrclk_div, -- &axg_mst_b_lrclk_div, -- &axg_mst_c_lrclk_div, -- &axg_mst_d_lrclk_div, -- &axg_mst_e_lrclk_div, -- &axg_mst_f_lrclk_div, -- &axg_mst_a_lrclk, -- &axg_mst_b_lrclk, -- &axg_mst_c_lrclk, -- &axg_mst_d_lrclk, -- &axg_mst_e_lrclk, -- &axg_mst_f_lrclk, -- &axg_tdmin_a_sclk_sel, -- &axg_tdmin_b_sclk_sel, -- &axg_tdmin_c_sclk_sel, -- &axg_tdmin_lb_sclk_sel, -- &axg_tdmout_a_sclk_sel, -- &axg_tdmout_b_sclk_sel, -- &axg_tdmout_c_sclk_sel, -- &axg_tdmin_a_sclk_pre_en, -- &axg_tdmin_b_sclk_pre_en, -- &axg_tdmin_c_sclk_pre_en, -- &axg_tdmin_lb_sclk_pre_en, -- &axg_tdmout_a_sclk_pre_en, -- &axg_tdmout_b_sclk_pre_en, -- &axg_tdmout_c_sclk_pre_en, -- &axg_tdmin_a_sclk_post_en, -- &axg_tdmin_b_sclk_post_en, -- &axg_tdmin_c_sclk_post_en, -- &axg_tdmin_lb_sclk_post_en, -- &axg_tdmout_a_sclk_post_en, -- &axg_tdmout_b_sclk_post_en, -- &axg_tdmout_c_sclk_post_en, -- &axg_tdmin_a_sclk, -- &axg_tdmin_b_sclk, -- &axg_tdmin_c_sclk, -- &axg_tdmin_lb_sclk, -- &axg_tdmout_a_sclk, -- &axg_tdmout_b_sclk, -- &axg_tdmout_c_sclk, -- &axg_tdmin_a_lrclk, -- &axg_tdmin_b_lrclk, -- &axg_tdmin_c_lrclk, -- &axg_tdmin_lb_lrclk, -- &axg_tdmout_a_lrclk, -- &axg_tdmout_b_lrclk, -- &axg_tdmout_c_lrclk, -+static struct clk_regmap *const aud_clk_regmaps[] = { -+ &aud_ddr_arb, -+ &aud_pdm, -+ &aud_tdmin_a, -+ &aud_tdmin_b, -+ &aud_tdmin_c, -+ &aud_tdmin_lb, -+ &aud_tdmout_a, -+ &aud_tdmout_b, -+ &aud_tdmout_c, -+ &aud_frddr_a, -+ &aud_frddr_b, -+ &aud_frddr_c, -+ &aud_toddr_a, -+ &aud_toddr_b, -+ &aud_toddr_c, -+ &aud_loopback, -+ &aud_spdifin, -+ &aud_spdifout, -+ &aud_resample, -+ &aud_power_detect, -+ &aud_mst_a_mclk_sel, -+ &aud_mst_b_mclk_sel, -+ &aud_mst_c_mclk_sel, -+ &aud_mst_d_mclk_sel, -+ &aud_mst_e_mclk_sel, -+ &aud_mst_f_mclk_sel, -+ &aud_mst_a_mclk_div, -+ &aud_mst_b_mclk_div, -+ &aud_mst_c_mclk_div, -+ &aud_mst_d_mclk_div, -+ &aud_mst_e_mclk_div, -+ &aud_mst_f_mclk_div, -+ &aud_mst_a_mclk, -+ &aud_mst_b_mclk, -+ &aud_mst_c_mclk, -+ &aud_mst_d_mclk, -+ &aud_mst_e_mclk, -+ &aud_mst_f_mclk, -+ &aud_spdifout_clk_sel, -+ &aud_spdifout_clk_div, -+ &aud_spdifout_clk, -+ &aud_spdifin_clk_sel, -+ &aud_spdifin_clk_div, -+ &aud_spdifin_clk, -+ &aud_pdm_dclk_sel, -+ &aud_pdm_dclk_div, -+ &aud_pdm_dclk, -+ &aud_pdm_sysclk_sel, -+ &aud_pdm_sysclk_div, -+ &aud_pdm_sysclk, -+ &aud_mst_a_sclk_pre_en, -+ &aud_mst_b_sclk_pre_en, -+ &aud_mst_c_sclk_pre_en, -+ &aud_mst_d_sclk_pre_en, -+ &aud_mst_e_sclk_pre_en, -+ &aud_mst_f_sclk_pre_en, -+ &aud_mst_a_sclk_div, -+ &aud_mst_b_sclk_div, -+ &aud_mst_c_sclk_div, -+ &aud_mst_d_sclk_div, -+ &aud_mst_e_sclk_div, -+ &aud_mst_f_sclk_div, -+ &aud_mst_a_sclk_post_en, -+ &aud_mst_b_sclk_post_en, -+ &aud_mst_c_sclk_post_en, -+ &aud_mst_d_sclk_post_en, -+ &aud_mst_e_sclk_post_en, -+ &aud_mst_f_sclk_post_en, -+ &aud_mst_a_sclk, -+ &aud_mst_b_sclk, -+ &aud_mst_c_sclk, -+ &aud_mst_d_sclk, -+ &aud_mst_e_sclk, -+ &aud_mst_f_sclk, -+ &aud_mst_a_lrclk_div, -+ &aud_mst_b_lrclk_div, -+ &aud_mst_c_lrclk_div, -+ &aud_mst_d_lrclk_div, -+ &aud_mst_e_lrclk_div, -+ &aud_mst_f_lrclk_div, -+ &aud_mst_a_lrclk, -+ &aud_mst_b_lrclk, -+ &aud_mst_c_lrclk, -+ &aud_mst_d_lrclk, -+ &aud_mst_e_lrclk, -+ &aud_mst_f_lrclk, -+ &aud_tdmin_a_sclk_sel, -+ &aud_tdmin_b_sclk_sel, -+ &aud_tdmin_c_sclk_sel, -+ &aud_tdmin_lb_sclk_sel, -+ &aud_tdmout_a_sclk_sel, -+ &aud_tdmout_b_sclk_sel, -+ &aud_tdmout_c_sclk_sel, -+ &aud_tdmin_a_sclk_pre_en, -+ &aud_tdmin_b_sclk_pre_en, -+ &aud_tdmin_c_sclk_pre_en, -+ &aud_tdmin_lb_sclk_pre_en, -+ &aud_tdmout_a_sclk_pre_en, -+ &aud_tdmout_b_sclk_pre_en, -+ &aud_tdmout_c_sclk_pre_en, -+ &aud_tdmin_a_sclk_post_en, -+ &aud_tdmin_b_sclk_post_en, -+ &aud_tdmin_c_sclk_post_en, -+ &aud_tdmin_lb_sclk_post_en, -+ &aud_tdmout_a_sclk_post_en, -+ &aud_tdmout_b_sclk_post_en, -+ &aud_tdmout_c_sclk_post_en, -+ &aud_tdmin_a_sclk, -+ &aud_tdmin_b_sclk, -+ &aud_tdmin_c_sclk, -+ &aud_tdmin_lb_sclk, -+ &aud_tdmout_a_sclk, -+ &aud_tdmout_b_sclk, -+ &aud_tdmout_c_sclk, -+ &aud_tdmin_a_lrclk, -+ &aud_tdmin_b_lrclk, -+ &aud_tdmin_c_lrclk, -+ &aud_tdmin_lb_lrclk, -+ &aud_tdmout_a_lrclk, -+ &aud_tdmout_b_lrclk, -+ &aud_tdmout_c_lrclk, - }; - - static int devm_clk_get_enable(struct device *dev, char *id) -@@ -672,7 +672,7 @@ static int axg_register_clk_hw_input(struct device *dev, - struct clk_hw *hw; - int err = 0; - -- clk_name = kasprintf(GFP_KERNEL, "axg_%s", name); -+ clk_name = kasprintf(GFP_KERNEL, "aud_%s", name); - if (!clk_name) - return -ENOMEM; - -@@ -755,7 +755,7 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) - } - - /* Register the peripheral input clock */ -- hw = meson_clk_hw_register_input(dev, "pclk", "axg_audio_pclk", 0); -+ hw = meson_clk_hw_register_input(dev, "pclk", "audio_pclk", 0); - if (IS_ERR(hw)) - return PTR_ERR(hw); - -@@ -763,28 +763,28 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) - - /* Register optional input master clocks */ - ret = axg_register_clk_hw_inputs(dev, "mst_in", -- AXG_MST_IN_COUNT, -+ AUD_MST_IN_COUNT, - AUD_CLKID_MST0); - if (ret) - return ret; - - /* Register optional input slave sclks */ - ret = axg_register_clk_hw_inputs(dev, "slv_sclk", -- AXG_SLV_SCLK_COUNT, -+ AUD_SLV_SCLK_COUNT, - AUD_CLKID_SLV_SCLK0); - if (ret) - return ret; - - /* Register optional input slave lrclks */ - ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", -- AXG_SLV_LRCLK_COUNT, -+ AUD_SLV_LRCLK_COUNT, - AUD_CLKID_SLV_LRCLK0); - if (ret) - return ret; - - /* Populate regmap for the regmap backed clocks */ -- for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++) -- axg_audio_clk_regmaps[i]->map = map; -+ for (i = 0; i < ARRAY_SIZE(aud_clk_regmaps); i++) -+ aud_clk_regmaps[i]->map = map; - - /* Take care to skip the registered input clocks */ - for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) { - -From 1d83a59947004b402cb632893dd8f1e449d4a6bc Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 29 Mar 2019 17:06:48 +0100 -Subject: [PATCH 035/249] FROMGIT: clk: meson: axg-audio: don't register inputs - in the onecell data - -Clock inputs should not be exported outside the controller. It is a hack -to have a stable global clock name within the clock controller, even for -clocks external to the controller. - -There is an ongoing effort to replace this hack with something better. -The first step is to not register those clocks in the provider anymore, -so we can completely remove them later on. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190329160649.31603-4-jbrunet@baylibre.com -(cherry picked from commit 6d6d2a24b2c7a717a75f4e5f3a0e2ebd35ae5573 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/axg-audio.c | 21 ++++++--------------- - drivers/clk/meson/axg-audio.h | 29 ----------------------------- - 2 files changed, 6 insertions(+), 44 deletions(-) - -diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c -index 38fccffc171ea..e8516f9c03d31 100644 ---- a/drivers/clk/meson/axg-audio.c -+++ b/drivers/clk/meson/axg-audio.c -@@ -665,8 +665,7 @@ static int devm_clk_get_enable(struct device *dev, char *id) - } - - static int axg_register_clk_hw_input(struct device *dev, -- const char *name, -- unsigned int clkid) -+ const char *name) - { - char *clk_name; - struct clk_hw *hw; -@@ -686,8 +685,6 @@ static int axg_register_clk_hw_input(struct device *dev, - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to get %s clock", name); - } -- } else { -- axg_audio_hw_onecell_data.hws[clkid] = hw; - } - - kfree(clk_name); -@@ -696,8 +693,7 @@ static int axg_register_clk_hw_input(struct device *dev, - - static int axg_register_clk_hw_inputs(struct device *dev, - const char *basename, -- unsigned int count, -- unsigned int clkid) -+ unsigned int count) - { - char *name; - int i, ret; -@@ -707,7 +703,7 @@ static int axg_register_clk_hw_inputs(struct device *dev, - if (!name) - return -ENOMEM; - -- ret = axg_register_clk_hw_input(dev, name, clkid + i); -+ ret = axg_register_clk_hw_input(dev, name); - kfree(name); - if (ret) - return ret; -@@ -759,26 +755,21 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) - if (IS_ERR(hw)) - return PTR_ERR(hw); - -- axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw; -- - /* Register optional input master clocks */ - ret = axg_register_clk_hw_inputs(dev, "mst_in", -- AUD_MST_IN_COUNT, -- AUD_CLKID_MST0); -+ AUD_MST_IN_COUNT); - if (ret) - return ret; - - /* Register optional input slave sclks */ - ret = axg_register_clk_hw_inputs(dev, "slv_sclk", -- AUD_SLV_SCLK_COUNT, -- AUD_CLKID_SLV_SCLK0); -+ AUD_SLV_SCLK_COUNT); - if (ret) - return ret; - - /* Register optional input slave lrclks */ - ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", -- AUD_SLV_LRCLK_COUNT, -- AUD_CLKID_SLV_LRCLK0); -+ AUD_SLV_LRCLK_COUNT); - if (ret) - return ret; - -diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h -index 644f0b0fddf25..9644c2ff0b3b6 100644 ---- a/drivers/clk/meson/axg-audio.h -+++ b/drivers/clk/meson/axg-audio.h -@@ -51,35 +51,6 @@ - * These indices are entirely contrived and do not map onto the hardware. - */ - --#define AUD_CLKID_PCLK 0 --#define AUD_CLKID_MST0 1 --#define AUD_CLKID_MST1 2 --#define AUD_CLKID_MST2 3 --#define AUD_CLKID_MST3 4 --#define AUD_CLKID_MST4 5 --#define AUD_CLKID_MST5 6 --#define AUD_CLKID_MST6 7 --#define AUD_CLKID_MST7 8 --#define AUD_CLKID_SLV_SCLK0 9 --#define AUD_CLKID_SLV_SCLK1 10 --#define AUD_CLKID_SLV_SCLK2 11 --#define AUD_CLKID_SLV_SCLK3 12 --#define AUD_CLKID_SLV_SCLK4 13 --#define AUD_CLKID_SLV_SCLK5 14 --#define AUD_CLKID_SLV_SCLK6 15 --#define AUD_CLKID_SLV_SCLK7 16 --#define AUD_CLKID_SLV_SCLK8 17 --#define AUD_CLKID_SLV_SCLK9 18 --#define AUD_CLKID_SLV_LRCLK0 19 --#define AUD_CLKID_SLV_LRCLK1 20 --#define AUD_CLKID_SLV_LRCLK2 21 --#define AUD_CLKID_SLV_LRCLK3 22 --#define AUD_CLKID_SLV_LRCLK4 23 --#define AUD_CLKID_SLV_LRCLK5 24 --#define AUD_CLKID_SLV_LRCLK6 25 --#define AUD_CLKID_SLV_LRCLK7 26 --#define AUD_CLKID_SLV_LRCLK8 27 --#define AUD_CLKID_SLV_LRCLK9 28 - #define AUD_CLKID_MST_A_MCLK_SEL 59 - #define AUD_CLKID_MST_B_MCLK_SEL 60 - #define AUD_CLKID_MST_C_MCLK_SEL 61 - -From 046266fc6983d305c06f8e52d5df3f60a1007858 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Fri, 29 Mar 2019 17:06:49 +0100 -Subject: [PATCH 036/249] FROMGIT: clk: meson: axg-audio: add g12a support - -The g12a audio clock controller is largely similar to the existing axg -controller, with the addition of the spdif output B and TDM pad clocks. - -This commit extends the existing axg audio clock controller driver -to work with multiple compatibles and add the g12a specific clocks - -Signed-off-by: Maxime Jourdan -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190329160649.31603-5-jbrunet@baylibre.com -(cherry picked from commit 075001385c66a00fba9810b9ecb88d644384df88 - https://github.com/BayLibre/clk-meson/ next/drivers) ---- - drivers/clk/meson/axg-audio.c | 240 +++++++++++++++++++++++++++++++++- - drivers/clk/meson/axg-audio.h | 7 +- - 2 files changed, 239 insertions(+), 8 deletions(-) - -diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c -index e8516f9c03d31..8028ff6f66107 100644 ---- a/drivers/clk/meson/axg-audio.c -+++ b/drivers/clk/meson/axg-audio.c -@@ -97,6 +97,7 @@ static AUD_PCLK_GATE(spdifin, 16); - static AUD_PCLK_GATE(spdifout, 17); - static AUD_PCLK_GATE(resample, 18); - static AUD_PCLK_GATE(power_detect, 19); -+static AUD_PCLK_GATE(spdifout_b, 21); - - /* Audio Master Clocks */ - static const char * const mst_mux_parent_names[] = { -@@ -124,6 +125,7 @@ static AUD_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); - static AUD_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); - static AUD_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); - static AUD_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -+static AUD_MST_MCLK_MUX(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); - - #define AUD_MST_DIV(_name, _reg, _flag) \ - AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ -@@ -145,6 +147,7 @@ static AUD_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); - static AUD_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); - static AUD_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); - static AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -+static AUD_MST_MCLK_DIV(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); - - #define AUD_MST_MCLK_GATE(_name, _reg) \ - AUD_GATE(_name, _reg, 31, "aud_"#_name"_div", \ -@@ -160,6 +163,7 @@ static AUD_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); - static AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); - static AUD_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); - static AUD_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -+static AUD_MST_MCLK_GATE(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); - - /* Sample Clocks */ - #define AUD_MST_SCLK_PRE_EN(_name, _reg) \ -@@ -377,6 +381,45 @@ static AUD_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); - static AUD_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); - static AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); - -+/* G12a Pad control */ -+#define AUD_TDM_PAD_CTRL(_name, _reg, _shift, _parents) \ -+ AUD_MUX(tdm_##_name, _reg, 0x7, _shift, 0, _parents, \ -+ CLK_SET_RATE_NO_REPARENT) -+ -+static const char * const mclk_pad_ctrl_parent_names[] = { -+ "aud_mst_a_mclk", "aud_mst_b_mclk", "aud_mst_c_mclk", -+ "aud_mst_d_mclk", "aud_mst_e_mclk", "aud_mst_f_mclk", -+}; -+ -+static AUD_TDM_PAD_CTRL(mclk_pad_0, AUDIO_MST_PAD_CTRL0, 0, -+ mclk_pad_ctrl_parent_names); -+static AUD_TDM_PAD_CTRL(mclk_pad_1, AUDIO_MST_PAD_CTRL0, 4, -+ mclk_pad_ctrl_parent_names); -+ -+static const char * const lrclk_pad_ctrl_parent_names[] = { -+ "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", -+ "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", -+}; -+ -+static AUD_TDM_PAD_CTRL(lrclk_pad_0, AUDIO_MST_PAD_CTRL1, 16, -+ lrclk_pad_ctrl_parent_names); -+static AUD_TDM_PAD_CTRL(lrclk_pad_1, AUDIO_MST_PAD_CTRL1, 20, -+ lrclk_pad_ctrl_parent_names); -+static AUD_TDM_PAD_CTRL(lrclk_pad_2, AUDIO_MST_PAD_CTRL1, 24, -+ lrclk_pad_ctrl_parent_names); -+ -+static const char * const sclk_pad_ctrl_parent_names[] = { -+ "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", -+ "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", -+}; -+ -+static AUD_TDM_PAD_CTRL(sclk_pad_0, AUDIO_MST_PAD_CTRL1, 0, -+ sclk_pad_ctrl_parent_names); -+static AUD_TDM_PAD_CTRL(sclk_pad_1, AUDIO_MST_PAD_CTRL1, 4, -+ sclk_pad_ctrl_parent_names); -+static AUD_TDM_PAD_CTRL(sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, -+ sclk_pad_ctrl_parent_names); -+ - /* - * Array of all clocks provided by this provider - * The input clocks of the controller will be populated at runtime -@@ -509,7 +552,156 @@ static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { - .num = NR_CLKS, - }; - --/* Convenience table to populate regmap in .probe() */ -+/* -+ * Array of all G12A clocks provided by this provider -+ * The input clocks of the controller will be populated at runtime -+ */ -+static struct clk_hw_onecell_data g12a_audio_hw_onecell_data = { -+ .hws = { -+ [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw, -+ [AUD_CLKID_PDM] = &aud_pdm.hw, -+ [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw, -+ [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw, -+ [AUD_CLKID_TDMIN_C] = &aud_tdmin_c.hw, -+ [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw, -+ [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw, -+ [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw, -+ [AUD_CLKID_TDMOUT_C] = &aud_tdmout_c.hw, -+ [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw, -+ [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw, -+ [AUD_CLKID_FRDDR_C] = &aud_frddr_c.hw, -+ [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw, -+ [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw, -+ [AUD_CLKID_TODDR_C] = &aud_toddr_c.hw, -+ [AUD_CLKID_LOOPBACK] = &aud_loopback.hw, -+ [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw, -+ [AUD_CLKID_SPDIFOUT] = &aud_spdifout.hw, -+ [AUD_CLKID_RESAMPLE] = &aud_resample.hw, -+ [AUD_CLKID_POWER_DETECT] = &aud_power_detect.hw, -+ [AUD_CLKID_SPDIFOUT_B] = &aud_spdifout_b.hw, -+ [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw, -+ [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw, -+ [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw, -+ [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw, -+ [AUD_CLKID_MST_E_MCLK_SEL] = &aud_mst_e_mclk_sel.hw, -+ [AUD_CLKID_MST_F_MCLK_SEL] = &aud_mst_f_mclk_sel.hw, -+ [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw, -+ [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw, -+ [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw, -+ [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw, -+ [AUD_CLKID_MST_E_MCLK_DIV] = &aud_mst_e_mclk_div.hw, -+ [AUD_CLKID_MST_F_MCLK_DIV] = &aud_mst_f_mclk_div.hw, -+ [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw, -+ [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw, -+ [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw, -+ [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw, -+ [AUD_CLKID_MST_E_MCLK] = &aud_mst_e_mclk.hw, -+ [AUD_CLKID_MST_F_MCLK] = &aud_mst_f_mclk.hw, -+ [AUD_CLKID_SPDIFOUT_CLK_SEL] = &aud_spdifout_clk_sel.hw, -+ [AUD_CLKID_SPDIFOUT_CLK_DIV] = &aud_spdifout_clk_div.hw, -+ [AUD_CLKID_SPDIFOUT_CLK] = &aud_spdifout_clk.hw, -+ [AUD_CLKID_SPDIFOUT_B_CLK_SEL] = &aud_spdifout_b_clk_sel.hw, -+ [AUD_CLKID_SPDIFOUT_B_CLK_DIV] = &aud_spdifout_b_clk_div.hw, -+ [AUD_CLKID_SPDIFOUT_B_CLK] = &aud_spdifout_b_clk.hw, -+ [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw, -+ [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw, -+ [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw, -+ [AUD_CLKID_PDM_DCLK_SEL] = &aud_pdm_dclk_sel.hw, -+ [AUD_CLKID_PDM_DCLK_DIV] = &aud_pdm_dclk_div.hw, -+ [AUD_CLKID_PDM_DCLK] = &aud_pdm_dclk.hw, -+ [AUD_CLKID_PDM_SYSCLK_SEL] = &aud_pdm_sysclk_sel.hw, -+ [AUD_CLKID_PDM_SYSCLK_DIV] = &aud_pdm_sysclk_div.hw, -+ [AUD_CLKID_PDM_SYSCLK] = &aud_pdm_sysclk.hw, -+ [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw, -+ [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw, -+ [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw, -+ [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw, -+ [AUD_CLKID_MST_E_SCLK_PRE_EN] = &aud_mst_e_sclk_pre_en.hw, -+ [AUD_CLKID_MST_F_SCLK_PRE_EN] = &aud_mst_f_sclk_pre_en.hw, -+ [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw, -+ [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw, -+ [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw, -+ [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw, -+ [AUD_CLKID_MST_E_SCLK_DIV] = &aud_mst_e_sclk_div.hw, -+ [AUD_CLKID_MST_F_SCLK_DIV] = &aud_mst_f_sclk_div.hw, -+ [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw, -+ [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw, -+ [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw, -+ [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw, -+ [AUD_CLKID_MST_E_SCLK_POST_EN] = &aud_mst_e_sclk_post_en.hw, -+ [AUD_CLKID_MST_F_SCLK_POST_EN] = &aud_mst_f_sclk_post_en.hw, -+ [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw, -+ [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw, -+ [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw, -+ [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw, -+ [AUD_CLKID_MST_E_SCLK] = &aud_mst_e_sclk.hw, -+ [AUD_CLKID_MST_F_SCLK] = &aud_mst_f_sclk.hw, -+ [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw, -+ [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw, -+ [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw, -+ [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw, -+ [AUD_CLKID_MST_E_LRCLK_DIV] = &aud_mst_e_lrclk_div.hw, -+ [AUD_CLKID_MST_F_LRCLK_DIV] = &aud_mst_f_lrclk_div.hw, -+ [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw, -+ [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw, -+ [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw, -+ [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw, -+ [AUD_CLKID_MST_E_LRCLK] = &aud_mst_e_lrclk.hw, -+ [AUD_CLKID_MST_F_LRCLK] = &aud_mst_f_lrclk.hw, -+ [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_C_SCLK_SEL] = &aud_tdmin_c_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &aud_tdmout_c_sclk_sel.hw, -+ [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &aud_tdmin_c_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &aud_tdmout_c_sclk_pre_en.hw, -+ [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &aud_tdmin_c_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &aud_tdmout_c_sclk_post_en.hw, -+ [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw, -+ [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw, -+ [AUD_CLKID_TDMIN_C_SCLK] = &aud_tdmin_c_sclk.hw, -+ [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw, -+ [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw, -+ [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw, -+ [AUD_CLKID_TDMOUT_C_SCLK] = &aud_tdmout_c_sclk.hw, -+ [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw, -+ [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw, -+ [AUD_CLKID_TDMIN_C_LRCLK] = &aud_tdmin_c_lrclk.hw, -+ [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw, -+ [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw, -+ [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw, -+ [AUD_CLKID_TDMOUT_C_LRCLK] = &aud_tdmout_c_lrclk.hw, -+ [AUD_CLKID_TDM_MCLK_PAD0] = &aud_tdm_mclk_pad_0.hw, -+ [AUD_CLKID_TDM_MCLK_PAD1] = &aud_tdm_mclk_pad_1.hw, -+ [AUD_CLKID_TDM_LRCLK_PAD0] = &aud_tdm_lrclk_pad_0.hw, -+ [AUD_CLKID_TDM_LRCLK_PAD1] = &aud_tdm_lrclk_pad_1.hw, -+ [AUD_CLKID_TDM_LRCLK_PAD2] = &aud_tdm_lrclk_pad_2.hw, -+ [AUD_CLKID_TDM_SCLK_PAD0] = &aud_tdm_sclk_pad_0.hw, -+ [AUD_CLKID_TDM_SCLK_PAD1] = &aud_tdm_sclk_pad_1.hw, -+ [AUD_CLKID_TDM_SCLK_PAD2] = &aud_tdm_sclk_pad_2.hw, -+ [NR_CLKS] = NULL, -+ }, -+ .num = NR_CLKS, -+}; -+ -+/* Convenience table to populate regmap in .probe() -+ * Note that this table is shared between both AXG and G12A, -+ * with spdifout_b clocks being exclusive to G12A. Since those -+ * clocks are not declared within the AXG onecell table, we do not -+ * feel the need to have separate AXG/G12A regmap tables. -+ */ - static struct clk_regmap *const aud_clk_regmaps[] = { - &aud_ddr_arb, - &aud_pdm, -@@ -531,6 +723,7 @@ static struct clk_regmap *const aud_clk_regmaps[] = { - &aud_spdifout, - &aud_resample, - &aud_power_detect, -+ &aud_spdifout_b, - &aud_mst_a_mclk_sel, - &aud_mst_b_mclk_sel, - &aud_mst_c_mclk_sel, -@@ -632,6 +825,17 @@ static struct clk_regmap *const aud_clk_regmaps[] = { - &aud_tdmout_a_lrclk, - &aud_tdmout_b_lrclk, - &aud_tdmout_c_lrclk, -+ &aud_spdifout_b_clk_sel, -+ &aud_spdifout_b_clk_div, -+ &aud_spdifout_b_clk, -+ &aud_tdm_mclk_pad_0, -+ &aud_tdm_mclk_pad_1, -+ &aud_tdm_lrclk_pad_0, -+ &aud_tdm_lrclk_pad_1, -+ &aud_tdm_lrclk_pad_2, -+ &aud_tdm_sclk_pad_0, -+ &aud_tdm_sclk_pad_1, -+ &aud_tdm_sclk_pad_2, - }; - - static int devm_clk_get_enable(struct device *dev, char *id) -@@ -719,15 +923,24 @@ static const struct regmap_config axg_audio_regmap_cfg = { - .max_register = AUDIO_CLK_PDMIN_CTRL1, - }; - -+struct audioclk_data { -+ struct clk_hw_onecell_data *hw_onecell_data; -+}; -+ - static int axg_audio_clkc_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -+ const struct audioclk_data *data; - struct regmap *map; - struct resource *res; - void __iomem *regs; - struct clk_hw *hw; - int ret, i; - -+ data = of_device_get_match_data(dev); -+ if (!data) -+ return -EINVAL; -+ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) -@@ -778,8 +991,8 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) - aud_clk_regmaps[i]->map = map; - - /* Take care to skip the registered input clocks */ -- for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) { -- hw = axg_audio_hw_onecell_data.hws[i]; -+ for (i = AUD_CLKID_DDR_ARB; i < data->hw_onecell_data->num; i++) { -+ hw = data->hw_onecell_data->hws[i]; - /* array might be sparse */ - if (!hw) - continue; -@@ -793,12 +1006,25 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) - } - - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, -- &axg_audio_hw_onecell_data); -+ data->hw_onecell_data); - } - -+static const struct audioclk_data axg_audioclk_data = { -+ .hw_onecell_data = &axg_audio_hw_onecell_data, -+}; -+ -+static const struct audioclk_data g12a_audioclk_data = { -+ .hw_onecell_data = &g12a_audio_hw_onecell_data, -+}; -+ - static const struct of_device_id clkc_match_table[] = { -- { .compatible = "amlogic,axg-audio-clkc" }, -- {} -+ { -+ .compatible = "amlogic,axg-audio-clkc", -+ .data = &axg_audioclk_data -+ }, { -+ .compatible = "amlogic,g12a-audio-clkc", -+ .data = &g12a_audioclk_data -+ }, {} - }; - MODULE_DEVICE_TABLE(of, clkc_match_table); - -@@ -811,6 +1037,6 @@ static struct platform_driver axg_audio_driver = { - }; - module_platform_driver(axg_audio_driver); - --MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver"); -+MODULE_DESCRIPTION("Amlogic AXG/G12A Audio Clock driver"); - MODULE_AUTHOR("Jerome Brunet "); - MODULE_LICENSE("GPL v2"); -diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h -index 9644c2ff0b3b6..5d972d55d6c74 100644 ---- a/drivers/clk/meson/axg-audio.h -+++ b/drivers/clk/meson/axg-audio.h -@@ -20,6 +20,8 @@ - #define AUDIO_MCLK_D_CTRL 0x010 - #define AUDIO_MCLK_E_CTRL 0x014 - #define AUDIO_MCLK_F_CTRL 0x018 -+#define AUDIO_MST_PAD_CTRL0 0x01c -+#define AUDIO_MST_PAD_CTRL1 0x020 - #define AUDIO_MST_A_SCLK_CTRL0 0x040 - #define AUDIO_MST_A_SCLK_CTRL1 0x044 - #define AUDIO_MST_B_SCLK_CTRL0 0x048 -@@ -45,6 +47,7 @@ - #define AUDIO_CLK_LOCKER_CTRL 0x0A8 - #define AUDIO_CLK_PDMIN_CTRL0 0x0AC - #define AUDIO_CLK_PDMIN_CTRL1 0x0B0 -+#define AUDIO_CLK_SPDIFOUT_B_CTRL 0x0B4 - - /* - * CLKID index values -@@ -109,10 +112,12 @@ - #define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 148 - #define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 149 - #define AUD_CLKID_TDMOUT_C_SCLK_POST_EN 150 -+#define AUD_CLKID_SPDIFOUT_B_CLK_SEL 153 -+#define AUD_CLKID_SPDIFOUT_B_CLK_DIV 154 - - /* include the CLKIDs which are part of the DT bindings */ - #include - --#define NR_CLKS 151 -+#define NR_CLKS 163 - - #endif /*__AXG_AUDIO_CLKC_H */ - -From ef3250f3d0571d3266e40989d4a399e6395580cb Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Mon, 11 Mar 2019 11:51:44 +0100 -Subject: [PATCH 037/249] FROMGIT: drm/meson: exclusively use the canvas - provider module - -Now that the DMC register range is no longer in the bindings, remove any -mention towards it and exclusively use the meson-canvas module. - -Signed-off-by: Maxime Jourdan -Acked-by: Neil Armstrong -Signed-off-by: Neil Armstrong -Link: https://patchwork.freedesktop.org/patch/msgid/20190311105144.7276-3-mjourdan@baylibre.com -(cherry picked from commit 2bf6b5b0e374fccda724ca208e8d5433b869246a - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/Makefile | 2 +- - drivers/gpu/drm/meson/meson_canvas.c | 73 ----------------------- - drivers/gpu/drm/meson/meson_canvas.h | 51 ---------------- - drivers/gpu/drm/meson/meson_crtc.c | 84 ++++++++------------------- - drivers/gpu/drm/meson/meson_drv.c | 68 ++++++++-------------- - drivers/gpu/drm/meson/meson_drv.h | 1 - - drivers/gpu/drm/meson/meson_overlay.c | 8 --- - drivers/gpu/drm/meson/meson_plane.c | 6 +- - drivers/gpu/drm/meson/meson_viu.c | 1 - - 9 files changed, 51 insertions(+), 243 deletions(-) - delete mode 100644 drivers/gpu/drm/meson/meson_canvas.c - delete mode 100644 drivers/gpu/drm/meson/meson_canvas.h - -diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile -index 7709f2fbb9f77..d4ea82fc493b6 100644 ---- a/drivers/gpu/drm/meson/Makefile -+++ b/drivers/gpu/drm/meson/Makefile -@@ -1,5 +1,5 @@ - meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o --meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_overlay.o -+meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o - - obj-$(CONFIG_DRM_MESON) += meson-drm.o - obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o -diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c -deleted file mode 100644 -index 5de11aa7c775e..0000000000000 ---- a/drivers/gpu/drm/meson/meson_canvas.c -+++ /dev/null -@@ -1,73 +0,0 @@ --/* -- * Copyright (C) 2016 BayLibre, SAS -- * Author: Neil Armstrong -- * Copyright (C) 2015 Amlogic, Inc. All rights reserved. -- * Copyright (C) 2014 Endless Mobile -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License as -- * published by the Free Software Foundation; either version 2 of the -- * License, or (at your option) any later version. -- * -- * 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. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, see . -- */ -- --#include --#include --#include "meson_drv.h" --#include "meson_canvas.h" --#include "meson_registers.h" -- --/** -- * DOC: Canvas -- * -- * CANVAS is a memory zone where physical memory frames information -- * are stored for the VIU to scanout. -- */ -- --/* DMC Registers */ --#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */ --#define CANVAS_WIDTH_LBIT 29 --#define CANVAS_WIDTH_LWID 3 --#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */ --#define CANVAS_WIDTH_HBIT 0 --#define CANVAS_HEIGHT_BIT 9 --#define CANVAS_BLKMODE_BIT 24 --#define CANVAS_ENDIAN_BIT 26 --#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */ --#define CANVAS_LUT_WR_EN (0x2 << 8) --#define CANVAS_LUT_RD_EN (0x1 << 8) -- --void meson_canvas_setup(struct meson_drm *priv, -- uint32_t canvas_index, uint32_t addr, -- uint32_t stride, uint32_t height, -- unsigned int wrap, -- unsigned int blkmode, -- unsigned int endian) --{ -- unsigned int val; -- -- regmap_write(priv->dmc, DMC_CAV_LUT_DATAL, -- (((addr + 7) >> 3)) | -- (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT)); -- -- regmap_write(priv->dmc, DMC_CAV_LUT_DATAH, -- ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) << -- CANVAS_WIDTH_HBIT) | -- (height << CANVAS_HEIGHT_BIT) | -- (wrap << 22) | -- (blkmode << CANVAS_BLKMODE_BIT) | -- (endian << CANVAS_ENDIAN_BIT)); -- -- regmap_write(priv->dmc, DMC_CAV_LUT_ADDR, -- CANVAS_LUT_WR_EN | canvas_index); -- -- /* Force a read-back to make sure everything is flushed. */ -- regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val); --} -diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h -deleted file mode 100644 -index 85dbf26e2826a..0000000000000 ---- a/drivers/gpu/drm/meson/meson_canvas.h -+++ /dev/null -@@ -1,51 +0,0 @@ --/* -- * Copyright (C) 2016 BayLibre, SAS -- * Author: Neil Armstrong -- * Copyright (C) 2014 Endless Mobile -- * -- * This program is free software; you can redistribute it and/or -- * modify it under the terms of the GNU General Public License as -- * published by the Free Software Foundation; either version 2 of the -- * License, or (at your option) any later version. -- * -- * 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. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, see . -- */ -- --/* Canvas LUT Memory */ -- --#ifndef __MESON_CANVAS_H --#define __MESON_CANVAS_H -- --#define MESON_CANVAS_ID_OSD1 0x4e --#define MESON_CANVAS_ID_VD1_0 0x60 --#define MESON_CANVAS_ID_VD1_1 0x61 --#define MESON_CANVAS_ID_VD1_2 0x62 -- --/* Canvas configuration. */ --#define MESON_CANVAS_WRAP_NONE 0x00 --#define MESON_CANVAS_WRAP_X 0x01 --#define MESON_CANVAS_WRAP_Y 0x02 -- --#define MESON_CANVAS_BLKMODE_LINEAR 0x00 --#define MESON_CANVAS_BLKMODE_32x32 0x01 --#define MESON_CANVAS_BLKMODE_64x64 0x02 -- --#define MESON_CANVAS_ENDIAN_SWAP16 0x1 --#define MESON_CANVAS_ENDIAN_SWAP32 0x3 --#define MESON_CANVAS_ENDIAN_SWAP64 0x7 --#define MESON_CANVAS_ENDIAN_SWAP128 0xf -- --void meson_canvas_setup(struct meson_drm *priv, -- uint32_t canvas_index, uint32_t addr, -- uint32_t stride, uint32_t height, -- unsigned int wrap, -- unsigned int blkmode, -- unsigned int endian); -- --#endif /* __MESON_CANVAS_H */ -diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c -index 43e29984f8b17..6d9311e254efc 100644 ---- a/drivers/gpu/drm/meson/meson_crtc.c -+++ b/drivers/gpu/drm/meson/meson_crtc.c -@@ -37,7 +37,6 @@ - #include "meson_venc.h" - #include "meson_vpp.h" - #include "meson_viu.h" --#include "meson_canvas.h" - #include "meson_registers.h" - - /* CRTC definition */ -@@ -214,13 +213,7 @@ void meson_crtc_irq(struct meson_drm *priv) - writel_relaxed(priv->viu.osd_sc_v_ctrl0, - priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); - -- if (priv->canvas) -- meson_canvas_config(priv->canvas, priv->canvas_id_osd1, -- priv->viu.osd1_addr, priv->viu.osd1_stride, -- priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, -- MESON_CANVAS_BLKMODE_LINEAR, 0); -- else -- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, -+ meson_canvas_config(priv->canvas, priv->canvas_id_osd1, - priv->viu.osd1_addr, priv->viu.osd1_stride, - priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, 0); -@@ -237,61 +230,34 @@ void meson_crtc_irq(struct meson_drm *priv) - - switch (priv->viu.vd1_planes) { - case 3: -- if (priv->canvas) -- meson_canvas_config(priv->canvas, -- priv->canvas_id_vd1_2, -- priv->viu.vd1_addr2, -- priv->viu.vd1_stride2, -- priv->viu.vd1_height2, -- MESON_CANVAS_WRAP_NONE, -- MESON_CANVAS_BLKMODE_LINEAR, -- MESON_CANVAS_ENDIAN_SWAP64); -- else -- meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_2, -- priv->viu.vd1_addr2, -- priv->viu.vd1_stride2, -- priv->viu.vd1_height2, -- MESON_CANVAS_WRAP_NONE, -- MESON_CANVAS_BLKMODE_LINEAR, -- MESON_CANVAS_ENDIAN_SWAP64); -+ meson_canvas_config(priv->canvas, -+ priv->canvas_id_vd1_2, -+ priv->viu.vd1_addr2, -+ priv->viu.vd1_stride2, -+ priv->viu.vd1_height2, -+ MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); - /* fallthrough */ - case 2: -- if (priv->canvas) -- meson_canvas_config(priv->canvas, -- priv->canvas_id_vd1_1, -- priv->viu.vd1_addr1, -- priv->viu.vd1_stride1, -- priv->viu.vd1_height1, -- MESON_CANVAS_WRAP_NONE, -- MESON_CANVAS_BLKMODE_LINEAR, -- MESON_CANVAS_ENDIAN_SWAP64); -- else -- meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_1, -- priv->viu.vd1_addr2, -- priv->viu.vd1_stride2, -- priv->viu.vd1_height2, -- MESON_CANVAS_WRAP_NONE, -- MESON_CANVAS_BLKMODE_LINEAR, -- MESON_CANVAS_ENDIAN_SWAP64); -+ meson_canvas_config(priv->canvas, -+ priv->canvas_id_vd1_1, -+ priv->viu.vd1_addr1, -+ priv->viu.vd1_stride1, -+ priv->viu.vd1_height1, -+ MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); - /* fallthrough */ - case 1: -- if (priv->canvas) -- meson_canvas_config(priv->canvas, -- priv->canvas_id_vd1_0, -- priv->viu.vd1_addr0, -- priv->viu.vd1_stride0, -- priv->viu.vd1_height0, -- MESON_CANVAS_WRAP_NONE, -- MESON_CANVAS_BLKMODE_LINEAR, -- MESON_CANVAS_ENDIAN_SWAP64); -- else -- meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0, -- priv->viu.vd1_addr2, -- priv->viu.vd1_stride2, -- priv->viu.vd1_height2, -- MESON_CANVAS_WRAP_NONE, -- MESON_CANVAS_BLKMODE_LINEAR, -- MESON_CANVAS_ENDIAN_SWAP64); -+ meson_canvas_config(priv->canvas, -+ priv->canvas_id_vd1_0, -+ priv->viu.vd1_addr0, -+ priv->viu.vd1_stride0, -+ priv->viu.vd1_height0, -+ MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); - }; - - writel_relaxed(priv->viu.vd1_if0_gen_reg, -diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c -index 8a4ebcb6405ce..079d22299d789 100644 ---- a/drivers/gpu/drm/meson/meson_drv.c -+++ b/drivers/gpu/drm/meson/meson_drv.c -@@ -48,7 +48,6 @@ - #include "meson_vpp.h" - #include "meson_viu.h" - #include "meson_venc.h" --#include "meson_canvas.h" - #include "meson_registers.h" - - #define DRIVER_NAME "meson" -@@ -231,50 +230,31 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) - } - - priv->canvas = meson_canvas_get(dev); -- if (!IS_ERR(priv->canvas)) { -- ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); -- if (ret) -- goto free_drm; -- ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); -- if (ret) { -- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); -- goto free_drm; -- } -- ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); -- if (ret) { -- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); -- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); -- goto free_drm; -- } -- ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); -- if (ret) { -- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); -- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); -- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); -- goto free_drm; -- } -- } else { -- priv->canvas = NULL; -- -- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); -- if (!res) { -- ret = -EINVAL; -- goto free_drm; -- } -- /* Simply ioremap since it may be a shared register zone */ -- regs = devm_ioremap(dev, res->start, resource_size(res)); -- if (!regs) { -- ret = -EADDRNOTAVAIL; -- goto free_drm; -- } -+ if (IS_ERR(priv->canvas)) { -+ ret = PTR_ERR(priv->canvas); -+ goto free_drm; -+ } - -- priv->dmc = devm_regmap_init_mmio(dev, regs, -- &meson_regmap_config); -- if (IS_ERR(priv->dmc)) { -- dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); -- ret = PTR_ERR(priv->dmc); -- goto free_drm; -- } -+ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); -+ if (ret) -+ goto free_drm; -+ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); -+ if (ret) { -+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1); -+ goto free_drm; -+ } -+ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); -+ if (ret) { -+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1); -+ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); -+ goto free_drm; -+ } -+ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); -+ if (ret) { -+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1); -+ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); -+ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); -+ goto free_drm; - } - - priv->vsync_irq = platform_get_irq(pdev, 0); -diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h -index 4dccf4cd042a5..214a7cb18ce27 100644 ---- a/drivers/gpu/drm/meson/meson_drv.h -+++ b/drivers/gpu/drm/meson/meson_drv.h -@@ -29,7 +29,6 @@ struct meson_drm { - struct device *dev; - void __iomem *io_base; - struct regmap *hhi; -- struct regmap *dmc; - int vsync_irq; - - struct meson_canvas *canvas; -diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c -index 691a9fd16b366..b54a22e483b92 100644 ---- a/drivers/gpu/drm/meson/meson_overlay.c -+++ b/drivers/gpu/drm/meson/meson_overlay.c -@@ -22,7 +22,6 @@ - #include "meson_overlay.h" - #include "meson_vpp.h" - #include "meson_viu.h" --#include "meson_canvas.h" - #include "meson_registers.h" - - /* VD1_IF0_GEN_REG */ -@@ -350,13 +349,6 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, - - DRM_DEBUG_DRIVER("\n"); - -- /* Fallback is canvas provider is not available */ -- if (!priv->canvas) { -- priv->canvas_id_vd1_0 = MESON_CANVAS_ID_VD1_0; -- priv->canvas_id_vd1_1 = MESON_CANVAS_ID_VD1_1; -- priv->canvas_id_vd1_2 = MESON_CANVAS_ID_VD1_2; -- } -- - interlace_mode = state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE; - - spin_lock_irqsave(&priv->drm->event_lock, flags); -diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c -index 6119a02242788..b7786218cb10a 100644 ---- a/drivers/gpu/drm/meson/meson_plane.c -+++ b/drivers/gpu/drm/meson/meson_plane.c -@@ -38,7 +38,6 @@ - #include "meson_plane.h" - #include "meson_vpp.h" - #include "meson_viu.h" --#include "meson_canvas.h" - #include "meson_registers.h" - - /* OSD_SCI_WH_M1 */ -@@ -148,10 +147,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, - (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | - OSD_BLK0_ENABLE; - -- if (priv->canvas) -- canvas_id_osd1 = priv->canvas_id_osd1; -- else -- canvas_id_osd1 = MESON_CANVAS_ID_OSD1; -+ canvas_id_osd1 = priv->canvas_id_osd1; - - /* Set up BLK0 to point to the right canvas */ - priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) | -diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c -index e46e05f50bad7..ac0f3687e09a3 100644 ---- a/drivers/gpu/drm/meson/meson_viu.c -+++ b/drivers/gpu/drm/meson/meson_viu.c -@@ -25,7 +25,6 @@ - #include "meson_viu.h" - #include "meson_vpp.h" - #include "meson_venc.h" --#include "meson_canvas.h" - #include "meson_registers.h" - - /** - -From d3f3465466dd0ff8b456d5202443dc27ea2d8e66 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 1 Apr 2019 10:09:49 +0200 -Subject: [PATCH 038/249] FROMGIT: dt-bindings: gpu: add bindings for the ARM - Mali Bifrost GPU - -Add the bindings for the Bifrost family of ARM Mali GPUs. - -The Bifrost GPU architecture is similar to the Midgard family, -but with a different Shader Core & Execution Engine structures. - -Bindings are based on the Midgard family bindings, but the inner -architectural changes makes it a separate family needing separate -bindings. - -The Bifrost GPUs are present in a number of recent SoCs, like the -Amlogic G12A Family, and many other vendors. -The Amlogic vendor specific compatible is added to handle the -specific IP integration differences and dependencies. - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring -[narmstrong: fixed small typo in compatible description] -Link: https://patchwork.freedesktop.org/patch/msgid/20190401080949.14550-1-narmstrong@baylibre.com -(cherry picked from commit ebc41018d84bc526e9f873a80228aba24c9f9189 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - .../bindings/gpu/arm,mali-bifrost.txt | 92 +++++++++++++++++++ - 1 file changed, 92 insertions(+) - create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt - -diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt -new file mode 100644 -index 0000000000000..b8be9dbc68b4c ---- /dev/null -+++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt -@@ -0,0 +1,92 @@ -+ARM Mali Bifrost GPU -+==================== -+ -+Required properties: -+ -+- compatible : -+ * Since Mali Bifrost GPU model/revision is fully discoverable by reading -+ some determined registers, must contain the following: -+ + "arm,mali-bifrost" -+ * which must be preceded by one of the following vendor specifics: -+ + "amlogic,meson-g12a-mali" -+ -+- reg : Physical base address of the device and length of the register area. -+ -+- interrupts : Contains the three IRQ lines required by Mali Bifrost devices, -+ in the following defined order. -+ -+- interrupt-names : Contains the names of IRQ resources in this exact defined -+ order: "job", "mmu", "gpu". -+ -+Optional properties: -+ -+- clocks : Phandle to clock for the Mali Bifrost device. -+ -+- mali-supply : Phandle to regulator for the Mali device. Refer to -+ Documentation/devicetree/bindings/regulator/regulator.txt for details. -+ -+- operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt -+ for details. -+ -+- resets : Phandle of the GPU reset line. -+ -+Vendor-specific bindings -+------------------------ -+ -+The Mali GPU is integrated very differently from one SoC to -+another. In order to accommodate those differences, you have the option -+to specify one more vendor-specific compatible, among: -+ -+- "amlogic,meson-g12a-mali" -+ Required properties: -+ - resets : Should contain phandles of : -+ + GPU reset line -+ + GPU APB glue reset line -+ -+Example for a Mali-G31: -+ -+gpu@ffa30000 { -+ compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; -+ reg = <0xffe40000 0x10000>; -+ interrupts = , -+ , -+ ; -+ interrupt-names = "job", "mmu", "gpu"; -+ clocks = <&clk CLKID_MALI>; -+ mali-supply = <&vdd_gpu>; -+ operating-points-v2 = <&gpu_opp_table>; -+ resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; -+}; -+ -+gpu_opp_table: opp_table0 { -+ compatible = "operating-points-v2"; -+ -+ opp@533000000 { -+ opp-hz = /bits/ 64 <533000000>; -+ opp-microvolt = <1250000>; -+ }; -+ opp@450000000 { -+ opp-hz = /bits/ 64 <450000000>; -+ opp-microvolt = <1150000>; -+ }; -+ opp@400000000 { -+ opp-hz = /bits/ 64 <400000000>; -+ opp-microvolt = <1125000>; -+ }; -+ opp@350000000 { -+ opp-hz = /bits/ 64 <350000000>; -+ opp-microvolt = <1075000>; -+ }; -+ opp@266000000 { -+ opp-hz = /bits/ 64 <266000000>; -+ opp-microvolt = <1025000>; -+ }; -+ opp@160000000 { -+ opp-hz = /bits/ 64 <160000000>; -+ opp-microvolt = <925000>; -+ }; -+ opp@100000000 { -+ opp-hz = /bits/ 64 <100000000>; -+ opp-microvolt = <912500>; -+ }; -+}; - -From 186dc507a63f4d775bd989481bb231609b3970cb Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 13 Mar 2019 15:10:28 +0100 -Subject: [PATCH 039/249] FROMGIT: dt-bindings: display: amlogic, meson-vpu: - Add G12A compatible and ports - -The Amlogic G12A VPU is very similar to the Amlogic GXM VPU but with : -- an enhanced plane blender, with up to 3 OSD planes -- support for AFBC 1.2 decoder (for Bifrost GPU) -- support display mode up to 4k60@75Hz - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring -Link: https://patchwork.freedesktop.org/patch/msgid/20190313141030.5958-2-narmstrong@baylibre.com -(cherry picked from commit 71bfbaa47b6ddf267ee383350f96cf3d3401bdc5 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - .../devicetree/bindings/display/amlogic,meson-vpu.txt | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt -index c65fd7a7467c0..8041283a4cafa 100644 ---- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt -+++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt -@@ -57,6 +57,7 @@ Required properties: - - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" - - GXM (S912) : "amlogic,meson-gxm-vpu" - followed by the common "amlogic,meson-gx-vpu" -+ - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-vpu" - - reg: base address and size of he following memory-mapped regions : - - vpu - - hhi -@@ -84,6 +85,9 @@ corresponding to each VPU output. - S905X (GXL) CVBS VDAC HDMI-TX - S905D (GXL) CVBS VDAC HDMI-TX - S912 (GXM) CVBS VDAC HDMI-TX -+ S905X2 (G12A) CVBS VDAC HDMI-TX -+ S905Y2 (G12A) CVBS VDAC HDMI-TX -+ S905D2 (G12A) CVBS VDAC HDMI-TX - - Example: - - -From 361720b6086f2f6030ed1847210ed8fb6a163b34 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 13 Mar 2019 15:10:29 +0100 -Subject: [PATCH 040/249] FROMGIT: dt-bindings: display: amlogic, - meson-dw-hdmi: Add G12A compatible and ports - -The Amlogic G12A SoC has a slighly modified DW-HDMI Glue with -support for HDMI 2.1 and a different DW-HDMI register access. - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring -Link: https://patchwork.freedesktop.org/patch/msgid/20190313141030.5958-3-narmstrong@baylibre.com -(cherry picked from commit 6c28dca669c6ee3377a9e52ed9432c0158d43ed6 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - .../devicetree/bindings/display/amlogic,meson-dw-hdmi.txt | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt -index bf4a18047309a..3a50a7862cf3f 100644 ---- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt -+++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt -@@ -37,6 +37,7 @@ Required properties: - - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" - - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" - followed by the common "amlogic,meson-gx-dw-hdmi" -+ - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-dw-hdmi" - - reg: Physical base address and length of the controller's registers. - - interrupts: The HDMI interrupt number - - clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, -@@ -66,6 +67,9 @@ corresponding to each HDMI output and input. - S905X (GXL) VENC Input TMDS Output - S905D (GXL) VENC Input TMDS Output - S912 (GXM) VENC Input TMDS Output -+ S905X2 (G12A) VENC Input TMDS Output -+ S905Y2 (G12A) VENC Input TMDS Output -+ S905D2 (G12A) VENC Input TMDS Output - - Example: - - -From be774f8725e8e5fdf9608cdcf78448afa6b2f418 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:14 +0100 -Subject: [PATCH 041/249] FROMGIT: drm/meson: Switch PLL to 5.94GHz base for - 297Mhz pixel clock - -On Amlogic G12A SoC, the 2,97GHz PLL frequency is not stable enough -to provide a correct 297MHz pixel clock, so switch the PLL base -frequency with a /2 OD when the 297MHz pixel clock is requested. - -This solves the issue on G12A and also works fine on GXBB, GXL & GXM. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-2-narmstrong@baylibre.com -(cherry picked from commit 61af6e22ec265849133bdfc4058bf0f1b28c5c24 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_vclk.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c -index f6ba35a405f8d..c15a5a5df6331 100644 ---- a/drivers/gpu/drm/meson/meson_vclk.c -+++ b/drivers/gpu/drm/meson/meson_vclk.c -@@ -396,8 +396,8 @@ struct meson_vclk_params { - }, - [MESON_VCLK_HDMI_297000] = { - .pixel_freq = 297000, -- .pll_base_freq = 2970000, -- .pll_od1 = 1, -+ .pll_base_freq = 5940000, -+ .pll_od1 = 2, - .pll_od2 = 1, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - -From 7f4fa153c248e0f05b4de87c02abf9779ed1261d Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:15 +0100 -Subject: [PATCH 042/249] FROMGIT: drm/meson: Add registers for G12A SoC - -This patch adds the new VPU registers added since the -Amlogic GXM SoCs. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-3-narmstrong@baylibre.com -(cherry picked from commit b93a66faeea9ddf3dd00c51af0f13a65d3c18cd1 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_registers.h | 247 ++++++++++++++++++++++++ - 1 file changed, 247 insertions(+) - -diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h -index 5c7e02c703bc7..cfaf90501bb17 100644 ---- a/drivers/gpu/drm/meson/meson_registers.h -+++ b/drivers/gpu/drm/meson/meson_registers.h -@@ -216,6 +216,29 @@ - #define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b - #define VIU_OSD2_TEST_RDDATA 0x1a4c - #define VIU_OSD2_PROT_CTRL 0x1a4e -+#define VIU_OSD2_MALI_UNPACK_CTRL 0x1abd -+#define VIU_OSD2_DIMM_CTRL 0x1acf -+ -+#define VIU_OSD3_CTRL_STAT 0x3d80 -+#define VIU_OSD3_CTRL_STAT2 0x3d81 -+#define VIU_OSD3_COLOR_ADDR 0x3d82 -+#define VIU_OSD3_COLOR 0x3d83 -+#define VIU_OSD3_TCOLOR_AG0 0x3d84 -+#define VIU_OSD3_TCOLOR_AG1 0x3d85 -+#define VIU_OSD3_TCOLOR_AG2 0x3d86 -+#define VIU_OSD3_TCOLOR_AG3 0x3d87 -+#define VIU_OSD3_BLK0_CFG_W0 0x3d88 -+#define VIU_OSD3_BLK0_CFG_W1 0x3d8c -+#define VIU_OSD3_BLK0_CFG_W2 0x3d90 -+#define VIU_OSD3_BLK0_CFG_W3 0x3d94 -+#define VIU_OSD3_BLK0_CFG_W4 0x3d98 -+#define VIU_OSD3_BLK1_CFG_W4 0x3d99 -+#define VIU_OSD3_BLK2_CFG_W4 0x3d9a -+#define VIU_OSD3_FIFO_CTRL_STAT 0x3d9c -+#define VIU_OSD3_TEST_RDDATA 0x3d9d -+#define VIU_OSD3_PROT_CTRL 0x3d9e -+#define VIU_OSD3_MALI_UNPACK_CTRL 0x3d9f -+#define VIU_OSD3_DIMM_CTRL 0x3da0 - - #define VD1_IF0_GEN_REG 0x1a50 - #define VD1_IF0_CANVAS0 0x1a51 -@@ -287,6 +310,27 @@ - #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e - #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f - #define VD1_IF0_GEN_REG3 0x1aa7 -+ -+#define VIU_OSD_BLENDO_H_START_END 0x1aa9 -+#define VIU_OSD_BLENDO_V_START_END 0x1aaa -+#define VIU_OSD_BLEND_GEN_CTRL0 0x1aab -+#define VIU_OSD_BLEND_GEN_CTRL1 0x1aac -+#define VIU_OSD_BLEND_DUMMY_DATA 0x1aad -+#define VIU_OSD_BLEND_CURRENT_XY 0x1aae -+ -+#define VIU_OSD2_MATRIX_CTRL 0x1ab0 -+#define VIU_OSD2_MATRIX_COEF00_01 0x1ab1 -+#define VIU_OSD2_MATRIX_COEF02_10 0x1ab2 -+#define VIU_OSD2_MATRIX_COEF11_12 0x1ab3 -+#define VIU_OSD2_MATRIX_COEF20_21 0x1ab4 -+#define VIU_OSD2_MATRIX_COEF22 0x1ab5 -+#define VIU_OSD2_MATRIX_OFFSET0_1 0x1ab6 -+#define VIU_OSD2_MATRIX_OFFSET2 0x1ab7 -+#define VIU_OSD2_MATRIX_PRE_OFFSET0_1 0x1ab8 -+#define VIU_OSD2_MATRIX_PRE_OFFSET2 0x1ab9 -+#define VIU_OSD2_MATRIX_PROBE_COLOR 0x1aba -+#define VIU_OSD2_MATRIX_HL_COLOR 0x1abb -+#define VIU_OSD2_MATRIX_PROBE_POS 0x1abc - #define VIU_OSD1_EOTF_CTL 0x1ad4 - #define VIU_OSD1_EOTF_COEF00_01 0x1ad5 - #define VIU_OSD1_EOTF_COEF02_10 0x1ad6 -@@ -481,6 +525,82 @@ - #define VPP_OSD_SCALE_COEF 0x1dcd - #define VPP_INT_LINE_NUM 0x1dce - -+#define VPP_WRAP_OSD1_MATRIX_COEF00_01 0x3d60 -+#define VPP_WRAP_OSD1_MATRIX_COEF02_10 0x3d61 -+#define VPP_WRAP_OSD1_MATRIX_COEF11_12 0x3d62 -+#define VPP_WRAP_OSD1_MATRIX_COEF20_21 0x3d63 -+#define VPP_WRAP_OSD1_MATRIX_COEF22 0x3d64 -+#define VPP_WRAP_OSD1_MATRIX_COEF13_14 0x3d65 -+#define VPP_WRAP_OSD1_MATRIX_COEF23_24 0x3d66 -+#define VPP_WRAP_OSD1_MATRIX_COEF15_25 0x3d67 -+#define VPP_WRAP_OSD1_MATRIX_CLIP 0x3d68 -+#define VPP_WRAP_OSD1_MATRIX_OFFSET0_1 0x3d69 -+#define VPP_WRAP_OSD1_MATRIX_OFFSET2 0x3d6a -+#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1 0x3d6b -+#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2 0x3d6c -+#define VPP_WRAP_OSD1_MATRIX_EN_CTRL 0x3d6d -+ -+#define VPP_WRAP_OSD2_MATRIX_COEF00_01 0x3d70 -+#define VPP_WRAP_OSD2_MATRIX_COEF02_10 0x3d71 -+#define VPP_WRAP_OSD2_MATRIX_COEF11_12 0x3d72 -+#define VPP_WRAP_OSD2_MATRIX_COEF20_21 0x3d73 -+#define VPP_WRAP_OSD2_MATRIX_COEF22 0x3d74 -+#define VPP_WRAP_OSD2_MATRIX_COEF13_14 0x3d75 -+#define VPP_WRAP_OSD2_MATRIX_COEF23_24 0x3d76 -+#define VPP_WRAP_OSD2_MATRIX_COEF15_25 0x3d77 -+#define VPP_WRAP_OSD2_MATRIX_CLIP 0x3d78 -+#define VPP_WRAP_OSD2_MATRIX_OFFSET0_1 0x3d79 -+#define VPP_WRAP_OSD2_MATRIX_OFFSET2 0x3d7a -+#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1 0x3d7b -+#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2 0x3d7c -+#define VPP_WRAP_OSD2_MATRIX_EN_CTRL 0x3d7d -+ -+#define VPP_WRAP_OSD3_MATRIX_COEF00_01 0x3db0 -+#define VPP_WRAP_OSD3_MATRIX_COEF02_10 0x3db1 -+#define VPP_WRAP_OSD3_MATRIX_COEF11_12 0x3db2 -+#define VPP_WRAP_OSD3_MATRIX_COEF20_21 0x3db3 -+#define VPP_WRAP_OSD3_MATRIX_COEF22 0x3db4 -+#define VPP_WRAP_OSD3_MATRIX_COEF13_14 0x3db5 -+#define VPP_WRAP_OSD3_MATRIX_COEF23_24 0x3db6 -+#define VPP_WRAP_OSD3_MATRIX_COEF15_25 0x3db7 -+#define VPP_WRAP_OSD3_MATRIX_CLIP 0x3db8 -+#define VPP_WRAP_OSD3_MATRIX_OFFSET0_1 0x3db9 -+#define VPP_WRAP_OSD3_MATRIX_OFFSET2 0x3dba -+#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET0_1 0x3dbb -+#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2 0x3dbc -+#define VPP_WRAP_OSD3_MATRIX_EN_CTRL 0x3dbd -+ -+/* osd2 scaler */ -+#define OSD2_VSC_PHASE_STEP 0x3d00 -+#define OSD2_VSC_INI_PHASE 0x3d01 -+#define OSD2_VSC_CTRL0 0x3d02 -+#define OSD2_HSC_PHASE_STEP 0x3d03 -+#define OSD2_HSC_INI_PHASE 0x3d04 -+#define OSD2_HSC_CTRL0 0x3d05 -+#define OSD2_HSC_INI_PAT_CTRL 0x3d06 -+#define OSD2_SC_DUMMY_DATA 0x3d07 -+#define OSD2_SC_CTRL0 0x3d08 -+#define OSD2_SCI_WH_M1 0x3d09 -+#define OSD2_SCO_H_START_END 0x3d0a -+#define OSD2_SCO_V_START_END 0x3d0b -+#define OSD2_SCALE_COEF_IDX 0x3d18 -+#define OSD2_SCALE_COEF 0x3d19 -+ -+/* osd34 scaler */ -+#define OSD34_SCALE_COEF_IDX 0x3d1e -+#define OSD34_SCALE_COEF 0x3d1f -+#define OSD34_VSC_PHASE_STEP 0x3d20 -+#define OSD34_VSC_INI_PHASE 0x3d21 -+#define OSD34_VSC_CTRL0 0x3d22 -+#define OSD34_HSC_PHASE_STEP 0x3d23 -+#define OSD34_HSC_INI_PHASE 0x3d24 -+#define OSD34_HSC_CTRL0 0x3d25 -+#define OSD34_HSC_INI_PAT_CTRL 0x3d26 -+#define OSD34_SC_DUMMY_DATA 0x3d27 -+#define OSD34_SC_CTRL0 0x3d28 -+#define OSD34_SCI_WH_M1 0x3d29 -+#define OSD34_SCO_H_START_END 0x3d2a -+#define OSD34_SCO_V_START_END 0x3d2b - /* viu2 */ - #define VIU2_ADDR_START 0x1e00 - #define VIU2_ADDR_END 0x1eff -@@ -1400,4 +1520,131 @@ - #define OSDSR_YBIC_VCOEF0 0x3149 - #define OSDSR_CBIC_VCOEF0 0x314a - -+/* osd afbcd on gxtvbb */ -+#define OSD1_AFBCD_ENABLE 0x31a0 -+#define OSD1_AFBCD_MODE 0x31a1 -+#define OSD1_AFBCD_SIZE_IN 0x31a2 -+#define OSD1_AFBCD_HDR_PTR 0x31a3 -+#define OSD1_AFBCD_FRAME_PTR 0x31a4 -+#define OSD1_AFBCD_CHROMA_PTR 0x31a5 -+#define OSD1_AFBCD_CONV_CTRL 0x31a6 -+#define OSD1_AFBCD_STATUS 0x31a8 -+#define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 -+#define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa -+#define VIU_MISC_CTRL1 0x1a07 -+ -+/* add for gxm and 962e dv core2 */ -+#define DOLBY_CORE2A_SWAP_CTRL1 0x3434 -+#define DOLBY_CORE2A_SWAP_CTRL2 0x3435 -+ -+/* osd afbc on g12a */ -+#define VPU_MAFBC_BLOCK_ID 0x3a00 -+#define VPU_MAFBC_IRQ_RAW_STATUS 0x3a01 -+#define VPU_MAFBC_IRQ_CLEAR 0x3a02 -+#define VPU_MAFBC_IRQ_MASK 0x3a03 -+#define VPU_MAFBC_IRQ_STATUS 0x3a04 -+#define VPU_MAFBC_COMMAND 0x3a05 -+#define VPU_MAFBC_STATUS 0x3a06 -+#define VPU_MAFBC_SURFACE_CFG 0x3a07 -+ -+/* osd afbc on g12a */ -+#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10 -+#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11 -+#define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12 -+#define VPU_MAFBC_BUFFER_WIDTH_S0 0x3a13 -+#define VPU_MAFBC_BUFFER_HEIGHT_S0 0x3a14 -+#define VPU_MAFBC_BOUNDING_BOX_X_START_S0 0x3a15 -+#define VPU_MAFBC_BOUNDING_BOX_X_END_S0 0x3a16 -+#define VPU_MAFBC_BOUNDING_BOX_Y_START_S0 0x3a17 -+#define VPU_MAFBC_BOUNDING_BOX_Y_END_S0 0x3a18 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0 0x3a19 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0 0x3a1a -+#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S0 0x3a1b -+#define VPU_MAFBC_PREFETCH_CFG_S0 0x3a1c -+ -+#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1 0x3a30 -+#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1 0x3a31 -+#define VPU_MAFBC_FORMAT_SPECIFIER_S1 0x3a32 -+#define VPU_MAFBC_BUFFER_WIDTH_S1 0x3a33 -+#define VPU_MAFBC_BUFFER_HEIGHT_S1 0x3a34 -+#define VPU_MAFBC_BOUNDING_BOX_X_START_S1 0x3a35 -+#define VPU_MAFBC_BOUNDING_BOX_X_END_S1 0x3a36 -+#define VPU_MAFBC_BOUNDING_BOX_Y_START_S1 0x3a37 -+#define VPU_MAFBC_BOUNDING_BOX_Y_END_S1 0x3a38 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1 0x3a39 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1 0x3a3a -+#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S1 0x3a3b -+#define VPU_MAFBC_PREFETCH_CFG_S1 0x3a3c -+ -+#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S2 0x3a50 -+#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S2 0x3a51 -+#define VPU_MAFBC_FORMAT_SPECIFIER_S2 0x3a52 -+#define VPU_MAFBC_BUFFER_WIDTH_S2 0x3a53 -+#define VPU_MAFBC_BUFFER_HEIGHT_S2 0x3a54 -+#define VPU_MAFBC_BOUNDING_BOX_X_START_S2 0x3a55 -+#define VPU_MAFBC_BOUNDING_BOX_X_END_S2 0x3a56 -+#define VPU_MAFBC_BOUNDING_BOX_Y_START_S2 0x3a57 -+#define VPU_MAFBC_BOUNDING_BOX_Y_END_S2 0x3a58 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S2 0x3a59 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S2 0x3a5a -+#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S2 0x3a5b -+#define VPU_MAFBC_PREFETCH_CFG_S2 0x3a5c -+ -+#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S3 0x3a70 -+#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S3 0x3a71 -+#define VPU_MAFBC_FORMAT_SPECIFIER_S3 0x3a72 -+#define VPU_MAFBC_BUFFER_WIDTH_S3 0x3a73 -+#define VPU_MAFBC_BUFFER_HEIGHT_S3 0x3a74 -+#define VPU_MAFBC_BOUNDING_BOX_X_START_S3 0x3a75 -+#define VPU_MAFBC_BOUNDING_BOX_X_END_S3 0x3a76 -+#define VPU_MAFBC_BOUNDING_BOX_Y_START_S3 0x3a77 -+#define VPU_MAFBC_BOUNDING_BOX_Y_END_S3 0x3a78 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S3 0x3a79 -+#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S3 0x3a7a -+#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S3 0x3a7b -+#define VPU_MAFBC_PREFETCH_CFG_S3 0x3a7c -+ -+#define DOLBY_PATH_CTRL 0x1a0c -+#define OSD_PATH_MISC_CTRL 0x1a0e -+#define MALI_AFBCD_TOP_CTRL 0x1a0f -+ -+#define VIU_OSD_BLEND_CTRL 0x39b0 -+#define VIU_OSD_BLEND_CTRL1 0x39c0 -+#define VIU_OSD_BLEND_DIN0_SCOPE_H 0x39b1 -+#define VIU_OSD_BLEND_DIN0_SCOPE_V 0x39b2 -+#define VIU_OSD_BLEND_DIN1_SCOPE_H 0x39b3 -+#define VIU_OSD_BLEND_DIN1_SCOPE_V 0x39b4 -+#define VIU_OSD_BLEND_DIN2_SCOPE_H 0x39b5 -+#define VIU_OSD_BLEND_DIN2_SCOPE_V 0x39b6 -+#define VIU_OSD_BLEND_DIN3_SCOPE_H 0x39b7 -+#define VIU_OSD_BLEND_DIN3_SCOPE_V 0x39b8 -+#define VIU_OSD_BLEND_DUMMY_DATA0 0x39b9 -+#define VIU_OSD_BLEND_DUMMY_ALPHA 0x39ba -+#define VIU_OSD_BLEND_BLEND0_SIZE 0x39bb -+#define VIU_OSD_BLEND_BLEND1_SIZE 0x39bc -+#define VIU_OSD_BLEND_RO_CURRENT_XY 0x39bf -+ -+#define VPP_OUT_H_V_SIZE 0x1da5 -+ -+#define VPP_VD2_HDR_IN_SIZE 0x1df0 -+#define VPP_OSD1_IN_SIZE 0x1df1 -+#define VPP_GCLK_CTRL2 0x1df2 -+#define VD2_PPS_DUMMY_DATA 0x1df4 -+#define VPP_OSD1_BLD_H_SCOPE 0x1df5 -+#define VPP_OSD1_BLD_V_SCOPE 0x1df6 -+#define VPP_OSD2_BLD_H_SCOPE 0x1df7 -+#define VPP_OSD2_BLD_V_SCOPE 0x1df8 -+#define VPP_WRBAK_CTRL 0x1df9 -+#define VPP_SLEEP_CTRL 0x1dfa -+#define VD1_BLEND_SRC_CTRL 0x1dfb -+#define VD2_BLEND_SRC_CTRL 0x1dfc -+#define OSD1_BLEND_SRC_CTRL 0x1dfd -+#define OSD2_BLEND_SRC_CTRL 0x1dfe -+ -+#define VPP_POST_BLEND_BLEND_DUMMY_DATA 0x3968 -+#define VPP_POST_BLEND_DUMMY_ALPHA 0x3969 -+#define VPP_RDARB_MODE 0x3978 -+#define VPP_RDARB_REQEN_SLV 0x3979 -+#define VPU_RDARB_MODE_L2C1 0x279d -+ - #endif /* __MESON_REGISTERS_H */ - -From 4c74bd81938dcef24a848f9721df38ac7e889e71 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:16 +0100 -Subject: [PATCH 043/249] FROMGIT: drm/meson: Add G12A Support for VPP setup - -Amlogic G12A needs a different VPP setup code, handle it here. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-4-narmstrong@baylibre.com -(cherry picked from commit e4d1ae1fa3603614ed9799b4407a8d09a796fb0b - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_vpp.c | 51 ++++++++++++++++++------------- - 1 file changed, 29 insertions(+), 22 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c -index f9efb431e9535..8c52a3455ef47 100644 ---- a/drivers/gpu/drm/meson/meson_vpp.c -+++ b/drivers/gpu/drm/meson/meson_vpp.c -@@ -112,32 +112,39 @@ void meson_vpp_init(struct meson_drm *priv) - writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL)); - writel_relaxed(0x1020080, - priv->io_base + _REG(VPP_DUMMY_DATA1)); -- } -+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ writel_relaxed(0xf, priv->io_base + _REG(DOLBY_PATH_CTRL)); - - /* Initialize vpu fifo control registers */ -- writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | -- 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ writel_relaxed(0xfff << 20 | 0x1000, -+ priv->io_base + _REG(VPP_OFIFO_SIZE)); -+ else -+ writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | -+ 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); - writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES)); - -- /* Turn off preblend */ -- writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0, -- priv->io_base + _REG(VPP_MISC)); -- -- /* Turn off POSTBLEND */ -- writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, -- priv->io_base + _REG(VPP_MISC)); -- -- /* Force all planes off */ -- writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | -- VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | -- VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, -- priv->io_base + _REG(VPP_MISC)); -- -- /* Setup default VD settings */ -- writel_relaxed(4096, -- priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); -- writel_relaxed(4096, -- priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); -+ if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ /* Turn off preblend */ -+ writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0, -+ priv->io_base + _REG(VPP_MISC)); -+ -+ /* Turn off POSTBLEND */ -+ writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, -+ priv->io_base + _REG(VPP_MISC)); -+ -+ /* Force all planes off */ -+ writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | -+ VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | -+ VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, -+ priv->io_base + _REG(VPP_MISC)); -+ -+ /* Setup default VD settings */ -+ writel_relaxed(4096, -+ priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); -+ writel_relaxed(4096, -+ priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); -+ } - - /* Disable Scalers */ - writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); - -From 2953e224163700e393ac626a42c54f08155c403f Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:17 +0100 -Subject: [PATCH 044/249] FROMGIT: drm/meson: Add G12A Support for VIU setup - -Amlogic G12A SoC needs a different VIU setup code, -handle it. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-5-narmstrong@baylibre.com -(cherry picked from commit 728883948b0d3c01492c1f83d505645aa2ca09d0 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_viu.c | 72 ++++++++++++++++++++++++++++--- - 1 file changed, 67 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c -index ac0f3687e09a3..0169c98b01c94 100644 ---- a/drivers/gpu/drm/meson/meson_viu.c -+++ b/drivers/gpu/drm/meson/meson_viu.c -@@ -90,6 +90,34 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { - EOTF_COEFF_RIGHTSHIFT /* right shift */ - }; - -+void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m, -+ bool csc_on) -+{ -+ /* VPP WRAP OSD1 matrix */ -+ writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1)); -+ writel(m[2] & 0xfff, -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2)); -+ writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01)); -+ writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10)); -+ writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12)); -+ writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21)); -+ writel((m[11] & 0x1fff) << 16, -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22)); -+ -+ writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff), -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1)); -+ writel(m[20] & 0xfff, -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2)); -+ -+ writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, -+ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); -+} -+ - void meson_viu_set_osd_matrix(struct meson_drm *priv, - enum viu_matrix_sel_e m_select, - int *m, bool csc_on) -@@ -336,14 +364,24 @@ void meson_viu_init(struct meson_drm *priv) - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) - meson_viu_load_matrix(priv); -+ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff, -+ true); - - /* Initialize OSD1 fifo control register */ - reg = BIT(0) | /* Urgent DDR request priority */ -- (4 << 5) | /* hold_fifo_lines */ -- (3 << 10) | /* burst length 64 */ -- (32 << 12) | /* fifo_depth_val: 32*8=256 */ -- (2 << 22) | /* 4 words in 1 burst */ -- (2 << 24); -+ (4 << 5); /* hold_fifo_lines */ -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ reg |= (1 << 10) | /* burst length 32 */ -+ (32 << 12) | /* fifo_depth_val: 32*8=256 */ -+ (2 << 22) | /* 4 words in 1 burst */ -+ (2 << 24) | -+ (1 << 31); -+ else -+ reg |= (3 << 10) | /* burst length 64 */ -+ (32 << 12) | /* fifo_depth_val: 32*8=256 */ -+ (2 << 22) | /* 4 words in 1 burst */ -+ (2 << 24); - writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); - writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); - -@@ -369,6 +407,30 @@ void meson_viu_init(struct meson_drm *priv) - writel_relaxed(0x00FF00C0, - priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); - -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ writel_relaxed(4 << 29 | -+ 1 << 27 | -+ 1 << 26 | /* blend_din0 input to blend0 */ -+ 1 << 25 | /* blend1_dout to blend2 */ -+ 1 << 24 | /* blend1_din3 input to blend1 */ -+ 1 << 20 | -+ 0 << 16 | -+ 1, -+ priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); -+ writel_relaxed(3 << 8 | -+ 1 << 20, -+ priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); -+ writel_relaxed(1 << 20, -+ priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); -+ writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); -+ writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); -+ writel_relaxed(0, -+ priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); -+ writel_relaxed(0, -+ priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); -+ writel_bits_relaxed(0x3 << 2, 0x3 << 2, -+ priv->io_base + _REG(DOLBY_PATH_CTRL)); -+ } - - priv->viu.osd1_enabled = false; - priv->viu.osd1_commit = false; - -From 2b0b206f454e1ac5293598b47a863b4745de2493 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:18 +0100 -Subject: [PATCH 045/249] FROMGIT: drm/meson: Add G12A support for OSD1 Plane - -Amlogic G12A SoC supports now up to 3 OSD planes (1 more than the -previous SoCs) and a brand new OSD plane blender module. - -This patch uses the same OSD1 plane for G12A, using the exact same scaler -and OSD1 setup registers, except using the new blender register to -disable the plane. - -Signed-off-by: Neil Armstrong -[narmstrong: fixed typo in commit log] -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-6-narmstrong@baylibre.com -(cherry picked from commit 490f50c109d1178aae4124cd9138b231d030e554 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_plane.c | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c -index b7786218cb10a..bf8f1fab63aa9 100644 ---- a/drivers/gpu/drm/meson/meson_plane.c -+++ b/drivers/gpu/drm/meson/meson_plane.c -@@ -294,6 +294,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, - priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; - priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; - -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1; -+ priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1; -+ priv->viu.osb_blend0_size = dst_h << 16 | dst_w; -+ priv->viu.osb_blend1_size = dst_h << 16 | dst_w; -+ } -+ - /* Update Canvas with buffer address */ - gem = drm_fb_cma_get_gem_obj(fb, 0); - -@@ -320,8 +327,12 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, - struct meson_drm *priv = meson_plane->priv; - - /* Disable OSD1 */ -- writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, -- priv->io_base + _REG(VPP_MISC)); -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ writel_bits_relaxed(BIT(0) | BIT(21), 0, -+ priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); -+ else -+ writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, -+ priv->io_base + _REG(VPP_MISC)); - - meson_plane->enabled = false; - - -From 427d164c3823ebab6fd0c3f7c2f058eef3c0ff42 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:19 +0100 -Subject: [PATCH 046/249] FROMGIT: drm/meson: Add G12A Support for the Overlay - video plane - -Amlogic G12A SoC supports the same set of Video Planes, but now -are handled by the new OSD plane blender module. - -This patch uses the same VD1 plane for G12A, using the exact same scaler -and VD1 setup registers, except using the new blender register to -disable the plane. - -Signed-off-by: Neil Armstrong -[narmstrong: fix typo in commit log] -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-7-narmstrong@baylibre.com -(cherry picked from commit 11c2d4c751e5b339f8a3c6b9f19120bb331af0ef - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_overlay.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c -index b54a22e483b92..bdbf925ff3e85 100644 ---- a/drivers/gpu/drm/meson/meson_overlay.c -+++ b/drivers/gpu/drm/meson/meson_overlay.c -@@ -516,8 +516,14 @@ static void meson_overlay_atomic_disable(struct drm_plane *plane, - priv->viu.vd1_enabled = false; - - /* Disable VD1 */ -- writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, -- priv->io_base + _REG(VPP_MISC)); -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); -+ writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); -+ writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0)); -+ writel_relaxed(0, priv->io_base + _REG(VD2_IF0_GEN_REG + 0x17b0)); -+ } else -+ writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, -+ priv->io_base + _REG(VPP_MISC)); - - } - - -From 15a35f845c1c1b3995d522a3b7540d63f594b21e Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:20 +0100 -Subject: [PATCH 047/249] FROMGIT: drm/meson: Add G12A support for plane - handling in CRTC driver - -This patch adds support for the new OSD+VD Plane blending module -in the CRTC code by adding the G12A code to manage the blending -module and setting the right OSD1 & VD1 plane registers. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-8-narmstrong@baylibre.com -(cherry picked from commit 68679d41a3d6d7e55ed49b4e5688d1089de7c5a7 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_crtc.c | 269 +++++++++++++++++++++++------ - drivers/gpu/drm/meson/meson_drv.h | 4 + - 2 files changed, 221 insertions(+), 52 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c -index 6d9311e254efc..5579f8ac3e3f7 100644 ---- a/drivers/gpu/drm/meson/meson_crtc.c -+++ b/drivers/gpu/drm/meson/meson_crtc.c -@@ -39,12 +39,17 @@ - #include "meson_viu.h" - #include "meson_registers.h" - -+#define MESON_G12A_VIU_OFFSET 0x5ec0 -+ - /* CRTC definition */ - - struct meson_crtc { - struct drm_crtc base; - struct drm_pending_vblank_event *event; - struct meson_drm *priv; -+ void (*enable_osd1)(struct meson_drm *priv); -+ void (*enable_vd1)(struct meson_drm *priv); -+ unsigned int viu_offset; - }; - #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) - -@@ -80,6 +85,44 @@ static const struct drm_crtc_funcs meson_crtc_funcs = { - - }; - -+static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, -+ struct drm_crtc_state *old_state) -+{ -+ struct meson_crtc *meson_crtc = to_meson_crtc(crtc); -+ struct drm_crtc_state *crtc_state = crtc->state; -+ struct meson_drm *priv = meson_crtc->priv; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ if (!crtc_state) { -+ DRM_ERROR("Invalid crtc_state\n"); -+ return; -+ } -+ -+ /* VD1 Preblend vertical start/end */ -+ writel(FIELD_PREP(GENMASK(11, 0), 2303), -+ priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); -+ -+ /* Setup Blender */ -+ writel(crtc_state->mode.hdisplay | -+ crtc_state->mode.vdisplay << 16, -+ priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); -+ -+ writel_relaxed(0 << 16 | -+ (crtc_state->mode.hdisplay - 1), -+ priv->io_base + _REG(VPP_OSD1_BLD_H_SCOPE)); -+ writel_relaxed(0 << 16 | -+ (crtc_state->mode.vdisplay - 1), -+ priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE)); -+ writel_relaxed(crtc_state->mode.hdisplay << 16 | -+ crtc_state->mode.vdisplay, -+ priv->io_base + _REG(VPP_OUT_H_V_SIZE)); -+ -+ drm_crtc_vblank_on(crtc); -+ -+ priv->viu.osd1_enabled = true; -+} -+ - static void meson_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) - { -@@ -110,6 +153,31 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, - priv->viu.osd1_enabled = true; - } - -+static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, -+ struct drm_crtc_state *old_state) -+{ -+ struct meson_crtc *meson_crtc = to_meson_crtc(crtc); -+ struct meson_drm *priv = meson_crtc->priv; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ drm_crtc_vblank_off(crtc); -+ -+ priv->viu.osd1_enabled = false; -+ priv->viu.osd1_commit = false; -+ -+ priv->viu.vd1_enabled = false; -+ priv->viu.vd1_commit = false; -+ -+ if (crtc->state->event && !crtc->state->active) { -+ spin_lock_irq(&crtc->dev->event_lock); -+ drm_crtc_send_vblank_event(crtc, crtc->state->event); -+ spin_unlock_irq(&crtc->dev->event_lock); -+ -+ crtc->state->event = NULL; -+ } -+} -+ - static void meson_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) - { -@@ -173,6 +241,53 @@ static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { - .atomic_disable = meson_crtc_atomic_disable, - }; - -+static const struct drm_crtc_helper_funcs meson_g12a_crtc_helper_funcs = { -+ .atomic_begin = meson_crtc_atomic_begin, -+ .atomic_flush = meson_crtc_atomic_flush, -+ .atomic_enable = meson_g12a_crtc_atomic_enable, -+ .atomic_disable = meson_g12a_crtc_atomic_disable, -+}; -+ -+static void meson_crtc_enable_osd1(struct meson_drm *priv) -+{ -+ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, -+ priv->io_base + _REG(VPP_MISC)); -+} -+ -+static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv) -+{ -+ writel_relaxed(priv->viu.osd_blend_din0_scope_h, -+ priv->io_base + -+ _REG(VIU_OSD_BLEND_DIN0_SCOPE_H)); -+ writel_relaxed(priv->viu.osd_blend_din0_scope_v, -+ priv->io_base + -+ _REG(VIU_OSD_BLEND_DIN0_SCOPE_V)); -+ writel_relaxed(priv->viu.osb_blend0_size, -+ priv->io_base + -+ _REG(VIU_OSD_BLEND_BLEND0_SIZE)); -+ writel_relaxed(priv->viu.osb_blend1_size, -+ priv->io_base + -+ _REG(VIU_OSD_BLEND_BLEND1_SIZE)); -+} -+ -+static void meson_crtc_enable_vd1(struct meson_drm *priv) -+{ -+ writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | -+ VPP_COLOR_MNG_ENABLE, -+ VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | -+ VPP_COLOR_MNG_ENABLE, -+ priv->io_base + _REG(VPP_MISC)); -+} -+ -+static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv) -+{ -+ writel_relaxed(((1 << 16) | /* post bld premult*/ -+ (1 << 8) | /* post src */ -+ (1 << 4) | /* pre bld premult*/ -+ (1 << 0)), -+ priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); -+} -+ - void meson_crtc_irq(struct meson_drm *priv) - { - struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); -@@ -219,8 +334,8 @@ void meson_crtc_irq(struct meson_drm *priv) - MESON_CANVAS_BLKMODE_LINEAR, 0); - - /* Enable OSD1 */ -- writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, -- priv->io_base + _REG(VPP_MISC)); -+ if (meson_crtc->enable_osd1) -+ meson_crtc->enable_osd1(priv); - - priv->viu.osd1_commit = false; - } -@@ -261,89 +376,133 @@ void meson_crtc_irq(struct meson_drm *priv) - }; - - writel_relaxed(priv->viu.vd1_if0_gen_reg, -- priv->io_base + _REG(VD1_IF0_GEN_REG)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_GEN_REG)); - writel_relaxed(priv->viu.vd1_if0_gen_reg, -- priv->io_base + _REG(VD2_IF0_GEN_REG)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_GEN_REG)); - writel_relaxed(priv->viu.vd1_if0_gen_reg2, -- priv->io_base + _REG(VD1_IF0_GEN_REG2)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_GEN_REG2)); - writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, -- priv->io_base + _REG(VIU_VD1_FMT_CTRL)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VIU_VD1_FMT_CTRL)); - writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, -- priv->io_base + _REG(VIU_VD2_FMT_CTRL)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VIU_VD2_FMT_CTRL)); - writel_relaxed(priv->viu.viu_vd1_fmt_w, -- priv->io_base + _REG(VIU_VD1_FMT_W)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VIU_VD1_FMT_W)); - writel_relaxed(priv->viu.viu_vd1_fmt_w, -- priv->io_base + _REG(VIU_VD2_FMT_W)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VIU_VD2_FMT_W)); - writel_relaxed(priv->viu.vd1_if0_canvas0, -- priv->io_base + _REG(VD1_IF0_CANVAS0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CANVAS0)); - writel_relaxed(priv->viu.vd1_if0_canvas0, -- priv->io_base + _REG(VD1_IF0_CANVAS1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CANVAS1)); - writel_relaxed(priv->viu.vd1_if0_canvas0, -- priv->io_base + _REG(VD2_IF0_CANVAS0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CANVAS0)); - writel_relaxed(priv->viu.vd1_if0_canvas0, -- priv->io_base + _REG(VD2_IF0_CANVAS1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CANVAS1)); - writel_relaxed(priv->viu.vd1_if0_luma_x0, -- priv->io_base + _REG(VD1_IF0_LUMA_X0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_LUMA_X0)); - writel_relaxed(priv->viu.vd1_if0_luma_x0, -- priv->io_base + _REG(VD1_IF0_LUMA_X1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_LUMA_X1)); - writel_relaxed(priv->viu.vd1_if0_luma_x0, -- priv->io_base + _REG(VD2_IF0_LUMA_X0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_LUMA_X0)); - writel_relaxed(priv->viu.vd1_if0_luma_x0, -- priv->io_base + _REG(VD2_IF0_LUMA_X1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_LUMA_X1)); - writel_relaxed(priv->viu.vd1_if0_luma_y0, -- priv->io_base + _REG(VD1_IF0_LUMA_Y0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_LUMA_Y0)); - writel_relaxed(priv->viu.vd1_if0_luma_y0, -- priv->io_base + _REG(VD1_IF0_LUMA_Y1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_LUMA_Y1)); - writel_relaxed(priv->viu.vd1_if0_luma_y0, -- priv->io_base + _REG(VD2_IF0_LUMA_Y0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_LUMA_Y0)); - writel_relaxed(priv->viu.vd1_if0_luma_y0, -- priv->io_base + _REG(VD2_IF0_LUMA_Y1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_LUMA_Y1)); - writel_relaxed(priv->viu.vd1_if0_chroma_x0, -- priv->io_base + _REG(VD1_IF0_CHROMA_X0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CHROMA_X0)); - writel_relaxed(priv->viu.vd1_if0_chroma_x0, -- priv->io_base + _REG(VD1_IF0_CHROMA_X1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CHROMA_X1)); - writel_relaxed(priv->viu.vd1_if0_chroma_x0, -- priv->io_base + _REG(VD2_IF0_CHROMA_X0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CHROMA_X0)); - writel_relaxed(priv->viu.vd1_if0_chroma_x0, -- priv->io_base + _REG(VD2_IF0_CHROMA_X1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CHROMA_X1)); - writel_relaxed(priv->viu.vd1_if0_chroma_y0, -- priv->io_base + _REG(VD1_IF0_CHROMA_Y0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CHROMA_Y0)); - writel_relaxed(priv->viu.vd1_if0_chroma_y0, -- priv->io_base + _REG(VD1_IF0_CHROMA_Y1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CHROMA_Y1)); - writel_relaxed(priv->viu.vd1_if0_chroma_y0, -- priv->io_base + _REG(VD2_IF0_CHROMA_Y0)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CHROMA_Y0)); - writel_relaxed(priv->viu.vd1_if0_chroma_y0, -- priv->io_base + _REG(VD2_IF0_CHROMA_Y1)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CHROMA_Y1)); - writel_relaxed(priv->viu.vd1_if0_repeat_loop, -- priv->io_base + _REG(VD1_IF0_RPT_LOOP)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_RPT_LOOP)); - writel_relaxed(priv->viu.vd1_if0_repeat_loop, -- priv->io_base + _REG(VD2_IF0_RPT_LOOP)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_RPT_LOOP)); - writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, -- priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_LUMA0_RPT_PAT)); - writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, -- priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_LUMA0_RPT_PAT)); - writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, -- priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_LUMA1_RPT_PAT)); - writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, -- priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_LUMA1_RPT_PAT)); - writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, -- priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CHROMA0_RPT_PAT)); - writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, -- priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CHROMA0_RPT_PAT)); - writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, -- priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CHROMA1_RPT_PAT)); - writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, -- priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT)); -- writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL)); -- writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL)); -- writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL)); -- writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CHROMA1_RPT_PAT)); -+ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_LUMA_PSEL)); -+ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_CHROMA_PSEL)); -+ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_LUMA_PSEL)); -+ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + -+ _REG(VD2_IF0_CHROMA_PSEL)); - writel_relaxed(priv->viu.vd1_range_map_y, -- priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_RANGE_MAP_Y)); - writel_relaxed(priv->viu.vd1_range_map_cb, -- priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_RANGE_MAP_CB)); - writel_relaxed(priv->viu.vd1_range_map_cr, -- priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR)); -+ priv->io_base + meson_crtc->viu_offset + -+ _REG(VD1_IF0_RANGE_MAP_CR)); - writel_relaxed(0x78404, - priv->io_base + _REG(VPP_SC_MISC)); - writel_relaxed(priv->viu.vpp_pic_in_height, -@@ -389,11 +548,8 @@ void meson_crtc_irq(struct meson_drm *priv) - writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); - - /* Enable VD1 */ -- writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | -- VPP_COLOR_MNG_ENABLE, -- VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | -- VPP_COLOR_MNG_ENABLE, -- priv->io_base + _REG(VPP_MISC)); -+ if (meson_crtc->enable_vd1) -+ meson_crtc->enable_vd1(priv); - - priv->viu.vd1_commit = false; - } -@@ -430,7 +586,16 @@ int meson_crtc_create(struct meson_drm *priv) - return ret; - } - -- drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1; -+ meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1; -+ meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; -+ drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs); -+ } else { -+ meson_crtc->enable_osd1 = meson_crtc_enable_osd1; -+ meson_crtc->enable_vd1 = meson_crtc_enable_vd1; -+ drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); -+ } - - priv->crtc = crtc; - -diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h -index 214a7cb18ce27..9614baa836b92 100644 ---- a/drivers/gpu/drm/meson/meson_drv.h -+++ b/drivers/gpu/drm/meson/meson_drv.h -@@ -62,6 +62,10 @@ struct meson_drm { - uint32_t osd_sc_h_phase_step; - uint32_t osd_sc_h_ctrl0; - uint32_t osd_sc_v_ctrl0; -+ uint32_t osd_blend_din0_scope_h; -+ uint32_t osd_blend_din0_scope_v; -+ uint32_t osb_blend0_size; -+ uint32_t osb_blend1_size; - - bool vd1_enabled; - bool vd1_commit; - -From 52fccfa8527daecd653a114798899e00bd10f087 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:21 +0100 -Subject: [PATCH 048/249] FROMGIT: drm/meson: Add G12A support for CVBS Encoder - -The Meson G12A SoCs uses the exact same CVBS encoder except a simple -CVBS DAC register offset and settings delta. - -Signed-off-by: Neil Armstrong -[narmstrong: fixed subject typo] -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-9-narmstrong@baylibre.com -(cherry picked from commit 64d598a106c3d6c06071fd66780d3d7d7d15251a - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_venc.c | 11 +++++++++-- - drivers/gpu/drm/meson/meson_venc_cvbs.c | 25 ++++++++++++++++++------- - 2 files changed, 27 insertions(+), 9 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c -index 66d73a932d193..6faca7313339e 100644 ---- a/drivers/gpu/drm/meson/meson_venc.c -+++ b/drivers/gpu/drm/meson/meson_venc.c -@@ -73,7 +73,9 @@ - /* HHI Registers */ - #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ - #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ -+#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ - #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ -+#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ - #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ - - struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { -@@ -1675,8 +1677,13 @@ void meson_venc_disable_vsync(struct meson_drm *priv) - void meson_venc_init(struct meson_drm *priv) - { - /* Disable CVBS VDAC */ -- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); -- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); -+ regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8); -+ } else { -+ regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); -+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); -+ } - - /* Power Down Dacs */ - writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); -diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c -index d622d817b6df1..2c5341c881c47 100644 ---- a/drivers/gpu/drm/meson/meson_venc_cvbs.c -+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c -@@ -37,7 +37,9 @@ - - /* HHI VDAC Registers */ - #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ -+#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ - #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ -+#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ - - struct meson_venc_cvbs { - struct drm_encoder encoder; -@@ -166,8 +168,13 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder) - struct meson_drm *priv = meson_venc_cvbs->priv; - - /* Disable CVBS VDAC */ -- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); -- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); -+ regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); -+ } else { -+ regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); -+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); -+ } - } - - static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) -@@ -179,13 +186,17 @@ static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) - /* VDAC0 source is not from ATV */ - writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); - -- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { - regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1); -- else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || -- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) -+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); -+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || -+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { - regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001); -- -- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); -+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); -+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001); -+ regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); -+ } - } - - static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, - -From 69f6ae40245b7d26374cd8c8ca7f23b529e0a627 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:22 +0100 -Subject: [PATCH 049/249] FROMGIT: drm/meson: Add G12A Video Clock setup - -While switching to the Common Clock Framework is still Work In Progress, -this patch adds the corresponding G12A HDMI PLL setup to be on-par -with the other SoCs support. - -The G12A has only a single tweak about the high frequency setup, -where the HDMI PLL needs a specific setup to handle correctly the -5.94GHz DCO frequency. - -Apart that, it handls ecorrectly all the other HDMI frequencies -and can achieve even better DMT clock frequency precision with -the larger fractional dividier width. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-10-narmstrong@baylibre.com -(cherry picked from commit 202b9808f8edc8508f34f99a96c6cbe88042aff1 - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_vclk.c | 119 ++++++++++++++++++++++++++--- - 1 file changed, 108 insertions(+), 11 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c -index c15a5a5df6331..b39034745444a 100644 ---- a/drivers/gpu/drm/meson/meson_vclk.c -+++ b/drivers/gpu/drm/meson/meson_vclk.c -@@ -113,9 +113,12 @@ - #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ - #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ - #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ -+#define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */ - - #define HDMI_PLL_RESET BIT(28) -+#define HDMI_PLL_RESET_G12A BIT(29) - #define HDMI_PLL_LOCK BIT(31) -+#define HDMI_PLL_LOCK_G12A (3 << 30) - - #define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001) - -@@ -257,6 +260,10 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d); -+ -+ /* Poll for lock bit */ -+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, -+ (val & HDMI_PLL_LOCK), 10, 0); - } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); -@@ -271,11 +278,26 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) - HDMI_PLL_RESET, HDMI_PLL_RESET); - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - HDMI_PLL_RESET, 0); -- } - -- /* Poll for lock bit */ -- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, -- (val & HDMI_PLL_LOCK), 10, 0); -+ /* Poll for lock bit */ -+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, -+ (val & HDMI_PLL_LOCK), 10, 0); -+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00010000); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x6a28dc00); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x56540000); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x3a0504f7); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); -+ -+ /* Poll for lock bit */ -+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, -+ ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A), -+ 10, 0); -+ } - - /* Disable VCLK2 */ - regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); -@@ -288,8 +310,13 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) - VCLK2_DIV_MASK, (55 - 1)); - - /* select vid_pll for vclk2 */ -- regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, -- VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, -+ VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT)); -+ else -+ regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, -+ VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); -+ - /* enable vclk2 gate */ - regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN); - -@@ -476,32 +503,80 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, - (val & HDMI_PLL_LOCK), 10, 0); -+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m); -+ -+ /* Enable and reset */ -+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, -+ 0x3 << 28, 0x3 << 28); -+ -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); -+ -+ /* G12A HDMI PLL Needs specific parameters for 5.4GHz */ -+ if (m >= 0xf7) { -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0xea68dc00); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000); -+ } else { -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000); -+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000); -+ } -+ -+ do { -+ /* Reset PLL */ -+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, -+ HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A); -+ -+ /* UN-Reset PLL */ -+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, -+ HDMI_PLL_RESET_G12A, 0); -+ -+ /* Poll for lock bits */ -+ if (!regmap_read_poll_timeout(priv->hhi, -+ HHI_HDMI_PLL_CNTL, val, -+ ((val & HDMI_PLL_LOCK_G12A) -+ == HDMI_PLL_LOCK_G12A), -+ 10, 100)) -+ break; -+ } while(1); - } - - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 16, pll_od_to_reg(od1) << 16); - else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || -- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) -+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 21, pll_od_to_reg(od1) << 21); -+ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, -+ 3 << 16, pll_od_to_reg(od1) << 16); - - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 22, pll_od_to_reg(od2) << 22); - else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || -- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) -+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 23, pll_od_to_reg(od2) << 23); -+ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, -+ 3 << 18, pll_od_to_reg(od2) << 18); - - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 18, pll_od_to_reg(od3) << 18); - else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || -- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) -+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 19, pll_od_to_reg(od3) << 19); -- -+ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, -+ 3 << 20, pll_od_to_reg(od3) << 20); - } - - #define XTAL_FREQ 24000 -@@ -518,6 +593,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, - - #define HDMI_FRAC_MAX_GXBB 4096 - #define HDMI_FRAC_MAX_GXL 1024 -+#define HDMI_FRAC_MAX_G12A 131072 - - static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, - unsigned int m, -@@ -534,6 +610,9 @@ static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, - parent_freq *= 2; - } - -+ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) -+ frac_max = HDMI_FRAC_MAX_G12A; -+ - /* We can have a perfect match !*/ - if (pll_freq / m == parent_freq && - pll_freq % m == 0) -@@ -559,7 +638,8 @@ static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, - if (frac >= HDMI_FRAC_MAX_GXBB) - return false; - } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || -- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { -+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu") || -+ meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { - /* Empiric supported min/max dividers */ - if (m < 106 || m > 247) - return false; -@@ -713,6 +793,23 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, - break; - } - -+ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); -+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ switch (pll_base_freq) { -+ case 2970000: -+ m = 0x7b; -+ frac = vic_alternate_clock ? 0x140b4 : 0x18000; -+ break; -+ case 4320000: -+ m = vic_alternate_clock ? 0xb3 : 0xb4; -+ frac = vic_alternate_clock ? 0x1a3ee : 0; -+ break; -+ case 5940000: -+ m = 0xf7; -+ frac = vic_alternate_clock ? 0x8148 : 0x10000; -+ break; -+ } -+ - meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); - } - - -From 2f0d9002b9e49e6b942101393006f22a20bf35fc Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:23 +0100 -Subject: [PATCH 050/249] FROMGIT: drm/meson: Add G12A compatible - -Finally add the Amlogic G12A SoC compatible for the VPU driver. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-11-narmstrong@baylibre.com -(cherry picked from commit 4deb190aa3551dfb2b7508960dc217702cb7278d - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_drv.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c -index 079d22299d789..faf1b1b0357cd 100644 ---- a/drivers/gpu/drm/meson/meson_drv.c -+++ b/drivers/gpu/drm/meson/meson_drv.c -@@ -447,6 +447,7 @@ static const struct of_device_id dt_match[] = { - { .compatible = "amlogic,meson-gxbb-vpu" }, - { .compatible = "amlogic,meson-gxl-vpu" }, - { .compatible = "amlogic,meson-gxm-vpu" }, -+ { .compatible = "amlogic,meson-g12a-vpu" }, - {} - }; - MODULE_DEVICE_TABLE(of, dt_match); - -From 93c59c97a0f0952e960e5d00a870630a54d23336 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 15:18:24 +0100 -Subject: [PATCH 051/249] FROMGIT: drm/meson: Add G12A support for the DW-HDMI - Glue - -The Amlogic G12A embeds the same Synopsys DW-HDMI Controller, -but with : -- a "backport" of the HDR signaling registers from more recent - DW-HDMI controllers, this will need a tweak since it's not - normally present on this version of the DW-HDMI controller -- A direct mapping of TOP and DW-HDMI registers instead of an - internal bus accessed using read/write registers -- Support for RX-SENSE, but not yet implemented -- Support for HDMI 2.1 Dynamic HDR, but not yet implemented -- Different registers mapping for the HDMI PHY setup - -This patchs adds support for these changes while providing exact -same support as the previous GXBB, GXL & GXM SoCs. - -Signed-off-by: Neil Armstrong -Tested-by: Jerome Brunet -Reviewed-by: Jerome Brunet -Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-12-narmstrong@baylibre.com -(cherry picked from commit 3b7c1237a72a970daca99a6dc30f980f8bbaa34c - git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_dw_hdmi.c | 163 ++++++++++++++++++++------ - drivers/gpu/drm/meson/meson_dw_hdmi.h | 32 ++++- - 2 files changed, 157 insertions(+), 38 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c -index 563953ec6ad03..779da21143b9b 100644 ---- a/drivers/gpu/drm/meson/meson_dw_hdmi.c -+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -105,6 +106,7 @@ - #define HDMITX_TOP_ADDR_REG 0x0 - #define HDMITX_TOP_DATA_REG 0x4 - #define HDMITX_TOP_CTRL_REG 0x8 -+#define HDMITX_TOP_G12A_OFFSET 0x8000 - - /* Controller Communication Channel */ - #define HDMITX_DWC_ADDR_REG 0x10 -@@ -118,6 +120,8 @@ - #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ - #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ - #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ -+#define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */ -+#define HHI_HDMI_PHY_CNTL5 0x3b4 /* 0xed */ - - static DEFINE_SPINLOCK(reg_lock); - -@@ -127,12 +131,26 @@ enum meson_venc_source { - MESON_VENC_SOURCE_ENCP = 2, - }; - -+struct meson_dw_hdmi; -+ -+struct meson_dw_hdmi_data { -+ unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr); -+ void (*top_write)(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr, unsigned int data); -+ unsigned int (*dwc_read)(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr); -+ void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr, unsigned int data); -+}; -+ - struct meson_dw_hdmi { - struct drm_encoder encoder; - struct dw_hdmi_plat_data dw_plat_data; - struct meson_drm *priv; - struct device *dev; - void __iomem *hdmitx; -+ const struct meson_dw_hdmi_data *data; - struct reset_control *hdmitx_apb; - struct reset_control *hdmitx_ctrl; - struct reset_control *hdmitx_phy; -@@ -174,6 +192,12 @@ static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi, - return data; - } - -+static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr) -+{ -+ return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); -+} -+ - static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, - unsigned int addr, unsigned int data) - { -@@ -191,18 +215,24 @@ static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, - spin_unlock_irqrestore(®_lock, flags); - } - -+static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr, unsigned int data) -+{ -+ writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); -+} -+ - /* Helper to change specific bits in PHY registers */ - static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, - unsigned int addr, - unsigned int mask, - unsigned int val) - { -- unsigned int data = dw_hdmi_top_read(dw_hdmi, addr); -+ unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr); - - data &= ~mask; - data |= val; - -- dw_hdmi_top_write(dw_hdmi, addr, data); -+ dw_hdmi->data->top_write(dw_hdmi, addr, data); - } - - static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, -@@ -226,6 +256,12 @@ static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, - return data; - } - -+static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr) -+{ -+ return readb(dw_hdmi->hdmitx + addr); -+} -+ - static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, - unsigned int addr, unsigned int data) - { -@@ -243,18 +279,24 @@ static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, - spin_unlock_irqrestore(®_lock, flags); - } - -+static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi, -+ unsigned int addr, unsigned int data) -+{ -+ writeb(data, dw_hdmi->hdmitx + addr); -+} -+ - /* Helper to change specific bits in controller registers */ - static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, - unsigned int addr, - unsigned int mask, - unsigned int val) - { -- unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr); -+ unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr); - - data &= ~mask; - data |= val; - -- dw_hdmi_dwc_write(dw_hdmi, addr, data); -+ dw_hdmi->data->dwc_write(dw_hdmi, addr, data); - } - - /* Bridge */ -@@ -300,6 +342,24 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, - regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); - regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); - } -+ } else if (dw_hdmi_is_compatible(dw_hdmi, -+ "amlogic,meson-g12a-dw-hdmi")) { -+ if (pixel_clock >= 371250) { -+ /* 5.94Gbps, 3.7125Gbps */ -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4); -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b); -+ } else if (pixel_clock >= 297000) { -+ /* 2.97Gbps */ -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262); -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); -+ } else { -+ /* 1.485Gbps, and below */ -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242); -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); -+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); -+ } - } - } - -@@ -375,7 +435,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, - regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); - - /* Bring out of reset */ -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); - - /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ - dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, -@@ -384,24 +444,25 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, - 0x3 << 4, 0x3 << 4); - - /* Enable normal output to PHY */ -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); - - /* TMDS pattern setup (TOFIX Handle the YUV420 case) */ - if (mode->clock > 340000) { -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0); -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, -+ 0); -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, - 0x03ff03ff); - } else { -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, - 0x001f001f); -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, - 0x001f001f); - } - - /* Load TMDS pattern */ -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); - msleep(20); -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); - - /* Setup PHY parameters */ - meson_hdmi_phy_setup_mode(dw_hdmi, mode); -@@ -412,7 +473,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, - - /* BIT_INVERT */ - if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || -- dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) -+ dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || -+ dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) - regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, - BIT(17), 0); - else -@@ -480,7 +542,7 @@ static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, - { - struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; - -- return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ? -+ return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ? - connector_status_connected : connector_status_disconnected; - } - -@@ -490,11 +552,11 @@ static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi, - struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; - - /* Setup HPD Filter */ -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, - (0xa << 12) | 0xa0); - - /* Clear interrupts */ -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, - HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); - - /* Unmask interrupts */ -@@ -515,8 +577,8 @@ static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id) - struct meson_dw_hdmi *dw_hdmi = dev_id; - u32 stat; - -- stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); -- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); -+ stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); -+ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); - - /* HPD Events, handle in the threaded interrupt handler */ - if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { -@@ -686,7 +748,9 @@ static const struct drm_encoder_helper_funcs - static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, - unsigned int *result) - { -- *result = dw_hdmi_dwc_read(context, reg); -+ struct meson_dw_hdmi *dw_hdmi = context; -+ -+ *result = dw_hdmi->data->dwc_read(dw_hdmi, reg); - - return 0; - -@@ -695,7 +759,9 @@ static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, - static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, - unsigned int val) - { -- dw_hdmi_dwc_write(context, reg, val); -+ struct meson_dw_hdmi *dw_hdmi = context; -+ -+ dw_hdmi->data->dwc_write(dw_hdmi, reg, val); - - return 0; - } -@@ -709,6 +775,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = { - .fast_io = true, - }; - -+static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = { -+ .top_read = dw_hdmi_top_read, -+ .top_write = dw_hdmi_top_write, -+ .dwc_read = dw_hdmi_dwc_read, -+ .dwc_write = dw_hdmi_dwc_write, -+}; -+ -+static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { -+ .top_read = dw_hdmi_g12a_top_read, -+ .top_write = dw_hdmi_g12a_top_write, -+ .dwc_read = dw_hdmi_g12a_dwc_read, -+ .dwc_write = dw_hdmi_g12a_dwc_write, -+}; -+ - static bool meson_hdmi_connector_is_available(struct device *dev) - { - struct device_node *ep, *remote; -@@ -735,6 +815,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, - void *data) - { - struct platform_device *pdev = to_platform_device(dev); -+ const struct meson_dw_hdmi_data *match; - struct meson_dw_hdmi *meson_dw_hdmi; - struct drm_device *drm = data; - struct meson_drm *priv = drm->dev_private; -@@ -751,6 +832,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, - return -ENODEV; - } - -+ match = of_device_get_match_data(&pdev->dev); -+ if (!match) { -+ dev_err(&pdev->dev, "failed to get match data\n"); -+ return -ENODEV; -+ } -+ - meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), - GFP_KERNEL); - if (!meson_dw_hdmi) -@@ -758,6 +845,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, - - meson_dw_hdmi->priv = priv; - meson_dw_hdmi->dev = dev; -+ meson_dw_hdmi->data = match; - dw_plat_data = &meson_dw_hdmi->dw_plat_data; - encoder = &meson_dw_hdmi->encoder; - -@@ -858,24 +946,28 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, - reset_control_reset(meson_dw_hdmi->hdmitx_phy); - - /* Enable APB3 fail on error */ -- writel_bits_relaxed(BIT(15), BIT(15), -- meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); -- writel_bits_relaxed(BIT(15), BIT(15), -- meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); -+ if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { -+ writel_bits_relaxed(BIT(15), BIT(15), -+ meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); -+ writel_bits_relaxed(BIT(15), BIT(15), -+ meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); -+ } - - /* Bring out of reset */ -- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0); -+ meson_dw_hdmi->data->top_write(meson_dw_hdmi, -+ HDMITX_TOP_SW_RESET, 0); - - msleep(20); - -- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff); -+ meson_dw_hdmi->data->top_write(meson_dw_hdmi, -+ HDMITX_TOP_CLK_CNTL, 0xff); - - /* Enable HDMI-TX Interrupt */ -- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, -- HDMITX_TOP_INTR_CORE); -+ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, -+ HDMITX_TOP_INTR_CORE); - -- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, -- HDMITX_TOP_INTR_CORE); -+ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, -+ HDMITX_TOP_INTR_CORE); - - /* Bridge / Connector */ - -@@ -924,9 +1016,14 @@ static int meson_dw_hdmi_remove(struct platform_device *pdev) - } - - static const struct of_device_id meson_dw_hdmi_of_table[] = { -- { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, -- { .compatible = "amlogic,meson-gxl-dw-hdmi" }, -- { .compatible = "amlogic,meson-gxm-dw-hdmi" }, -+ { .compatible = "amlogic,meson-gxbb-dw-hdmi", -+ .data = &meson_dw_hdmi_gx_data }, -+ { .compatible = "amlogic,meson-gxl-dw-hdmi", -+ .data = &meson_dw_hdmi_gx_data }, -+ { .compatible = "amlogic,meson-gxm-dw-hdmi", -+ .data = &meson_dw_hdmi_gx_data }, -+ { .compatible = "amlogic,meson-g12a-dw-hdmi", -+ .data = &meson_dw_hdmi_g12a_data }, - { } - }; - MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); -diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h -index 0b81183125e33..03e2f0c1a2d50 100644 ---- a/drivers/gpu/drm/meson/meson_dw_hdmi.h -+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h -@@ -21,9 +21,12 @@ - #define __MESON_DW_HDMI_H - - /* -- * Bit 7 RW Reserved. Default 1. -- * Bit 6 RW Reserved. Default 1. -- * Bit 5 RW Reserved. Default 1. -+ * Bit 15-10: RW Reserved. Default 1 starting from G12A -+ * Bit 9 RW sw_reset_i2c starting from G12A -+ * Bit 8 RW sw_reset_axiarb starting from G12A -+ * Bit 7 RW Reserved. Default 1, sw_reset_emp starting from G12A -+ * Bit 6 RW Reserved. Default 1, sw_reset_flt starting from G12A -+ * Bit 5 RW Reserved. Default 1, sw_reset_hdcp22 starting from G12A - * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset. - * Default 1. - * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset; -@@ -39,12 +42,16 @@ - #define HDMITX_TOP_SW_RESET (0x000) - - /* -+ * Bit 31 RW free_clk_en: 0=Enable clock gating for power saving; 1= Disable - * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0. - * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0. - * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0. - * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0. - * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0. -- * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. -+ * Bit 7 RW hdcp22_skpclk_en: starting from G12A, 1=enable; 0=disable -+ * Bit 6 RW hdcp22_esmclk_en: starting from G12A, 1=enable; 0=disable -+ * Bit 5 RW hdcp22_tmdsclk_en: starting from G12A, 1=enable; 0=disable -+ * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. Reserved for G12A - * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0. - * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0. - * Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0. -@@ -53,6 +60,8 @@ - #define HDMITX_TOP_CLK_CNTL (0x001) - - /* -+ * Bit 31:28 RW rxsense_glitch_width: starting from G12A -+ * Bit 27:16 RW rxsense_valid_width: starting from G12A - * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0. - * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0. - */ -@@ -61,6 +70,9 @@ - /* - * intr_maskn: MASK_N, one bit per interrupt source. - * 1=Enable interrupt source; 0=Disable interrupt source. Default 0. -+ * [ 7] rxsense_fall starting from G12A -+ * [ 6] rxsense_rise starting from G12A -+ * [ 5] err_i2c_timeout starting from G12A - * [ 4] hdcp22_rndnum_err - * [ 3] nonce_rfrsh_rise - * [ 2] hpd_fall_intr -@@ -73,6 +85,9 @@ - * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt - * bit, read back the interrupt status. - * Bit 31 R IP interrupt status -+ * Bit 7 RW rxsense_fall starting from G12A -+ * Bit 6 RW rxsense_rise starting from G12A -+ * Bit 5 RW err_i2c_timeout starting from G12A - * Bit 2 RW hpd_fall - * Bit 1 RW hpd_rise - * Bit 0 RW IP interrupt -@@ -80,6 +95,9 @@ - #define HDMITX_TOP_INTR_STAT (0x004) - - /* -+ * [7] rxsense_fall starting from G12A -+ * [6] rxsense_rise starting from G12A -+ * [5] err_i2c_timeout starting from G12A - * [4] hdcp22_rndnum_err - * [3] nonce_rfrsh_rise - * [2] hpd_fall -@@ -91,6 +109,8 @@ - #define HDMITX_TOP_INTR_CORE BIT(0) - #define HDMITX_TOP_INTR_HPD_RISE BIT(1) - #define HDMITX_TOP_INTR_HPD_FALL BIT(2) -+#define HDMITX_TOP_INTR_RXSENSE_RISE BIT(6) -+#define HDMITX_TOP_INTR_RXSENSE_FALL BIT(7) - - /* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; - * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. -@@ -140,7 +160,9 @@ - */ - #define HDMITX_TOP_REVOCMEM_STAT (0x00D) - --/* Bit 0 R filtered HPD status. */ -+/* Bit 1 R filtered RxSense status -+ * Bit 0 R filtered HPD status. -+ */ - #define HDMITX_TOP_STAT0 (0x00E) - - #endif /* __MESON_DW_HDMI_H */ - -From f49c47fd4696e1f2b33c80ca45f8765a650740d2 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 10:39:36 +0100 -Subject: [PATCH 052/249] UPSTREAM: dt-bindings: phy: Add Amlogic G12A USB2 PHY - Bindings - -Add the Amlogic G12A Family USB2 OTG PHY Bindings - -The PHY can work in host or peripheral modes depending on it's position. -Configuration of the mode is part of the USBCTRL registers which are -outside of the PHY registers. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Signed-off-by: Kishon Vijay Abraham I -(cherry picked from commit 7609db4e846b26bab1c259fb025c56f4c262a21a) ---- - .../bindings/phy/meson-g12a-usb2-phy.txt | 22 +++++++++++++++++++ - 1 file changed, 22 insertions(+) - create mode 100644 Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt - -diff --git a/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt -new file mode 100644 -index 0000000000000..a6ebc3dea159f ---- /dev/null -+++ b/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt -@@ -0,0 +1,22 @@ -+* Amlogic G12A USB2 PHY binding -+ -+Required properties: -+- compatible: Should be "amlogic,meson-g12a-usb2-phy" -+- reg: The base address and length of the registers -+- #phys-cells: must be 0 (see phy-bindings.txt in this directory) -+- clocks: a phandle to the clock of this PHY -+- clock-names: must be "xtal" -+- resets: a phandle to the reset line of this PHY -+- reset-names: must be "phy" -+- phy-supply: see phy-bindings.txt in this directory -+ -+Example: -+ usb2_phy0: phy@36000 { -+ compatible = "amlogic,g12a-usb2-phy"; -+ reg = <0x0 0x36000 0x0 0x2000>; -+ clocks = <&xtal>; -+ clock-names = "xtal"; -+ resets = <&reset RESET_USB_PHY21>; -+ reset-names = "phy"; -+ #phy-cells = <0>; -+ }; - -From b9c670240de8260212a7833bdaae470486e492ec Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 10:39:37 +0100 -Subject: [PATCH 053/249] UPSTREAM: dt-bindings: phy: Add Amlogic G12A - USB3+PCIE Combo PHY Bindings - -Add the Amlogic G12A Family USB3 + PCIE Combo PHY Bindings. - -This PHY can provide exclusively USB3 or PCIE support on shared I/Os. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Signed-off-by: Kishon Vijay Abraham I -(cherry picked from commit ab6dbeb24d1a93425b2d1d91b17a7bce79dba41b) ---- - .../bindings/phy/meson-g12a-usb3-pcie-phy.txt | 22 +++++++++++++++++++ - 1 file changed, 22 insertions(+) - create mode 100644 Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt - -diff --git a/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt b/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt -new file mode 100644 -index 0000000000000..7cfc17e2df315 ---- /dev/null -+++ b/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt -@@ -0,0 +1,22 @@ -+* Amlogic G12A USB3 + PCIE Combo PHY binding -+ -+Required properties: -+- compatible: Should be "amlogic,meson-g12a-usb3-pcie-phy" -+- #phys-cells: must be 1. The cell number is used to select the phy mode -+ as defined in between PHY_TYPE_USB3 and PHY_TYPE_PCIE -+- reg: The base address and length of the registers -+- clocks: a phandle to the 100MHz reference clock of this PHY -+- clock-names: must be "ref_clk" -+- resets: phandle to the reset lines for the PHY control -+- reset-names: must be "phy" -+ -+Example: -+ usb3_pcie_phy: phy@46000 { -+ compatible = "amlogic,g12a-usb3-pcie-phy"; -+ reg = <0x0 0x46000 0x0 0x2000>; -+ clocks = <&clkc CLKID_PCIE_PLL>; -+ clock-names = "ref_clk"; -+ resets = <&reset RESET_PCIE_PHY>; -+ reset-names = "phy"; -+ #phy-cells = <1>; -+ }; - -From 8735a1a320370afadec8eb5489f8152e78454ce0 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 10:39:40 +0100 -Subject: [PATCH 054/249] UPSTREAM: phy: amlogic: add Amlogic G12A USB2 PHY - Driver - -This adds support for the USB2 PHY found in the Amlogic G12A SoC Family. - -It supports Host and/or Peripheral mode, depending on it's position. -The first PHY is only used as Host, but the second supports Dual modes -defined by the USB Control Glue HW in front of the USB Controllers. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kishon Vijay Abraham I -(cherry picked from commit 16df8bcb672c45e69a7bf4b37bb6de12c705e195) -Signed-off-by: Neil Armstrong ---- - drivers/phy/amlogic/Kconfig | 11 + - drivers/phy/amlogic/Makefile | 1 + - drivers/phy/amlogic/phy-meson-g12a-usb2.c | 341 ++++++++++++++++++++++ - 3 files changed, 353 insertions(+) - create mode 100644 drivers/phy/amlogic/phy-meson-g12a-usb2.c - -diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig -index 23fe1cda2f70d..560ff0f1ed4c1 100644 ---- a/drivers/phy/amlogic/Kconfig -+++ b/drivers/phy/amlogic/Kconfig -@@ -36,3 +36,14 @@ config PHY_MESON_GXL_USB3 - Enable this to support the Meson USB3 PHY and OTG detection - IP block found in Meson GXL and GXM SoCs. - If unsure, say N. -+ -+config PHY_MESON_G12A_USB2 -+ tristate "Meson G12A USB2 PHY driver" -+ default ARCH_MESON -+ depends on OF && (ARCH_MESON || COMPILE_TEST) -+ select GENERIC_PHY -+ select REGMAP_MMIO -+ help -+ Enable this to support the Meson USB2 PHYs found in Meson -+ G12A SoCs. -+ If unsure, say N. -diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile -index 4fd8848c194d6..7d4d10f5a6b3a 100644 ---- a/drivers/phy/amlogic/Makefile -+++ b/drivers/phy/amlogic/Makefile -@@ -1,3 +1,4 @@ - obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o - obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o -+obj-$(CONFIG_PHY_MESON_G12A_USB2) += phy-meson-g12a-usb2.o - obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o -diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb2.c b/drivers/phy/amlogic/phy-meson-g12a-usb2.c -new file mode 100644 -index 0000000000000..9065ffc85eb47 ---- /dev/null -+++ b/drivers/phy/amlogic/phy-meson-g12a-usb2.c -@@ -0,0 +1,341 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Meson G12A USB2 PHY driver -+ * -+ * Copyright (C) 2017 Martin Blumenstingl -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved -+ * Copyright (C) 2019 BayLibre, SAS -+ * Author: Neil Armstrong -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define PHY_CTRL_R0 0x0 -+#define PHY_CTRL_R1 0x4 -+#define PHY_CTRL_R2 0x8 -+#define PHY_CTRL_R3 0xc -+ #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0) -+ #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2) -+ #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4) -+ -+#define PHY_CTRL_R4 0x10 -+ #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0) -+ #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8) -+ #define PHY_CTRL_R4_CALIB_CODE_23_16 GENMASK(23, 16) -+ #define PHY_CTRL_R4_I_C2L_CAL_EN BIT(24) -+ #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25) -+ #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26) -+ #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27) -+ #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28) -+ #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30) -+ -+#define PHY_CTRL_R5 0x14 -+#define PHY_CTRL_R6 0x18 -+#define PHY_CTRL_R7 0x1c -+#define PHY_CTRL_R8 0x20 -+#define PHY_CTRL_R9 0x24 -+#define PHY_CTRL_R10 0x28 -+#define PHY_CTRL_R11 0x2c -+#define PHY_CTRL_R12 0x30 -+#define PHY_CTRL_R13 0x34 -+ #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0) -+ #define PHY_CTRL_R13_LOAD_STAT BIT(14) -+ #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15) -+ #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16) -+ #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21) -+ #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22) -+ #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23) -+ #define PHY_CTRL_R13_I_C2L_HS_EN BIT(24) -+ #define PHY_CTRL_R13_I_C2L_FS_EN BIT(25) -+ #define PHY_CTRL_R13_I_C2L_LS_EN BIT(26) -+ #define PHY_CTRL_R13_I_C2L_HS_OE BIT(27) -+ #define PHY_CTRL_R13_I_C2L_FS_OE BIT(28) -+ #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29) -+ #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30) -+ -+#define PHY_CTRL_R14 0x38 -+ #define PHY_CTRL_R14_I_RDP_EN BIT(0) -+ #define PHY_CTRL_R14_I_RPU_SW1_EN BIT(1) -+ #define PHY_CTRL_R14_I_RPU_SW2_EN GENMASK(2, 3) -+ #define PHY_CTRL_R14_PG_RSTN BIT(4) -+ #define PHY_CTRL_R14_I_C2L_DATA_16_8 BIT(5) -+ #define PHY_CTRL_R14_I_C2L_ASSERT_SINGLE_EN_ZERO BIT(6) -+ #define PHY_CTRL_R14_BYPASS_CTRL_7_0 GENMASK(15, 8) -+ #define PHY_CTRL_R14_BYPASS_CTRL_15_8 GENMASK(23, 16) -+ -+#define PHY_CTRL_R15 0x3c -+#define PHY_CTRL_R16 0x40 -+ #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0) -+ #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10) -+ #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20) -+ #define PHY_CTRL_R16_MPLL_SDM_EN BIT(21) -+ #define PHY_CTRL_R16_MPLL_LOAD BIT(22) -+ #define PHY_CTRL_R16_MPLL_DCO_SDM_EN BIT(23) -+ #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24) -+ #define PHY_CTRL_R16_MPLL_LOCK_F BIT(26) -+ #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27) -+ #define PHY_CTRL_R16_MPLL_EN BIT(28) -+ #define PHY_CTRL_R16_MPLL_RESET BIT(29) -+ #define PHY_CTRL_R16_MPLL_LOCK BIT(30) -+ #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31) -+ -+#define PHY_CTRL_R17 0x44 -+ #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0) -+ #define PHY_CTRL_R17_MPLL_FIX_EN BIT(16) -+ #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17) -+ #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20) -+ #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23) -+ #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24) -+ #define PHY_CTRL_R17_MPLL_FILTER_PVT1 GENMASK(31, 28) -+ -+#define PHY_CTRL_R18 0x48 -+ #define PHY_CTRL_R18_MPLL_LKW_SEL GENMASK(1, 0) -+ #define PHY_CTRL_R18_MPLL_LK_W GENMASK(5, 2) -+ #define PHY_CTRL_R18_MPLL_LK_S GENMASK(11, 6) -+ #define PHY_CTRL_R18_MPLL_DCO_M_EN BIT(12) -+ #define PHY_CTRL_R18_MPLL_DCO_CLK_SEL BIT(13) -+ #define PHY_CTRL_R18_MPLL_PFD_GAIN GENMASK(15, 14) -+ #define PHY_CTRL_R18_MPLL_ROU GENMASK(18, 16) -+ #define PHY_CTRL_R18_MPLL_DATA_SEL GENMASK(21, 19) -+ #define PHY_CTRL_R18_MPLL_BIAS_ADJ GENMASK(23, 22) -+ #define PHY_CTRL_R18_MPLL_BB_MODE GENMASK(25, 24) -+ #define PHY_CTRL_R18_MPLL_ALPHA GENMASK(28, 26) -+ #define PHY_CTRL_R18_MPLL_ADJ_LDO GENMASK(30, 29) -+ #define PHY_CTRL_R18_MPLL_ACG_RANGE BIT(31) -+ -+#define PHY_CTRL_R19 0x4c -+#define PHY_CTRL_R20 0x50 -+ #define PHY_CTRL_R20_USB2_IDDET_EN BIT(0) -+ #define PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0 GENMASK(3, 1) -+ #define PHY_CTRL_R20_USB2_OTG_VBUSDET_EN BIT(4) -+ #define PHY_CTRL_R20_USB2_AMON_EN BIT(5) -+ #define PHY_CTRL_R20_USB2_CAL_CODE_R5 BIT(6) -+ #define PHY_CTRL_R20_BYPASS_OTG_DET BIT(7) -+ #define PHY_CTRL_R20_USB2_DMON_EN BIT(8) -+ #define PHY_CTRL_R20_USB2_DMON_SEL_3_0 GENMASK(12, 9) -+ #define PHY_CTRL_R20_USB2_EDGE_DRV_EN BIT(13) -+ #define PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0 GENMASK(15, 14) -+ #define PHY_CTRL_R20_USB2_BGR_ADJ_4_0 GENMASK(20, 16) -+ #define PHY_CTRL_R20_USB2_BGR_START BIT(21) -+ #define PHY_CTRL_R20_USB2_BGR_VREF_4_0 GENMASK(28, 24) -+ #define PHY_CTRL_R20_USB2_BGR_DBG_1_0 GENMASK(30, 29) -+ #define PHY_CTRL_R20_BYPASS_CAL_DONE_R5 BIT(31) -+ -+#define PHY_CTRL_R21 0x54 -+ #define PHY_CTRL_R21_USB2_BGR_FORCE BIT(0) -+ #define PHY_CTRL_R21_USB2_CAL_ACK_EN BIT(1) -+ #define PHY_CTRL_R21_USB2_OTG_ACA_EN BIT(2) -+ #define PHY_CTRL_R21_USB2_TX_STRG_PD BIT(3) -+ #define PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0 GENMASK(5, 4) -+ #define PHY_CTRL_R21_BYPASS_UTMI_CNTR GENMASK(15, 6) -+ #define PHY_CTRL_R21_BYPASS_UTMI_REG GENMASK(25, 20) -+ -+#define PHY_CTRL_R22 0x58 -+#define PHY_CTRL_R23 0x5c -+ -+#define RESET_COMPLETE_TIME 1000 -+#define PLL_RESET_COMPLETE_TIME 100 -+ -+struct phy_meson_g12a_usb2_priv { -+ struct device *dev; -+ struct regmap *regmap; -+ struct clk *clk; -+ struct reset_control *reset; -+}; -+ -+static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = { -+ .reg_bits = 8, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = PHY_CTRL_R23, -+}; -+ -+static int phy_meson_g12a_usb2_init(struct phy *phy) -+{ -+ struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); -+ int ret; -+ -+ ret = reset_control_reset(priv->reset); -+ if (ret) -+ return ret; -+ -+ udelay(RESET_COMPLETE_TIME); -+ -+ /* usb2_otg_aca_en == 0 */ -+ regmap_update_bits(priv->regmap, PHY_CTRL_R21, -+ PHY_CTRL_R21_USB2_OTG_ACA_EN, 0); -+ -+ /* PLL Setup : 24MHz * 20 / 1 = 480MHz */ -+ regmap_write(priv->regmap, PHY_CTRL_R16, -+ FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | -+ FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | -+ PHY_CTRL_R16_MPLL_LOAD | -+ FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | -+ PHY_CTRL_R16_MPLL_FAST_LOCK | -+ PHY_CTRL_R16_MPLL_EN | -+ PHY_CTRL_R16_MPLL_RESET); -+ -+ regmap_write(priv->regmap, PHY_CTRL_R17, -+ FIELD_PREP(PHY_CTRL_R17_MPLL_FRAC_IN, 0) | -+ FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA1, 7) | -+ FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA0, 7) | -+ FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | -+ FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); -+ -+ regmap_write(priv->regmap, PHY_CTRL_R18, -+ FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) | -+ FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | -+ PHY_CTRL_R18_MPLL_ACG_RANGE); -+ -+ udelay(PLL_RESET_COMPLETE_TIME); -+ -+ /* UnReset PLL */ -+ regmap_write(priv->regmap, PHY_CTRL_R16, -+ FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | -+ FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | -+ PHY_CTRL_R16_MPLL_LOAD | -+ FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | -+ PHY_CTRL_R16_MPLL_FAST_LOCK | -+ PHY_CTRL_R16_MPLL_EN); -+ -+ /* PHY Tuning */ -+ regmap_write(priv->regmap, PHY_CTRL_R20, -+ FIELD_PREP(PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0, 4) | -+ PHY_CTRL_R20_USB2_OTG_VBUSDET_EN | -+ FIELD_PREP(PHY_CTRL_R20_USB2_DMON_SEL_3_0, 15) | -+ PHY_CTRL_R20_USB2_EDGE_DRV_EN | -+ FIELD_PREP(PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0, 3) | -+ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_ADJ_4_0, 0) | -+ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | -+ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); -+ -+ regmap_write(priv->regmap, PHY_CTRL_R4, -+ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | -+ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | -+ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | -+ PHY_CTRL_R4_TEST_BYPASS_MODE_EN | -+ FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | -+ FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); -+ -+ /* Tuning Disconnect Threshold */ -+ regmap_write(priv->regmap, PHY_CTRL_R3, -+ FIELD_PREP(PHY_CTRL_R3_SQUELCH_REF, 0) | -+ FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) | -+ FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3)); -+ -+ /* Analog Settings */ -+ regmap_write(priv->regmap, PHY_CTRL_R14, 0); -+ regmap_write(priv->regmap, PHY_CTRL_R13, -+ PHY_CTRL_R13_UPDATE_PMA_SIGNALS | -+ FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); -+ -+ return 0; -+} -+ -+static int phy_meson_g12a_usb2_exit(struct phy *phy) -+{ -+ struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); -+ -+ return reset_control_reset(priv->reset); -+} -+ -+/* set_mode is not needed, mode setting is handled via the UTMI bus */ -+static const struct phy_ops phy_meson_g12a_usb2_ops = { -+ .init = phy_meson_g12a_usb2_init, -+ .exit = phy_meson_g12a_usb2_exit, -+ .owner = THIS_MODULE, -+}; -+ -+static int phy_meson_g12a_usb2_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct phy_provider *phy_provider; -+ struct resource *res; -+ struct phy_meson_g12a_usb2_priv *priv; -+ struct phy *phy; -+ void __iomem *base; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->dev = dev; -+ platform_set_drvdata(pdev, priv); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ priv->regmap = devm_regmap_init_mmio(dev, base, -+ &phy_meson_g12a_usb2_regmap_conf); -+ if (IS_ERR(priv->regmap)) -+ return PTR_ERR(priv->regmap); -+ -+ priv->clk = devm_clk_get(dev, "xtal"); -+ if (IS_ERR(priv->clk)) -+ return PTR_ERR(priv->clk); -+ -+ priv->reset = devm_reset_control_get(dev, "phy"); -+ if (IS_ERR(priv->reset)) -+ return PTR_ERR(priv->reset); -+ -+ ret = reset_control_deassert(priv->reset); -+ if (ret) -+ return ret; -+ -+ phy = devm_phy_create(dev, NULL, &phy_meson_g12a_usb2_ops); -+ if (IS_ERR(phy)) { -+ ret = PTR_ERR(phy); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to create PHY\n"); -+ -+ return ret; -+ } -+ -+ phy_set_bus_width(phy, 8); -+ phy_set_drvdata(phy, priv); -+ -+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -+ -+ return PTR_ERR_OR_ZERO(phy_provider); -+} -+ -+static const struct of_device_id phy_meson_g12a_usb2_of_match[] = { -+ { .compatible = "amlogic,g12a-usb2-phy", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, phy_meson_g12a_usb2_of_match); -+ -+static struct platform_driver phy_meson_g12a_usb2_driver = { -+ .probe = phy_meson_g12a_usb2_probe, -+ .driver = { -+ .name = "phy-meson-g12a-usb2", -+ .of_match_table = phy_meson_g12a_usb2_of_match, -+ }, -+}; -+module_platform_driver(phy_meson_g12a_usb2_driver); -+ -+MODULE_AUTHOR("Martin Blumenstingl "); -+MODULE_AUTHOR("Neil Armstrong "); -+MODULE_DESCRIPTION("Meson G12A USB2 PHY driver"); -+MODULE_LICENSE("GPL v2"); - -From 0a20d973f2620cee04b7003d908192c5917a08a9 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 10:39:41 +0100 -Subject: [PATCH 055/249] UPSTREAM: phy: amlogic: Add Amlogic G12A USB3 + PCIE - Combo PHY Driver - -This adds support for the shared USB3 + PCIE PHY found in the -Amlogic G12A SoC Family. - -It supports USB3 Host mode or PCIE 2.0 mode, depending on the layout of -the board. - -Selection is done by the #phy-cells, making the mode static and exclusive. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kishon Vijay Abraham I -(cherry picked from commit 36077e16c050d1b063cdfec8c1d38d51d112f86d) ---- - drivers/phy/amlogic/Kconfig | 11 + - drivers/phy/amlogic/Makefile | 1 + - .../phy/amlogic/phy-meson-g12a-usb3-pcie.c | 413 ++++++++++++++++++ - 3 files changed, 425 insertions(+) - create mode 100644 drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c - -diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig -index 560ff0f1ed4c1..4c08c1ccdd049 100644 ---- a/drivers/phy/amlogic/Kconfig -+++ b/drivers/phy/amlogic/Kconfig -@@ -47,3 +47,14 @@ config PHY_MESON_G12A_USB2 - Enable this to support the Meson USB2 PHYs found in Meson - G12A SoCs. - If unsure, say N. -+ -+config PHY_MESON_G12A_USB3_PCIE -+ tristate "Meson G12A USB3+PCIE Combo PHY driver" -+ default ARCH_MESON -+ depends on OF && (ARCH_MESON || COMPILE_TEST) -+ select GENERIC_PHY -+ select REGMAP_MMIO -+ help -+ Enable this to support the Meson USB3 + PCIE Combo PHY found -+ in Meson G12A SoCs. -+ If unsure, say N. -diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile -index 7d4d10f5a6b3a..fdd008e1b19b6 100644 ---- a/drivers/phy/amlogic/Makefile -+++ b/drivers/phy/amlogic/Makefile -@@ -2,3 +2,4 @@ obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o - obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o - obj-$(CONFIG_PHY_MESON_G12A_USB2) += phy-meson-g12a-usb2.o - obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o -+obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE) += phy-meson-g12a-usb3-pcie.o -diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c -new file mode 100644 -index 0000000000000..6233a7979a931 ---- /dev/null -+++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c -@@ -0,0 +1,413 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Amlogic G12A USB3 + PCIE Combo PHY driver -+ * -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved -+ * Copyright (C) 2019 BayLibre, SAS -+ * Author: Neil Armstrong -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define PHY_R0 0x00 -+ #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0) -+ #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5) -+ -+#define PHY_R1 0x04 -+ #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0) -+ #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5) -+ #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10) -+ #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13) -+ #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16) -+ #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21) -+ #define PHY_R1_PHY_REF_CLKDIV2 BIT(24) -+ #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25) -+ -+#define PHY_R2 0x08 -+ #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0) -+ #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6) -+ #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12) -+ #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18) -+ -+#define PHY_R4 0x10 -+ #define PHY_R4_PHY_CR_WRITE BIT(0) -+ #define PHY_R4_PHY_CR_READ BIT(1) -+ #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2) -+ #define PHY_R4_PHY_CR_CAP_DATA BIT(18) -+ #define PHY_R4_PHY_CR_CAP_ADDR BIT(19) -+ -+#define PHY_R5 0x14 -+ #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0) -+ #define PHY_R5_PHY_CR_ACK BIT(16) -+ #define PHY_R5_PHY_BS_OUT BIT(17) -+ -+struct phy_g12a_usb3_pcie_priv { -+ struct regmap *regmap; -+ struct regmap *regmap_cr; -+ struct clk *clk_ref; -+ struct reset_control *reset; -+ struct phy *phy; -+ unsigned int mode; -+}; -+ -+static const struct regmap_config phy_g12a_usb3_pcie_regmap_conf = { -+ .reg_bits = 8, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = PHY_R5, -+}; -+ -+static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv, -+ unsigned int addr) -+{ -+ unsigned int val, reg; -+ int ret; -+ -+ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr); -+ -+ regmap_write(priv->regmap, PHY_R4, reg); -+ regmap_write(priv->regmap, PHY_R4, reg); -+ -+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ (val & PHY_R5_PHY_CR_ACK), -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ regmap_write(priv->regmap, PHY_R4, reg); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ !(val & PHY_R5_PHY_CR_ACK), -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int phy_g12a_usb3_pcie_cr_bus_read(void *context, unsigned int addr, -+ unsigned int *data) -+{ -+ struct phy_g12a_usb3_pcie_priv *priv = context; -+ unsigned int val; -+ int ret; -+ -+ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); -+ if (ret) -+ return ret; -+ -+ regmap_write(priv->regmap, PHY_R4, 0); -+ regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ (val & PHY_R5_PHY_CR_ACK), -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val); -+ -+ regmap_write(priv->regmap, PHY_R4, 0); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ !(val & PHY_R5_PHY_CR_ACK), -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int phy_g12a_usb3_pcie_cr_bus_write(void *context, unsigned int addr, -+ unsigned int data) -+{ -+ struct phy_g12a_usb3_pcie_priv *priv = context; -+ unsigned int val, reg; -+ int ret; -+ -+ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); -+ if (ret) -+ return ret; -+ -+ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data); -+ -+ regmap_write(priv->regmap, PHY_R4, reg); -+ regmap_write(priv->regmap, PHY_R4, reg); -+ -+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ (val & PHY_R5_PHY_CR_ACK), -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ regmap_write(priv->regmap, PHY_R4, reg); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ (val & PHY_R5_PHY_CR_ACK) == 0, -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ regmap_write(priv->regmap, PHY_R4, reg); -+ -+ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ (val & PHY_R5_PHY_CR_ACK), -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ regmap_write(priv->regmap, PHY_R4, reg); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, -+ (val & PHY_R5_PHY_CR_ACK) == 0, -+ 5, 1000); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = { -+ .reg_bits = 16, -+ .val_bits = 16, -+ .reg_read = phy_g12a_usb3_pcie_cr_bus_read, -+ .reg_write = phy_g12a_usb3_pcie_cr_bus_write, -+ .max_register = 0xffff, -+ .fast_io = true, -+}; -+ -+static int phy_g12a_usb3_init(struct phy *phy) -+{ -+ struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); -+ int data, ret; -+ -+ /* Switch PHY to USB3 */ -+ /* TODO figure out how to handle when PCIe was set in the bootloader */ -+ regmap_update_bits(priv->regmap, PHY_R0, -+ PHY_R0_PCIE_USB3_SWITCH, -+ PHY_R0_PCIE_USB3_SWITCH); -+ -+ /* -+ * WORKAROUND: There is SSPHY suspend bug due to -+ * which USB enumerates -+ * in HS mode instead of SS mode. Workaround it by asserting -+ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus -+ * mode -+ */ -+ ret = regmap_update_bits(priv->regmap_cr, 0x102d, BIT(7), BIT(7)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_update_bits(priv->regmap_cr, 0x1010, 0xff0, 20); -+ if (ret) -+ return ret; -+ -+ /* -+ * Fix RX Equalization setting as follows -+ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 -+ */ -+ ret = regmap_read(priv->regmap_cr, 0x1006, &data); -+ if (ret) -+ return ret; -+ -+ data &= ~BIT(6); -+ data |= BIT(7); -+ data &= ~(0x7 << 8); -+ data |= (0x3 << 8); -+ data |= (1 << 11); -+ ret = regmap_write(priv->regmap_cr, 0x1006, data); -+ if (ret) -+ return ret; -+ -+ /* -+ * Set EQ and TX launch amplitudes as follows -+ * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 -+ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 -+ * LANE0.TX_OVRD_DRV_LO.EN set to 1. -+ */ -+ ret = regmap_read(priv->regmap_cr, 0x1002, &data); -+ if (ret) -+ return ret; -+ -+ data &= ~0x3f80; -+ data |= (0x16 << 7); -+ data &= ~0x7f; -+ data |= (0x7f | BIT(14)); -+ ret = regmap_write(priv->regmap_cr, 0x1002, data); -+ if (ret) -+ return ret; -+ -+ /* MPLL_LOOP_CTL.PROP_CNTRL = 8 */ -+ ret = regmap_update_bits(priv->regmap_cr, 0x30, 0xf << 4, 8 << 4); -+ if (ret) -+ return ret; -+ -+ regmap_update_bits(priv->regmap, PHY_R2, -+ PHY_R2_PHY_TX_VBOOST_LVL, -+ FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4)); -+ -+ regmap_update_bits(priv->regmap, PHY_R1, -+ PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL, -+ FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) | -+ FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9)); -+ -+ return 0; -+} -+ -+static int phy_g12a_usb3_pcie_init(struct phy *phy) -+{ -+ struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); -+ int ret; -+ -+ ret = reset_control_reset(priv->reset); -+ if (ret) -+ return ret; -+ -+ if (priv->mode == PHY_TYPE_USB3) -+ return phy_g12a_usb3_init(phy); -+ -+ /* Power UP PCIE */ -+ /* TODO figure out when the bootloader has set USB3 mode before */ -+ regmap_update_bits(priv->regmap, PHY_R0, -+ PHY_R0_PCIE_POWER_STATE, -+ FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c)); -+ -+ return 0; -+} -+ -+static int phy_g12a_usb3_pcie_exit(struct phy *phy) -+{ -+ struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); -+ -+ return reset_control_reset(priv->reset); -+} -+ -+static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, -+ struct of_phandle_args *args) -+{ -+ struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); -+ unsigned int mode; -+ -+ if (args->args_count < 1) { -+ dev_err(dev, "invalid number of arguments\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ mode = args->args[0]; -+ -+ if (mode != PHY_TYPE_USB3 && mode != PHY_TYPE_PCIE) { -+ dev_err(dev, "invalid phy mode select argument\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ priv->mode = mode; -+ -+ return priv->phy; -+} -+ -+static const struct phy_ops phy_g12a_usb3_pcie_ops = { -+ .init = phy_g12a_usb3_pcie_init, -+ .exit = phy_g12a_usb3_pcie_exit, -+ .owner = THIS_MODULE, -+}; -+ -+static int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct phy_g12a_usb3_pcie_priv *priv; -+ struct resource *res; -+ struct phy_provider *phy_provider; -+ void __iomem *base; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ priv->regmap = devm_regmap_init_mmio(dev, base, -+ &phy_g12a_usb3_pcie_regmap_conf); -+ if (IS_ERR(priv->regmap)) -+ return PTR_ERR(priv->regmap); -+ -+ priv->regmap_cr = devm_regmap_init(dev, NULL, priv, -+ &phy_g12a_usb3_pcie_cr_regmap_conf); -+ if (IS_ERR(priv->regmap_cr)) -+ return PTR_ERR(priv->regmap_cr); -+ -+ priv->clk_ref = devm_clk_get(dev, "ref_clk"); -+ if (IS_ERR(priv->clk_ref)) -+ return PTR_ERR(priv->clk_ref); -+ -+ ret = clk_prepare_enable(priv->clk_ref); -+ if (ret) -+ goto err_disable_clk_ref; -+ -+ priv->reset = devm_reset_control_array_get(dev, false, false); -+ if (IS_ERR(priv->reset)) -+ return PTR_ERR(priv->reset); -+ -+ priv->phy = devm_phy_create(dev, np, &phy_g12a_usb3_pcie_ops); -+ if (IS_ERR(priv->phy)) { -+ ret = PTR_ERR(priv->phy); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to create PHY\n"); -+ -+ return ret; -+ } -+ -+ phy_set_drvdata(priv->phy, priv); -+ dev_set_drvdata(dev, priv); -+ -+ phy_provider = devm_of_phy_provider_register(dev, -+ phy_g12a_usb3_pcie_xlate); -+ -+ return PTR_ERR_OR_ZERO(phy_provider); -+ -+err_disable_clk_ref: -+ clk_disable_unprepare(priv->clk_ref); -+ -+ return ret; -+} -+ -+static const struct of_device_id phy_g12a_usb3_pcie_of_match[] = { -+ { .compatible = "amlogic,g12a-usb3-pcie-phy", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, phy_g12a_usb3_pcie_of_match); -+ -+static struct platform_driver phy_g12a_usb3_pcie_driver = { -+ .probe = phy_g12a_usb3_pcie_probe, -+ .driver = { -+ .name = "phy-g12a-usb3-pcie", -+ .of_match_table = phy_g12a_usb3_pcie_of_match, -+ }, -+}; -+module_platform_driver(phy_g12a_usb3_pcie_driver); -+ -+MODULE_AUTHOR("Neil Armstrong "); -+MODULE_DESCRIPTION("Amlogic G12A USB3 + PCIE Combo PHY driver"); -+MODULE_LICENSE("GPL v2"); - -From 9db5bf0097baa3fa7f555124e37c0ecdd753e9bc Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 23 Apr 2019 10:51:24 +0200 -Subject: [PATCH 056/249] UPSTREAM: dt-bindings: usb: dwc2: Add Amlogic G12A - DWC2 Compatible - -Adds the specific compatible string for the DWC2 IP found in the -Amlogic G12A SoC Family. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Signed-off-by: Felipe Balbi -(cherry picked from commit 7a76b97325c2cc6c6599a2b3b15d32aebf2f48ee) ---- - Documentation/devicetree/bindings/usb/dwc2.txt | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt -index 6dc3c4a344830..e150b7b227c9e 100644 ---- a/Documentation/devicetree/bindings/usb/dwc2.txt -+++ b/Documentation/devicetree/bindings/usb/dwc2.txt -@@ -14,6 +14,7 @@ Required properties: - - "amlogic,meson8-usb": The DWC2 USB controller instance in Amlogic Meson8 SoCs; - - "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs; - - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs; -+ - "amlogic,meson-g12a-usb": The DWC2 USB controller instance in Amlogic G12A SoCs; - - "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs; - - snps,dwc2: A generic DWC2 USB controller with default parameters. - - "st,stm32f4x9-fsotg": The DWC2 USB FS/HS controller instance in STM32F4x9 SoCs - -From e5bf510e9ea3fd8f36b9279506829c601d6882df Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 23 Apr 2019 10:51:25 +0200 -Subject: [PATCH 057/249] UPSTREAM: dt-bindings: usb: dwc3: Add Amlogic G12A - DWC3 Glue Bindings - -Adds the bindings for the Amlogic G12A USB Glue HW. - -The Amlogic G12A SoC Family embeds 2 USB Controllers : -- a DWC3 IP configured as Host for USB2 and USB3 -- a DWC2 IP configured as Peripheral USB2 Only - -A glue connects these both controllers to 2 USB2 PHYs, -and optionnally to an USB3+PCIE Combo PHY shared with the PCIE controller. - -The Glue configures the UTMI 8bit interfaces for the USB2 PHYs, including -routing of the OTG PHY between the DWC3 and DWC2 controllers, and -setups the on-chip OTG mode selection for this PHY. - -The PHYs phandles are passed to the Glue node since the Glue controls the -interface with the PHY, not the DWC3 controller. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Signed-off-by: Felipe Balbi -(cherry picked from commit e8c77fa091808c7e27ad15c7256743b6c2406b02) ---- - .../devicetree/bindings/usb/amlogic,dwc3.txt | 88 +++++++++++++++++++ - 1 file changed, 88 insertions(+) - -diff --git a/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt -index 9a8b631904fd6..b9f04e617eb77 100644 ---- a/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt -+++ b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt -@@ -40,3 +40,91 @@ Example device nodes: - phy-names = "usb2-phy", "usb3-phy"; - }; - }; -+ -+Amlogic Meson G12A DWC3 USB SoC Controller Glue -+ -+The Amlogic G12A embeds a DWC3 USB IP Core configured for USB2 and USB3 -+in host-only mode, and a DWC2 IP Core configured for USB2 peripheral mode -+only. -+ -+A glue connects the DWC3 core to USB2 PHYs and optionnaly to an USB3 PHY. -+ -+One of the USB2 PHY can be re-routed in peripheral mode to a DWC2 USB IP. -+ -+The DWC3 Glue controls the PHY routing and power, an interrupt line is -+connected to the Glue to serve as OTG ID change detection. -+ -+Required properties: -+- compatible: Should be "amlogic,meson-g12a-usb-ctrl" -+- clocks: a handle for the "USB" clock -+- resets: a handle for the shared "USB" reset line -+- reg: The base address and length of the registers -+- interrupts: the interrupt specifier for the OTG detection -+- phys: handle to used PHYs on the system -+ - a <0> phandle can be used if a PHY is not used -+- phy-names: names of the used PHYs on the system : -+ - "usb2-phy0" for USB2 PHY0 if USBHOST_A port is used -+ - "usb2-phy1" for USB2 PHY1 if USBOTG_B port is used -+ - "usb3-phy0" for USB3 PHY if USB3_0 is used -+- dr_mode: should be "host", "peripheral", or "otg" depending on -+ the usage and configuration of the OTG Capable port. -+ - "host" and "peripheral" means a fixed Host or Device only connection -+ - "otg" means the port can be used as both Host or Device and -+ be switched automatically using the OTG ID pin. -+ -+Optional properties: -+- vbus-supply: should be a phandle to the regulator controlling the VBUS -+ power supply when used in OTG switchable mode -+ -+Required child nodes: -+ -+A child node must exist to represent the core DWC3 IP block. The name of -+the node is not important. The content of the node is defined in dwc3.txt. -+ -+A child node must exist to represent the core DWC2 IP block. The name of -+the node is not important. The content of the node is defined in dwc2.txt. -+ -+PHY documentation is provided in the following places: -+- Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt -+- Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt -+ -+Example device nodes: -+ usb: usb@ffe09000 { -+ compatible = "amlogic,meson-g12a-usb-ctrl"; -+ reg = <0x0 0xffe09000 0x0 0xa0>; -+ interrupts = ; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ clocks = <&clkc CLKID_USB>; -+ resets = <&reset RESET_USB>; -+ -+ dr_mode = "otg"; -+ -+ phys = <&usb2_phy0>, <&usb2_phy1>, -+ <&usb3_pcie_phy PHY_TYPE_USB3>; -+ phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; -+ -+ dwc2: usb@ff400000 { -+ compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; -+ reg = <0x0 0xff400000 0x0 0x40000>; -+ interrupts = ; -+ clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; -+ clock-names = "ddr"; -+ phys = <&usb2_phy1>; -+ dr_mode = "peripheral"; -+ g-rx-fifo-size = <192>; -+ g-np-tx-fifo-size = <128>; -+ g-tx-fifo-size = <128 128 16 16 16>; -+ }; -+ -+ dwc3: usb@ff500000 { -+ compatible = "snps,dwc3"; -+ reg = <0x0 0xff500000 0x0 0x100000>; -+ interrupts = ; -+ dr_mode = "host"; -+ snps,dis_u2_susphy_quirk; -+ snps,quirk-frame-length-adjustment; -+ }; -+ }; - -From cca7872a15fdb519d0e332d28eaf56440447978b Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 23 Apr 2019 10:51:26 +0200 -Subject: [PATCH 058/249] UPSTREAM: usb: dwc2: Add Amlogic G12A DWC2 Params - -This patchs sets the params for the DWC2 Controller found in the -Amlogic G12A SoC family. - -It mainly sets the settings reported incorrect by the driver, -leaving the remaining detected automatically by the driver and -provided by the DT node. - -Signed-off-by: Neil Armstrong -Acked-by: Minas Harutyunyan -Signed-off-by: Felipe Balbi -(cherry picked from commit fc4e326ee72cc36c942333c65d851247b31c567b) ---- - drivers/usb/dwc2/params.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c -index 24ff5f21cb25d..442113246cba6 100644 ---- a/drivers/usb/dwc2/params.c -+++ b/drivers/usb/dwc2/params.c -@@ -121,6 +121,16 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) - p->power_down = DWC2_POWER_DOWN_PARAM_NONE; - } - -+static void dwc2_set_amlogic_g12a_params(struct dwc2_hsotg *hsotg) -+{ -+ struct dwc2_core_params *p = &hsotg->params; -+ -+ p->lpm = false; -+ p->lpm_clock_gating = false; -+ p->besl = false; -+ p->hird_threshold_en = false; -+} -+ - static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) - { - struct dwc2_core_params *p = &hsotg->params; -@@ -167,6 +177,8 @@ const struct of_device_id dwc2_of_match_table[] = { - .data = dwc2_set_amlogic_params }, - { .compatible = "amlogic,meson-gxbb-usb", - .data = dwc2_set_amlogic_params }, -+ { .compatible = "amlogic,meson-g12a-usb", -+ .data = dwc2_set_amlogic_g12a_params }, - { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, - { .compatible = "st,stm32f4x9-fsotg", - .data = dwc2_set_stm32f4x9_fsotg_params }, - -From 80ef089553065260869056a4ed3e9351c127cab0 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 23 Apr 2019 10:51:27 +0200 -Subject: [PATCH 059/249] UPSTREAM: usb: dwc3: Add Amlogic G12A DWC3 glue - -Adds support for Amlogic G12A USB Control Glue HW. - -The Amlogic G12A SoC Family embeds 2 USB Controllers : -- a DWC3 IP configured as Host for USB2 and USB3 -- a DWC2 IP configured as Peripheral USB2 Only - -A glue connects these both controllers to 2 USB2 PHYs, and optionnally -to an USB3+PCIE Combo PHY shared with the PCIE controller. - -The Glue configures the UTMI 8bit interfaces for the USB2 PHYs, including -routing of the OTG PHY between the DWC3 and DWC2 controllers, and -setups the on-chip OTG mode selection for this PHY. - -This drivers supports the on-probe setup of the OTG mode, and manually -via a debugfs interface. The IRQ mode change detect is yet to be added -in a future patchset, mainly due to lack of hardware to validate on. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Felipe Balbi -(cherry picked from commit c99993376f72ca3dcc989813512607c6435cbed8) ---- - drivers/usb/dwc3/Kconfig | 10 + - drivers/usb/dwc3/Makefile | 1 + - drivers/usb/dwc3/dwc3-meson-g12a.c | 604 +++++++++++++++++++++++++++++ - 3 files changed, 615 insertions(+) - create mode 100644 drivers/usb/dwc3/dwc3-meson-g12a.c - -diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig -index 2b1494460d0cb..d2ea9670563cb 100644 ---- a/drivers/usb/dwc3/Kconfig -+++ b/drivers/usb/dwc3/Kconfig -@@ -95,6 +95,16 @@ config USB_DWC3_KEYSTONE - Support of USB2/3 functionality in TI Keystone2 and AM654 platforms. - Say 'Y' or 'M' here if you have one such device - -+config USB_DWC3_MESON_G12A -+ tristate "Amlogic Meson G12A Platforms" -+ depends on OF && COMMON_CLK -+ depends on ARCH_MESON || COMPILE_TEST -+ default USB_DWC3 -+ select USB_ROLE_SWITCH -+ help -+ Support USB2/3 functionality in Amlogic G12A platforms. -+ Say 'Y' or 'M' if you have one such device. -+ - config USB_DWC3_OF_SIMPLE - tristate "Generic OF Simple Glue Layer" - depends on OF && COMMON_CLK -diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile -index 6e3ef6144e5d9..ae86da0dc5bd1 100644 ---- a/drivers/usb/dwc3/Makefile -+++ b/drivers/usb/dwc3/Makefile -@@ -47,6 +47,7 @@ obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o - obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o - obj-$(CONFIG_USB_DWC3_HAPS) += dwc3-haps.o - obj-$(CONFIG_USB_DWC3_KEYSTONE) += dwc3-keystone.o -+obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o - obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o - obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o - obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o -diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c -new file mode 100644 -index 0000000000000..2aec31a2eacbd ---- /dev/null -+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c -@@ -0,0 +1,604 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * USB Glue for Amlogic G12A SoCs -+ * -+ * Copyright (c) 2019 BayLibre, SAS -+ * Author: Neil Armstrong -+ */ -+ -+/* -+ * The USB is organized with a glue around the DWC3 Controller IP as : -+ * - Control registers for each USB2 Ports -+ * - Control registers for the USB PHY layer -+ * - SuperSpeed PHY can be enabled only if port is used -+ * -+ * TOFIX: -+ * - Add dynamic OTG switching with ID change interrupt -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* USB2 Ports Control Registers */ -+ -+#define U2P_REG_SIZE 0x20 -+ -+#define U2P_R0 0x0 -+ #define U2P_R0_HOST_DEVICE BIT(0) -+ #define U2P_R0_POWER_OK BIT(1) -+ #define U2P_R0_HAST_MODE BIT(2) -+ #define U2P_R0_POWER_ON_RESET BIT(3) -+ #define U2P_R0_ID_PULLUP BIT(4) -+ #define U2P_R0_DRV_VBUS BIT(5) -+ -+#define U2P_R1 0x4 -+ #define U2P_R1_PHY_READY BIT(0) -+ #define U2P_R1_ID_DIG BIT(1) -+ #define U2P_R1_OTG_SESSION_VALID BIT(2) -+ #define U2P_R1_VBUS_VALID BIT(3) -+ -+/* USB Glue Control Registers */ -+ -+#define USB_R0 0x80 -+ #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17) -+ #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18) -+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19) -+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29) -+ #define USB_R0_U2D_ACT BIT(31) -+ -+#define USB_R1 0x84 -+ #define USB_R1_U3H_BIGENDIAN_GS BIT(0) -+ #define USB_R1_U3H_PME_ENABLE BIT(1) -+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2) -+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7) -+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12) -+ #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16) -+ #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17) -+ #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18) -+ #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19) -+ #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25) -+ -+#define USB_R2 0x88 -+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20) -+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26) -+ -+#define USB_R3 0x8c -+ #define USB_R3_P30_SSC_ENABLE BIT(0) -+ #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1) -+ #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4) -+ #define USB_R3_P30_REF_SSP_EN BIT(13) -+ -+#define USB_R4 0x90 -+ #define USB_R4_P21_PORT_RESET_0 BIT(0) -+ #define USB_R4_P21_SLEEP_M0 BIT(1) -+ #define USB_R4_MEM_PD_MASK GENMASK(3, 2) -+ #define USB_R4_P21_ONLY BIT(4) -+ -+#define USB_R5 0x94 -+ #define USB_R5_ID_DIG_SYNC BIT(0) -+ #define USB_R5_ID_DIG_REG BIT(1) -+ #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2) -+ #define USB_R5_ID_DIG_EN_0 BIT(4) -+ #define USB_R5_ID_DIG_EN_1 BIT(5) -+ #define USB_R5_ID_DIG_CURR BIT(6) -+ #define USB_R5_ID_DIG_IRQ BIT(7) -+ #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8) -+ #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16) -+ -+enum { -+ USB2_HOST_PHY = 0, -+ USB2_OTG_PHY, -+ USB3_HOST_PHY, -+ PHY_COUNT, -+}; -+ -+static const char *phy_names[PHY_COUNT] = { -+ "usb2-phy0", "usb2-phy1", "usb3-phy0", -+}; -+ -+struct dwc3_meson_g12a { -+ struct device *dev; -+ struct regmap *regmap; -+ struct clk *clk; -+ struct reset_control *reset; -+ struct phy *phys[PHY_COUNT]; -+ enum usb_dr_mode otg_mode; -+ enum phy_mode otg_phy_mode; -+ unsigned int usb2_ports; -+ unsigned int usb3_ports; -+ struct regulator *vbus; -+ struct usb_role_switch_desc switch_desc; -+ struct usb_role_switch *role_switch; -+}; -+ -+static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv, -+ int i, enum phy_mode mode) -+{ -+ if (mode == PHY_MODE_USB_HOST) -+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), -+ U2P_R0_HOST_DEVICE, -+ U2P_R0_HOST_DEVICE); -+ else -+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), -+ U2P_R0_HOST_DEVICE, 0); -+} -+ -+static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv) -+{ -+ int i; -+ -+ if (priv->otg_mode == USB_DR_MODE_PERIPHERAL) -+ priv->otg_phy_mode = PHY_MODE_USB_DEVICE; -+ else -+ priv->otg_phy_mode = PHY_MODE_USB_HOST; -+ -+ for (i = 0 ; i < USB3_HOST_PHY ; ++i) { -+ if (!priv->phys[i]) -+ continue; -+ -+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), -+ U2P_R0_POWER_ON_RESET, -+ U2P_R0_POWER_ON_RESET); -+ -+ if (i == USB2_OTG_PHY) { -+ regmap_update_bits(priv->regmap, -+ U2P_R0 + (U2P_REG_SIZE * i), -+ U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, -+ U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS); -+ -+ dwc3_meson_g12a_usb2_set_mode(priv, i, -+ priv->otg_phy_mode); -+ } else -+ dwc3_meson_g12a_usb2_set_mode(priv, i, -+ PHY_MODE_USB_HOST); -+ -+ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), -+ U2P_R0_POWER_ON_RESET, 0); -+ } -+ -+ return 0; -+} -+ -+static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv) -+{ -+ regmap_update_bits(priv->regmap, USB_R3, -+ USB_R3_P30_SSC_RANGE_MASK | -+ USB_R3_P30_REF_SSP_EN, -+ USB_R3_P30_SSC_ENABLE | -+ FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) | -+ USB_R3_P30_REF_SSP_EN); -+ udelay(2); -+ -+ regmap_update_bits(priv->regmap, USB_R2, -+ USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, -+ FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15)); -+ -+ regmap_update_bits(priv->regmap, USB_R2, -+ USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, -+ FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20)); -+ -+ udelay(2); -+ -+ regmap_update_bits(priv->regmap, USB_R1, -+ USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT, -+ USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); -+ -+ regmap_update_bits(priv->regmap, USB_R1, -+ USB_R1_P30_PCS_TX_SWING_FULL_MASK, -+ FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127)); -+} -+ -+static void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a *priv) -+{ -+ if (priv->otg_phy_mode == PHY_MODE_USB_DEVICE) { -+ regmap_update_bits(priv->regmap, USB_R0, -+ USB_R0_U2D_ACT, USB_R0_U2D_ACT); -+ regmap_update_bits(priv->regmap, USB_R0, -+ USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0); -+ regmap_update_bits(priv->regmap, USB_R4, -+ USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0); -+ } else { -+ regmap_update_bits(priv->regmap, USB_R0, -+ USB_R0_U2D_ACT, 0); -+ regmap_update_bits(priv->regmap, USB_R4, -+ USB_R4_P21_SLEEP_M0, 0); -+ } -+} -+ -+static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv) -+{ -+ int ret; -+ -+ ret = dwc3_meson_g12a_usb2_init(priv); -+ if (ret) -+ return ret; -+ -+ regmap_update_bits(priv->regmap, USB_R1, -+ USB_R1_U3H_FLADJ_30MHZ_REG_MASK, -+ FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20)); -+ -+ regmap_update_bits(priv->regmap, USB_R5, -+ USB_R5_ID_DIG_EN_0, -+ USB_R5_ID_DIG_EN_0); -+ regmap_update_bits(priv->regmap, USB_R5, -+ USB_R5_ID_DIG_EN_1, -+ USB_R5_ID_DIG_EN_1); -+ regmap_update_bits(priv->regmap, USB_R5, -+ USB_R5_ID_DIG_TH_MASK, -+ FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff)); -+ -+ /* If we have an actual SuperSpeed port, initialize it */ -+ if (priv->usb3_ports) -+ dwc3_meson_g12a_usb3_init(priv); -+ -+ dwc3_meson_g12a_usb_otg_apply_mode(priv); -+ -+ return 0; -+} -+ -+static const struct regmap_config phy_meson_g12a_usb3_regmap_conf = { -+ .reg_bits = 8, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = USB_R5, -+}; -+ -+static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) -+{ -+ int i; -+ -+ for (i = 0 ; i < PHY_COUNT ; ++i) { -+ priv->phys[i] = devm_phy_optional_get(priv->dev, phy_names[i]); -+ if (!priv->phys[i]) -+ continue; -+ -+ if (IS_ERR(priv->phys[i])) -+ return PTR_ERR(priv->phys[i]); -+ -+ if (i == USB3_HOST_PHY) -+ priv->usb3_ports++; -+ else -+ priv->usb2_ports++; -+ } -+ -+ dev_info(priv->dev, "USB2 ports: %d\n", priv->usb2_ports); -+ dev_info(priv->dev, "USB3 ports: %d\n", priv->usb3_ports); -+ -+ return 0; -+} -+ -+static enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv) -+{ -+ u32 reg; -+ -+ regmap_read(priv->regmap, USB_R5, ®); -+ -+ if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG)) -+ return PHY_MODE_USB_DEVICE; -+ -+ return PHY_MODE_USB_HOST; -+} -+ -+static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, -+ enum phy_mode mode) -+{ -+ int ret; -+ -+ if (!priv->phys[USB2_OTG_PHY]) -+ return -EINVAL; -+ -+ if (mode == PHY_MODE_USB_HOST) -+ dev_info(priv->dev, "switching to Host Mode\n"); -+ else -+ dev_info(priv->dev, "switching to Device Mode\n"); -+ -+ if (priv->vbus) { -+ if (mode == PHY_MODE_USB_DEVICE) -+ ret = regulator_disable(priv->vbus); -+ else -+ ret = regulator_enable(priv->vbus); -+ if (ret) -+ return ret; -+ } -+ -+ priv->otg_phy_mode = mode; -+ -+ dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode); -+ -+ dwc3_meson_g12a_usb_otg_apply_mode(priv); -+ -+ return 0; -+} -+ -+static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role) -+{ -+ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); -+ enum phy_mode mode; -+ -+ if (role == USB_ROLE_NONE) -+ return 0; -+ -+ mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST -+ : PHY_MODE_USB_DEVICE; -+ -+ if (mode == priv->otg_phy_mode) -+ return 0; -+ -+ return dwc3_meson_g12a_otg_mode_set(priv, mode); -+} -+ -+static enum usb_role dwc3_meson_g12a_role_get(struct device *dev) -+{ -+ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); -+ -+ return priv->otg_phy_mode == PHY_MODE_USB_HOST ? -+ USB_ROLE_HOST : USB_ROLE_DEVICE; -+} -+ -+static struct device *dwc3_meson_g12_find_child(struct device *dev, -+ const char *compatible) -+{ -+ struct platform_device *pdev; -+ struct device_node *np; -+ -+ np = of_get_compatible_child(dev->of_node, compatible); -+ if (!np) -+ return NULL; -+ -+ pdev = of_find_device_by_node(np); -+ of_node_put(np); -+ if (!pdev) -+ return NULL; -+ -+ return &pdev->dev; -+} -+ -+static int dwc3_meson_g12a_probe(struct platform_device *pdev) -+{ -+ struct dwc3_meson_g12a *priv; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ void __iomem *base; -+ struct resource *res; -+ enum phy_mode otg_id; -+ int ret, i; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ priv->regmap = devm_regmap_init_mmio(dev, base, -+ &phy_meson_g12a_usb3_regmap_conf); -+ if (IS_ERR(priv->regmap)) -+ return PTR_ERR(priv->regmap); -+ -+ priv->vbus = devm_regulator_get_optional(dev, "vbus"); -+ if (IS_ERR(priv->vbus)) { -+ if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) -+ return PTR_ERR(priv->vbus); -+ priv->vbus = NULL; -+ } -+ -+ priv->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(priv->clk)) -+ return PTR_ERR(priv->clk); -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) -+ return ret; -+ -+ devm_add_action_or_reset(dev, -+ (void(*)(void *))clk_disable_unprepare, -+ priv->clk); -+ -+ platform_set_drvdata(pdev, priv); -+ priv->dev = dev; -+ -+ priv->reset = devm_reset_control_get(dev, NULL); -+ if (IS_ERR(priv->reset)) { -+ ret = PTR_ERR(priv->reset); -+ dev_err(dev, "failed to get device reset, err=%d\n", ret); -+ return ret; -+ } -+ -+ ret = reset_control_reset(priv->reset); -+ if (ret) -+ return ret; -+ -+ ret = dwc3_meson_g12a_get_phys(priv); -+ if (ret) -+ return ret; -+ -+ if (priv->vbus) { -+ ret = regulator_enable(priv->vbus); -+ if (ret) -+ return ret; -+ } -+ -+ /* Get dr_mode */ -+ priv->otg_mode = usb_get_dr_mode(dev); -+ -+ dwc3_meson_g12a_usb_init(priv); -+ -+ /* Init PHYs */ -+ for (i = 0 ; i < PHY_COUNT ; ++i) { -+ ret = phy_init(priv->phys[i]); -+ if (ret) -+ return ret; -+ } -+ -+ /* Set PHY Power */ -+ for (i = 0 ; i < PHY_COUNT ; ++i) { -+ ret = phy_power_on(priv->phys[i]); -+ if (ret) -+ goto err_phys_exit; -+ } -+ -+ ret = of_platform_populate(np, NULL, NULL, dev); -+ if (ret) { -+ clk_disable_unprepare(priv->clk); -+ goto err_phys_power; -+ } -+ -+ /* Setup OTG mode corresponding to the ID pin */ -+ if (priv->otg_mode == USB_DR_MODE_OTG) { -+ /* TOFIX Handle ID mode toggling via IRQ */ -+ otg_id = dwc3_meson_g12a_get_id(priv); -+ if (otg_id != priv->otg_phy_mode) { -+ if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) -+ dev_warn(dev, "Failed to switch OTG mode\n"); -+ } -+ } -+ -+ /* Setup role switcher */ -+ priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, -+ "snps,dwc3"); -+ priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); -+ priv->switch_desc.allow_userspace_control = true; -+ priv->switch_desc.set = dwc3_meson_g12a_role_set; -+ priv->switch_desc.get = dwc3_meson_g12a_role_get; -+ -+ priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); -+ if (IS_ERR(priv->role_switch)) -+ dev_warn(dev, "Unable to register Role Switch\n"); -+ -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ pm_runtime_get_sync(dev); -+ -+ return 0; -+ -+err_phys_power: -+ for (i = 0 ; i < PHY_COUNT ; ++i) -+ phy_power_off(priv->phys[i]); -+ -+err_phys_exit: -+ for (i = 0 ; i < PHY_COUNT ; ++i) -+ phy_exit(priv->phys[i]); -+ -+ return ret; -+} -+ -+static int dwc3_meson_g12a_remove(struct platform_device *pdev) -+{ -+ struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ int i; -+ -+ usb_role_switch_unregister(priv->role_switch); -+ -+ of_platform_depopulate(dev); -+ -+ for (i = 0 ; i < PHY_COUNT ; ++i) { -+ phy_power_off(priv->phys[i]); -+ phy_exit(priv->phys[i]); -+ } -+ -+ pm_runtime_disable(dev); -+ pm_runtime_put_noidle(dev); -+ pm_runtime_set_suspended(dev); -+ -+ return 0; -+} -+ -+static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev) -+{ -+ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); -+ -+ clk_disable(priv->clk); -+ -+ return 0; -+} -+ -+static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) -+{ -+ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); -+ -+ return clk_enable(priv->clk); -+} -+ -+static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) -+{ -+ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); -+ int i; -+ -+ for (i = 0 ; i < PHY_COUNT ; ++i) { -+ phy_power_off(priv->phys[i]); -+ phy_exit(priv->phys[i]); -+ } -+ -+ reset_control_assert(priv->reset); -+ -+ return 0; -+} -+ -+static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev) -+{ -+ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); -+ int i, ret; -+ -+ reset_control_deassert(priv->reset); -+ -+ dwc3_meson_g12a_usb_init(priv); -+ -+ /* Init PHYs */ -+ for (i = 0 ; i < PHY_COUNT ; ++i) { -+ ret = phy_init(priv->phys[i]); -+ if (ret) -+ return ret; -+ } -+ -+ /* Set PHY Power */ -+ for (i = 0 ; i < PHY_COUNT ; ++i) { -+ ret = phy_power_on(priv->phys[i]); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume) -+ SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend, -+ dwc3_meson_g12a_runtime_resume, NULL) -+}; -+ -+static const struct of_device_id dwc3_meson_g12a_match[] = { -+ { .compatible = "amlogic,meson-g12a-usb-ctrl" }, -+ { /* Sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); -+ -+static struct platform_driver dwc3_meson_g12a_driver = { -+ .probe = dwc3_meson_g12a_probe, -+ .remove = dwc3_meson_g12a_remove, -+ .driver = { -+ .name = "dwc3-meson-g12a", -+ .of_match_table = dwc3_meson_g12a_match, -+ .pm = &dwc3_meson_g12a_dev_pm_ops, -+ }, -+}; -+ -+module_platform_driver(dwc3_meson_g12a_driver); -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer"); -+MODULE_AUTHOR("Neil Armstrong "); - -From 22eb5e142c7c3e8b0ba84075c9a65aed68cda145 Mon Sep 17 00:00:00 2001 -From: Colin Ian King -Date: Wed, 17 Apr 2019 17:26:28 +0100 -Subject: [PATCH 060/249] UPSTREAM: ASoC: hdmi-codec: fix spelling mistake - "plalform" -> "platform" - -There is a spelling mistake in a dev_err message. Fix it. - -Signed-off-by: Colin Ian King -Signed-off-by: Mark Brown -(cherry picked from commit 7b6531c5054e7804ccce25f389a2d4810357f5c9) -Signed-off-by: Neil Armstrong ---- - sound/soc/codecs/hdmi-codec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 35df73e42cbc5..b9d9dde9fbaf4 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -757,7 +757,7 @@ static int hdmi_codec_probe(struct platform_device *pdev) - dev_dbg(dev, "%s()\n", __func__); - - if (!hcd) { -- dev_err(dev, "%s: No plalform data\n", __func__); -+ dev_err(dev, "%s: No platform data\n", __func__); - return -EINVAL; - } - - -From a6118030ab40baa635a596af19136dd0039ebd8f Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 29 Apr 2019 15:29:40 +0200 -Subject: [PATCH 062/249] UPSTREAM: ASoC: hdmi-codec: stream is already locked - in hw_params - -startup() should have run before hw_params() is called, so the -current_substream pointer should already be properly set. There -is no reason to call hdmi_codec_new_stream() again in the -hw_params() callback - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 726fc60babe4a46e946e69a9dbd3e21aaec4d58e) -Signed-off-by: Neil Armstrong ---- - sound/soc/codecs/hdmi-codec.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 720de0a53c799..39caf19abb0bc 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -496,10 +496,6 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, - return ret; - } - -- ret = hdmi_codec_new_stream(substream, dai); -- if (ret) -- return ret; -- - hdmi_audio_infoframe_init(&hp.cea); - hp.cea.channels = params_channels(params); - hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; - -From 9c4008d852ccf0ecd0029f1849e1203042883ce1 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 6 May 2019 11:58:12 +0200 -Subject: [PATCH 063/249] UPSTREAM: ASoC: hdmi-codec: remove function name - debug traces - -Remove the debug traces only showing the function name on entry. -The same can be obtained using ftrace. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 900e5daf7034cf65ce4072b86f297c42f9042433) -Signed-off-by: Neil Armstrong ---- - sound/soc/codecs/hdmi-codec.c | 12 ------------ - 1 file changed, 12 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 39caf19abb0bc..eb31d7eddcbf8 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -416,8 +416,6 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - int ret = 0; - -- dev_dbg(dai->dev, "%s()\n", __func__); -- - ret = hdmi_codec_new_stream(substream, dai); - if (ret) - return ret; -@@ -457,8 +455,6 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, - { - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - -- dev_dbg(dai->dev, "%s()\n", __func__); -- - WARN_ON(hcp->current_stream != substream); - - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; -@@ -527,8 +523,6 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - struct hdmi_codec_daifmt cf = { 0 }; - -- dev_dbg(dai->dev, "%s()\n", __func__); -- - if (dai->id == DAI_ID_SPDIF) - return 0; - -@@ -597,8 +591,6 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) - { - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - -- dev_dbg(dai->dev, "%s()\n", __func__); -- - if (hcp->hcd.ops->digital_mute) - return hcp->hcd.ops->digital_mute(dai->dev->parent, - hcp->hcd.data, mute); -@@ -656,8 +648,6 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, - }; - int ret; - -- dev_dbg(dai->dev, "%s()\n", __func__); -- - ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, - NULL, drv->playback.channels_max, 0, - &hcp->chmap_info); -@@ -754,8 +744,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) - int dai_count, i = 0; - int ret; - -- dev_dbg(dev, "%s()\n", __func__); -- - if (!hcd) { - dev_err(dev, "%s: No platform data\n", __func__); - return -EINVAL; - -From f27a8c03d6dca2faacc22c0385667faf70c36cea Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 6 May 2019 11:58:13 +0200 -Subject: [PATCH 064/249] UPSTREAM: ASoC: hdmi-codec: remove reference to the - current substream - -If the hdmi-codec is on a codec-to-codec link, the substream pointer -it receives is completely made up by snd_soc_dai_link_event(). -The pointer will be different between startup() and shutdown(). - -The hdmi-codec complains when this happens even if it is not really a -problem. The current_substream pointer is not used for anything useful -apart from getting the exclusive ownership of the device. - -Remove current_substream pointer and replace the exclusive locking -mechanism with a simple variable and some atomic operations. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 3fcf94ef4d418668fa66e33ce9aabb05689b55f6) -Signed-off-by: Neil Armstrong ---- - sound/soc/codecs/hdmi-codec.c | 58 ++++++++++------------------------- - 1 file changed, 16 insertions(+), 42 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index eb31d7eddcbf8..4d32f93f6be68 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -280,11 +280,10 @@ struct hdmi_codec_priv { - struct hdmi_codec_pdata hcd; - struct snd_soc_dai_driver *daidrv; - struct hdmi_codec_daifmt daifmt[2]; -- struct mutex current_stream_lock; -- struct snd_pcm_substream *current_stream; - uint8_t eld[MAX_ELD_BYTES]; - struct snd_pcm_chmap *chmap_info; - unsigned int chmap_idx; -+ unsigned long busy; - }; - - static const struct snd_soc_dapm_widget hdmi_widgets[] = { -@@ -392,42 +391,22 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, - return 0; - } - --static int hdmi_codec_new_stream(struct snd_pcm_substream *substream, -- struct snd_soc_dai *dai) --{ -- struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); -- int ret = 0; -- -- mutex_lock(&hcp->current_stream_lock); -- if (!hcp->current_stream) { -- hcp->current_stream = substream; -- } else if (hcp->current_stream != substream) { -- dev_err(dai->dev, "Only one simultaneous stream supported!\n"); -- ret = -EINVAL; -- } -- mutex_unlock(&hcp->current_stream_lock); -- -- return ret; --} -- - static int hdmi_codec_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - int ret = 0; - -- ret = hdmi_codec_new_stream(substream, dai); -- if (ret) -- return ret; -+ ret = test_and_set_bit(0, &hcp->busy); -+ if (ret) { -+ dev_err(dai->dev, "Only one simultaneous stream supported!\n"); -+ return -EINVAL; -+ } - - if (hcp->hcd.ops->audio_startup) { - ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); -- if (ret) { -- mutex_lock(&hcp->current_stream_lock); -- hcp->current_stream = NULL; -- mutex_unlock(&hcp->current_stream_lock); -- return ret; -- } -+ if (ret) -+ goto err; - } - - if (hcp->hcd.ops->get_eld) { -@@ -437,17 +416,18 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, - if (!ret) { - ret = snd_pcm_hw_constraint_eld(substream->runtime, - hcp->eld); -- if (ret) { -- mutex_lock(&hcp->current_stream_lock); -- hcp->current_stream = NULL; -- mutex_unlock(&hcp->current_stream_lock); -- return ret; -- } -+ if (ret) -+ goto err; - } - /* Select chmap supported */ - hdmi_codec_eld_chmap(hcp); - } - return 0; -+ -+err: -+ /* Release the exclusive lock on error */ -+ clear_bit(0, &hcp->busy); -+ return ret; - } - - static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, -@@ -455,14 +435,10 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, - { - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - -- WARN_ON(hcp->current_stream != substream); -- - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); - -- mutex_lock(&hcp->current_stream_lock); -- hcp->current_stream = NULL; -- mutex_unlock(&hcp->current_stream_lock); -+ clear_bit(0, &hcp->busy); - } - - static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, -@@ -761,8 +737,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) - return -ENOMEM; - - hcp->hcd = *hcd; -- mutex_init(&hcp->current_stream_lock); -- - hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv), - GFP_KERNEL); - if (!hcp->daidrv) - -From 138b08265088ba3a0356bfdb9dcfeddd8913f5ca Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 6 May 2019 11:58:14 +0200 -Subject: [PATCH 065/249] UPSTREAM: ASoC: hdmi-codec: remove reference to the - dai drivers in the private data - -Keeping the a pointer to the dai drivers is not necessary. It is not used -by the hdmi_codec after the probe. - -Even if it was used, the 'struct snd_soc_dai_driver' can accessed through -the 'struct snd_soc_dai' so keeping the pointer in the private data -structure is not useful. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 1de005d47d90343666c5cc50a50929e05e52baac) -Signed-off-by: Neil Armstrong ---- - sound/soc/codecs/hdmi-codec.c | 18 ++++++++---------- - 1 file changed, 8 insertions(+), 10 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 4d32f93f6be68..9408e6bc4d3e5 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -278,7 +278,6 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { - - struct hdmi_codec_priv { - struct hdmi_codec_pdata hcd; -- struct snd_soc_dai_driver *daidrv; - struct hdmi_codec_daifmt daifmt[2]; - uint8_t eld[MAX_ELD_BYTES]; - struct snd_pcm_chmap *chmap_info; -@@ -715,6 +714,7 @@ static const struct snd_soc_component_driver hdmi_driver = { - static int hdmi_codec_probe(struct platform_device *pdev) - { - struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; -+ struct snd_soc_dai_driver *daidrv; - struct device *dev = &pdev->dev; - struct hdmi_codec_priv *hcp; - int dai_count, i = 0; -@@ -737,27 +737,25 @@ static int hdmi_codec_probe(struct platform_device *pdev) - return -ENOMEM; - - hcp->hcd = *hcd; -- hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv), -- GFP_KERNEL); -- if (!hcp->daidrv) -+ daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); -+ if (!daidrv) - return -ENOMEM; - - if (hcd->i2s) { -- hcp->daidrv[i] = hdmi_i2s_dai; -- hcp->daidrv[i].playback.channels_max = -- hcd->max_i2s_channels; -+ daidrv[i] = hdmi_i2s_dai; -+ daidrv[i].playback.channels_max = hcd->max_i2s_channels; - i++; - } - - if (hcd->spdif) { -- hcp->daidrv[i] = hdmi_spdif_dai; -+ daidrv[i] = hdmi_spdif_dai; - hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF; - } - - dev_set_drvdata(dev, hcp); - -- ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv, -- dai_count); -+ ret = devm_snd_soc_register_component(dev, &hdmi_driver, daidrv, -+ dai_count); - if (ret) { - dev_err(dev, "%s: snd_soc_register_component() failed (%d)\n", - __func__, ret); - -From 82dc0a826a10bacacb3cca8e955b599acd7b1253 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 6 May 2019 11:58:15 +0200 -Subject: [PATCH 066/249] UPSTREAM: ASoC: hdmi-codec: remove ops dependency on - the dai id - -The dependency on the dai_id can be removed by setting different ops -for the i2s and spdif dai and storing the dai format information in -each dai structure. It simplies the code a bit. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 0cf4610b9f297e570da4d98514b310f076ecc8ab) -Signed-off-by: Neil Armstrong ---- - sound/soc/codecs/hdmi-codec.c | 100 +++++++++++++++++++++++----------- - 1 file changed, 67 insertions(+), 33 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 9408e6bc4d3e5..90a8927666259 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -278,7 +278,6 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { - - struct hdmi_codec_priv { - struct hdmi_codec_pdata hcd; -- struct hdmi_codec_daifmt daifmt[2]; - uint8_t eld[MAX_ELD_BYTES]; - struct snd_pcm_chmap *chmap_info; - unsigned int chmap_idx; -@@ -445,6 +444,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); -+ struct hdmi_codec_daifmt *cf = dai->playback_dma_data; - struct hdmi_codec_params hp = { - .iec = { - .status = { 0 }, -@@ -489,28 +489,27 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, - hp.channels = params_channels(params); - - return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, -- &hcp->daifmt[dai->id], &hp); -+ cf, &hp); - } - --static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, -- unsigned int fmt) -+static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, -+ unsigned int fmt) - { -- struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); -- struct hdmi_codec_daifmt cf = { 0 }; -+ struct hdmi_codec_daifmt *cf = dai->playback_dma_data; - -- if (dai->id == DAI_ID_SPDIF) -- return 0; -+ /* Reset daifmt */ -+ memset(cf, 0, sizeof(*cf)); - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: -- cf.bit_clk_master = 1; -- cf.frame_clk_master = 1; -+ cf->bit_clk_master = 1; -+ cf->frame_clk_master = 1; - break; - case SND_SOC_DAIFMT_CBS_CFM: -- cf.frame_clk_master = 1; -+ cf->frame_clk_master = 1; - break; - case SND_SOC_DAIFMT_CBM_CFS: -- cf.bit_clk_master = 1; -+ cf->bit_clk_master = 1; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; -@@ -522,43 +521,41 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_NB_IF: -- cf.frame_clk_inv = 1; -+ cf->frame_clk_inv = 1; - break; - case SND_SOC_DAIFMT_IB_NF: -- cf.bit_clk_inv = 1; -+ cf->bit_clk_inv = 1; - break; - case SND_SOC_DAIFMT_IB_IF: -- cf.frame_clk_inv = 1; -- cf.bit_clk_inv = 1; -+ cf->frame_clk_inv = 1; -+ cf->bit_clk_inv = 1; - break; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: -- cf.fmt = HDMI_I2S; -+ cf->fmt = HDMI_I2S; - break; - case SND_SOC_DAIFMT_DSP_A: -- cf.fmt = HDMI_DSP_A; -+ cf->fmt = HDMI_DSP_A; - break; - case SND_SOC_DAIFMT_DSP_B: -- cf.fmt = HDMI_DSP_B; -+ cf->fmt = HDMI_DSP_B; - break; - case SND_SOC_DAIFMT_RIGHT_J: -- cf.fmt = HDMI_RIGHT_J; -+ cf->fmt = HDMI_RIGHT_J; - break; - case SND_SOC_DAIFMT_LEFT_J: -- cf.fmt = HDMI_LEFT_J; -+ cf->fmt = HDMI_LEFT_J; - break; - case SND_SOC_DAIFMT_AC97: -- cf.fmt = HDMI_AC97; -+ cf->fmt = HDMI_AC97; - break; - default: - dev_err(dai->dev, "Invalid DAI interface format\n"); - return -EINVAL; - } - -- hcp->daifmt[dai->id] = cf; -- - return 0; - } - -@@ -573,14 +570,20 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) - return 0; - } - --static const struct snd_soc_dai_ops hdmi_dai_ops = { -+static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, -- .set_fmt = hdmi_codec_set_fmt, -+ .set_fmt = hdmi_codec_i2s_set_fmt, - .digital_mute = hdmi_codec_digital_mute, - }; - -+static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { -+ .startup = hdmi_codec_startup, -+ .shutdown = hdmi_codec_shutdown, -+ .hw_params = hdmi_codec_hw_params, -+ .digital_mute = hdmi_codec_digital_mute, -+}; - - #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ -@@ -648,20 +651,52 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, - static int hdmi_dai_probe(struct snd_soc_dai *dai) - { - struct snd_soc_dapm_context *dapm; -+ struct hdmi_codec_daifmt *daifmt; - struct snd_soc_dapm_route route = { - .sink = "TX", - .source = dai->driver->playback.stream_name, - }; -+ int ret; - - dapm = snd_soc_component_get_dapm(dai->component); -+ ret = snd_soc_dapm_add_routes(dapm, &route, 1); -+ if (ret) -+ return ret; -+ -+ daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL); -+ if (!daifmt) -+ return -ENOMEM; - -- return snd_soc_dapm_add_routes(dapm, &route, 1); -+ dai->playback_dma_data = daifmt; -+ return 0; -+} -+ -+static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) -+{ -+ struct hdmi_codec_daifmt *cf = dai->playback_dma_data; -+ int ret; -+ -+ ret = hdmi_dai_probe(dai); -+ if (ret) -+ return ret; -+ -+ cf = dai->playback_dma_data; -+ cf->fmt = HDMI_SPDIF; -+ -+ return 0; -+} -+ -+static int hdmi_codec_dai_remove(struct snd_soc_dai *dai) -+{ -+ kfree(dai->playback_dma_data); -+ return 0; - } - - static const struct snd_soc_dai_driver hdmi_i2s_dai = { - .name = "i2s-hifi", - .id = DAI_ID_I2S, - .probe = hdmi_dai_probe, -+ .remove = hdmi_codec_dai_remove, - .playback = { - .stream_name = "I2S Playback", - .channels_min = 2, -@@ -670,14 +705,15 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { - .formats = I2S_FORMATS, - .sig_bits = 24, - }, -- .ops = &hdmi_dai_ops, -+ .ops = &hdmi_codec_i2s_dai_ops, - .pcm_new = hdmi_codec_pcm_new, - }; - - static const struct snd_soc_dai_driver hdmi_spdif_dai = { - .name = "spdif-hifi", - .id = DAI_ID_SPDIF, -- .probe = hdmi_dai_probe, -+ .probe = hdmi_dai_spdif_probe, -+ .remove = hdmi_codec_dai_remove, - .playback = { - .stream_name = "SPDIF Playback", - .channels_min = 2, -@@ -685,7 +721,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { - .rates = HDMI_RATES, - .formats = SPDIF_FORMATS, - }, -- .ops = &hdmi_dai_ops, -+ .ops = &hdmi_codec_spdif_dai_ops, - .pcm_new = hdmi_codec_pcm_new, - }; - -@@ -747,10 +783,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) - i++; - } - -- if (hcd->spdif) { -+ if (hcd->spdif) - daidrv[i] = hdmi_spdif_dai; -- hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF; -- } - - dev_set_drvdata(dev, hcp); - - -From 9dc13d7c0233a8cb6b242846a7371bdfefc654b3 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 29 Apr 2019 11:47:49 +0200 -Subject: [PATCH 067/249] UPSTREAM: ASoC: fix valid stream condition - -A stream may specify a rate range using 'rate_min' and 'rate_max', so a -stream may be valid and not specify any rates. However, as stream cannot -be valid and not have any channel. Let's use this condition instead to -determine if a stream is valid or not. - -Fixes: cde79035c6cf ("ASoC: Handle multiple codecs with split playback / capture") -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 6a7c59c6d9f3b280e81d7a04bbe4e55e90152dce) -Signed-off-by: Neil Armstrong ---- - sound/soc/soc-pcm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c -index be80a12fba27c..c4e5d292a0d76 100644 ---- a/sound/soc/soc-pcm.c -+++ b/sound/soc/soc-pcm.c -@@ -43,8 +43,8 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) - else - codec_stream = &dai->driver->capture; - -- /* If the codec specifies any rate at all, it supports the stream. */ -- return codec_stream->rates; -+ /* If the codec specifies any channels at all, it supports the stream */ -+ return codec_stream->channels_min; - } - - /** - -From 6d486503dc795f8a989150c95eccc267dcffe39f Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 29 Apr 2019 11:47:50 +0200 -Subject: [PATCH 068/249] UPSTREAM: ASoC: skip hw_free on codec dai for which - the stream is invalid - -Like for hw_params, hw_free should not be called on codec dai for -which the current stream is invalid. - -Fixes: cde79035c6cf ("ASoC: Handle multiple codecs with split playback / capture") -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit f47b9ad927c6370b80922af434dda98764a43804) -Signed-off-by: Neil Armstrong ---- - sound/soc/soc-pcm.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c -index c4e5d292a0d76..69ea962de5856 100644 ---- a/sound/soc/soc-pcm.c -+++ b/sound/soc/soc-pcm.c -@@ -1033,6 +1033,9 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, - - codec_err: - for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { -+ if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) -+ continue; -+ - if (codec_dai->driver->ops->hw_free) - codec_dai->driver->ops->hw_free(substream, codec_dai); - codec_dai->rate = 0; -@@ -1090,6 +1093,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) - - /* now free hw params for the DAIs */ - for_each_rtd_codec_dai(rtd, i, codec_dai) { -+ if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) -+ continue; -+ - if (codec_dai->driver->ops->hw_free) - codec_dai->driver->ops->hw_free(substream, codec_dai); - } - -From a94cd4dd33fa0bc465f8540ca30c882a8154c01d Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 13:50:15 +0200 -Subject: [PATCH 069/249] FROMGIT: ASoC: max98357a: add missing supported rates - -According the publicly available datasheet (and some test) the max98357a -also supports 32, 44.1 and 88.2 kHz sample rate. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit fdf34366d3242d5eeffa1b4d9a3497ebf30a4ecb - git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) -Signed-off-by: Neil Armstrong ---- - sound/soc/codecs/max98357a.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c -index d469576b5a7bb..d037a3e4d3232 100644 ---- a/sound/soc/codecs/max98357a.c -+++ b/sound/soc/codecs/max98357a.c -@@ -97,7 +97,10 @@ static struct snd_soc_dai_driver max98357a_dai_driver = { - SNDRV_PCM_FMTBIT_S32, - .rates = SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000 | -+ SNDRV_PCM_RATE_32000 | -+ SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | -+ SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, - .rate_min = 8000, - .rate_max = 96000, - -From a8790dfb8563038dc3832a4eac59af56e708650b Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 13:17:28 +0200 -Subject: [PATCH 070/249] FROMGIT: ASoC: meson: add g12a compatibles - -Add new compatible strings for the g12a devices. -Audio wise, the g12a is fairly to close to the axg, yet some differences -need to be handled. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 679f4e6cfd45bcc14bb563576e419ac9e43fad7c - git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) -Signed-off-by: Neil Armstrong ---- - Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt | 4 +++- - Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt | 3 ++- - .../devicetree/bindings/sound/amlogic,axg-spdifin.txt | 3 ++- - .../devicetree/bindings/sound/amlogic,axg-spdifout.txt | 3 ++- - .../devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt | 4 +++- - 5 files changed, 12 insertions(+), 5 deletions(-) - -diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt -index 3dfc2515e5c67..4330fc9dca6d8 100644 ---- a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt -+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt -@@ -2,7 +2,9 @@ - - Required properties: - - compatible: 'amlogic,axg-toddr' or -- 'amlogic,axg-frddr' -+ 'amlogic,axg-toddr' or -+ 'amlogic,g12a-frddr' or -+ 'amlogic,g12a-toddr' - - reg: physical base address of the controller and length of memory - mapped region. - - interrupts: interrupt specifier for the fifo. -diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt -index 5672d0bc5b166..73f473a9365f7 100644 ---- a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt -+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt -@@ -1,7 +1,8 @@ - * Amlogic Audio PDM input - - Required properties: --- compatible: 'amlogic,axg-pdm' -+- compatible: 'amlogic,axg-pdm' or -+ 'amlogic,g12a-pdm' - - reg: physical base address of the controller and length of memory - mapped region. - - clocks: list of clock phandle, one for each entry clock-names. -diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt -index 2e6cb7d9b2029..0b82504fa4190 100644 ---- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt -+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt -@@ -1,7 +1,8 @@ - * Amlogic Audio SPDIF Input - - Required properties: --- compatible: 'amlogic,axg-spdifin' -+- compatible: 'amlogic,axg-spdifin' or -+ 'amlogic,g12a-spdifin' - - interrupts: interrupt specifier for the spdif input. - - clocks: list of clock phandle, one for each entry clock-names. - - clock-names: should contain the following: -diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt -index 521c38ad89e71..826152730508e 100644 ---- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt -+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt -@@ -1,7 +1,8 @@ - * Amlogic Audio SPDIF Output - - Required properties: --- compatible: 'amlogic,axg-spdifout' -+- compatible: 'amlogic,axg-spdifout' or -+ 'amlogic,g12a-spdifout' - - clocks: list of clock phandle, one for each entry clock-names. - - clock-names: should contain the following: - * "pclk" : peripheral clock. -diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt -index 1c1b7490554ea..3b94a715a0b9b 100644 ---- a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt -+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt -@@ -2,7 +2,9 @@ - - Required properties: - - compatible: 'amlogic,axg-tdmin' or -- 'amlogic,axg-tdmout' -+ 'amlogic,axg-tdmout' or -+ 'amlogic,g12a-tdmin' or -+ 'amlogic,g12a-tdmout' - - reg: physical base address of the controller and length of memory - mapped region. - - clocks: list of clock phandle, one for each entry clock-names. - -From 7291779c68c58785c107307a4a00a466dab8bc9d Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 13:17:29 +0200 -Subject: [PATCH 071/249] FROMGIT: ASoC: meson: axg-fifo: add g12a support - -The g12a fifos gained the ability to set the initial address of the -pointer within the buffer, instead of defaulting to the buffer start -address. - -It is not very useful to us (yet) but we need to put a copy the buffer -start address in the related register for the fifo to work properly on the -g12a SoC family - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit 7c02509a8a9981fb2c16b75904423e7ab2f9f43a - git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/axg-fifo.c | 34 +++++++++++++++++++++++++++++++--- - sound/soc/meson/axg-fifo.h | 2 ++ - 2 files changed, 33 insertions(+), 3 deletions(-) - -diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c -index 75e5e480fda28..01c1c7db25100 100644 ---- a/sound/soc/meson/axg-fifo.c -+++ b/sound/soc/meson/axg-fifo.c -@@ -19,7 +19,7 @@ - * This file implements the platform operations common to the playback and - * capture frontend DAI. The logic behind this two types of fifo is very - * similar but some difference exist. -- * These differences the respective DAI drivers -+ * These differences are handled in the respective DAI drivers - */ - - static struct snd_pcm_hardware axg_fifo_hw = { -@@ -133,6 +133,23 @@ static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss, - return 0; - } - -+static int g12a_fifo_pcm_hw_params(struct snd_pcm_substream *ss, -+ struct snd_pcm_hw_params *params) -+{ -+ struct axg_fifo *fifo = axg_fifo_data(ss); -+ struct snd_pcm_runtime *runtime = ss->runtime; -+ int ret; -+ -+ ret = axg_fifo_pcm_hw_params(ss, params); -+ if (ret) -+ return ret; -+ -+ /* Set the initial memory address of the DMA */ -+ regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr); -+ -+ return 0; -+} -+ - static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss) - { - struct axg_fifo *fifo = axg_fifo_data(ss); -@@ -262,6 +279,17 @@ const struct snd_pcm_ops axg_fifo_pcm_ops = { - }; - EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops); - -+const struct snd_pcm_ops g12a_fifo_pcm_ops = { -+ .open = axg_fifo_pcm_open, -+ .close = axg_fifo_pcm_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = g12a_fifo_pcm_hw_params, -+ .hw_free = axg_fifo_pcm_hw_free, -+ .pointer = axg_fifo_pcm_pointer, -+ .trigger = axg_fifo_pcm_trigger, -+}; -+EXPORT_SYMBOL_GPL(g12a_fifo_pcm_ops); -+ - int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type) - { - struct snd_card *card = rtd->card->snd_card; -@@ -278,7 +306,7 @@ static const struct regmap_config axg_fifo_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, -- .max_register = FIFO_STATUS2, -+ .max_register = FIFO_INIT_ADDR, - }; - - int axg_fifo_probe(struct platform_device *pdev) -@@ -339,6 +367,6 @@ int axg_fifo_probe(struct platform_device *pdev) - } - EXPORT_SYMBOL_GPL(axg_fifo_probe); - --MODULE_DESCRIPTION("Amlogic AXG fifo driver"); -+MODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver"); - MODULE_AUTHOR("Jerome Brunet "); - MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h -index d9f516cfbeda2..5caf81241dfee 100644 ---- a/sound/soc/meson/axg-fifo.h -+++ b/sound/soc/meson/axg-fifo.h -@@ -60,6 +60,7 @@ struct snd_soc_pcm_runtime; - #define FIFO_STATUS1 0x14 - #define STATUS1_INT_STS(x) ((x) << 0) - #define FIFO_STATUS2 0x18 -+#define FIFO_INIT_ADDR 0x24 - - struct axg_fifo { - struct regmap *map; -@@ -74,6 +75,7 @@ struct axg_fifo_match_data { - }; - - extern const struct snd_pcm_ops axg_fifo_pcm_ops; -+extern const struct snd_pcm_ops g12a_fifo_pcm_ops; - - int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type); - int axg_fifo_probe(struct platform_device *pdev); - -From 9c274e6acdf442bb173a2b124a9fc5d07e13feeb Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 13:17:30 +0200 -Subject: [PATCH 072/249] FROMGIT: ASoC: meson: axg-toddr: add g12a support - -Since the g12a SoC fifo can set the fifo initial start address, we must -make sure to actually reset the write pointer to this address when -starting a capture. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit a3c23a8ad4dc07100d916d75ca30c982288b868d - git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/axg-toddr.c | 53 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 53 insertions(+) - -diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c -index 0e9ca3882ae5c..4f63e434fad4b 100644 ---- a/sound/soc/meson/axg-toddr.c -+++ b/sound/soc/meson/axg-toddr.c -@@ -24,6 +24,7 @@ - #define CTRL0_TODDR_MSB_POS(x) ((x) << 8) - #define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) - #define CTRL0_TODDR_LSB_POS(x) ((x) << 3) -+#define CTRL1_TODDR_FORCE_FINISH BIT(25) - - #define TODDR_MSB_POS 31 - -@@ -33,6 +34,22 @@ static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd, - return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_CAPTURE); - } - -+static int g12a_toddr_dai_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); -+ -+ /* Reset the write pointer to the FIFO_INIT_ADDR */ -+ regmap_update_bits(fifo->map, FIFO_CTRL1, -+ CTRL1_TODDR_FORCE_FINISH, 0); -+ regmap_update_bits(fifo->map, FIFO_CTRL1, -+ CTRL1_TODDR_FORCE_FINISH, CTRL1_TODDR_FORCE_FINISH); -+ regmap_update_bits(fifo->map, FIFO_CTRL1, -+ CTRL1_TODDR_FORCE_FINISH, 0); -+ -+ return 0; -+} -+ - static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -@@ -172,10 +189,46 @@ static const struct axg_fifo_match_data axg_toddr_match_data = { - .dai_drv = &axg_toddr_dai_drv - }; - -+static const struct snd_soc_dai_ops g12a_toddr_ops = { -+ .prepare = g12a_toddr_dai_prepare, -+ .hw_params = axg_toddr_dai_hw_params, -+ .startup = axg_toddr_dai_startup, -+ .shutdown = axg_toddr_dai_shutdown, -+}; -+ -+static struct snd_soc_dai_driver g12a_toddr_dai_drv = { -+ .name = "TODDR", -+ .capture = { -+ .stream_name = "Capture", -+ .channels_min = 1, -+ .channels_max = AXG_FIFO_CH_MAX, -+ .rates = AXG_FIFO_RATES, -+ .formats = AXG_FIFO_FORMATS, -+ }, -+ .ops = &g12a_toddr_ops, -+ .pcm_new = axg_toddr_pcm_new, -+}; -+ -+static const struct snd_soc_component_driver g12a_toddr_component_drv = { -+ .dapm_widgets = axg_toddr_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets), -+ .dapm_routes = axg_toddr_dapm_routes, -+ .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes), -+ .ops = &g12a_fifo_pcm_ops -+}; -+ -+static const struct axg_fifo_match_data g12a_toddr_match_data = { -+ .component_drv = &g12a_toddr_component_drv, -+ .dai_drv = &g12a_toddr_dai_drv -+}; -+ - static const struct of_device_id axg_toddr_of_match[] = { - { - .compatible = "amlogic,axg-toddr", - .data = &axg_toddr_match_data, -+ }, { -+ .compatible = "amlogic,g12a-toddr", -+ .data = &g12a_toddr_match_data, - }, {} - }; - MODULE_DEVICE_TABLE(of, axg_toddr_of_match); - -From 24e5a97911389c4ee6712aceb956d8013f420e7f Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 13:17:31 +0200 -Subject: [PATCH 073/249] FROMGIT: ASoC: meson: axg-frddr: add g12a support - -On the axg, frddr could only be connected to 1 downstream element, so the -playback was possible on 1 interface only at a time. - -On the g12a, the frddr may connect and wait for the request of up to 3 -downstream elements. With this, it possible for single playback to be -played on several interfaces at the same time. - -Like the toddr fifo, the g12a frddr also need to take care of resetting -the read pointer to the initial fifo address when preparing a playback. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit fcced66f208d778aa2dea05910161689503c16bf - git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/axg-frddr.c | 143 +++++++++++++++++++++++++++++++++++- - 1 file changed, 140 insertions(+), 3 deletions(-) - -diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c -index a6f6f6a2eca80..2b8807737b2be 100644 ---- a/sound/soc/meson/axg-frddr.c -+++ b/sound/soc/meson/axg-frddr.c -@@ -3,7 +3,9 @@ - // Copyright (c) 2018 BayLibre, SAS. - // Author: Jerome Brunet - --/* This driver implements the frontend playback DAI of AXG based SoCs */ -+/* -+ * This driver implements the frontend playback DAI of AXG and G12A based SoCs -+ */ - - #include - #include -@@ -14,7 +16,29 @@ - - #include "axg-fifo.h" - --#define CTRL0_FRDDR_PP_MODE BIT(30) -+#define CTRL0_FRDDR_PP_MODE BIT(30) -+#define CTRL0_SEL1_EN_SHIFT 3 -+#define CTRL0_SEL2_SHIFT 4 -+#define CTRL0_SEL2_EN_SHIFT 7 -+#define CTRL0_SEL3_SHIFT 8 -+#define CTRL0_SEL3_EN_SHIFT 11 -+#define CTRL1_FRDDR_FORCE_FINISH BIT(12) -+ -+static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); -+ -+ /* Reset the read pointer to the FIFO_INIT_ADDR */ -+ regmap_update_bits(fifo->map, FIFO_CTRL1, -+ CTRL1_FRDDR_FORCE_FINISH, 0); -+ regmap_update_bits(fifo->map, FIFO_CTRL1, -+ CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH); -+ regmap_update_bits(fifo->map, FIFO_CTRL1, -+ CTRL1_FRDDR_FORCE_FINISH, 0); -+ -+ return 0; -+} - - static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -@@ -119,10 +143,123 @@ static const struct axg_fifo_match_data axg_frddr_match_data = { - .dai_drv = &axg_frddr_dai_drv - }; - -+static const struct snd_soc_dai_ops g12a_frddr_ops = { -+ .prepare = g12a_frddr_dai_prepare, -+ .startup = axg_frddr_dai_startup, -+ .shutdown = axg_frddr_dai_shutdown, -+}; -+ -+static struct snd_soc_dai_driver g12a_frddr_dai_drv = { -+ .name = "FRDDR", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 1, -+ .channels_max = AXG_FIFO_CH_MAX, -+ .rates = AXG_FIFO_RATES, -+ .formats = AXG_FIFO_FORMATS, -+ }, -+ .ops = &g12a_frddr_ops, -+ .pcm_new = axg_frddr_pcm_new, -+}; -+ -+static const char * const g12a_frddr_sel_texts[] = { -+ "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", -+}; -+ -+static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, -+ g12a_frddr_sel_texts); -+static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT, -+ g12a_frddr_sel_texts); -+static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT, -+ g12a_frddr_sel_texts); -+ -+static const struct snd_kcontrol_new g12a_frddr_out1_demux = -+ SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum); -+static const struct snd_kcontrol_new g12a_frddr_out2_demux = -+ SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum); -+static const struct snd_kcontrol_new g12a_frddr_out3_demux = -+ SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum); -+ -+static const struct snd_kcontrol_new g12a_frddr_out1_enable = -+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, -+ CTRL0_SEL1_EN_SHIFT, 1, 0); -+static const struct snd_kcontrol_new g12a_frddr_out2_enable = -+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, -+ CTRL0_SEL2_EN_SHIFT, 1, 0); -+static const struct snd_kcontrol_new g12a_frddr_out3_enable = -+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, -+ CTRL0_SEL3_EN_SHIFT, 1, 0); -+ -+static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = { -+ SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0, -+ &g12a_frddr_out1_enable), -+ SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0, -+ &g12a_frddr_out2_enable), -+ SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0, -+ &g12a_frddr_out3_enable), -+ SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0, -+ &g12a_frddr_out1_demux), -+ SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0, -+ &g12a_frddr_out2_demux), -+ SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0, -+ &g12a_frddr_out3_demux), -+ SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), -+}; -+ -+static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = { -+ { "SRC 1", NULL, "Playback" }, -+ { "SRC 2", NULL, "Playback" }, -+ { "SRC 3", NULL, "Playback" }, -+ { "SRC 1 EN", "Switch", "SRC 1" }, -+ { "SRC 2 EN", "Switch", "SRC 2" }, -+ { "SRC 3 EN", "Switch", "SRC 3" }, -+ { "SINK 1 SEL", NULL, "SRC 1 EN" }, -+ { "SINK 2 SEL", NULL, "SRC 2 EN" }, -+ { "SINK 3 SEL", NULL, "SRC 3 EN" }, -+ { "OUT 0", "OUT 0", "SINK 1 SEL" }, -+ { "OUT 1", "OUT 1", "SINK 1 SEL" }, -+ { "OUT 2", "OUT 2", "SINK 1 SEL" }, -+ { "OUT 3", "OUT 3", "SINK 1 SEL" }, -+ { "OUT 4", "OUT 4", "SINK 1 SEL" }, -+ { "OUT 0", "OUT 0", "SINK 2 SEL" }, -+ { "OUT 1", "OUT 1", "SINK 2 SEL" }, -+ { "OUT 2", "OUT 2", "SINK 2 SEL" }, -+ { "OUT 3", "OUT 3", "SINK 2 SEL" }, -+ { "OUT 4", "OUT 4", "SINK 2 SEL" }, -+ { "OUT 0", "OUT 0", "SINK 3 SEL" }, -+ { "OUT 1", "OUT 1", "SINK 3 SEL" }, -+ { "OUT 2", "OUT 2", "SINK 3 SEL" }, -+ { "OUT 3", "OUT 3", "SINK 3 SEL" }, -+ { "OUT 4", "OUT 4", "SINK 3 SEL" }, -+}; -+ -+static const struct snd_soc_component_driver g12a_frddr_component_drv = { -+ .dapm_widgets = g12a_frddr_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets), -+ .dapm_routes = g12a_frddr_dapm_routes, -+ .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), -+ .ops = &g12a_fifo_pcm_ops -+}; -+ -+static const struct axg_fifo_match_data g12a_frddr_match_data = { -+ .component_drv = &g12a_frddr_component_drv, -+ .dai_drv = &g12a_frddr_dai_drv -+}; -+ - static const struct of_device_id axg_frddr_of_match[] = { - { - .compatible = "amlogic,axg-frddr", - .data = &axg_frddr_match_data, -+ }, { -+ .compatible = "amlogic,g12a-frddr", -+ .data = &g12a_frddr_match_data, - }, {} - }; - MODULE_DEVICE_TABLE(of, axg_frddr_of_match); -@@ -136,6 +273,6 @@ static struct platform_driver axg_frddr_pdrv = { - }; - module_platform_driver(axg_frddr_pdrv); - --MODULE_DESCRIPTION("Amlogic AXG playback fifo driver"); -+MODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver"); - MODULE_AUTHOR("Jerome Brunet "); - MODULE_LICENSE("GPL v2"); - -From 26d9868563f2192ab78f2ab9cb3e7455e2aa537e Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 13:17:32 +0200 -Subject: [PATCH 074/249] FROMGIT: ASoC: meson: axg-tdm-formatter: rework - quirks settings - -The g12a tdmout requires a different signal skew offset than the axg. -With this change, the skew offset is added as a parameter of the tdm -formatters to prepare the addition of the g12a support. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit f01bc67f58fde599b48d2dde5d0f48dccd84c4f1 - git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/axg-tdm-formatter.c | 6 ++++-- - sound/soc/meson/axg-tdm-formatter.h | 11 +++++++++-- - sound/soc/meson/axg-tdmin.c | 16 +++++++++++----- - sound/soc/meson/axg-tdmout.c | 16 +++++++++++----- - 4 files changed, 35 insertions(+), 14 deletions(-) - -diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c -index 43e390f9358a4..0c6cce5c57732 100644 ---- a/sound/soc/meson/axg-tdm-formatter.c -+++ b/sound/soc/meson/axg-tdm-formatter.c -@@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks); - static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter) - { - struct axg_tdm_stream *ts = formatter->stream; -- bool invert = formatter->drv->invert_sclk; -+ bool invert = formatter->drv->quirks->invert_sclk; - int ret; - - /* Do nothing if the formatter is already enabled */ -@@ -85,7 +85,9 @@ static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter) - return ret; - - /* Setup the stream parameter in the formatter */ -- ret = formatter->drv->ops->prepare(formatter->map, formatter->stream); -+ ret = formatter->drv->ops->prepare(formatter->map, -+ formatter->drv->quirks, -+ formatter->stream); - if (ret) - return ret; - -diff --git a/sound/soc/meson/axg-tdm-formatter.h b/sound/soc/meson/axg-tdm-formatter.h -index cf947caf3cb15..9ef98e955cb27 100644 ---- a/sound/soc/meson/axg-tdm-formatter.h -+++ b/sound/soc/meson/axg-tdm-formatter.h -@@ -14,18 +14,25 @@ struct regmap; - struct snd_soc_dapm_widget; - struct snd_kcontrol; - -+struct axg_tdm_formatter_hw { -+ unsigned int skew_offset; -+ bool invert_sclk; -+}; -+ - struct axg_tdm_formatter_ops { - struct axg_tdm_stream *(*get_stream)(struct snd_soc_dapm_widget *w); - void (*enable)(struct regmap *map); - void (*disable)(struct regmap *map); -- int (*prepare)(struct regmap *map, struct axg_tdm_stream *ts); -+ int (*prepare)(struct regmap *map, -+ const struct axg_tdm_formatter_hw *quirks, -+ struct axg_tdm_stream *ts); - }; - - struct axg_tdm_formatter_driver { - const struct snd_soc_component_driver *component_drv; - const struct regmap_config *regmap_cfg; - const struct axg_tdm_formatter_ops *ops; -- bool invert_sclk; -+ const struct axg_tdm_formatter_hw *quirks; - }; - - int axg_tdm_formatter_set_channel_masks(struct regmap *map, -diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c -index bbac44c816886..a790f925a4ef3 100644 ---- a/sound/soc/meson/axg-tdmin.c -+++ b/sound/soc/meson/axg-tdmin.c -@@ -107,21 +107,22 @@ static void axg_tdmin_disable(struct regmap *map) - regmap_update_bits(map, TDMIN_CTRL, TDMIN_CTRL_ENABLE, 0); - } - --static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts) -+static int axg_tdmin_prepare(struct regmap *map, -+ const struct axg_tdm_formatter_hw *quirks, -+ struct axg_tdm_stream *ts) - { -- unsigned int val = 0; -+ unsigned int val, skew = quirks->skew_offset; - - /* Set stream skew */ - switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_DSP_A: -- val |= TDMIN_CTRL_IN_BIT_SKEW(3); -+ skew += 1; - break; - - case SND_SOC_DAIFMT_LEFT_J: - case SND_SOC_DAIFMT_RIGHT_J: - case SND_SOC_DAIFMT_DSP_B: -- val = TDMIN_CTRL_IN_BIT_SKEW(2); - break; - - default: -@@ -130,6 +131,8 @@ static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts) - return -EINVAL; - } - -+ val = TDMIN_CTRL_IN_BIT_SKEW(skew); -+ - /* Set stream format mode */ - switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: -@@ -204,7 +207,10 @@ static const struct axg_tdm_formatter_driver axg_tdmin_drv = { - .component_drv = &axg_tdmin_component_drv, - .regmap_cfg = &axg_tdmin_regmap_cfg, - .ops = &axg_tdmin_ops, -- .invert_sclk = false, -+ .quirks = &(const struct axg_tdm_formatter_hw) { -+ .invert_sclk = false, -+ .skew_offset = 2, -+ }, - }; - - static const struct of_device_id axg_tdmin_of_match[] = { -diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c -index f73368ee1088f..3984818e2a7cf 100644 ---- a/sound/soc/meson/axg-tdmout.c -+++ b/sound/soc/meson/axg-tdmout.c -@@ -124,21 +124,22 @@ static void axg_tdmout_disable(struct regmap *map) - regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0); - } - --static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts) -+static int axg_tdmout_prepare(struct regmap *map, -+ const struct axg_tdm_formatter_hw *quirks, -+ struct axg_tdm_stream *ts) - { -- unsigned int val = 0; -+ unsigned int val, skew = quirks->skew_offset; - - /* Set the stream skew */ - switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_DSP_A: -- val |= TDMOUT_CTRL0_INIT_BITNUM(1); - break; - - case SND_SOC_DAIFMT_LEFT_J: - case SND_SOC_DAIFMT_RIGHT_J: - case SND_SOC_DAIFMT_DSP_B: -- val |= TDMOUT_CTRL0_INIT_BITNUM(2); -+ skew += 1; - break; - - default: -@@ -147,6 +148,8 @@ static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts) - return -EINVAL; - } - -+ val = TDMOUT_CTRL0_INIT_BITNUM(skew); -+ - /* Set the slot width */ - val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1); - -@@ -234,7 +237,10 @@ static const struct axg_tdm_formatter_driver axg_tdmout_drv = { - .component_drv = &axg_tdmout_component_drv, - .regmap_cfg = &axg_tdmout_regmap_cfg, - .ops = &axg_tdmout_ops, -- .invert_sclk = true, -+ .quirks = &(const struct axg_tdm_formatter_hw) { -+ .invert_sclk = true, -+ .skew_offset = 1, -+ }, - }; - - static const struct of_device_id axg_tdmout_of_match[] = { - -From a100d9ea2b2aaaaf8c8a16582472fd0caf9c0c2e Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 13:17:33 +0200 -Subject: [PATCH 075/249] FROMGIT: ASoC: meson: axg-tdmout: add g12a support - -The axg tdmout driver just need a different skew offset to operate -correctly on the g12a SoC family. - -Signed-off-by: Jerome Brunet -Signed-off-by: Mark Brown -(cherry picked from commit aa191a37b801be6c5abebe77e67dcec7c5c0faee - git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/axg-tdmout.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c -index 3984818e2a7cf..527bfc4487e02 100644 ---- a/sound/soc/meson/axg-tdmout.c -+++ b/sound/soc/meson/axg-tdmout.c -@@ -243,10 +243,23 @@ static const struct axg_tdm_formatter_driver axg_tdmout_drv = { - }, - }; - -+static const struct axg_tdm_formatter_driver g12a_tdmout_drv = { -+ .component_drv = &axg_tdmout_component_drv, -+ .regmap_cfg = &axg_tdmout_regmap_cfg, -+ .ops = &axg_tdmout_ops, -+ .quirks = &(const struct axg_tdm_formatter_hw) { -+ .invert_sclk = true, -+ .skew_offset = 2, -+ }, -+}; -+ - static const struct of_device_id axg_tdmout_of_match[] = { - { - .compatible = "amlogic,axg-tdmout", - .data = &axg_tdmout_drv, -+ }, { -+ .compatible = "amlogic,g12a-tdmout", -+ .data = &g12a_tdmout_drv, - }, {} - }; - MODULE_DEVICE_TABLE(of, axg_tdmout_of_match); - -From ddeda41714235e1959a77f2effd9550f5e8f058c Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 13 Mar 2019 15:10:30 +0100 -Subject: [PATCH 076/249] FROMGIT: dt-bindings: power: amlogic, meson-gx-pwrc: - Add G12A compatible - -The Amlogic G12A has a slighly different Power Control, but uses the -same address space and sysctrl registers. - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring -Signed-off-by: Kevin Hilman -(cherry picked from commit 55d76e83a39d2cba7ed686327498efb386b7e8f7 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../devicetree/bindings/power/amlogic,meson-gx-pwrc.txt | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt b/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt -index 1cd050b4054ca..0fdc3dd1125e8 100644 ---- a/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt -+++ b/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt -@@ -16,7 +16,9 @@ Device Tree Bindings: - --------------------- - - Required properties: --- compatible: should be "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs -+- compatible: should be one of the following : -+ - "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs -+ - "amlogic,meson-g12a-pwrc-vpu" for the Meson G12A SoCs - - #power-domain-cells: should be 0 - - amlogic,hhi-sysctrl: phandle to the HHI sysctrl node - - resets: phandles to the reset lines needed for this power demain sequence - -From 90afb116135299eb312c812307ddbb6b3c8dd9d6 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:03:37 +0100 -Subject: [PATCH 077/249] FROMGIT: arm64: dts: meson: g12a: Add SAR ADC node - -This patch adds the SAR ADC controller node. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 820873cf38daaf965b37018028c5cc7015735745 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index d6ca0bbd8f74a..9c666e2a45b0a 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -5,6 +5,7 @@ - - #include - #include -+#include - #include - #include - -@@ -290,6 +291,20 @@ - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; -+ -+ saradc: adc@9000 { -+ compatible = "amlogic,meson-g12a-saradc", -+ "amlogic,meson-saradc"; -+ reg = <0x0 0x9000 0x0 0x48>; -+ #io-channel-cells = <1>; -+ interrupts = ; -+ clocks = <&xtal>, -+ <&clkc_AO CLKID_AO_SAR_ADC>, -+ <&clkc_AO CLKID_AO_SAR_ADC_CLK>, -+ <&clkc_AO CLKID_AO_SAR_ADC_SEL>; -+ clock-names = "clkin", "core", "adc_clk", "adc_sel"; -+ status = "disabled"; -+ }; - }; - - gic: interrupt-controller@ffc01000 { - -From 45d610803e08336acf7f831114714cc8b363b0d9 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:03:38 +0100 -Subject: [PATCH 078/249] FROMGIT: arm64: dts: meson: g12a: Add G12A USB nodes - -This patch adds the nodes for the USB Complex found in the Amlogic -G12A SoC. - -It includes the : -- 2 USB2 PHYs -- 1 USB3 + PCIE Combo PHY -- the USB Glue with it's DWC2 and DWC3 sub-nodes - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 9baf7d6be730cbd996eb56d6047ff1d5147cbff0 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 75 +++++++++++++++++++++ - 1 file changed, 75 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 9c666e2a45b0a..d4dc1a6caab50 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -3,11 +3,13 @@ - * Copyright (c) 2018 Amlogic, Inc. All rights reserved. - */ - -+#include - #include - #include - #include - #include - #include -+#include - - / { - compatible = "amlogic,g12a"; -@@ -183,6 +185,26 @@ - }; - }; - -+ usb2_phy0: phy@36000 { -+ compatible = "amlogic,g12a-usb2-phy"; -+ reg = <0x0 0x36000 0x0 0x2000>; -+ clocks = <&xtal>; -+ clock-names = "xtal"; -+ resets = <&reset RESET_USB_PHY20>; -+ reset-names = "phy"; -+ #phy-cells = <0>; -+ }; -+ -+ usb2_phy1: phy@3a000 { -+ compatible = "amlogic,g12a-usb2-phy"; -+ reg = <0x0 0x3a000 0x0 0x2000>; -+ clocks = <&xtal>; -+ clock-names = "xtal"; -+ resets = <&reset RESET_USB_PHY21>; -+ reset-names = "phy"; -+ #phy-cells = <0>; -+ }; -+ - hiu: bus@3c000 { - compatible = "simple-bus"; - reg = <0x0 0x3c000 0x0 0x1400>; -@@ -203,6 +225,18 @@ - }; - }; - }; -+ -+ usb3_pcie_phy: phy@46000 { -+ compatible = "amlogic,g12a-usb3-pcie-phy"; -+ reg = <0x0 0x46000 0x0 0x2000>; -+ clocks = <&clkc CLKID_PCIE_PLL>; -+ clock-names = "ref_clk"; -+ resets = <&reset RESET_PCIE_PHY>; -+ reset-names = "phy"; -+ assigned-clocks = <&clkc CLKID_PCIE_PLL>; -+ assigned-clock-rates = <100000000>; -+ #phy-cells = <1>; -+ }; - }; - - aobus: bus@ff800000 { -@@ -366,6 +400,47 @@ - status = "disabled"; - }; - }; -+ -+ usb: usb@ffe09000 { -+ status = "disabled"; -+ compatible = "amlogic,meson-g12a-usb-ctrl"; -+ reg = <0x0 0xffe09000 0x0 0xa0>; -+ interrupts = ; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ clocks = <&clkc CLKID_USB>; -+ resets = <&reset RESET_USB>; -+ -+ dr_mode = "otg"; -+ -+ phys = <&usb2_phy0>, <&usb2_phy1>, -+ <&usb3_pcie_phy PHY_TYPE_USB3>; -+ phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; -+ -+ dwc2: usb@ff400000 { -+ compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; -+ reg = <0x0 0xff400000 0x0 0x40000>; -+ interrupts = ; -+ clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; -+ clock-names = "ddr"; -+ phys = <&usb2_phy1>; -+ dr_mode = "peripheral"; -+ g-rx-fifo-size = <192>; -+ g-np-tx-fifo-size = <128>; -+ g-tx-fifo-size = <128 128 16 16 16>; -+ }; -+ -+ dwc3: usb@ff500000 { -+ compatible = "snps,dwc3"; -+ reg = <0x0 0xff500000 0x0 0x100000>; -+ interrupts = ; -+ dr_mode = "host"; -+ snps,dis_u2_susphy_quirk; -+ snps,quirk-frame-length-adjustment; -+ }; -+ }; - }; - - timer { - -From e32830e48024d722be800777e6d3a83c6e636da6 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:03:39 +0100 -Subject: [PATCH 079/249] FROMGIT: arm64: dts: meson: g12a: Add mali-g31 gpu - node - -This patch adds the ARM Mali G31 GPU node. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 2607fd087370777fd2ae2ff7c1681fe1fb02566d - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 27 +++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index d4dc1a6caab50..858ddd68665c9 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -441,6 +441,33 @@ - snps,quirk-frame-length-adjustment; - }; - }; -+ -+ mali: gpu@ffe40000 { -+ compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; -+ reg = <0x0 0xffe40000 0x0 0x40000>; -+ interrupt-parent = <&gic>; -+ interrupts = , -+ , -+ ; -+ interrupt-names = "gpu", "mmu", "job"; -+ clocks = <&clkc CLKID_MALI>; -+ resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; -+ -+ /* -+ * Mali clocking is provided by two identical clock paths -+ * MALI_0 and MALI_1 muxed to a single clock by a glitch -+ * free mux to safely change frequency while running. -+ */ -+ assigned-clocks = <&clkc CLKID_MALI_0_SEL>, -+ <&clkc CLKID_MALI_0>, -+ <&clkc CLKID_MALI>; /* Glitch free mux */ -+ assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>, -+ <0>, /* Do Nothing */ -+ <&clkc CLKID_MALI_0>; -+ assigned-clock-rates = <0>, /* Do Nothing */ -+ <800000000>, -+ <0>; /* Do Nothing */ -+ }; - }; - - timer { - -From d8aea2c7f9f8400f299ea9d81defc796e17cf542 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 18 Mar 2019 11:04:51 +0100 -Subject: [PATCH 080/249] FROMGIT: arm64: dts: meson-g12a-u200: add regulators - -Add system regulators for the S905D U200 reference design. - -Add some regulators. Still missing -* VDD_EE (0.8V - PWM controlled) -* VDD_CPU (PWM controlled) - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -Acked-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit aa77657b018fbd0eebfc78ee3f8b07fec4f5cda7 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../boot/dts/amlogic/meson-g12a-u200.dts | 79 +++++++++++++++++++ - 1 file changed, 79 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index f2afd0bf3e28b..c69328d163337 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -6,6 +6,8 @@ - /dts-v1/; - - #include "meson-g12a.dtsi" -+#include -+#include - - / { - compatible = "amlogic,u200", "amlogic,g12a"; -@@ -21,6 +23,83 @@ - device_type = "memory"; - reg = <0x0 0x0 0x0 0x40000000>; - }; -+ -+ flash_1v8: regulator-flash_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "FLASH_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ -+ main_12v: regulator-main_12v { -+ compatible = "regulator-fixed"; -+ regulator-name = "12V"; -+ regulator-min-microvolt = <12000000>; -+ regulator-max-microvolt = <12000000>; -+ regulator-always-on; -+ }; -+ -+ vcc_1v8: regulator-vcc_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ -+ vcc_3v3: regulator-vcc_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ /* FIXME: actually controlled by VDDCPU_B_EN */ -+ }; -+ -+ vcc_5v: regulator-vcc_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&main_12v>; -+ -+ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; -+ enable-active-high; -+ }; -+ -+ usb_pwr_en: regulator-usb_pwr_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "USB_PWR_EN"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&vcc_5v>; -+ -+ gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ }; -+ -+ vddao_1v8: regulator-vddao_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ -+ vddao_3v3: regulator-vddao_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&main_12v>; -+ regulator-always-on; -+ }; -+ - }; - - &uart_AO { - -From f3888b33e14cfb4c288f096cf45a30a656d17e15 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:14:50 +0100 -Subject: [PATCH 081/249] FROMGIT: arm64: dts: meson-g12a-sei510: Add ADC Key - and BT support - -Add support for the : -- ADC Touch key -- Bluetooth Module on UART A - -Signed-off-by: Neil Armstrong -Acked-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit d1c023af198835833203f64160d3aefe1fbb45e8 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../boot/dts/amlogic/meson-g12a-sei510.dts | 30 +++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 43d57e20294a0..ebdad5a192f1c 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -7,6 +7,7 @@ - - #include "meson-g12a.dtsi" - #include -+#include - #include - - / { -@@ -17,6 +18,19 @@ - serial0 = &uart_AO; - }; - -+ adc_keys { -+ compatible = "adc-keys"; -+ io-channels = <&saradc 0>; -+ io-channel-names = "buttons"; -+ keyup-threshold-microvolt = <1800000>; -+ -+ button-onoff { -+ label = "On/Off"; -+ linux,code = ; -+ press-threshold-microvolt = <1700000>; -+ }; -+ }; -+ - ao_5v: regulator-ao_5v { - compatible = "regulator-fixed"; - regulator-name = "AO_5V"; -@@ -87,7 +101,23 @@ - vin-supply = <&vddao_3v3>; - regulator-always-on; - }; -+}; -+ -+&saradc { -+ status = "okay"; -+ vref-supply = <&vddio_ao1v8>; -+}; -+ -+&uart_A { -+ status = "okay"; -+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; -+ pinctrl-names = "default"; -+ uart-has-rtscts; - -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; -+ }; - }; - - &uart_AO { - -From 81bdbeb60217f55e1996331909b01bb53d26db0b Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:14:51 +0100 -Subject: [PATCH 082/249] FROMGIT: arm64: dts: meson-g12a-sei510: Enable USB - -Enable the USB2 and USB3 Host ports on the SEI520 Set-Top-Box. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 41cc4551f45470c6052c84615af81873122cf158 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index ebdad5a192f1c..c350a0165d447 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -125,3 +125,8 @@ - pinctrl-0 = <&uart_ao_a_pins>; - pinctrl-names = "default"; - }; -+ -+&usb { -+ status = "okay"; -+ dr_mode = "host"; -+}; - -From 97b5ad85d2c4b2209423e7dc7187855fc3155dd7 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:14:52 +0100 -Subject: [PATCH 083/249] FROMGIT: arm64: dts: meson-g12a-u200: Enable USB - -Enable the USB2 OTG and USB3 Host ports on the S905D2 Reference Design. - -Signed-off-by: Neil Armstrong -Acked-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 8ad7624453cf1c6788b726e51727a2c7c4f7abd3 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index c69328d163337..2240e365af27e 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -108,3 +108,15 @@ - pinctrl-names = "default"; - }; - -+&usb { -+ status = "okay"; -+ vbus-supply = <&usb_pwr_en>; -+}; -+ -+&usb2_phy0 { -+ phy-supply = <&vcc_5v>; -+}; -+ -+&usb2_phy1 { -+ phy-supply = <&vcc_5v>; -+}; - -From 8427322c45ac90aa04a8c5fbed25dcd6a9e98b08 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 25 Mar 2019 11:14:53 +0100 -Subject: [PATCH 084/249] FROMGIT: arm64: dts: meson-g12a-x96-max: Enable USB - -Enable the USB2 and USB3 Host ports on the X96 Max Set-Top-Box. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Kevin Hilman -(cherry picked from commit 45b72126022923ebdcd9f9b58af1ff47f73452fa - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 0a6919523ba94..b5b88262c06a3 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -107,3 +107,8 @@ - pinctrl-0 = <&uart_ao_a_pins>; - pinctrl-names = "default"; - }; -+ -+&usb { -+ status = "okay"; -+ dr_mode = "host"; -+}; - -From 5863c32f2d98803eecb3d386f392300ddb061e3b Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 8 Apr 2019 11:31:35 +0200 -Subject: [PATCH 085/249] FROMGIT: arm64: dts: meson-g12a: Add VPU and HDMI - related nodes - -Add VPU and HDMI display support. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 083feecd854833dcee8f1e98d7197195f5fd3649 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 131 ++++++++++++++++++++ - 1 file changed, 131 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 858ddd68665c9..a696612f8f442 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -109,6 +109,37 @@ - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xff600000 0x0 0x200000>; - -+ hdmi_tx: hdmi-tx@0 { -+ compatible = "amlogic,meson-g12a-dw-hdmi"; -+ reg = <0x0 0x0 0x0 0x10000>; -+ interrupts = ; -+ resets = <&reset RESET_HDMITX_CAPB3>, -+ <&reset RESET_HDMITX_PHY>, -+ <&reset RESET_HDMITX>; -+ reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; -+ clocks = <&clkc CLKID_HDMI>, -+ <&clkc CLKID_HTX_PCLK>, -+ <&clkc CLKID_VPU_INTR>; -+ clock-names = "isfr", "iahb", "venci"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ -+ /* VPU VENC Input */ -+ hdmi_tx_venc_port: port@0 { -+ reg = <0>; -+ -+ hdmi_tx_in: endpoint { -+ remote-endpoint = <&hdmi_tx_out>; -+ }; -+ }; -+ -+ /* TMDS Output */ -+ hdmi_tx_tmds_port: port@1 { -+ reg = <1>; -+ }; -+ }; -+ - periphs: bus@34400 { - compatible = "simple-bus"; - reg = <0x0 0x34400 0x0 0x400>; -@@ -138,6 +169,23 @@ - gpio-ranges = <&periphs_pinctrl 0 0 86>; - }; - -+ hdmitx_ddc_pins: hdmitx_ddc { -+ mux { -+ groups = "hdmitx_sda", -+ "hdmitx_sck"; -+ function = "hdmitx"; -+ bias-disable; -+ }; -+ }; -+ -+ hdmitx_hpd_pins: hdmitx_hpd { -+ mux { -+ groups = "hdmitx_hpd_in"; -+ function = "hdmitx"; -+ bias-disable; -+ }; -+ }; -+ - uart_a_pins: uart-a { - mux { - groups = "uart_a_tx", -@@ -195,6 +243,19 @@ - #phy-cells = <0>; - }; - -+ dmc: bus@38000 { -+ compatible = "simple-bus"; -+ reg = <0x0 0x38000 0x0 0x400>; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>; -+ -+ canvas: video-lut@48 { -+ compatible = "amlogic,canvas"; -+ reg = <0x0 0x48 0x0 0x14>; -+ }; -+ }; -+ - usb2_phy1: phy@3a000 { - compatible = "amlogic,g12a-usb2-phy"; - reg = <0x0 0x3a000 0x0 0x2000>; -@@ -262,6 +323,50 @@ - clock-names = "xtal", "mpeg-clk"; - }; - -+ pwrc_vpu: power-controller-vpu { -+ compatible = "amlogic,meson-g12a-pwrc-vpu"; -+ #power-domain-cells = <0>; -+ amlogic,hhi-sysctrl = <&hhi>; -+ resets = <&reset RESET_VIU>, -+ <&reset RESET_VENC>, -+ <&reset RESET_VCBUS>, -+ <&reset RESET_BT656>, -+ <&reset RESET_RDMA>, -+ <&reset RESET_VENCI>, -+ <&reset RESET_VENCP>, -+ <&reset RESET_VDAC>, -+ <&reset RESET_VDI6>, -+ <&reset RESET_VENCL>, -+ <&reset RESET_VID_LOCK>; -+ clocks = <&clkc CLKID_VPU>, -+ <&clkc CLKID_VAPB>; -+ clock-names = "vpu", "vapb"; -+ /* -+ * VPU clocking is provided by two identical clock paths -+ * VPU_0 and VPU_1 muxed to a single clock by a glitch -+ * free mux to safely change frequency while running. -+ * Same for VAPB but with a final gate after the glitch free mux. -+ */ -+ assigned-clocks = <&clkc CLKID_VPU_0_SEL>, -+ <&clkc CLKID_VPU_0>, -+ <&clkc CLKID_VPU>, /* Glitch free mux */ -+ <&clkc CLKID_VAPB_0_SEL>, -+ <&clkc CLKID_VAPB_0>, -+ <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ -+ assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, -+ <0>, /* Do Nothing */ -+ <&clkc CLKID_VPU_0>, -+ <&clkc CLKID_FCLK_DIV4>, -+ <0>, /* Do Nothing */ -+ <&clkc CLKID_VAPB_0>; -+ assigned-clock-rates = <0>, /* Do Nothing */ -+ <666666666>, -+ <0>, /* Do Nothing */ -+ <0>, /* Do Nothing */ -+ <250000000>, -+ <0>; /* Do Nothing */ -+ }; -+ - ao_pinctrl: pinctrl@14 { - compatible = "amlogic,meson-g12a-aobus-pinctrl"; - #address-cells = <2>; -@@ -341,6 +446,32 @@ - }; - }; - -+ vpu: vpu@ff900000 { -+ compatible = "amlogic,meson-g12a-vpu"; -+ reg = <0x0 0xff900000 0x0 0x100000>, -+ <0x0 0xff63c000 0x0 0x1000>; -+ reg-names = "vpu", "hhi"; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ amlogic,canvas = <&canvas>; -+ power-domains = <&pwrc_vpu>; -+ -+ /* CVBS VDAC output port */ -+ cvbs_vdac_port: port@0 { -+ reg = <0>; -+ }; -+ -+ /* HDMI-TX output port */ -+ hdmi_tx_port: port@1 { -+ reg = <1>; -+ -+ hdmi_tx_out: endpoint { -+ remote-endpoint = <&hdmi_tx_in>; -+ }; -+ }; -+ }; -+ - gic: interrupt-controller@ffc01000 { - compatible = "arm,gic-400"; - reg = <0x0 0xffc01000 0 0x1000>, - -From 625b73d78138030e6fbb84f2595ec4c4b90e2212 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 8 Apr 2019 11:31:36 +0200 -Subject: [PATCH 086/249] FROMGIT: arm64: dts: meson-g12a: Add AO-CEC nodes - -Amlogic G12A embeds 2 CEC controllers : -- AO-CEC-A the same controller as in GXBB, GXL & GXM SoCs -- AO-CEC-B is a new controller - -Note, the two controller can work simultanously since 2 Pads can -handle CEC, thus this SoC can handle 2 distinct CEC busses. - -This patch adds the nodes for the AO-CEC-A and AO-CEC-B controllers. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 91516e5419cf91947213b4d9c62b4728701063e9 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 34 +++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index a696612f8f442..9f72396ba7103 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -169,6 +169,22 @@ - gpio-ranges = <&periphs_pinctrl 0 0 86>; - }; - -+ cec_ao_a_h_pins: cec_ao_a_h { -+ mux { -+ groups = "cec_ao_a_h"; -+ function = "cec_ao_a_h"; -+ bias-disable; -+ }; -+ }; -+ -+ cec_ao_b_h_pins: cec_ao_b_h { -+ mux { -+ groups = "cec_ao_b_h"; -+ function = "cec_ao_b_h"; -+ bias-disable; -+ }; -+ }; -+ - hdmitx_ddc_pins: hdmitx_ddc { - mux { - groups = "hdmitx_sda", -@@ -405,12 +421,30 @@ - }; - }; - -+ cec_AO: cec@100 { -+ compatible = "amlogic,meson-gx-ao-cec"; -+ reg = <0x0 0x00100 0x0 0x14>; -+ interrupts = ; -+ clocks = <&clkc_AO CLKID_AO_CEC>; -+ clock-names = "core"; -+ status = "disabled"; -+ }; -+ - sec_AO: ao-secure@140 { - compatible = "amlogic,meson-gx-ao-secure", "syscon"; - reg = <0x0 0x140 0x0 0x140>; - amlogic,has-chip-id; - }; - -+ cecb_AO: cec@280 { -+ compatible = "amlogic,meson-g12a-ao-cec"; -+ reg = <0x0 0x00280 0x0 0x1c>; -+ interrupts = ; -+ clocks = <&clkc_AO CLKID_AO_CTS_OSCIN>; -+ clock-names = "oscin"; -+ status = "disabled"; -+ }; -+ - uart_AO: serial@3000 { - compatible = "amlogic,meson-gx-uart", - "amlogic,meson-ao-uart"; - -From ea29362ac5d2a99cb60dc4712049052c206044ba Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 8 Apr 2019 11:31:37 +0200 -Subject: [PATCH 087/249] FROMGIT: arm64: dts: meson-g12a-x96-max: Add support - for Video Display - -This patch adds the HDMI, CVBS and CEC attributes and nodes to support -full display on the X96 Max STB. - -AO-CEC-B is used by default and AO-CEC-A is disabled. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit b0be96160a55701af4748bcebbe0cd5fb7aec697 - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../boot/dts/amlogic/meson-g12a-x96-max.dts | 54 +++++++++++++++++++ - 1 file changed, 54 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index b5b88262c06a3..b3d913f28f121 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -24,6 +24,27 @@ - reg = <0x0 0x0 0x0 0x40000000>; - }; - -+ cvbs-connector { -+ compatible = "composite-video-connector"; -+ -+ port { -+ cvbs_connector_in: endpoint { -+ remote-endpoint = <&cvbs_vdac_out>; -+ }; -+ }; -+ }; -+ -+ hdmi-connector { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi_connector_in: endpoint { -+ remote-endpoint = <&hdmi_tx_tmds_out>; -+ }; -+ }; -+ }; -+ - flash_1v8: regulator-flash_1v8 { - compatible = "regulator-fixed"; - regulator-name = "FLASH_1V8"; -@@ -90,6 +111,39 @@ - }; - }; - -+&cec_AO { -+ pinctrl-0 = <&cec_ao_a_h_pins>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cecb_AO { -+ pinctrl-0 = <&cec_ao_b_h_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cvbs_vdac_port { -+ cvbs_vdac_out: endpoint { -+ remote-endpoint = <&cvbs_connector_in>; -+ }; -+}; -+ -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -+ pinctrl-names = "default"; -+ hdmi-supply = <&vcc_5v>; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ - &uart_A { - status = "okay"; - pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; - -From f0cf87ede64f379eb27d5a8cb6db7cca1692fcd6 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 8 Apr 2019 11:31:38 +0200 -Subject: [PATCH 088/249] FROMGIT: arm64: dts: meson-g12a-sei510: Add support - for Video Display - -This patch adds the HDMI, CVBS and CEC attributes and nodes to support -full display on the SEI510 STB. - -AO-CEC-B is used by default and AO-CEC-A is disabled. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 912a3395df3a80fe789ebc406e595314ebefc45e - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../boot/dts/amlogic/meson-g12a-sei510.dts | 53 +++++++++++++++++++ - 1 file changed, 53 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index c350a0165d447..34b40587e5ef1 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -44,6 +44,16 @@ - stdout-path = "serial0:115200n8"; - }; - -+ cvbs-connector { -+ compatible = "composite-video-connector"; -+ -+ port { -+ cvbs_connector_in: endpoint { -+ remote-endpoint = <&cvbs_vdac_out>; -+ }; -+ }; -+ }; -+ - dc_in: regulator-dc_in { - compatible = "regulator-fixed"; - regulator-name = "DC_IN"; -@@ -61,6 +71,17 @@ - regulator-always-on; - }; - -+ hdmi-connector { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi_connector_in: endpoint { -+ remote-endpoint = <&hdmi_tx_tmds_out>; -+ }; -+ }; -+ }; -+ - memory@0 { - device_type = "memory"; - reg = <0x0 0x0 0x0 0x40000000>; -@@ -103,6 +124,26 @@ - }; - }; - -+&cec_AO { -+ pinctrl-0 = <&cec_ao_a_h_pins>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cecb_AO { -+ pinctrl-0 = <&cec_ao_b_h_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cvbs_vdac_port { -+ cvbs_vdac_out: endpoint { -+ remote-endpoint = <&cvbs_connector_in>; -+ }; -+}; -+ - &saradc { - status = "okay"; - vref-supply = <&vddio_ao1v8>; -@@ -120,6 +161,18 @@ - }; - }; - -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From 68e5a972d2af554c10e53515e70d804e4f34ebfb Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 8 Apr 2019 11:31:39 +0200 -Subject: [PATCH 089/249] FROMGIT: arm64: dts: meson-g12a-u200: Add support for - Video Display - -This patch adds the HDMI, CVBS and CEC attributes and nodes to support -full display on the U200 Reference Design. - -AO-CEC-B is used by default and AO-CEC-A is disabled. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 659f2563d323b09ca12b0e70bb6a50c1b25af3ee - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) ---- - .../boot/dts/amlogic/meson-g12a-u200.dts | 54 +++++++++++++++++++ - 1 file changed, 54 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index 2240e365af27e..0e8045b8a9158 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -24,6 +24,16 @@ - reg = <0x0 0x0 0x0 0x40000000>; - }; - -+ cvbs-connector { -+ compatible = "composite-video-connector"; -+ -+ port { -+ cvbs_connector_in: endpoint { -+ remote-endpoint = <&cvbs_vdac_out>; -+ }; -+ }; -+ }; -+ - flash_1v8: regulator-flash_1v8 { - compatible = "regulator-fixed"; - regulator-name = "FLASH_1V8"; -@@ -33,6 +43,17 @@ - regulator-always-on; - }; - -+ hdmi-connector { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi_connector_in: endpoint { -+ remote-endpoint = <&hdmi_tx_tmds_out>; -+ }; -+ }; -+ }; -+ - main_12v: regulator-main_12v { - compatible = "regulator-fixed"; - regulator-name = "12V"; -@@ -102,6 +123,39 @@ - - }; - -+&cec_AO { -+ pinctrl-0 = <&cec_ao_a_h_pins>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cecb_AO { -+ pinctrl-0 = <&cec_ao_b_h_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cvbs_vdac_port { -+ cvbs_vdac_out: endpoint { -+ remote-endpoint = <&cvbs_connector_in>; -+ }; -+}; -+ -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -+ pinctrl-names = "default"; -+ hdmi-supply = <&vcc_5v>; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From 39bfd6c05de42e7a941e0363361aca9e34056d3d Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 1 Apr 2019 09:48:01 +0200 -Subject: [PATCH 090/249] FROMGIT: soc: amlogic: meson-gx-pwrc-vpu: Fix power - on/off register bitmask - -The register bitmask to power on/off the VPU memories was incorectly set -to 0x2 instead of 0x3. While still working, let's use the recommended -vendor value instead. - -Fixes: 75fcb5ca4b46 ("soc: amlogic: add Meson GX VPU Domains driver") -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit 2fe3b4bbc93ec30a173ebae7d2b8c530416df3af - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) ---- - drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c -index 6289965c42e98..05421d029dff9 100644 ---- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c -+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c -@@ -54,12 +54,12 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) - /* Power Down Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, -- 0x2 << i, 0x3 << i); -+ 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, -- 0x2 << i, 0x3 << i); -+ 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 8; i < 16; i++) { -@@ -108,13 +108,13 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) - /* Power Up Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, -- 0x2 << i, 0); -+ 0x3 << i, 0); - udelay(5); - } - - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, -- 0x2 << i, 0); -+ 0x3 << i, 0); - udelay(5); - } - - -From 67456f6b7894b0a9a6c1b430349c88787391be28 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 1 Apr 2019 09:52:58 +0200 -Subject: [PATCH 091/249] FROMGIT: soc: amlogic: meson-gx-pwrc-vpu: Add support - for G12A - -The Amlogic G12A SoC has a very similar VPU Power Controller setup -than the older GXBB, GXL & GXm SoCs. - -This patch adds the variant support for G12A. - -Signed-off-by: Neil Armstrong -Signed-off-by: Kevin Hilman -(cherry picked from commit bb1dca3a3900a00b881286c96340d6ab85eafe0c - git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) ---- - drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 152 ++++++++++++++++++++++-- - 1 file changed, 140 insertions(+), 12 deletions(-) - -diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c -index 05421d029dff9..511b6856225d6 100644 ---- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c -+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -26,6 +27,7 @@ - #define HHI_MEM_PD_REG0 (0x40 << 2) - #define HHI_VPU_MEM_PD_REG0 (0x41 << 2) - #define HHI_VPU_MEM_PD_REG1 (0x42 << 2) -+#define HHI_VPU_MEM_PD_REG2 (0x4d << 2) - - struct meson_gx_pwrc_vpu { - struct generic_pm_domain genpd; -@@ -80,6 +82,49 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) - return 0; - } - -+static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd) -+{ -+ struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); -+ int i; -+ -+ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); -+ udelay(20); -+ -+ /* Power Down Memories */ -+ for (i = 0; i < 32; i += 2) { -+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, -+ 0x3 << i, 0x3 << i); -+ udelay(5); -+ } -+ for (i = 0; i < 32; i += 2) { -+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, -+ 0x3 << i, 0x3 << i); -+ udelay(5); -+ } -+ for (i = 0; i < 32; i += 2) { -+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, -+ 0x3 << i, 0x3 << i); -+ udelay(5); -+ } -+ for (i = 8; i < 16; i++) { -+ regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, -+ BIT(i), BIT(i)); -+ udelay(5); -+ } -+ udelay(20); -+ -+ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); -+ -+ msleep(20); -+ -+ clk_disable_unprepare(pd->vpu_clk); -+ clk_disable_unprepare(pd->vapb_clk); -+ -+ return 0; -+} -+ - static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd) - { - int ret; -@@ -143,6 +188,60 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) - return 0; - } - -+static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd) -+{ -+ struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); -+ int ret; -+ int i; -+ -+ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VPU_HDMI, 0); -+ udelay(20); -+ -+ /* Power Up Memories */ -+ for (i = 0; i < 32; i += 2) { -+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, -+ 0x3 << i, 0); -+ udelay(5); -+ } -+ -+ for (i = 0; i < 32; i += 2) { -+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, -+ 0x3 << i, 0); -+ udelay(5); -+ } -+ -+ for (i = 0; i < 32; i += 2) { -+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, -+ 0x3 << i, 0); -+ udelay(5); -+ } -+ -+ for (i = 8; i < 16; i++) { -+ regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, -+ BIT(i), 0); -+ udelay(5); -+ } -+ udelay(20); -+ -+ ret = reset_control_assert(pd->rstc); -+ if (ret) -+ return ret; -+ -+ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VPU_HDMI_ISO, 0); -+ -+ ret = reset_control_deassert(pd->rstc); -+ if (ret) -+ return ret; -+ -+ ret = meson_gx_pwrc_vpu_setup_clk(pd); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ - static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd) - { - u32 reg; -@@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = { - }, - }; - -+static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = { -+ .genpd = { -+ .name = "vpu_hdmi", -+ .power_off = meson_g12a_pwrc_vpu_power_off, -+ .power_on = meson_g12a_pwrc_vpu_power_on, -+ }, -+}; -+ - static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) - { -+ const struct meson_gx_pwrc_vpu *vpu_pd_match; - struct regmap *regmap_ao, *regmap_hhi; -+ struct meson_gx_pwrc_vpu *vpu_pd; - struct reset_control *rstc; - struct clk *vpu_clk; - struct clk *vapb_clk; - bool powered_off; - int ret; - -+ vpu_pd_match = of_device_get_match_data(&pdev->dev); -+ if (!vpu_pd_match) { -+ dev_err(&pdev->dev, "failed to get match data\n"); -+ return -ENODEV; -+ } -+ -+ vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL); -+ if (!vpu_pd) -+ return -ENOMEM; -+ -+ memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd)); -+ - regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node)); - if (IS_ERR(regmap_ao)) { - dev_err(&pdev->dev, "failed to get regmap\n"); -@@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) - return PTR_ERR(vapb_clk); - } - -- vpu_hdmi_pd.regmap_ao = regmap_ao; -- vpu_hdmi_pd.regmap_hhi = regmap_hhi; -- vpu_hdmi_pd.rstc = rstc; -- vpu_hdmi_pd.vpu_clk = vpu_clk; -- vpu_hdmi_pd.vapb_clk = vapb_clk; -+ vpu_pd->regmap_ao = regmap_ao; -+ vpu_pd->regmap_hhi = regmap_hhi; -+ vpu_pd->rstc = rstc; -+ vpu_pd->vpu_clk = vpu_clk; -+ vpu_pd->vapb_clk = vapb_clk; -+ -+ platform_set_drvdata(pdev, vpu_pd); - -- powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); -+ powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); - - /* If already powered, sync the clock states */ - if (!powered_off) { -- ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd); -+ ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd); - if (ret) - return ret; - } - -- pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov, -+ pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov, - powered_off); - - return of_genpd_add_provider_simple(pdev->dev.of_node, -- &vpu_hdmi_pd.genpd); -+ &vpu_pd->genpd); - } - - static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev) - { -+ struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev); - bool powered_off; - -- powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); -+ powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); - if (!powered_off) -- meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd); -+ vpu_pd->genpd.power_off(&vpu_pd->genpd); - } - - static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = { -- { .compatible = "amlogic,meson-gx-pwrc-vpu" }, -+ { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd }, -+ { -+ .compatible = "amlogic,meson-g12a-pwrc-vpu", -+ .data = &vpu_hdmi_pd_g12a -+ }, - { /* sentinel */ } - }; - - -From d860e5a85b15d603d5bba033246e7e2ef46cd56f Mon Sep 17 00:00:00 2001 -From: Hans Verkuil -Date: Wed, 10 Apr 2019 05:13:28 -0400 -Subject: [PATCH 092/249] FROMGIT: media: cec-notifier: add - cec_notifier_parse_hdmi_phandle helper - -Add helper function to parse the DT for the hdmi-phandle property -and return the corresponding struct device pointer. - -It takes care to avoid increasing the device refcount since all -we need is the device pointer. This pointer is used in the -notifier list as a key, but it is never accessed by the CEC driver. - -Signed-off-by: Hans Verkuil -Reported-by: Wen Yang -Acked-by: Wen Yang -Signed-off-by: Mauro Carvalho Chehab -(cherry picked from commit fbbd403b3286b4467f8b755efa0f10819cef9bba - git://linuxtv.org/media_tree.git master) ---- - drivers/media/cec/cec-notifier.c | 30 ++++++++++++++++++++++++++++++ - include/media/cec-notifier.h | 19 ++++++++++++++++++- - 2 files changed, 48 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c -index dd2078b27a419..9598c7778871a 100644 ---- a/drivers/media/cec/cec-notifier.c -+++ b/drivers/media/cec/cec-notifier.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -127,3 +128,32 @@ void cec_notifier_unregister(struct cec_notifier *n) - cec_notifier_put(n); - } - EXPORT_SYMBOL_GPL(cec_notifier_unregister); -+ -+struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) -+{ -+ struct platform_device *hdmi_pdev; -+ struct device *hdmi_dev = NULL; -+ struct device_node *np; -+ -+ np = of_parse_phandle(dev->of_node, "hdmi-phandle", 0); -+ -+ if (!np) { -+ dev_err(dev, "Failed to find HDMI node in device tree\n"); -+ return ERR_PTR(-ENODEV); -+ } -+ hdmi_pdev = of_find_device_by_node(np); -+ of_node_put(np); -+ if (hdmi_pdev) { -+ hdmi_dev = &hdmi_pdev->dev; -+ /* -+ * Note that the device struct is only used as a key into the -+ * cec_notifiers list, it is never actually accessed. -+ * So we decrement the reference here so we don't leak -+ * memory. -+ */ -+ put_device(hdmi_dev); -+ return hdmi_dev; -+ } -+ return ERR_PTR(-EPROBE_DEFER); -+} -+EXPORT_SYMBOL_GPL(cec_notifier_parse_hdmi_phandle); -diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h -index 814eeef35a5cf..57b3a9f6ea1d5 100644 ---- a/include/media/cec-notifier.h -+++ b/include/media/cec-notifier.h -@@ -9,7 +9,7 @@ - #ifndef LINUX_CEC_NOTIFIER_H - #define LINUX_CEC_NOTIFIER_H - --#include -+#include - #include - - struct device; -@@ -87,6 +87,17 @@ void cec_notifier_unregister(struct cec_notifier *n); - void cec_register_cec_notifier(struct cec_adapter *adap, - struct cec_notifier *notifier); - -+/** -+ * cec_notifier_parse_hdmi_phandle - find the hdmi device from "hdmi-phandle" -+ * @dev: the device with the "hdmi-phandle" device tree property -+ * -+ * Returns the device pointer referenced by the "hdmi-phandle" property. -+ * Note that the refcount of the returned device is not incremented. -+ * This device pointer is only used as a key value in the notifier -+ * list, but it is never accessed by the CEC driver. -+ */ -+struct device *cec_notifier_parse_hdmi_phandle(struct device *dev); -+ - #else - static inline struct cec_notifier *cec_notifier_get_conn(struct device *dev, - const char *conn) -@@ -122,6 +133,12 @@ static inline void cec_register_cec_notifier(struct cec_adapter *adap, - struct cec_notifier *notifier) - { - } -+ -+static inline struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) -+{ -+ return ERR_PTR(-ENODEV); -+} -+ - #endif - - /** - -From 8d922af065e8a8cfcb67308276b4def00177c3d4 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 12 Apr 2019 04:30:58 -0400 -Subject: [PATCH 093/249] FROMGIT: media: dt-bindings: media: meson-ao-cec: Add - G12A AO-CEC-B Compatible - -The Amlogic G12A embeds a second CEC controller named AO-CEC-B, and -the other one is AO-CEC-A described by the current bindings. - -The register interface is very close but the internal architecture -is totally different. - -The other difference is the clock source, the AO-CEC-B takes the -"oscin", the Always-On Oscillator clock, as input and embeds a -dual-divider clock divider to provide the precise 32768Hz base -clock for CEC communication. - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring -Signed-off-by: Hans Verkuil -Signed-off-by: Mauro Carvalho Chehab -(cherry picked from commit 3473ba384de7cf5df33f0ea3650aa4c7aaf1c995 - git://linuxtv.org/media_tree.git master) ---- - .../devicetree/bindings/media/meson-ao-cec.txt | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/Documentation/devicetree/bindings/media/meson-ao-cec.txt b/Documentation/devicetree/bindings/media/meson-ao-cec.txt -index 8671bdb08080e..c67fc41d4aa23 100644 ---- a/Documentation/devicetree/bindings/media/meson-ao-cec.txt -+++ b/Documentation/devicetree/bindings/media/meson-ao-cec.txt -@@ -4,16 +4,23 @@ The Amlogic Meson AO-CEC module is present is Amlogic SoCs and its purpose is - to handle communication between HDMI connected devices over the CEC bus. - - Required properties: -- - compatible : value should be following -+ - compatible : value should be following depending on the SoC : -+ For GXBB, GXL, GXM and G12A (AO_CEC_A module) : - "amlogic,meson-gx-ao-cec" -+ For G12A (AO_CEC_B module) : -+ "amlogic,meson-g12a-ao-cec" - - - reg : Physical base address of the IP registers and length of memory - mapped region. - - - interrupts : AO-CEC interrupt number to the CPU. - - clocks : from common clock binding: handle to AO-CEC clock. -- - clock-names : from common clock binding: must contain "core", -- corresponding to entry in the clocks property. -+ - clock-names : from common clock binding, must contain : -+ For GXBB, GXL, GXM and G12A (AO_CEC_A module) : -+ - "core" -+ For G12A (AO_CEC_B module) : -+ - "oscin" -+ corresponding to entry in the clocks property. - - hdmi-phandle: phandle to the HDMI controller - - Example: - -From 64ebd1eed771d48cb81357a8ae3977978f342e81 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 12 Apr 2019 04:30:59 -0400 -Subject: [PATCH 094/249] FROMGIT: media: platform: meson: Add Amlogic Meson - G12A AO CEC Controller driver - -The Amlogic G12A SoC embeds a second CEC controller with a totally -different design. - -The two controller can work in the same time since the CEC line can -be set to two different pins on the two controllers. - -This second CEC controller is documented as "AO-CEC-B", thus the -registers will be named "CECB_" to differentiate with the other -AO-CEC driver. - -Unlike the other AO-CEC controller, this one takes the Oscillator -clock as input and embeds a dual-divider to provide a precise -32768Hz clock for communication. This is handled by registering -a clock in the driver. - -Unlike the other AO-CEC controller, this controller supports setting -up to 15 logical addresses and supports the signal_free_time settings -in the transmit function. - -Unfortunately, this controller does not support "monitor" mode. - -Signed-off-by: Neil Armstrong -Signed-off-by: Hans Verkuil -Signed-off-by: Mauro Carvalho Chehab -(cherry picked from commit b7778c46683ce468f49141a18d984f6f13c6c5d2 - git://linuxtv.org/media_tree.git master) ---- - drivers/media/platform/Kconfig | 16 + - drivers/media/platform/meson/Makefile | 1 + - drivers/media/platform/meson/ao-cec-g12a.c | 779 +++++++++++++++++++++ - 3 files changed, 796 insertions(+) - create mode 100644 drivers/media/platform/meson/ao-cec-g12a.c - -diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 4acbed1896449..ea3a65e1ddbcd 100644 ---- a/drivers/media/platform/Kconfig -+++ b/drivers/media/platform/Kconfig -@@ -578,6 +578,22 @@ config VIDEO_MESON_AO_CEC - generic CEC framework interface. - CEC bus is present in the HDMI connector and enables communication - -+config VIDEO_MESON_G12A_AO_CEC -+ tristate "Amlogic Meson G12A AO CEC driver" -+ depends on ARCH_MESON || COMPILE_TEST -+ depends on COMMON_CLK && OF -+ select REGMAP -+ select REGMAP_MMIO -+ select CEC_CORE -+ select CEC_NOTIFIER -+ ---help--- -+ This is a driver for Amlogic Meson G12A SoCs AO CEC interface. -+ This driver if for the new AO-CEC module found in G12A SoCs, -+ usually named AO_CEC_B in documentation. -+ It uses the generic CEC framework interface. -+ CEC bus is present in the HDMI connector and enables communication -+ between compatible devices. -+ - config CEC_GPIO - tristate "Generic GPIO-based CEC driver" - depends on PREEMPT || COMPILE_TEST -diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile -index 597beb8f34d15..f611c23c37180 100644 ---- a/drivers/media/platform/meson/Makefile -+++ b/drivers/media/platform/meson/Makefile -@@ -1 +1,2 @@ - obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o -+obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o -diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c -new file mode 100644 -index 0000000000000..3620a1e310f52 ---- /dev/null -+++ b/drivers/media/platform/meson/ao-cec-g12a.c -@@ -0,0 +1,779 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Driver for Amlogic Meson AO CEC G12A Controller -+ * -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved -+ * Copyright (C) 2019 BayLibre, SAS -+ * Author: Neil Armstrong -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* CEC Registers */ -+ -+#define CECB_CLK_CNTL_REG0 0x00 -+ -+#define CECB_CLK_CNTL_N1 GENMASK(11, 0) -+#define CECB_CLK_CNTL_N2 GENMASK(23, 12) -+#define CECB_CLK_CNTL_DUAL_EN BIT(28) -+#define CECB_CLK_CNTL_OUTPUT_EN BIT(30) -+#define CECB_CLK_CNTL_INPUT_EN BIT(31) -+ -+#define CECB_CLK_CNTL_REG1 0x04 -+ -+#define CECB_CLK_CNTL_M1 GENMASK(11, 0) -+#define CECB_CLK_CNTL_M2 GENMASK(23, 12) -+#define CECB_CLK_CNTL_BYPASS_EN BIT(24) -+ -+/* -+ * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal -+ * change pulse width < filter_del * T(filter_tick) * 3. -+ * [9:8] Filter_tick_sel: Select which periodical pulse for -+ * glitch-filtering CEC line signal. -+ * - 0=Use T(xtal)*3 = 125ns; -+ * - 1=Use once-per-1us pulse; -+ * - 2=Use once-per-10us pulse; -+ * - 3=Use once-per-100us pulse. -+ * [3] Sysclk_en. 0=Disable system clock; 1=Enable system clock. -+ * [2:1] cntl_clk -+ * - 0 = Disable clk (Power-off mode) -+ * - 1 = Enable gated clock (Normal mode) -+ * - 2 = Enable free-run clk (Debug mode) -+ * [0] SW_RESET 1=Apply reset; 0=No reset. -+ */ -+#define CECB_GEN_CNTL_REG 0x08 -+ -+#define CECB_GEN_CNTL_RESET BIT(0) -+#define CECB_GEN_CNTL_CLK_DISABLE 0 -+#define CECB_GEN_CNTL_CLK_ENABLE 1 -+#define CECB_GEN_CNTL_CLK_ENABLE_DBG 2 -+#define CECB_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1) -+#define CECB_GEN_CNTL_SYS_CLK_EN BIT(3) -+#define CECB_GEN_CNTL_FILTER_TICK_125NS 0 -+#define CECB_GEN_CNTL_FILTER_TICK_1US 1 -+#define CECB_GEN_CNTL_FILTER_TICK_10US 2 -+#define CECB_GEN_CNTL_FILTER_TICK_100US 3 -+#define CECB_GEN_CNTL_FILTER_TICK_SEL GENMASK(9, 8) -+#define CECB_GEN_CNTL_FILTER_DEL GENMASK(14, 12) -+ -+/* -+ * [7:0] cec_reg_addr -+ * [15:8] cec_reg_wrdata -+ * [16] cec_reg_wr -+ * - 0 = Read -+ * - 1 = Write -+ * [31:24] cec_reg_rddata -+ */ -+#define CECB_RW_REG 0x0c -+ -+#define CECB_RW_ADDR GENMASK(7, 0) -+#define CECB_RW_WR_DATA GENMASK(15, 8) -+#define CECB_RW_WRITE_EN BIT(16) -+#define CECB_RW_BUS_BUSY BIT(23) -+#define CECB_RW_RD_DATA GENMASK(31, 24) -+ -+/* -+ * [0] DONE Interrupt -+ * [1] End Of Message Interrupt -+ * [2] Not Acknowlegde Interrupt -+ * [3] Arbitration Loss Interrupt -+ * [4] Initiator Error Interrupt -+ * [5] Follower Error Interrupt -+ * [6] Wake-Up Interrupt -+ */ -+#define CECB_INTR_MASKN_REG 0x10 -+#define CECB_INTR_CLR_REG 0x14 -+#define CECB_INTR_STAT_REG 0x18 -+ -+#define CECB_INTR_DONE BIT(0) -+#define CECB_INTR_EOM BIT(1) -+#define CECB_INTR_NACK BIT(2) -+#define CECB_INTR_ARB_LOSS BIT(3) -+#define CECB_INTR_INITIATOR_ERR BIT(4) -+#define CECB_INTR_FOLLOWER_ERR BIT(5) -+#define CECB_INTR_WAKE_UP BIT(6) -+ -+/* CEC Commands */ -+ -+#define CECB_CTRL 0x00 -+ -+#define CECB_CTRL_SEND BIT(0) -+#define CECB_CTRL_TYPE GENMASK(2, 1) -+#define CECB_CTRL_TYPE_RETRY 0 -+#define CECB_CTRL_TYPE_NEW 1 -+#define CECB_CTRL_TYPE_NEXT 2 -+ -+#define CECB_CTRL2 0x01 -+#define CECB_INTR_MASK 0x02 -+#define CECB_LADD_LOW 0x05 -+#define CECB_LADD_HIGH 0x06 -+#define CECB_TX_CNT 0x07 -+#define CECB_RX_CNT 0x08 -+#define CECB_STAT0 0x09 -+#define CECB_TX_DATA00 0x10 -+#define CECB_TX_DATA01 0x11 -+#define CECB_TX_DATA02 0x12 -+#define CECB_TX_DATA03 0x13 -+#define CECB_TX_DATA04 0x14 -+#define CECB_TX_DATA05 0x15 -+#define CECB_TX_DATA06 0x16 -+#define CECB_TX_DATA07 0x17 -+#define CECB_TX_DATA08 0x18 -+#define CECB_TX_DATA09 0x19 -+#define CECB_TX_DATA10 0x1A -+#define CECB_TX_DATA11 0x1B -+#define CECB_TX_DATA12 0x1C -+#define CECB_TX_DATA13 0x1D -+#define CECB_TX_DATA14 0x1E -+#define CECB_TX_DATA15 0x1F -+#define CECB_RX_DATA00 0x20 -+#define CECB_RX_DATA01 0x21 -+#define CECB_RX_DATA02 0x22 -+#define CECB_RX_DATA03 0x23 -+#define CECB_RX_DATA04 0x24 -+#define CECB_RX_DATA05 0x25 -+#define CECB_RX_DATA06 0x26 -+#define CECB_RX_DATA07 0x27 -+#define CECB_RX_DATA08 0x28 -+#define CECB_RX_DATA09 0x29 -+#define CECB_RX_DATA10 0x2A -+#define CECB_RX_DATA11 0x2B -+#define CECB_RX_DATA12 0x2C -+#define CECB_RX_DATA13 0x2D -+#define CECB_RX_DATA14 0x2E -+#define CECB_RX_DATA15 0x2F -+#define CECB_LOCK_BUF 0x30 -+ -+#define CECB_LOCK_BUF_EN BIT(0) -+ -+#define CECB_WAKEUPCTRL 0x31 -+ -+struct meson_ao_cec_g12a_device { -+ struct platform_device *pdev; -+ struct regmap *regmap; -+ struct regmap *regmap_cec; -+ spinlock_t cec_reg_lock; -+ struct cec_notifier *notify; -+ struct cec_adapter *adap; -+ struct cec_msg rx_msg; -+ struct clk *oscin; -+ struct clk *core; -+}; -+ -+static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { -+ .reg_bits = 8, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = CECB_INTR_STAT_REG, -+}; -+ -+/* -+ * The AO-CECB embeds a dual/divider to generate a more precise -+ * 32,768KHz clock for CEC core clock. -+ * ______ ______ -+ * | | | | -+ * ______ | Div1 |-| Cnt1 | ______ -+ * | | /|______| |______|\ | | -+ * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> -+ * |______| | \| | | |/ | |______| -+ * | | Div2 |-| Cnt2 | | -+ * | |______| |______| | -+ * |_______________________| -+ * -+ * The dividing can be switched to single or dual, with a counter -+ * for each divider to set when the switching is done. -+ * The entire dividing mechanism can be also bypassed. -+ */ -+ -+struct meson_ao_cec_g12a_dualdiv_clk { -+ struct clk_hw hw; -+ struct regmap *regmap; -+}; -+ -+#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \ -+ container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \ -+ -+static unsigned long -+meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = -+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); -+ unsigned long n1; -+ u32 reg0, reg1; -+ -+ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®0); -+ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1); -+ -+ if (reg1 & CECB_CLK_CNTL_BYPASS_EN) -+ return parent_rate; -+ -+ if (reg0 & CECB_CLK_CNTL_DUAL_EN) { -+ unsigned long n2, m1, m2, f1, f2, p1, p2; -+ -+ n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; -+ n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1; -+ -+ m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; -+ m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; -+ -+ f1 = DIV_ROUND_CLOSEST(parent_rate, n1); -+ f2 = DIV_ROUND_CLOSEST(parent_rate, n2); -+ -+ p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); -+ p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); -+ -+ return DIV_ROUND_UP(100000000, p1 + p2); -+ } -+ -+ n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; -+ -+ return DIV_ROUND_CLOSEST(parent_rate, n1); -+} -+ -+static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw) -+{ -+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = -+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); -+ -+ -+ /* Disable Input & Output */ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, -+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, -+ 0); -+ -+ /* Set N1 & N2 */ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, -+ CECB_CLK_CNTL_N1, -+ FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1)); -+ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, -+ CECB_CLK_CNTL_N2, -+ FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1)); -+ -+ /* Set M1 & M2 */ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, -+ CECB_CLK_CNTL_M1, -+ FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1)); -+ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, -+ CECB_CLK_CNTL_M2, -+ FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1)); -+ -+ /* Enable Dual divisor */ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, -+ CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN); -+ -+ /* Disable divisor bypass */ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, -+ CECB_CLK_CNTL_BYPASS_EN, 0); -+ -+ /* Enable Input & Output */ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, -+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, -+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN); -+ -+ return 0; -+} -+ -+static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw) -+{ -+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = -+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); -+ -+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, -+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, -+ 0); -+} -+ -+static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw) -+{ -+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = -+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); -+ int val; -+ -+ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val); -+ -+ return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN)); -+} -+ -+static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = { -+ .recalc_rate = meson_ao_cec_g12a_dualdiv_clk_recalc_rate, -+ .is_enabled = meson_ao_cec_g12a_dualdiv_clk_is_enabled, -+ .enable = meson_ao_cec_g12a_dualdiv_clk_enable, -+ .disable = meson_ao_cec_g12a_dualdiv_clk_disable, -+}; -+ -+static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec) -+{ -+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk; -+ struct device *dev = &ao_cec->pdev->dev; -+ struct clk_init_data init; -+ const char *parent_name; -+ struct clk *clk; -+ char *name; -+ -+ dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL); -+ if (!dualdiv_clk) -+ return -ENOMEM; -+ -+ name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev)); -+ if (!name) -+ return -ENOMEM; -+ -+ parent_name = __clk_get_name(ao_cec->oscin); -+ -+ init.name = name; -+ init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops; -+ init.flags = 0; -+ init.parent_names = &parent_name; -+ init.num_parents = 1; -+ dualdiv_clk->regmap = ao_cec->regmap; -+ dualdiv_clk->hw.init = &init; -+ -+ clk = devm_clk_register(dev, &dualdiv_clk->hw); -+ kfree(name); -+ if (IS_ERR(clk)) { -+ dev_err(dev, "failed to register clock\n"); -+ return PTR_ERR(clk); -+ } -+ -+ ao_cec->core = clk; -+ -+ return 0; -+} -+ -+static int meson_ao_cec_g12a_read(void *context, unsigned int addr, -+ unsigned int *data) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = context; -+ u32 reg = FIELD_PREP(CECB_RW_ADDR, addr); -+ unsigned long flags; -+ int ret = 0; -+ -+ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); -+ -+ ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); -+ if (ret) -+ goto read_out; -+ -+ ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, -+ !(reg & CECB_RW_BUS_BUSY), -+ 5, 1000); -+ if (ret) -+ goto read_out; -+ -+ ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®); -+ -+ *data = FIELD_GET(CECB_RW_RD_DATA, reg); -+ -+read_out: -+ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); -+ -+ return ret; -+} -+ -+static int meson_ao_cec_g12a_write(void *context, unsigned int addr, -+ unsigned int data) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = context; -+ unsigned long flags; -+ u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | -+ FIELD_PREP(CECB_RW_WR_DATA, data) | -+ CECB_RW_WRITE_EN; -+ int ret = 0; -+ -+ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); -+ -+ ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); -+ -+ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); -+ -+ return ret; -+} -+ -+static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .reg_read = meson_ao_cec_g12a_read, -+ .reg_write = meson_ao_cec_g12a_write, -+ .max_register = 0xffff, -+ .fast_io = true, -+}; -+ -+static inline void -+meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec, -+ bool enable) -+{ -+ u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK | -+ CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR | -+ CECB_INTR_FOLLOWER_ERR; -+ -+ regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG, -+ enable ? cfg : 0); -+} -+ -+static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec) -+{ -+ int i, ret = 0; -+ u32 val; -+ -+ ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val); -+ -+ ao_cec->rx_msg.len = val; -+ if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) -+ ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; -+ -+ for (i = 0; i < ao_cec->rx_msg.len; i++) { -+ ret |= regmap_read(ao_cec->regmap_cec, -+ CECB_RX_DATA00 + i, &val); -+ -+ ao_cec->rx_msg.msg[i] = val & 0xff; -+ } -+ -+ ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); -+ if (ret) -+ return; -+ -+ cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); -+} -+ -+static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = data; -+ u32 stat; -+ -+ regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); -+ if (stat) -+ return IRQ_WAKE_THREAD; -+ -+ return IRQ_NONE; -+} -+ -+static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = data; -+ u32 stat; -+ -+ regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); -+ regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat); -+ -+ if (stat & CECB_INTR_DONE) -+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK); -+ -+ if (stat & CECB_INTR_EOM) -+ meson_ao_cec_g12a_irq_rx(ao_cec); -+ -+ if (stat & CECB_INTR_NACK) -+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK); -+ -+ if (stat & CECB_INTR_ARB_LOSS) { -+ regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0); -+ regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, -+ CECB_CTRL_SEND | CECB_CTRL_TYPE, 0); -+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST); -+ } -+ -+ /* Initiator reports an error on the CEC bus */ -+ if (stat & CECB_INTR_INITIATOR_ERR) -+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); -+ -+ /* Follower reports a receive error, just reset RX buffer */ -+ if (stat & CECB_INTR_FOLLOWER_ERR) -+ regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); -+ -+ return IRQ_HANDLED; -+} -+ -+static int -+meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = adap->priv; -+ int ret = 0; -+ -+ if (logical_addr == CEC_LOG_ADDR_INVALID) { -+ /* Assume this will allways succeed */ -+ regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0); -+ regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0); -+ -+ return 0; -+ } else if (logical_addr < 8) { -+ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW, -+ BIT(logical_addr), -+ BIT(logical_addr)); -+ } else { -+ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, -+ BIT(logical_addr - 8), -+ BIT(logical_addr - 8)); -+ } -+ -+ /* Always set Broadcast/Unregistered 15 address */ -+ ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, -+ BIT(CEC_LOG_ADDR_UNREGISTERED - 8), -+ BIT(CEC_LOG_ADDR_UNREGISTERED - 8)); -+ -+ return ret ? -EIO : 0; -+} -+ -+static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts, -+ u32 signal_free_time, struct cec_msg *msg) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = adap->priv; -+ unsigned int type; -+ int ret = 0; -+ u32 val; -+ int i; -+ -+ /* Check if RX is in progress */ -+ ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val); -+ if (ret) -+ return ret; -+ if (val & CECB_LOCK_BUF_EN) -+ return -EBUSY; -+ -+ /* Check if TX Busy */ -+ ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val); -+ if (ret) -+ return ret; -+ if (val & CECB_CTRL_SEND) -+ return -EBUSY; -+ -+ switch (signal_free_time) { -+ case CEC_SIGNAL_FREE_TIME_RETRY: -+ type = CECB_CTRL_TYPE_RETRY; -+ break; -+ case CEC_SIGNAL_FREE_TIME_NEXT_XFER: -+ type = CECB_CTRL_TYPE_NEXT; -+ break; -+ case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: -+ default: -+ type = CECB_CTRL_TYPE_NEW; -+ break; -+ } -+ -+ for (i = 0; i < msg->len; i++) -+ ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i, -+ msg->msg[i]); -+ -+ ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len); -+ if (ret) -+ return -EIO; -+ -+ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, -+ CECB_CTRL_SEND | -+ CECB_CTRL_TYPE, -+ CECB_CTRL_SEND | -+ FIELD_PREP(CECB_CTRL_TYPE, type)); -+ -+ return ret; -+} -+ -+static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = adap->priv; -+ -+ meson_ao_cec_g12a_irq_setup(ao_cec, false); -+ -+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, -+ CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET); -+ -+ if (!enable) -+ return 0; -+ -+ /* Setup Filter */ -+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, -+ CECB_GEN_CNTL_FILTER_TICK_SEL | -+ CECB_GEN_CNTL_FILTER_DEL, -+ FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL, -+ CECB_GEN_CNTL_FILTER_TICK_1US) | -+ FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7)); -+ -+ /* Enable System Clock */ -+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, -+ CECB_GEN_CNTL_SYS_CLK_EN, -+ CECB_GEN_CNTL_SYS_CLK_EN); -+ -+ /* Enable gated clock (Normal mode). */ -+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, -+ CECB_GEN_CNTL_CLK_CTRL_MASK, -+ FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK, -+ CECB_GEN_CNTL_CLK_ENABLE)); -+ -+ /* Release Reset */ -+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, -+ CECB_GEN_CNTL_RESET, 0); -+ -+ meson_ao_cec_g12a_irq_setup(ao_cec, true); -+ -+ return 0; -+} -+ -+static const struct cec_adap_ops meson_ao_cec_g12a_ops = { -+ .adap_enable = meson_ao_cec_g12a_adap_enable, -+ .adap_log_addr = meson_ao_cec_g12a_set_log_addr, -+ .adap_transmit = meson_ao_cec_g12a_transmit, -+}; -+ -+static int meson_ao_cec_g12a_probe(struct platform_device *pdev) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec; -+ struct device *hdmi_dev; -+ struct resource *res; -+ void __iomem *base; -+ int ret, irq; -+ -+ hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); -+ if (IS_ERR(hdmi_dev)) -+ return PTR_ERR(hdmi_dev); -+ -+ ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); -+ if (!ao_cec) -+ return -ENOMEM; -+ -+ spin_lock_init(&ao_cec->cec_reg_lock); -+ ao_cec->pdev = pdev; -+ -+ ao_cec->notify = cec_notifier_get(hdmi_dev); -+ if (!ao_cec->notify) -+ return -ENOMEM; -+ -+ ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, -+ "meson_g12a_ao_cec", -+ CEC_CAP_DEFAULTS, -+ CEC_MAX_LOG_ADDRS); -+ if (IS_ERR(ao_cec->adap)) { -+ ret = PTR_ERR(ao_cec->adap); -+ goto out_probe_notify; -+ } -+ -+ ao_cec->adap->owner = THIS_MODULE; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) { -+ ret = PTR_ERR(base); -+ goto out_probe_adapter; -+ } -+ -+ ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, -+ &meson_ao_cec_g12a_regmap_conf); -+ if (IS_ERR(ao_cec->regmap)) { -+ ret = PTR_ERR(ao_cec->regmap); -+ goto out_probe_adapter; -+ } -+ -+ ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, -+ &meson_ao_cec_g12a_cec_regmap_conf); -+ if (IS_ERR(ao_cec->regmap_cec)) { -+ ret = PTR_ERR(ao_cec->regmap_cec); -+ goto out_probe_adapter; -+ } -+ -+ irq = platform_get_irq(pdev, 0); -+ ret = devm_request_threaded_irq(&pdev->dev, irq, -+ meson_ao_cec_g12a_irq, -+ meson_ao_cec_g12a_irq_thread, -+ 0, NULL, ao_cec); -+ if (ret) { -+ dev_err(&pdev->dev, "irq request failed\n"); -+ goto out_probe_adapter; -+ } -+ -+ ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); -+ if (IS_ERR(ao_cec->oscin)) { -+ dev_err(&pdev->dev, "oscin clock request failed\n"); -+ ret = PTR_ERR(ao_cec->oscin); -+ goto out_probe_adapter; -+ } -+ -+ ret = meson_ao_cec_g12a_setup_clk(ao_cec); -+ if (ret) -+ goto out_probe_adapter; -+ -+ ret = clk_prepare_enable(ao_cec->core); -+ if (ret) { -+ dev_err(&pdev->dev, "core clock enable failed\n"); -+ goto out_probe_adapter; -+ } -+ -+ device_reset_optional(&pdev->dev); -+ -+ platform_set_drvdata(pdev, ao_cec); -+ -+ ret = cec_register_adapter(ao_cec->adap, &pdev->dev); -+ if (ret < 0) { -+ cec_notifier_put(ao_cec->notify); -+ goto out_probe_core_clk; -+ } -+ -+ /* Setup Hardware */ -+ regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); -+ -+ cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); -+ -+ return 0; -+ -+out_probe_core_clk: -+ clk_disable_unprepare(ao_cec->core); -+ -+out_probe_adapter: -+ cec_delete_adapter(ao_cec->adap); -+ -+out_probe_notify: -+ cec_notifier_put(ao_cec->notify); -+ -+ dev_err(&pdev->dev, "CEC controller registration failed\n"); -+ -+ return ret; -+} -+ -+static int meson_ao_cec_g12a_remove(struct platform_device *pdev) -+{ -+ struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev); -+ -+ clk_disable_unprepare(ao_cec->core); -+ -+ cec_unregister_adapter(ao_cec->adap); -+ -+ cec_notifier_put(ao_cec->notify); -+ -+ return 0; -+} -+ -+static const struct of_device_id meson_ao_cec_g12a_of_match[] = { -+ { .compatible = "amlogic,meson-g12a-ao-cec", }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); -+ -+static struct platform_driver meson_ao_cec_g12a_driver = { -+ .probe = meson_ao_cec_g12a_probe, -+ .remove = meson_ao_cec_g12a_remove, -+ .driver = { -+ .name = "meson-ao-cec-g12a", -+ .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), -+ }, -+}; -+ -+module_platform_driver(meson_ao_cec_g12a_driver); -+ -+MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver"); -+MODULE_AUTHOR("Neil Armstrong "); -+MODULE_LICENSE("GPL"); - -From 27529762e1b4f4d3d80541474c76afeb9b1e4b58 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 12 Apr 2019 04:31:00 -0400 -Subject: [PATCH 095/249] FROMGIT: media: MAINTAINERS: Update AO CEC with - ao-cec-g12a driver - -Update the MAINTAINERS entry with the new AO-CEC driver for G12A. - -Signed-off-by: Neil Armstrong -Signed-off-by: Hans Verkuil -Signed-off-by: Mauro Carvalho Chehab -(cherry picked from commit a4dfc8a24796ff312d1d307e11f26f8ca466e938 - git://linuxtv.org/media_tree.git master) ---- - MAINTAINERS | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index 2c2fce72e694f..ddc31a0716ab8 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -10057,6 +10057,7 @@ L: linux-amlogic@lists.infradead.org - W: http://linux-meson.com/ - S: Supported - F: drivers/media/platform/meson/ao-cec.c -+F: drivers/media/platform/meson/ao-cec-g12a.c - F: Documentation/devicetree/bindings/media/meson-ao-cec.txt - T: git git://linuxtv.org/media_tree.git - - -From 8a1ac659c340c5614d4d8295a823e51cf26e3303 Mon Sep 17 00:00:00 2001 -From: YueHaibing -Date: Sat, 13 Apr 2019 22:14:55 +0800 -Subject: [PATCH 096/249] FROMGIT: drm/meson: Make some functions static - -Fix sparse warnings: - -drivers/gpu/drm/meson/meson_viu.c:93:6: warning: symbol 'meson_viu_set_g12a_osd1_matrix' was not declared. Should it be static? -drivers/gpu/drm/meson/meson_viu.c:121:6: warning: symbol 'meson_viu_set_osd_matrix' was not declared. Should it be static? -drivers/gpu/drm/meson/meson_viu.c:190:6: warning: symbol 'meson_viu_set_osd_lut' was not declared. Should it be static? - -Signed-off-by: YueHaibing -Acked-by: Neil Armstrong -Signed-off-by: Neil Armstrong -Link: https://patchwork.freedesktop.org/patch/msgid/20190413141455.34020-1-yuehaibing@huawei.com -(cherry picked from commit 2ccb8433ebe8dc99ed7cd0e3b8ff6976dcc05e3d - https://github.com/freedesktop/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_viu.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c -index 0169c98b01c94..b59072342cae7 100644 ---- a/drivers/gpu/drm/meson/meson_viu.c -+++ b/drivers/gpu/drm/meson/meson_viu.c -@@ -90,8 +90,8 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { - EOTF_COEFF_RIGHTSHIFT /* right shift */ - }; - --void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m, -- bool csc_on) -+static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, -+ int *m, bool csc_on) - { - /* VPP WRAP OSD1 matrix */ - writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), -@@ -118,8 +118,8 @@ void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m, - priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); - } - --void meson_viu_set_osd_matrix(struct meson_drm *priv, -- enum viu_matrix_sel_e m_select, -+static void meson_viu_set_osd_matrix(struct meson_drm *priv, -+ enum viu_matrix_sel_e m_select, - int *m, bool csc_on) - { - if (m_select == VIU_MATRIX_OSD) { -@@ -187,10 +187,10 @@ void meson_viu_set_osd_matrix(struct meson_drm *priv, - #define OSD_EOTF_LUT_SIZE 33 - #define OSD_OETF_LUT_SIZE 41 - --void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, -- unsigned int *r_map, unsigned int *g_map, -- unsigned int *b_map, -- bool csc_on) -+static void -+meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, -+ unsigned int *r_map, unsigned int *g_map, -+ unsigned int *b_map, bool csc_on) - { - unsigned int addr_port; - unsigned int data_port; - -From 51bbd9e7fe83cf7faa77fe360b47817c56ca6a58 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 8 Apr 2019 11:01:37 +0200 -Subject: [PATCH 097/249] FROMGIT: drm/meson: add size and alignment - requirements for dumb buffers - -The Amlogic SoCs Canvas buffers stride must be aligned on 64bytes -and overall size should be aligned on PAGE width. - -Adds a custom dumb_create op to adds these requirements. - -Fixes: bbbe775ec5b5 ("drm: Add support for Amlogic Meson Graphic Controller") -Suggested-by: Sky Zhou -Signed-off-by: Neil Armstrong -Reviewed-by: Sky Zhou -Link: https://patchwork.freedesktop.org/patch/msgid/20190408090137.2402-1-narmstrong@baylibre.com -(cherry picked from commit 852ce7285c99e3f7b56e76511e1b33c645a2b648 - https://github.com/freedesktop/drm-misc drm-misc-next) ---- - drivers/gpu/drm/meson/meson_drv.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c -index faf1b1b0357cd..72b01e6be0d9d 100644 ---- a/drivers/gpu/drm/meson/meson_drv.c -+++ b/drivers/gpu/drm/meson/meson_drv.c -@@ -90,6 +90,18 @@ static irqreturn_t meson_irq(int irq, void *arg) - return IRQ_HANDLED; - } - -+static int meson_dumb_create(struct drm_file *file, struct drm_device *dev, -+ struct drm_mode_create_dumb *args) -+{ -+ /* -+ * We need 64bytes aligned stride, and PAGE aligned size -+ */ -+ args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), SZ_64); -+ args->size = PAGE_ALIGN(args->pitch * args->height); -+ -+ return drm_gem_cma_dumb_create_internal(file, dev, args); -+} -+ - DEFINE_DRM_GEM_CMA_FOPS(fops); - - static struct drm_driver meson_driver = { -@@ -112,7 +124,7 @@ static struct drm_driver meson_driver = { - .gem_prime_mmap = drm_gem_cma_prime_mmap, - - /* GEM Ops */ -- .dumb_create = drm_gem_cma_dumb_create, -+ .dumb_create = meson_dumb_create, - .gem_free_object_unlocked = drm_gem_cma_free_object, - .gem_vm_ops = &drm_gem_cma_vm_ops, - - -From 587d6fd2663ba72cdcb2bed109a2c56950f2080c Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 15:11:44 +0200 -Subject: [PATCH 098/249] FROMGIT: dt-bindings: net: phy: add g12a mdio mux - documentation - -Add documentation for the device tree bindings of the MDIO mux of Amlogic -g12a SoC family - -Reviewed-by: Rob Herring -Signed-off-by: Jerome Brunet -Signed-off-by: David S. Miller -(cherry picked from commit 867934e9c9babe9192797726f6910554bbdc28ce - git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) -Signed-off-by: Neil Armstrong ---- - .../bindings/net/mdio-mux-meson-g12a.txt | 48 +++++++++++++++++++ - 1 file changed, 48 insertions(+) - create mode 100644 Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt - -diff --git a/Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt b/Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt -new file mode 100644 -index 0000000000000..3a96cbed92947 ---- /dev/null -+++ b/Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt -@@ -0,0 +1,48 @@ -+Properties for the MDIO bus multiplexer/glue of Amlogic G12a SoC family. -+ -+This is a special case of a MDIO bus multiplexer. It allows to choose between -+the internal mdio bus leading to the embedded 10/100 PHY or the external -+MDIO bus. -+ -+Required properties in addition to the generic multiplexer properties: -+- compatible : amlogic,g12a-mdio-mux -+- reg: physical address and length of the multiplexer/glue registers -+- clocks: list of clock phandle, one for each entry clock-names. -+- clock-names: should contain the following: -+ * "pclk" : peripheral clock. -+ * "clkin0" : platform crytal -+ * "clkin1" : SoC 50MHz MPLL -+ -+Example : -+ -+mdio_mux: mdio-multiplexer@4c000 { -+ compatible = "amlogic,g12a-mdio-mux"; -+ reg = <0x0 0x4c000 0x0 0xa4>; -+ clocks = <&clkc CLKID_ETH_PHY>, -+ <&xtal>, -+ <&clkc CLKID_MPLL_5OM>; -+ clock-names = "pclk", "clkin0", "clkin1"; -+ mdio-parent-bus = <&mdio0>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ext_mdio: mdio@0 { -+ reg = <0>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ -+ int_mdio: mdio@1 { -+ reg = <1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ internal_ephy: ethernet-phy@8 { -+ compatible = "ethernet-phy-id0180.3301", -+ "ethernet-phy-ieee802.3-c22"; -+ interrupts = ; -+ reg = <8>; -+ max-speed = <100>; -+ }; -+ }; -+}; - -From 4eeb71337c6dfb38c327b6f4728cc168ff913294 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 15:11:45 +0200 -Subject: [PATCH 099/249] FROMGIT: net: phy: add amlogic g12a mdio mux support - -Add support for the mdio mux and internal phy glue of the g12a SoC family - -Reviewed-by: Neil Armstrong # clk parts -Signed-off-by: Jerome Brunet -Signed-off-by: David S. Miller -(cherry picked from commit 7090425104dbd87959bd424e9bd5a8711fde0986 - git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) -Signed-off-by: Neil Armstrong ---- - drivers/net/phy/Kconfig | 11 + - drivers/net/phy/Makefile | 1 + - drivers/net/phy/mdio-mux-meson-g12a.c | 380 ++++++++++++++++++++++++++ - 3 files changed, 392 insertions(+) - create mode 100644 drivers/net/phy/mdio-mux-meson-g12a.c - -diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig -index 520657945b827..1b04004e1f379 100644 ---- a/drivers/net/phy/Kconfig -+++ b/drivers/net/phy/Kconfig -@@ -76,6 +76,17 @@ config MDIO_BUS_MUX_GPIO - several child MDIO busses to a parent bus. Child bus - selection is under the control of GPIO lines. - -+config MDIO_BUS_MUX_MESON_G12A -+ tristate "Amlogic G12a based MDIO bus multiplexer" -+ depends on ARCH_MESON || COMPILE_TEST -+ depends on OF_MDIO && HAS_IOMEM && COMMON_CLK -+ select MDIO_BUS_MUX -+ default m if ARCH_MESON -+ help -+ This module provides a driver for the MDIO multiplexer/glue of -+ the amlogic g12a SoC. The multiplexers connects either the external -+ or the internal MDIO bus to the parent bus. -+ - config MDIO_BUS_MUX_MMIOREG - tristate "MMIO device-controlled MDIO bus multiplexers" - depends on OF_MDIO && HAS_IOMEM -diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile -index ece5dae67174f..27d7f9f3b0de4 100644 ---- a/drivers/net/phy/Makefile -+++ b/drivers/net/phy/Makefile -@@ -28,6 +28,7 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o - obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o - obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC) += mdio-mux-bcm-iproc.o - obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o -+obj-$(CONFIG_MDIO_BUS_MUX_MESON_G12A) += mdio-mux-meson-g12a.o - obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o - obj-$(CONFIG_MDIO_BUS_MUX_MULTIPLEXER) += mdio-mux-multiplexer.o - obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o -diff --git a/drivers/net/phy/mdio-mux-meson-g12a.c b/drivers/net/phy/mdio-mux-meson-g12a.c -new file mode 100644 -index 0000000000000..6fa29ea8e2a36 ---- /dev/null -+++ b/drivers/net/phy/mdio-mux-meson-g12a.c -@@ -0,0 +1,380 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright (c) 2019 Baylibre, SAS. -+ * Author: Jerome Brunet -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define ETH_PLL_STS 0x40 -+#define ETH_PLL_CTL0 0x44 -+#define PLL_CTL0_LOCK_DIG BIT(30) -+#define PLL_CTL0_RST BIT(29) -+#define PLL_CTL0_EN BIT(28) -+#define PLL_CTL0_SEL BIT(23) -+#define PLL_CTL0_N GENMASK(14, 10) -+#define PLL_CTL0_M GENMASK(8, 0) -+#define PLL_LOCK_TIMEOUT 1000000 -+#define PLL_MUX_NUM_PARENT 2 -+#define ETH_PLL_CTL1 0x48 -+#define ETH_PLL_CTL2 0x4c -+#define ETH_PLL_CTL3 0x50 -+#define ETH_PLL_CTL4 0x54 -+#define ETH_PLL_CTL5 0x58 -+#define ETH_PLL_CTL6 0x5c -+#define ETH_PLL_CTL7 0x60 -+ -+#define ETH_PHY_CNTL0 0x80 -+#define EPHY_G12A_ID 0x33000180 -+#define ETH_PHY_CNTL1 0x84 -+#define PHY_CNTL1_ST_MODE GENMASK(2, 0) -+#define PHY_CNTL1_ST_PHYADD GENMASK(7, 3) -+#define EPHY_DFLT_ADD 8 -+#define PHY_CNTL1_MII_MODE GENMASK(15, 14) -+#define EPHY_MODE_RMII 0x1 -+#define PHY_CNTL1_CLK_EN BIT(16) -+#define PHY_CNTL1_CLKFREQ BIT(17) -+#define PHY_CNTL1_PHY_ENB BIT(18) -+#define ETH_PHY_CNTL2 0x88 -+#define PHY_CNTL2_USE_INTERNAL BIT(5) -+#define PHY_CNTL2_SMI_SRC_MAC BIT(6) -+#define PHY_CNTL2_RX_CLK_EPHY BIT(9) -+ -+#define MESON_G12A_MDIO_EXTERNAL_ID 0 -+#define MESON_G12A_MDIO_INTERNAL_ID 1 -+ -+struct g12a_mdio_mux { -+ bool pll_is_enabled; -+ void __iomem *regs; -+ void *mux_handle; -+ struct clk *pclk; -+ struct clk *pll; -+}; -+ -+struct g12a_ephy_pll { -+ void __iomem *base; -+ struct clk_hw hw; -+}; -+ -+#define g12a_ephy_pll_to_dev(_hw) \ -+ container_of(_hw, struct g12a_ephy_pll, hw) -+ -+static unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); -+ u32 val, m, n; -+ -+ val = readl(pll->base + ETH_PLL_CTL0); -+ m = FIELD_GET(PLL_CTL0_M, val); -+ n = FIELD_GET(PLL_CTL0_N, val); -+ -+ return parent_rate * m / n; -+} -+ -+static int g12a_ephy_pll_enable(struct clk_hw *hw) -+{ -+ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); -+ u32 val = readl(pll->base + ETH_PLL_CTL0); -+ -+ /* Apply both enable an reset */ -+ val |= PLL_CTL0_RST | PLL_CTL0_EN; -+ writel(val, pll->base + ETH_PLL_CTL0); -+ -+ /* Clear the reset to let PLL lock */ -+ val &= ~PLL_CTL0_RST; -+ writel(val, pll->base + ETH_PLL_CTL0); -+ -+ /* Poll on the digital lock instead of the usual analog lock -+ * This is done because bit 31 is unreliable on some SoC. Bit -+ * 31 may indicate that the PLL is not lock eventhough the clock -+ * is actually running -+ */ -+ return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val, -+ val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT); -+} -+ -+static void g12a_ephy_pll_disable(struct clk_hw *hw) -+{ -+ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); -+ u32 val; -+ -+ val = readl(pll->base + ETH_PLL_CTL0); -+ val &= ~PLL_CTL0_EN; -+ val |= PLL_CTL0_RST; -+ writel(val, pll->base + ETH_PLL_CTL0); -+} -+ -+static int g12a_ephy_pll_is_enabled(struct clk_hw *hw) -+{ -+ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); -+ unsigned int val; -+ -+ val = readl(pll->base + ETH_PLL_CTL0); -+ -+ return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0; -+} -+ -+static void g12a_ephy_pll_init(struct clk_hw *hw) -+{ -+ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); -+ -+ /* Apply PLL HW settings */ -+ writel(0x29c0040a, pll->base + ETH_PLL_CTL0); -+ writel(0x927e0000, pll->base + ETH_PLL_CTL1); -+ writel(0xac5f49e5, pll->base + ETH_PLL_CTL2); -+ writel(0x00000000, pll->base + ETH_PLL_CTL3); -+ writel(0x00000000, pll->base + ETH_PLL_CTL4); -+ writel(0x20200000, pll->base + ETH_PLL_CTL5); -+ writel(0x0000c002, pll->base + ETH_PLL_CTL6); -+ writel(0x00000023, pll->base + ETH_PLL_CTL7); -+} -+ -+static const struct clk_ops g12a_ephy_pll_ops = { -+ .recalc_rate = g12a_ephy_pll_recalc_rate, -+ .is_enabled = g12a_ephy_pll_is_enabled, -+ .enable = g12a_ephy_pll_enable, -+ .disable = g12a_ephy_pll_disable, -+ .init = g12a_ephy_pll_init, -+}; -+ -+static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv) -+{ -+ int ret; -+ -+ /* Enable the phy clock */ -+ if (!priv->pll_is_enabled) { -+ ret = clk_prepare_enable(priv->pll); -+ if (ret) -+ return ret; -+ } -+ -+ priv->pll_is_enabled = true; -+ -+ /* Initialize ephy control */ -+ writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0); -+ writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) | -+ FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) | -+ FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) | -+ PHY_CNTL1_CLK_EN | -+ PHY_CNTL1_CLKFREQ | -+ PHY_CNTL1_PHY_ENB, -+ priv->regs + ETH_PHY_CNTL1); -+ writel(PHY_CNTL2_USE_INTERNAL | -+ PHY_CNTL2_SMI_SRC_MAC | -+ PHY_CNTL2_RX_CLK_EPHY, -+ priv->regs + ETH_PHY_CNTL2); -+ -+ return 0; -+} -+ -+static int g12a_enable_external_mdio(struct g12a_mdio_mux *priv) -+{ -+ /* Reset the mdio bus mux */ -+ writel_relaxed(0x0, priv->regs + ETH_PHY_CNTL2); -+ -+ /* Disable the phy clock if enabled */ -+ if (priv->pll_is_enabled) { -+ clk_disable_unprepare(priv->pll); -+ priv->pll_is_enabled = false; -+ } -+ -+ return 0; -+} -+ -+static int g12a_mdio_switch_fn(int current_child, int desired_child, -+ void *data) -+{ -+ struct g12a_mdio_mux *priv = dev_get_drvdata(data); -+ -+ if (current_child == desired_child) -+ return 0; -+ -+ switch (desired_child) { -+ case MESON_G12A_MDIO_EXTERNAL_ID: -+ return g12a_enable_external_mdio(priv); -+ case MESON_G12A_MDIO_INTERNAL_ID: -+ return g12a_enable_internal_mdio(priv); -+ default: -+ return -EINVAL; -+ } -+} -+ -+static const struct of_device_id g12a_mdio_mux_match[] = { -+ { .compatible = "amlogic,g12a-mdio-mux", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, g12a_mdio_mux_match); -+ -+static int g12a_ephy_glue_clk_register(struct device *dev) -+{ -+ struct g12a_mdio_mux *priv = dev_get_drvdata(dev); -+ const char *parent_names[PLL_MUX_NUM_PARENT]; -+ struct clk_init_data init; -+ struct g12a_ephy_pll *pll; -+ struct clk_mux *mux; -+ struct clk *clk; -+ char *name; -+ int i; -+ -+ /* get the mux parents */ -+ for (i = 0; i < PLL_MUX_NUM_PARENT; i++) { -+ char in_name[8]; -+ -+ snprintf(in_name, sizeof(in_name), "clkin%d", i); -+ clk = devm_clk_get(dev, in_name); -+ if (IS_ERR(clk)) { -+ if (PTR_ERR(clk) != -EPROBE_DEFER) -+ dev_err(dev, "Missing clock %s\n", in_name); -+ return PTR_ERR(clk); -+ } -+ -+ parent_names[i] = __clk_get_name(clk); -+ } -+ -+ /* create the input mux */ -+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); -+ if (!mux) -+ return -ENOMEM; -+ -+ name = kasprintf(GFP_KERNEL, "%s#mux", dev_name(dev)); -+ if (!name) -+ return -ENOMEM; -+ -+ init.name = name; -+ init.ops = &clk_mux_ro_ops; -+ init.flags = 0; -+ init.parent_names = parent_names; -+ init.num_parents = PLL_MUX_NUM_PARENT; -+ -+ mux->reg = priv->regs + ETH_PLL_CTL0; -+ mux->shift = __ffs(PLL_CTL0_SEL); -+ mux->mask = PLL_CTL0_SEL >> mux->shift; -+ mux->hw.init = &init; -+ -+ clk = devm_clk_register(dev, &mux->hw); -+ kfree(name); -+ if (IS_ERR(clk)) { -+ dev_err(dev, "failed to register input mux\n"); -+ return PTR_ERR(clk); -+ } -+ -+ /* create the pll */ -+ pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); -+ if (!pll) -+ return -ENOMEM; -+ -+ name = kasprintf(GFP_KERNEL, "%s#pll", dev_name(dev)); -+ if (!name) -+ return -ENOMEM; -+ -+ init.name = name; -+ init.ops = &g12a_ephy_pll_ops; -+ init.flags = 0; -+ parent_names[0] = __clk_get_name(clk); -+ init.parent_names = parent_names; -+ init.num_parents = 1; -+ -+ pll->base = priv->regs; -+ pll->hw.init = &init; -+ -+ clk = devm_clk_register(dev, &pll->hw); -+ kfree(name); -+ if (IS_ERR(clk)) { -+ dev_err(dev, "failed to register input mux\n"); -+ return PTR_ERR(clk); -+ } -+ -+ priv->pll = clk; -+ -+ return 0; -+} -+ -+static int g12a_mdio_mux_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct g12a_mdio_mux *priv; -+ struct resource *res; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, priv); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ priv->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(priv->regs)) -+ return PTR_ERR(priv->regs); -+ -+ priv->pclk = devm_clk_get(dev, "pclk"); -+ if (IS_ERR(priv->pclk)) { -+ ret = PTR_ERR(priv->pclk); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to get peripheral clock\n"); -+ return ret; -+ } -+ -+ /* Make sure the device registers are clocked */ -+ ret = clk_prepare_enable(priv->pclk); -+ if (ret) { -+ dev_err(dev, "failed to enable peripheral clock"); -+ return ret; -+ } -+ -+ /* Register PLL in CCF */ -+ ret = g12a_ephy_glue_clk_register(dev); -+ if (ret) -+ goto err; -+ -+ ret = mdio_mux_init(dev, dev->of_node, g12a_mdio_switch_fn, -+ &priv->mux_handle, dev, NULL); -+ if (ret) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "mdio multiplexer init failed: %d", ret); -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ clk_disable_unprepare(priv->pclk); -+ return ret; -+} -+ -+static int g12a_mdio_mux_remove(struct platform_device *pdev) -+{ -+ struct g12a_mdio_mux *priv = platform_get_drvdata(pdev); -+ -+ mdio_mux_uninit(priv->mux_handle); -+ -+ if (priv->pll_is_enabled) -+ clk_disable_unprepare(priv->pll); -+ -+ clk_disable_unprepare(priv->pclk); -+ -+ return 0; -+} -+ -+static struct platform_driver g12a_mdio_mux_driver = { -+ .probe = g12a_mdio_mux_probe, -+ .remove = g12a_mdio_mux_remove, -+ .driver = { -+ .name = "g12a-mdio_mux", -+ .of_match_table = g12a_mdio_mux_match, -+ }, -+}; -+module_platform_driver(g12a_mdio_mux_driver); -+ -+MODULE_DESCRIPTION("Amlogic G12a MDIO multiplexer driver"); -+MODULE_AUTHOR("Jerome Brunet "); -+MODULE_LICENSE("GPL v2"); - -From 8d2e275796d61e5c54bb4296886725ff6ad1d779 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 15:11:46 +0200 -Subject: [PATCH 100/249] FROMGIT: net: phy: meson-gxl: add g12a support - -The g12a SoC family uses the type of internal PHY that was used on the -gxl family. The quirks of gxl family, like the LPA register corruption, -appear to have been resolved on this new SoC generation. - -Signed-off-by: Jerome Brunet -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller -(cherry picked from commit 5c3407abb3382fb0621a503662d00495f7ab65c4 - git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) -Signed-off-by: Neil Armstrong ---- - drivers/net/phy/meson-gxl.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c -index 0eec2913c289b..2033c93a46ca8 100644 ---- a/drivers/net/phy/meson-gxl.c -+++ b/drivers/net/phy/meson-gxl.c -@@ -237,11 +237,22 @@ static struct phy_driver meson_gxl_phy[] = { - .config_intr = meson_gxl_config_intr, - .suspend = genphy_suspend, - .resume = genphy_resume, -+ }, { -+ PHY_ID_MATCH_EXACT(0x01803301), -+ .name = "Meson G12A Internal PHY", -+ .features = PHY_BASIC_FEATURES, -+ .flags = PHY_IS_INTERNAL, -+ .soft_reset = genphy_soft_reset, -+ .ack_interrupt = meson_gxl_ack_interrupt, -+ .config_intr = meson_gxl_config_intr, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, - }, - }; - - static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { - { 0x01814400, 0xfffffff0 }, -+ { PHY_ID_MATCH_VENDOR(0x01803301) }, - { } - }; - - -From 8d275e2172f69a82526b980d041bf7ee76855340 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 4 Apr 2019 15:11:47 +0200 -Subject: [PATCH 101/249] FROMGIT: net: phy: meson-gxl: clean-up gxl variant - driver - -The purpose of this change is to align the gxl and g12a driver -declaration. - -Like on the g12a variant, remove genphy_aneg_done() from the driver -declaration as the net phy framework will default to it anyway. - -Also, the gxl phy id should be an exact match as well, so let's change -this and use the macro provided. - -Signed-off-by: Jerome Brunet -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller -(cherry picked from commit fad137c4ef073c45fe7696680a555262d48319db - git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) -Signed-off-by: Neil Armstrong ---- - drivers/net/phy/meson-gxl.c | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c -index 2033c93a46ca8..6d4a8c508ec0c 100644 ---- a/drivers/net/phy/meson-gxl.c -+++ b/drivers/net/phy/meson-gxl.c -@@ -224,14 +224,12 @@ static int meson_gxl_config_intr(struct phy_device *phydev) - - static struct phy_driver meson_gxl_phy[] = { - { -- .phy_id = 0x01814400, -- .phy_id_mask = 0xfffffff0, -+ PHY_ID_MATCH_EXACT(0x01814400), - .name = "Meson GXL Internal PHY", - .features = PHY_BASIC_FEATURES, - .flags = PHY_IS_INTERNAL, - .soft_reset = genphy_soft_reset, - .config_init = meson_gxl_config_init, -- .aneg_done = genphy_aneg_done, - .read_status = meson_gxl_read_status, - .ack_interrupt = meson_gxl_ack_interrupt, - .config_intr = meson_gxl_config_intr, -@@ -251,7 +249,7 @@ static struct phy_driver meson_gxl_phy[] = { - }; - - static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { -- { 0x01814400, 0xfffffff0 }, -+ { PHY_ID_MATCH_VENDOR(0x01814400) }, - { PHY_ID_MATCH_VENDOR(0x01803301) }, - { } - }; - -From 0e4b883ac1f54130d46554898d7949b87a346fbb Mon Sep 17 00:00:00 2001 -From: Martin Blumenstingl -Date: Mon, 1 Apr 2019 20:18:16 +0200 -Subject: [PATCH 102/249] UPSTREAM: pwm: meson: Consider 128 a valid - pre-divider -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The pre-divider allows configuring longer PWM periods compared to using -the input clock directly. The pre-divider is 7 bit wide, meaning it's -maximum value is 128 (the register value is off-by-one: 0x7f or 127). - -Change the loop to also allow for the maximum possible value to be -considered valid. - -Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") -Signed-off-by: Martin Blumenstingl -Acked-by: Uwe Kleine-König -Reviewed-by: Neil Armstrong -Signed-off-by: Thierry Reding -(cherry picked from commit 51496e4446875726d50a5617a6e0e0dabbc2e6da) ---- - drivers/pwm/pwm-meson.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c -index c1ed641b3e266..aaae48ab484ef 100644 ---- a/drivers/pwm/pwm-meson.c -+++ b/drivers/pwm/pwm-meson.c -@@ -184,7 +184,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, - do_div(fin_ps, fin_freq); - - /* Calc pre_div with the period */ -- for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { -+ for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) { - cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, - fin_ps * (pre_div + 1)); - dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", -@@ -193,7 +193,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, - break; - } - -- if (pre_div == MISC_CLK_DIV_MASK) { -+ if (pre_div > MISC_CLK_DIV_MASK) { - dev_err(meson->chip.dev, "unable to get period pre_div\n"); - return -EINVAL; - } - -From b05b882710e729104362dcc5537c8882478b5f43 Mon Sep 17 00:00:00 2001 -From: Bichao Zheng -Date: Mon, 1 Apr 2019 20:18:17 +0200 -Subject: [PATCH 103/249] UPSTREAM: pwm: meson: Don't disable PWM when setting - duty repeatedly - -There is an abnormally low about 20ms,when setting duty repeatedly. -Because setting the duty will disable PWM and then enable. Delete -this operation now. - -Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") -Signed-off-by: Bichao Zheng -[ Dropped code instead of hiding it behind a comment ] -Signed-off-by: Martin Blumenstingl -Reviewed-by: Neil Armstrong -Signed-off-by: Thierry Reding -(cherry picked from commit a279345807e1e0ae79567a52cfdd9d30c9174a3c) -Signed-off-by: Neil Armstrong ---- - drivers/pwm/pwm-meson.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c -index aaae48ab484ef..2ab3d216b35a7 100644 ---- a/drivers/pwm/pwm-meson.c -+++ b/drivers/pwm/pwm-meson.c -@@ -314,11 +314,6 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - if (state->period != channel->state.period || - state->duty_cycle != channel->state.duty_cycle || - state->polarity != channel->state.polarity) { -- if (channel->state.enabled) { -- meson_pwm_disable(meson, pwm->hwpwm); -- channel->state.enabled = false; -- } -- - if (state->polarity != channel->state.polarity) { - if (state->polarity == PWM_POLARITY_NORMAL) - meson->inverter_mask |= BIT(pwm->hwpwm); - -From 099f5fac8ef04d59ccd148a843c9054da83a82fd Mon Sep 17 00:00:00 2001 -From: Martin Blumenstingl -Date: Mon, 1 Apr 2019 19:57:48 +0200 -Subject: [PATCH 104/249] UPSTREAM: pwm: meson: Use the spin-lock only to - protect register modifications -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Holding the spin-lock for all of the code in meson_pwm_apply() can -result in a "BUG: scheduling while atomic". This can happen because -clk_get_rate() (which is called from meson_pwm_calc()) may sleep. -Only hold the spin-lock when modifying registers to solve this. - -The reason why we need a spin-lock in the driver is because the -REG_MISC_AB register is shared between the two channels provided by one -PWM controller. The only functions where REG_MISC_AB is modified are -meson_pwm_enable() and meson_pwm_disable() so the register reads/writes -in there need to be protected by the spin-lock. - -The original code also used the spin-lock to protect the values in -struct meson_pwm_channel. This could be necessary if two consumers can -use the same PWM channel. However, PWM core doesn't allow this so we -don't need to protect the values in struct meson_pwm_channel with a -lock. - -Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") -Signed-off-by: Martin Blumenstingl -Reviewed-by: Uwe Kleine-König -Reviewed-by: Neil Armstrong -Signed-off-by: Thierry Reding -(cherry picked from commit f173747fffdf037c791405ab4f1ec0eb392fc48e) -Signed-off-by: Neil Armstrong ---- - drivers/pwm/pwm-meson.c | 25 +++++++++++++++++-------- - 1 file changed, 17 insertions(+), 8 deletions(-) - -diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c -index 2ab3d216b35a7..e247ab632530b 100644 ---- a/drivers/pwm/pwm-meson.c -+++ b/drivers/pwm/pwm-meson.c -@@ -111,6 +111,10 @@ struct meson_pwm { - const struct meson_pwm_data *data; - void __iomem *base; - u8 inverter_mask; -+ /* -+ * Protects register (write) access to the REG_MISC_AB register -+ * that is shared between the two PWMs. -+ */ - spinlock_t lock; - }; - -@@ -235,6 +239,7 @@ static void meson_pwm_enable(struct meson_pwm *meson, - { - u32 value, clk_shift, clk_enable, enable; - unsigned int offset; -+ unsigned long flags; - - switch (id) { - case 0: -@@ -255,6 +260,8 @@ static void meson_pwm_enable(struct meson_pwm *meson, - return; - } - -+ spin_lock_irqsave(&meson->lock, flags); -+ - value = readl(meson->base + REG_MISC_AB); - value &= ~(MISC_CLK_DIV_MASK << clk_shift); - value |= channel->pre_div << clk_shift; -@@ -267,11 +274,14 @@ static void meson_pwm_enable(struct meson_pwm *meson, - value = readl(meson->base + REG_MISC_AB); - value |= enable; - writel(value, meson->base + REG_MISC_AB); -+ -+ spin_unlock_irqrestore(&meson->lock, flags); - } - - static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) - { - u32 value, enable; -+ unsigned long flags; - - switch (id) { - case 0: -@@ -286,9 +296,13 @@ static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) - return; - } - -+ spin_lock_irqsave(&meson->lock, flags); -+ - value = readl(meson->base + REG_MISC_AB); - value &= ~enable; - writel(value, meson->base + REG_MISC_AB); -+ -+ spin_unlock_irqrestore(&meson->lock, flags); - } - - static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, -@@ -296,19 +310,16 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - { - struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); - struct meson_pwm *meson = to_meson_pwm(chip); -- unsigned long flags; - int err = 0; - - if (!state) - return -EINVAL; - -- spin_lock_irqsave(&meson->lock, flags); -- - if (!state->enabled) { - meson_pwm_disable(meson, pwm->hwpwm); - channel->state.enabled = false; - -- goto unlock; -+ return 0; - } - - if (state->period != channel->state.period || -@@ -324,7 +335,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - err = meson_pwm_calc(meson, channel, pwm->hwpwm, - state->duty_cycle, state->period); - if (err < 0) -- goto unlock; -+ return err; - - channel->state.polarity = state->polarity; - channel->state.period = state->period; -@@ -336,9 +347,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - channel->state.enabled = true; - } - --unlock: -- spin_unlock_irqrestore(&meson->lock, flags); -- return err; -+ return 0; - } - - static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - -From 8851941f3d6c6857d72a612e5966a6f93faa5158 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 23 Apr 2019 15:36:44 +0200 -Subject: [PATCH 105/249] UPSTREAM: dt-bindings: pwm: Update bindings for the - Meson G12A Family - -Update the doc to explicitly support Meson G12A Family. -The 2 first (A & B) AO PWM uses different clock source than the last 2 -(C & D) AO PWM modules, thus we need to differentiate them. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Signed-off-by: Thierry Reding -(cherry picked from commit ad36cb9186bc805b8fd0b9908469e29617211658) ---- - Documentation/devicetree/bindings/pwm/pwm-meson.txt | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/Documentation/devicetree/bindings/pwm/pwm-meson.txt b/Documentation/devicetree/bindings/pwm/pwm-meson.txt -index 1fa3f71821334..8916323540652 100644 ---- a/Documentation/devicetree/bindings/pwm/pwm-meson.txt -+++ b/Documentation/devicetree/bindings/pwm/pwm-meson.txt -@@ -7,6 +7,9 @@ Required properties: - or "amlogic,meson-gxbb-ao-pwm" - or "amlogic,meson-axg-ee-pwm" - or "amlogic,meson-axg-ao-pwm" -+ or "amlogic,meson-g12a-ee-pwm" -+ or "amlogic,meson-g12a-ao-pwm-ab" -+ or "amlogic,meson-g12a-ao-pwm-cd" - - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of - the cells format. - - -From 816a0e0c017cf15e5b4b13cc63b80724762a5289 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 23 Apr 2019 15:36:45 +0200 -Subject: [PATCH 106/249] UPSTREAM: pwm: meson: Add clock source configuration - for Meson G12A - -For the PWM controller in the Meson G12A SoC, the EE domain and AO domain -have different clock sources. This patch tries to describe them in the -DT compatible data. The two AO PWM controller has different clock source, -but the first AO controller (A & B) can reuse the AXG parents name. - -Signed-off-by: Neil Armstrong -Reviewed-by: Martin Blumenstingl -Signed-off-by: Thierry Reding -(cherry picked from commit f41efceb46e697a750e93c19e4579dc50697effe) ---- - drivers/pwm/pwm-meson.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c -index e247ab632530b..ba748027ecbf1 100644 ---- a/drivers/pwm/pwm-meson.c -+++ b/drivers/pwm/pwm-meson.c -@@ -433,6 +433,24 @@ static const struct meson_pwm_data pwm_axg_ao_data = { - .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names), - }; - -+static const char * const pwm_g12a_ao_cd_parent_names[] = { -+ "aoclk81", "xtal", -+}; -+ -+static const struct meson_pwm_data pwm_g12a_ao_cd_data = { -+ .parent_names = pwm_g12a_ao_cd_parent_names, -+ .num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_names), -+}; -+ -+static const char * const pwm_g12a_ee_parent_names[] = { -+ "xtal", "hdmi_pll", "fclk_div4", "fclk_div3" -+}; -+ -+static const struct meson_pwm_data pwm_g12a_ee_data = { -+ .parent_names = pwm_g12a_ee_parent_names, -+ .num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_names), -+}; -+ - static const struct of_device_id meson_pwm_matches[] = { - { - .compatible = "amlogic,meson8b-pwm", -@@ -454,6 +472,18 @@ static const struct of_device_id meson_pwm_matches[] = { - .compatible = "amlogic,meson-axg-ao-pwm", - .data = &pwm_axg_ao_data - }, -+ { -+ .compatible = "amlogic,meson-g12a-ee-pwm", -+ .data = &pwm_g12a_ee_data -+ }, -+ { -+ .compatible = "amlogic,meson-g12a-ao-pwm-ab", -+ .data = &pwm_axg_ao_data -+ }, -+ { -+ .compatible = "amlogic,meson-g12a-ao-pwm-cd", -+ .data = &pwm_g12a_ao_cd_data -+ }, - {}, - }; - MODULE_DEVICE_TABLE(of, meson_pwm_matches); - -From 6094f4aeb36b06313fe8dd456a0f8ced3f9889d4 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 23 Apr 2019 11:02:29 +0200 -Subject: [PATCH 107/249] UPSTREAM: mmc: meson-gx: remove open coded read with - timeout - -There is already a function available to poll a register until a -condition is met. Let's use it instead of open coding it. - -Reviewed-by: Martin Blumenstingl -Signed-off-by: Jerome Brunet -Reviewed-by: Kevin Hilman -Signed-off-by: Ulf Hansson -(cherry picked from commit 98849da63fffdc010dca6e6f6785c2e2ff34e807) -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 18 ++++-------------- - 1 file changed, 4 insertions(+), 14 deletions(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index 2eba507790e49..2deeacc051b1c 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1100,7 +1101,6 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) - - static int meson_mmc_wait_desc_stop(struct meson_host *host) - { -- int loop; - u32 status; - - /* -@@ -1110,20 +1110,10 @@ static int meson_mmc_wait_desc_stop(struct meson_host *host) - * If we don't confirm the descriptor is stopped, it might raise new - * IRQs after we have called mmc_request_done() which is bad. - */ -- for (loop = 50; loop; loop--) { -- status = readl(host->regs + SD_EMMC_STATUS); -- if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) -- udelay(100); -- else -- break; -- } - -- if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) { -- dev_err(host->dev, "Timed out waiting for host to stop\n"); -- return -ETIMEDOUT; -- } -- -- return 0; -+ return readl_poll_timeout(host->regs + SD_EMMC_STATUS, status, -+ !(status & (STATUS_BUSY | STATUS_DESC_BUSY)), -+ 100, 5000); - } - - static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) - -From 5d5e8be448e8a093bf1de6c5f7b7e159f91f50dc Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 23 Apr 2019 11:02:30 +0200 -Subject: [PATCH 108/249] UPSTREAM: mmc: meson-gx: ack only raised irq - -This is merely a clean up. It makes sense to only ack raised irqs -instead of acking everything all the time. - -Signed-off-by: Jerome Brunet -Acked-by: Martin Blumenstingl -Reviewed-by: Kevin Hilman -Signed-off-by: Ulf Hansson -(cherry picked from commit 9c5fdb07a28d730d4907d48905f06680691851e8) -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index 2deeacc051b1c..8b690ecde4c5f 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -1082,9 +1082,6 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) - } - - out: -- /* ack all enabled interrupts */ -- writel(irq_en, host->regs + SD_EMMC_STATUS); -- - if (cmd->error) { - /* Stop desc in case of errors */ - u32 start = readl(host->regs + SD_EMMC_START); -@@ -1096,6 +1093,9 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) - if (ret == IRQ_HANDLED) - meson_mmc_request_done(host->mmc, cmd->mrq); - -+ /* ack all raised interrupts */ -+ writel(status, host->regs + SD_EMMC_STATUS); -+ - return ret; - } - - -From 97267342fd64e62dc931f55679480c84e7cfcb8c Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 23 Apr 2019 11:02:31 +0200 -Subject: [PATCH 109/249] UPSTREAM: mmc: meson-gx: correct irq flag - -There is no reason for another device to request the MMC irq. It should -only be used the MMC device, so remove IRQ_SHARED and replace by -IRQ_ONESHOT as we don't the irq to fire again until the irq thread is -done - -Signed-off-by: Jerome Brunet -Reviewed-by: Martin Blumenstingl -Reviewed-by: Kevin Hilman -Signed-off-by: Ulf Hansson -(cherry picked from commit eb4d811277465784e2d25d74c19183295d4499ab) -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index 8b690ecde4c5f..3df50b53f8341 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -1328,7 +1328,7 @@ static int meson_mmc_probe(struct platform_device *pdev) - host->regs + SD_EMMC_IRQ_EN); - - ret = request_threaded_irq(host->irq, meson_mmc_irq, -- meson_mmc_irq_thread, IRQF_SHARED, -+ meson_mmc_irq_thread, IRQF_ONESHOT, - dev_name(&pdev->dev), host); - if (ret) - goto err_init_clk; - -From d764d585346e1d74f66d530133fa38954fc808b3 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 23 Apr 2019 11:02:32 +0200 -Subject: [PATCH 110/249] UPSTREAM: mmc: meson-gx: disable HS400 - -At the moment, all our attempts to enable HS400 on Amlogic chipsets have -been unsuccessful or unreliable. Until we can figure out how to enable this -mode safely and reliably, let's force it off. - -Signed-off-by: Jerome Brunet -Acked-by: Martin Blumenstingl -Reviewed-by: Kevin Hilman -Signed-off-by: Ulf Hansson -(cherry picked from commit d5f758f2df8015b8dcf47b6403cc192e4cef734d) -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index 3df50b53f8341..118f09da8dfbc 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -823,10 +823,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - if (meson_mmc_timing_is_ddr(ios)) - val |= CFG_DDR; - -- val &= ~CFG_CHK_DS; -- if (ios->timing == MMC_TIMING_MMC_HS400) -- val |= CFG_CHK_DS; -- - err = meson_mmc_clk_set(host, ios); - if (err) - dev_err(host->dev, "Failed to set clock: %d\n,", err); -@@ -1339,6 +1335,13 @@ static int meson_mmc_probe(struct platform_device *pdev) - mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc); - mmc->max_seg_size = mmc->max_req_size; - -+ /* -+ * At the moment, we don't know how to reliably enable HS400. -+ * From the different datasheets, it is not even clear if this mode -+ * is officially supported by any of the SoCs -+ */ -+ mmc->caps2 &= ~MMC_CAP2_HS400; -+ - /* data bounce buffer */ - host->bounce_buf_size = mmc->max_req_size; - host->bounce_buf = - -From b1330d44e875c09c8209816151ef96c9f115fdbb Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 23 Apr 2019 11:02:33 +0200 -Subject: [PATCH 111/249] UPSTREAM: mmc: meson-gx: avoid clock glitch when - switching to DDR modes - -Activating DDR in the Amlogic mmc controller, among other things, will -divide the output clock by 2. So by activating it with clock on, we are -creating a glitch on the output. - -Instead, let's deal with DDR when the clock output is off, when setting -the clock. - -Signed-off-by: Jerome Brunet -Tested-by: Martin Blumenstingl -Reviewed-by: Kevin Hilman -Signed-off-by: Ulf Hansson -(cherry picked from commit dc38ac8141a664f4cc96306e6de85f68bbee92b9) -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 73 +++++++++++++++++++-------------- - 1 file changed, 43 insertions(+), 30 deletions(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index 118f09da8dfbc..0454021c9ff5e 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -169,6 +169,7 @@ struct meson_host { - struct clk *rx_clk; - struct clk *tx_clk; - unsigned long req_rate; -+ bool ddr; - - struct pinctrl *pinctrl; - struct pinctrl_state *pins_default; -@@ -384,16 +385,6 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, - mmc_get_dma_dir(data)); - } - --static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios) --{ -- if (ios->timing == MMC_TIMING_MMC_DDR52 || -- ios->timing == MMC_TIMING_UHS_DDR50 || -- ios->timing == MMC_TIMING_MMC_HS400) -- return true; -- -- return false; --} -- - /* - * Gating the clock on this controller is tricky. It seems the mmc clock - * is also used by the controller. It may crash during some operation if the -@@ -430,36 +421,41 @@ static void meson_mmc_clk_ungate(struct meson_host *host) - writel(cfg, host->regs + SD_EMMC_CFG); - } - --static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) -+static int meson_mmc_clk_set(struct meson_host *host, unsigned long rate, -+ bool ddr) - { - struct mmc_host *mmc = host->mmc; -- unsigned long rate = ios->clock; - int ret; - u32 cfg; - -- /* DDR modes require higher module clock */ -- if (meson_mmc_timing_is_ddr(ios)) -- rate <<= 1; -- - /* Same request - bail-out */ -- if (host->req_rate == rate) -+ if (host->ddr == ddr && host->req_rate == rate) - return 0; - - /* stop clock */ - meson_mmc_clk_gate(host); - host->req_rate = 0; -+ mmc->actual_clock = 0; - -- if (!rate) { -- mmc->actual_clock = 0; -- /* return with clock being stopped */ -+ /* return with clock being stopped */ -+ if (!rate) - return 0; -- } - - /* Stop the clock during rate change to avoid glitches */ - cfg = readl(host->regs + SD_EMMC_CFG); - cfg |= CFG_STOP_CLOCK; - writel(cfg, host->regs + SD_EMMC_CFG); - -+ if (ddr) { -+ /* DDR modes require higher module clock */ -+ rate <<= 1; -+ cfg |= CFG_DDR; -+ } else { -+ cfg &= ~CFG_DDR; -+ } -+ writel(cfg, host->regs + SD_EMMC_CFG); -+ host->ddr = ddr; -+ - ret = clk_set_rate(host->mmc_clk, rate); - if (ret) { - dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n", -@@ -471,12 +467,14 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) - mmc->actual_clock = clk_get_rate(host->mmc_clk); - - /* We should report the real output frequency of the controller */ -- if (meson_mmc_timing_is_ddr(ios)) -+ if (ddr) { -+ host->req_rate >>= 1; - mmc->actual_clock >>= 1; -+ } - - dev_dbg(host->dev, "clk rate: %u Hz\n", mmc->actual_clock); -- if (ios->clock != mmc->actual_clock) -- dev_dbg(host->dev, "requested rate was %u\n", ios->clock); -+ if (rate != mmc->actual_clock) -+ dev_dbg(host->dev, "requested rate was %lu\n", rate); - - /* (re)start clock */ - meson_mmc_clk_ungate(host); -@@ -750,6 +748,25 @@ static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) - return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); - } - -+static int meson_mmc_prepare_ios_clock(struct meson_host *host, -+ struct mmc_ios *ios) -+{ -+ bool ddr; -+ -+ switch (ios->timing) { -+ case MMC_TIMING_MMC_DDR52: -+ case MMC_TIMING_UHS_DDR50: -+ ddr = true; -+ break; -+ -+ default: -+ ddr = false; -+ break; -+ } -+ -+ return meson_mmc_clk_set(host, ios->clock, ddr); -+} -+ - static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - { - struct meson_host *host = mmc_priv(mmc); -@@ -818,16 +835,12 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - val = readl(host->regs + SD_EMMC_CFG); - val &= ~CFG_BUS_WIDTH_MASK; - val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width); -+ writel(val, host->regs + SD_EMMC_CFG); - -- val &= ~CFG_DDR; -- if (meson_mmc_timing_is_ddr(ios)) -- val |= CFG_DDR; -- -- err = meson_mmc_clk_set(host, ios); -+ err = meson_mmc_prepare_ios_clock(host, ios); - if (err) - dev_err(host->dev, "Failed to set clock: %d\n,", err); - -- writel(val, host->regs + SD_EMMC_CFG); - dev_dbg(host->dev, "SD_EMMC_CFG: 0x%08x\n", val); - } - - -From 387ac95ff367eeef80c061632b6b1622531aed85 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 23 Apr 2019 11:02:34 +0200 -Subject: [PATCH 112/249] UPSTREAM: mmc: meson-gx: remove Rx phase tuning - -This remove all the code related to phase settings. Using the Rx phase -for tuning has not been reliable. We had several issues over the past -months, on both v2 and v3 mmc chips After discussing the issue matter -with Amlogic, They suggested to set a phase shift of 180 between Core and -Tx and use signal resampling for the tuning. - -Since we won't be playing with the phase anymore, let's remove all the -clock code related to it and set the appropriate value on init. - -Signed-off-by: Jerome Brunet -Tested-by: Martin Blumenstingl -Reviewed-by: Kevin Hilman -Signed-off-by: Ulf Hansson -(cherry picked from commit 5e6f75f42393d1619ca426a4909df963cc814fbc) -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 290 ++------------------------------ - 1 file changed, 13 insertions(+), 277 deletions(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index 0454021c9ff5e..acdc5520d02cc 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -49,6 +49,8 @@ - #define CLK_CORE_PHASE_MASK GENMASK(9, 8) - #define CLK_TX_PHASE_MASK GENMASK(11, 10) - #define CLK_RX_PHASE_MASK GENMASK(13, 12) -+#define CLK_PHASE_0 0 -+#define CLK_PHASE_180 2 - #define CLK_V2_TX_DELAY_MASK GENMASK(19, 16) - #define CLK_V2_RX_DELAY_MASK GENMASK(23, 20) - #define CLK_V2_ALWAYS_ON BIT(24) -@@ -57,10 +59,6 @@ - #define CLK_V3_RX_DELAY_MASK GENMASK(27, 22) - #define CLK_V3_ALWAYS_ON BIT(28) - --#define CLK_DELAY_STEP_PS 200 --#define CLK_PHASE_STEP 30 --#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) -- - #define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask) - #define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask) - #define CLK_ALWAYS_ON(h) (h->data->always_on) -@@ -165,9 +163,8 @@ struct meson_host { - - void __iomem *regs; - struct clk *core_clk; -+ struct clk *mux_clk; - struct clk *mmc_clk; -- struct clk *rx_clk; -- struct clk *tx_clk; - unsigned long req_rate; - bool ddr; - -@@ -209,90 +206,6 @@ struct meson_host { - #define CMD_RESP_MASK GENMASK(31, 1) - #define CMD_RESP_SRAM BIT(0) - --struct meson_mmc_phase { -- struct clk_hw hw; -- void __iomem *reg; -- unsigned long phase_mask; -- unsigned long delay_mask; -- unsigned int delay_step_ps; --}; -- --#define to_meson_mmc_phase(_hw) container_of(_hw, struct meson_mmc_phase, hw) -- --static int meson_mmc_clk_get_phase(struct clk_hw *hw) --{ -- struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); -- unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); -- unsigned long period_ps, p, d; -- int degrees; -- u32 val; -- -- val = readl(mmc->reg); -- p = (val & mmc->phase_mask) >> __ffs(mmc->phase_mask); -- degrees = p * 360 / phase_num; -- -- if (mmc->delay_mask) { -- period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, -- clk_get_rate(hw->clk)); -- d = (val & mmc->delay_mask) >> __ffs(mmc->delay_mask); -- degrees += d * mmc->delay_step_ps * 360 / period_ps; -- degrees %= 360; -- } -- -- return degrees; --} -- --static void meson_mmc_apply_phase_delay(struct meson_mmc_phase *mmc, -- unsigned int phase, -- unsigned int delay) --{ -- u32 val; -- -- val = readl(mmc->reg); -- val &= ~mmc->phase_mask; -- val |= phase << __ffs(mmc->phase_mask); -- -- if (mmc->delay_mask) { -- val &= ~mmc->delay_mask; -- val |= delay << __ffs(mmc->delay_mask); -- } -- -- writel(val, mmc->reg); --} -- --static int meson_mmc_clk_set_phase(struct clk_hw *hw, int degrees) --{ -- struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); -- unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); -- unsigned long period_ps, d = 0, r; -- uint64_t p; -- -- p = degrees % 360; -- -- if (!mmc->delay_mask) { -- p = DIV_ROUND_CLOSEST_ULL(p, 360 / phase_num); -- } else { -- period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, -- clk_get_rate(hw->clk)); -- -- /* First compute the phase index (p), the remainder (r) is the -- * part we'll try to acheive using the delays (d). -- */ -- r = do_div(p, 360 / phase_num); -- d = DIV_ROUND_CLOSEST(r * period_ps, -- 360 * mmc->delay_step_ps); -- d = min(d, mmc->delay_mask >> __ffs(mmc->delay_mask)); -- } -- -- meson_mmc_apply_phase_delay(mmc, p, d); -- return 0; --} -- --static const struct clk_ops meson_mmc_clk_phase_ops = { -- .get_phase = meson_mmc_clk_get_phase, -- .set_phase = meson_mmc_clk_set_phase, --}; -- - static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data) - { - unsigned int timeout = data->timeout_ns / NSEC_PER_MSEC; -@@ -492,8 +405,6 @@ static int meson_mmc_clk_init(struct meson_host *host) - struct clk_init_data init; - struct clk_mux *mux; - struct clk_divider *div; -- struct meson_mmc_phase *core, *tx, *rx; -- struct clk *clk; - char clk_name[32]; - int i, ret = 0; - const char *mux_parent_names[MUX_CLK_NUM_PARENTS]; -@@ -501,9 +412,11 @@ static int meson_mmc_clk_init(struct meson_host *host) - u32 clk_reg; - - /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ -- clk_reg = 0; -- clk_reg |= CLK_ALWAYS_ON(host); -+ clk_reg = CLK_ALWAYS_ON(host); - clk_reg |= CLK_DIV_MASK; -+ clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180); -+ clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0); -+ clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0); - writel(clk_reg, host->regs + SD_EMMC_CLOCK); - - /* get the mux parents */ -@@ -539,9 +452,9 @@ static int meson_mmc_clk_init(struct meson_host *host) - mux->mask = CLK_SRC_MASK >> mux->shift; - mux->hw.init = &init; - -- clk = devm_clk_register(host->dev, &mux->hw); -- if (WARN_ON(IS_ERR(clk))) -- return PTR_ERR(clk); -+ host->mux_clk = devm_clk_register(host->dev, &mux->hw); -+ if (WARN_ON(IS_ERR(host->mux_clk))) -+ return PTR_ERR(host->mux_clk); - - /* create the divider */ - div = devm_kzalloc(host->dev, sizeof(*div), GFP_KERNEL); -@@ -552,7 +465,7 @@ static int meson_mmc_clk_init(struct meson_host *host) - init.name = clk_name; - init.ops = &clk_divider_ops; - init.flags = CLK_SET_RATE_PARENT; -- clk_parent[0] = __clk_get_name(clk); -+ clk_parent[0] = __clk_get_name(host->mux_clk); - init.parent_names = clk_parent; - init.num_parents = 1; - -@@ -562,192 +475,19 @@ static int meson_mmc_clk_init(struct meson_host *host) - div->hw.init = &init; - div->flags = CLK_DIVIDER_ONE_BASED; - -- clk = devm_clk_register(host->dev, &div->hw); -- if (WARN_ON(IS_ERR(clk))) -- return PTR_ERR(clk); -- -- /* create the mmc core clock */ -- core = devm_kzalloc(host->dev, sizeof(*core), GFP_KERNEL); -- if (!core) -- return -ENOMEM; -- -- snprintf(clk_name, sizeof(clk_name), "%s#core", dev_name(host->dev)); -- init.name = clk_name; -- init.ops = &meson_mmc_clk_phase_ops; -- init.flags = CLK_SET_RATE_PARENT; -- clk_parent[0] = __clk_get_name(clk); -- init.parent_names = clk_parent; -- init.num_parents = 1; -- -- core->reg = host->regs + SD_EMMC_CLOCK; -- core->phase_mask = CLK_CORE_PHASE_MASK; -- core->hw.init = &init; -- -- host->mmc_clk = devm_clk_register(host->dev, &core->hw); -- if (WARN_ON(PTR_ERR_OR_ZERO(host->mmc_clk))) -+ host->mmc_clk = devm_clk_register(host->dev, &div->hw); -+ if (WARN_ON(IS_ERR(host->mmc_clk))) - return PTR_ERR(host->mmc_clk); - -- /* create the mmc tx clock */ -- tx = devm_kzalloc(host->dev, sizeof(*tx), GFP_KERNEL); -- if (!tx) -- return -ENOMEM; -- -- snprintf(clk_name, sizeof(clk_name), "%s#tx", dev_name(host->dev)); -- init.name = clk_name; -- init.ops = &meson_mmc_clk_phase_ops; -- init.flags = 0; -- clk_parent[0] = __clk_get_name(host->mmc_clk); -- init.parent_names = clk_parent; -- init.num_parents = 1; -- -- tx->reg = host->regs + SD_EMMC_CLOCK; -- tx->phase_mask = CLK_TX_PHASE_MASK; -- tx->delay_mask = CLK_TX_DELAY_MASK(host); -- tx->delay_step_ps = CLK_DELAY_STEP_PS; -- tx->hw.init = &init; -- -- host->tx_clk = devm_clk_register(host->dev, &tx->hw); -- if (WARN_ON(PTR_ERR_OR_ZERO(host->tx_clk))) -- return PTR_ERR(host->tx_clk); -- -- /* create the mmc rx clock */ -- rx = devm_kzalloc(host->dev, sizeof(*rx), GFP_KERNEL); -- if (!rx) -- return -ENOMEM; -- -- snprintf(clk_name, sizeof(clk_name), "%s#rx", dev_name(host->dev)); -- init.name = clk_name; -- init.ops = &meson_mmc_clk_phase_ops; -- init.flags = 0; -- clk_parent[0] = __clk_get_name(host->mmc_clk); -- init.parent_names = clk_parent; -- init.num_parents = 1; -- -- rx->reg = host->regs + SD_EMMC_CLOCK; -- rx->phase_mask = CLK_RX_PHASE_MASK; -- rx->delay_mask = CLK_RX_DELAY_MASK(host); -- rx->delay_step_ps = CLK_DELAY_STEP_PS; -- rx->hw.init = &init; -- -- host->rx_clk = devm_clk_register(host->dev, &rx->hw); -- if (WARN_ON(PTR_ERR_OR_ZERO(host->rx_clk))) -- return PTR_ERR(host->rx_clk); -- - /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ - host->mmc->f_min = clk_round_rate(host->mmc_clk, 400000); - ret = clk_set_rate(host->mmc_clk, host->mmc->f_min); - if (ret) - return ret; - -- clk_set_phase(host->mmc_clk, 180); -- clk_set_phase(host->tx_clk, 0); -- clk_set_phase(host->rx_clk, 0); -- - return clk_prepare_enable(host->mmc_clk); - } - --static void meson_mmc_shift_map(unsigned long *map, unsigned long shift) --{ -- DECLARE_BITMAP(left, CLK_PHASE_POINT_NUM); -- DECLARE_BITMAP(right, CLK_PHASE_POINT_NUM); -- -- /* -- * shift the bitmap right and reintroduce the dropped bits on the left -- * of the bitmap -- */ -- bitmap_shift_right(right, map, shift, CLK_PHASE_POINT_NUM); -- bitmap_shift_left(left, map, CLK_PHASE_POINT_NUM - shift, -- CLK_PHASE_POINT_NUM); -- bitmap_or(map, left, right, CLK_PHASE_POINT_NUM); --} -- --static void meson_mmc_find_next_region(unsigned long *map, -- unsigned long *start, -- unsigned long *stop) --{ -- *start = find_next_bit(map, CLK_PHASE_POINT_NUM, *start); -- *stop = find_next_zero_bit(map, CLK_PHASE_POINT_NUM, *start); --} -- --static int meson_mmc_find_tuning_point(unsigned long *test) --{ -- unsigned long shift, stop, offset = 0, start = 0, size = 0; -- -- /* Get the all good/all bad situation out the way */ -- if (bitmap_full(test, CLK_PHASE_POINT_NUM)) -- return 0; /* All points are good so point 0 will do */ -- else if (bitmap_empty(test, CLK_PHASE_POINT_NUM)) -- return -EIO; /* No successful tuning point */ -- -- /* -- * Now we know there is a least one region find. Make sure it does -- * not wrap by the shifting the bitmap if necessary -- */ -- shift = find_first_zero_bit(test, CLK_PHASE_POINT_NUM); -- if (shift != 0) -- meson_mmc_shift_map(test, shift); -- -- while (start < CLK_PHASE_POINT_NUM) { -- meson_mmc_find_next_region(test, &start, &stop); -- -- if ((stop - start) > size) { -- offset = start; -- size = stop - start; -- } -- -- start = stop; -- } -- -- /* Get the center point of the region */ -- offset += (size / 2); -- -- /* Shift the result back */ -- offset = (offset + shift) % CLK_PHASE_POINT_NUM; -- -- return offset; --} -- --static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, -- struct clk *clk) --{ -- int point, ret; -- DECLARE_BITMAP(test, CLK_PHASE_POINT_NUM); -- -- dev_dbg(mmc_dev(mmc), "%s phase/delay tunning...\n", -- __clk_get_name(clk)); -- bitmap_zero(test, CLK_PHASE_POINT_NUM); -- -- /* Explore tuning points */ -- for (point = 0; point < CLK_PHASE_POINT_NUM; point++) { -- clk_set_phase(clk, point * CLK_PHASE_STEP); -- ret = mmc_send_tuning(mmc, opcode, NULL); -- if (!ret) -- set_bit(point, test); -- } -- -- /* Find the optimal tuning point and apply it */ -- point = meson_mmc_find_tuning_point(test); -- if (point < 0) -- return point; /* tuning failed */ -- -- clk_set_phase(clk, point * CLK_PHASE_STEP); -- dev_dbg(mmc_dev(mmc), "success with phase: %d\n", -- clk_get_phase(clk)); -- return 0; --} -- --static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) --{ -- struct meson_host *host = mmc_priv(mmc); -- int adj = 0; -- -- /* enable signal resampling w/o delay */ -- adj = ADJUST_ADJ_EN; -- writel(adj, host->regs + host->data->adjust); -- -- return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); --} -- - static int meson_mmc_prepare_ios_clock(struct meson_host *host, - struct mmc_ios *ios) - { -@@ -796,9 +536,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - /* disable signal resampling */ - writel(0, host->regs + host->data->adjust); - -- /* Reset rx phase */ -- clk_set_phase(host->rx_clk, 0); -- - break; - - case MMC_POWER_ON: -@@ -1226,7 +963,6 @@ static const struct mmc_host_ops meson_mmc_ops = { - .get_cd = meson_mmc_get_cd, - .pre_req = meson_mmc_pre_req, - .post_req = meson_mmc_post_req, -- .execute_tuning = meson_mmc_execute_tuning, - .card_busy = meson_mmc_card_busy, - .start_signal_voltage_switch = meson_mmc_voltage_switch, - }; - -From c71c4edd8d6b76ca10e523f12848cd2985868284 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 23 Apr 2019 11:02:35 +0200 -Subject: [PATCH 113/249] UPSTREAM: mmc: meson-gx: add signal resampling tuning - -Use signal resampling tuning for the UHS and HS200 modes. -Instead of trying to get the *best* resampling setting with complex -window calculation, we just stop on the first working setting. - -If the tuning setting later proves unstable, we will just continue the -tuning where we left it. - -Signed-off-by: Jerome Brunet -Tested-by: Martin Blumenstingl -Reviewed-by: Kevin Hilman -Signed-off-by: Ulf Hansson -(cherry picked from commit f50b7ac5e4ed33f5d2095bfecf48e0671289d188) -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 73 +++++++++++++++++++++++++++++++-- - 1 file changed, 70 insertions(+), 3 deletions(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index acdc5520d02cc..c5a8af4ca76b2 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -488,6 +488,61 @@ static int meson_mmc_clk_init(struct meson_host *host) - return clk_prepare_enable(host->mmc_clk); - } - -+static void meson_mmc_disable_resampling(struct meson_host *host) -+{ -+ unsigned int val = readl(host->regs + host->data->adjust); -+ -+ val &= ~ADJUST_ADJ_EN; -+ writel(val, host->regs + host->data->adjust); -+} -+ -+static void meson_mmc_reset_resampling(struct meson_host *host) -+{ -+ unsigned int val; -+ -+ meson_mmc_disable_resampling(host); -+ -+ val = readl(host->regs + host->data->adjust); -+ val &= ~ADJUST_ADJ_DELAY_MASK; -+ writel(val, host->regs + host->data->adjust); -+} -+ -+static int meson_mmc_resampling_tuning(struct mmc_host *mmc, u32 opcode) -+{ -+ struct meson_host *host = mmc_priv(mmc); -+ unsigned int val, dly, max_dly, i; -+ int ret; -+ -+ /* Resampling is done using the source clock */ -+ max_dly = DIV_ROUND_UP(clk_get_rate(host->mux_clk), -+ clk_get_rate(host->mmc_clk)); -+ -+ val = readl(host->regs + host->data->adjust); -+ val |= ADJUST_ADJ_EN; -+ writel(val, host->regs + host->data->adjust); -+ -+ if (mmc->doing_retune) -+ dly = FIELD_GET(ADJUST_ADJ_DELAY_MASK, val) + 1; -+ else -+ dly = 0; -+ -+ for (i = 0; i < max_dly; i++) { -+ val &= ~ADJUST_ADJ_DELAY_MASK; -+ val |= FIELD_PREP(ADJUST_ADJ_DELAY_MASK, (dly + i) % max_dly); -+ writel(val, host->regs + host->data->adjust); -+ -+ ret = mmc_send_tuning(mmc, opcode, NULL); -+ if (!ret) { -+ dev_dbg(mmc_dev(mmc), "resampling delay: %u\n", -+ (dly + i) % max_dly); -+ return 0; -+ } -+ } -+ -+ meson_mmc_reset_resampling(host); -+ return -EIO; -+} -+ - static int meson_mmc_prepare_ios_clock(struct meson_host *host, - struct mmc_ios *ios) - { -@@ -507,6 +562,19 @@ static int meson_mmc_prepare_ios_clock(struct meson_host *host, - return meson_mmc_clk_set(host, ios->clock, ddr); - } - -+static void meson_mmc_check_resampling(struct meson_host *host, -+ struct mmc_ios *ios) -+{ -+ switch (ios->timing) { -+ case MMC_TIMING_LEGACY: -+ case MMC_TIMING_MMC_HS: -+ case MMC_TIMING_SD_HS: -+ case MMC_TIMING_MMC_DDR52: -+ meson_mmc_disable_resampling(host); -+ break; -+ } -+} -+ - static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - { - struct meson_host *host = mmc_priv(mmc); -@@ -533,9 +601,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - if (!IS_ERR(mmc->supply.vmmc)) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); - -- /* disable signal resampling */ -- writel(0, host->regs + host->data->adjust); -- - break; - - case MMC_POWER_ON: -@@ -574,6 +639,7 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width); - writel(val, host->regs + SD_EMMC_CFG); - -+ meson_mmc_check_resampling(host, ios); - err = meson_mmc_prepare_ios_clock(host, ios); - if (err) - dev_err(host->dev, "Failed to set clock: %d\n,", err); -@@ -963,6 +1029,7 @@ static const struct mmc_host_ops meson_mmc_ops = { - .get_cd = meson_mmc_get_cd, - .pre_req = meson_mmc_pre_req, - .post_req = meson_mmc_post_req, -+ .execute_tuning = meson_mmc_resampling_tuning, - .card_busy = meson_mmc_card_busy, - .start_signal_voltage_switch = meson_mmc_voltage_switch, - }; - -From 4bfdc07be57722cdad3a17d174d2d1d2f4653ce1 Mon Sep 17 00:00:00 2001 -From: Hans Verkuil -Date: Wed, 10 Apr 2019 05:13:29 -0400 -Subject: [PATCH 114/249] UPSTREAM: media: meson: ao-cec: use new - cec_notifier_parse_hdmi_phandle helper - -The meson CEC driver increased the HDMI device refcount when -it shouldn't. Use the new helper function to ensure that that -doesn't happen and to simplify the driver code. - -Signed-off-by: Hans Verkuil -Acked-by: Neil Armstrong -Signed-off-by: Mauro Carvalho Chehab -(cherry picked from commit 6bc37729df640748ed1718e3f150d63cbff1dc7e) -Signed-off-by: Neil Armstrong ---- - drivers/media/platform/meson/ao-cec.c | 16 +++++----------- - 1 file changed, 5 insertions(+), 11 deletions(-) - -diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c -index cd4be38ab5acc..facf9b029e797 100644 ---- a/drivers/media/platform/meson/ao-cec.c -+++ b/drivers/media/platform/meson/ao-cec.c -@@ -601,20 +601,14 @@ static const struct cec_adap_ops meson_ao_cec_ops = { - static int meson_ao_cec_probe(struct platform_device *pdev) - { - struct meson_ao_cec_device *ao_cec; -- struct platform_device *hdmi_dev; -- struct device_node *np; -+ struct device *hdmi_dev; - struct resource *res; - int ret, irq; - -- np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); -- if (!np) { -- dev_err(&pdev->dev, "Failed to find hdmi node\n"); -- return -ENODEV; -- } -+ hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - -- hdmi_dev = of_find_device_by_node(np); -- if (hdmi_dev == NULL) -- return -EPROBE_DEFER; -+ if (IS_ERR(hdmi_dev)) -+ return PTR_ERR(hdmi_dev); - - ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); - if (!ao_cec) -@@ -622,7 +616,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev) - - spin_lock_init(&ao_cec->cec_reg_lock); - -- ao_cec->notify = cec_notifier_get(&hdmi_dev->dev); -+ ao_cec->notify = cec_notifier_get(hdmi_dev); - if (!ao_cec->notify) - return -ENOMEM; - - -From 63e581a76dc7cf1cbd4390ba0d5c59fa114c068d Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Sun, 12 May 2019 22:57:43 +0200 -Subject: [PATCH 115/249] FROMLIST: clk: meson: fix MPLL 50M binding id typo - -MPLL_5OM (the capital letter o) should indeed be MPLL_50M (the number) -Fix this before it gets used. - -Reported-by: Martin Blumenstingl -Fixes: 25db146aa726 ("dt-bindings: clk: meson: add g12a periph clock controller bindings") -Signed-off-by: Jerome Brunet -Acked-by: Neil Armstrong -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/g12a.c | 4 ++-- - drivers/clk/meson/g12a.h | 2 +- - include/dt-bindings/clock/g12a-clkc.h | 2 +- - 3 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index 739f64fdf1e3b..206fafd299ea6 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -2734,8 +2734,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { - [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, - [CLKID_MALI_1] = &g12a_mali_1.hw, - [CLKID_MALI] = &g12a_mali.hw, -- [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw, -- [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw, -+ [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, -+ [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, - [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, - [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, - [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, -diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h -index 39c41af708044..bcc05cd9882f0 100644 ---- a/drivers/clk/meson/g12a.h -+++ b/drivers/clk/meson/g12a.h -@@ -166,7 +166,7 @@ - #define CLKID_HDMI_DIV 167 - #define CLKID_MALI_0_DIV 170 - #define CLKID_MALI_1_DIV 173 --#define CLKID_MPLL_5OM_DIV 176 -+#define CLKID_MPLL_50M_DIV 176 - #define CLKID_SYS_PLL_DIV16_EN 178 - #define CLKID_SYS_PLL_DIV16 179 - #define CLKID_CPU_CLK_DYN0_SEL 180 -diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h -index 82c9e0c020b21..e10470ed7c4f1 100644 ---- a/include/dt-bindings/clock/g12a-clkc.h -+++ b/include/dt-bindings/clock/g12a-clkc.h -@@ -130,7 +130,7 @@ - #define CLKID_MALI_1_SEL 172 - #define CLKID_MALI_1 174 - #define CLKID_MALI 175 --#define CLKID_MPLL_5OM 177 -+#define CLKID_MPLL_50M 177 - #define CLKID_CPU_CLK 187 - #define CLKID_PCIE_PLL 201 - #define CLKID_VDEC_1 204 - -From 589f53ff8c99f92174d3ff072062b58a8ec2e619 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:45:31 +0200 -Subject: [PATCH 116/249] FROMLIST: clk: meson: g12a: fix gp0 and hifi ranges - -While some SoC samples are able to lock with a PLL factor of 55, others -samples can't. ATM, a minimum of 60 appears to work on all the samples -I have tried. - -Even with 60, it sometimes takes a long time for the PLL to eventually -lock. The documentation says that the minimum rate of these PLLs DCO -should be 3GHz, a factor of 125. Let's use that to be on the safe side. - -With factor range changed, the PLL seems to lock quickly (enough) so far. -It is still unclear if the range was the only reason for the delay. - -Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/g12a.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index 206fafd299ea6..d11606d5ddbd6 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -463,7 +463,7 @@ static struct clk_regmap g12a_cpu_clk_trace = { - }; - - static const struct pll_mult_range g12a_gp0_pll_mult_range = { -- .min = 55, -+ .min = 125, - .max = 255, - }; - - -From d0b436a7fe01aeb89d2264ae7b019cf68bddf5ae Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:31:09 +0200 -Subject: [PATCH 117/249] FROMLIST: clk: meson: mpll: properly handle spread - spectrum - -The bit 'SSEN' available on some MPLL DSS outputs is not related to the -fractional part of the divider but to the function called -'Spread Spectrum'. - -This function might be used to solve EM issues by adding a jitter on -clock signal. This widens the signal spectrum and weakens the peaks in it. - -While spread spectrum might be useful for some application, it is -problematic for others, such as audio. - -This patch introduce a new flag to the MPLL driver to enable (or not) the -spread spectrum function. - -Fixes: 1f737ffa13ef ("clk: meson: mpll: fix mpll0 fractional part ignored") -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/clk-mpll.c | 9 ++++++--- - drivers/clk/meson/clk-mpll.h | 1 + - 2 files changed, 7 insertions(+), 3 deletions(-) - -diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c -index f76850d99e591..d3f42e0864313 100644 ---- a/drivers/clk/meson/clk-mpll.c -+++ b/drivers/clk/meson/clk-mpll.c -@@ -119,9 +119,12 @@ static int mpll_set_rate(struct clk_hw *hw, - meson_parm_write(clk->map, &mpll->sdm, sdm); - meson_parm_write(clk->map, &mpll->sdm_en, 1); - -- /* Set additional fractional part enable if required */ -- if (MESON_PARM_APPLICABLE(&mpll->ssen)) -- meson_parm_write(clk->map, &mpll->ssen, 1); -+ /* Set spread spectrum if possible */ -+ if (MESON_PARM_APPLICABLE(&mpll->ssen)) { -+ unsigned int ss = -+ mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0; -+ meson_parm_write(clk->map, &mpll->ssen, ss); -+ } - - /* Set the integer divider part */ - meson_parm_write(clk->map, &mpll->n2, n2); -diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h -index cf79340006dd7..0f948430fed48 100644 ---- a/drivers/clk/meson/clk-mpll.h -+++ b/drivers/clk/meson/clk-mpll.h -@@ -23,6 +23,7 @@ struct meson_clk_mpll_data { - }; - - #define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) -+#define CLK_MESON_MPLL_SPREAD_SPECTRUM BIT(1) - - extern const struct clk_ops meson_clk_mpll_ro_ops; - extern const struct clk_ops meson_clk_mpll_ops; - -From 5b3d82d3de68220a8b8d8e1e7ba0922e124296ca Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:31:10 +0200 -Subject: [PATCH 118/249] FROMLIST: clk: meson: gxbb: no spread spectrum on - mpll0 - -The documentation says there is an SSEN bit on mpll0 but, after testing -it, no spread spectrum function appears to be enabled by this bit on any -of the MPLLs. - -Let's remove it until we know more - -Fixes: 1f737ffa13ef ("clk: meson: mpll: fix mpll0 fractional part ignored") -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/gxbb.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c -index 29ffb4fde7145..dab16d9b1af8b 100644 ---- a/drivers/clk/meson/gxbb.c -+++ b/drivers/clk/meson/gxbb.c -@@ -679,11 +679,6 @@ static struct clk_regmap gxbb_mpll0_div = { - .shift = 16, - .width = 9, - }, -- .ssen = { -- .reg_off = HHI_MPLL_CNTL, -- .shift = 25, -- .width = 1, -- }, - .lock = &meson_clk_lock, - }, - .hw.init = &(struct clk_init_data){ - -From 4e091b46ecd6d09322b9c19ff791a5eb69f4ffed Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:31:11 +0200 -Subject: [PATCH 119/249] FROMLIST: clk: meson: axg: spread spectrum is on - mpll2 - -After testing, it appears that the SSEN bit controls the spread -spectrum function on MPLL2, not MPLL0. - -Fixes: 78b4af312f91 ("clk: meson-axg: add clock controller drivers") -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/axg.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c -index 7a8ef80e5f2cb..3ddd0efc9ee0b 100644 ---- a/drivers/clk/meson/axg.c -+++ b/drivers/clk/meson/axg.c -@@ -469,11 +469,6 @@ static struct clk_regmap axg_mpll0_div = { - .shift = 16, - .width = 9, - }, -- .ssen = { -- .reg_off = HHI_MPLL_CNTL, -- .shift = 25, -- .width = 1, -- }, - .misc = { - .reg_off = HHI_PLL_TOP_MISC, - .shift = 0, -@@ -568,6 +563,11 @@ static struct clk_regmap axg_mpll2_div = { - .shift = 16, - .width = 9, - }, -+ .ssen = { -+ .reg_off = HHI_MPLL_CNTL, -+ .shift = 25, -+ .width = 1, -+ }, - .misc = { - .reg_off = HHI_PLL_TOP_MISC, - .shift = 2, - -From 7fb2041c723972b7ab631af3d5e2aac145a3a23a Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:31:12 +0200 -Subject: [PATCH 120/249] FROMLIST: clk: meson: mpll: add init callback and - regs - -Until now (gx and axg), the mpll setting on boot (whatever the -bootloader) was good enough to generate a clean fractional division. - -It is not the case on the g12a. While moving away from the vendor u-boot, -it was noticed the fractional part of the divider was no longer applied. -Like on the pll, some magic settings need to applied on the mpll -register. - -This change adds the ability to do that on the mpll driver. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/clk-mpll.c | 35 ++++++++++++++++++++++++----------- - drivers/clk/meson/clk-mpll.h | 2 ++ - 2 files changed, 26 insertions(+), 11 deletions(-) - -diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c -index d3f42e0864313..2d39a8bc367c3 100644 ---- a/drivers/clk/meson/clk-mpll.c -+++ b/drivers/clk/meson/clk-mpll.c -@@ -115,8 +115,30 @@ static int mpll_set_rate(struct clk_hw *hw, - else - __acquire(mpll->lock); - -- /* Enable and set the fractional part */ -+ /* Set the fractional part */ - meson_parm_write(clk->map, &mpll->sdm, sdm); -+ -+ /* Set the integer divider part */ -+ meson_parm_write(clk->map, &mpll->n2, n2); -+ -+ if (mpll->lock) -+ spin_unlock_irqrestore(mpll->lock, flags); -+ else -+ __release(mpll->lock); -+ -+ return 0; -+} -+ -+static void mpll_init(struct clk_hw *hw) -+{ -+ struct clk_regmap *clk = to_clk_regmap(hw); -+ struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); -+ -+ if (mpll->init_count) -+ regmap_multi_reg_write(clk->map, mpll->init_regs, -+ mpll->init_count); -+ -+ /* Enable the fractional part */ - meson_parm_write(clk->map, &mpll->sdm_en, 1); - - /* Set spread spectrum if possible */ -@@ -126,19 +148,9 @@ static int mpll_set_rate(struct clk_hw *hw, - meson_parm_write(clk->map, &mpll->ssen, ss); - } - -- /* Set the integer divider part */ -- meson_parm_write(clk->map, &mpll->n2, n2); -- - /* Set the magic misc bit if required */ - if (MESON_PARM_APPLICABLE(&mpll->misc)) - meson_parm_write(clk->map, &mpll->misc, 1); -- -- if (mpll->lock) -- spin_unlock_irqrestore(mpll->lock, flags); -- else -- __release(mpll->lock); -- -- return 0; - } - - const struct clk_ops meson_clk_mpll_ro_ops = { -@@ -151,6 +163,7 @@ const struct clk_ops meson_clk_mpll_ops = { - .recalc_rate = mpll_recalc_rate, - .round_rate = mpll_round_rate, - .set_rate = mpll_set_rate, -+ .init = mpll_init, - }; - EXPORT_SYMBOL_GPL(meson_clk_mpll_ops); - -diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h -index 0f948430fed48..a991d568c43ae 100644 ---- a/drivers/clk/meson/clk-mpll.h -+++ b/drivers/clk/meson/clk-mpll.h -@@ -18,6 +18,8 @@ struct meson_clk_mpll_data { - struct parm n2; - struct parm ssen; - struct parm misc; -+ const struct reg_sequence *init_regs; -+ unsigned int init_count; - spinlock_t *lock; - u8 flags; - }; - -From 2bb779d258c73f180152ec74ddd4c3b51ed4a205 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:31:13 +0200 -Subject: [PATCH 121/249] FROMLIST: clk: meson: g12a: add mpll register init - sequences - -Add the required init of each MPLL of the g12a. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/g12a.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index d11606d5ddbd6..ef1d2e4c8fd28 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -1001,6 +1001,10 @@ static struct clk_fixed_factor g12a_mpll_prediv = { - }, - }; - -+static const struct reg_sequence g12a_mpll0_init_regs[] = { -+ { .reg = HHI_MPLL_CNTL2, .def = 0x40000033 }, -+}; -+ - static struct clk_regmap g12a_mpll0_div = { - .data = &(struct meson_clk_mpll_data){ - .sdm = { -@@ -1024,6 +1028,8 @@ static struct clk_regmap g12a_mpll0_div = { - .width = 1, - }, - .lock = &meson_clk_lock, -+ .init_regs = g12a_mpll0_init_regs, -+ .init_count = ARRAY_SIZE(g12a_mpll0_init_regs), - }, - .hw.init = &(struct clk_init_data){ - .name = "mpll0_div", -@@ -1047,6 +1053,10 @@ static struct clk_regmap g12a_mpll0 = { - }, - }; - -+static const struct reg_sequence g12a_mpll1_init_regs[] = { -+ { .reg = HHI_MPLL_CNTL4, .def = 0x40000033 }, -+}; -+ - static struct clk_regmap g12a_mpll1_div = { - .data = &(struct meson_clk_mpll_data){ - .sdm = { -@@ -1070,6 +1080,8 @@ static struct clk_regmap g12a_mpll1_div = { - .width = 1, - }, - .lock = &meson_clk_lock, -+ .init_regs = g12a_mpll1_init_regs, -+ .init_count = ARRAY_SIZE(g12a_mpll1_init_regs), - }, - .hw.init = &(struct clk_init_data){ - .name = "mpll1_div", -@@ -1093,6 +1105,10 @@ static struct clk_regmap g12a_mpll1 = { - }, - }; - -+static const struct reg_sequence g12a_mpll2_init_regs[] = { -+ { .reg = HHI_MPLL_CNTL6, .def = 0x40000033 }, -+}; -+ - static struct clk_regmap g12a_mpll2_div = { - .data = &(struct meson_clk_mpll_data){ - .sdm = { -@@ -1116,6 +1132,8 @@ static struct clk_regmap g12a_mpll2_div = { - .width = 1, - }, - .lock = &meson_clk_lock, -+ .init_regs = g12a_mpll2_init_regs, -+ .init_count = ARRAY_SIZE(g12a_mpll2_init_regs), - }, - .hw.init = &(struct clk_init_data){ - .name = "mpll2_div", -@@ -1139,6 +1157,10 @@ static struct clk_regmap g12a_mpll2 = { - }, - }; - -+static const struct reg_sequence g12a_mpll3_init_regs[] = { -+ { .reg = HHI_MPLL_CNTL8, .def = 0x40000033 }, -+}; -+ - static struct clk_regmap g12a_mpll3_div = { - .data = &(struct meson_clk_mpll_data){ - .sdm = { -@@ -1162,6 +1184,8 @@ static struct clk_regmap g12a_mpll3_div = { - .width = 1, - }, - .lock = &meson_clk_lock, -+ .init_regs = g12a_mpll3_init_regs, -+ .init_count = ARRAY_SIZE(g12a_mpll3_init_regs), - }, - .hw.init = &(struct clk_init_data){ - .name = "mpll3_div", - -From 4d87e27519b27bacd736e5ed46bc0f952ecf5819 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:31:14 +0200 -Subject: [PATCH 122/249] FROMLIST: clk: meson: eeclk: add init regs - -Like the PLL and MPLL, the controller may require some magic setting to -be applied on startup. - -This is needed when the initial setting is not applied by the boot ROM. -The controller need to do it when the setting applies to several clock, -like all the MPLLs in the case of g12a. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/meson-eeclk.c | 3 +++ - drivers/clk/meson/meson-eeclk.h | 2 ++ - 2 files changed, 5 insertions(+) - -diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c -index 37a34c9c3885e..6ba2094be2577 100644 ---- a/drivers/clk/meson/meson-eeclk.c -+++ b/drivers/clk/meson/meson-eeclk.c -@@ -34,6 +34,9 @@ int meson_eeclkc_probe(struct platform_device *pdev) - return PTR_ERR(map); - } - -+ if (data->init_count) -+ regmap_multi_reg_write(map, data->init_regs, data->init_count); -+ - input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); - if (IS_ERR(input)) { - ret = PTR_ERR(input); -diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h -index 1b809b1419fe0..9ab5d6fa7ccb2 100644 ---- a/drivers/clk/meson/meson-eeclk.h -+++ b/drivers/clk/meson/meson-eeclk.h -@@ -17,6 +17,8 @@ struct platform_device; - struct meson_eeclkc_data { - struct clk_regmap *const *regmap_clks; - unsigned int regmap_clk_num; -+ const struct reg_sequence *init_regs; -+ unsigned int init_count; - struct clk_hw_onecell_data *hw_onecell_data; - }; - - -From aa923cd99d1ffd071e7db0319162e0905b0800ac Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 May 2019 14:31:15 +0200 -Subject: [PATCH 123/249] FROMLIST: clk: meson: g12a: add controller register - init - -Add the MPLL common register initial setting - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/g12a.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index ef1d2e4c8fd28..d5aceb79a91a8 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -2992,10 +2992,16 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { - &g12a_vdec_hevcf, - }; - -+static const struct reg_sequence g12a_init_regs[] = { -+ { .reg = HHI_MPLL_CNTL0, .def = 0x00000543 }, -+}; -+ - static const struct meson_eeclkc_data g12a_clkc_data = { - .regmap_clks = g12a_clk_regmaps, - .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), -- .hw_onecell_data = &g12a_hw_onecell_data -+ .hw_onecell_data = &g12a_hw_onecell_data, -+ .init_regs = g12a_init_regs, -+ .init_count = ARRAY_SIZE(g12a_init_regs), - }; - - static const struct of_device_id clkc_match_table[] = { - -From 428bbcedc99fd5b073aab2c775cfd9f78fa78ce9 Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 10 May 2019 10:23:19 +0200 -Subject: [PATCH 124/249] FROMLIST: dt-bindings: pinctrl: add a - 'drive-strength-microamp' property - -This property allow drive-strength parameter in uA instead of mA. - -Signed-off-by: Guillaume La Roque -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Signed-off-by: Neil Armstrong ---- - Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt -index cef2b5855d60f..fcd37e93ed4da 100644 ---- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt -+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt -@@ -258,6 +258,7 @@ drive-push-pull - drive actively high and low - drive-open-drain - drive with open drain - drive-open-source - drive with open source - drive-strength - sink or source at most X mA -+drive-strength-microamp - sink or source at most X uA - input-enable - enable input on pin (no effect on output, such as - enabling an input buffer) - input-disable - disable input on pin (no effect on output, such as -@@ -326,6 +327,8 @@ arguments are described below. - - - drive-strength takes as argument the target strength in mA. - -+- drive-strength-microamp takes as argument the target strength in uA. -+ - - input-debounce takes the debounce time in usec as argument - or 0 to disable debouncing - - -From 0e9d1f0da2925ab28e8ab022c0cd9621ef99abaf Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 10 May 2019 10:23:20 +0200 -Subject: [PATCH 125/249] FROMLIST: pinctrl: generic: add new - 'drive-strength-microamp' property support - -Add drive-strength-microamp property support to allow drive strength in uA - -Signed-off-by: Guillaume La Roque -Signed-off-by: Neil Armstrong ---- - drivers/pinctrl/pinconf-generic.c | 2 ++ - include/linux/pinctrl/pinconf-generic.h | 3 +++ - 2 files changed, 5 insertions(+) - -diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c -index b4f7f8a458eaf..d0cbdb1ad76a9 100644 ---- a/drivers/pinctrl/pinconf-generic.c -+++ b/drivers/pinctrl/pinconf-generic.c -@@ -39,6 +39,7 @@ static const struct pin_config_item conf_items[] = { - PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false), - PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false), - PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true), -+ PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true), - PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true), - PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false), - PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false), -@@ -167,6 +168,7 @@ static const struct pinconf_generic_params dt_params[] = { - { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, - { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, - { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, -+ { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 }, - { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, - { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, - { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, -diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h -index 6c06806411084..72d06d6a30996 100644 ---- a/include/linux/pinctrl/pinconf-generic.h -+++ b/include/linux/pinctrl/pinconf-generic.h -@@ -55,6 +55,8 @@ - * push-pull mode, the argument is ignored. - * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current - * passed as argument. The argument is in mA. -+ * @PIN_CONFIG_DRIVE_STRENGTH_UA: the pin will sink or source at most the current -+ * passed as argument. The argument is in uA. - * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode, - * which means it will wait for signals to settle when reading inputs. The - * argument gives the debounce time in usecs. Setting the -@@ -112,6 +114,7 @@ enum pin_config_param { - PIN_CONFIG_DRIVE_OPEN_SOURCE, - PIN_CONFIG_DRIVE_PUSH_PULL, - PIN_CONFIG_DRIVE_STRENGTH, -+ PIN_CONFIG_DRIVE_STRENGTH_UA, - PIN_CONFIG_INPUT_DEBOUNCE, - PIN_CONFIG_INPUT_ENABLE, - PIN_CONFIG_INPUT_SCHMITT, - -From de9a915165524d151dd47bf21b8151e7ac064e7b Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 10 May 2019 10:23:21 +0200 -Subject: [PATCH 126/249] FROMLIST: dt-bindings: pinctrl: meson: Add - drive-strength-microamp property - -Add optional drive-strength-microamp property - -Signed-off-by: Guillaume La Roque -Reviewed-by: Martin Blumenstingl -Reviewed-by: Rob Herring -Signed-off-by: Neil Armstrong ---- - Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt -index a47dd990a8d3a..a7618605bf1ef 100644 ---- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt -+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt -@@ -51,6 +51,10 @@ Configuration nodes support the generic properties "bias-disable", - "bias-pull-up" and "bias-pull-down", described in file - pinctrl-bindings.txt - -+Optional properties : -+ - drive-strength-microamp: Drive strength for the specified pins in uA. -+ This property is only valid for G12A and newer. -+ - === Example === - - pinctrl: pinctrl@c1109880 { - -From 7ed2690c52c38d99e53111045774987dd4dc0a37 Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 10 May 2019 10:23:22 +0200 -Subject: [PATCH 127/249] FROMLIST: pinctrl: meson: Rework enable/disable bias - part - -rework bias enable/disable part to prepare drive-strength integration -no functional changes - -Signed-off-by: Guillaume La Roque -Reviewed-by: Martin Blumenstingl -Tested-by: Martin Blumenstingl -Signed-off-by: Neil Armstrong ---- - drivers/pinctrl/meson/pinctrl-meson.c | 85 +++++++++++++++------------ - 1 file changed, 49 insertions(+), 36 deletions(-) - -diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c -index 96a4a72708e49..8ea5c1527064c 100644 ---- a/drivers/pinctrl/meson/pinctrl-meson.c -+++ b/drivers/pinctrl/meson/pinctrl-meson.c -@@ -174,62 +174,75 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, - return 0; - } - --static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, -- unsigned long *configs, unsigned num_configs) -+static int meson_pinconf_disable_bias(struct meson_pinctrl *pc, -+ unsigned int pin) - { -- struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); - struct meson_bank *bank; -- enum pin_config_param param; -- unsigned int reg, bit; -- int i, ret; -+ unsigned int reg, bit = 0; -+ int ret; - - ret = meson_get_bank(pc, pin, &bank); - if (ret) - return ret; - -+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); -+ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin, -+ bool pull_up) -+{ -+ struct meson_bank *bank; -+ unsigned int reg, bit, val = 0; -+ int ret; -+ -+ ret = meson_get_bank(pc, pin, &bank); -+ if (ret) -+ return ret; -+ -+ meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); -+ if (pull_up) -+ val = BIT(bit); -+ -+ ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val); -+ if (ret) -+ return ret; -+ -+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); -+ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit)); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, -+ unsigned long *configs, unsigned num_configs) -+{ -+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); -+ enum pin_config_param param; -+ int i, ret; -+ - for (i = 0; i < num_configs; i++) { - param = pinconf_to_config_param(configs[i]); - - switch (param) { - case PIN_CONFIG_BIAS_DISABLE: -- dev_dbg(pc->dev, "pin %u: disable bias\n", pin); -- -- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, -- &bit); -- ret = regmap_update_bits(pc->reg_pullen, reg, -- BIT(bit), 0); -+ ret = meson_pinconf_disable_bias(pc, pin); - if (ret) - return ret; - break; - case PIN_CONFIG_BIAS_PULL_UP: -- dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin); -- -- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, -- ®, &bit); -- ret = regmap_update_bits(pc->reg_pullen, reg, -- BIT(bit), BIT(bit)); -- if (ret) -- return ret; -- -- meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); -- ret = regmap_update_bits(pc->reg_pull, reg, -- BIT(bit), BIT(bit)); -+ ret = meson_pinconf_enable_bias(pc, pin, true); - if (ret) - return ret; - break; - case PIN_CONFIG_BIAS_PULL_DOWN: -- dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin); -- -- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, -- ®, &bit); -- ret = regmap_update_bits(pc->reg_pullen, reg, -- BIT(bit), BIT(bit)); -- if (ret) -- return ret; -- -- meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); -- ret = regmap_update_bits(pc->reg_pull, reg, -- BIT(bit), 0); -+ ret = meson_pinconf_enable_bias(pc, pin, false); - if (ret) - return ret; - break; - -From 68c85a8e2e96de2ca61723034539f136f5e8cba4 Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 10 May 2019 10:23:23 +0200 -Subject: [PATCH 128/249] FROMLIST: pinctrl: meson: add support of - drive-strength-microamp - -drive-strength-microamp is a new feature needed for G12A SoC. -the default DS setting after boot is usually 500uA and it is not enough for -many functions. We need to be able to set the drive strength to reliably -enable things like MMC, I2C, etc ... - -Signed-off-by: Guillaume La Roque -Reviewed-by: Martin Blumenstingl -Tested-by: Martin Blumenstingl -Signed-off-by: Neil Armstrong ---- - drivers/pinctrl/meson/pinctrl-meson.c | 99 +++++++++++++++++++++++++++ - drivers/pinctrl/meson/pinctrl-meson.h | 18 ++++- - 2 files changed, 116 insertions(+), 1 deletion(-) - -diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c -index 8ea5c1527064c..33b4b141baac6 100644 ---- a/drivers/pinctrl/meson/pinctrl-meson.c -+++ b/drivers/pinctrl/meson/pinctrl-meson.c -@@ -220,11 +220,54 @@ static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin, - return 0; - } - -+static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc, -+ unsigned int pin, -+ u16 drive_strength_ua) -+{ -+ struct meson_bank *bank; -+ unsigned int reg, bit, ds_val; -+ int ret; -+ -+ if (!pc->reg_ds) { -+ dev_err(pc->dev, "drive-strength not supported\n"); -+ return -ENOTSUPP; -+ } -+ -+ ret = meson_get_bank(pc, pin, &bank); -+ if (ret) -+ return ret; -+ -+ meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); -+ bit = bit << 1; -+ -+ if (drive_strength_ua <= 500) { -+ ds_val = MESON_PINCONF_DRV_500UA; -+ } else if (drive_strength_ua <= 2500) { -+ ds_val = MESON_PINCONF_DRV_2500UA; -+ } else if (drive_strength_ua <= 3000) { -+ ds_val = MESON_PINCONF_DRV_3000UA; -+ } else if (drive_strength_ua <= 4000) { -+ ds_val = MESON_PINCONF_DRV_4000UA; -+ } else { -+ dev_warn_once(pc->dev, -+ "pin %u: invalid drive-strength : %d , default to 4mA\n", -+ pin, drive_strength_ua); -+ ds_val = MESON_PINCONF_DRV_4000UA; -+ } -+ -+ ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ - static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, - unsigned long *configs, unsigned num_configs) - { - struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); - enum pin_config_param param; -+ unsigned int drive_strength_ua; - int i, ret; - - for (i = 0; i < num_configs; i++) { -@@ -246,6 +289,14 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, - if (ret) - return ret; - break; -+ case PIN_CONFIG_DRIVE_STRENGTH_UA: -+ drive_strength_ua = -+ pinconf_to_config_argument(configs[i]); -+ ret = meson_pinconf_set_drive_strength -+ (pc, pin, drive_strength_ua); -+ if (ret) -+ return ret; -+ break; - default: - return -ENOTSUPP; - } -@@ -288,12 +339,55 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin) - return conf; - } - -+static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc, -+ unsigned int pin, -+ u16 *drive_strength_ua) -+{ -+ struct meson_bank *bank; -+ unsigned int reg, bit; -+ unsigned int val; -+ int ret; -+ -+ if (!pc->reg_ds) -+ return -ENOTSUPP; -+ -+ ret = meson_get_bank(pc, pin, &bank); -+ if (ret) -+ return ret; -+ -+ meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); -+ -+ ret = regmap_read(pc->reg_ds, reg, &val); -+ if (ret) -+ return ret; -+ -+ switch ((val >> bit) & 0x3) { -+ case MESON_PINCONF_DRV_500UA: -+ *drive_strength_ua = 500; -+ break; -+ case MESON_PINCONF_DRV_2500UA: -+ *drive_strength_ua = 2500; -+ break; -+ case MESON_PINCONF_DRV_3000UA: -+ *drive_strength_ua = 3000; -+ break; -+ case MESON_PINCONF_DRV_4000UA: -+ *drive_strength_ua = 4000; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ - static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, - unsigned long *config) - { - struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); - enum pin_config_param param = pinconf_to_config_param(*config); - u16 arg; -+ int ret; - - switch (param) { - case PIN_CONFIG_BIAS_DISABLE: -@@ -304,6 +398,11 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, - else - return -EINVAL; - break; -+ case PIN_CONFIG_DRIVE_STRENGTH_UA: -+ ret = meson_pinconf_get_drive_strength(pc, pin, &arg); -+ if (ret) -+ return ret; -+ break; - default: - return -ENOTSUPP; - } -diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h -index 5eaab925f427f..cd955fb7c2ce3 100644 ---- a/drivers/pinctrl/meson/pinctrl-meson.h -+++ b/drivers/pinctrl/meson/pinctrl-meson.h -@@ -71,9 +71,20 @@ enum meson_reg_type { - REG_DIR, - REG_OUT, - REG_IN, -+ REG_DS, - NUM_REG, - }; - -+/** -+ * enum meson_pinconf_drv - value of drive-strength supported -+ */ -+enum meson_pinconf_drv { -+ MESON_PINCONF_DRV_500UA, -+ MESON_PINCONF_DRV_2500UA, -+ MESON_PINCONF_DRV_3000UA, -+ MESON_PINCONF_DRV_4000UA, -+}; -+ - /** - * struct meson bank - * -@@ -132,7 +143,8 @@ struct meson_pinctrl { - .num_groups = ARRAY_SIZE(fn ## _groups), \ - } - --#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ -+#define BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, \ -+ dsr, dsb) \ - { \ - .name = n, \ - .first = f, \ -@@ -145,9 +157,13 @@ struct meson_pinctrl { - [REG_DIR] = { dr, db }, \ - [REG_OUT] = { or, ob }, \ - [REG_IN] = { ir, ib }, \ -+ [REG_DS] = { dsr, dsb }, \ - }, \ - } - -+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ -+ BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, 0, 0) -+ - #define MESON_PIN(x) PINCTRL_PIN(x, #x) - - /* Common pmx functions */ - -From aff7a16af9e128cd7f1a7ddc01e60b55775abdfc Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 10 May 2019 10:23:24 +0200 -Subject: [PATCH 129/249] FROMLIST: pinctrl: meson: g12a: add DS bank value - -add drive-strength bank regiter and bit value for G12A SoC - -Signed-off-by: Guillaume La Roque -Reviewed-by: Martin Blumenstingl -Signed-off-by: Neil Armstrong ---- - drivers/pinctrl/meson/pinctrl-meson-g12a.c | 36 +++++++++++----------- - 1 file changed, 18 insertions(+), 18 deletions(-) - -diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c -index d494492e98e9c..3475cd7bd2af3 100644 ---- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c -+++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c -@@ -1304,28 +1304,28 @@ static struct meson_pmx_func meson_g12a_aobus_functions[] = { - }; - - static struct meson_bank meson_g12a_periphs_banks[] = { -- /* name first last irq pullen pull dir out in */ -- BANK("Z", GPIOZ_0, GPIOZ_15, 12, 27, -- 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), -- BANK("H", GPIOH_0, GPIOH_8, 28, 36, -- 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), -- BANK("BOOT", BOOT_0, BOOT_15, 37, 52, -- 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), -- BANK("C", GPIOC_0, GPIOC_7, 53, 60, -- 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), -- BANK("A", GPIOA_0, GPIOA_15, 61, 76, -- 5, 0, 5, 0, 16, 0, 17, 0, 18, 0), -- BANK("X", GPIOX_0, GPIOX_19, 77, 96, -- 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), -+ /* name first last irq pullen pull dir out in ds */ -+ BANK_DS("Z", GPIOZ_0, GPIOZ_15, 12, 27, -+ 4, 0, 4, 0, 12, 0, 13, 0, 14, 0, 5, 0), -+ BANK_DS("H", GPIOH_0, GPIOH_8, 28, 36, -+ 3, 0, 3, 0, 9, 0, 10, 0, 11, 0, 4, 0), -+ BANK_DS("BOOT", BOOT_0, BOOT_15, 37, 52, -+ 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0), -+ BANK_DS("C", GPIOC_0, GPIOC_7, 53, 60, -+ 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0), -+ BANK_DS("A", GPIOA_0, GPIOA_15, 61, 76, -+ 5, 0, 5, 0, 16, 0, 17, 0, 18, 0, 6, 0), -+ BANK_DS("X", GPIOX_0, GPIOX_19, 77, 96, -+ 2, 0, 2, 0, 6, 0, 7, 0, 8, 0, 2, 0), - }; - - static struct meson_bank meson_g12a_aobus_banks[] = { -- /* name first last irq pullen pull dir out in */ -- BANK("AO", GPIOAO_0, GPIOAO_11, 0, 11, -- 3, 0, 2, 0, 0, 0, 4, 0, 1, 0), -+ /* name first last irq pullen pull dir out in ds */ -+ BANK_DS("AO", GPIOAO_0, GPIOAO_11, 0, 11, 3, 0, 2, 0, 0, 0, 4, 0, 1, 0, -+ 0, 0), - /* GPIOE actually located in the AO bank */ -- BANK("E", GPIOE_0, GPIOE_2, 97, 99, -- 3, 16, 2, 16, 0, 16, 4, 16, 1, 16), -+ BANK_DS("E", GPIOE_0, GPIOE_2, 97, 99, 3, 16, 2, 16, 0, 16, 4, 16, 1, -+ 16, 1, 0), - }; - - static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = { - -From 952c6cf49de885601bc897b6bdf79ec2db2c4483 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 10 May 2019 17:53:26 +0200 -Subject: [PATCH 130/249] FROMLIST: arm64: dts: meson: sei510: consistently - order nodes - -Like order boards, order nodes by address then node names then aliases. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12a-sei510.dts | 92 +++++++++---------- - 1 file changed, 46 insertions(+), 46 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 34b40587e5ef1..61fb30047d7fc 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -14,10 +14,6 @@ - compatible = "seirobotics,sei510", "amlogic,g12a"; - model = "SEI Robotics SEI510"; - -- aliases { -- serial0 = &uart_AO; -- }; -- - adc_keys { - compatible = "adc-keys"; - io-channels = <&saradc 0>; -@@ -31,13 +27,8 @@ - }; - }; - -- ao_5v: regulator-ao_5v { -- compatible = "regulator-fixed"; -- regulator-name = "AO_5V"; -- regulator-min-microvolt = <5000000>; -- regulator-max-microvolt = <5000000>; -- vin-supply = <&dc_in>; -- regulator-always-on; -+ aliases { -+ serial0 = &uart_AO; - }; - - chosen { -@@ -54,23 +45,6 @@ - }; - }; - -- dc_in: regulator-dc_in { -- compatible = "regulator-fixed"; -- regulator-name = "DC_IN"; -- regulator-min-microvolt = <5000000>; -- regulator-max-microvolt = <5000000>; -- regulator-always-on; -- }; -- -- emmc_1v8: regulator-emmc_1v8 { -- compatible = "regulator-fixed"; -- regulator-name = "EMMC_1V8"; -- regulator-min-microvolt = <1800000>; -- regulator-max-microvolt = <1800000>; -- vin-supply = <&vddao_3v3>; -- regulator-always-on; -- }; -- - hdmi-connector { - compatible = "hdmi-connector"; - type = "a"; -@@ -87,12 +61,30 @@ - reg = <0x0 0x0 0x0 0x40000000>; - }; - -- reserved-memory { -- /* TEE Reserved Memory */ -- bl32_reserved: bl32@5000000 { -- reg = <0x0 0x05300000 0x0 0x2000000>; -- no-map; -- }; -+ ao_5v: regulator-ao_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "AO_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&dc_in>; -+ regulator-always-on; -+ }; -+ -+ dc_in: regulator-dc_in { -+ compatible = "regulator-fixed"; -+ regulator-name = "DC_IN"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ }; -+ -+ emmc_1v8: regulator-emmc_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "EMMC_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; - }; - - vddao_3v3: regulator-vddao_3v3 { -@@ -122,6 +114,14 @@ - vin-supply = <&vddao_3v3>; - regulator-always-on; - }; -+ -+ reserved-memory { -+ /* TEE Reserved Memory */ -+ bl32_reserved: bl32@5000000 { -+ reg = <0x0 0x05300000 0x0 0x2000000>; -+ no-map; -+ }; -+ }; - }; - - &cec_AO { -@@ -144,6 +144,18 @@ - }; - }; - -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ - &saradc { - status = "okay"; - vref-supply = <&vddio_ao1v8>; -@@ -161,18 +173,6 @@ - }; - }; - --&hdmi_tx { -- status = "okay"; -- pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -- pinctrl-names = "default"; --}; -- --&hdmi_tx_tmds_port { -- hdmi_tx_tmds_out: endpoint { -- remote-endpoint = <&hdmi_connector_in>; -- }; --}; -- - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From 5c90a99c8894a78c50ea33ca287c868081eba99a Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 10 May 2019 17:53:27 +0200 -Subject: [PATCH 131/249] FROMLIST: arm64: dts: meson: u200: consistently order - nodes - -Like order boards, order nodes by address then node names then aliases. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12a-u200.dts | 50 ++++++++++--------- - 1 file changed, 26 insertions(+), 24 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index 0e8045b8a9158..79c70c04ccd19 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -16,13 +16,10 @@ - aliases { - serial0 = &uart_AO; - }; -+ - chosen { - stdout-path = "serial0:115200n8"; - }; -- memory@0 { -- device_type = "memory"; -- reg = <0x0 0x0 0x0 0x40000000>; -- }; - - cvbs-connector { - compatible = "composite-video-connector"; -@@ -34,15 +31,6 @@ - }; - }; - -- flash_1v8: regulator-flash_1v8 { -- compatible = "regulator-fixed"; -- regulator-name = "FLASH_1V8"; -- regulator-min-microvolt = <1800000>; -- regulator-max-microvolt = <1800000>; -- vin-supply = <&vcc_3v3>; -- regulator-always-on; -- }; -- - hdmi-connector { - compatible = "hdmi-connector"; - type = "a"; -@@ -54,6 +42,20 @@ - }; - }; - -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x0 0x0 0x40000000>; -+ }; -+ -+ flash_1v8: regulator-flash_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "FLASH_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ - main_12v: regulator-main_12v { - compatible = "regulator-fixed"; - regulator-name = "12V"; -@@ -62,6 +64,17 @@ - regulator-always-on; - }; - -+ usb_pwr_en: regulator-usb_pwr_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "USB_PWR_EN"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&vcc_5v>; -+ -+ gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ }; -+ - vcc_1v8: regulator-vcc_1v8 { - compatible = "regulator-fixed"; - regulator-name = "VCC_1V8"; -@@ -92,17 +105,6 @@ - enable-active-high; - }; - -- usb_pwr_en: regulator-usb_pwr_en { -- compatible = "regulator-fixed"; -- regulator-name = "USB_PWR_EN"; -- regulator-min-microvolt = <5000000>; -- regulator-max-microvolt = <5000000>; -- vin-supply = <&vcc_5v>; -- -- gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; -- enable-active-high; -- }; -- - vddao_1v8: regulator-vddao_1v8 { - compatible = "regulator-fixed"; - regulator-name = "VDDAO_1V8"; - -From 886ed10475ae22e15ce16977e6c26cb40d3fc37b Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 10 May 2019 18:49:36 +0200 -Subject: [PATCH 132/249] FROMLIST: arm64: dts: meson: g12a: add ethernet mac - controller - -Add the synopsys ethernet mac controller embedded in the g12a SoC family. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 9f72396ba7103..2034e9d51ad8f 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -102,6 +102,27 @@ - #size-cells = <2>; - ranges; - -+ ethmac: ethernet@ff3f0000 { -+ compatible = "amlogic,meson-axg-dwmac", -+ "snps,dwmac-3.70a", -+ "snps,dwmac"; -+ reg = <0x0 0xff3f0000 0x0 0x10000 -+ 0x0 0xff634540 0x0 0x8>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ clocks = <&clkc CLKID_ETH>, -+ <&clkc CLKID_FCLK_DIV2>, -+ <&clkc CLKID_MPLL2>; -+ clock-names = "stmmaceth", "clkin0", "clkin1"; -+ status = "disabled"; -+ -+ mdio0: mdio { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "snps,dwmac-mdio"; -+ }; -+ }; -+ - apb: bus@ff600000 { - compatible = "simple-bus"; - reg = <0x0 0xff600000 0x0 0x200000>; - -From 15ac466d12398b5816c854c5bb32c83e74d8e299 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 10 May 2019 18:49:37 +0200 -Subject: [PATCH 133/249] FROMLIST: arm64: dts: meson: g12a: add ethernet - pinctrl definitions - -Add the ethernet pinctrl settings for RMII, RGMII and internal phy leds - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 37 +++++++++++++++++++++ - 1 file changed, 37 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 2034e9d51ad8f..b26da285ad929 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -206,6 +206,43 @@ - }; - }; - -+ eth_leds_pins: eth-leds { -+ mux { -+ groups = "eth_link_led", -+ "eth_act_led"; -+ function = "eth"; -+ bias-disable; -+ }; -+ }; -+ -+ eth_rmii_pins: eth-rmii { -+ mux { -+ groups = "eth_mdio", -+ "eth_mdc", -+ "eth_rgmii_rx_clk", -+ "eth_rx_dv", -+ "eth_rxd0", -+ "eth_rxd1", -+ "eth_txen", -+ "eth_txd0", -+ "eth_txd1"; -+ function = "eth"; -+ bias-disable; -+ }; -+ }; -+ -+ eth_rgmii_pins: eth-rgmii { -+ mux { -+ groups = "eth_rxd2_rgmii", -+ "eth_rxd3_rgmii", -+ "eth_rgmii_tx_clk", -+ "eth_txd2_rgmii", -+ "eth_txd3_rgmii"; -+ function = "eth"; -+ bias-disable; -+ }; -+ }; -+ - hdmitx_ddc_pins: hdmitx_ddc { - mux { - groups = "hdmitx_sda", - -From aadc5e1356bb4f26e76a307ecc7e58b4528d9688 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 10 May 2019 18:49:38 +0200 -Subject: [PATCH 134/249] FROMLIST: arm64: dts: meson: g12a: add mdio - multiplexer - -Add the g12a mdio multiplexer which allows to connect to either -an external phy through the SoC pins or the internal 10/100 phy - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong -[narmstrong: fixed CLKID_MPLL_50M] ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 32 +++++++++++++++++++++ - 1 file changed, 32 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index b26da285ad929..2ab39f39f679f 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -372,6 +372,38 @@ - assigned-clock-rates = <100000000>; - #phy-cells = <1>; - }; -+ -+ eth_phy: mdio-multiplexer@4c000 { -+ compatible = "amlogic,g12a-mdio-mux"; -+ reg = <0x0 0x4c000 0x0 0xa4>; -+ clocks = <&clkc CLKID_ETH_PHY>, -+ <&xtal>, -+ <&clkc CLKID_MPLL_50M>; -+ clock-names = "pclk", "clkin0", "clkin1"; -+ mdio-parent-bus = <&mdio0>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ext_mdio: mdio@0 { -+ reg = <0>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ -+ int_mdio: mdio@1 { -+ reg = <1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ internal_ephy: ethernet_phy@8 { -+ compatible = "ethernet-phy-id0180.3301", -+ "ethernet-phy-ieee802.3-c22"; -+ interrupts = ; -+ reg = <8>; -+ max-speed = <100>; -+ }; -+ }; -+ }; - }; - - aobus: bus@ff800000 { - -From 99ae6ee90cd8bff09da4f094c963a0552f66f145 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 10 May 2019 18:49:39 +0200 -Subject: [PATCH 135/249] FROMLIST: arm64: dts: meson: u200: add internal - network - -The u200 is the main mother board for the S905D2. It can provide -both the internal and external network. However, by default the -resistance required for the external RGMII bus are not fitted, so -enable the internal PHY. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index 79c70c04ccd19..f1cb02567a130 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -15,6 +15,7 @@ - - aliases { - serial0 = &uart_AO; -+ ethernet0 = ðmac; - }; - - chosen { -@@ -145,6 +146,12 @@ - }; - }; - -+ðmac { -+ status = "okay"; -+ phy-handle = <&internal_ephy>; -+ phy-mode = "rmii"; -+}; -+ - &hdmi_tx { - status = "okay"; - pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; - -From 43d2941fab29f9d4cc12cef8f513dc199ce7c50a Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 10 May 2019 18:49:40 +0200 -Subject: [PATCH 136/249] FROMLIST: arm64: dts: meson: sei510: add network - support - -Enable the network interface of the SEI510 which use the internal PHY. - -Signed-off-by: Jerome Brunet -Tested-by: Kevin Hilman -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 61fb30047d7fc..4a785b17c1af7 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -29,6 +29,7 @@ - - aliases { - serial0 = &uart_AO; -+ ethernet0 = ðmac; - }; - - chosen { -@@ -144,6 +145,12 @@ - }; - }; - -+ðmac { -+ status = "okay"; -+ phy-handle = <&internal_ephy>; -+ phy-mode = "rmii"; -+}; -+ - &hdmi_tx { - status = "okay"; - pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; - -From 671da6b5f5c9f385b8a5c04787b9febe0f3e5caf Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Sun, 12 May 2019 23:12:37 +0200 -Subject: [PATCH 137/249] FROMLIST: net: meson: fixup g12a glue ephy id - -The phy id chosen by Amlogic is incorrectly set in the mdio mux and -does not match the phy driver. - -It was not detected before because DT forces the use the correct driver -for the internal PHY. - -Fixes: 7090425104db ("net: phy: add amlogic g12a mdio mux support") -Reported-by: Qi Duan -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/net/phy/mdio-mux-meson-g12a.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/net/phy/mdio-mux-meson-g12a.c b/drivers/net/phy/mdio-mux-meson-g12a.c -index 6fa29ea8e2a36..6644762ff2abb 100644 ---- a/drivers/net/phy/mdio-mux-meson-g12a.c -+++ b/drivers/net/phy/mdio-mux-meson-g12a.c -@@ -33,7 +33,7 @@ - #define ETH_PLL_CTL7 0x60 - - #define ETH_PHY_CNTL0 0x80 --#define EPHY_G12A_ID 0x33000180 -+#define EPHY_G12A_ID 0x33010180 - #define ETH_PHY_CNTL1 0x84 - #define PHY_CNTL1_ST_MODE GENMASK(2, 0) - #define PHY_CNTL1_ST_PHYADD GENMASK(7, 3) - -From b499c275a5a1857f45c92cf68fe554d11c419678 Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 12 Apr 2019 12:02:20 +0200 -Subject: [PATCH 138/249] FROMLIST: dt-bindings: clk: g12a-clkc: add - Temperature Sensor clock ID - -Add clock id used by temperature sensor for G12A Socs - -Signed-off-by: Guillaume La Roque -Reviewed-by: Martin Blumenstingl ---- - include/dt-bindings/clock/g12a-clkc.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h -index e10470ed7c4f1..b6b127e456345 100644 ---- a/include/dt-bindings/clock/g12a-clkc.h -+++ b/include/dt-bindings/clock/g12a-clkc.h -@@ -136,5 +136,6 @@ - #define CLKID_VDEC_1 204 - #define CLKID_VDEC_HEVC 207 - #define CLKID_VDEC_HEVCF 210 -+#define CLKID_TS 212 - - #endif /* __G12A_CLKC_H */ - -From fa512588c07fbd208365f7a80088723b5bef4303 Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Fri, 12 Apr 2019 12:02:21 +0200 -Subject: [PATCH 139/249] FROMLIST: clk: meson-g12a: Add Temperature Sensor - clock - -Add TS clock used by two temperature sensor - -Signed-off-by: Guillaume La Roque -Reviewed-by: Martin Blumenstingl ---- - drivers/clk/meson/g12a.c | 31 +++++++++++++++++++++++++++++++ - drivers/clk/meson/g12a.h | 3 ++- - 2 files changed, 33 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index d5aceb79a91a8..a7b621bebb7e2 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -2504,6 +2504,33 @@ static struct clk_regmap g12a_mali = { - }, - }; - -+static struct clk_regmap g12a_ts_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_TS_CLK_CNTL, -+ .shift = 0, -+ .width = 8, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "ts_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "xtal" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_regmap g12a_ts = { -+ .data = &(struct clk_regmap_gate_data){ -+ .offset = HHI_TS_CLK_CNTL, -+ .bit_idx = 8, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "ts", -+ .ops = &clk_regmap_gate_ops, -+ .parent_names = (const char *[]){ "ts_div" }, -+ .num_parents = 1, -+ }, -+}; -+ - /* Everything Else (EE) domain gates */ - static MESON_GATE(g12a_ddr, HHI_GCLK_MPEG0, 0); - static MESON_GATE(g12a_dos, HHI_GCLK_MPEG0, 1); -@@ -2793,6 +2820,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { - [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, - [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, - [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, -+ [CLKID_TS_DIV] = &g12a_ts_div.hw, -+ [CLKID_TS] = &g12a_ts.hw, - [NR_CLKS] = NULL, - }, - .num = NR_CLKS, -@@ -2990,6 +3019,8 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { - &g12a_vdec_hevcf_sel, - &g12a_vdec_hevcf_div, - &g12a_vdec_hevcf, -+ &g12a_ts_div, -+ &g12a_ts, - }; - - static const struct reg_sequence g12a_init_regs[] = { -diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h -index bcc05cd9882f0..bda1501ba671e 100644 ---- a/drivers/clk/meson/g12a.h -+++ b/drivers/clk/meson/g12a.h -@@ -195,8 +195,9 @@ - #define CLKID_VDEC_HEVC_DIV 206 - #define CLKID_VDEC_HEVCF_SEL 208 - #define CLKID_VDEC_HEVCF_DIV 209 -+#define CLKID_TS_DIV 211 - --#define NR_CLKS 211 -+#define NR_CLKS 213 - - /* include the CLKIDs that have been made part of the DT binding */ - #include - -From c574de0f772993aa0cbc7534c1c3a2cf5e362b28 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 14 Mar 2019 14:50:42 +0100 -Subject: [PATCH 140/249] FROMLIST: dt-bindings: clk: meson: add g12b periph - clock controller bindings - -This patch adds the specific Amlogic G12B clock driver compatible. - -G12B clock driver is very close, the main differences are : -- the clock tree is duplicated for the both clusters, and the - SYS_PLL are swapped between the clusters -- G12A has additional clocks like for CSI an other components - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring ---- - Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt -index 5c8b105be4d66..6eaa520923139 100644 ---- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt -+++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt -@@ -10,6 +10,7 @@ Required Properties: - "amlogic,gxl-clkc" for GXL and GXM SoC, - "amlogic,axg-clkc" for AXG SoC. - "amlogic,g12a-clkc" for G12A SoC. -+ "amlogic,g12b-clkc" for G12B SoC. - - clocks : list of clock phandle, one for each entry clock-names. - - clock-names : should contain the following: - * "xtal": the platform xtal - -From 09393a868c0527f8855db18384bd946574f48b83 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 14 Mar 2019 14:51:18 +0100 -Subject: [PATCH 141/249] FROMLIST: clk: meson: g12a: Add support for G12B CPUB - clocks - -This patch support for the specific Amlogic G12B clocks. - -G12B clock driver is very close, the main differences are : -- the clock tree is duplicated for the both clusters, and the - SYS_PLL are swapped between the clusters -- G12A has additional clocks like for CSI an other components - -Here only the cpu clock tree is handled. - -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/g12a.c | 443 +++++++++++++++++++++++++++++++++++++++ - drivers/clk/meson/g12a.h | 20 +- - 2 files changed, 462 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index a7b621bebb7e2..bbd67e9be3ddc 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -150,6 +150,57 @@ static struct clk_regmap g12a_sys_pll = { - }, - }; - -+static struct clk_regmap g12b_sys1_pll_dco = { -+ .data = &(struct meson_clk_pll_data){ -+ .en = { -+ .reg_off = HHI_SYS1_PLL_CNTL0, -+ .shift = 28, -+ .width = 1, -+ }, -+ .m = { -+ .reg_off = HHI_SYS1_PLL_CNTL0, -+ .shift = 0, -+ .width = 8, -+ }, -+ .n = { -+ .reg_off = HHI_SYS1_PLL_CNTL0, -+ .shift = 10, -+ .width = 5, -+ }, -+ .l = { -+ .reg_off = HHI_SYS1_PLL_CNTL0, -+ .shift = 31, -+ .width = 1, -+ }, -+ .rst = { -+ .reg_off = HHI_SYS1_PLL_CNTL0, -+ .shift = 29, -+ .width = 1, -+ }, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "sys1_pll_dco", -+ .ops = &meson_clk_pll_ro_ops, -+ .parent_names = (const char *[]){ IN_PREFIX "xtal" }, -+ .num_parents = 1, -+ }, -+}; -+ -+static struct clk_regmap g12b_sys1_pll = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS1_PLL_CNTL0, -+ .shift = 16, -+ .width = 3, -+ .flags = CLK_DIVIDER_POWER_OF_TWO, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "sys1_pll", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "sys1_pll_dco" }, -+ .num_parents = 1, -+ }, -+}; -+ - static struct clk_regmap g12a_sys_pll_div16_en = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_SYS_CPU_CLK_CNTL1, -@@ -306,6 +357,150 @@ static struct clk_regmap g12a_cpu_clk = { - }, - }; - -+/* Datasheet names this field as "Final_mux_sel" */ -+static struct clk_regmap g12b_cpu_clk = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPU_CLK_CNTL0, -+ .mask = 0x1, -+ .shift = 11, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpu_clk", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpu_clk_dyn", -+ "sys1_pll" }, -+ .num_parents = 2, -+ }, -+}; -+ -+/* Datasheet names this field as "premux0" */ -+static struct clk_regmap g12b_cpub_clk_premux0 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .mask = 0x3, -+ .shift = 0, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk_dyn0_sel", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ IN_PREFIX "xtal", -+ "fclk_div2", -+ "fclk_div3" }, -+ .num_parents = 3, -+ }, -+}; -+ -+/* Datasheet names this field as "mux0_divn_tcnt" */ -+static struct clk_regmap g12b_cpub_clk_mux0_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .shift = 4, -+ .width = 6, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk_dyn0_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpub_clk_dyn0_sel" }, -+ .num_parents = 1, -+ }, -+}; -+ -+/* Datasheet names this field as "postmux0" */ -+static struct clk_regmap g12b_cpub_clk_postmux0 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .mask = 0x1, -+ .shift = 2, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk_dyn0", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpub_clk_dyn0_sel", -+ "cpub_clk_dyn0_div" }, -+ .num_parents = 2, -+ }, -+}; -+ -+/* Datasheet names this field as "premux1" */ -+static struct clk_regmap g12b_cpub_clk_premux1 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .mask = 0x3, -+ .shift = 16, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk_dyn1_sel", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ IN_PREFIX "xtal", -+ "fclk_div2", -+ "fclk_div3" }, -+ .num_parents = 3, -+ }, -+}; -+ -+/* Datasheet names this field as "Mux1_divn_tcnt" */ -+static struct clk_regmap g12b_cpub_clk_mux1_div = { -+ .data = &(struct clk_regmap_div_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .shift = 20, -+ .width = 6, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk_dyn1_div", -+ .ops = &clk_regmap_divider_ro_ops, -+ .parent_names = (const char *[]){ "cpub_clk_dyn1_sel" }, -+ .num_parents = 1, -+ }, -+}; -+ -+/* Datasheet names this field as "postmux1" */ -+static struct clk_regmap g12b_cpub_clk_postmux1 = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .mask = 0x1, -+ .shift = 18, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk_dyn1", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpub_clk_dyn1_sel", -+ "cpub_clk_dyn1_div" }, -+ .num_parents = 2, -+ }, -+}; -+ -+/* Datasheet names this field as "Final_dyn_mux_sel" */ -+static struct clk_regmap g12b_cpub_clk_dyn = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .mask = 0x1, -+ .shift = 10, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk_dyn", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpub_clk_dyn0", -+ "cpub_clk_dyn1" }, -+ .num_parents = 2, -+ }, -+}; -+ -+/* Datasheet names this field as "Final_mux_sel" */ -+static struct clk_regmap g12b_cpub_clk = { -+ .data = &(struct clk_regmap_mux_data){ -+ .offset = HHI_SYS_CPUB_CLK_CNTL, -+ .mask = 0x1, -+ .shift = 11, -+ }, -+ .hw.init = &(struct clk_init_data){ -+ .name = "cpub_clk", -+ .ops = &clk_regmap_mux_ro_ops, -+ .parent_names = (const char *[]){ "cpub_clk_dyn", -+ "sys_pll" }, -+ .num_parents = 2, -+ }, -+}; -+ - static struct clk_regmap g12a_cpu_clk_div16_en = { - .data = &(struct clk_regmap_gate_data){ - .offset = HHI_SYS_CPU_CLK_CNTL1, -@@ -2827,6 +3022,236 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { - .num = NR_CLKS, - }; - -+static struct clk_hw_onecell_data g12b_hw_onecell_data = { -+ .hws = { -+ [CLKID_SYS_PLL] = &g12a_sys_pll.hw, -+ [CLKID_FIXED_PLL] = &g12a_fixed_pll.hw, -+ [CLKID_FCLK_DIV2] = &g12a_fclk_div2.hw, -+ [CLKID_FCLK_DIV3] = &g12a_fclk_div3.hw, -+ [CLKID_FCLK_DIV4] = &g12a_fclk_div4.hw, -+ [CLKID_FCLK_DIV5] = &g12a_fclk_div5.hw, -+ [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, -+ [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, -+ [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, -+ [CLKID_MPEG_SEL] = &g12a_mpeg_clk_sel.hw, -+ [CLKID_MPEG_DIV] = &g12a_mpeg_clk_div.hw, -+ [CLKID_CLK81] = &g12a_clk81.hw, -+ [CLKID_MPLL0] = &g12a_mpll0.hw, -+ [CLKID_MPLL1] = &g12a_mpll1.hw, -+ [CLKID_MPLL2] = &g12a_mpll2.hw, -+ [CLKID_MPLL3] = &g12a_mpll3.hw, -+ [CLKID_DDR] = &g12a_ddr.hw, -+ [CLKID_DOS] = &g12a_dos.hw, -+ [CLKID_AUDIO_LOCKER] = &g12a_audio_locker.hw, -+ [CLKID_MIPI_DSI_HOST] = &g12a_mipi_dsi_host.hw, -+ [CLKID_ETH_PHY] = &g12a_eth_phy.hw, -+ [CLKID_ISA] = &g12a_isa.hw, -+ [CLKID_PL301] = &g12a_pl301.hw, -+ [CLKID_PERIPHS] = &g12a_periphs.hw, -+ [CLKID_SPICC0] = &g12a_spicc_0.hw, -+ [CLKID_I2C] = &g12a_i2c.hw, -+ [CLKID_SANA] = &g12a_sana.hw, -+ [CLKID_SD] = &g12a_sd.hw, -+ [CLKID_RNG0] = &g12a_rng0.hw, -+ [CLKID_UART0] = &g12a_uart0.hw, -+ [CLKID_SPICC1] = &g12a_spicc_1.hw, -+ [CLKID_HIU_IFACE] = &g12a_hiu_reg.hw, -+ [CLKID_MIPI_DSI_PHY] = &g12a_mipi_dsi_phy.hw, -+ [CLKID_ASSIST_MISC] = &g12a_assist_misc.hw, -+ [CLKID_SD_EMMC_A] = &g12a_emmc_a.hw, -+ [CLKID_SD_EMMC_B] = &g12a_emmc_b.hw, -+ [CLKID_SD_EMMC_C] = &g12a_emmc_c.hw, -+ [CLKID_AUDIO_CODEC] = &g12a_audio_codec.hw, -+ [CLKID_AUDIO] = &g12a_audio.hw, -+ [CLKID_ETH] = &g12a_eth_core.hw, -+ [CLKID_DEMUX] = &g12a_demux.hw, -+ [CLKID_AUDIO_IFIFO] = &g12a_audio_ififo.hw, -+ [CLKID_ADC] = &g12a_adc.hw, -+ [CLKID_UART1] = &g12a_uart1.hw, -+ [CLKID_G2D] = &g12a_g2d.hw, -+ [CLKID_RESET] = &g12a_reset.hw, -+ [CLKID_PCIE_COMB] = &g12a_pcie_comb.hw, -+ [CLKID_PARSER] = &g12a_parser.hw, -+ [CLKID_USB] = &g12a_usb_general.hw, -+ [CLKID_PCIE_PHY] = &g12a_pcie_phy.hw, -+ [CLKID_AHB_ARB0] = &g12a_ahb_arb0.hw, -+ [CLKID_AHB_DATA_BUS] = &g12a_ahb_data_bus.hw, -+ [CLKID_AHB_CTRL_BUS] = &g12a_ahb_ctrl_bus.hw, -+ [CLKID_HTX_HDCP22] = &g12a_htx_hdcp22.hw, -+ [CLKID_HTX_PCLK] = &g12a_htx_pclk.hw, -+ [CLKID_BT656] = &g12a_bt656.hw, -+ [CLKID_USB1_DDR_BRIDGE] = &g12a_usb1_to_ddr.hw, -+ [CLKID_MMC_PCLK] = &g12a_mmc_pclk.hw, -+ [CLKID_UART2] = &g12a_uart2.hw, -+ [CLKID_VPU_INTR] = &g12a_vpu_intr.hw, -+ [CLKID_GIC] = &g12a_gic.hw, -+ [CLKID_SD_EMMC_A_CLK0_SEL] = &g12a_sd_emmc_a_clk0_sel.hw, -+ [CLKID_SD_EMMC_A_CLK0_DIV] = &g12a_sd_emmc_a_clk0_div.hw, -+ [CLKID_SD_EMMC_A_CLK0] = &g12a_sd_emmc_a_clk0.hw, -+ [CLKID_SD_EMMC_B_CLK0_SEL] = &g12a_sd_emmc_b_clk0_sel.hw, -+ [CLKID_SD_EMMC_B_CLK0_DIV] = &g12a_sd_emmc_b_clk0_div.hw, -+ [CLKID_SD_EMMC_B_CLK0] = &g12a_sd_emmc_b_clk0.hw, -+ [CLKID_SD_EMMC_C_CLK0_SEL] = &g12a_sd_emmc_c_clk0_sel.hw, -+ [CLKID_SD_EMMC_C_CLK0_DIV] = &g12a_sd_emmc_c_clk0_div.hw, -+ [CLKID_SD_EMMC_C_CLK0] = &g12a_sd_emmc_c_clk0.hw, -+ [CLKID_MPLL0_DIV] = &g12a_mpll0_div.hw, -+ [CLKID_MPLL1_DIV] = &g12a_mpll1_div.hw, -+ [CLKID_MPLL2_DIV] = &g12a_mpll2_div.hw, -+ [CLKID_MPLL3_DIV] = &g12a_mpll3_div.hw, -+ [CLKID_FCLK_DIV2_DIV] = &g12a_fclk_div2_div.hw, -+ [CLKID_FCLK_DIV3_DIV] = &g12a_fclk_div3_div.hw, -+ [CLKID_FCLK_DIV4_DIV] = &g12a_fclk_div4_div.hw, -+ [CLKID_FCLK_DIV5_DIV] = &g12a_fclk_div5_div.hw, -+ [CLKID_FCLK_DIV7_DIV] = &g12a_fclk_div7_div.hw, -+ [CLKID_FCLK_DIV2P5_DIV] = &g12a_fclk_div2p5_div.hw, -+ [CLKID_HIFI_PLL] = &g12a_hifi_pll.hw, -+ [CLKID_VCLK2_VENCI0] = &g12a_vclk2_venci0.hw, -+ [CLKID_VCLK2_VENCI1] = &g12a_vclk2_venci1.hw, -+ [CLKID_VCLK2_VENCP0] = &g12a_vclk2_vencp0.hw, -+ [CLKID_VCLK2_VENCP1] = &g12a_vclk2_vencp1.hw, -+ [CLKID_VCLK2_VENCT0] = &g12a_vclk2_venct0.hw, -+ [CLKID_VCLK2_VENCT1] = &g12a_vclk2_venct1.hw, -+ [CLKID_VCLK2_OTHER] = &g12a_vclk2_other.hw, -+ [CLKID_VCLK2_ENCI] = &g12a_vclk2_enci.hw, -+ [CLKID_VCLK2_ENCP] = &g12a_vclk2_encp.hw, -+ [CLKID_DAC_CLK] = &g12a_dac_clk.hw, -+ [CLKID_AOCLK] = &g12a_aoclk_gate.hw, -+ [CLKID_IEC958] = &g12a_iec958_gate.hw, -+ [CLKID_ENC480P] = &g12a_enc480p.hw, -+ [CLKID_RNG1] = &g12a_rng1.hw, -+ [CLKID_VCLK2_ENCT] = &g12a_vclk2_enct.hw, -+ [CLKID_VCLK2_ENCL] = &g12a_vclk2_encl.hw, -+ [CLKID_VCLK2_VENCLMMC] = &g12a_vclk2_venclmmc.hw, -+ [CLKID_VCLK2_VENCL] = &g12a_vclk2_vencl.hw, -+ [CLKID_VCLK2_OTHER1] = &g12a_vclk2_other1.hw, -+ [CLKID_FIXED_PLL_DCO] = &g12a_fixed_pll_dco.hw, -+ [CLKID_SYS_PLL_DCO] = &g12a_sys_pll_dco.hw, -+ [CLKID_GP0_PLL_DCO] = &g12a_gp0_pll_dco.hw, -+ [CLKID_HIFI_PLL_DCO] = &g12a_hifi_pll_dco.hw, -+ [CLKID_DMA] = &g12a_dma.hw, -+ [CLKID_EFUSE] = &g12a_efuse.hw, -+ [CLKID_ROM_BOOT] = &g12a_rom_boot.hw, -+ [CLKID_RESET_SEC] = &g12a_reset_sec.hw, -+ [CLKID_SEC_AHB_APB3] = &g12a_sec_ahb_apb3.hw, -+ [CLKID_MPLL_PREDIV] = &g12a_mpll_prediv.hw, -+ [CLKID_VPU_0_SEL] = &g12a_vpu_0_sel.hw, -+ [CLKID_VPU_0_DIV] = &g12a_vpu_0_div.hw, -+ [CLKID_VPU_0] = &g12a_vpu_0.hw, -+ [CLKID_VPU_1_SEL] = &g12a_vpu_1_sel.hw, -+ [CLKID_VPU_1_DIV] = &g12a_vpu_1_div.hw, -+ [CLKID_VPU_1] = &g12a_vpu_1.hw, -+ [CLKID_VPU] = &g12a_vpu.hw, -+ [CLKID_VAPB_0_SEL] = &g12a_vapb_0_sel.hw, -+ [CLKID_VAPB_0_DIV] = &g12a_vapb_0_div.hw, -+ [CLKID_VAPB_0] = &g12a_vapb_0.hw, -+ [CLKID_VAPB_1_SEL] = &g12a_vapb_1_sel.hw, -+ [CLKID_VAPB_1_DIV] = &g12a_vapb_1_div.hw, -+ [CLKID_VAPB_1] = &g12a_vapb_1.hw, -+ [CLKID_VAPB_SEL] = &g12a_vapb_sel.hw, -+ [CLKID_VAPB] = &g12a_vapb.hw, -+ [CLKID_HDMI_PLL_DCO] = &g12a_hdmi_pll_dco.hw, -+ [CLKID_HDMI_PLL_OD] = &g12a_hdmi_pll_od.hw, -+ [CLKID_HDMI_PLL_OD2] = &g12a_hdmi_pll_od2.hw, -+ [CLKID_HDMI_PLL] = &g12a_hdmi_pll.hw, -+ [CLKID_VID_PLL] = &g12a_vid_pll_div.hw, -+ [CLKID_VID_PLL_SEL] = &g12a_vid_pll_sel.hw, -+ [CLKID_VID_PLL_DIV] = &g12a_vid_pll.hw, -+ [CLKID_VCLK_SEL] = &g12a_vclk_sel.hw, -+ [CLKID_VCLK2_SEL] = &g12a_vclk2_sel.hw, -+ [CLKID_VCLK_INPUT] = &g12a_vclk_input.hw, -+ [CLKID_VCLK2_INPUT] = &g12a_vclk2_input.hw, -+ [CLKID_VCLK_DIV] = &g12a_vclk_div.hw, -+ [CLKID_VCLK2_DIV] = &g12a_vclk2_div.hw, -+ [CLKID_VCLK] = &g12a_vclk.hw, -+ [CLKID_VCLK2] = &g12a_vclk2.hw, -+ [CLKID_VCLK_DIV1] = &g12a_vclk_div1.hw, -+ [CLKID_VCLK_DIV2_EN] = &g12a_vclk_div2_en.hw, -+ [CLKID_VCLK_DIV4_EN] = &g12a_vclk_div4_en.hw, -+ [CLKID_VCLK_DIV6_EN] = &g12a_vclk_div6_en.hw, -+ [CLKID_VCLK_DIV12_EN] = &g12a_vclk_div12_en.hw, -+ [CLKID_VCLK2_DIV1] = &g12a_vclk2_div1.hw, -+ [CLKID_VCLK2_DIV2_EN] = &g12a_vclk2_div2_en.hw, -+ [CLKID_VCLK2_DIV4_EN] = &g12a_vclk2_div4_en.hw, -+ [CLKID_VCLK2_DIV6_EN] = &g12a_vclk2_div6_en.hw, -+ [CLKID_VCLK2_DIV12_EN] = &g12a_vclk2_div12_en.hw, -+ [CLKID_VCLK_DIV2] = &g12a_vclk_div2.hw, -+ [CLKID_VCLK_DIV4] = &g12a_vclk_div4.hw, -+ [CLKID_VCLK_DIV6] = &g12a_vclk_div6.hw, -+ [CLKID_VCLK_DIV12] = &g12a_vclk_div12.hw, -+ [CLKID_VCLK2_DIV2] = &g12a_vclk2_div2.hw, -+ [CLKID_VCLK2_DIV4] = &g12a_vclk2_div4.hw, -+ [CLKID_VCLK2_DIV6] = &g12a_vclk2_div6.hw, -+ [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, -+ [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, -+ [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, -+ [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, -+ [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, -+ [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, -+ [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, -+ [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, -+ [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, -+ [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, -+ [CLKID_HDMI_DIV] = &g12a_hdmi_div.hw, -+ [CLKID_HDMI] = &g12a_hdmi.hw, -+ [CLKID_MALI_0_SEL] = &g12a_mali_0_sel.hw, -+ [CLKID_MALI_0_DIV] = &g12a_mali_0_div.hw, -+ [CLKID_MALI_0] = &g12a_mali_0.hw, -+ [CLKID_MALI_1_SEL] = &g12a_mali_1_sel.hw, -+ [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, -+ [CLKID_MALI_1] = &g12a_mali_1.hw, -+ [CLKID_MALI] = &g12a_mali.hw, -+ [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, -+ [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, -+ [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, -+ [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, -+ [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, -+ [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, -+ [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, -+ [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, -+ [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, -+ [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, -+ [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, -+ [CLKID_CPU_CLK] = &g12b_cpu_clk.hw, -+ [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, -+ [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, -+ [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, -+ [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, -+ [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, -+ [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, -+ [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, -+ [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, -+ [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, -+ [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, -+ [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, -+ [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, -+ [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, -+ [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, -+ [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, -+ [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, -+ [CLKID_VDEC_1] = &g12a_vdec_1.hw, -+ [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, -+ [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, -+ [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, -+ [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, -+ [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, -+ [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, -+ [CLKID_TS_DIV] = &g12a_ts_div.hw, -+ [CLKID_TS] = &g12a_ts.hw, -+ [CLKID_SYS1_PLL_DCO] = &g12b_sys1_pll_dco.hw, -+ [CLKID_SYS1_PLL] = &g12b_sys1_pll.hw, -+ [CLKID_CPUB_CLK_DYN0_SEL] = &g12b_cpub_clk_premux0.hw, -+ [CLKID_CPUB_CLK_DYN0_DIV] = &g12b_cpub_clk_mux0_div.hw, -+ [CLKID_CPUB_CLK_DYN0] = &g12b_cpub_clk_postmux0.hw, -+ [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_premux1.hw, -+ [CLKID_CPUB_CLK_DYN1_DIV] = &g12b_cpub_clk_mux1_div.hw, -+ [CLKID_CPUB_CLK_DYN1] = &g12b_cpub_clk_postmux1.hw, -+ [CLKID_CPUB_CLK_DYN] = &g12b_cpub_clk_dyn.hw, -+ [CLKID_CPUB_CLK] = &g12b_cpub_clk.hw, -+ [NR_CLKS] = NULL, -+ }, -+ .num = NR_CLKS, -+}; -+ - /* Convenience table to populate regmap in .probe */ - static struct clk_regmap *const g12a_clk_regmaps[] = { - &g12a_clk81, -@@ -3021,6 +3446,17 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { - &g12a_vdec_hevcf, - &g12a_ts_div, - &g12a_ts, -+ &g12b_cpu_clk, -+ &g12b_sys1_pll_dco, -+ &g12b_sys1_pll, -+ &g12b_cpub_clk_premux0, -+ &g12b_cpub_clk_mux0_div, -+ &g12b_cpub_clk_postmux0, -+ &g12b_cpub_clk_premux1, -+ &g12b_cpub_clk_mux1_div, -+ &g12b_cpub_clk_postmux1, -+ &g12b_cpub_clk_dyn, -+ &g12b_cpub_clk, - }; - - static const struct reg_sequence g12a_init_regs[] = { -@@ -3035,8 +3471,15 @@ static const struct meson_eeclkc_data g12a_clkc_data = { - .init_count = ARRAY_SIZE(g12a_init_regs), - }; - -+static const struct meson_eeclkc_data g12b_clkc_data = { -+ .regmap_clks = g12a_clk_regmaps, -+ .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), -+ .hw_onecell_data = &g12b_hw_onecell_data -+}; -+ - static const struct of_device_id clkc_match_table[] = { - { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data }, -+ { .compatible = "amlogic,g12b-clkc", .data = &g12b_clkc_data }, - {} - }; - -diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h -index bda1501ba671e..d2f9a657e1499 100644 ---- a/drivers/clk/meson/g12a.h -+++ b/drivers/clk/meson/g12a.h -@@ -69,6 +69,7 @@ - #define HHI_VDEC4_CLK_CNTL 0x1EC - #define HHI_HDCP22_CLK_CNTL 0x1F0 - #define HHI_VAPBCLK_CNTL 0x1F4 -+#define HHI_SYS_CPUB_CLK_CNTL 0x208 - #define HHI_VPU_CLKB_CNTL 0x20C - #define HHI_GEN_CLK_CNTL 0x228 - #define HHI_VDIN_MEAS_CLK_CNTL 0x250 -@@ -102,6 +103,13 @@ - #define HHI_HDMI_PLL_CNTL5 0x334 - #define HHI_HDMI_PLL_CNTL6 0x338 - #define HHI_SPICC_CLK_CNTL 0x3dc -+#define HHI_SYS1_PLL_CNTL0 0x380 -+#define HHI_SYS1_PLL_CNTL1 0x384 -+#define HHI_SYS1_PLL_CNTL2 0x388 -+#define HHI_SYS1_PLL_CNTL3 0x38c -+#define HHI_SYS1_PLL_CNTL4 0x390 -+#define HHI_SYS1_PLL_CNTL5 0x394 -+#define HHI_SYS1_PLL_CNTL6 0x398 - - /* - * CLKID index values -@@ -196,8 +204,18 @@ - #define CLKID_VDEC_HEVCF_SEL 208 - #define CLKID_VDEC_HEVCF_DIV 209 - #define CLKID_TS_DIV 211 -+#define CLKID_SYS1_PLL_DCO 213 -+#define CLKID_SYS1_PLL 214 -+#define CLKID_CPUB_CLK_DYN0_SEL 215 -+#define CLKID_CPUB_CLK_DYN0_DIV 216 -+#define CLKID_CPUB_CLK_DYN0 217 -+#define CLKID_CPUB_CLK_DYN1_SEL 218 -+#define CLKID_CPUB_CLK_DYN1_DIV 219 -+#define CLKID_CPUB_CLK_DYN1 220 -+#define CLKID_CPUB_CLK_DYN 221 -+#define CLKID_CPUB_CLK 222 - --#define NR_CLKS 213 -+#define NR_CLKS 223 - - /* include the CLKIDs that have been made part of the DT binding */ - #include - -From a60b44654f9a38216f263140703beffcb22ef096 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 14 Mar 2019 15:58:19 +0100 -Subject: [PATCH 142/249] FROMLIST: clk: meson: g12a: mark fclk_div3 as - critical - -On Amlogic Meson G12b platform, the fclk_div3 seems to be necessary for -the system to operate correctly. - -Disabling it cause the entire system to freeze, including peripherals. - -This patch patch marks this clock as critical, fixing boot on G12b platforms. - -Signed-off-by: Neil Armstrong ---- - drivers/clk/meson/g12a.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c -index bbd67e9be3ddc..268e8a5cfbd62 100644 ---- a/drivers/clk/meson/g12a.c -+++ b/drivers/clk/meson/g12a.c -@@ -1060,6 +1060,16 @@ static struct clk_regmap g12a_fclk_div3 = { - .ops = &clk_regmap_gate_ops, - .parent_names = (const char *[]){ "fclk_div3_div" }, - .num_parents = 1, -+ /* -+ * This clock is used by the resident firmware and is required -+ * by the platform to operate correctly. -+ * Until the following condition are met, we need this clock to -+ * be marked as critical: -+ * a) Mark the clock used by a firmware resource, if possible -+ * b) CCF has a clock hand-off mechanism to make the sure the -+ * clock stays on until the proper driver comes along -+ */ -+ .flags = CLK_IS_CRITICAL, - }, - }; - - -From d4ac66449d518261daf0d2eb970a956812199d71 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 14 Mar 2019 10:05:19 +0100 -Subject: [PATCH 143/249] FROMLIST: dt-bindings: arm: amlogic: add G12B - bindings - -Add compatible for the Amlogic G12B SoC, sharing most of the -features and architecture with the G12A SoC. - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring ---- - Documentation/devicetree/bindings/arm/amlogic.txt | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt -index 061f7b98a07f1..94bbcc646e105 100644 ---- a/Documentation/devicetree/bindings/arm/amlogic.txt -+++ b/Documentation/devicetree/bindings/arm/amlogic.txt -@@ -61,6 +61,10 @@ Boards with the Amlogic Meson G12A S905D2 SoC shall have the following propertie - Required root node property: - compatible: "amlogic,g12a"; - -+Boards with the Amlogic Meson G12B S922X SoC shall have the following properties: -+ Required root node property: -+ compatible: "amlogic,g12b"; -+ - Board compatible values (alphabetically, grouped by SoC): - - - "geniatech,atv1200" (Meson6) - -From ccc06c35562d484c711ea9a203588e67b89668d0 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 14 Mar 2019 10:22:07 +0100 -Subject: [PATCH 144/249] FROMLIST: dt-bindings: arm: amlogic: add Odroid-N2 - binding - -Add compatible for the Amlogic G12B (S922X) SoC based Odroid-N2 SBC -from HardKernel. - -Signed-off-by: Neil Armstrong -Reviewed-by: Rob Herring ---- - Documentation/devicetree/bindings/arm/amlogic.txt | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt -index 94bbcc646e105..eff41128268eb 100644 ---- a/Documentation/devicetree/bindings/arm/amlogic.txt -+++ b/Documentation/devicetree/bindings/arm/amlogic.txt -@@ -116,6 +116,8 @@ Board compatible values (alphabetically, grouped by SoC): - - "amediatech,x96-max" (Meson g12a s905x2) - - "seirobotics,sei510" (Meson g12a s905x2) - -+ - "hardkernel,odroid-n2" (Meson g12b s922x) -+ - Amlogic Meson Firmware registers Interface - ------------------------------------------ - - -From f9913b0420698dbda91f69adb90085c967601081 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 14 Mar 2019 10:21:12 +0100 -Subject: [PATCH 145/249] FROMLIST: arm64: dts: meson: Add minimal support for - Odroid-N2 - -This patch adds basic support for : -- Amlogic G12B, which is very similar to G12A -- The HardKernel Odroid-N2 based on the S922X SoC - -The Amlogic G12B SoC is very similar with the G12A SoC, sharing -most of the features and architecture, but with these differences : -- The first CPU cluster only has 2xCortex-A53 instead of 4 -- G12B has a second cluster of 4xCortex-A73 -- Both cluster can achieve 2GHz instead of 1,8GHz for G12A -- CPU Clock architecture is difference, thus needing a different - compatible to handle this slight difference -- Supports a MIPI CSI input -- Embeds a Mali-G52 instead of a Mali-G31, but integration is the same - -Actual support is done in the same way as for the GXM support, including -the G12A dtsi and redefining the CPU clusters. -Unlike GXM, the first cluster is different, thus needing to remove -the last 2 cpu nodes of the first cluster. - -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/Makefile | 1 + - .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 185 ++++++++++++++++++ - arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 82 ++++++++ - 3 files changed, 268 insertions(+) - create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts - create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b.dtsi - -diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile -index e129c03ced140..07b861fe5fa5f 100644 ---- a/arch/arm64/boot/dts/amlogic/Makefile -+++ b/arch/arm64/boot/dts/amlogic/Makefile -@@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb -+dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-odroidc2.dtb -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts -new file mode 100644 -index 0000000000000..0541fe0bbaea9 ---- /dev/null -+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2019 BayLibre, SAS -+ * Author: Neil Armstrong -+ */ -+ -+/dts-v1/; -+ -+#include "meson-g12b.dtsi" -+#include -+#include -+ -+/ { -+ compatible = "hardkernel,odroid-n2", "amlogic,g12b"; -+ model = "Hardkernel ODROID-N2"; -+ -+ aliases { -+ serial0 = &uart_AO; -+ }; -+ -+ chosen { -+ stdout-path = "serial0:115200n8"; -+ }; -+ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x0 0x0 0x40000000>; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ blue { -+ label = "n2:blue"; -+ gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; -+ linux,default-trigger = "heartbeat"; -+ }; -+ }; -+ -+ main_12v: regulator-main_12v { -+ compatible = "regulator-fixed"; -+ regulator-name = "12V"; -+ regulator-min-microvolt = <12000000>; -+ regulator-max-microvolt = <12000000>; -+ regulator-always-on; -+ }; -+ -+ vcc_5v: regulator-vcc_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ }; -+ -+ vcc_1v8: regulator-vcc_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ -+ vcc_3v3: regulator-vcc_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ /* FIXME: actually controlled by VDDCPU_B_EN */ -+ }; -+ -+ hub_5v: regulator-hub_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "HUB_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&vcc_5v>; -+ -+ gpio = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ }; -+ -+ usb_pwr_en: regulator-usb_pwr_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "USB_PWR_EN"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&hub_5v>; -+ -+ gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ }; -+ -+ vddao_1v8: regulator-vddao_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ -+ vddao_3v3: regulator-vddao_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&main_12v>; -+ regulator-always-on; -+ }; -+ -+ hdmi-connector { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi_connector_in: endpoint { -+ remote-endpoint = <&hdmi_tx_tmds_out>; -+ }; -+ }; -+ }; -+}; -+ -+&cec_AO { -+ pinctrl-0 = <&cec_ao_a_h_pins>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cecb_AO { -+ pinctrl-0 = <&cec_ao_b_h_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&gpio { -+ /* -+ * WARNING: The USB Hub on the Odroid-N2 needs a reset signal -+ * to be turned high in order to be detected by the USB Controller -+ * This signal should be handled by a USB specific power sequence -+ * in order to reset the Hub when USB bus is powered down. -+ */ -+ usb-hub { -+ gpio-hog; -+ gpios = ; -+ output-high; -+ line-name = "usb-hub-reset"; -+ }; -+}; -+ -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -+ pinctrl-names = "default"; -+ hdmi-supply = <&vcc_5v>; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ -+&uart_AO { -+ status = "okay"; -+ pinctrl-0 = <&uart_ao_a_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&usb { -+ status = "okay"; -+}; -+ -+&usb2_phy0 { -+ phy-supply = <&usb_pwr_en>; -+}; -+ -+&usb2_phy1 { -+ phy-supply = <&vcc_5v>; -+}; -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi -new file mode 100644 -index 0000000000000..0359539ba8840 ---- /dev/null -+++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi -@@ -0,0 +1,82 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2019 BayLibre, SAS -+ * Author: Neil Armstrong -+ */ -+ -+#include "meson-g12a.dtsi" -+ -+/ { -+ compatible = "amlogic,g12b"; -+ -+ cpus { -+ cpu-map { -+ cluster0 { -+ core0 { -+ cpu = <&cpu0>; -+ }; -+ -+ core1 { -+ cpu = <&cpu1>; -+ }; -+ }; -+ -+ cluster1 { -+ core0 { -+ cpu = <&cpu100>; -+ }; -+ -+ core1 { -+ cpu = <&cpu101>; -+ }; -+ -+ core2 { -+ cpu = <&cpu102>; -+ }; -+ -+ core3 { -+ cpu = <&cpu103>; -+ }; -+ }; -+ }; -+ -+ /delete-node/ cpu@2; -+ /delete-node/ cpu@3; -+ -+ cpu100: cpu@100 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a73", "arm,armv8"; -+ reg = <0x0 0x100>; -+ enable-method = "psci"; -+ next-level-cache = <&l2>; -+ }; -+ -+ cpu101: cpu@101 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a73", "arm,armv8"; -+ reg = <0x0 0x101>; -+ enable-method = "psci"; -+ next-level-cache = <&l2>; -+ }; -+ -+ cpu102: cpu@102 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a73", "arm,armv8"; -+ reg = <0x0 0x102>; -+ enable-method = "psci"; -+ next-level-cache = <&l2>; -+ }; -+ -+ cpu103: cpu@103 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a73", "arm,armv8"; -+ reg = <0x0 0x103>; -+ enable-method = "psci"; -+ next-level-cache = <&l2>; -+ }; -+ }; -+}; -+ -+&clkc { -+ compatible = "amlogic,g12b-clkc"; -+}; - -From 2a1175fe774426d5303821b1c2f3200a59b02f9c Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 12 Apr 2019 11:23:37 +0200 -Subject: [PATCH 146/249] FROMLIST: arm64: dts: meson-g12a: Add PWM nodes - -This adds the EE and AO PWM nodes and the possible pinctrl settings. - -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 179 ++++++++++++++++++++ - 1 file changed, 179 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 2ab39f39f679f..4f4355322673f 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -260,6 +260,94 @@ - }; - }; - -+ pwm_a_pins: pwm-a { -+ mux { -+ groups = "pwm_a"; -+ function = "pwm_a"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_b_x7_pins: pwm-b-x7 { -+ mux { -+ groups = "pwm_b_x7"; -+ function = "pwm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_b_x19_pins: pwm-b-x19 { -+ mux { -+ groups = "pwm_b_x19"; -+ function = "pwm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_c_c_pins: pwm-c-c { -+ mux { -+ groups = "pwm_c_c"; -+ function = "pwm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_c_x5_pins: pwm-c-x5 { -+ mux { -+ groups = "pwm_c_x5"; -+ function = "pwm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_c_x8_pins: pwm-c-x8 { -+ mux { -+ groups = "pwm_c_x8"; -+ function = "pwm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_d_x3_pins: pwm-d-x3 { -+ mux { -+ groups = "pwm_d_x3"; -+ function = "pwm_d"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_d_x6_pins: pwm-d-x6 { -+ mux { -+ groups = "pwm_d_x6"; -+ function = "pwm_d"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_e_pins: pwm-e { -+ mux { -+ groups = "pwm_e"; -+ function = "pwm_e"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_f_x_pins: pwm-f-x { -+ mux { -+ groups = "pwm_f_x"; -+ function = "pwm_f"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_f_h_pins: pwm-f-h { -+ mux { -+ groups = "pwm_f_h"; -+ function = "pwm_f"; -+ bias-disable; -+ }; -+ }; -+ - uart_a_pins: uart-a { - mux { - groups = "uart_a_tx", -@@ -508,6 +596,62 @@ - bias-disable; - }; - }; -+ -+ pwm_ao_a_pins: pwm-ao-a { -+ mux { -+ groups = "pwm_ao_a"; -+ function = "pwm_ao_a"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_ao_b_pins: pwm-ao-b { -+ mux { -+ groups = "pwm_ao_b"; -+ function = "pwm_ao_b"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_ao_c_4_pins: pwm-ao-c-4 { -+ mux { -+ groups = "pwm_ao_c_4"; -+ function = "pwm_ao_c"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_ao_c_6_pins: pwm-ao-c-6 { -+ mux { -+ groups = "pwm_ao_c_6"; -+ function = "pwm_ao_c"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_ao_d_5_pins: pwm-ao-d-5 { -+ mux { -+ groups = "pwm_ao_d_5"; -+ function = "pwm_ao_d"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_ao_d_10_pins: pwm-ao-d-10 { -+ mux { -+ groups = "pwm_ao_d_10"; -+ function = "pwm_ao_d"; -+ bias-disable; -+ }; -+ }; -+ -+ pwm_ao_d_e_pins: pwm-ao-d-e { -+ mux { -+ groups = "pwm_ao_d_e"; -+ function = "pwm_ao_d"; -+ bias-disable; -+ }; -+ }; - }; - }; - -@@ -535,6 +679,13 @@ - status = "disabled"; - }; - -+ pwm_AO_cd: pwm@2000 { -+ compatible = "amlogic,meson-g12a-ao-pwm-cd"; -+ reg = <0x0 0x2000 0x0 0x20>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ - uart_AO: serial@3000 { - compatible = "amlogic,meson-gx-uart", - "amlogic,meson-ao-uart"; -@@ -555,6 +706,13 @@ - status = "disabled"; - }; - -+ pwm_AO_ab: pwm@7000 { -+ compatible = "amlogic,meson-g12a-ao-pwm-ab"; -+ reg = <0x0 0x7000 0x0 0x20>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ - saradc: adc@9000 { - compatible = "amlogic,meson-g12a-saradc", - "amlogic,meson-saradc"; -@@ -623,6 +781,27 @@ - #reset-cells = <1>; - }; - -+ pwm_ef: pwm@19000 { -+ compatible = "amlogic,meson-g12a-ee-pwm"; -+ reg = <0x0 0x19000 0x0 0x20>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ -+ pwm_cd: pwm@1a000 { -+ compatible = "amlogic,meson-g12a-ee-pwm"; -+ reg = <0x0 0x1a000 0x0 0x20>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ -+ pwm_ab: pwm@1b000 { -+ compatible = "amlogic,meson-g12a-ee-pwm"; -+ reg = <0x0 0x1b000 0x0 0x20>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ - clk_msr: clock-measure@18000 { - compatible = "amlogic,meson-g12a-clk-measure"; - reg = <0x0 0x18000 0x0 0x10>; - -From afa93eb97486e10f45d09dc5d0af8b2c8b3d8c31 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 4 Feb 2019 15:45:34 +0100 -Subject: [PATCH 147/249] FROMLIST: arm64: dts: meson-g12a: Add IR nodes - -Amlogic G12A SoCs uses the exact same IR decoder as previous -families, add the IR node and the pintctrl setting. - -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 4f4355322673f..ee713693be777 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -649,6 +649,13 @@ - mux { - groups = "pwm_ao_d_e"; - function = "pwm_ao_d"; -+ }; -+ }; -+ -+ remote_input_ao_pins: remote-input-ao { -+ mux { -+ groups = "remote_ao_input"; -+ function = "remote_ao_input"; - bias-disable; - }; - }; -@@ -713,6 +720,13 @@ - status = "disabled"; - }; - -+ ir: ir@8000 { -+ compatible = "amlogic,meson-gxbb-ir"; -+ reg = <0x0 0x8000 0x0 0x20>; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ - saradc: adc@9000 { - compatible = "amlogic,meson-g12a-saradc", - "amlogic,meson-saradc"; - -From 2be6ee97eda8f4fca30f02db1e222434e1fbff09 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 11 Apr 2019 16:02:16 +0200 -Subject: [PATCH 148/249] FROMLIST: arm64: dts: meson-g12a-x96-max: enable IR - decoder - -Add support for the IR decoder input on the X96 Max board. - -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index b3d913f28f121..5cdc263b03e67 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -144,6 +144,12 @@ - }; - }; - -+&ir { -+ status = "okay"; -+ pinctrl-0 = <&remote_input_ao_pins>; -+ pinctrl-names = "default"; -+}; -+ - &uart_A { - status = "okay"; - pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; - -From 4ed272775f97e7a842530561f63336a2cbeb6904 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 11 Apr 2019 16:03:03 +0200 -Subject: [PATCH 149/249] FROMLIST: arm64: dts: meson-g12a-u200: enable IR - decoder - -Add support for the IR decoder input on the U200 Reference Design board. - -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index f1cb02567a130..c2221eb4549e2 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -165,6 +165,12 @@ - }; - }; - -+&ir { -+ status = "okay"; -+ pinctrl-0 = <&remote_input_ao_pins>; -+ pinctrl-names = "default"; -+}; -+ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From 7c0cd2a31134d9a93749c044c8ff4451ccbbbe6c Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 25 Apr 2019 15:20:10 +0000 -Subject: [PATCH 150/249] FROMLIST: drm/meson: Add support for XBGR8888 & - ABGR8888 formats - -Add missing XBGR8888 & ABGR8888 formats variants from the primary plane. - -Fixes: bbbe775ec5b5 ("drm: Add support for Amlogic Meson Graphic Controller") -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190429075238.7884-1-narmstrong@baylibre.com ---- - drivers/gpu/drm/meson/meson_plane.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c -index bf8f1fab63aa9..b8f6b08a89a67 100644 ---- a/drivers/gpu/drm/meson/meson_plane.c -+++ b/drivers/gpu/drm/meson/meson_plane.c -@@ -165,6 +165,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | - OSD_COLOR_MATRIX_32_ARGB; - break; -+ case DRM_FORMAT_XBGR8888: -+ /* For XRGB, replace the pixel's alpha by 0xFF */ -+ writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN, -+ priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); -+ priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | -+ OSD_COLOR_MATRIX_32_ABGR; -+ break; - case DRM_FORMAT_ARGB8888: - /* For ARGB, use the pixel's alpha */ - writel_bits_relaxed(OSD_REPLACE_EN, 0, -@@ -172,6 +179,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | - OSD_COLOR_MATRIX_32_ARGB; - break; -+ case DRM_FORMAT_ABGR8888: -+ /* For ARGB, use the pixel's alpha */ -+ writel_bits_relaxed(OSD_REPLACE_EN, 0, -+ priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); -+ priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | -+ OSD_COLOR_MATRIX_32_ABGR; -+ break; - case DRM_FORMAT_RGB888: - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | - OSD_COLOR_MATRIX_24_RGB; -@@ -356,7 +370,9 @@ static const struct drm_plane_funcs meson_plane_funcs = { - - static const uint32_t supported_drm_formats[] = { - DRM_FORMAT_ARGB8888, -+ DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB8888, -+ DRM_FORMAT_XBGR8888, - DRM_FORMAT_RGB888, - DRM_FORMAT_RGB565, - }; - -From 601b2ce79fa9a0a8e2e7de739a49e5f156648395 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 26 Apr 2019 10:13:23 +0000 -Subject: [PATCH 151/249] FROMLIST: drm/meson: Add zpos immutable property to - planes - -Add immutable zpos property to primary and overlay planes to specify -the current fixed zpos position. - -Fixes: f9a2348196d1 ("drm/meson: Support Overlay plane for video rendering") -Signed-off-by: Neil Armstrong -Link: https://lkml.kernel.org/r/20190429075247.7946-1-narmstrong@baylibre.com ---- - drivers/gpu/drm/meson/meson_overlay.c | 3 +++ - drivers/gpu/drm/meson/meson_plane.c | 3 +++ - 2 files changed, 6 insertions(+) - -diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c -index bdbf925ff3e85..dceb3df5e6526 100644 ---- a/drivers/gpu/drm/meson/meson_overlay.c -+++ b/drivers/gpu/drm/meson/meson_overlay.c -@@ -578,6 +578,9 @@ int meson_overlay_create(struct meson_drm *priv) - - drm_plane_helper_add(plane, &meson_overlay_helper_funcs); - -+ /* For now, VD Overlay plane is always on the back */ -+ drm_plane_create_zpos_immutable_property(plane, 0); -+ - priv->overlay_plane = plane; - - DRM_DEBUG_DRIVER("\n"); -diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c -index b8f6b08a89a67..2f7f4dfce45be 100644 ---- a/drivers/gpu/drm/meson/meson_plane.c -+++ b/drivers/gpu/drm/meson/meson_plane.c -@@ -399,6 +399,9 @@ int meson_plane_create(struct meson_drm *priv) - - drm_plane_helper_add(plane, &meson_plane_helper_funcs); - -+ /* For now, OSD Primary plane is always on the front */ -+ drm_plane_create_zpos_immutable_property(plane, 1); -+ - priv->primary_plane = plane; - - return 0; - -From d297597f9a3a1f89d4db70383a105c43e55983b8 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 29 Apr 2019 12:23:25 +0200 -Subject: [PATCH 152/249] FROMLIST: drm/meson: imply dw-hdmi i2s audio for - meson hdmi - -Imply the i2s part of the Synopsys HDMI driver for Amlogic SoCs. -This will enable the i2s part by default when meson hdmi driver -is enable but let platforms not supported by the audio subsystem -disable it if necessary. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/meson/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig -index c28b69f485555..a480e4a80beab 100644 ---- a/drivers/gpu/drm/meson/Kconfig -+++ b/drivers/gpu/drm/meson/Kconfig -@@ -14,3 +14,4 @@ config DRM_MESON_DW_HDMI - depends on DRM_MESON - default y if DRM_MESON - select DRM_DW_HDMI -+ imply DRM_DW_HDMI_I2S_AUDIO - -From 57c04b9c5bec28d82b26f918a1c77822ed55081f Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 11:16:09 +0200 -Subject: [PATCH 153/249] FROMLIST: arm64: dts: meson: g12a: add mmc nodes - -Add port B (sdcard) and port C (eMMC) pinctrl and controllers nodes to -the g12a DT. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 124 ++++++++++++++++++++ - 1 file changed, 124 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index ee713693be777..b5f145a5a08dd 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -243,6 +243,48 @@ - }; - }; - -+ emmc_pins: emmc { -+ mux-0 { -+ groups = "emmc_nand_d0", -+ "emmc_nand_d1", -+ "emmc_nand_d2", -+ "emmc_nand_d3", -+ "emmc_nand_d4", -+ "emmc_nand_d5", -+ "emmc_nand_d6", -+ "emmc_nand_d7", -+ "emmc_cmd"; -+ function = "emmc"; -+ bias-pull-up; -+ drive-strength-microamp = <4000>; -+ }; -+ -+ mux-1 { -+ groups = "emmc_clk"; -+ function = "emmc"; -+ bias-disable; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ -+ emmc_ds_pins: emmc-ds { -+ mux { -+ groups = "emmc_nand_ds"; -+ function = "emmc"; -+ bias-pull-down; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ -+ emmc_clk_gate_pins: emmc_clk_gate { -+ mux { -+ groups = "BOOT_8"; -+ function = "gpio_periphs"; -+ bias-pull-down; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ - hdmitx_ddc_pins: hdmitx_ddc { - mux { - groups = "hdmitx_sda", -@@ -348,6 +390,64 @@ - }; - }; - -+ sdcard_c_pins: sdcard_c { -+ mux-0 { -+ groups = "sdcard_d0_c", -+ "sdcard_d1_c", -+ "sdcard_d2_c", -+ "sdcard_d3_c", -+ "sdcard_cmd_c"; -+ function = "sdcard"; -+ bias-pull-up; -+ drive-strength-microamp = <4000>; -+ }; -+ -+ mux-1 { -+ groups = "sdcard_clk_c"; -+ function = "sdcard"; -+ bias-disable; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ -+ sdcard_clk_gate_c_pins: sdcard_clk_gate_c { -+ mux { -+ groups = "GPIOC_4"; -+ function = "gpio_periphs"; -+ bias-pull-down; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ -+ sdcard_z_pins: sdcard_z { -+ mux-0 { -+ groups = "sdcard_d0_z", -+ "sdcard_d1_z", -+ "sdcard_d2_z", -+ "sdcard_d3_z", -+ "sdcard_cmd_z"; -+ function = "sdcard"; -+ bias-pull-up; -+ drive-strength-microamp = <4000>; -+ }; -+ -+ mux-1 { -+ groups = "sdcard_clk_z"; -+ function = "sdcard"; -+ bias-disable; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ -+ sdcard_clk_gate_z_pins: sdcard_clk_gate_z { -+ mux { -+ groups = "GPIOZ_6"; -+ function = "gpio_periphs"; -+ bias-pull-down; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ - uart_a_pins: uart-a { - mux { - groups = "uart_a_tx", -@@ -849,6 +949,30 @@ - }; - }; - -+ sd_emmc_b: sd@ffe05000 { -+ compatible = "amlogic,meson-axg-mmc"; -+ reg = <0x0 0xffe05000 0x0 0x800>; -+ interrupts = ; -+ status = "disabled"; -+ clocks = <&clkc CLKID_SD_EMMC_B>, -+ <&clkc CLKID_SD_EMMC_B_CLK0>, -+ <&clkc CLKID_FCLK_DIV2>; -+ clock-names = "core", "clkin0", "clkin1"; -+ resets = <&reset RESET_SD_EMMC_B>; -+ }; -+ -+ sd_emmc_c: mmc@ffe07000 { -+ compatible = "amlogic,meson-axg-mmc"; -+ reg = <0x0 0xffe07000 0x0 0x800>; -+ interrupts = ; -+ status = "disabled"; -+ clocks = <&clkc CLKID_SD_EMMC_C>, -+ <&clkc CLKID_SD_EMMC_C_CLK0>, -+ <&clkc CLKID_FCLK_DIV2>; -+ clock-names = "core", "clkin0", "clkin1"; -+ resets = <&reset RESET_SD_EMMC_C>; -+ }; -+ - usb: usb@ffe09000 { - status = "disabled"; - compatible = "amlogic,meson-g12a-usb-ctrl"; - -From 66a03968735669560fb291f1097b610efda8afe2 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 11:16:10 +0200 -Subject: [PATCH 154/249] FROMLIST: arm64: dts: meson: u200: add sd and emmc - -Enable eMMC and SDCard on the g12a u200 board - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12a-u200.dts | 42 +++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index c2221eb4549e2..2b6c2cd41aa68 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -32,6 +32,11 @@ - }; - }; - -+ emmc_pwrseq: emmc-pwrseq { -+ compatible = "mmc-pwrseq-emmc"; -+ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; -+ }; -+ - hdmi-connector { - compatible = "hdmi-connector"; - type = "a"; -@@ -171,6 +176,43 @@ - pinctrl-names = "default"; - }; - -+/* SD card */ -+&sd_emmc_b { -+ status = "okay"; -+ pinctrl-0 = <&sdcard_c_pins>; -+ pinctrl-1 = <&sdcard_clk_gate_c_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ max-frequency = <50000000>; -+ disable-wp; -+ -+ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddao_3v3>; -+}; -+ -+/* eMMC */ -+&sd_emmc_c { -+ status = "okay"; -+ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; -+ pinctrl-1 = <&emmc_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ max-frequency = <200000000>; -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&emmc_pwrseq>; -+ vmmc-supply = <&vcc_3v3>; -+ vqmmc-supply = <&flash_1v8>; -+}; -+ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From 8f465d7c9306498f7874b1f1ba61944ba18aaa19 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 11:16:11 +0200 -Subject: [PATCH 155/249] FROMLIST: arm64: dts: meson: sei510: add sd and emmc - -Enable eMMC and SDCard on the g12a sei510 board - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12a-sei510.dts | 42 +++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 4a785b17c1af7..4376d9378908c 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -46,6 +46,11 @@ - }; - }; - -+ emmc_pwrseq: emmc-pwrseq { -+ compatible = "mmc-pwrseq-emmc"; -+ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; -+ }; -+ - hdmi-connector { - compatible = "hdmi-connector"; - type = "a"; -@@ -168,6 +173,43 @@ - vref-supply = <&vddio_ao1v8>; - }; - -+/* SD card */ -+&sd_emmc_b { -+ status = "okay"; -+ pinctrl-0 = <&sdcard_c_pins>; -+ pinctrl-1 = <&sdcard_clk_gate_c_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ max-frequency = <50000000>; -+ disable-wp; -+ -+ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddao_3v3>; -+}; -+ -+/* eMMC */ -+&sd_emmc_c { -+ status = "okay"; -+ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; -+ pinctrl-1 = <&emmc_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ max-frequency = <200000000>; -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&emmc_pwrseq>; -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&emmc_1v8>; -+}; -+ - &uart_A { - status = "okay"; - pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; - -From 885394afbaed6b22aa985b96289821f8ee3cfbea Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 11:45:37 +0200 -Subject: [PATCH 156/249] FROMLIST: arm64: dts: meson: g12a: set uart_ao clocks - -Now that the AO clock controller is available, make the uarts of the -always-on domain claim the appropriate peripheral clock. - -Signed-off-by: Jerome Brunet -Reviewed-by: Neil Armstrong -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index b5f145a5a08dd..7b95d91d08255 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -798,7 +798,7 @@ - "amlogic,meson-ao-uart"; - reg = <0x0 0x3000 0x0 0x18>; - interrupts = ; -- clocks = <&xtal>, <&xtal>, <&xtal>; -+ clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; -@@ -808,7 +808,7 @@ - "amlogic,meson-ao-uart"; - reg = <0x0 0x4000 0x0 0x18>; - interrupts = ; -- clocks = <&xtal>, <&xtal>, <&xtal>; -+ clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; - status = "disabled"; - }; - -From 8c51017d1eb954dddf0ef151ba3ede002785ba0f Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Tue, 14 May 2019 12:12:35 +0200 -Subject: [PATCH 157/249] FROMLIST: arm64: dts: meson: g12a: add i2c nodes - -Add pinctrl and nodes for i2c support on amlogic g12a - -Signed-off-by: Guillaume La Roque -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 268 ++++++++++++++++++++ - 1 file changed, 268 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 7b95d91d08255..05fcaf73203bf 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -302,6 +302,188 @@ - }; - }; - -+ -+ i2c0_sda_c_pins: i2c0-sda-c { -+ mux { -+ groups = "i2c0_sda_c"; -+ function = "i2c0"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ -+ }; -+ }; -+ -+ i2c0_sck_c_pins: i2c0-sck-c { -+ mux { -+ groups = "i2c0_sck_c"; -+ function = "i2c0"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c0_sda_z0_pins: i2c0-sda-z0 { -+ mux { -+ groups = "i2c0_sda_z0"; -+ function = "i2c0"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c0_sck_z1_pins: i2c0-sck-z1 { -+ mux { -+ groups = "i2c0_sck_z1"; -+ function = "i2c0"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c0_sda_z7_pins: i2c0-sda-z7 { -+ mux { -+ groups = "i2c0_sda_z7"; -+ function = "i2c0"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c0_sda_z8_pins: i2c0-sda-z8 { -+ mux { -+ groups = "i2c0_sda_z8"; -+ function = "i2c0"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c1_sda_x_pins: i2c1-sda-x { -+ mux { -+ groups = "i2c1_sda_x"; -+ function = "i2c1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c1_sck_x_pins: i2c1-sck-x { -+ mux { -+ groups = "i2c1_sck_x"; -+ function = "i2c1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c1_sda_h2_pins: i2c1-sda-h2 { -+ mux { -+ groups = "i2c1_sda_h2"; -+ function = "i2c1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c1_sck_h3_pins: i2c1-sck-h3 { -+ mux { -+ groups = "i2c1_sck_h3"; -+ function = "i2c1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c1_sda_h6_pins: i2c1-sda-h6 { -+ mux { -+ groups = "i2c1_sda_h6"; -+ function = "i2c1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c1_sck_h7_pins: i2c1-sck-h7 { -+ mux { -+ groups = "i2c1_sck_h7"; -+ function = "i2c1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c2_sda_x_pins: i2c2-sda-x { -+ mux { -+ groups = "i2c2_sda_x"; -+ function = "i2c2"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c2_sck_x_pins: i2c2-sck-x { -+ mux { -+ groups = "i2c2_sck_x"; -+ function = "i2c2"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c2_sda_z_pins: i2c2-sda-z { -+ mux { -+ groups = "i2c2_sda_z"; -+ function = "i2c2"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c2_sck_z_pins: i2c2-sck-z { -+ mux { -+ groups = "i2c2_sck_z"; -+ function = "i2c2"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c3_sda_h_pins: i2c3-sda-h { -+ mux { -+ groups = "i2c3_sda_h"; -+ function = "i2c3"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c3_sck_h_pins: i2c3-sck-h { -+ mux { -+ groups = "i2c3_sck_h"; -+ function = "i2c3"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c3_sda_a_pins: i2c3-sda-a { -+ mux { -+ groups = "i2c3_sda_a"; -+ function = "i2c3"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c3_sck_a_pins: i2c3-sck-a { -+ mux { -+ groups = "i2c3_sck_a"; -+ function = "i2c3"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ - pwm_a_pins: pwm-a { - mux { - groups = "pwm_a"; -@@ -679,6 +861,42 @@ - gpio-ranges = <&ao_pinctrl 0 0 15>; - }; - -+ i2c_ao_sck_pins: i2c_ao_sck_pins { -+ mux { -+ groups = "i2c_ao_sck"; -+ function = "i2c_ao"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c_ao_sda_pins: i2c_ao_sda { -+ mux { -+ groups = "i2c_ao_sda"; -+ function = "i2c_ao"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c_ao_sck_e_pins: i2c_ao_sck_e { -+ mux { -+ groups = "i2c_ao_sck_e"; -+ function = "i2c_ao"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ i2c_ao_sda_e_pins: i2c_ao_sda_e { -+ mux { -+ groups = "i2c_ao_sda_e"; -+ function = "i2c_ao"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ - uart_ao_a_pins: uart-a-ao { - mux { - groups = "uart_ao_a_tx", -@@ -813,6 +1031,16 @@ - status = "disabled"; - }; - -+ i2c_AO: i2c@5000 { -+ compatible = "amlogic,meson-axg-i2c"; -+ status = "disabled"; -+ reg = <0x0 0x05000 0x0 0x20>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&clkc CLKID_I2C>; -+ }; -+ - pwm_AO_ab: pwm@7000 { - compatible = "amlogic,meson-g12a-ao-pwm-ab"; - reg = <0x0 0x7000 0x0 0x20>; -@@ -916,6 +1144,46 @@ - status = "disabled"; - }; - -+ i2c3: i2c@1c000 { -+ compatible = "amlogic,meson-axg-i2c"; -+ status = "disabled"; -+ reg = <0x0 0x1c000 0x0 0x20>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&clkc CLKID_I2C>; -+ }; -+ -+ i2c2: i2c@1d000 { -+ compatible = "amlogic,meson-axg-i2c"; -+ status = "disabled"; -+ reg = <0x0 0x1d000 0x0 0x20>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&clkc CLKID_I2C>; -+ }; -+ -+ i2c1: i2c@1e000 { -+ compatible = "amlogic,meson-axg-i2c"; -+ status = "disabled"; -+ reg = <0x0 0x1e000 0x0 0x20>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&clkc CLKID_I2C>; -+ }; -+ -+ i2c0: i2c@1f000 { -+ compatible = "amlogic,meson-axg-i2c"; -+ status = "disabled"; -+ reg = <0x0 0x1f000 0x0 0x20>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&clkc CLKID_I2C>; -+ }; -+ - clk_msr: clock-measure@18000 { - compatible = "amlogic,meson-g12a-clk-measure"; - reg = <0x0 0x18000 0x0 0x10>; - -From 00515ec7e1bbd92e715e46b8582c50045b3b2d91 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 12:12:36 +0200 -Subject: [PATCH 158/249] FROMLIST: arm64: dts: meson: u200: enable i2c busses - -Add the 3 i2c busses present on the u200 reference design. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12a-u200.dts | 21 +++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index 2b6c2cd41aa68..8551fbd4a488c 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -176,6 +176,27 @@ - pinctrl-names = "default"; - }; - -+/* i2c Touch */ -+&i2c0 { -+ status = "okay"; -+ pinctrl-0 = <&i2c0_sda_z0_pins>, <&i2c0_sck_z1_pins>; -+ pinctrl-names = "default"; -+}; -+ -+/* i2c CM */ -+&i2c2 { -+ status = "okay"; -+ pinctrl-0 = <&i2c2_sda_z_pins>, <&i2c2_sck_z_pins>; -+ pinctrl-names = "default"; -+}; -+ -+/* i2c Audio */ -+&i2c3 { -+ status = "okay"; -+ pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>; -+ pinctrl-names = "default"; -+}; -+ - /* SD card */ - &sd_emmc_b { - status = "okay"; - -From c251d749b39eeee2b3330a9fefee0e15a61880ed Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 12:12:37 +0200 -Subject: [PATCH 159/249] FROMLIST: arm64: dts: meson: sei510: enable i2c3 - -Add the i2c bus used for RGB led controller. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 4376d9378908c..9f0b8005877ae 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -168,6 +168,12 @@ - }; - }; - -+&i2c3 { -+ status = "okay"; -+ pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>; -+ pinctrl-names = "default"; -+}; -+ - &saradc { - status = "okay"; - vref-supply = <&vddio_ao1v8>; - -From 26f252d4fcecb7af98ea4ef610a7ade7b8f6e731 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:03 +0200 -Subject: [PATCH 160/249] FROMLIST: arm64: dts: meson: g12a: add audio clock - controller - -Add the g12a clock controller dedicated to audio. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 36 +++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 05fcaf73203bf..b67bdcbc16a31 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -731,6 +731,42 @@ - }; - }; - -+ audio: bus@42000 { -+ compatible = "simple-bus"; -+ reg = <0x0 0x42000 0x0 0x2000>; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>; -+ -+ clkc_audio: clock-controller@0 { -+ status = "disabled"; -+ compatible = "amlogic,g12a-audio-clkc"; -+ reg = <0x0 0x0 0x0 0xb4>; -+ #clock-cells = <1>; -+ -+ clocks = <&clkc CLKID_AUDIO>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>, -+ <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL3>, -+ <&clkc CLKID_HIFI_PLL>, -+ <&clkc CLKID_FCLK_DIV3>, -+ <&clkc CLKID_FCLK_DIV4>, -+ <&clkc CLKID_GP0_PLL>; -+ clock-names = "pclk", -+ "mst_in0", -+ "mst_in1", -+ "mst_in2", -+ "mst_in3", -+ "mst_in4", -+ "mst_in5", -+ "mst_in6", -+ "mst_in7"; -+ -+ resets = <&reset RESET_AUDIO>; -+ }; -+ }; -+ - usb3_pcie_phy: phy@46000 { - compatible = "amlogic,g12a-usb3-pcie-phy"; - reg = <0x0 0x46000 0x0 0x2000>; - -From 43bf187e1732fac571d216f220abaf4972a3a63d Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:04 +0200 -Subject: [PATCH 161/249] FROMLIST: arm64: dts: meson: g12a: add audio memory - arbitrer - -Add the audio DDR memory arbitrer of the g12a SoC family. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index b67bdcbc16a31..668f43fad57e5 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -5,6 +5,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -765,6 +766,14 @@ - - resets = <&reset RESET_AUDIO>; - }; -+ -+ arb: reset-controller@280 { -+ status = "disabled"; -+ compatible = "amlogic,meson-axg-audio-arb"; -+ reg = <0x0 0x280 0x0 0x4>; -+ #reset-cells = <1>; -+ clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; -+ }; - }; - - usb3_pcie_phy: phy@46000 { - -From c104488a20d9a6a188b8603e02fa3810156ea263 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:05 +0200 -Subject: [PATCH 162/249] FROMLIST: arm64: dts: meson: g12a: add audio fifos - -Add the playback and capture memory interfaces of the g12a SoC family. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 67 +++++++++++++++++++++ - 1 file changed, 67 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 668f43fad57e5..7f382f59b2ef8 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - - / { -@@ -767,6 +768,72 @@ - resets = <&reset RESET_AUDIO>; - }; - -+ toddr_a: audio-controller@100 { -+ compatible = "amlogic,g12a-toddr"; -+ reg = <0x0 0x100 0x0 0x1c>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "TODDR_A"; -+ interrupts = ; -+ clocks = <&clkc_audio AUD_CLKID_TODDR_A>; -+ resets = <&arb AXG_ARB_TODDR_A>; -+ status = "disabled"; -+ }; -+ -+ toddr_b: audio-controller@140 { -+ compatible = "amlogic,g12a-toddr"; -+ reg = <0x0 0x140 0x0 0x1c>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "TODDR_B"; -+ interrupts = ; -+ clocks = <&clkc_audio AUD_CLKID_TODDR_B>; -+ resets = <&arb AXG_ARB_TODDR_B>; -+ status = "disabled"; -+ }; -+ -+ toddr_c: audio-controller@180 { -+ compatible = "amlogic,g12a-toddr"; -+ reg = <0x0 0x180 0x0 0x1c>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "TODDR_C"; -+ interrupts = ; -+ clocks = <&clkc_audio AUD_CLKID_TODDR_C>; -+ resets = <&arb AXG_ARB_TODDR_C>; -+ status = "disabled"; -+ }; -+ -+ frddr_a: audio-controller@1c0 { -+ compatible = "amlogic,g12a-frddr"; -+ reg = <0x0 0x1c0 0x0 0x1c>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "FRDDR_A"; -+ interrupts = ; -+ clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; -+ resets = <&arb AXG_ARB_FRDDR_A>; -+ status = "disabled"; -+ }; -+ -+ frddr_b: audio-controller@200 { -+ compatible = "amlogic,g12a-frddr"; -+ reg = <0x0 0x200 0x0 0x1c>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "FRDDR_B"; -+ interrupts = ; -+ clocks = <&clkc_audio AUD_CLKID_FRDDR_B>; -+ resets = <&arb AXG_ARB_FRDDR_B>; -+ status = "disabled"; -+ }; -+ -+ frddr_c: audio-controller@240 { -+ compatible = "amlogic,g12a-frddr"; -+ reg = <0x0 0x240 0x0 0x1c>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "FRDDR_C"; -+ interrupts = ; -+ clocks = <&clkc_audio AUD_CLKID_FRDDR_C>; -+ resets = <&arb AXG_ARB_FRDDR_C>; -+ status = "disabled"; -+ }; -+ - arb: reset-controller@280 { - status = "disabled"; - compatible = "amlogic,meson-axg-audio-arb"; - -From 540d0eddb18133b1ff75d9a9acadf4866584aa58 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:06 +0200 -Subject: [PATCH 163/249] FROMLIST: arm64: dts: meson: g12a: add tdm - -Add the devices and pinctrl definitions for the tdm interfaces of -the g12a SoC family. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 658 ++++++++++++++++++++ - 1 file changed, 658 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 7f382f59b2ef8..73aa3025b50a2 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -20,6 +20,39 @@ - #address-cells = <2>; - #size-cells = <2>; - -+ tdmif_a: audio-controller-0 { -+ compatible = "amlogic,axg-tdm-iface"; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "TDM_A"; -+ clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>, -+ <&clkc_audio AUD_CLKID_MST_A_SCLK>, -+ <&clkc_audio AUD_CLKID_MST_A_LRCLK>; -+ clock-names = "mclk", "sclk", "lrclk"; -+ status = "disabled"; -+ }; -+ -+ tdmif_b: audio-controller-1 { -+ compatible = "amlogic,axg-tdm-iface"; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "TDM_B"; -+ clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>, -+ <&clkc_audio AUD_CLKID_MST_B_SCLK>, -+ <&clkc_audio AUD_CLKID_MST_B_LRCLK>; -+ clock-names = "mclk", "sclk", "lrclk"; -+ status = "disabled"; -+ }; -+ -+ tdmif_c: audio-controller-2 { -+ compatible = "amlogic,axg-tdm-iface"; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "TDM_C"; -+ clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>, -+ <&clkc_audio AUD_CLKID_MST_C_SCLK>, -+ <&clkc_audio AUD_CLKID_MST_C_LRCLK>; -+ clock-names = "mclk", "sclk", "lrclk"; -+ status = "disabled"; -+ }; -+ - cpus { - #address-cells = <0x2>; - #size-cells = <0x0>; -@@ -486,6 +519,42 @@ - }; - }; - -+ mclk0_a_pins: mclk0_a { -+ mux { -+ groups = "mclk0_a"; -+ function = "mclk0"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ mclk1_a_pins: mclk1_a { -+ mux { -+ groups = "mclk1_a"; -+ function = "mclk1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ mclk1_x_pins: mclk1_x { -+ mux { -+ groups = "mclk1_x"; -+ function = "mclk1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ mclk1_z_pins: mclk1_z { -+ mux { -+ groups = "mclk1_z"; -+ function = "mclk1"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ - pwm_a_pins: pwm-a { - mux { - groups = "pwm_a"; -@@ -632,6 +701,399 @@ - }; - }; - -+ tdm_a_din0_pins: tdm-a-din0 { -+ mux { -+ groups = "tdm_a_din0"; -+ function = "tdm_a"; -+ bias-disable; -+ }; -+ }; -+ -+ -+ tdm_a_din1_pins: tdm-a-din1 { -+ mux { -+ groups = "tdm_a_din1"; -+ function = "tdm_a"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_a_dout0_pins: tdm-a-dout0 { -+ mux { -+ groups = "tdm_a_dout0"; -+ function = "tdm_a"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_a_dout1_pins: tdm-a-dout1 { -+ mux { -+ groups = "tdm_a_dout1"; -+ function = "tdm_a"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_a_fs_pins: tdm-a-fs { -+ mux { -+ groups = "tdm_a_fs"; -+ function = "tdm_a"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_a_sclk_pins: tdm-a-sclk { -+ mux { -+ groups = "tdm_a_sclk"; -+ function = "tdm_a"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_a_slv_fs_pins: tdm-a-slv-fs { -+ mux { -+ groups = "tdm_a_slv_fs"; -+ function = "tdm_a"; -+ bias-disable; -+ }; -+ }; -+ -+ -+ tdm_a_slv_sclk_pins: tdm-a-slv-sclk { -+ mux { -+ groups = "tdm_a_slv_sclk"; -+ function = "tdm_a"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_b_din0_pins: tdm-b-din0 { -+ mux { -+ groups = "tdm_b_din0"; -+ function = "tdm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_b_din1_pins: tdm-b-din1 { -+ mux { -+ groups = "tdm_b_din1"; -+ function = "tdm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_b_din2_pins: tdm-b-din2 { -+ mux { -+ groups = "tdm_b_din2"; -+ function = "tdm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_b_din3_a_pins: tdm-b-din3-a { -+ mux { -+ groups = "tdm_b_din3_a"; -+ function = "tdm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_b_din3_h_pins: tdm-b-din3-h { -+ mux { -+ groups = "tdm_b_din3_h"; -+ function = "tdm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_b_dout0_pins: tdm-b-dout0 { -+ mux { -+ groups = "tdm_b_dout0"; -+ function = "tdm_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_b_dout1_pins: tdm-b-dout1 { -+ mux { -+ groups = "tdm_b_dout1"; -+ function = "tdm_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_b_dout2_pins: tdm-b-dout2 { -+ mux { -+ groups = "tdm_b_dout2"; -+ function = "tdm_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_b_dout3_a_pins: tdm-b-dout3-a { -+ mux { -+ groups = "tdm_b_dout3_a"; -+ function = "tdm_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_b_dout3_h_pins: tdm-b-dout3-h { -+ mux { -+ groups = "tdm_b_dout3_h"; -+ function = "tdm_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_b_fs_pins: tdm-b-fs { -+ mux { -+ groups = "tdm_b_fs"; -+ function = "tdm_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_b_sclk_pins: tdm-b-sclk { -+ mux { -+ groups = "tdm_b_sclk"; -+ function = "tdm_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_b_slv_fs_pins: tdm-b-slv-fs { -+ mux { -+ groups = "tdm_b_slv_fs"; -+ function = "tdm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_b_slv_sclk_pins: tdm-b-slv-sclk { -+ mux { -+ groups = "tdm_b_slv_sclk"; -+ function = "tdm_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din0_a_pins: tdm-c-din0-a { -+ mux { -+ groups = "tdm_c_din0_a"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din0_z_pins: tdm-c-din0-z { -+ mux { -+ groups = "tdm_c_din0_z"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din1_a_pins: tdm-c-din1-a { -+ mux { -+ groups = "tdm_c_din1_a"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din1_z_pins: tdm-c-din1-z { -+ mux { -+ groups = "tdm_c_din1_z"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din2_a_pins: tdm-c-din2-a { -+ mux { -+ groups = "tdm_c_din2_a"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din2_z_pins: tdm-c-din2-z { -+ mux { -+ groups = "tdm_c_din2_z"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din3_a_pins: tdm-c-din3-a { -+ mux { -+ groups = "tdm_c_din3_a"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_din3_z_pins: tdm-c-din3-z { -+ mux { -+ groups = "tdm_c_din3_z"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_dout0_a_pins: tdm-c-dout0-a { -+ mux { -+ groups = "tdm_c_dout0_a"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_dout0_z_pins: tdm-c-dout0-z { -+ mux { -+ groups = "tdm_c_dout0_z"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_dout1_a_pins: tdm-c-dout1-a { -+ mux { -+ groups = "tdm_c_dout1_a"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_dout1_z_pins: tdm-c-dout1-z { -+ mux { -+ groups = "tdm_c_dout1_z"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_dout2_a_pins: tdm-c-dout2-a { -+ mux { -+ groups = "tdm_c_dout2_a"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_dout2_z_pins: tdm-c-dout2-z { -+ mux { -+ groups = "tdm_c_dout2_z"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_dout3_a_pins: tdm-c-dout3-a { -+ mux { -+ groups = "tdm_c_dout3_a"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_dout3_z_pins: tdm-c-dout3-z { -+ mux { -+ groups = "tdm_c_dout3_z"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_fs_a_pins: tdm-c-fs-a { -+ mux { -+ groups = "tdm_c_fs_a"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_fs_z_pins: tdm-c-fs-z { -+ mux { -+ groups = "tdm_c_fs_z"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_sclk_a_pins: tdm-c-sclk-a { -+ mux { -+ groups = "tdm_c_sclk_a"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_sclk_z_pins: tdm-c-sclk-z { -+ mux { -+ groups = "tdm_c_sclk_z"; -+ function = "tdm_c"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_c_slv_fs_a_pins: tdm-c-slv-fs-a { -+ mux { -+ groups = "tdm_c_slv_fs_a"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_slv_fs_z_pins: tdm-c-slv-fs-z { -+ mux { -+ groups = "tdm_c_slv_fs_z"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_slv_sclk_a_pins: tdm-c-slv-sclk-a { -+ mux { -+ groups = "tdm_c_slv_sclk_a"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_c_slv_sclk_z_pins: tdm-c-slv-sclk-z { -+ mux { -+ groups = "tdm_c_slv_sclk_z"; -+ function = "tdm_c"; -+ bias-disable; -+ }; -+ }; -+ - uart_a_pins: uart-a { - mux { - groups = "uart_a_tx", -@@ -841,6 +1303,108 @@ - #reset-cells = <1>; - clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; - }; -+ -+ tdmin_a: audio-controller@300 { -+ compatible = "amlogic,g12a-tdmin", -+ "amlogic,axg-tdmin"; -+ reg = <0x0 0x300 0x0 0x40>; -+ sound-name-prefix = "TDMIN_A"; -+ clocks = <&clkc_audio AUD_CLKID_TDMIN_A>, -+ <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>, -+ <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>; -+ clock-names = "pclk", "sclk", "sclk_sel", -+ "lrclk", "lrclk_sel"; -+ status = "disabled"; -+ }; -+ -+ tdmin_b: audio-controller@340 { -+ compatible = "amlogic,g12a-tdmin", -+ "amlogic,axg-tdmin"; -+ reg = <0x0 0x340 0x0 0x40>; -+ sound-name-prefix = "TDMIN_B"; -+ clocks = <&clkc_audio AUD_CLKID_TDMIN_B>, -+ <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>, -+ <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>; -+ clock-names = "pclk", "sclk", "sclk_sel", -+ "lrclk", "lrclk_sel"; -+ status = "disabled"; -+ }; -+ -+ tdmin_c: audio-controller@380 { -+ compatible = "amlogic,g12a-tdmin", -+ "amlogic,axg-tdmin"; -+ reg = <0x0 0x380 0x0 0x40>; -+ sound-name-prefix = "TDMIN_C"; -+ clocks = <&clkc_audio AUD_CLKID_TDMIN_C>, -+ <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>, -+ <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>; -+ clock-names = "pclk", "sclk", "sclk_sel", -+ "lrclk", "lrclk_sel"; -+ status = "disabled"; -+ }; -+ -+ tdmin_lb: audio-controller@3c0 { -+ compatible = "amlogic,g12a-tdmin", -+ "amlogic,axg-tdmin"; -+ reg = <0x0 0x3c0 0x0 0x40>; -+ sound-name-prefix = "TDMIN_LB"; -+ clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>, -+ <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>, -+ <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>, -+ <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>; -+ clock-names = "pclk", "sclk", "sclk_sel", -+ "lrclk", "lrclk_sel"; -+ status = "disabled"; -+ }; -+ -+ tdmout_a: audio-controller@500 { -+ compatible = "amlogic,g12a-tdmout"; -+ reg = <0x0 0x500 0x0 0x40>; -+ sound-name-prefix = "TDMOUT_A"; -+ clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, -+ <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, -+ <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, -+ <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>, -+ <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>; -+ clock-names = "pclk", "sclk", "sclk_sel", -+ "lrclk", "lrclk_sel"; -+ status = "disabled"; -+ }; -+ -+ tdmout_b: audio-controller@540 { -+ compatible = "amlogic,g12a-tdmout"; -+ reg = <0x0 0x540 0x0 0x40>; -+ sound-name-prefix = "TDMOUT_B"; -+ clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>, -+ <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>, -+ <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>, -+ <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>, -+ <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>; -+ clock-names = "pclk", "sclk", "sclk_sel", -+ "lrclk", "lrclk_sel"; -+ status = "disabled"; -+ }; -+ -+ tdmout_c: audio-controller@580 { -+ compatible = "amlogic,g12a-tdmout"; -+ reg = <0x0 0x580 0x0 0x40>; -+ sound-name-prefix = "TDMOUT_C"; -+ clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>, -+ <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>, -+ <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>, -+ <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>, -+ <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>; -+ clock-names = "pclk", "sclk", "sclk_sel", -+ "lrclk", "lrclk_sel"; -+ status = "disabled"; -+ }; - }; - - usb3_pcie_phy: phy@46000 { -@@ -1009,6 +1573,100 @@ - }; - }; - -+ mclk0_ao_pins: mclk0-ao { -+ mux { -+ groups = "mclk0_ao"; -+ function = "mclk0_ao"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_ao_b_din0_pins: tdm-ao-b-din0 { -+ mux { -+ groups = "tdm_ao_b_din0"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_ao_b_din1_pins: tdm-ao-b-din1 { -+ mux { -+ groups = "tdm_ao_b_din1"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_ao_b_din2_pins: tdm-ao-b-din2 { -+ mux { -+ groups = "tdm_ao_b_din2"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_ao_b_dout0_pins: tdm-ao-b-dout0 { -+ mux { -+ groups = "tdm_ao_b_dout0"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_ao_b_dout1_pins: tdm-ao-b-dout1 { -+ mux { -+ groups = "tdm_ao_b_dout1"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_ao_b_dout2_pins: tdm-ao-b-dout2 { -+ mux { -+ groups = "tdm_ao_b_dout2"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_ao_b_fs_pins: tdm-ao-b-fs { -+ mux { -+ groups = "tdm_ao_b_fs"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_ao_b_sclk_pins: tdm-ao-b-sclk { -+ mux { -+ groups = "tdm_ao_b_sclk"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ drive-strength-microamp = <3000>; -+ }; -+ }; -+ -+ tdm_ao_b_slv_fs_pins: tdm-ao-b-slv-fs { -+ mux { -+ groups = "tdm_ao_b_slv_fs"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ }; -+ }; -+ -+ tdm_ao_b_slv_sclk_pins: tdm-ao-b-slv-sclk { -+ mux { -+ groups = "tdm_ao_b_slv_sclk"; -+ function = "tdm_ao_b"; -+ bias-disable; -+ }; -+ }; -+ - uart_ao_a_pins: uart-a-ao { - mux { - groups = "uart_ao_a_tx", - -From fc0995a2c81aa81181c862ca5fe785d338628263 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:07 +0200 -Subject: [PATCH 164/249] FROMLIST: arm64: dts: meson: g12a: add spdifouts - -Add the devices nodes and pinctrl definitions for the spdif outputs of -the g12a SoC family - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 60 +++++++++++++++++++++ - 1 file changed, 60 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 73aa3025b50a2..0cb04f83c5213 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -701,6 +701,33 @@ - }; - }; - -+ spdif_out_h_pins: spdif-out-h { -+ mux { -+ groups = "spdif_out_h"; -+ function = "spdif_out"; -+ drive-strength-microamp = <500>; -+ bias-disable; -+ }; -+ }; -+ -+ spdif_out_a11_pins: spdif-out-a11 { -+ mux { -+ groups = "spdif_out_a11"; -+ function = "spdif_out"; -+ drive-strength-microamp = <500>; -+ bias-disable; -+ }; -+ }; -+ -+ spdif_out_a13_pins: spdif-out-a13 { -+ mux { -+ groups = "spdif_out_a13"; -+ function = "spdif_out"; -+ drive-strength-microamp = <500>; -+ bias-disable; -+ }; -+ }; -+ - tdm_a_din0_pins: tdm-a-din0 { - mux { - groups = "tdm_a_din0"; -@@ -1364,6 +1391,18 @@ - status = "disabled"; - }; - -+ spdifout: audio-controller@480 { -+ compatible = "amlogic,g12a-spdifout", -+ "amlogic,axg-spdifout"; -+ reg = <0x0 0x480 0x0 0x50>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "SPDIFOUT"; -+ clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>, -+ <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>; -+ clock-names = "pclk", "mclk"; -+ status = "disabled"; -+ }; -+ - tdmout_a: audio-controller@500 { - compatible = "amlogic,g12a-tdmout"; - reg = <0x0 0x500 0x0 0x40>; -@@ -1405,6 +1444,18 @@ - "lrclk", "lrclk_sel"; - status = "disabled"; - }; -+ -+ spdifout_b: audio-controller@680 { -+ compatible = "amlogic,g12a-spdifout", -+ "amlogic,axg-spdifout"; -+ reg = <0x0 0x680 0x0 0x50>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "SPDIFOUT_B"; -+ clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>, -+ <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>; -+ clock-names = "pclk", "mclk"; -+ status = "disabled"; -+ }; - }; - - usb3_pcie_phy: phy@46000 { -@@ -1590,6 +1641,15 @@ - }; - }; - -+ spdif_ao_out_pins: spdif_ao_out { -+ mux { -+ groups = "spdif_ao_out"; -+ function = "spdif_ao_out"; -+ drive-strength-microamp = <500>; -+ bias-disable; -+ }; -+ }; -+ - tdm_ao_b_din1_pins: tdm-ao-b-din1 { - mux { - groups = "tdm_ao_b_din1"; - -From d040122987c72bda00023d06f569c32b4985f601 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:08 +0200 -Subject: [PATCH 165/249] FROMLIST: arm64: dts: meson: g12a: add pdm - -Add the pdm device node and the pinctrl definition for this capture -interface g12a SoC family - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 177 ++++++++++++++++++++ - 1 file changed, 177 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 0cb04f83c5213..42292d3992338 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -555,6 +555,170 @@ - }; - }; - -+ pdm_din0_a_pins: pdm_din0_a { -+ mux { -+ groups = "pdm_din0_a"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din0_c_pins: pdm_din0_c { -+ mux { -+ groups = "pdm_din0_c"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din0_x_pins: pdm_din0_x { -+ mux { -+ groups = "pdm_din0_x"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din0_z_pins: pdm_din0_z { -+ mux { -+ groups = "pdm_din0_z"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din1_a_pins: pdm_din1_a { -+ mux { -+ groups = "pdm_din1_a"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din1_c_pins: pdm_din1_c { -+ mux { -+ groups = "pdm_din1_c"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din1_x_pins: pdm_din1_x { -+ mux { -+ groups = "pdm_din1_x"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din1_z_pins: pdm_din1_z { -+ mux { -+ groups = "pdm_din1_z"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din2_a_pins: pdm_din2_a { -+ mux { -+ groups = "pdm_din2_a"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din2_c_pins: pdm_din2_c { -+ mux { -+ groups = "pdm_din2_c"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din2_x_pins: pdm_din2_x { -+ mux { -+ groups = "pdm_din2_x"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din2_z_pins: pdm_din2_z { -+ mux { -+ groups = "pdm_din2_z"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din3_a_pins: pdm_din3_a { -+ mux { -+ groups = "pdm_din3_a"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din3_c_pins: pdm_din3_c { -+ mux { -+ groups = "pdm_din3_c"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din3_x_pins: pdm_din3_x { -+ mux { -+ groups = "pdm_din3_x"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_din3_z_pins: pdm_din3_z { -+ mux { -+ groups = "pdm_din3_z"; -+ function = "pdm"; -+ bias-disable; -+ }; -+ }; -+ -+ pdm_dclk_a_pins: pdm_dclk_a { -+ mux { -+ groups = "pdm_dclk_a"; -+ function = "pdm"; -+ bias-disable; -+ drive-strength-microamp = <500>; -+ }; -+ }; -+ -+ pdm_dclk_c_pins: pdm_dclk_c { -+ mux { -+ groups = "pdm_dclk_c"; -+ function = "pdm"; -+ bias-disable; -+ drive-strength-microamp = <500>; -+ }; -+ }; -+ -+ pdm_dclk_x_pins: pdm_dclk_x { -+ mux { -+ groups = "pdm_dclk_x"; -+ function = "pdm"; -+ bias-disable; -+ drive-strength-microamp = <500>; -+ }; -+ }; -+ -+ pdm_dclk_z_pins: pdm_dclk_z { -+ mux { -+ groups = "pdm_dclk_z"; -+ function = "pdm"; -+ bias-disable; -+ drive-strength-microamp = <500>; -+ }; -+ }; -+ - pwm_a_pins: pwm-a { - mux { - groups = "pwm_a"; -@@ -1222,6 +1386,19 @@ - }; - }; - -+ pdm: audio-controller@40000 { -+ compatible = "amlogic,g12a-pdm", -+ "amlogic,axg-pdm"; -+ reg = <0x0 0x40000 0x0 0x34>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "PDM"; -+ clocks = <&clkc_audio AUD_CLKID_PDM>, -+ <&clkc_audio AUD_CLKID_PDM_DCLK>, -+ <&clkc_audio AUD_CLKID_PDM_SYSCLK>; -+ clock-names = "pclk", "dclk", "sysclk"; -+ status = "disabled"; -+ }; -+ - audio: bus@42000 { - compatible = "simple-bus"; - reg = <0x0 0x42000 0x0 0x2000>; - -From 955d6af8987bd39aa651aa3decfd005340acab54 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:09 +0200 -Subject: [PATCH 166/249] FROMLIST: arm64: dts: meson: g12a: add spdifin - -Add the spdif input device node and the pinctrl definition for -this capture interface g12a SoC family - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 37 +++++++++++++++++++++ - 1 file changed, 37 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 42292d3992338..40cdab068577d 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -865,6 +865,30 @@ - }; - }; - -+ spdif_in_a10_pins: spdif-in-a10 { -+ mux { -+ groups = "spdif_in_a10"; -+ function = "spdif_in"; -+ bias-disable; -+ }; -+ }; -+ -+ spdif_in_a12_pins: spdif-in-a12 { -+ mux { -+ groups = "spdif_in_a12"; -+ function = "spdif_in"; -+ bias-disable; -+ }; -+ }; -+ -+ spdif_in_h_pins: spdif-in-h { -+ mux { -+ groups = "spdif_in_h"; -+ function = "spdif_in"; -+ bias-disable; -+ }; -+ }; -+ - spdif_out_h_pins: spdif-out-h { - mux { - groups = "spdif_out_h"; -@@ -1568,6 +1592,19 @@ - status = "disabled"; - }; - -+ spdifin: audio-controller@400 { -+ compatible = "amlogic,g12a-spdifin", -+ "amlogic,axg-spdifin"; -+ reg = <0x0 0x400 0x0 0x30>; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "SPDIFIN"; -+ interrupts = ; -+ clocks = <&clkc_audio AUD_CLKID_SPDIFIN>, -+ <&clkc_audio AUD_CLKID_SPDIFIN_CLK>; -+ clock-names = "pclk", "refclk"; -+ status = "disabled"; -+ }; -+ - spdifout: audio-controller@480 { - compatible = "amlogic,g12a-spdifout", - "amlogic,axg-spdifout"; - -From 22df6e84290731863bd4b40560609c4492155cd1 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 14 May 2019 13:15:10 +0200 -Subject: [PATCH 167/249] FROMLIST: arm64: dts: meson: g12a: enable hdmi_tx - sound dai provider - -At the moment the sysnopsys hdmi i2s driver provides a single playback -DAI. Add the corresponding sound-dai-cell to the hdmi device node. - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 40cdab068577d..8822acab23315 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -179,6 +179,7 @@ - clock-names = "isfr", "iahb", "venci"; - #address-cells = <1>; - #size-cells = <0>; -+ #sound-dai-cells = <0>; - status = "disabled"; - - /* VPU VENC Input */ - -From f5ee2d03881853eb3425aefa150de1be2a3eeae3 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 13 May 2019 11:15:46 +0200 -Subject: [PATCH 168/249] FROMLIST: dt-bindings: mmc: meson-gx: add - ddr-access-quirk property - -On the Amlogic G12A SoC family, (only) the SDIO controller has a bug which -makes any DDR access from the MMC controller fail. - -Add the amlogic,ddr-access-quirk property so signal this particular -controller has this bug and needs a quirk to work properly. - -Signed-off-by: Neil Armstrong ---- - Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt -index 13e70409e8ac6..f8914dab06c60 100644 ---- a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt -+++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt -@@ -22,6 +22,10 @@ Required properties: - clock rate requested by the MMC core. - - resets : phandle of the internal reset line - -+Optional properties: -+- amlogic,ddr-access-quirk: set when HW cannot access the DDR memory, like on -+ the G12A SDIO controller. -+ - Example: - - sd_emmc_a: mmc@70000 { - -From 8e7e969c288262fa5dc3e5b4bbf77b8cd7ad9bc0 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 13 May 2019 11:15:47 +0200 -Subject: [PATCH 169/249] FROMLIST: mmc: meson-gx: add ddr-access-quirk - -On the Amlogic G12A SoC family, (only) the SDIO controller fails to access -the data from DDR, leading to a broken controller. - -But each MMC controller has 1,5KiB of SRAM after the registers, that can -be used as bounce buffer to avoid direct DDR access from the integrated -DMAs (this SRAM may be used by the boot ROM when DDR is not yet initialized). - -The quirk is to disable the chained descriptor for this controller, and -use this SRAM memory zone as buffer for the bounce buffer fallback mode. - -The performance hit hasn't been evaluated, but the fix has been tested -using a WiFi AP6398S SDIO module, and the iperf3 Bandwidth measurement gave -55.2 Mbits/sec over a 63 Hours long test, with the SDIO ios set as High-Speed -at 50MHz clock. It gave 170 Mbits/sec as SDR104 and 200MHz clock. - -Signed-off-by: Neil Armstrong -Reviewed-by: Kevin Hilman -Signed-off-by: Neil Armstrong ---- - drivers/mmc/host/meson-gx-mmc.c | 65 ++++++++++++++++++++++++++------- - 1 file changed, 52 insertions(+), 13 deletions(-) - -diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c -index c5a8af4ca76b2..6ef4653040526 100644 ---- a/drivers/mmc/host/meson-gx-mmc.c -+++ b/drivers/mmc/host/meson-gx-mmc.c -@@ -129,6 +129,9 @@ - #define SD_EMMC_TXD 0x94 - #define SD_EMMC_LAST_REG SD_EMMC_TXD - -+#define SD_EMMC_SRAM_DATA_BUF_LEN 1536 -+#define SD_EMMC_SRAM_DATA_BUF_OFF 0x200 -+ - #define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */ - #define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */ - #define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */ -@@ -168,6 +171,8 @@ struct meson_host { - unsigned long req_rate; - bool ddr; - -+ bool ddr_access_quirk; -+ - struct pinctrl *pinctrl; - struct pinctrl_state *pins_default; - struct pinctrl_state *pins_clk_gate; -@@ -232,11 +237,20 @@ static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd) - static void meson_mmc_get_transfer_mode(struct mmc_host *mmc, - struct mmc_request *mrq) - { -+ struct meson_host *host = mmc_priv(mmc); - struct mmc_data *data = mrq->data; - struct scatterlist *sg; - int i; - bool use_desc_chain_mode = true; - -+ /* -+ * When Controller DMA cannot directly access DDR memory, disable -+ * support for Chain Mode to directly use the internal SRAM using -+ * the bounce buffer mode. -+ */ -+ if (host->ddr_access_quirk) -+ return; -+ - /* - * Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been - * reported. For some strange reason this occurs in descriptor -@@ -1049,6 +1063,10 @@ static int meson_mmc_probe(struct platform_device *pdev) - host->dev = &pdev->dev; - dev_set_drvdata(&pdev->dev, host); - -+ /* The G12A SDIO Controller needs an SRAM bounce buffer */ -+ host->ddr_access_quirk = device_property_read_bool(&pdev->dev, -+ "amlogic,ddr-access-quirk"); -+ - /* Get regulators and the supported OCR mask */ - host->vqmmc_enabled = false; - ret = mmc_regulator_get_supply(mmc); -@@ -1146,9 +1164,16 @@ static int meson_mmc_probe(struct platform_device *pdev) - goto err_init_clk; - - mmc->caps |= MMC_CAP_CMD23; -- mmc->max_blk_count = CMD_CFG_LENGTH_MASK; -+ if (host->ddr_access_quirk) { -+ /* Limit to the available sram memory */ -+ mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size; -+ mmc->max_blk_count = mmc->max_segs; -+ } else { -+ mmc->max_blk_count = CMD_CFG_LENGTH_MASK; -+ mmc->max_segs = SD_EMMC_DESC_BUF_LEN / -+ sizeof(struct sd_emmc_desc); -+ } - mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; -- mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc); - mmc->max_seg_size = mmc->max_req_size; - - /* -@@ -1158,15 +1183,27 @@ static int meson_mmc_probe(struct platform_device *pdev) - */ - mmc->caps2 &= ~MMC_CAP2_HS400; - -- /* data bounce buffer */ -- host->bounce_buf_size = mmc->max_req_size; -- host->bounce_buf = -- dma_alloc_coherent(host->dev, host->bounce_buf_size, -- &host->bounce_dma_addr, GFP_KERNEL); -- if (host->bounce_buf == NULL) { -- dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n"); -- ret = -ENOMEM; -- goto err_free_irq; -+ if (host->ddr_access_quirk) { -+ /* -+ * The MMC Controller embeds 1,5KiB of internal SRAM -+ * that can be used to be used as bounce buffer. -+ * In the case of the G12A SDIO controller, use these -+ * instead of the DDR memory -+ */ -+ host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN; -+ host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF; -+ host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF; -+ } else { -+ /* data bounce buffer */ -+ host->bounce_buf_size = mmc->max_req_size; -+ host->bounce_buf = -+ dma_alloc_coherent(host->dev, host->bounce_buf_size, -+ &host->bounce_dma_addr, GFP_KERNEL); -+ if (host->bounce_buf == NULL) { -+ dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n"); -+ ret = -ENOMEM; -+ goto err_free_irq; -+ } - } - - host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN, -@@ -1208,8 +1245,10 @@ static int meson_mmc_remove(struct platform_device *pdev) - - dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN, - host->descs, host->descs_dma_addr); -- dma_free_coherent(host->dev, host->bounce_buf_size, -- host->bounce_buf, host->bounce_dma_addr); -+ -+ if (!host->ddr_access_quirk) -+ dma_free_coherent(host->dev, host->bounce_buf_size, -+ host->bounce_buf, host->bounce_dma_addr); - - clk_disable_unprepare(host->mmc_clk); - clk_disable_unprepare(host->core_clk); - -From 2bccc28e7190cb1ea0c6ce556de880c1a04c2726 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 26 Apr 2019 17:55:24 +0200 -Subject: [PATCH 170/249] WIP: ASoC: dapm: let mux force a disconnect during - power update - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - sound/soc/soc-dapm.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c -index 0382a47b30bd8..0e3bda80f5319 100644 ---- a/sound/soc/soc-dapm.c -+++ b/sound/soc/soc-dapm.c -@@ -2244,7 +2244,7 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, - dapm_kcontrol_for_each_path(path, kcontrol) { - found = 1; - /* we now need to match the string in the enum to the path */ -- if (!(strcmp(path->name, e->texts[mux]))) -+ if (e && !(strcmp(path->name, e->texts[mux]))) - connect = true; - else - connect = false; - -From 16f03e497af82f68fed2cdfe482f1c24f917c96b Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 12 Apr 2019 14:15:32 +0200 -Subject: [PATCH 171/249] WIP: ASoC: meson: axg-card: set link name based on - link node name - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/axg-card.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c -index aa54d2c612c98..5c8deee8d512d 100644 ---- a/sound/soc/meson/axg-card.c -+++ b/sound/soc/meson/axg-card.c -@@ -80,10 +80,11 @@ static int axg_card_parse_dai(struct snd_soc_card *card, - - static int axg_card_set_link_name(struct snd_soc_card *card, - struct snd_soc_dai_link *link, -+ struct device_node *node, - const char *prefix) - { - char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s", -- prefix, link->cpu_of_node->full_name); -+ prefix, node->full_name); - if (!name) - return -ENOMEM; - -@@ -474,7 +475,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, - codec++; - } - -- ret = axg_card_set_link_name(card, link, "be"); -+ ret = axg_card_set_link_name(card, link, node, "be"); - if (ret) - dev_err(card->dev, "error setting %pOFn link name\n", np); - -@@ -483,6 +484,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, - - static int axg_card_set_fe_link(struct snd_soc_card *card, - struct snd_soc_dai_link *link, -+ struct device_node *node, - bool is_playback) - { - link->dynamic = 1; -@@ -497,7 +499,7 @@ static int axg_card_set_fe_link(struct snd_soc_card *card, - else - link->dpcm_capture = 1; - -- return axg_card_set_link_name(card, link, "fe"); -+ return axg_card_set_link_name(card, link, node, "fe"); - } - - static int axg_card_cpu_is_capture_fe(struct device_node *np) -@@ -527,9 +529,9 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, - return ret; - - if (axg_card_cpu_is_playback_fe(dai_link->cpu_of_node)) -- ret = axg_card_set_fe_link(card, dai_link, true); -+ ret = axg_card_set_fe_link(card, dai_link, np, true); - else if (axg_card_cpu_is_capture_fe(dai_link->cpu_of_node)) -- ret = axg_card_set_fe_link(card, dai_link, false); -+ ret = axg_card_set_fe_link(card, dai_link, np, false); - else - ret = axg_card_set_be_link(card, dai_link, np); - - -From 0781679d344e5749e23f89f2b20cd4b362904ad2 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 16 Apr 2019 10:36:53 +0200 -Subject: [PATCH 172/249] WIP: ASoC: meson: add tohdmitx support in axg-card - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/axg-card.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c -index 5c8deee8d512d..6c5181c988287 100644 ---- a/sound/soc/meson/axg-card.c -+++ b/sound/soc/meson/axg-card.c -@@ -29,6 +29,15 @@ struct axg_dai_link_tdm_data { - struct axg_dai_link_tdm_mask *codec_masks; - }; - -+/* Base params for the HDMI codec to codec link */ -+static const struct snd_soc_pcm_stream hdmi_codec_params = { -+ .formats = SNDRV_PCM_FMTBIT_S24_LE, -+ .rate_min = 8000, -+ .rate_max = 192000, -+ .channels_min = 2, -+ .channels_max = 8, -+}; -+ - #define PREFIX "amlogic," - - static int axg_card_reallocate_links(struct axg_card *priv, -@@ -517,6 +526,11 @@ static int axg_card_cpu_is_tdm_iface(struct device_node *np) - return of_device_is_compatible(np, PREFIX "axg-tdm-iface"); - } - -+static int g12a_card_is_hdmi_codec(struct device_node *np) -+{ -+ return of_device_is_compatible(np, PREFIX "g12a-tohdmitx"); -+} -+ - static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, - int *index) - { -@@ -540,6 +554,8 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, - - if (axg_card_cpu_is_tdm_iface(dai_link->cpu_of_node)) - ret = axg_card_parse_tdm(card, np, index); -+ else if (g12a_card_is_hdmi_codec(dai_link->cpu_of_node)) -+ dai_link->params = &hdmi_codec_params; - - return ret; - } - -From 0003d9d433211507354950cff9c5a01fde316c17 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 16 Apr 2019 10:36:19 +0200 -Subject: [PATCH 173/249] WIP: ASoC: meson: add g12a tohdmitx control - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - sound/soc/meson/Kconfig | 7 + - sound/soc/meson/Makefile | 2 + - sound/soc/meson/g12a-tohdmitx.c | 439 ++++++++++++++++++++++++++++++++ - 3 files changed, 448 insertions(+) - create mode 100644 sound/soc/meson/g12a-tohdmitx.c - -diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig -index 8779fe23671d6..6ffaa85df70ca 100644 ---- a/sound/soc/meson/Kconfig -+++ b/sound/soc/meson/Kconfig -@@ -82,4 +82,11 @@ config SND_MESON_AXG_PDM - help - Select Y or M to add support for PDM input embedded - in the Amlogic AXG SoC family -+ -+config SND_MESON_G12A_TOHDMITX -+ tristate "Amlogic G12A To HDMI TX Control Support" -+ imply SND_SOC_HDMI_CODEC -+ help -+ Select Y or M to add support for HDMI audio on the g12a SoC -+ family - endmenu -diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile -index b45dfb9e2f888..1a8b1470ed843 100644 ---- a/sound/soc/meson/Makefile -+++ b/sound/soc/meson/Makefile -@@ -11,6 +11,7 @@ snd-soc-meson-axg-sound-card-objs := axg-card.o - snd-soc-meson-axg-spdifin-objs := axg-spdifin.o - snd-soc-meson-axg-spdifout-objs := axg-spdifout.o - snd-soc-meson-axg-pdm-objs := axg-pdm.o -+snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o - - obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o - obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o -@@ -23,3 +24,4 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o - obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o - obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o - obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o -+obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o -diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c -new file mode 100644 -index 0000000000000..e49d6c8306838 ---- /dev/null -+++ b/sound/soc/meson/g12a-tohdmitx.c -@@ -0,0 +1,439 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// -+// Copyright (c) 2019 BayLibre, SAS. -+// Author: Jerome Brunet -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define G12A_TOHDMITX_DRV_NAME "g12a-tohdmitx" -+ -+#define TOHDMITX_CTRL0 0x0 -+#define CTRL0_ENABLE_SHIFT 31 -+#define CTRL0_I2S_DAT_SEL GENMASK(13, 12) -+#define CTRL0_I2S_LRCLK_SEL GENMASK(9, 8) -+#define CTRL0_I2S_BLK_CAP_INV BIT(7) -+#define CTRL0_I2S_BCLK_O_INV BIT(6) -+#define CTRL0_I2S_BCLK_SEL GENMASK(5, 4) -+#define CTRL0_SPDIF_CLK_CAP_INV BIT(3) -+#define CTRL0_SPDIF_CLK_O_INV BIT(2) -+#define CTRL0_SPDIF_SEL BIT(1) -+#define CTRL0_SPDIF_CLK_SEL BIT(0) -+ -+struct g12a_tohdmitx { -+ struct regmap *map; -+}; -+ -+struct g12a_tohdmitx_input { -+ struct snd_pcm_hw_params params; -+ unsigned int fmt; -+}; -+ -+static struct snd_soc_dapm_widget * -+g12a_tohdmitx_get_input(struct snd_soc_dapm_widget *w) -+{ -+ struct snd_soc_dapm_path *p = NULL; -+ struct snd_soc_dapm_widget *in; -+ -+ snd_soc_dapm_widget_for_each_source_path(w, p) { -+ if (!p->connect) -+ continue; -+ -+ /* Check that we still are in the same component */ -+ if (snd_soc_dapm_to_component(w->dapm) != -+ snd_soc_dapm_to_component(p->source->dapm)) -+ continue; -+ -+ if (p->source->id == snd_soc_dapm_dai_in) -+ return p->source; -+ -+ in = g12a_tohdmitx_get_input(p->source); -+ if (in) -+ return in; -+ } -+ -+ return NULL; -+} -+ -+static struct g12a_tohdmitx_input * -+g12a_tohdmitx_get_input_data(struct snd_soc_dapm_widget *w) -+{ -+ struct snd_soc_dapm_widget *in = -+ g12a_tohdmitx_get_input(w); -+ struct snd_soc_dai *dai; -+ -+ if (WARN_ON(!in)) -+ return NULL; -+ -+ dai = in->priv; -+ -+ return dai->playback_dma_data; -+} -+ -+static const char * const g12a_tohdmitx_i2s_mux_texts[] = { -+ "I2S A", "I2S B", "I2S C", -+}; -+ -+static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_i2s_mux_enum, -+ g12a_tohdmitx_i2s_mux_texts); -+ -+static int g12a_tohdmitx_get_input_val(struct g12a_tohdmitx *priv, -+ unsigned int mask) -+{ -+ unsigned int val; -+ -+ regmap_read(priv->map, TOHDMITX_CTRL0, &val); -+ return (val & mask) >> __ffs(mask); -+} -+ -+static int g12a_tohdmitx_i2s_mux_get_enum(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_kcontrol_component(kcontrol); -+ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); -+ -+ ucontrol->value.enumerated.item[0] = -+ g12a_tohdmitx_get_input_val(priv, CTRL0_I2S_DAT_SEL); -+ -+ return 0; -+} -+ -+static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_kcontrol_component(kcontrol); -+ struct snd_soc_dapm_context *dapm = -+ snd_soc_dapm_kcontrol_dapm(kcontrol); -+ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int mux = ucontrol->value.enumerated.item[0]; -+ unsigned int val = g12a_tohdmitx_get_input_val(priv, CTRL0_I2S_DAT_SEL); -+ -+ /* Force disconnect of the mux while updating */ -+ if (val != mux) -+ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); -+ -+ regmap_update_bits(priv->map, TOHDMITX_CTRL0, -+ CTRL0_I2S_DAT_SEL | -+ CTRL0_I2S_LRCLK_SEL | -+ CTRL0_I2S_BCLK_SEL, -+ FIELD_PREP(CTRL0_I2S_DAT_SEL, mux) | -+ FIELD_PREP(CTRL0_I2S_LRCLK_SEL, mux) | -+ FIELD_PREP(CTRL0_I2S_BCLK_SEL, mux)); -+ -+ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); -+ -+ return 0; -+} -+ -+static const struct snd_kcontrol_new g12a_tohdmitx_i2s_mux = -+ SOC_DAPM_ENUM_EXT("I2S Source", g12a_tohdmitx_i2s_mux_enum, -+ g12a_tohdmitx_i2s_mux_get_enum, -+ g12a_tohdmitx_i2s_mux_put_enum); -+ -+static const char * const g12a_tohdmitx_spdif_mux_texts[] = { -+ "SPDIF A", "SPDIF B", -+}; -+ -+static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_spdif_mux_enum, -+ g12a_tohdmitx_spdif_mux_texts); -+ -+static int g12a_tohdmitx_spdif_mux_get_enum(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_kcontrol_component(kcontrol); -+ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); -+ -+ ucontrol->value.enumerated.item[0] = -+ g12a_tohdmitx_get_input_val(priv, CTRL0_SPDIF_SEL); -+ -+ return 0; -+} -+ -+static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_kcontrol_component(kcontrol); -+ struct snd_soc_dapm_context *dapm = -+ snd_soc_dapm_kcontrol_dapm(kcontrol); -+ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); -+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -+ unsigned int mux = ucontrol->value.enumerated.item[0]; -+ unsigned int val = g12a_tohdmitx_get_input_val(priv, CTRL0_SPDIF_SEL); -+ -+ /* Force disconnect of the mux while updating */ -+ if (val != mux) -+ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); -+ -+ regmap_update_bits(priv->map, TOHDMITX_CTRL0, -+ CTRL0_SPDIF_SEL | -+ CTRL0_SPDIF_CLK_SEL, -+ FIELD_PREP(CTRL0_SPDIF_SEL, mux) | -+ FIELD_PREP(CTRL0_SPDIF_CLK_SEL, mux)); -+ -+ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); -+ -+ return 0; -+} -+ -+static const struct snd_kcontrol_new g12a_tohdmitx_spdif_mux = -+ SOC_DAPM_ENUM_EXT("SPDIF Source", g12a_tohdmitx_spdif_mux_enum, -+ g12a_tohdmitx_spdif_mux_get_enum, -+ g12a_tohdmitx_spdif_mux_put_enum); -+ -+static const struct snd_kcontrol_new g12a_tohdmitx_out_enable = -+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOHDMITX_CTRL0, -+ CTRL0_ENABLE_SHIFT, 1, 0); -+ -+static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { -+ SND_SOC_DAPM_MUX("I2S SRC", SND_SOC_NOPM, 0, 0, -+ &g12a_tohdmitx_i2s_mux), -+ SND_SOC_DAPM_SWITCH("I2S OUT EN", SND_SOC_NOPM, 0, 0, -+ &g12a_tohdmitx_out_enable), -+ SND_SOC_DAPM_MUX("SPDIF SRC", SND_SOC_NOPM, 0, 0, -+ &g12a_tohdmitx_spdif_mux), -+ SND_SOC_DAPM_SWITCH("SPDIF OUT EN", SND_SOC_NOPM, 0, 0, -+ &g12a_tohdmitx_out_enable), -+}; -+ -+static int g12a_tohdmitx_input_probe(struct snd_soc_dai *dai) -+{ -+ struct g12a_tohdmitx_input *data; -+ -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ dai->playback_dma_data = data; -+ return 0; -+} -+ -+static int g12a_tohdmitx_input_remove(struct snd_soc_dai *dai) -+{ -+ kfree(dai->playback_dma_data); -+ return 0; -+} -+ -+static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct g12a_tohdmitx_input *data = dai->playback_dma_data; -+ -+ /* Save the stream params for the downstream link */ -+ memcpy(&data->params, params, sizeof(*params)); -+ -+ return 0; -+} -+ -+static int g12a_tohdmitx_output_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct g12a_tohdmitx_input *in_data = -+ g12a_tohdmitx_get_input_data(dai->capture_widget); -+ -+ if (!in_data) -+ return -ENODEV; -+ -+ memcpy(params, &in_data->params, sizeof(*params)); -+ -+ return 0; -+} -+ -+static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai, -+ unsigned int fmt) -+{ -+ struct g12a_tohdmitx_input *data = dai->playback_dma_data; -+ -+ /* Save the source stream format for the downstream link */ -+ data->fmt = fmt; -+ return 0; -+} -+ -+static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct g12a_tohdmitx_input *in_data = -+ g12a_tohdmitx_get_input_data(dai->capture_widget); -+ -+ if (!in_data) -+ return -ENODEV; -+ -+ if (!in_data->fmt) -+ return 0; -+ -+ return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt); -+} -+ -+static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { -+ .hw_params = g12a_tohdmitx_input_hw_params, -+ .set_fmt = g12a_tohdmitx_input_set_fmt, -+}; -+ -+static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { -+ .hw_params = g12a_tohdmitx_output_hw_params, -+ .startup = g12a_tohdmitx_output_startup, -+}; -+ -+#define TOHDMITX_SPDIF_FORMATS \ -+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ -+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) -+ -+#define TOHDMITX_I2S_FORMATS \ -+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ -+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ -+ SNDRV_PCM_FMTBIT_S32_LE) -+ -+#define TOHDMITX_IN(_name, _fmt, _chmax) { \ -+ .name = _name, \ -+ .playback = { \ -+ .stream_name = _name " Playback", \ -+ .channels_min = 1, \ -+ .channels_max = (_chmax), \ -+ .rate_min = 8000, \ -+ .rate_max = 192000, \ -+ .formats = (_fmt), \ -+ }, \ -+ .ops = &g12a_tohdmitx_input_ops, \ -+ .probe = g12a_tohdmitx_input_probe, \ -+ .remove = g12a_tohdmitx_input_remove, \ -+} -+ -+#define TOHDMITX_OUT(_name, _fmt, _chmax) { \ -+ .name = _name, \ -+ .capture = { \ -+ .stream_name = _name " Capture", \ -+ .channels_min = 1, \ -+ .channels_max = (_chmax), \ -+ .rate_min = 8000, \ -+ .rate_max = 192000, \ -+ .formats = (_fmt), \ -+ }, \ -+ .ops = &g12a_tohdmitx_output_ops, \ -+} -+ -+static struct snd_soc_dai_driver g12a_tohdmitx_dai_drv[] = { -+ TOHDMITX_IN("I2S IN A", TOHDMITX_I2S_FORMATS, 8), -+ TOHDMITX_IN("I2S IN B", TOHDMITX_I2S_FORMATS, 8), -+ TOHDMITX_IN("I2S IN C", TOHDMITX_I2S_FORMATS, 8), -+ TOHDMITX_OUT("I2S OUT", TOHDMITX_I2S_FORMATS, 8), -+ TOHDMITX_IN("SPDIF IN A", TOHDMITX_SPDIF_FORMATS, 2), -+ TOHDMITX_IN("SPDIF IN B", TOHDMITX_SPDIF_FORMATS, 2), -+ TOHDMITX_OUT("SPDIF OUT", TOHDMITX_SPDIF_FORMATS, 2), -+}; -+ -+static const struct snd_soc_dapm_route g12a_tohdmitx_routes[] = { -+ { "I2S SRC", "I2S A", "I2S IN A Playback" }, -+ { "I2S SRC", "I2S B", "I2S IN B Playback" }, -+ { "I2S SRC", "I2S C", "I2S IN C Playback" }, -+ { "I2S OUT EN", "Switch", "I2S SRC" }, -+ { "I2S OUT Capture", NULL, "I2S OUT EN" }, -+ { "SPDIF SRC", "SPDIF A", "SPDIF IN A Playback" }, -+ { "SPDIF SRC", "SPDIF B", "SPDIF IN B Playback" }, -+ { "SPDIF OUT EN", "Switch", "SPDIF SRC" }, -+ { "SPDIF OUT Capture", NULL, "SPDIF OUT EN" }, -+}; -+ -+static const struct snd_soc_component_driver g12a_tohdmitx_component_drv = { -+ .dapm_widgets = g12a_tohdmitx_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(g12a_tohdmitx_widgets), -+ .dapm_routes = g12a_tohdmitx_routes, -+ .num_dapm_routes = ARRAY_SIZE(g12a_tohdmitx_routes), -+ .endianness = 1, -+ .non_legacy_dai_naming = 1, -+}; -+ -+static const struct regmap_config g12a_tohdmitx_regmap_cfg = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+}; -+ -+static const struct of_device_id g12a_tohdmitx_of_match[] = { -+ { .compatible = "amlogic,g12a-tohdmitx", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, g12a_tohdmitx_of_match); -+ -+static int g12a_tohdmitx_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct g12a_tohdmitx *priv; -+ struct resource *res; -+ void __iomem *regs; -+ struct clk *pclk; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ platform_set_drvdata(pdev, priv); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); -+ -+ pclk = devm_clk_get(dev, NULL); -+ if (IS_ERR(pclk)) { -+ ret = PTR_ERR(pclk); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "failed to get pclk\n"); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(pclk); -+ if (ret) { -+ dev_err(dev, "pclk enable failed\n"); -+ return ret; -+ } -+ -+ ret = devm_add_action_or_reset(dev, -+ (void(*)(void *))clk_disable_unprepare, -+ pclk); -+ if (ret) { -+ dev_err(dev, "failed to add pclk reset aciton\n"); -+ clk_disable_unprepare(pclk); -+ return ret; -+ } -+ -+ /* Enable the clock here */ -+ priv->map = devm_regmap_init_mmio(dev, regs, &g12a_tohdmitx_regmap_cfg); -+ if (IS_ERR(priv->map)) { -+ dev_err(dev, "failed to init regmap: %ld\n", -+ PTR_ERR(priv->map)); -+ return PTR_ERR(priv->map); -+ } -+ -+ /* Initialize the static clock parameters */ -+ regmap_write(priv->map, TOHDMITX_CTRL0, -+ CTRL0_I2S_BLK_CAP_INV | CTRL0_SPDIF_CLK_CAP_INV); -+ -+ return devm_snd_soc_register_component(dev, -+ &g12a_tohdmitx_component_drv, g12a_tohdmitx_dai_drv, -+ ARRAY_SIZE(g12a_tohdmitx_dai_drv)); -+} -+ -+static struct platform_driver g12a_tohdmitx_pdrv = { -+ .driver = { -+ .name = G12A_TOHDMITX_DRV_NAME, -+ .of_match_table = g12a_tohdmitx_of_match, -+ }, -+ .probe = g12a_tohdmitx_probe, -+}; -+module_platform_driver(g12a_tohdmitx_pdrv); -+ -+MODULE_AUTHOR("Jerome Brunet "); -+MODULE_DESCRIPTION("Amlogic G12a To HDMI Tx Control Codec Driver"); -+MODULE_LICENSE("GPL v2"); - -From c753955463b03c766f02dc94d87cfa56828ec8db Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Thu, 14 Feb 2019 14:11:58 +0100 -Subject: [PATCH 174/249] WIP: ASoC: max98357a: add Kconfig name - -Allows the module to be built on its own ---- - sound/soc/codecs/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 667fc1d59e189..1d3f2ee159316 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -699,7 +699,7 @@ config SND_SOC_MAX98095 - tristate - - config SND_SOC_MAX98357A -- tristate -+ tristate "Maxim MAX98357A" - - config SND_SOC_MAX98371 - tristate - -From 57a92dec4917797644b96a07603e2ede90ad3d6e Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Sun, 12 May 2019 22:12:52 +0200 -Subject: [PATCH 175/249] WIP: ASoC: hdmi-codec: re-introduce mutex locking - -Replace the bit atomic operations by a mutex to ensure only one dai -at a time is active on the hdmi codec. - -This is a follow up on change: -3fcf94ef4d41 ("ASoC: hdmi-codec: remove reference to the current substream") - -Suggested-by: Mark Brown -Signed-off-by: Jerome Brunet ---- - sound/soc/codecs/hdmi-codec.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 90a8927666259..6a0cc8d7e1412 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -281,7 +281,7 @@ struct hdmi_codec_priv { - uint8_t eld[MAX_ELD_BYTES]; - struct snd_pcm_chmap *chmap_info; - unsigned int chmap_idx; -- unsigned long busy; -+ struct mutex lock; - }; - - static const struct snd_soc_dapm_widget hdmi_widgets[] = { -@@ -395,8 +395,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - int ret = 0; - -- ret = test_and_set_bit(0, &hcp->busy); -- if (ret) { -+ ret = mutex_trylock(&hcp->lock); -+ if (!ret) { - dev_err(dai->dev, "Only one simultaneous stream supported!\n"); - return -EINVAL; - } -@@ -424,7 +424,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, - - err: - /* Release the exclusive lock on error */ -- clear_bit(0, &hcp->busy); -+ mutex_unlock(&hcp->lock); - return ret; - } - -@@ -436,7 +436,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); - -- clear_bit(0, &hcp->busy); -+ mutex_unlock(&hcp->lock); - } - - static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, -@@ -773,6 +773,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) - return -ENOMEM; - - hcp->hcd = *hcd; -+ mutex_init(&hcp->lock); -+ - daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); - if (!daidrv) - return -ENOMEM; - -From f2e2fdf50f201f7dac844d78be70d94457c4b3af Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Wed, 3 Apr 2019 10:25:55 +0200 -Subject: [PATCH 176/249] WIP: drm: dw-hdmi-i2s: support more i2s modes - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 26 ++++++++++++++++--- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 6 +++-- - 2 files changed, 27 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -index 5cbb71a866d54..2b624cff541d7 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -@@ -44,9 +44,8 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, - u8 inputclkfs = 0; - - /* it cares I2S only */ -- if ((fmt->fmt != HDMI_I2S) || -- (fmt->bit_clk_master | fmt->frame_clk_master)) { -- dev_err(dev, "unsupported format/settings\n"); -+ if (fmt->bit_clk_master | fmt->frame_clk_master) { -+ dev_err(dev, "unsupported clock settings\n"); - return -EINVAL; - } - -@@ -63,6 +62,27 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, - break; - } - -+ switch (fmt->fmt) { -+ case HDMI_I2S: -+ conf1 |= HDMI_AUD_CONF1_MODE_I2S; -+ break; -+ case HDMI_RIGHT_J: -+ conf1 |= HDMI_AUD_CONF1_MODE_RIGHT_J; -+ break; -+ case HDMI_LEFT_J: -+ conf1 |= HDMI_AUD_CONF1_MODE_LEFT_J; -+ break; -+ case HDMI_DSP_A: -+ conf1 |= HDMI_AUD_CONF1_MODE_BURST_1; -+ break; -+ case HDMI_DSP_B: -+ conf1 |= HDMI_AUD_CONF1_MODE_BURST_2; -+ break; -+ default: -+ dev_err(dev, "unsupported format\n"); -+ return -EINVAL; -+ } -+ - dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); - - hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -index 3f3c616eba97b..6ff14dcfc6842 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -@@ -873,8 +873,10 @@ enum { - - /* AUD_CONF1 field values */ - HDMI_AUD_CONF1_MODE_I2S = 0x00, -- HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02, -- HDMI_AUD_CONF1_MODE_LEFT_J = 0x04, -+ HDMI_AUD_CONF1_MODE_RIGHT_J = 0x20, -+ HDMI_AUD_CONF1_MODE_LEFT_J = 0x40, -+ HDMI_AUD_CONF1_MODE_BURST_1 = 0x60, -+ HDMI_AUD_CONF1_MODE_BURST_2 = 0x80, - HDMI_AUD_CONF1_WIDTH_16 = 0x10, - HDMI_AUD_CONF1_WIDTH_24 = 0x18, - - -From aae89bc725a9b97722704df5ac9aadcee8793d68 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Wed, 3 Apr 2019 10:28:57 +0200 -Subject: [PATCH 177/249] WIP: drm: dw-hdmi-i2s: support 4*2 channels - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -index 2b624cff541d7..cdb1480f5975f 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -@@ -139,7 +139,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) - - pdata.ops = &dw_hdmi_i2s_ops; - pdata.i2s = 1; -- pdata.max_i2s_channels = 6; -+ pdata.max_i2s_channels = 8; - pdata.data = audio; - - memset(&pdevinfo, 0, sizeof(pdevinfo)); - -From 4c4ad3a418008b1f1f011994333348eec4d541d3 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 17 Jan 2019 19:16:42 +0100 -Subject: [PATCH 178/249] WIP: arm64: dts: meson: g12a: add mhu mailboxes - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 8822acab23315..8d10c8da37359 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -1409,6 +1409,16 @@ - clock-names = "xtal"; - }; - }; -+ -+ mailbox: mailbox@404 { -+ compatible = "amlogic,meson-gx-mhu", -+ "amlogic,meson-gxbb-mhu"; -+ reg = <0 0x404 0 0x4c>; -+ interrupts = , -+ , -+ ; -+ #mbox-cells = <1>; -+ }; - }; - - pdm: audio-controller@40000 { - -From 6ca47184cad55333fad80ebdd32b4a7d22918f1a Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 17 Jan 2019 19:17:25 +0100 -Subject: [PATCH 179/249] WIP: arm64: dts: meson: g12a: add sram shared memory - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 8d10c8da37359..02596a5e10ac2 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -2151,6 +2151,24 @@ - }; - }; - -+ sram: sram@fffc0000 { -+ compatible = "mmio-sram"; -+ reg = <0x0 0xfffc0000 0x0 0x20000>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0 0x0 0xfffc0000 0x20000>; -+ -+ cpu_scp_lpri: scp-shmem@13000 { -+ compatible = "amlogic,meson-axg-scp-shmem"; -+ reg = <0x13000 0x400>; -+ }; -+ -+ cpu_scp_hpri: scp-shmem@13400 { -+ compatible = "amlogic,meson-axg-scp-shmem"; -+ reg = <0x13400 0x400>; -+ }; -+ }; -+ - gic: interrupt-controller@ffc01000 { - compatible = "arm,gic-400"; - reg = <0x0 0xffc01000 0 0x1000>, - -From 393b7130d5109f7aea9bf7ea1403d5a91c7915c7 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Wed, 5 Sep 2018 10:58:27 +0200 -Subject: [PATCH 180/249] WIP: arm64: dts: meson: add dwmac-3.710 to ethmac - compatible list - -Adding snps,dwmac-3.710 will trigger some needed work around in the driver - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 3 ++- - arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 2 +- - 2 files changed, 3 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi -index 34704fecf7566..c71c0e5834c61 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi -@@ -171,7 +171,8 @@ - ranges; - - ethmac: ethernet@ff3f0000 { -- compatible = "amlogic,meson-axg-dwmac", "snps,dwmac"; -+ compatible = "amlogic,meson-axg-dwmac", "snps,dwmac-3.710", -+ "snps,dwmac"; - reg = <0x0 0xff3f0000 0x0 0x10000 - 0x0 0xff634540 0x0 0x8>; - interrupts = ; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -index 6772709b9e195..b7240ec8a4f5b 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -@@ -486,7 +486,7 @@ - }; - - ethmac: ethernet@c9410000 { -- compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac"; -+ compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac-3.710", "snps,dwmac"; - reg = <0x0 0xc9410000 0x0 0x10000 - 0x0 0xc8834540 0x0 0x4>; - interrupts = ; - -From 2a7e1811c77f83c881828b67cdfd027af5d92e88 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 29 Jan 2019 16:19:53 +0100 -Subject: [PATCH 181/249] WIP: arm64: dts: g12a: add mailbox clock gate - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 02596a5e10ac2..f39314960c9d5 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -1417,6 +1417,8 @@ - interrupts = , - , - ; -+ clocks = <&clkc_AO CLKID_AO_MAILBOX>; -+ clock-names = "pclk"; - #mbox-cells = <1>; - }; - }; - -From 8464c72157428ce1eaeffe514edc0e080698e476 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 29 Jan 2019 16:24:34 +0100 -Subject: [PATCH 182/249] WIP: arm64: dts: meson: g12a: add uart_ao reset - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index f39314960c9d5..ea71fbe3928c4 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -2075,6 +2076,7 @@ - interrupts = ; - clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; -+ reset = <&clkc_AO RESET_AO_UART>; - status = "disabled"; - }; - -@@ -2085,6 +2087,7 @@ - interrupts = ; - clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; - clock-names = "xtal", "pclk", "baud"; -+ reset = <&clkc_AO RESET_AO_UART2>; - status = "disabled"; - }; - - -From 806e7edd91c5f5fafde071a17b7c62ae2302741f Mon Sep 17 00:00:00 2001 -From: Zheng Yang -Date: Tue, 27 Jun 2017 16:22:01 +0800 -Subject: [PATCH 183/249] WIP: drm/bridge: dw-hdmi: support dynamically get - input/out color info - -To get input/output bus_format/enc_format dynamically, this patch -introduce following functions in plat_data: - - get_input_bus_format - - get_output_bus_format - - get_enc_in_encoding - - get_enc_out_encoding - -Signed-off-by: Zheng Yang -Signed-off-by: Neil Armstrong -Tested-by: Heiko Stuebner ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++++++------ - include/drm/bridge/dw_hdmi.h | 5 ++++ - 2 files changed, 26 insertions(+), 7 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index ab7968c8f6a29..6fe73f1669734 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1841,6 +1841,7 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) - static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - { - int ret; -+ void *data = hdmi->plat_data->phy_data; - - hdmi_disable_overflow_interrupts(hdmi); - -@@ -1852,10 +1853,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic); - } - -- if ((hdmi->vic == 6) || (hdmi->vic == 7) || -- (hdmi->vic == 21) || (hdmi->vic == 22) || -- (hdmi->vic == 2) || (hdmi->vic == 3) || -- (hdmi->vic == 17) || (hdmi->vic == 18)) -+ if (hdmi->plat_data->get_enc_out_encoding) -+ hdmi->hdmi_data.enc_out_encoding = -+ hdmi->plat_data->get_enc_out_encoding(data); -+ else if ((hdmi->vic == 6) || (hdmi->vic == 7) || -+ (hdmi->vic == 21) || (hdmi->vic == 22) || -+ (hdmi->vic == 2) || (hdmi->vic == 3) || -+ (hdmi->vic == 17) || (hdmi->vic == 18)) - hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601; - else - hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709; -@@ -1864,21 +1868,31 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; - - /* TOFIX: Get input format from plat data or fallback to RGB888 */ -- if (hdmi->plat_data->input_bus_format) -+ if (hdmi->plat_data->get_input_bus_format) -+ hdmi->hdmi_data.enc_in_bus_format = -+ hdmi->plat_data->get_input_bus_format(data); -+ else if (hdmi->plat_data->input_bus_format) - hdmi->hdmi_data.enc_in_bus_format = - hdmi->plat_data->input_bus_format; - else - hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - - /* TOFIX: Get input encoding from plat data or fallback to none */ -- if (hdmi->plat_data->input_bus_encoding) -+ if (hdmi->plat_data->get_enc_in_encoding) -+ hdmi->hdmi_data.enc_in_encoding = -+ hdmi->plat_data->get_enc_in_encoding(data); -+ else if (hdmi->plat_data->input_bus_encoding) - hdmi->hdmi_data.enc_in_encoding = - hdmi->plat_data->input_bus_encoding; - else - hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT; - - /* TOFIX: Default to RGB888 output format */ -- hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; -+ if (hdmi->plat_data->get_output_bus_format) -+ hdmi->hdmi_data.enc_out_bus_format = -+ hdmi->plat_data->get_output_bus_format(data); -+ else -+ hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - - hdmi->hdmi_data.pix_repet_factor = 0; - hdmi->hdmi_data.hdcp_enable = 0; -diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h -index 66e70770cce5d..d506df2382de6 100644 ---- a/include/drm/bridge/dw_hdmi.h -+++ b/include/drm/bridge/dw_hdmi.h -@@ -144,6 +144,11 @@ struct dw_hdmi_plat_data { - int (*configure_phy)(struct dw_hdmi *hdmi, - const struct dw_hdmi_plat_data *pdata, - unsigned long mpixelclock); -+ -+ unsigned long (*get_input_bus_format)(void *data); -+ unsigned long (*get_output_bus_format)(void *data); -+ unsigned long (*get_enc_in_encoding)(void *data); -+ unsigned long (*get_enc_out_encoding)(void *data); - }; - - struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, - -From 7305124553c8448bd76a2b5a6add3792831af27c Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 14 Nov 2018 17:39:46 +0100 -Subject: [PATCH 184/249] WIP: drm/bridge: dw-hdmi: allow ycbcr420 modes for >= - 0x200a - -Now the DW-HDMI Controller supports the HDMI2.0 modes, enable support -for these modes in the connector if the platform supports them. -We limit these modes to DW-HDMI IP version >= 0x200a which -are designed to support HDMI2.0 display modes. - -Signed-off-by: Neil Armstrong -Tested-by: Heiko Stuebner ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++++ - include/drm/bridge/dw_hdmi.h | 1 + - 2 files changed, 7 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 6fe73f1669734..c68b6ed1bb35e 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2643,6 +2643,12 @@ __dw_hdmi_probe(struct platform_device *pdev, - if (hdmi->phy.ops->setup_hpd) - hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); - -+ if (hdmi->version >= 0x200a) -+ hdmi->connector.ycbcr_420_allowed = -+ hdmi->plat_data->ycbcr_420_allowed; -+ else -+ hdmi->connector.ycbcr_420_allowed = false; -+ - memset(&pdevinfo, 0, sizeof(pdevinfo)); - pdevinfo.parent = dev; - pdevinfo.id = PLATFORM_DEVID_AUTO; -diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h -index d506df2382de6..ede8bff9fffc5 100644 ---- a/include/drm/bridge/dw_hdmi.h -+++ b/include/drm/bridge/dw_hdmi.h -@@ -130,6 +130,7 @@ struct dw_hdmi_plat_data { - const struct drm_display_mode *mode); - unsigned long input_bus_format; - unsigned long input_bus_encoding; -+ bool ycbcr_420_allowed; - - /* Vendor PHY support */ - const struct dw_hdmi_phy_ops *phy_ops; - -From 581841d4b664a7d7cd7ded52f409a6c2dcf8cb1b Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 15 Nov 2018 16:41:23 +0100 -Subject: [PATCH 185/249] WIP: drm/meson: Add YUV420 output support - -This patch adds support for the YUV420 output from the Amlogic Meson SoCs -Video Processing Unit to the HDMI Controller. - -The YUV420 is obtained by generating a YUV444 pixel stream like -the classic HDMI display modes, but then the Video Encoder output -can be configured to down-sample the YUV444 pixel stream to a YUV420 -stream. -In addition if pixel stream down-sampling, the Y Cb Cr components must -also be mapped differently to align with the HDMI2.0 specifications. - -This mode needs a different clock generation scheme since the TMDS PHY -clock must match the 10x ration with the YUV420 pixel clock, but -the video encoder must run at 2x the pixel clock. - -This patch adds the TMDS PHY clock value in all the video clock setup -in order to better support these specific uses cases and switch -to the Common Clock framework for clocks handling in the future. - -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/meson/meson_dw_hdmi.c | 114 ++++++++++++++++++++---- - drivers/gpu/drm/meson/meson_vclk.c | 93 ++++++++++++++----- - drivers/gpu/drm/meson/meson_vclk.h | 7 +- - drivers/gpu/drm/meson/meson_venc.c | 6 +- - drivers/gpu/drm/meson/meson_venc.h | 11 +++ - drivers/gpu/drm/meson/meson_venc_cvbs.c | 3 +- - 6 files changed, 188 insertions(+), 46 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c -index 779da21143b9b..0d09f067d689a 100644 ---- a/drivers/gpu/drm/meson/meson_dw_hdmi.c -+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c -@@ -159,6 +159,8 @@ struct meson_dw_hdmi { - struct regulator *hdmi_supply; - u32 irq_stat; - struct dw_hdmi *hdmi; -+ unsigned long input_bus_format; -+ unsigned long output_bus_format; - }; - #define encoder_to_meson_dw_hdmi(x) \ - container_of(x, struct meson_dw_hdmi, encoder) -@@ -308,6 +310,10 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, - struct meson_drm *priv = dw_hdmi->priv; - unsigned int pixel_clock = mode->clock; - -+ /* For 420, pixel clock is half unlike venc clock */ -+ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) -+ pixel_clock /= 2; -+ - if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || - dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) { - if (pixel_clock >= 371250) { -@@ -383,25 +389,36 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, - { - struct meson_drm *priv = dw_hdmi->priv; - int vic = drm_match_cea_mode(mode); -+ unsigned int phy_freq; - unsigned int vclk_freq; - unsigned int venc_freq; - unsigned int hdmi_freq; - - vclk_freq = mode->clock; - -+ /* For 420, pixel clock is half unlike venc clock */ -+ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) -+ vclk_freq /= 2; -+ -+ /* TMDS clock is pixel_clock * 10 */ -+ phy_freq = vclk_freq * 10; -+ - if (!vic) { -- meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq, -- vclk_freq, vclk_freq, false); -+ meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq, -+ vclk_freq, vclk_freq, vclk_freq, false); - return; - } - -+ /* 480i/576i needs global pixel doubling */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - vclk_freq *= 2; - - venc_freq = vclk_freq; - hdmi_freq = vclk_freq; - -- if (meson_venc_hdmi_venc_repeat(vic)) -+ /* VENC double pixels for 1080i, 720p and YUV420 modes */ -+ if (meson_venc_hdmi_venc_repeat(vic) || -+ dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) - venc_freq *= 2; - - vclk_freq = max(venc_freq, hdmi_freq); -@@ -409,11 +426,11 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - venc_freq /= 2; - -- DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n", -- vclk_freq, venc_freq, hdmi_freq, -+ DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n", -+ phy_freq, vclk_freq, venc_freq, hdmi_freq, - priv->venc.hdmi_use_enci); - -- meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq, -+ meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq, - venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); - } - -@@ -446,8 +463,9 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, - /* Enable normal output to PHY */ - dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); - -- /* TMDS pattern setup (TOFIX Handle the YUV420 case) */ -- if (mode->clock > 340000) { -+ /* TMDS pattern setup */ -+ if (mode->clock > 340000 && -+ dw_hdmi->input_bus_format == MEDIA_BUS_FMT_YUV8_1X24) { - dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, - 0); - dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, -@@ -622,6 +640,8 @@ dw_hdmi_mode_valid(struct drm_connector *connector, - const struct drm_display_mode *mode) - { - struct meson_drm *priv = connector->dev->dev_private; -+ bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; -+ unsigned int phy_freq; - unsigned int vclk_freq; - unsigned int venc_freq; - unsigned int hdmi_freq; -@@ -630,9 +650,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, - - DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); - -- /* If sink max TMDS clock, we reject the mode */ -+ /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ - if (connector->display_info.max_tmds_clock && -- mode->clock > connector->display_info.max_tmds_clock) -+ mode->clock > connector->display_info.max_tmds_clock && -+ !drm_mode_is_420_only(&connector->display_info, mode) && -+ !drm_mode_is_420_also(&connector->display_info, mode)) - return MODE_BAD; - - /* Check against non-VIC supported modes */ -@@ -648,6 +670,15 @@ dw_hdmi_mode_valid(struct drm_connector *connector, - - vclk_freq = mode->clock; - -+ /* For 420, pixel clock is half unlike venc clock */ -+ if (drm_mode_is_420_only(&connector->display_info, mode) || -+ (!is_hdmi2_sink && -+ drm_mode_is_420_also(&connector->display_info, mode))) -+ vclk_freq /= 2; -+ -+ /* TMDS clock is pixel_clock * 10 */ -+ phy_freq = vclk_freq * 10; -+ - /* 480i/576i needs global pixel doubling */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - vclk_freq *= 2; -@@ -655,8 +686,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, - venc_freq = vclk_freq; - hdmi_freq = vclk_freq; - -- /* VENC double pixels for 1080i and 720p modes */ -- if (meson_venc_hdmi_venc_repeat(vic)) -+ /* VENC double pixels for 1080i, 720p and YUV420 modes */ -+ if (meson_venc_hdmi_venc_repeat(vic) || -+ drm_mode_is_420_only(&connector->display_info, mode) || -+ (!is_hdmi2_sink && -+ drm_mode_is_420_also(&connector->display_info, mode))) - venc_freq *= 2; - - vclk_freq = max(venc_freq, hdmi_freq); -@@ -664,10 +698,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector, - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - venc_freq /= 2; - -- dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, -- vclk_freq, venc_freq, hdmi_freq); -+ dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", -+ __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); - -- return meson_vclk_vic_supported_freq(vclk_freq); -+ return meson_vclk_vic_supported_freq(phy_freq, vclk_freq); - } - - /* Encoder */ -@@ -685,6 +719,21 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) - { -+ struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); -+ struct drm_display_info *info = &conn_state->connector->display_info; -+ struct drm_display_mode *mode = &crtc_state->mode; -+ bool is_hdmi2_sink = -+ conn_state->connector->display_info.hdmi.scdc.supported; -+ -+ if (drm_mode_is_420_only(info, mode) || -+ (!is_hdmi2_sink && drm_mode_is_420_also(info, mode))) { -+ dw_hdmi->input_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; -+ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; -+ } else { -+ dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; -+ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24; -+ } -+ - return 0; - } - -@@ -722,17 +771,29 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, - struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); - struct meson_drm *priv = dw_hdmi->priv; - int vic = drm_match_cea_mode(mode); -+ unsigned int ycrcb_map = MESON_VENC_MAP_CB_Y_CR; -+ bool yuv420_mode = false; - - DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); - -+ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { -+ ycrcb_map = MESON_VENC_MAP_CR_Y_CB; -+ yuv420_mode = true; -+ } -+ - /* VENC + VENC-DVI Mode setup */ -- meson_venc_hdmi_mode_set(priv, vic, mode); -+ meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); - - /* VCLK Set clock */ - dw_hdmi_set_vclk(dw_hdmi, mode); - -- /* Setup YUV444 to HDMI-TX, no 10bit diphering */ -- writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); -+ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) -+ /* Setup YUV420 to HDMI-TX, no 10bit diphering */ -+ writel_relaxed(2 | (2 << 2), -+ priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); -+ else -+ /* Setup YUV444 to HDMI-TX, no 10bit diphering */ -+ writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); - } - - static const struct drm_encoder_helper_funcs -@@ -789,6 +850,20 @@ static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { - .dwc_write = dw_hdmi_g12a_dwc_write, - }; - -+static unsigned long meson_dw_hdmi_get_in_bus_format(void *data) -+{ -+ struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; -+ -+ return dw_hdmi->input_bus_format; -+} -+ -+static unsigned long meson_dw_hdmi_get_out_bus_format(void *data) -+{ -+ struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; -+ -+ return dw_hdmi->output_bus_format; -+} -+ - static bool meson_hdmi_connector_is_available(struct device *dev) - { - struct device_node *ep, *remote; -@@ -977,6 +1052,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, - dw_plat_data->phy_data = meson_dw_hdmi; - dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; - dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; -+ dw_plat_data->get_input_bus_format = meson_dw_hdmi_get_in_bus_format; -+ dw_plat_data->get_output_bus_format = meson_dw_hdmi_get_out_bus_format; -+ dw_plat_data->ycbcr_420_allowed = true; - - platform_set_drvdata(pdev, meson_dw_hdmi); - -diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c -index b39034745444a..44250eff8a3f4 100644 ---- a/drivers/gpu/drm/meson/meson_vclk.c -+++ b/drivers/gpu/drm/meson/meson_vclk.c -@@ -364,12 +364,17 @@ enum { - /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ - MESON_VCLK_HDMI_297000, - /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ -- MESON_VCLK_HDMI_594000 -+ MESON_VCLK_HDMI_594000, -+/* 2970 /1 /1 /1 /5 /1 => /1 /2 */ -+ MESON_VCLK_HDMI_594000_YUV420, - }; - - struct meson_vclk_params { -+ unsigned int pll_freq; -+ unsigned int phy_freq; -+ unsigned int vclk_freq; -+ unsigned int venc_freq; - unsigned int pixel_freq; -- unsigned int pll_base_freq; - unsigned int pll_od1; - unsigned int pll_od2; - unsigned int pll_od3; -@@ -377,8 +382,11 @@ struct meson_vclk_params { - unsigned int vclk_div; - } params[] = { - [MESON_VCLK_HDMI_ENCI_54000] = { -+ .pll_freq = 4320000, -+ .phy_freq = 270000, -+ .vclk_freq = 54000, -+ .venc_freq = 54000, - .pixel_freq = 54000, -- .pll_base_freq = 4320000, - .pll_od1 = 4, - .pll_od2 = 4, - .pll_od3 = 1, -@@ -386,8 +394,11 @@ struct meson_vclk_params { - .vclk_div = 1, - }, - [MESON_VCLK_HDMI_DDR_54000] = { -- .pixel_freq = 54000, -- .pll_base_freq = 4320000, -+ .pll_freq = 4320000, -+ .phy_freq = 270000, -+ .vclk_freq = 54000, -+ .venc_freq = 54000, -+ .pixel_freq = 27000, - .pll_od1 = 4, - .pll_od2 = 4, - .pll_od3 = 1, -@@ -395,8 +406,11 @@ struct meson_vclk_params { - .vclk_div = 1, - }, - [MESON_VCLK_HDMI_DDR_148500] = { -- .pixel_freq = 148500, -- .pll_base_freq = 2970000, -+ .pll_freq = 2970000, -+ .phy_freq = 742500, -+ .vclk_freq = 148500, -+ .venc_freq = 148500, -+ .pixel_freq = 74250, - .pll_od1 = 4, - .pll_od2 = 1, - .pll_od3 = 1, -@@ -404,8 +418,11 @@ struct meson_vclk_params { - .vclk_div = 1, - }, - [MESON_VCLK_HDMI_74250] = { -+ .pll_freq = 2970000, -+ .phy_freq = 742500, -+ .vclk_freq = 74250, -+ .venc_freq = 74250, - .pixel_freq = 74250, -- .pll_base_freq = 2970000, - .pll_od1 = 2, - .pll_od2 = 2, - .pll_od3 = 2, -@@ -413,8 +430,11 @@ struct meson_vclk_params { - .vclk_div = 1, - }, - [MESON_VCLK_HDMI_148500] = { -+ .pll_freq = 2970000, -+ .phy_freq = 1485000, -+ .vclk_freq = 148500, -+ .venc_freq = 148500, - .pixel_freq = 148500, -- .pll_base_freq = 2970000, - .pll_od1 = 1, - .pll_od2 = 2, - .pll_od3 = 2, -@@ -422,8 +442,11 @@ struct meson_vclk_params { - .vclk_div = 1, - }, - [MESON_VCLK_HDMI_297000] = { -+ .pll_freq = 5940000, -+ .phy_freq = 2970000, -+ .venc_freq = 297000, -+ .vclk_freq = 297000, - .pixel_freq = 297000, -- .pll_base_freq = 5940000, - .pll_od1 = 2, - .pll_od2 = 1, - .pll_od3 = 1, -@@ -431,14 +454,29 @@ struct meson_vclk_params { - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_594000] = { -+ .pll_freq = 5940000, -+ .phy_freq = 5940000, -+ .venc_freq = 594000, -+ .vclk_freq = 594000, - .pixel_freq = 594000, -- .pll_base_freq = 5940000, - .pll_od1 = 1, - .pll_od2 = 1, - .pll_od3 = 2, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 1, - }, -+ [MESON_VCLK_HDMI_594000_YUV420] = { -+ .pll_freq = 5940000, -+ .phy_freq = 2970000, -+ .venc_freq = 594000, -+ .vclk_freq = 594000, -+ .pixel_freq = 297000, -+ .pll_od1 = 2, -+ .pll_od2 = 1, -+ .pll_od3 = 1, -+ .vid_pll_div = VID_PLL_DIV_5, -+ .vclk_div = 1, -+ }, - { /* sentinel */ }, - }; - -@@ -696,6 +734,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv, - unsigned int od, m, frac, od1, od2, od3; - - if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) { -+ /* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */ - od3 = 1; - if (od < 4) { - od1 = 2; -@@ -718,21 +757,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv, - } - - enum drm_mode_status --meson_vclk_vic_supported_freq(unsigned int freq) -+meson_vclk_vic_supported_freq(unsigned int phy_freq, -+ unsigned int vclk_freq) - { - int i; - -- DRM_DEBUG_DRIVER("freq = %d\n", freq); -+ DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n", -+ phy_freq, vclk_freq); - - for (i = 0 ; params[i].pixel_freq ; ++i) { - DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n", - i, params[i].pixel_freq, - FREQ_1000_1001(params[i].pixel_freq)); -+ DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", -+ i, params[i].phy_freq, -+ FREQ_1000_1001(params[i].phy_freq/10)*10); - /* Match strict frequency */ -- if (freq == params[i].pixel_freq) -+ if (phy_freq == params[i].phy_freq && -+ vclk_freq == params[i].vclk_freq) - return MODE_OK; - /* Match 1000/1001 variant */ -- if (freq == FREQ_1000_1001(params[i].pixel_freq)) -+ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && -+ vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) - return MODE_OK; - } - -@@ -960,8 +1006,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, - } - - void meson_vclk_setup(struct meson_drm *priv, unsigned int target, -- unsigned int vclk_freq, unsigned int venc_freq, -- unsigned int dac_freq, bool hdmi_use_enci) -+ unsigned int phy_freq, unsigned int vclk_freq, -+ unsigned int venc_freq, unsigned int dac_freq, -+ bool hdmi_use_enci) - { - bool vic_alternate_clock = false; - unsigned int freq; -@@ -980,7 +1027,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, - * - venc_div = 1 - * - encp encoder - */ -- meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, -+ meson_vclk_set(priv, phy_freq, 0, 0, 0, - VID_PLL_DIV_5, 2, 1, 1, false, false); - return; - } -@@ -1002,9 +1049,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, - } - - for (freq = 0 ; params[freq].pixel_freq ; ++freq) { -- if (vclk_freq == params[freq].pixel_freq || -- vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) { -- if (vclk_freq != params[freq].pixel_freq) -+ if ((phy_freq == params[freq].phy_freq || -+ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && -+ (vclk_freq == params[freq].vclk_freq || -+ vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { -+ if (vclk_freq != params[freq].vclk_freq) - vic_alternate_clock = true; - else - vic_alternate_clock = false; -@@ -1033,7 +1082,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, - return; - } - -- meson_vclk_set(priv, params[freq].pll_base_freq, -+ meson_vclk_set(priv, params[freq].pll_freq, - params[freq].pll_od1, params[freq].pll_od2, - params[freq].pll_od3, params[freq].vid_pll_div, - params[freq].vclk_div, hdmi_tx_div, venc_div, -diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h -index 4bd8752da02ab..c4d19ddfcd790 100644 ---- a/drivers/gpu/drm/meson/meson_vclk.h -+++ b/drivers/gpu/drm/meson/meson_vclk.h -@@ -33,10 +33,11 @@ enum { - enum drm_mode_status - meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); - enum drm_mode_status --meson_vclk_vic_supported_freq(unsigned int freq); -+meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq); - - void meson_vclk_setup(struct meson_drm *priv, unsigned int target, -- unsigned int vclk_freq, unsigned int venc_freq, -- unsigned int dac_freq, bool hdmi_use_enci); -+ unsigned int phy_freq, unsigned int vclk_freq, -+ unsigned int venc_freq, unsigned int dac_freq, -+ bool hdmi_use_enci); - - #endif /* __MESON_VCLK_H */ -diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c -index 6faca7313339e..5460c4439612c 100644 ---- a/drivers/gpu/drm/meson/meson_venc.c -+++ b/drivers/gpu/drm/meson/meson_venc.c -@@ -958,6 +958,8 @@ bool meson_venc_hdmi_venc_repeat(int vic) - EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat); - - void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, -+ unsigned int ycrcb_map, -+ bool yuv420_mode, - struct drm_display_mode *mode) - { - union meson_hdmi_venc_mode *vmode = NULL; -@@ -1508,8 +1510,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, - writel_relaxed((use_enci ? 1 : 2) | - (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) | - (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) | -- 4 << 5 | -- (venc_repeat ? 1 << 8 : 0) | -+ (ycrcb_map << 5) | -+ (venc_repeat || yuv420_mode ? 1 << 8 : 0) | - (hdmi_repeat ? 1 << 12 : 0), - priv->io_base + _REG(VPU_HDMI_SETTING)); - -diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h -index 97eaebbfa0c4a..5580bf38e3812 100644 ---- a/drivers/gpu/drm/meson/meson_venc.h -+++ b/drivers/gpu/drm/meson/meson_venc.h -@@ -33,6 +33,15 @@ enum { - MESON_VENC_MODE_HDMI, - }; - -+enum { -+ MESON_VENC_MAP_CR_Y_CB = 0, -+ MESON_VENC_MAP_Y_CB_CR, -+ MESON_VENC_MAP_Y_CR_CB, -+ MESON_VENC_MAP_CB_CR_Y, -+ MESON_VENC_MAP_CB_Y_CR, -+ MESON_VENC_MAP_CR_CB_Y, -+}; -+ - struct meson_cvbs_enci_mode { - unsigned int mode_tag; - unsigned int hso_begin; /* HSO begin position */ -@@ -70,6 +79,8 @@ extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc; - void meson_venci_cvbs_mode_set(struct meson_drm *priv, - struct meson_cvbs_enci_mode *mode); - void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, -+ unsigned int ycrcb_map, -+ bool yuv420_mode, - struct drm_display_mode *mode); - unsigned int meson_venci_get_field(struct meson_drm *priv); - -diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c -index 2c5341c881c47..c1bbc601cf132 100644 ---- a/drivers/gpu/drm/meson/meson_venc_cvbs.c -+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c -@@ -218,7 +218,8 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, - /* Setup 27MHz vclk2 for ENCI and VDAC */ - meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, - MESON_VCLK_CVBS, MESON_VCLK_CVBS, -- MESON_VCLK_CVBS, true); -+ MESON_VCLK_CVBS, MESON_VCLK_CVBS, -+ true); - break; - } - } - -From 2cec5da66ce308bdaf1c9aef4c13df56857e281e Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Sun, 18 Nov 2018 14:06:11 +0100 -Subject: [PATCH 186/249] WIP: drm/meson: Output in YUV444 if sink supports it - -With the YUV420 handling, we can dynamically setup the HDMI output -pixel format depending on the mode and connector info. -So now, we can output in YUV444, which is the native video pipeline -format, directly to the HDMI Sink if it's supported without -necessarily involving the HDMI Controller CSC. - -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/meson/meson_dw_hdmi.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c -index 0d09f067d689a..feafb896ecaee 100644 ---- a/drivers/gpu/drm/meson/meson_dw_hdmi.c -+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c -@@ -731,7 +731,10 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder, - dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; - } else { - dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; -- dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24; -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_YUV8_1X24; -+ else -+ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - } - - return 0; - -From f0ab196aa42e72addba4db147c842ba3d4381548 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 17 Jan 2019 19:00:11 +0100 -Subject: [PATCH 187/249] WIP: arm64: dts: meson: g12a: add SDIO pins - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 23 +++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index ea71fbe3928c4..b2f9087ab1c7b 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -867,6 +867,29 @@ - }; - }; - -+ sdio_pins: sdio { -+ mux { -+ groups = "sdio_d0", -+ "sdio_d1", -+ "sdio_d2", -+ "sdio_d3", -+ "sdio_cmd", -+ "sdio_clk"; -+ function = "sdio"; -+ bias-disable; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ -+ sdio_clk_gate_pins: sdio_clk_gate { -+ mux { -+ groups = "GPIOX_4"; -+ function = "gpio_periphs"; -+ bias-pull-down; -+ drive-strength-microamp = <4000>; -+ }; -+ }; -+ - spdif_in_a10_pins: spdif-in-a10 { - mux { - groups = "spdif_in_a10"; - -From 66f026a11e8c8e3777bc44b876d0bf45a34f4ba6 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 21 Jan 2019 21:37:52 +0100 -Subject: [PATCH 188/249] WIP: arm64: dts: meson: g12a: add SDIO controller - -The Amlogic G12A SDIO Controller has a bug preventing direct DDR access, -mark this specific controller with the amlogic,ddr-access-quirk property. - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index b2f9087ab1c7b..600f7ce6b8c76 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -2318,6 +2318,19 @@ - }; - }; - -+ sd_emmc_a: sd@ffe03000 { -+ compatible = "amlogic,meson-axg-mmc"; -+ reg = <0x0 0xffe03000 0x0 0x800>; -+ interrupts = ; -+ status = "disabled"; -+ clocks = <&clkc CLKID_SD_EMMC_A>, -+ <&clkc CLKID_SD_EMMC_A_CLK0>, -+ <&clkc CLKID_FCLK_DIV2>; -+ clock-names = "core", "clkin0", "clkin1"; -+ resets = <&reset RESET_SD_EMMC_A>; -+ amlogic,ddr-access-quirk; -+ }; -+ - sd_emmc_b: sd@ffe05000 { - compatible = "amlogic,meson-axg-mmc"; - reg = <0x0 0xffe05000 0x0 0x800>; - -From f457f2387361601ed1da1a2f622af6ae397390bd Mon Sep 17 00:00:00 2001 -From: Guillaume La Roque -Date: Mon, 28 Jan 2019 15:45:37 +0000 -Subject: [PATCH 189/249] WIP: arm64: dts: meson: x96: add sd and emmc - -Signed-off-by: Guillaume La Roque ---- - .../boot/dts/amlogic/meson-g12a-x96-max.dts | 40 +++++++++++++++++++ - 1 file changed, 40 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 5cdc263b03e67..69aae6c03dc55 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -45,6 +45,11 @@ - }; - }; - -+ emmc_pwrseq: emmc-pwrseq { -+ compatible = "mmc-pwrseq-emmc"; -+ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; -+ }; -+ - flash_1v8: regulator-flash_1v8 { - compatible = "regulator-fixed"; - regulator-name = "FLASH_1V8"; -@@ -172,3 +177,38 @@ - status = "okay"; - dr_mode = "host"; - }; -+ -+/* SD card */ -+&sd_emmc_b { -+ status = "okay"; -+ pinctrl-0 = <&sdcard_c_pins>; -+ pinctrl-1 = <&sdcard_clk_gate_c_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ max-frequency = <100000000>; -+ disable-wp; -+ -+ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddao_3v3>; -+}; -+ -+/* eMMC */ -+&sd_emmc_c { -+ status = "okay"; -+ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; -+ pinctrl-1 = <&emmc_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ max-frequency = <100000000>; -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&emmc_pwrseq>; -+ vmmc-supply = <&vcc_3v3>; -+ vqmmc-supply = <&flash_1v8>; -+}; - -From fc11f8b165ab91f60345f4c047083cdab84ca7f7 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 8 Feb 2019 14:53:35 +0100 -Subject: [PATCH 190/249] WIP: arm64: dts: meson-g12a-x96-max: Enable Wifi SDIO - Module - ---- - .../boot/dts/amlogic/meson-g12a-x96-max.dts | 48 +++++++++++++++++++ - 1 file changed, 48 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 69aae6c03dc55..8b263ec1e7a2a 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -50,6 +50,13 @@ - reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; - }; - -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; -+ clocks = <&wifi32k>; -+ clock-names = "ext_clock"; -+ }; -+ - flash_1v8: regulator-flash_1v8 { - compatible = "regulator-fixed"; - regulator-name = "FLASH_1V8"; -@@ -114,6 +121,13 @@ - vin-supply = <&dc_in>; - regulator-always-on; - }; -+ -+ wifi32k: wifi32k { -+ compatible = "pwm-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <32768>; -+ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ -+ }; - }; - - &cec_AO { -@@ -155,6 +169,12 @@ - pinctrl-names = "default"; - }; - -+&pwm_ef { -+ status = "okay"; -+ pinctrl-0 = <&pwm_e_pins>; -+ pinctrl-names = "default"; -+}; -+ - &uart_A { - status = "okay"; - pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; -@@ -178,6 +198,34 @@ - dr_mode = "host"; - }; - -+/* SDIO */ -+&sd_emmc_a { -+ status = "okay"; -+ pinctrl-0 = <&sdio_pins>; -+ pinctrl-1 = <&sdio_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ sd-uhs-sdr50; -+ max-frequency = <100000000>; -+ -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&sdio_pwrseq>; -+ -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddao_1v8>; -+ -+ brcmf: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ }; -+}; -+ - /* SD card */ - &sd_emmc_b { - status = "okay"; - -From 23aaa150078b4bf95bf223c7f46ba78650632fb9 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 8 Feb 2019 15:41:15 +0100 -Subject: [PATCH 191/249] WIP: arm64: dts: meson-g12a-x96-max: Add Gigabit - Ethernet Support - ---- - .../boot/dts/amlogic/meson-g12a-x96-max.dts | 22 +++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 8b263ec1e7a2a..648b7deed22d7 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -15,6 +15,7 @@ - - aliases { - serial0 = &uart_AO; -+ ethernet0 = ðmac; - }; - chosen { - stdout-path = "serial0:115200n8"; -@@ -169,6 +170,27 @@ - pinctrl-names = "default"; - }; - -+&ext_mdio { -+ external_phy: ethernet-phy@0 { -+ compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ max-speed = <1000>; -+ eee-broken-1000t; -+ }; -+}; -+ -+ðmac { -+ pinctrl-0 = <ð_rmii_pins>, <ð_rgmii_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ phy-mode = "rgmii"; -+ phy-handle = <&external_phy>; -+ amlogic,tx-delay-ns = <2>; -+ snps,reset-gpio = <&gpio GPIOZ_14 0>; -+ snps,reset-delays-us = <0 10000 1000000>; -+ snps,reset-active-low; -+}; -+ - &pwm_ef { - status = "okay"; - pinctrl-0 = <&pwm_e_pins>; - -From 960ae664cc478ceb5268d059595ea6217d802587 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 12 Feb 2019 11:56:58 +0100 -Subject: [PATCH 192/249] WIP: arm64: dts: meson-g12a-sei510: Add base - peripherals - -* SDIO + WiFi -* IR ---- - .../boot/dts/amlogic/meson-g12a-sei510.dts | 54 +++++++++++++++++++ - 1 file changed, 54 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 9f0b8005877ae..530c601fc9cb4 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -128,6 +128,20 @@ - no-map; - }; - }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; -+ clocks = <&wifi32k>; -+ clock-names = "ext_clock"; -+ }; -+ -+ wifi32k: wifi32k { -+ compatible = "pwm-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <32768>; -+ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ -+ }; - }; - - &cec_AO { -@@ -174,11 +188,51 @@ - pinctrl-names = "default"; - }; - -+&ir { -+ status = "okay"; -+ pinctrl-0 = <&remote_input_ao_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&pwm_ef { -+ status = "okay"; -+ pinctrl-0 = <&pwm_e_pins>; -+ pinctrl-names = "default"; -+}; -+ - &saradc { - status = "okay"; - vref-supply = <&vddio_ao1v8>; - }; - -+/* SDIO */ -+&sd_emmc_a { -+ status = "okay"; -+ pinctrl-0 = <&sdio_pins>; -+ pinctrl-1 = <&sdio_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ sd-uhs-sdr50; -+ max-frequency = <100000000>; -+ -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&sdio_pwrseq>; -+ -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddio_ao1v8>; -+ -+ brcmf: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ }; -+}; -+ - /* SD card */ - &sd_emmc_b { - status = "okay"; - -From 204117d03f17338f984722a64d420106f8db38f8 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 26 Feb 2019 11:21:41 +0100 -Subject: [PATCH 193/249] WIP: arm64: dts: meson-g12a: add missing - drive-strength hdmi ddc - ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 600f7ce6b8c76..51d2b2ac2acf4 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -328,6 +328,7 @@ - "hdmitx_sck"; - function = "hdmitx"; - bias-disable; -+ drive-strength-microamp = <4000>; - }; - }; - - -From 358c41ce27d41cf63d59beb0617c6979b1bcf518 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 12 Mar 2019 16:50:21 +0100 -Subject: [PATCH 194/249] WIP: arm64: dts: meson: g12a: add drive strength for - eth pins - ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 51d2b2ac2acf4..9fc47fd76c180 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -264,6 +264,7 @@ - "eth_txd0", - "eth_txd1"; - function = "eth"; -+ drive-strength-microamp = <4000>; - bias-disable; - }; - }; -@@ -276,6 +277,7 @@ - "eth_txd2_rgmii", - "eth_txd3_rgmii"; - function = "eth"; -+ drive-strength-microamp = <4000>; - bias-disable; - }; - }; - -From c6998477efba1921e0fbdf24ae5c2aad5289ca78 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 22 Feb 2019 16:39:33 +0100 -Subject: [PATCH 195/249] WIP: arm64: dts: meson-g12b-odroid-n2: Add - peripherals - -Add Ethernet, MMC, SDCard, IR & AO-CEC-B nodes. - -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 101 ++++++++++++++++++ - 1 file changed, 101 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts -index 0541fe0bbaea9..380b5cebb21df 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts -@@ -16,6 +16,7 @@ - - aliases { - serial0 = &uart_AO; -+ ethernet0 = ðmac; - }; - - chosen { -@@ -27,6 +28,11 @@ - reg = <0x0 0x0 0x0 0x40000000>; - }; - -+ emmc_pwrseq: emmc-pwrseq { -+ compatible = "mmc-pwrseq-emmc"; -+ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; -+ }; -+ - leds { - compatible = "gpio-leds"; - -@@ -37,6 +43,40 @@ - }; - }; - -+ tflash_vdd: regulator-tflash_vdd { -+ compatible = "regulator-fixed"; -+ -+ regulator-name = "TFLASH_VDD"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ -+ gpio = <&gpio_ao GPIOAO_8 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ }; -+ -+ tf_io: gpio-regulator-tf_io { -+ compatible = "regulator-gpio"; -+ -+ regulator-name = "TF_IO"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ -+ gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; -+ gpios-states = <0>; -+ -+ states = <3300000 0 -+ 1800000 1>; -+ }; -+ -+ flash_1v8: regulator-flash_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "FLASH_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ - main_12v: regulator-main_12v { - compatible = "regulator-fixed"; - regulator-name = "12V"; -@@ -138,6 +178,24 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&ext_mdio { -+ external_phy: ethernet-phy@0 { -+ compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ max-speed = <1000>; -+ eee-broken-1000t; -+ }; -+}; -+ -+ðmac { -+ pinctrl-0 = <ð_rmii_pins>, <ð_rgmii_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ phy-mode = "rgmii"; -+ phy-handle = <&external_phy>; -+ amlogic,tx-delay-ns = <2>; -+}; -+ - &gpio { - /* - * WARNING: The USB Hub on the Odroid-N2 needs a reset signal -@@ -166,6 +224,49 @@ - }; - }; - -+&ir { -+ status = "okay"; -+ pinctrl-0 = <&remote_input_ao_pins>; -+ pinctrl-names = "default"; -+}; -+ -+/* SD card */ -+&sd_emmc_b { -+ status = "okay"; -+ pinctrl-0 = <&sdcard_c_pins>; -+ pinctrl-1 = <&sdcard_clk_gate_c_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ max-frequency = <50000000>; -+ disable-wp; -+ -+ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; -+ vmmc-supply = <&tflash_vdd>; -+ vqmmc-supply = <&tf_io>; -+ -+}; -+ -+/* eMMC */ -+&sd_emmc_c { -+ status = "okay"; -+ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; -+ pinctrl-1 = <&emmc_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ max-frequency = <200000000>; -+ disable-wp; -+ -+ mmc-pwrseq = <&emmc_pwrseq>; -+ vmmc-supply = <&vcc_3v3>; -+ vqmmc-supply = <&flash_1v8>; -+}; -+ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From d814c70104c2d107794e1afde2c052b806c2fc31 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 13 Feb 2019 17:21:26 +0100 -Subject: [PATCH 196/249] WIP: arm64: dts: meson-g12a-sei510: add max98357a DAC - -The SEI510 board features a max98357a audio codec - -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 530c601fc9cb4..50d8ac55eed8a 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -32,6 +32,13 @@ - ethernet0 = ðmac; - }; - -+ mono_dac: audio-codec { -+ compatible = "maxim,max98357a"; -+ #sound-dai-cells = <0>; -+ sound-name-prefix = "U16"; -+ sdmode-gpios = <&gpio GPIOX_8 GPIO_ACTIVE_HIGH>; -+ }; -+ - chosen { - stdout-path = "serial0:115200n8"; - }; - -From dba98c740ece82f04e0a3a672a053a3c6a30422b Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Tue, 16 Apr 2019 10:35:09 +0200 -Subject: [PATCH 197/249] WIP: arm64: dts: meson: g12a: add tohdmitx - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 9fc47fd76c180..9fa4ef37d6243 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -1710,6 +1710,15 @@ - clock-names = "pclk", "mclk"; - status = "disabled"; - }; -+ -+ tohdmitx: audio-controller@744 { -+ compatible = "amlogic,g12a-tohdmitx"; -+ reg = <0x0 0x744 0x0 0x4>; -+ #sound-dai-cells = <1>; -+ sound-name-prefix = "TOHDMITX"; -+ clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; /* FIXME */ -+ status = "disabled"; -+ }; - }; - - usb3_pcie_phy: phy@46000 { - -From 4aa9ffaea6621ecd747118d1c502704c69a72fe2 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 18 Mar 2019 13:46:06 +0100 -Subject: [PATCH 198/249] WIP: arm64: dts: meson: u200: add audio support - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12a-u200.dts | 244 ++++++++++++++++++ - 1 file changed, 244 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -index 8551fbd4a488c..332a4b27174be 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts -@@ -18,6 +18,13 @@ - ethernet0 = ðmac; - }; - -+ spdif_dit: audio-codec-1 { -+ #sound-dai-cells = <0>; -+ compatible = "linux,spdif-dit"; -+ status = "okay"; -+ sound-name-prefix = "DIT"; -+ }; -+ - chosen { - stdout-path = "serial0:115200n8"; - }; -@@ -129,6 +136,155 @@ - regulator-always-on; - }; - -+ sound { -+ compatible = "amlogic,axg-sound-card"; -+ model = "G12A-U200"; -+ audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmout_c>, -+ <&tdmin_a>, <&tdmin_b>, <&tdmin_c>, -+ <&tdmin_lb>; -+ audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", -+ "TDMOUT_A IN 1", "FRDDR_B OUT 0", -+ "TDMOUT_A IN 2", "FRDDR_C OUT 0", -+ "TDM_A Playback", "TDMOUT_A OUT", -+ "TDMOUT_B IN 0", "FRDDR_A OUT 1", -+ "TDMOUT_B IN 1", "FRDDR_B OUT 1", -+ "TDMOUT_B IN 2", "FRDDR_C OUT 1", -+ "TDM_B Playback", "TDMOUT_B OUT", -+ "TDMOUT_C IN 0", "FRDDR_A OUT 2", -+ "TDMOUT_C IN 1", "FRDDR_B OUT 2", -+ "TDMOUT_C IN 2", "FRDDR_C OUT 2", -+ "TDM_C Playback", "TDMOUT_C OUT", -+ "SPDIFOUT IN 0", "FRDDR_A OUT 3", -+ "SPDIFOUT IN 1", "FRDDR_B OUT 3", -+ "SPDIFOUT IN 2", "FRDDR_C OUT 3", -+ "TDMIN_A IN 0", "TDM_A Capture", -+ "TDMIN_A IN 1", "TDM_B Capture", -+ "TDMIN_A IN 3", "TDM_A Loopback", -+ "TDMIN_A IN 4", "TDM_B Loopback", -+ "TDMIN_B IN 0", "TDM_A Capture", -+ "TDMIN_B IN 1", "TDM_B Capture", -+ "TDMIN_B IN 3", "TDM_A Loopback", -+ "TDMIN_B IN 4", "TDM_B Loopback", -+ "TDMIN_C IN 0", "TDM_A Capture", -+ "TDMIN_C IN 1", "TDM_B Capture", -+ "TDMIN_C IN 3", "TDM_A Loopback", -+ "TDMIN_C IN 4", "TDM_B Loopback", -+ "TDMIN_LB IN 3", "TDM_A Capture", -+ "TDMIN_LB IN 4", "TDM_B Capture", -+ "TDMIN_LB IN 0", "TDM_A Loopback", -+ "TDMIN_LB IN 1", "TDM_B Loopback", -+ "TODDR_A IN 0", "TDMIN_A OUT", -+ "TODDR_B IN 0", "TDMIN_A OUT", -+ "TODDR_C IN 0", "TDMIN_A OUT", -+ "TODDR_A IN 1", "TDMIN_B OUT", -+ "TODDR_B IN 1", "TDMIN_B OUT", -+ "TODDR_C IN 1", "TDMIN_B OUT", -+ "TODDR_A IN 2", "TDMIN_C OUT", -+ "TODDR_B IN 2", "TDMIN_C OUT", -+ "TODDR_C IN 2", "TDMIN_C OUT", -+ "TODDR_A IN 6", "TDMIN_LB OUT", -+ "TODDR_B IN 6", "TDMIN_LB OUT", -+ "TODDR_C IN 6", "TDMIN_LB OUT"; -+ -+ assigned-clocks = <&clkc CLKID_HIFI_PLL>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <589824000>, -+ <270950400>, -+ <393216000>; -+ -+ status = "okay"; -+ -+ dai-link-0 { -+ sound-dai = <&frddr_a>; -+ }; -+ -+ dai-link-1 { -+ sound-dai = <&frddr_b>; -+ }; -+ -+ dai-link-2 { -+ sound-dai = <&frddr_c>; -+ }; -+ -+ dai-link-3 { -+ sound-dai = <&toddr_a>; -+ }; -+ -+ dai-link-4 { -+ sound-dai = <&toddr_b>; -+ }; -+ -+ dai-link-5 { -+ sound-dai = <&toddr_c>; -+ }; -+ -+ dai-link-6 { -+ sound-dai = <&tdmif_b>; -+ dai-format = "i2s"; -+ dai-tdm-slot-tx-mask-0 = <1 1>; -+ mclk-fs = <256>; -+ -+ codec@1 { -+ sound-dai = <&tohdmitx 1>; -+ }; -+ }; -+ -+ dai-link-7 { -+ sound-dai = <&tdmif_a>; -+ dai-format = "i2s"; -+ dai-tdm-slot-tx-mask-0 = <1 1>; -+ mclk-fs = <256>; -+ -+ codec@1 { -+ sound-dai = <&tohdmitx 0>; -+ }; -+ }; -+ -+ dai-link-8 { -+ sound-dai = <&tdmif_c>; -+ dai-format = "i2s"; -+ dai-tdm-slot-tx-mask-0 = <1 1>; -+ mclk-fs = <256>; -+ -+ codec@1 { -+ sound-dai = <&tohdmitx 2>; -+ }; -+ }; -+ -+ dai-link-9 { -+ sound-dai = <&spdifout>; -+ -+ codec@0 { -+ sound-dai = <&spdif_dit>; -+ }; -+ -+ codec@1 { -+ sound-dai = <&tohdmitx 4>; -+ }; -+ }; -+ -+ dai-link-10 { -+ sound-dai = <&spdifout_b>; -+ -+ codec { -+ sound-dai = <&tohdmitx 5>; -+ }; -+ }; -+ -+ dai-link-11 { -+ sound-dai = <&tohdmitx 3>; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+}; -+ -+&arb { -+ status = "okay"; - }; - - &cec_AO { -@@ -145,6 +301,10 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&clkc_audio { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; -@@ -157,6 +317,18 @@ - phy-mode = "rmii"; - }; - -+&frddr_a { -+ status = "okay"; -+}; -+ -+&frddr_b { -+ status = "okay"; -+}; -+ -+&frddr_c { -+ status = "okay"; -+}; -+ - &hdmi_tx { - status = "okay"; - pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -@@ -234,6 +406,78 @@ - vqmmc-supply = <&flash_1v8>; - }; - -+&spdifout { -+ pinctrl-0 = <&spdif_ao_out_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&spdifout_b { -+ status = "okay"; -+}; -+ -+&tdmif_a { -+ pinctrl-0 = <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>, <&tdm_a_dout0_pins> ; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&tdmif_b { -+ pinctrl-0 = <&mclk0_a_pins>, <&tdm_b_fs_pins>, <&tdm_b_sclk_pins>, -+ <&tdm_b_dout0_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&tdmif_c { -+ status = "okay"; -+}; -+ -+&tdmin_a { -+ inctrl-0 = <&tdm_a_dout0_pins>, <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>; -+ status = "okay"; -+}; -+ -+&tdmin_b { -+ status = "okay"; -+}; -+ -+&tdmin_c { -+ status = "okay"; -+}; -+ -+&tdmin_lb { -+ status = "okay"; -+}; -+ -+&tdmout_a { -+ status = "okay"; -+}; -+ -+&tdmout_b { -+ status = "okay"; -+}; -+ -+&tdmout_c { -+ status = "okay"; -+}; -+ -+&toddr_a { -+ status = "okay"; -+}; -+ -+&toddr_b { -+ status = "okay"; -+}; -+ -+&toddr_c { -+ status = "okay"; -+}; -+ -+&tohdmitx { -+ status = "okay"; -+}; -+ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; - -From a0933fc9008daf4ad9038c3cd32df5f0e9029727 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 18 Mar 2019 13:45:39 +0100 -Subject: [PATCH 199/249] WIP: arm64: dts: meson: sei510: enable audio - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-g12a-sei510.dts | 246 +++++++++++++++++- - 1 file changed, 245 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index 50d8ac55eed8a..a497add0907af 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -32,13 +32,22 @@ - ethernet0 = ðmac; - }; - -- mono_dac: audio-codec { -+ mono_dac: audio-codec-0 { - compatible = "maxim,max98357a"; - #sound-dai-cells = <0>; - sound-name-prefix = "U16"; - sdmode-gpios = <&gpio GPIOX_8 GPIO_ACTIVE_HIGH>; - }; - -+ dmics: audio-codec-1 { -+ #sound-dai-cells = <0>; -+ compatible = "dmic-codec"; -+ num-channels = <2>; -+ wakeup-delay-ms = <50>; -+ status = "okay"; -+ sound-name-prefix = "MIC"; -+ }; -+ - chosen { - stdout-path = "serial0:115200n8"; - }; -@@ -143,6 +152,133 @@ - clock-names = "ext_clock"; - }; - -+ sound { -+ compatible = "amlogic,axg-sound-card"; -+ model = "G12A-SEI510"; -+ audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmout_c>, -+ <&tdmin_a>, <&tdmin_b>, <&tdmin_c>, -+ <&tdmin_lb>; -+ audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", -+ "TDMOUT_A IN 1", "FRDDR_B OUT 0", -+ "TDMOUT_A IN 2", "FRDDR_C OUT 0", -+ "TDM_A Playback", "TDMOUT_A OUT", -+ "TDMOUT_B IN 0", "FRDDR_A OUT 1", -+ "TDMOUT_B IN 1", "FRDDR_B OUT 1", -+ "TDMOUT_B IN 2", "FRDDR_C OUT 1", -+ "TDM_B Playback", "TDMOUT_B OUT", -+ "TODDR_A IN 4", "PDM Capture", -+ "TODDR_B IN 4", "PDM Capture", -+ "TODDR_C IN 4", "PDM Capture", -+ "TDMIN_A IN 0", "TDM_A Capture", -+ "TDMIN_A IN 3", "TDM_A Loopback", -+ "TDMIN_B IN 0", "TDM_A Capture", -+ "TDMIN_B IN 3", "TDM_A Loopback", -+ "TDMIN_C IN 0", "TDM_A Capture", -+ "TDMIN_C IN 3", "TDM_A Loopback", -+ "TDMIN_LB IN 3", "TDM_A Capture", -+ "TDMIN_LB IN 0", "TDM_A Loopback", -+ "TDMIN_A IN 1", "TDM_B Capture", -+ "TDMIN_A IN 4", "TDM_B Loopback", -+ "TDMIN_B IN 1", "TDM_B Capture", -+ "TDMIN_B IN 4", "TDM_B Loopback", -+ "TDMIN_C IN 1", "TDM_B Capture", -+ "TDMIN_C IN 4", "TDM_B Loopback", -+ "TDMIN_LB IN 4", "TDM_B Capture", -+ "TDMIN_LB IN 1", "TDM_B Loopback", -+ "TODDR_A IN 0", "TDMIN_A OUT", -+ "TODDR_B IN 0", "TDMIN_A OUT", -+ "TODDR_C IN 0", "TDMIN_A OUT", -+ "TODDR_A IN 1", "TDMIN_B OUT", -+ "TODDR_B IN 1", "TDMIN_B OUT", -+ "TODDR_C IN 1", "TDMIN_B OUT", -+ "TODDR_A IN 2", "TDMIN_C OUT", -+ "TODDR_B IN 2", "TDMIN_C OUT", -+ "TODDR_C IN 2", "TDMIN_C OUT", -+ "TODDR_A IN 6", "TDMIN_LB OUT", -+ "TODDR_B IN 6", "TDMIN_LB OUT", -+ "TODDR_C IN 6", "TDMIN_LB OUT"; -+ -+ /* FIXME */ -+ assigned-clocks = <&clkc CLKID_HIFI_PLL>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <589824000>, -+ <270950400>, -+ <393216000>; -+ -+ status = "okay"; -+ -+ dai-link-0 { -+ sound-dai = <&frddr_a>; -+ }; -+ -+ dai-link-1 { -+ sound-dai = <&frddr_b>; -+ }; -+ -+ dai-link-2 { -+ sound-dai = <&frddr_c>; -+ }; -+ -+ dai-link-3 { -+ sound-dai = <&toddr_a>; -+ }; -+ -+ dai-link-4 { -+ sound-dai = <&toddr_b>; -+ }; -+ -+ dai-link-5 { -+ sound-dai = <&toddr_c>; -+ }; -+ -+ dai-link-6 { -+ sound-dai = <&tdmif_a>; -+ dai-format = "i2s"; -+ dai-tdm-slot-tx-mask-0 = <1 1>; -+ mclk-fs = <256>; -+ -+ codec-0 { -+ sound-dai = <&mono_dac>; -+ }; -+ -+ codec-1 { -+ sound-dai = <&tohdmitx 0>; -+ }; -+ }; -+ -+ dai-link-7 { -+ sound-dai = <&pdm>; -+ -+ codec { -+ sound-dai = <&dmics>; -+ }; -+ }; -+ -+ dai-link-8 { -+ sound-dai = <&tdmif_b>; -+ dai-format = "i2s"; -+ dai-tdm-slot-tx-mask-0 = <1 1>; -+ dai-tdm-slot-tx-mask-1 = <1 1>; -+ dai-tdm-slot-tx-mask-2 = <1 1>; -+ dai-tdm-slot-tx-mask-3 = <1 1>; -+ mclk-fs = <256>; -+ -+ codec@0 { -+ sound-dai = <&tohdmitx 1>; -+ }; -+ }; -+ -+ dai-link-9 { -+ sound-dai = <&tohdmitx 3>; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+ - wifi32k: wifi32k { - compatible = "pwm-clock"; - #clock-cells = <0>; -@@ -151,6 +287,10 @@ - }; - }; - -+&arb { -+ status = "okay"; -+}; -+ - &cec_AO { - pinctrl-0 = <&cec_ao_a_h_pins>; - pinctrl-names = "default"; -@@ -165,6 +305,10 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&clkc_audio { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; -@@ -177,6 +321,18 @@ - phy-mode = "rmii"; - }; - -+&frddr_a { -+ status = "okay"; -+}; -+ -+&frddr_b { -+ status = "okay"; -+}; -+ -+&frddr_c { -+ status = "okay"; -+}; -+ - &hdmi_tx { - status = "okay"; - pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -@@ -201,6 +357,14 @@ - pinctrl-names = "default"; - }; - -+&pdm { -+ pinctrl-0 = <&pdm_din0_z_pins>, <&pdm_din1_z_pins>, -+ <&pdm_din2_z_pins>, <&pdm_din3_z_pins>, -+ <&pdm_dclk_z_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ - &pwm_ef { - status = "okay"; - pinctrl-0 = <&pwm_e_pins>; -@@ -277,6 +441,86 @@ - vqmmc-supply = <&emmc_1v8>; - }; - -+&tdmif_a { -+ pinctrl-0 = <&tdm_a_dout0_pins>, <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ -+ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD0>, -+ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD0>; -+ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_A_SCLK>, -+ <&clkc_audio AUD_CLKID_MST_A_LRCLK>; -+ assigned-clock-rates = <0>, <0>; -+}; -+ -+&tdmif_b { -+ status = "okay"; -+ -+ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD1>, -+ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD1>, -+ <&clkc_audio AUD_CLKID_TDM_MCLK_PAD0>; -+ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_B_SCLK>, -+ <&clkc_audio AUD_CLKID_MST_B_LRCLK>, -+ <&clkc_audio AUD_CLKID_MST_B_MCLK>; -+ assigned-clock-rates = <0>, <0>, <0>; -+}; -+ -+&tdmif_c { -+ status = "okay"; -+ -+ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD2>, -+ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD2>, -+ <&clkc_audio AUD_CLKID_TDM_MCLK_PAD1>; -+ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_C_SCLK>, -+ <&clkc_audio AUD_CLKID_MST_C_LRCLK>, -+ <&clkc_audio AUD_CLKID_MST_C_MCLK>; -+ assigned-clock-rates = <0>, <0>, <0>; -+}; -+ -+&tdmin_a { -+ status = "okay"; -+}; -+ -+&tdmin_b { -+ status = "okay"; -+}; -+ -+&tdmin_c { -+ status = "okay"; -+}; -+ -+&tdmin_lb { -+ status = "okay"; -+}; -+ -+&tdmout_a { -+ status = "okay"; -+}; -+ -+&tdmout_b { -+ status = "okay"; -+}; -+ -+&tdmout_c { -+ status = "okay"; -+}; -+ -+&toddr_a { -+ status = "okay"; -+}; -+ -+&toddr_b { -+ status = "okay"; -+}; -+ -+&toddr_c { -+ status = "okay"; -+}; -+ -+&tohdmitx { -+ status = "okay"; -+}; -+ - &uart_A { - status = "okay"; - pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; - -From 7c3d9ce2a78fa344d701894e7fc0bea185213563 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 14 May 2019 10:00:52 +0200 -Subject: [PATCH 200/249] WIP: Bluetooth: btbcm: Add entry for BCM4359C0 UART - bluetooth - ---- - drivers/bluetooth/btbcm.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c -index d5d6e6e5da3bf..b9eac94c503d2 100644 ---- a/drivers/bluetooth/btbcm.c -+++ b/drivers/bluetooth/btbcm.c -@@ -342,6 +342,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { - { 0x230f, "BCM4356A2" }, /* 001.003.015 */ - { 0x220e, "BCM20702A1" }, /* 001.002.014 */ - { 0x4217, "BCM4329B1" }, /* 002.002.023 */ -+ { 0x6106, "BCM4359C0" }, /* 003.001.006 */ - { } - }; - - -From 39082908e3a2b38f9f787fa1d80d924227c3d180 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 14 May 2019 13:38:14 +0200 -Subject: [PATCH 201/249] WIP: arm64: dts: meson-g12a-sei510: Switch sound card - to MPPL2 instead of HIFI_PLL - ---- - arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -index a497add0907af..1b535b9ed1c51 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts -@@ -199,11 +199,11 @@ - "TODDR_C IN 6", "TDMIN_LB OUT"; - - /* FIXME */ -- assigned-clocks = <&clkc CLKID_HIFI_PLL>, -+ assigned-clocks = <&clkc CLKID_MPLL2>, - <&clkc CLKID_MPLL0>, - <&clkc CLKID_MPLL1>; - assigned-clock-parents = <0>, <0>, <0>; -- assigned-clock-rates = <589824000>, -+ assigned-clock-rates = <294912000>, - <270950400>, - <393216000>; - - -From 18e1f337541ad76b8756c887f310cd1c72f0d71b Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Tue, 14 May 2019 14:51:26 +0200 -Subject: [PATCH 202/249] fixup! FROMLIST: arm64: dts: meson: g12a: add audio - fifos - ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 9fa4ef37d6243..29db6ce2ccbb2 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -1499,7 +1499,7 @@ - }; - - toddr_a: audio-controller@100 { -- compatible = "amlogic,g12a-toddr"; -+ compatible = "amlogic,g12a-toddr", "amlogic,axg-toddr"; - reg = <0x0 0x100 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "TODDR_A"; -@@ -1510,7 +1510,7 @@ - }; - - toddr_b: audio-controller@140 { -- compatible = "amlogic,g12a-toddr"; -+ compatible = "amlogic,g12a-toddr", "amlogic,axg-toddr"; - reg = <0x0 0x140 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "TODDR_B"; -@@ -1521,7 +1521,7 @@ - }; - - toddr_c: audio-controller@180 { -- compatible = "amlogic,g12a-toddr"; -+ compatible = "amlogic,g12a-toddr", "amlogic,axg-toddr"; - reg = <0x0 0x180 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "TODDR_C"; -@@ -1532,7 +1532,7 @@ - }; - - frddr_a: audio-controller@1c0 { -- compatible = "amlogic,g12a-frddr"; -+ compatible = "amlogic,g12a-frddr", "amlogic,axg-frddr"; - reg = <0x0 0x1c0 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "FRDDR_A"; -@@ -1543,7 +1543,7 @@ - }; - - frddr_b: audio-controller@200 { -- compatible = "amlogic,g12a-frddr"; -+ compatible = "amlogic,g12a-frddr", "amlogic,axg-frddr"; - reg = <0x0 0x200 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "FRDDR_B"; -@@ -1554,7 +1554,7 @@ - }; - - frddr_c: audio-controller@240 { -- compatible = "amlogic,g12a-frddr"; -+ compatible = "amlogic,g12a-frddr", "amlogic,axg-frddr"; - reg = <0x0 0x240 0x0 0x1c>; - #sound-dai-cells = <0>; - sound-name-prefix = "FRDDR_C"; - -From 793cc3405b4bf1b744ca91eb701547ace14c48cb Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 29 Aug 2018 15:05:05 +0200 -Subject: [PATCH 203/249] WIP: dt-bindings: media: add Amlogic Video Decoder - Bindings - -Add documentation for the meson vdec dts node. - -Signed-off-by: Maxime Jourdan -Reviewed-by: Rob Herring ---- - .../bindings/media/amlogic,vdec.txt | 71 +++++++++++++++++++ - 1 file changed, 71 insertions(+) - create mode 100644 Documentation/devicetree/bindings/media/amlogic,vdec.txt - -diff --git a/Documentation/devicetree/bindings/media/amlogic,vdec.txt b/Documentation/devicetree/bindings/media/amlogic,vdec.txt -new file mode 100644 -index 0000000000000..aabdd01bcf32b ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/amlogic,vdec.txt -@@ -0,0 +1,71 @@ -+Amlogic Video Decoder -+================================ -+ -+The video decoding IP lies within the DOS memory region, -+except for the hardware bitstream parser that makes use of an undocumented -+region. -+ -+It makes use of the following blocks: -+ -+- ESPARSER is a bitstream parser that outputs to a VIFIFO. Further VDEC blocks -+then feed from this VIFIFO. -+- VDEC_1 can decode MPEG-1, MPEG-2, MPEG-4 part 2, MJPEG, H.263, H.264, VC-1. -+- VDEC_HEVC can decode HEVC and VP9. -+ -+Both VDEC_1 and VDEC_HEVC share the "vdec" IRQ and as such cannot run -+concurrently. -+ -+Device Tree Bindings: -+--------------------- -+ -+VDEC: Video Decoder -+-------------------------- -+ -+Required properties: -+- compatible: value should be different for each SoC family as : -+ - GXBB (S905) : "amlogic,gxbb-vdec" -+ - GXL (S905X, S905D) : "amlogic,gxl-vdec" -+ - GXM (S912) : "amlogic,gxm-vdec" -+- reg: base address and size of he following memory-mapped regions : -+ - dos -+ - esparser -+- reg-names: should contain the names of the previous memory regions -+- interrupts: should contain the following IRQs: -+ - vdec -+ - esparser -+- interrupt-names: should contain the names of the previous interrupts -+- amlogic,ao-sysctrl: should point to the AOBUS sysctrl node -+- amlogic,canvas: should point to a canvas provider node -+- clocks: should contain the following clocks : -+ - dos_parser -+ - dos -+ - vdec_1 -+ - vdec_hevc -+- clock-names: should contain the names of the previous clocks -+- resets: should contain the parser reset -+- reset-names: should be "esparser" -+ -+Example: -+ -+vdec: video-decoder@c8820000 { -+ compatible = "amlogic,gxbb-vdec"; -+ reg = <0x0 0xc8820000 0x0 0x10000>, -+ <0x0 0xc110a580 0x0 0xe4>; -+ reg-names = "dos", "esparser"; -+ -+ interrupts = , -+ ; -+ interrupt-names = "vdec", "esparser"; -+ -+ amlogic,ao-sysctrl = <&sysctrl_AO>; -+ amlogic,canvas = <&canvas>; -+ -+ clocks = <&clkc CLKID_DOS_PARSER>, -+ <&clkc CLKID_DOS>, -+ <&clkc CLKID_VDEC_1>, -+ <&clkc CLKID_VDEC_HEVC>; -+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; -+ -+ resets = <&reset RESET_PARSER>; -+ reset-names = "esparser"; -+}; - -From f3c22a1ed164e7a74a574dd40abbb9d2e2a11582 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Thu, 4 Oct 2018 15:37:39 +0200 -Subject: [PATCH 204/249] WIP: media: videodev2: add - V4L2_FMT_FLAG_FIXED_RESOLUTION - -When a v4l2 driver exposes V4L2_EVENT_SOURCE_CHANGE, some (usually -OUTPUT) formats may not be able to trigger this event. - -For instance, MPEG2 on Amlogic hardware does not support resolution -switching on the fly, and a decode session must operate at a set -resolution defined before the decoding start. - -Add a enum_fmt format flag to tag those specific formats. - -Signed-off-by: Maxime Jourdan ---- - Documentation/media/uapi/v4l/vidioc-enum-fmt.rst | 6 ++++++ - include/uapi/linux/videodev2.h | 5 +++-- - 2 files changed, 9 insertions(+), 2 deletions(-) - -diff --git a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst -index 822d6730e7d2c..b11448a1848b2 100644 ---- a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst -+++ b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst -@@ -127,6 +127,12 @@ one until ``EINVAL`` is returned. - - This format is not native to the device but emulated through - software (usually libv4l2), where possible try to use a native - format instead for better performance. -+ * - ``V4L2_FMT_FLAG_FIXED_RESOLUTION`` -+ - 0x0004 -+ - Dynamic resolution switching is not supported for this format, -+ even if the event ``V4L2_EVENT_SOURCE_CHANGE`` is supported by -+ the device. -+ - - - Return Value -diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h -index 1db220da3bccd..9c8a2d2e7bc62 100644 ---- a/include/uapi/linux/videodev2.h -+++ b/include/uapi/linux/videodev2.h -@@ -751,8 +751,9 @@ struct v4l2_fmtdesc { - __u32 reserved[4]; - }; - --#define V4L2_FMT_FLAG_COMPRESSED 0x0001 --#define V4L2_FMT_FLAG_EMULATED 0x0002 -+#define V4L2_FMT_FLAG_COMPRESSED 0x0001 -+#define V4L2_FMT_FLAG_EMULATED 0x0002 -+#define V4L2_FMT_FLAG_FIXED_RESOLUTION 0x0004 - - /* Frame Size and frame rate enumeration */ - /* - -From ce61c43ac2da5510a5faea890111c6e11c66a2c8 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 29 Aug 2018 15:17:22 +0200 -Subject: [PATCH 205/249] WIP: media: meson: add v4l2 m2m video decoder driver - -Amlogic SoCs feature a powerful video decoder unit able to -decode many formats, with a performance of usually up to 4k60. - -This is a driver for this IP that is based around the v4l2 m2m framework. - -It features decoding for: -- MPEG 1 -- MPEG 2 - -Supported SoCs are: GXBB (S905), GXL (S905X/W/D), GXM (S912) - -There is also a hardware bitstream parser (ESPARSER) that is handled here. - -Signed-off-by: Maxime Jourdan ---- - drivers/media/platform/Kconfig | 10 + - drivers/media/platform/meson/Makefile | 1 + - drivers/media/platform/meson/vdec/Makefile | 8 + - .../media/platform/meson/vdec/codec_mpeg12.c | 209 ++++ - .../media/platform/meson/vdec/codec_mpeg12.h | 14 + - drivers/media/platform/meson/vdec/dos_regs.h | 98 ++ - drivers/media/platform/meson/vdec/esparser.c | 323 +++++ - drivers/media/platform/meson/vdec/esparser.h | 32 + - drivers/media/platform/meson/vdec/vdec.c | 1071 +++++++++++++++++ - drivers/media/platform/meson/vdec/vdec.h | 265 ++++ - drivers/media/platform/meson/vdec/vdec_1.c | 229 ++++ - drivers/media/platform/meson/vdec/vdec_1.h | 14 + - .../media/platform/meson/vdec/vdec_ctrls.c | 51 + - .../media/platform/meson/vdec/vdec_ctrls.h | 14 + - .../media/platform/meson/vdec/vdec_helpers.c | 441 +++++++ - .../media/platform/meson/vdec/vdec_helpers.h | 80 ++ - .../media/platform/meson/vdec/vdec_platform.c | 107 ++ - .../media/platform/meson/vdec/vdec_platform.h | 30 + - 18 files changed, 2997 insertions(+) - create mode 100644 drivers/media/platform/meson/vdec/Makefile - create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.c - create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.h - create mode 100644 drivers/media/platform/meson/vdec/dos_regs.h - create mode 100644 drivers/media/platform/meson/vdec/esparser.c - create mode 100644 drivers/media/platform/meson/vdec/esparser.h - create mode 100644 drivers/media/platform/meson/vdec/vdec.c - create mode 100644 drivers/media/platform/meson/vdec/vdec.h - create mode 100644 drivers/media/platform/meson/vdec/vdec_1.c - create mode 100644 drivers/media/platform/meson/vdec/vdec_1.h - create mode 100644 drivers/media/platform/meson/vdec/vdec_ctrls.c - create mode 100644 drivers/media/platform/meson/vdec/vdec_ctrls.h - create mode 100644 drivers/media/platform/meson/vdec/vdec_helpers.c - create mode 100644 drivers/media/platform/meson/vdec/vdec_helpers.h - create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.c - create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.h - -diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index ea3a65e1ddbcd..82cefe97018e4 100644 ---- a/drivers/media/platform/Kconfig -+++ b/drivers/media/platform/Kconfig -@@ -501,6 +501,16 @@ config VIDEO_QCOM_VENUS - on various Qualcomm SoCs. - To compile this driver as a module choose m here. - -+config VIDEO_MESON_VDEC -+ tristate "Amlogic video decoder driver" -+ depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA -+ depends on ARCH_MESON || COMPILE_TEST -+ select VIDEOBUF2_DMA_CONTIG -+ select V4L2_MEM2MEM_DEV -+ select MESON_CANVAS -+ help -+ Support for the video decoder found in gxbb/gxl/gxm chips. -+ - endif # V4L_MEM2MEM_DRIVERS - - # TI VIDEO PORT Helper Modules -diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile -index f611c23c37180..2fc34afb70d19 100644 ---- a/drivers/media/platform/meson/Makefile -+++ b/drivers/media/platform/meson/Makefile -@@ -1,2 +1,3 @@ - obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o - obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o -+obj-$(CONFIG_VIDEO_MESON_VDEC) += vdec/ -diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile -new file mode 100644 -index 0000000000000..eba86083aadb4 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# Makefile for Amlogic meson video decoder driver -+ -+meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o -+meson-vdec-objs += vdec_1.o -+meson-vdec-objs += codec_mpeg12.o -+ -+obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o -diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.c b/drivers/media/platform/meson/vdec/codec_mpeg12.c -new file mode 100644 -index 0000000000000..d88530a7b81ae ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_mpeg12.c -@@ -0,0 +1,209 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#include -+#include -+ -+#include "vdec_helpers.h" -+#include "dos_regs.h" -+ -+#define SIZE_WORKSPACE SZ_128K -+/* Offset substracted by the firmware from the workspace paddr */ -+#define WORKSPACE_OFFSET (5 * SZ_1K) -+ -+/* map firmware registers to known MPEG1/2 functions */ -+#define MREG_SEQ_INFO AV_SCRATCH_4 -+ #define MPEG2_SEQ_DAR_MASK GENMASK(3, 0) -+ #define MPEG2_DAR_4_3 2 -+ #define MPEG2_DAR_16_9 3 -+ #define MPEG2_DAR_221_100 4 -+#define MREG_PIC_INFO AV_SCRATCH_5 -+#define MREG_PIC_WIDTH AV_SCRATCH_6 -+#define MREG_PIC_HEIGHT AV_SCRATCH_7 -+#define MREG_BUFFERIN AV_SCRATCH_8 -+#define MREG_BUFFEROUT AV_SCRATCH_9 -+#define MREG_CMD AV_SCRATCH_A -+#define MREG_CO_MV_START AV_SCRATCH_B -+#define MREG_ERROR_COUNT AV_SCRATCH_C -+#define MREG_FRAME_OFFSET AV_SCRATCH_D -+#define MREG_WAIT_BUFFER AV_SCRATCH_E -+#define MREG_FATAL_ERROR AV_SCRATCH_F -+ -+#define PICINFO_PROG 0x00008000 -+#define PICINFO_TOP_FIRST 0x00002000 -+ -+struct codec_mpeg12 { -+ /* Buffer for the MPEG1/2 Workspace */ -+ void *workspace_vaddr; -+ dma_addr_t workspace_paddr; -+}; -+ -+static const u8 eos_sequence[SZ_1K] = { 0x00, 0x00, 0x01, 0xB7 }; -+ -+static const u8 *codec_mpeg12_eos_sequence(u32 *len) -+{ -+ *len = ARRAY_SIZE(eos_sequence); -+ return eos_sequence; -+} -+ -+static int codec_mpeg12_can_recycle(struct amvdec_core *core) -+{ -+ return !amvdec_read_dos(core, MREG_BUFFERIN); -+} -+ -+static void codec_mpeg12_recycle(struct amvdec_core *core, u32 buf_idx) -+{ -+ amvdec_write_dos(core, MREG_BUFFERIN, buf_idx + 1); -+} -+ -+static int codec_mpeg12_start(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_mpeg12 *mpeg12 = sess->priv; -+ int ret; -+ -+ mpeg12 = kzalloc(sizeof(*mpeg12), GFP_KERNEL); -+ if (!mpeg12) -+ return -ENOMEM; -+ -+ /* Allocate some memory for the MPEG1/2 decoder's state */ -+ mpeg12->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, -+ &mpeg12->workspace_paddr, -+ GFP_KERNEL); -+ if (!mpeg12->workspace_vaddr) { -+ dev_err(core->dev, "Failed to request MPEG 1/2 Workspace\n"); -+ ret = -ENOMEM; -+ goto free_mpeg12; -+ } -+ -+ ret = amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, 0 }, -+ (u32[]){ 8, 0 }); -+ if (ret) -+ goto free_workspace; -+ -+ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4)); -+ amvdec_write_dos(core, MREG_CO_MV_START, -+ mpeg12->workspace_paddr + WORKSPACE_OFFSET); -+ -+ amvdec_write_dos(core, MPEG1_2_REG, 0); -+ amvdec_write_dos(core, PSCALE_CTRL, 0); -+ amvdec_write_dos(core, PIC_HEAD_INFO, 0x380); -+ amvdec_write_dos(core, M4_CONTROL_REG, 0); -+ amvdec_write_dos(core, MREG_BUFFERIN, 0); -+ amvdec_write_dos(core, MREG_BUFFEROUT, 0); -+ amvdec_write_dos(core, MREG_CMD, (sess->width << 16) | sess->height); -+ amvdec_write_dos(core, MREG_ERROR_COUNT, 0); -+ amvdec_write_dos(core, MREG_FATAL_ERROR, 0); -+ amvdec_write_dos(core, MREG_WAIT_BUFFER, 0); -+ -+ sess->keyframe_found = 1; -+ sess->priv = mpeg12; -+ -+ return 0; -+ -+free_workspace: -+ dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr, -+ mpeg12->workspace_paddr); -+free_mpeg12: -+ kfree(mpeg12); -+ -+ return ret; -+} -+ -+static int codec_mpeg12_stop(struct amvdec_session *sess) -+{ -+ struct codec_mpeg12 *mpeg12 = sess->priv; -+ struct amvdec_core *core = sess->core; -+ -+ if (mpeg12->workspace_vaddr) -+ dma_free_coherent(core->dev, SIZE_WORKSPACE, -+ mpeg12->workspace_vaddr, -+ mpeg12->workspace_paddr); -+ -+ return 0; -+} -+ -+static void codec_mpeg12_update_dar(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 seq = amvdec_read_dos(core, MREG_SEQ_INFO); -+ u32 ar = seq & MPEG2_SEQ_DAR_MASK; -+ -+ switch (ar) { -+ case MPEG2_DAR_4_3: -+ amvdec_set_par_from_dar(sess, 4, 3); -+ break; -+ case MPEG2_DAR_16_9: -+ amvdec_set_par_from_dar(sess, 16, 9); -+ break; -+ case MPEG2_DAR_221_100: -+ amvdec_set_par_from_dar(sess, 221, 100); -+ break; -+ default: -+ sess->pixelaspect.numerator = 1; -+ sess->pixelaspect.denominator = 1; -+ break; -+ } -+} -+ -+static irqreturn_t codec_mpeg12_threaded_isr(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 reg; -+ u32 pic_info; -+ u32 is_progressive; -+ u32 buffer_index; -+ u32 field = V4L2_FIELD_NONE; -+ u32 offset; -+ -+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); -+ reg = amvdec_read_dos(core, MREG_FATAL_ERROR); -+ if (reg == 1) { -+ dev_err(core->dev, "MPEG1/2 fatal error\n"); -+ amvdec_abort(sess); -+ return IRQ_HANDLED; -+ } -+ -+ reg = amvdec_read_dos(core, MREG_BUFFEROUT); -+ if (!reg) -+ return IRQ_HANDLED; -+ -+ /* Unclear what this means */ -+ if ((reg & GENMASK(23, 17)) == GENMASK(23, 17)) -+ goto end; -+ -+ pic_info = amvdec_read_dos(core, MREG_PIC_INFO); -+ is_progressive = pic_info & PICINFO_PROG; -+ -+ if (!is_progressive) -+ field = (pic_info & PICINFO_TOP_FIRST) ? -+ V4L2_FIELD_INTERLACED_TB : -+ V4L2_FIELD_INTERLACED_BT; -+ -+ codec_mpeg12_update_dar(sess); -+ buffer_index = ((reg & 0xf) - 1) & 7; -+ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET); -+ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field); -+ -+end: -+ amvdec_write_dos(core, MREG_BUFFEROUT, 0); -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t codec_mpeg12_isr(struct amvdec_session *sess) -+{ -+ return IRQ_WAKE_THREAD; -+} -+ -+struct amvdec_codec_ops codec_mpeg12_ops = { -+ .start = codec_mpeg12_start, -+ .stop = codec_mpeg12_stop, -+ .isr = codec_mpeg12_isr, -+ .threaded_isr = codec_mpeg12_threaded_isr, -+ .can_recycle = codec_mpeg12_can_recycle, -+ .recycle = codec_mpeg12_recycle, -+ .eos_sequence = codec_mpeg12_eos_sequence, -+}; -diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.h b/drivers/media/platform/meson/vdec/codec_mpeg12.h -new file mode 100644 -index 0000000000000..43cab5f39ca05 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_mpeg12.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CODEC_MPEG12_H_ -+#define __MESON_VDEC_CODEC_MPEG12_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_codec_ops codec_mpeg12_ops; -+ -+#endif -diff --git a/drivers/media/platform/meson/vdec/dos_regs.h b/drivers/media/platform/meson/vdec/dos_regs.h -new file mode 100644 -index 0000000000000..abd810542dbb5 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/dos_regs.h -@@ -0,0 +1,98 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_DOS_REGS_H_ -+#define __MESON_VDEC_DOS_REGS_H_ -+ -+/* DOS registers */ -+#define VDEC_ASSIST_AMR1_INT8 0x00b4 -+ -+#define ASSIST_MBOX1_CLR_REG 0x01d4 -+#define ASSIST_MBOX1_MASK 0x01d8 -+ -+#define MPSR 0x0c04 -+#define MCPU_INTR_MSK 0x0c10 -+#define CPSR 0x0c84 -+ -+#define IMEM_DMA_CTRL 0x0d00 -+#define IMEM_DMA_ADR 0x0d04 -+#define IMEM_DMA_COUNT 0x0d08 -+#define LMEM_DMA_CTRL 0x0d40 -+ -+#define MC_STATUS0 0x2424 -+#define MC_CTRL1 0x242c -+ -+#define PSCALE_RST 0x2440 -+#define PSCALE_CTRL 0x2444 -+#define PSCALE_BMEM_ADDR 0x247c -+#define PSCALE_BMEM_DAT 0x2480 -+ -+#define DBLK_CTRL 0x2544 -+#define DBLK_STATUS 0x254c -+ -+#define GCLK_EN 0x260c -+#define MDEC_PIC_DC_CTRL 0x2638 -+#define MDEC_PIC_DC_STATUS 0x263c -+#define ANC0_CANVAS_ADDR 0x2640 -+#define MDEC_PIC_DC_THRESH 0x26e0 -+ -+/* Firmware interface registers */ -+#define AV_SCRATCH_0 0x2700 -+#define AV_SCRATCH_1 0x2704 -+#define AV_SCRATCH_2 0x2708 -+#define AV_SCRATCH_3 0x270c -+#define AV_SCRATCH_4 0x2710 -+#define AV_SCRATCH_5 0x2714 -+#define AV_SCRATCH_6 0x2718 -+#define AV_SCRATCH_7 0x271c -+#define AV_SCRATCH_8 0x2720 -+#define AV_SCRATCH_9 0x2724 -+#define AV_SCRATCH_A 0x2728 -+#define AV_SCRATCH_B 0x272c -+#define AV_SCRATCH_C 0x2730 -+#define AV_SCRATCH_D 0x2734 -+#define AV_SCRATCH_E 0x2738 -+#define AV_SCRATCH_F 0x273c -+#define AV_SCRATCH_G 0x2740 -+#define AV_SCRATCH_H 0x2744 -+#define AV_SCRATCH_I 0x2748 -+#define AV_SCRATCH_J 0x274c -+#define AV_SCRATCH_K 0x2750 -+#define AV_SCRATCH_L 0x2754 -+ -+#define MPEG1_2_REG 0x3004 -+#define PIC_HEAD_INFO 0x300c -+#define POWER_CTL_VLD 0x3020 -+#define M4_CONTROL_REG 0x30a4 -+ -+/* Stream Buffer (stbuf) regs */ -+#define VLD_MEM_VIFIFO_START_PTR 0x3100 -+#define VLD_MEM_VIFIFO_CURR_PTR 0x3104 -+#define VLD_MEM_VIFIFO_END_PTR 0x3108 -+#define VLD_MEM_VIFIFO_CONTROL 0x3110 -+ #define MEM_FIFO_CNT_BIT 16 -+ #define MEM_FILL_ON_LEVEL BIT(10) -+ #define MEM_CTRL_EMPTY_EN BIT(2) -+ #define MEM_CTRL_FILL_EN BIT(1) -+#define VLD_MEM_VIFIFO_WP 0x3114 -+#define VLD_MEM_VIFIFO_RP 0x3118 -+#define VLD_MEM_VIFIFO_LEVEL 0x311c -+#define VLD_MEM_VIFIFO_BUF_CNTL 0x3120 -+ #define MEM_BUFCTRL_MANUAL BIT(1) -+#define VLD_MEM_VIFIFO_WRAP_COUNT 0x3144 -+ -+#define DCAC_DMA_CTRL 0x3848 -+ -+#define DOS_SW_RESET0 0xfc00 -+#define DOS_GCLK_EN0 0xfc04 -+#define DOS_GEN_CTRL0 0xfc08 -+#define DOS_MEM_PD_VDEC 0xfcc0 -+#define DOS_MEM_PD_HEVC 0xfccc -+#define DOS_SW_RESET3 0xfcd0 -+#define DOS_GCLK_EN3 0xfcd4 -+#define DOS_VDEC_MCRCC_STALL_CTRL 0xfd00 -+ -+#endif -diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c -new file mode 100644 -index 0000000000000..24e08b01c88a1 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/esparser.c -@@ -0,0 +1,323 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ * -+ * The Elementary Stream Parser is a HW bitstream parser. -+ * It reads bitstream buffers and feeds them to the VIFIFO -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "dos_regs.h" -+#include "esparser.h" -+#include "vdec_helpers.h" -+ -+/* PARSER REGS (CBUS) */ -+#define PARSER_CONTROL 0x00 -+ #define ES_PACK_SIZE_BIT 8 -+ #define ES_WRITE BIT(5) -+ #define ES_SEARCH BIT(1) -+ #define ES_PARSER_START BIT(0) -+#define PARSER_FETCH_ADDR 0x4 -+#define PARSER_FETCH_CMD 0x8 -+#define PARSER_CONFIG 0x14 -+ #define PS_CFG_MAX_FETCH_CYCLE_BIT 0 -+ #define PS_CFG_STARTCODE_WID_24_BIT 10 -+ #define PS_CFG_MAX_ES_WR_CYCLE_BIT 12 -+ #define PS_CFG_PFIFO_EMPTY_CNT_BIT 16 -+#define PFIFO_WR_PTR 0x18 -+#define PFIFO_RD_PTR 0x1c -+#define PARSER_SEARCH_PATTERN 0x24 -+ #define ES_START_CODE_PATTERN 0x00000100 -+#define PARSER_SEARCH_MASK 0x28 -+ #define ES_START_CODE_MASK 0xffffff00 -+ #define FETCH_ENDIAN_BIT 27 -+#define PARSER_INT_ENABLE 0x2c -+ #define PARSER_INT_HOST_EN_BIT 8 -+#define PARSER_INT_STATUS 0x30 -+ #define PARSER_INTSTAT_SC_FOUND 1 -+#define PARSER_ES_CONTROL 0x5c -+#define PARSER_VIDEO_START_PTR 0x80 -+#define PARSER_VIDEO_END_PTR 0x84 -+#define PARSER_VIDEO_WP 0x88 -+#define PARSER_VIDEO_HOLE 0x90 -+ -+#define SEARCH_PATTERN_LEN 512 -+ -+static DECLARE_WAIT_QUEUE_HEAD(wq); -+static int search_done; -+ -+static irqreturn_t esparser_isr(int irq, void *dev) -+{ -+ int int_status; -+ struct amvdec_core *core = dev; -+ -+ int_status = amvdec_read_parser(core, PARSER_INT_STATUS); -+ amvdec_write_parser(core, PARSER_INT_STATUS, int_status); -+ -+ if (int_status & PARSER_INTSTAT_SC_FOUND) { -+ amvdec_write_parser(core, PFIFO_RD_PTR, 0); -+ amvdec_write_parser(core, PFIFO_WR_PTR, 0); -+ search_done = 1; -+ wake_up_interruptible(&wq); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger -+ * ISRs. -+ * Also append a start code 000001ff at the end to trigger -+ * the ESPARSER interrupt. -+ */ -+static u32 esparser_pad_start_code(struct vb2_buffer *vb) -+{ -+ u32 payload_size = vb2_get_plane_payload(vb, 0); -+ u32 pad_size = 0; -+ u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size; -+ -+ if (payload_size < ESPARSER_MIN_PACKET_SIZE) { -+ pad_size = ESPARSER_MIN_PACKET_SIZE - payload_size; -+ memset(vaddr, 0, pad_size); -+ } -+ -+ memset(vaddr + pad_size, 0, SEARCH_PATTERN_LEN); -+ vaddr[pad_size] = 0x00; -+ vaddr[pad_size + 1] = 0x00; -+ vaddr[pad_size + 2] = 0x01; -+ vaddr[pad_size + 3] = 0xff; -+ -+ return pad_size; -+} -+ -+static int -+esparser_write_data(struct amvdec_core *core, dma_addr_t addr, u32 size) -+{ -+ amvdec_write_parser(core, PFIFO_RD_PTR, 0); -+ amvdec_write_parser(core, PFIFO_WR_PTR, 0); -+ amvdec_write_parser(core, PARSER_CONTROL, -+ ES_WRITE | -+ ES_PARSER_START | -+ ES_SEARCH | -+ (size << ES_PACK_SIZE_BIT)); -+ -+ amvdec_write_parser(core, PARSER_FETCH_ADDR, addr); -+ amvdec_write_parser(core, PARSER_FETCH_CMD, -+ (7 << FETCH_ENDIAN_BIT) | -+ (size + SEARCH_PATTERN_LEN)); -+ -+ search_done = 0; -+ return wait_event_interruptible_timeout(wq, search_done, (HZ / 5)); -+} -+ -+static u32 esparser_vififo_get_free_space(struct amvdec_session *sess) -+{ -+ u32 vififo_usage; -+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; -+ struct amvdec_core *core = sess->core; -+ -+ vififo_usage = vdec_ops->vififo_level(sess); -+ vififo_usage += amvdec_read_parser(core, PARSER_VIDEO_HOLE); -+ vififo_usage += (6 * SZ_1K); // 6 KiB internal fifo -+ -+ if (vififo_usage > sess->vififo_size) { -+ dev_warn(sess->core->dev, -+ "VIFIFO usage (%u) > VIFIFO size (%u)\n", -+ vififo_usage, sess->vififo_size); -+ return 0; -+ } -+ -+ return sess->vififo_size - vififo_usage; -+} -+ -+int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len) -+{ -+ struct device *dev = core->dev; -+ void *eos_vaddr; -+ dma_addr_t eos_paddr; -+ int ret; -+ -+ eos_vaddr = dma_alloc_coherent(dev, len + SEARCH_PATTERN_LEN, -+ &eos_paddr, GFP_KERNEL); -+ if (!eos_vaddr) -+ return -ENOMEM; -+ -+ memcpy(eos_vaddr, data, len); -+ ret = esparser_write_data(core, eos_paddr, len); -+ dma_free_coherent(dev, len + SEARCH_PATTERN_LEN, -+ eos_vaddr, eos_paddr); -+ -+ return ret; -+} -+ -+static u32 esparser_get_offset(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 offset = amvdec_read_parser(core, PARSER_VIDEO_WP) - -+ sess->vififo_paddr; -+ -+ if (offset < sess->last_offset) -+ sess->wrap_count++; -+ -+ sess->last_offset = offset; -+ offset += (sess->wrap_count * sess->vififo_size); -+ -+ return offset; -+} -+ -+static int -+esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) -+{ -+ int ret; -+ struct vb2_buffer *vb = &vbuf->vb2_buf; -+ struct amvdec_core *core = sess->core; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ u32 num_dst_bufs = 0; -+ u32 payload_size = vb2_get_plane_payload(vb, 0); -+ dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0); -+ u32 offset; -+ u32 pad_size; -+ -+ if (codec_ops->num_pending_bufs) -+ num_dst_bufs = codec_ops->num_pending_bufs(sess); -+ -+ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -+ -+ if (esparser_vififo_get_free_space(sess) < payload_size || -+ atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) -+ return -EAGAIN; -+ -+ v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf); -+ -+ offset = esparser_get_offset(sess); -+ -+ amvdec_add_ts_reorder(sess, vb->timestamp, offset); -+ dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n", -+ vb->timestamp, payload_size, offset); -+ -+ pad_size = esparser_pad_start_code(vb); -+ ret = esparser_write_data(core, phy, payload_size + pad_size); -+ -+ if (ret <= 0) { -+ dev_warn(core->dev, "esparser: input parsing error\n"); -+ amvdec_remove_ts(sess, vb->timestamp); -+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); -+ amvdec_write_parser(core, PARSER_FETCH_CMD, 0); -+ -+ return 0; -+ } -+ -+ /* We need to wait until we parse the first keyframe. -+ * All buffers prior to the first keyframe must be dropped. -+ */ -+ if (!sess->keyframe_found) -+ usleep_range(1000, 2000); -+ -+ if (sess->keyframe_found) -+ atomic_inc(&sess->esparser_queued_bufs); -+ else -+ amvdec_remove_ts(sess, vb->timestamp); -+ -+ vbuf->flags = 0; -+ vbuf->field = V4L2_FIELD_NONE; -+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); -+ -+ return 0; -+} -+ -+void esparser_queue_all_src(struct work_struct *work) -+{ -+ struct v4l2_m2m_buffer *buf, *n; -+ struct amvdec_session *sess = -+ container_of(work, struct amvdec_session, esparser_queue_work); -+ -+ mutex_lock(&sess->lock); -+ v4l2_m2m_for_each_src_buf_safe(sess->m2m_ctx, buf, n) { -+ if (sess->should_stop) -+ break; -+ -+ if (esparser_queue(sess, &buf->vb) < 0) -+ break; -+ } -+ mutex_unlock(&sess->lock); -+} -+ -+int esparser_power_up(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; -+ -+ reset_control_reset(core->esparser_reset); -+ amvdec_write_parser(core, PARSER_CONFIG, -+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | -+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | -+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT)); -+ -+ amvdec_write_parser(core, PFIFO_RD_PTR, 0); -+ amvdec_write_parser(core, PFIFO_WR_PTR, 0); -+ -+ amvdec_write_parser(core, PARSER_SEARCH_PATTERN, -+ ES_START_CODE_PATTERN); -+ amvdec_write_parser(core, PARSER_SEARCH_MASK, ES_START_CODE_MASK); -+ -+ amvdec_write_parser(core, PARSER_CONFIG, -+ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | -+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | -+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT) | -+ (2 << PS_CFG_STARTCODE_WID_24_BIT)); -+ -+ amvdec_write_parser(core, PARSER_CONTROL, -+ (ES_SEARCH | ES_PARSER_START)); -+ -+ amvdec_write_parser(core, PARSER_VIDEO_START_PTR, sess->vififo_paddr); -+ amvdec_write_parser(core, PARSER_VIDEO_END_PTR, -+ sess->vififo_paddr + sess->vififo_size - 8); -+ amvdec_write_parser(core, PARSER_ES_CONTROL, -+ amvdec_read_parser(core, PARSER_ES_CONTROL) & ~1); -+ -+ if (vdec_ops->conf_esparser) -+ vdec_ops->conf_esparser(sess); -+ -+ amvdec_write_parser(core, PARSER_INT_STATUS, 0xffff); -+ amvdec_write_parser(core, PARSER_INT_ENABLE, -+ BIT(PARSER_INT_HOST_EN_BIT)); -+ -+ return 0; -+} -+ -+int esparser_init(struct platform_device *pdev, struct amvdec_core *core) -+{ -+ struct device *dev = &pdev->dev; -+ int ret; -+ int irq; -+ -+ irq = platform_get_irq_byname(pdev, "esparser"); -+ if (irq < 0) { -+ dev_err(dev, "Failed getting ESPARSER IRQ from dtb\n"); -+ return irq; -+ } -+ -+ ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED, -+ "esparserirq", core); -+ if (ret) { -+ dev_err(dev, "Failed requesting ESPARSER IRQ\n"); -+ return ret; -+ } -+ -+ core->esparser_reset = -+ devm_reset_control_get_exclusive(dev, "esparser"); -+ if (IS_ERR(core->esparser_reset)) { -+ dev_err(dev, "Failed to get esparser_reset\n"); -+ return PTR_ERR(core->esparser_reset); -+ } -+ -+ return 0; -+} -diff --git a/drivers/media/platform/meson/vdec/esparser.h b/drivers/media/platform/meson/vdec/esparser.h -new file mode 100644 -index 0000000000000..ff51fe7fda664 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/esparser.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_ESPARSER_H_ -+#define __MESON_VDEC_ESPARSER_H_ -+ -+#include -+ -+#include "vdec.h" -+ -+int esparser_init(struct platform_device *pdev, struct amvdec_core *core); -+int esparser_power_up(struct amvdec_session *sess); -+ -+/** -+ * esparser_queue_eos() - write End Of Stream sequence to the ESPARSER -+ * -+ * @core vdec core struct -+ */ -+int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len); -+ -+/** -+ * esparser_queue_all_src() - work handler that writes as many src buffers -+ * as possible to the ESPARSER -+ */ -+void esparser_queue_all_src(struct work_struct *work); -+ -+#define ESPARSER_MIN_PACKET_SIZE SZ_4K -+ -+#endif -diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c -new file mode 100644 -index 0000000000000..da96a788ee5c6 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec.c -@@ -0,0 +1,1071 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "vdec.h" -+#include "esparser.h" -+#include "vdec_helpers.h" -+#include "vdec_ctrls.h" -+ -+struct dummy_buf { -+ struct vb2_v4l2_buffer vb; -+ struct list_head list; -+}; -+ -+/* 16 MiB for parsed bitstream swap exchange */ -+#define SIZE_VIFIFO SZ_16M -+ -+static u32 get_output_size(u32 width, u32 height) -+{ -+ return ALIGN(width * height, SZ_64K); -+} -+ -+u32 amvdec_get_output_size(struct amvdec_session *sess) -+{ -+ return get_output_size(sess->width, sess->height); -+} -+EXPORT_SYMBOL_GPL(amvdec_get_output_size); -+ -+static int vdec_codec_needs_recycle(struct amvdec_session *sess) -+{ -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ -+ return codec_ops->can_recycle && codec_ops->recycle; -+} -+ -+static int vdec_recycle_thread(void *data) -+{ -+ struct amvdec_session *sess = data; -+ struct amvdec_core *core = sess->core; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ struct amvdec_buffer *tmp, *n; -+ -+ while (!kthread_should_stop()) { -+ mutex_lock(&sess->bufs_recycle_lock); -+ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { -+ if (!codec_ops->can_recycle(core)) -+ break; -+ -+ codec_ops->recycle(core, tmp->vb->index); -+ list_del(&tmp->list); -+ kfree(tmp); -+ } -+ mutex_unlock(&sess->bufs_recycle_lock); -+ -+ usleep_range(5000, 10000); -+ } -+ -+ return 0; -+} -+ -+static int vdec_poweron(struct amvdec_session *sess) -+{ -+ int ret; -+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; -+ -+ ret = clk_prepare_enable(sess->core->dos_parser_clk); -+ if (ret) -+ return ret; -+ -+ ret = clk_prepare_enable(sess->core->dos_clk); -+ if (ret) -+ goto disable_dos_parser; -+ -+ ret = vdec_ops->start(sess); -+ if (ret) -+ goto disable_dos; -+ -+ esparser_power_up(sess); -+ -+ return 0; -+ -+disable_dos: -+ clk_disable_unprepare(sess->core->dos_clk); -+disable_dos_parser: -+ clk_disable_unprepare(sess->core->dos_parser_clk); -+ -+ return ret; -+} -+ -+static void vdec_wait_inactive(struct amvdec_session *sess) -+{ -+ /* We consider 50ms with no IRQ to be inactive. */ -+ while (time_is_after_jiffies64(sess->last_irq_jiffies + -+ msecs_to_jiffies(50))) -+ msleep(25); -+} -+ -+static void vdec_poweroff(struct amvdec_session *sess) -+{ -+ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ -+ sess->should_stop = 1; -+ vdec_wait_inactive(sess); -+ if (codec_ops->drain) -+ codec_ops->drain(sess); -+ -+ vdec_ops->stop(sess); -+ clk_disable_unprepare(sess->core->dos_clk); -+ clk_disable_unprepare(sess->core->dos_parser_clk); -+} -+ -+static void -+vdec_queue_recycle(struct amvdec_session *sess, struct vb2_buffer *vb) -+{ -+ struct amvdec_buffer *new_buf; -+ -+ new_buf = kmalloc(sizeof(*new_buf), GFP_KERNEL); -+ new_buf->vb = vb; -+ -+ mutex_lock(&sess->bufs_recycle_lock); -+ list_add_tail(&new_buf->list, &sess->bufs_recycle); -+ mutex_unlock(&sess->bufs_recycle_lock); -+} -+ -+static void vdec_m2m_device_run(void *priv) -+{ -+ struct amvdec_session *sess = priv; -+ -+ schedule_work(&sess->esparser_queue_work); -+} -+ -+static void vdec_m2m_job_abort(void *priv) -+{ -+ struct amvdec_session *sess = priv; -+ -+ v4l2_m2m_job_finish(sess->m2m_dev, sess->m2m_ctx); -+} -+ -+static const struct v4l2_m2m_ops vdec_m2m_ops = { -+ .device_run = vdec_m2m_device_run, -+ .job_abort = vdec_m2m_job_abort, -+}; -+ -+static void process_num_buffers(struct vb2_queue *q, -+ struct amvdec_session *sess, -+ unsigned int *num_buffers, -+ bool is_reqbufs) -+{ -+ const struct amvdec_format *fmt_out = sess->fmt_out; -+ unsigned int buffers_total = q->num_buffers + *num_buffers; -+ -+ if (is_reqbufs && buffers_total < fmt_out->min_buffers) -+ *num_buffers = fmt_out->min_buffers - q->num_buffers; -+ if (buffers_total > fmt_out->max_buffers) -+ *num_buffers = fmt_out->max_buffers - q->num_buffers; -+ -+ /* We need to program the complete CAPTURE buffer list -+ * in registers during start_streaming, and the firmwares -+ * are free to choose any of them to write frames to. As such, -+ * we need all of them to be queued into the driver -+ */ -+ sess->num_dst_bufs = q->num_buffers + *num_buffers; -+ q->min_buffers_needed = max(fmt_out->min_buffers, sess->num_dst_bufs); -+} -+ -+static int vdec_queue_setup(struct vb2_queue *q, -+ unsigned int *num_buffers, unsigned int *num_planes, -+ unsigned int sizes[], struct device *alloc_devs[]) -+{ -+ struct amvdec_session *sess = vb2_get_drv_priv(q); -+ u32 output_size = amvdec_get_output_size(sess); -+ -+ if (*num_planes) { -+ switch (q->type) { -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: -+ if (*num_planes != 1 || sizes[0] < output_size) -+ return -EINVAL; -+ break; -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: -+ switch (sess->pixfmt_cap) { -+ case V4L2_PIX_FMT_NV12M: -+ if (*num_planes != 2 || -+ sizes[0] < output_size || -+ sizes[1] < output_size / 2) -+ return -EINVAL; -+ break; -+ case V4L2_PIX_FMT_YUV420M: -+ if (*num_planes != 3 || -+ sizes[0] < output_size || -+ sizes[1] < output_size / 4 || -+ sizes[2] < output_size / 4) -+ return -EINVAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ process_num_buffers(q, sess, num_buffers, false); -+ break; -+ } -+ -+ return 0; -+ } -+ -+ switch (q->type) { -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: -+ sizes[0] = amvdec_get_output_size(sess); -+ *num_planes = 1; -+ break; -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: -+ switch (sess->pixfmt_cap) { -+ case V4L2_PIX_FMT_NV12M: -+ sizes[0] = output_size; -+ sizes[1] = output_size / 2; -+ *num_planes = 2; -+ break; -+ case V4L2_PIX_FMT_YUV420M: -+ sizes[0] = output_size; -+ sizes[1] = output_size / 4; -+ sizes[2] = output_size / 4; -+ *num_planes = 3; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ process_num_buffers(q, sess, num_buffers, true); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static void vdec_vb2_buf_queue(struct vb2_buffer *vb) -+{ -+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); -+ struct amvdec_session *sess = vb2_get_drv_priv(vb->vb2_queue); -+ struct v4l2_m2m_ctx *m2m_ctx = sess->m2m_ctx; -+ -+ v4l2_m2m_buf_queue(m2m_ctx, vbuf); -+ -+ if (!sess->streamon_out || !sess->streamon_cap) -+ return; -+ -+ if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && -+ vdec_codec_needs_recycle(sess)) -+ vdec_queue_recycle(sess, vb); -+ -+ schedule_work(&sess->esparser_queue_work); -+} -+ -+static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) -+{ -+ struct amvdec_session *sess = vb2_get_drv_priv(q); -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ struct amvdec_core *core = sess->core; -+ struct vb2_v4l2_buffer *buf; -+ int ret; -+ -+ if (core->cur_sess && core->cur_sess != sess) { -+ ret = -EBUSY; -+ goto bufs_done; -+ } -+ -+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) -+ sess->streamon_out = 1; -+ else -+ sess->streamon_cap = 1; -+ -+ if (!sess->streamon_out || !sess->streamon_cap) -+ return 0; -+ -+ if (sess->status == STATUS_NEEDS_RESUME && -+ q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { -+ codec_ops->resume(sess); -+ sess->status = STATUS_RUNNING; -+ return 0; -+ } -+ -+ sess->vififo_size = SIZE_VIFIFO; -+ sess->vififo_vaddr = -+ dma_alloc_coherent(sess->core->dev, sess->vififo_size, -+ &sess->vififo_paddr, GFP_KERNEL); -+ if (!sess->vififo_vaddr) { -+ dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n"); -+ ret = -ENOMEM; -+ goto bufs_done; -+ } -+ -+ sess->should_stop = 0; -+ sess->keyframe_found = 0; -+ sess->last_offset = 0; -+ sess->wrap_count = 0; -+ sess->dpb_size = 1; -+ sess->pixelaspect.numerator = 1; -+ sess->pixelaspect.denominator = 1; -+ atomic_set(&sess->esparser_queued_bufs, 0); -+ -+ ret = vdec_poweron(sess); -+ if (ret) -+ goto vififo_free; -+ -+ sess->sequence_cap = 0; -+ if (vdec_codec_needs_recycle(sess)) -+ sess->recycle_thread = kthread_run(vdec_recycle_thread, sess, -+ "vdec_recycle"); -+ -+ sess->status = STATUS_RUNNING; -+ core->cur_sess = sess; -+ -+ return 0; -+ -+vififo_free: -+ dma_free_coherent(sess->core->dev, sess->vififo_size, -+ sess->vififo_vaddr, sess->vififo_paddr); -+bufs_done: -+ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) -+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); -+ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) -+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); -+ -+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) -+ sess->streamon_out = 0; -+ else -+ sess->streamon_cap = 0; -+ -+ return ret; -+} -+ -+static void vdec_free_canvas(struct amvdec_session *sess) -+{ -+ int i; -+ -+ for (i = 0; i < sess->canvas_num; ++i) -+ meson_canvas_free(sess->core->canvas, sess->canvas_alloc[i]); -+ -+ sess->canvas_num = 0; -+} -+ -+static void vdec_reset_timestamps(struct amvdec_session *sess) -+{ -+ struct amvdec_timestamp *tmp, *n; -+ -+ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) { -+ list_del(&tmp->list); -+ kfree(tmp); -+ } -+} -+ -+static void vdec_reset_bufs_recycle(struct amvdec_session *sess) -+{ -+ struct amvdec_buffer *tmp, *n; -+ -+ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { -+ list_del(&tmp->list); -+ kfree(tmp); -+ } -+} -+ -+static void vdec_stop_streaming(struct vb2_queue *q) -+{ -+ struct amvdec_session *sess = vb2_get_drv_priv(q); -+ struct amvdec_core *core = sess->core; -+ struct vb2_v4l2_buffer *buf; -+ -+ if (sess->status == STATUS_RUNNING || -+ (sess->status == STATUS_NEEDS_RESUME && -+ (!sess->streamon_out || !sess->streamon_cap))) { -+ if (vdec_codec_needs_recycle(sess)) -+ kthread_stop(sess->recycle_thread); -+ -+ vdec_poweroff(sess); -+ vdec_free_canvas(sess); -+ dma_free_coherent(sess->core->dev, sess->vififo_size, -+ sess->vififo_vaddr, sess->vififo_paddr); -+ vdec_reset_timestamps(sess); -+ vdec_reset_bufs_recycle(sess); -+ kfree(sess->priv); -+ sess->priv = NULL; -+ core->cur_sess = NULL; -+ sess->status = STATUS_STOPPED; -+ } -+ -+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { -+ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) -+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); -+ -+ sess->streamon_out = 0; -+ } else { -+ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) -+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); -+ -+ sess->streamon_cap = 0; -+ } -+} -+ -+static const struct vb2_ops vdec_vb2_ops = { -+ .queue_setup = vdec_queue_setup, -+ .start_streaming = vdec_start_streaming, -+ .stop_streaming = vdec_stop_streaming, -+ .buf_queue = vdec_vb2_buf_queue, -+ .wait_prepare = vb2_ops_wait_prepare, -+ .wait_finish = vb2_ops_wait_finish, -+}; -+ -+static int -+vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) -+{ -+ strscpy(cap->driver, "meson-vdec", sizeof(cap->driver)); -+ strscpy(cap->card, "Amlogic Video Decoder", sizeof(cap->card)); -+ strscpy(cap->bus_info, "platform:meson-vdec", sizeof(cap->bus_info)); -+ -+ return 0; -+} -+ -+static const struct amvdec_format * -+find_format(const struct amvdec_format *fmts, u32 size, u32 pixfmt) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < size; i++) { -+ if (fmts[i].pixfmt == pixfmt) -+ return &fmts[i]; -+ } -+ -+ return NULL; -+} -+ -+static unsigned int -+vdec_supports_pixfmt_cap(const struct amvdec_format *fmt_out, u32 pixfmt_cap) -+{ -+ int i; -+ -+ for (i = 0; fmt_out->pixfmts_cap[i]; i++) -+ if (fmt_out->pixfmts_cap[i] == pixfmt_cap) -+ return 1; -+ -+ return 0; -+} -+ -+static const struct amvdec_format * -+vdec_try_fmt_common(struct amvdec_session *sess, u32 size, -+ struct v4l2_format *f) -+{ -+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; -+ struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; -+ const struct amvdec_format *fmts = sess->core->platform->formats; -+ const struct amvdec_format *fmt_out; -+ -+ memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); -+ memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); -+ -+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { -+ fmt_out = find_format(fmts, size, pixmp->pixelformat); -+ if (!fmt_out) { -+ pixmp->pixelformat = V4L2_PIX_FMT_MPEG2; -+ fmt_out = find_format(fmts, size, pixmp->pixelformat); -+ } -+ -+ pfmt[0].sizeimage = -+ get_output_size(pixmp->width, pixmp->height); -+ pfmt[0].bytesperline = 0; -+ pixmp->num_planes = 1; -+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { -+ fmt_out = sess->fmt_out; -+ if (!vdec_supports_pixfmt_cap(fmt_out, pixmp->pixelformat)) -+ pixmp->pixelformat = fmt_out->pixfmts_cap[0]; -+ -+ memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved)); -+ if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) { -+ pfmt[0].sizeimage = -+ get_output_size(pixmp->width, pixmp->height); -+ pfmt[0].bytesperline = ALIGN(pixmp->width, 64); -+ -+ pfmt[1].sizeimage = -+ get_output_size(pixmp->width, pixmp->height) / 2; -+ pfmt[1].bytesperline = ALIGN(pixmp->width, 64); -+ pixmp->num_planes = 2; -+ } else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) { -+ pfmt[0].sizeimage = -+ get_output_size(pixmp->width, pixmp->height); -+ pfmt[0].bytesperline = ALIGN(pixmp->width, 64); -+ -+ pfmt[1].sizeimage = -+ get_output_size(pixmp->width, pixmp->height) / 4; -+ pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2; -+ -+ pfmt[2].sizeimage = -+ get_output_size(pixmp->width, pixmp->height) / 4; -+ pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2; -+ pixmp->num_planes = 3; -+ } -+ } else { -+ return NULL; -+ } -+ -+ pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width); -+ pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height); -+ -+ if (pixmp->field == V4L2_FIELD_ANY) -+ pixmp->field = V4L2_FIELD_NONE; -+ -+ return fmt_out; -+} -+ -+static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ -+ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); -+ -+ return 0; -+} -+ -+static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; -+ -+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -+ pixmp->pixelformat = sess->pixfmt_cap; -+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) -+ pixmp->pixelformat = sess->fmt_out->pixfmt; -+ -+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { -+ pixmp->width = sess->width; -+ pixmp->height = sess->height; -+ pixmp->colorspace = sess->colorspace; -+ pixmp->ycbcr_enc = sess->ycbcr_enc; -+ pixmp->quantization = sess->quantization; -+ pixmp->xfer_func = sess->xfer_func; -+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { -+ pixmp->width = sess->width; -+ pixmp->height = sess->height; -+ } -+ -+ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); -+ -+ return 0; -+} -+ -+static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; -+ u32 num_formats = sess->core->platform->num_formats; -+ const struct amvdec_format *fmt_out; -+ struct v4l2_pix_format_mplane orig_pixmp; -+ struct v4l2_format format; -+ u32 pixfmt_out = 0, pixfmt_cap = 0; -+ -+ orig_pixmp = *pixmp; -+ -+ fmt_out = vdec_try_fmt_common(sess, num_formats, f); -+ -+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { -+ pixfmt_out = pixmp->pixelformat; -+ pixfmt_cap = sess->pixfmt_cap; -+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { -+ pixfmt_cap = pixmp->pixelformat; -+ pixfmt_out = sess->fmt_out->pixfmt; -+ } -+ -+ memset(&format, 0, sizeof(format)); -+ -+ format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; -+ format.fmt.pix_mp.pixelformat = pixfmt_out; -+ format.fmt.pix_mp.width = orig_pixmp.width; -+ format.fmt.pix_mp.height = orig_pixmp.height; -+ vdec_try_fmt_common(sess, num_formats, &format); -+ -+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { -+ sess->width = format.fmt.pix_mp.width; -+ sess->height = format.fmt.pix_mp.height; -+ sess->colorspace = pixmp->colorspace; -+ sess->ycbcr_enc = pixmp->ycbcr_enc; -+ sess->quantization = pixmp->quantization; -+ sess->xfer_func = pixmp->xfer_func; -+ } -+ -+ memset(&format, 0, sizeof(format)); -+ -+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; -+ format.fmt.pix_mp.pixelformat = pixfmt_cap; -+ format.fmt.pix_mp.width = orig_pixmp.width; -+ format.fmt.pix_mp.height = orig_pixmp.height; -+ vdec_try_fmt_common(sess, num_formats, &format); -+ -+ sess->width = format.fmt.pix_mp.width; -+ sess->height = format.fmt.pix_mp.height; -+ -+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) -+ sess->fmt_out = fmt_out; -+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -+ sess->pixfmt_cap = format.fmt.pix_mp.pixelformat; -+ -+ return 0; -+} -+ -+static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ const struct vdec_platform *platform = sess->core->platform; -+ const struct amvdec_format *fmt_out; -+ -+ memset(f->reserved, 0, sizeof(f->reserved)); -+ -+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { -+ if (f->index >= platform->num_formats) -+ return -EINVAL; -+ -+ fmt_out = &platform->formats[f->index]; -+ f->pixelformat = fmt_out->pixfmt; -+ f->flags = fmt_out->flags; -+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { -+ fmt_out = sess->fmt_out; -+ if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index]) -+ return -EINVAL; -+ -+ f->pixelformat = fmt_out->pixfmts_cap[f->index]; -+ } else { -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int vdec_enum_framesizes(struct file *file, void *fh, -+ struct v4l2_frmsizeenum *fsize) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ const struct amvdec_format *formats = sess->core->platform->formats; -+ const struct amvdec_format *fmt; -+ u32 num_formats = sess->core->platform->num_formats; -+ -+ fmt = find_format(formats, num_formats, fsize->pixel_format); -+ if (!fmt || fsize->index) -+ return -EINVAL; -+ -+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; -+ -+ fsize->stepwise.min_width = 256; -+ fsize->stepwise.max_width = fmt->max_width; -+ fsize->stepwise.step_width = 1; -+ fsize->stepwise.min_height = 144; -+ fsize->stepwise.max_height = fmt->max_height; -+ fsize->stepwise.step_height = 1; -+ -+ return 0; -+} -+ -+static int -+vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) -+{ -+ switch (cmd->cmd) { -+ case V4L2_DEC_CMD_STOP: -+ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) -+ return -EINVAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int -+vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ struct device *dev = sess->core->dev; -+ int ret; -+ -+ ret = vdec_try_decoder_cmd(file, fh, cmd); -+ if (ret) -+ return ret; -+ -+ if (!(sess->streamon_out & sess->streamon_cap)) -+ return 0; -+ -+ dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n"); -+ sess->should_stop = 1; -+ -+ vdec_wait_inactive(sess); -+ -+ if (codec_ops->drain) { -+ codec_ops->drain(sess); -+ } else if (codec_ops->eos_sequence) { -+ u32 len; -+ const u8 *data = codec_ops->eos_sequence(&len); -+ -+ esparser_queue_eos(sess->core, data, len); -+ } -+ -+ return ret; -+} -+ -+static int vdec_subscribe_event(struct v4l2_fh *fh, -+ const struct v4l2_event_subscription *sub) -+{ -+ switch (sub->type) { -+ case V4L2_EVENT_EOS: -+ return v4l2_event_subscribe(fh, sub, 2, NULL); -+ case V4L2_EVENT_SOURCE_CHANGE: -+ return v4l2_src_change_event_subscribe(fh, sub); -+ case V4L2_EVENT_CTRL: -+ return v4l2_ctrl_subscribe_event(fh, sub); -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int vdec_g_pixelaspect(struct file *file, void *fh, int type, -+ struct v4l2_fract *f) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ -+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -+ return -EINVAL; -+ -+ *f = sess->pixelaspect; -+ return 0; -+} -+ -+static const struct v4l2_ioctl_ops vdec_ioctl_ops = { -+ .vidioc_querycap = vdec_querycap, -+ .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt, -+ .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt, -+ .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt, -+ .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt, -+ .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, -+ .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt, -+ .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt, -+ .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt, -+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, -+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, -+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, -+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, -+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, -+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, -+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, -+ .vidioc_streamon = v4l2_m2m_ioctl_streamon, -+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, -+ .vidioc_enum_framesizes = vdec_enum_framesizes, -+ .vidioc_subscribe_event = vdec_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -+ .vidioc_try_decoder_cmd = vdec_try_decoder_cmd, -+ .vidioc_decoder_cmd = vdec_decoder_cmd, -+ .vidioc_g_pixelaspect = vdec_g_pixelaspect, -+}; -+ -+static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, -+ struct vb2_queue *dst_vq) -+{ -+ struct amvdec_session *sess = priv; -+ int ret; -+ -+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; -+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF; -+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; -+ src_vq->ops = &vdec_vb2_ops; -+ src_vq->mem_ops = &vb2_dma_contig_memops; -+ src_vq->drv_priv = sess; -+ src_vq->buf_struct_size = sizeof(struct dummy_buf); -+ src_vq->min_buffers_needed = 1; -+ src_vq->dev = sess->core->dev; -+ src_vq->lock = &sess->lock; -+ ret = vb2_queue_init(src_vq); -+ if (ret) -+ return ret; -+ -+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; -+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; -+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; -+ dst_vq->ops = &vdec_vb2_ops; -+ dst_vq->mem_ops = &vb2_dma_contig_memops; -+ dst_vq->drv_priv = sess; -+ dst_vq->buf_struct_size = sizeof(struct dummy_buf); -+ dst_vq->min_buffers_needed = 1; -+ dst_vq->dev = sess->core->dev; -+ dst_vq->lock = &sess->lock; -+ ret = vb2_queue_init(dst_vq); -+ if (ret) { -+ vb2_queue_release(src_vq); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int vdec_open(struct file *file) -+{ -+ struct amvdec_core *core = video_drvdata(file); -+ struct device *dev = core->dev; -+ const struct amvdec_format *formats = core->platform->formats; -+ struct amvdec_session *sess; -+ int ret; -+ -+ sess = kzalloc(sizeof(*sess), GFP_KERNEL); -+ if (!sess) -+ return -ENOMEM; -+ -+ sess->core = core; -+ -+ sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops); -+ if (IS_ERR(sess->m2m_dev)) { -+ dev_err(dev, "Fail to v4l2_m2m_init\n"); -+ ret = PTR_ERR(sess->m2m_dev); -+ goto err_free_sess; -+ } -+ -+ sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init); -+ if (IS_ERR(sess->m2m_ctx)) { -+ dev_err(dev, "Fail to v4l2_m2m_ctx_init\n"); -+ ret = PTR_ERR(sess->m2m_ctx); -+ goto err_m2m_release; -+ } -+ -+ ret = amvdec_init_ctrls(&sess->ctrl_handler); -+ if (ret) -+ goto err_m2m_release; -+ -+ sess->pixfmt_cap = formats[0].pixfmts_cap[0]; -+ sess->fmt_out = &formats[0]; -+ sess->width = 1280; -+ sess->height = 720; -+ sess->pixelaspect.numerator = 1; -+ sess->pixelaspect.denominator = 1; -+ sess->dpb_size = 1; -+ -+ INIT_LIST_HEAD(&sess->timestamps); -+ INIT_LIST_HEAD(&sess->bufs_recycle); -+ INIT_WORK(&sess->esparser_queue_work, esparser_queue_all_src); -+ mutex_init(&sess->lock); -+ mutex_init(&sess->bufs_recycle_lock); -+ spin_lock_init(&sess->ts_spinlock); -+ -+ v4l2_fh_init(&sess->fh, core->vdev_dec); -+ sess->fh.ctrl_handler = &sess->ctrl_handler; -+ v4l2_fh_add(&sess->fh); -+ sess->fh.m2m_ctx = sess->m2m_ctx; -+ file->private_data = &sess->fh; -+ -+ return 0; -+ -+err_m2m_release: -+ v4l2_m2m_release(sess->m2m_dev); -+err_free_sess: -+ kfree(sess); -+ return ret; -+} -+ -+static int vdec_close(struct file *file) -+{ -+ struct amvdec_session *sess = -+ container_of(file->private_data, struct amvdec_session, fh); -+ -+ v4l2_m2m_ctx_release(sess->m2m_ctx); -+ v4l2_m2m_release(sess->m2m_dev); -+ v4l2_fh_del(&sess->fh); -+ v4l2_fh_exit(&sess->fh); -+ -+ mutex_destroy(&sess->lock); -+ mutex_destroy(&sess->bufs_recycle_lock); -+ -+ kfree(sess); -+ -+ return 0; -+} -+ -+static const struct v4l2_file_operations vdec_fops = { -+ .owner = THIS_MODULE, -+ .open = vdec_open, -+ .release = vdec_close, -+ .unlocked_ioctl = video_ioctl2, -+ .poll = v4l2_m2m_fop_poll, -+ .mmap = v4l2_m2m_fop_mmap, -+}; -+ -+static irqreturn_t vdec_isr(int irq, void *data) -+{ -+ struct amvdec_core *core = data; -+ struct amvdec_session *sess = core->cur_sess; -+ -+ sess->last_irq_jiffies = get_jiffies_64(); -+ -+ return sess->fmt_out->codec_ops->isr(sess); -+} -+ -+static irqreturn_t vdec_threaded_isr(int irq, void *data) -+{ -+ struct amvdec_core *core = data; -+ struct amvdec_session *sess = core->cur_sess; -+ -+ return sess->fmt_out->codec_ops->threaded_isr(sess); -+} -+ -+static const struct of_device_id vdec_dt_match[] = { -+ { .compatible = "amlogic,gxbb-vdec", -+ .data = &vdec_platform_gxbb }, -+ { .compatible = "amlogic,gxm-vdec", -+ .data = &vdec_platform_gxm }, -+ { .compatible = "amlogic,gxl-vdec", -+ .data = &vdec_platform_gxl }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, vdec_dt_match); -+ -+static int vdec_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct video_device *vdev; -+ struct amvdec_core *core; -+ struct resource *r; -+ const struct of_device_id *of_id; -+ int irq; -+ int ret; -+ -+ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); -+ if (!core) -+ return -ENOMEM; -+ -+ core->dev = dev; -+ platform_set_drvdata(pdev, core); -+ -+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dos"); -+ core->dos_base = devm_ioremap_resource(dev, r); -+ if (IS_ERR(core->dos_base)) { -+ dev_err(dev, "Couldn't remap DOS memory\n"); -+ return PTR_ERR(core->dos_base); -+ } -+ -+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "esparser"); -+ core->esparser_base = devm_ioremap_resource(dev, r); -+ if (IS_ERR(core->esparser_base)) { -+ dev_err(dev, "Couldn't remap ESPARSER memory\n"); -+ return PTR_ERR(core->esparser_base); -+ } -+ -+ core->regmap_ao = syscon_regmap_lookup_by_phandle(dev->of_node, -+ "amlogic,ao-sysctrl"); -+ if (IS_ERR(core->regmap_ao)) { -+ dev_err(dev, "Couldn't regmap AO sysctrl\n"); -+ return PTR_ERR(core->regmap_ao); -+ } -+ -+ core->canvas = meson_canvas_get(dev); -+ if (!core->canvas) -+ return PTR_ERR(core->canvas); -+ -+ core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); -+ if (IS_ERR(core->dos_parser_clk)) -+ return -EPROBE_DEFER; -+ -+ core->dos_clk = devm_clk_get(dev, "dos"); -+ if (IS_ERR(core->dos_clk)) -+ return -EPROBE_DEFER; -+ -+ core->vdec_1_clk = devm_clk_get(dev, "vdec_1"); -+ if (IS_ERR(core->vdec_1_clk)) -+ return -EPROBE_DEFER; -+ -+ core->vdec_hevc_clk = devm_clk_get(dev, "vdec_hevc"); -+ if (IS_ERR(core->vdec_hevc_clk)) -+ return -EPROBE_DEFER; -+ -+ irq = platform_get_irq_byname(pdev, "vdec"); -+ if (irq < 0) -+ return irq; -+ -+ ret = devm_request_threaded_irq(core->dev, irq, vdec_isr, -+ vdec_threaded_isr, IRQF_ONESHOT, -+ "vdec", core); -+ if (ret) -+ return ret; -+ -+ ret = esparser_init(pdev, core); -+ if (ret) -+ return ret; -+ -+ ret = v4l2_device_register(dev, &core->v4l2_dev); -+ if (ret) { -+ dev_err(dev, "Couldn't register v4l2 device\n"); -+ return -ENOMEM; -+ } -+ -+ vdev = video_device_alloc(); -+ if (!vdev) { -+ ret = -ENOMEM; -+ goto err_vdev_release; -+ } -+ -+ of_id = of_match_node(vdec_dt_match, dev->of_node); -+ core->platform = of_id->data; -+ core->vdev_dec = vdev; -+ core->dev_dec = dev; -+ mutex_init(&core->lock); -+ -+ strscpy(vdev->name, "meson-video-decoder", sizeof(vdev->name)); -+ vdev->release = video_device_release; -+ vdev->fops = &vdec_fops; -+ vdev->ioctl_ops = &vdec_ioctl_ops; -+ vdev->vfl_dir = VFL_DIR_M2M; -+ vdev->v4l2_dev = &core->v4l2_dev; -+ vdev->lock = &core->lock; -+ vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; -+ -+ video_set_drvdata(vdev, core); -+ -+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); -+ if (ret) { -+ dev_err(dev, "Failed registering video device\n"); -+ goto err_vdev_release; -+ } -+ -+ return 0; -+ -+err_vdev_release: -+ video_device_release(vdev); -+ return ret; -+} -+ -+static int vdec_remove(struct platform_device *pdev) -+{ -+ struct amvdec_core *core = platform_get_drvdata(pdev); -+ -+ video_unregister_device(core->vdev_dec); -+ -+ return 0; -+} -+ -+static struct platform_driver meson_vdec_driver = { -+ .probe = vdec_probe, -+ .remove = vdec_remove, -+ .driver = { -+ .name = "meson-vdec", -+ .of_match_table = vdec_dt_match, -+ }, -+}; -+module_platform_driver(meson_vdec_driver); -+ -+MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM"); -+MODULE_AUTHOR("Maxime Jourdan "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h -new file mode 100644 -index 0000000000000..9f1e307057220 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec.h -@@ -0,0 +1,265 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CORE_H_ -+#define __MESON_VDEC_CORE_H_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "vdec_platform.h" -+ -+/* 32 buffers in 3-plane YUV420 */ -+#define MAX_CANVAS (32 * 3) -+ -+struct amvdec_buffer { -+ struct list_head list; -+ struct vb2_buffer *vb; -+}; -+ -+/** -+ * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset -+ * -+ * @list: used to make lists out of this struct -+ * @ts: timestamp -+ * @offset: offset in the VIFIFO where the associated packet was written -+ */ -+struct amvdec_timestamp { -+ struct list_head list; -+ u64 ts; -+ u32 offset; -+}; -+ -+struct amvdec_session; -+ -+/** -+ * struct amvdec_core - device parameters, singleton -+ * -+ * @dos_base: DOS memory base address -+ * @esparser_base: PARSER memory base address -+ * @regmap_ao: regmap for the AO bus -+ * @dev: core device -+ * @dev_dec: decoder device -+ * @platform: platform-specific data -+ * @canvas: canvas provider reference -+ * @dos_parser_clk: DOS_PARSER clock -+ * @dos_clk: DOS clock -+ * @vdec_1_clk: VDEC_1 clock -+ * @vdec_hevc_clk: VDEC_HEVC clock -+ * @esparser_reset: RESET for the PARSER -+ * @vdec_dec: video device for the decoder -+ * @v4l2_dev: v4l2 device -+ * @cur_sess: current decoding session -+ * @lock: lock for this structure -+ */ -+struct amvdec_core { -+ void __iomem *dos_base; -+ void __iomem *esparser_base; -+ struct regmap *regmap_ao; -+ -+ struct device *dev; -+ struct device *dev_dec; -+ const struct vdec_platform *platform; -+ -+ struct meson_canvas *canvas; -+ -+ struct clk *dos_parser_clk; -+ struct clk *dos_clk; -+ struct clk *vdec_1_clk; -+ struct clk *vdec_hevc_clk; -+ -+ struct reset_control *esparser_reset; -+ -+ struct video_device *vdev_dec; -+ struct v4l2_device v4l2_dev; -+ -+ struct amvdec_session *cur_sess; -+ struct mutex lock; -+}; -+ -+/** -+ * struct amvdec_ops - vdec operations -+ * -+ * @start: mandatory call when the vdec needs to initialize -+ * @stop: mandatory call when the vdec needs to stop -+ * @conf_esparser: mandatory call to let the vdec configure the ESPARSER -+ * @vififo_level: mandatory call to get the current amount of data -+ * in the VIFIFO -+ * @use_offsets: mandatory call. Returns 1 if the VDEC supports vififo offsets -+ */ -+struct amvdec_ops { -+ int (*start)(struct amvdec_session *sess); -+ int (*stop)(struct amvdec_session *sess); -+ void (*conf_esparser)(struct amvdec_session *sess); -+ u32 (*vififo_level)(struct amvdec_session *sess); -+}; -+ -+/** -+ * struct amvdec_codec_ops - codec operations -+ * -+ * @start: mandatory call when the codec needs to initialize -+ * @stop: mandatory call when the codec needs to stop -+ * @load_extended_firmware: optional call to load additional firmware bits -+ * @num_pending_bufs: optional call to get the number of dst buffers on hold -+ * @can_recycle: optional call to know if the codec is ready to recycle -+ * a dst buffer -+ * @recycle: optional call to tell the codec to recycle a dst buffer. Must go -+ * in pair with @can_recycle -+ * @drain: optional call if the codec has a custom way of draining -+ * @eos_sequence: optional call to get an end sequence to send to esparser -+ * for flush. Mutually exclusive with @drain. -+ * @isr: mandatory call when the ISR triggers -+ * @threaded_isr: mandatory call for the threaded ISR -+ */ -+struct amvdec_codec_ops { -+ int (*start)(struct amvdec_session *sess); -+ int (*stop)(struct amvdec_session *sess); -+ int (*load_extended_firmware)(struct amvdec_session *sess, -+ const u8 *data, u32 len); -+ u32 (*num_pending_bufs)(struct amvdec_session *sess); -+ int (*can_recycle)(struct amvdec_core *core); -+ void (*recycle)(struct amvdec_core *core, u32 buf_idx); -+ void (*drain)(struct amvdec_session *sess); -+ void (*resume)(struct amvdec_session *sess); -+ const u8 * (*eos_sequence)(u32 *len); -+ irqreturn_t (*isr)(struct amvdec_session *sess); -+ irqreturn_t (*threaded_isr)(struct amvdec_session *sess); -+}; -+ -+/** -+ * struct amvdec_format - describes one of the OUTPUT (src) format supported -+ * -+ * @pixfmt: V4L2 pixel format -+ * @min_buffers: minimum amount of CAPTURE (dst) buffers -+ * @max_buffers: maximum amount of CAPTURE (dst) buffers -+ * @max_width: maximum picture width supported -+ * @max_height: maximum picture height supported -+ * @flags: enum flags associated with this pixfmt -+ * @vdec_ops: the VDEC operations that support this format -+ * @codec_ops: the codec operations that support this format -+ * @firmware_path: Path to the firmware that supports this format -+ * @pixfmts_cap: list of CAPTURE pixel formats available with pixfmt -+ */ -+struct amvdec_format { -+ u32 pixfmt; -+ u32 min_buffers; -+ u32 max_buffers; -+ u32 max_width; -+ u32 max_height; -+ u32 flags; -+ -+ struct amvdec_ops *vdec_ops; -+ struct amvdec_codec_ops *codec_ops; -+ -+ char *firmware_path; -+ u32 pixfmts_cap[4]; -+}; -+ -+enum amvdec_status { -+ STATUS_STOPPED, -+ STATUS_RUNNING, -+ STATUS_NEEDS_RESUME, -+}; -+ -+/** -+ * struct amvdec_session - decoding session parameters -+ * -+ * @core: reference to the vdec core struct -+ * @fh: v4l2 file handle -+ * @m2m_dev: v4l2 m2m device -+ * @m2m_ctx: v4l2 m2m context -+ * @lock: session lock -+ * @fmt_out: vdec pixel format for the OUTPUT queue -+ * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue -+ * @width: current picture width -+ * @height: current picture height -+ * @colorspace: current colorspace -+ * @ycbcr_enc: current ycbcr_enc -+ * @quantization: current quantization -+ * @xfer_func: current transfer function -+ * @pixelaspect: Pixel Aspect Ratio reported by the decoder -+ * @esparser_queued_bufs: number of buffers currently queued into ESPARSER -+ * @esparser_queue_work: work struct for the ESPARSER to process src buffers -+ * @streamon_cap: stream on flag for capture queue -+ * @streamon_out: stream on flag for output queue -+ * @sequence_cap: capture sequence counter -+ * @should_stop: flag set if userspace signaled EOS via command -+ * or empty buffer -+ * @keyframe_found: flag set once a keyframe has been parsed -+ * @canvas_alloc: array of all the canvas IDs allocated -+ * @canvas_num: number of canvas IDs allocated -+ * @vififo_vaddr: virtual address for the VIFIFO -+ * @vififo_paddr: physical address for the VIFIFO -+ * @vififo_size: size of the VIFIFO dma alloc -+ * @bufs_recycle: list of buffers that need to be recycled -+ * @bufs_recycle_lock: lock for the bufs_recycle list -+ * @recycle_thread: task struct for the recycling thread -+ * @timestamps: chronological list of src timestamps -+ * @ts_spinlock: spinlock for the timestamps list -+ * @last_irq_jiffies: tracks last time the vdec triggered an IRQ -+ * @status: current decoding status -+ * @priv: codec private data -+ */ -+struct amvdec_session { -+ struct amvdec_core *core; -+ -+ struct v4l2_fh fh; -+ struct v4l2_m2m_dev *m2m_dev; -+ struct v4l2_m2m_ctx *m2m_ctx; -+ struct v4l2_ctrl_handler ctrl_handler; -+ struct mutex lock; -+ -+ const struct amvdec_format *fmt_out; -+ u32 pixfmt_cap; -+ -+ u32 width; -+ u32 height; -+ u32 colorspace; -+ u8 ycbcr_enc; -+ u8 quantization; -+ u8 xfer_func; -+ -+ struct v4l2_fract pixelaspect; -+ -+ atomic_t esparser_queued_bufs; -+ struct work_struct esparser_queue_work; -+ -+ unsigned int streamon_cap, streamon_out; -+ unsigned int sequence_cap; -+ unsigned int should_stop; -+ unsigned int keyframe_found; -+ unsigned int num_dst_bufs; -+ -+ u8 canvas_alloc[MAX_CANVAS]; -+ u32 canvas_num; -+ -+ void *vififo_vaddr; -+ dma_addr_t vififo_paddr; -+ u32 vififo_size; -+ -+ struct list_head bufs_recycle; -+ struct mutex bufs_recycle_lock; -+ struct task_struct *recycle_thread; -+ -+ struct list_head timestamps; -+ spinlock_t ts_spinlock; -+ -+ u64 last_irq_jiffies; -+ u32 last_offset; -+ u32 wrap_count; -+ u32 dpb_size; -+ -+ enum amvdec_status status; -+ void *priv; -+}; -+ -+u32 amvdec_get_output_size(struct amvdec_session *sess); -+ -+#endif -diff --git a/drivers/media/platform/meson/vdec/vdec_1.c b/drivers/media/platform/meson/vdec/vdec_1.c -new file mode 100644 -index 0000000000000..074767d4cb2c2 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_1.c -@@ -0,0 +1,229 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ * -+ * VDEC_1 is a video decoding block that allows decoding of -+ * MPEG 1/2/4, H.263, H.264, MJPEG, VC1 -+ */ -+ -+#include -+#include -+ -+#include "vdec_1.h" -+#include "vdec_helpers.h" -+#include "dos_regs.h" -+ -+/* AO Registers */ -+#define AO_RTI_GEN_PWR_SLEEP0 0xe8 -+#define AO_RTI_GEN_PWR_ISO0 0xec -+ #define GEN_PWR_VDEC_1 (BIT(3) | BIT(2)) -+ -+#define MC_SIZE (4096 * 4) -+ -+static int -+vdec_1_load_firmware(struct amvdec_session *sess, const char *fwname) -+{ -+ const struct firmware *fw; -+ struct amvdec_core *core = sess->core; -+ struct device *dev = core->dev_dec; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ static void *mc_addr; -+ static dma_addr_t mc_addr_map; -+ int ret; -+ u32 i = 1000; -+ -+ ret = request_firmware(&fw, fwname, dev); -+ if (ret < 0) -+ return -EINVAL; -+ -+ if (fw->size < MC_SIZE) { -+ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", -+ fw->size, MC_SIZE); -+ ret = -EINVAL; -+ goto release_firmware; -+ } -+ -+ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, -+ &mc_addr_map, GFP_KERNEL); -+ if (!mc_addr) { -+ ret = -ENOMEM; -+ goto release_firmware; -+ } -+ -+ memcpy(mc_addr, fw->data, MC_SIZE); -+ -+ amvdec_write_dos(core, MPSR, 0); -+ amvdec_write_dos(core, CPSR, 0); -+ -+ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); -+ -+ amvdec_write_dos(core, IMEM_DMA_ADR, mc_addr_map); -+ amvdec_write_dos(core, IMEM_DMA_COUNT, MC_SIZE / 4); -+ amvdec_write_dos(core, IMEM_DMA_CTRL, (0x8000 | (7 << 16))); -+ -+ while (--i && amvdec_read_dos(core, IMEM_DMA_CTRL) & 0x8000); -+ -+ if (i == 0) { -+ dev_err(dev, "Firmware load fail (DMA hang?)\n"); -+ ret = -EINVAL; -+ goto free_mc; -+ } -+ -+ if (codec_ops->load_extended_firmware) -+ ret = codec_ops->load_extended_firmware(sess, -+ fw->data + MC_SIZE, -+ fw->size - MC_SIZE); -+ -+free_mc: -+ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); -+release_firmware: -+ release_firmware(fw); -+ return ret; -+} -+ -+int vdec_1_stbuf_power_up(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_CONTROL, 0); -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_WRAP_COUNT, 0); -+ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4)); -+ -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_START_PTR, sess->vififo_paddr); -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_CURR_PTR, sess->vififo_paddr); -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_END_PTR, -+ sess->vififo_paddr + sess->vififo_size - 8); -+ -+ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); -+ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); -+ -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL); -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_WP, sess->vififo_paddr); -+ -+ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); -+ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); -+ -+ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, -+ (0x11 << MEM_FIFO_CNT_BIT) | MEM_FILL_ON_LEVEL | -+ MEM_CTRL_FILL_EN | MEM_CTRL_EMPTY_EN); -+ -+ return 0; -+} -+ -+static void vdec_1_conf_esparser(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ /* VDEC_1 specific ESPARSER stuff */ -+ amvdec_write_dos(core, DOS_GEN_CTRL0, 0); -+ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); -+ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); -+} -+ -+static u32 vdec_1_vififo_level(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ return amvdec_read_dos(core, VLD_MEM_VIFIFO_LEVEL); -+} -+ -+static int vdec_1_stop(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ -+ amvdec_write_dos(core, MPSR, 0); -+ amvdec_write_dos(core, CPSR, 0); -+ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 0); -+ -+ amvdec_write_dos(core, DOS_SW_RESET0, BIT(12) | BIT(11)); -+ amvdec_write_dos(core, DOS_SW_RESET0, 0); -+ amvdec_read_dos(core, DOS_SW_RESET0); -+ -+ /* enable vdec1 isolation */ -+ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc0); -+ /* power off vdec1 memories */ -+ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0xffffffff); -+ /* power off vdec1 */ -+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VDEC_1, GEN_PWR_VDEC_1); -+ -+ clk_disable_unprepare(core->vdec_1_clk); -+ -+ if (sess->priv) -+ codec_ops->stop(sess); -+ -+ return 0; -+} -+ -+static int vdec_1_start(struct amvdec_session *sess) -+{ -+ int ret; -+ struct amvdec_core *core = sess->core; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ -+ /* Configure the vdec clk to the maximum available */ -+ clk_set_rate(core->vdec_1_clk, 666666666); -+ ret = clk_prepare_enable(core->vdec_1_clk); -+ if (ret) -+ return ret; -+ -+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VDEC_1, 0); -+ udelay(10); -+ -+ /* Reset VDEC1 */ -+ amvdec_write_dos(core, DOS_SW_RESET0, 0xfffffffc); -+ amvdec_write_dos(core, DOS_SW_RESET0, 0x00000000); -+ -+ amvdec_write_dos(core, DOS_GCLK_EN0, 0x3ff); -+ -+ /* enable VDEC Memories */ -+ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0); -+ /* Remove VDEC1 Isolation */ -+ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0); -+ /* Reset DOS top registers */ -+ amvdec_write_dos(core, DOS_VDEC_MCRCC_STALL_CTRL, 0); -+ -+ amvdec_write_dos(core, GCLK_EN, 0x3ff); -+ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); -+ -+ vdec_1_stbuf_power_up(sess); -+ -+ ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path); -+ if (ret) -+ goto stop; -+ -+ ret = codec_ops->start(sess); -+ if (ret) -+ goto stop; -+ -+ /* Enable IRQ */ -+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); -+ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 1); -+ -+ /* Enable 2-plane output */ -+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) -+ amvdec_write_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); -+ else -+ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); -+ -+ /* Enable firmware processor */ -+ amvdec_write_dos(core, MPSR, 1); -+ /* Let the firmware settle */ -+ udelay(10); -+ -+ return 0; -+ -+stop: -+ vdec_1_stop(sess); -+ return ret; -+} -+ -+struct amvdec_ops vdec_1_ops = { -+ .start = vdec_1_start, -+ .stop = vdec_1_stop, -+ .conf_esparser = vdec_1_conf_esparser, -+ .vififo_level = vdec_1_vififo_level, -+}; -diff --git a/drivers/media/platform/meson/vdec/vdec_1.h b/drivers/media/platform/meson/vdec/vdec_1.h -new file mode 100644 -index 0000000000000..042d930c40d77 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_1.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_VDEC_1_H_ -+#define __MESON_VDEC_VDEC_1_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_ops vdec_1_ops; -+ -+#endif -diff --git a/drivers/media/platform/meson/vdec/vdec_ctrls.c b/drivers/media/platform/meson/vdec/vdec_ctrls.c -new file mode 100644 -index 0000000000000..d5d6b1b97aa54 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_ctrls.c -@@ -0,0 +1,51 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#include "vdec_ctrls.h" -+ -+static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct amvdec_session *sess = -+ container_of(ctrl->handler, struct amvdec_session, ctrl_handler); -+ -+ switch (ctrl->id) { -+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: -+ ctrl->val = sess->dpb_size; -+ break; -+ default: -+ return -EINVAL; -+ }; -+ -+ return 0; -+} -+ -+static const struct v4l2_ctrl_ops vdec_ctrl_ops = { -+ .g_volatile_ctrl = vdec_op_g_volatile_ctrl, -+}; -+ -+int amvdec_init_ctrls(struct v4l2_ctrl_handler *ctrl_handler) -+{ -+ int ret; -+ struct v4l2_ctrl *ctrl; -+ -+ ret = v4l2_ctrl_handler_init(ctrl_handler, 1); -+ if (ret) -+ return ret; -+ -+ ctrl = v4l2_ctrl_new_std(ctrl_handler, &vdec_ctrl_ops, -+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1); -+ if (ctrl) -+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; -+ -+ ret = ctrl_handler->error; -+ if (ret) { -+ v4l2_ctrl_handler_free(ctrl_handler); -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(amvdec_init_ctrls); -diff --git a/drivers/media/platform/meson/vdec/vdec_ctrls.h b/drivers/media/platform/meson/vdec/vdec_ctrls.h -new file mode 100644 -index 0000000000000..91bf0aabc17e4 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_ctrls.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CTRLS_H_ -+#define __MESON_VDEC_CTRLS_H_ -+ -+#include "vdec.h" -+ -+int amvdec_init_ctrls(struct v4l2_ctrl_handler *ctrl_handler); -+ -+#endif -diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c -new file mode 100644 -index 0000000000000..5adf9a378b32c ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_helpers.c -@@ -0,0 +1,441 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "vdec_helpers.h" -+ -+#define NUM_CANVAS_NV12 2 -+#define NUM_CANVAS_YUV420 3 -+ -+u32 amvdec_read_dos(struct amvdec_core *core, u32 reg) -+{ -+ return readl_relaxed(core->dos_base + reg); -+} -+EXPORT_SYMBOL_GPL(amvdec_read_dos); -+ -+void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val) -+{ -+ writel_relaxed(val, core->dos_base + reg); -+} -+EXPORT_SYMBOL_GPL(amvdec_write_dos); -+ -+void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val) -+{ -+ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) | val); -+} -+EXPORT_SYMBOL_GPL(amvdec_write_dos_bits); -+ -+void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val) -+{ -+ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) & ~val); -+} -+EXPORT_SYMBOL_GPL(amvdec_clear_dos_bits); -+ -+u32 amvdec_read_parser(struct amvdec_core *core, u32 reg) -+{ -+ return readl_relaxed(core->esparser_base + reg); -+} -+EXPORT_SYMBOL_GPL(amvdec_read_parser); -+ -+void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val) -+{ -+ writel_relaxed(val, core->esparser_base + reg); -+} -+EXPORT_SYMBOL_GPL(amvdec_write_parser); -+ -+static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id) -+{ -+ int ret; -+ -+ if (sess->canvas_num >= MAX_CANVAS) { -+ dev_err(sess->core->dev, "Reached max number of canvas\n"); -+ return -ENOMEM; -+ } -+ -+ ret = meson_canvas_alloc(sess->core->canvas, canvas_id); -+ if (ret) -+ return ret; -+ -+ sess->canvas_alloc[sess->canvas_num++] = *canvas_id; -+ return 0; -+} -+ -+static int set_canvas_yuv420m(struct amvdec_session *sess, -+ struct vb2_buffer *vb, u32 width, -+ u32 height, u32 reg) -+{ -+ struct amvdec_core *core = sess->core; -+ u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */ -+ dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */ -+ int ret, i; -+ -+ for (i = 0; i < NUM_CANVAS_YUV420; ++i) { -+ ret = canvas_alloc(sess, &canvas_id[i]); -+ if (ret) -+ return ret; -+ -+ buf_paddr[i] = -+ vb2_dma_contig_plane_dma_addr(vb, i); -+ } -+ -+ /* Y plane */ -+ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0], -+ width, height, MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); -+ -+ /* U plane */ -+ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1], -+ width / 2, height / 2, MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); -+ -+ /* V plane */ -+ meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2], -+ width / 2, height / 2, MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); -+ -+ amvdec_write_dos(core, reg, -+ ((canvas_id[2]) << 16) | -+ ((canvas_id[1]) << 8) | -+ (canvas_id[0])); -+ -+ return 0; -+} -+ -+static int set_canvas_nv12m(struct amvdec_session *sess, -+ struct vb2_buffer *vb, u32 width, -+ u32 height, u32 reg) -+{ -+ struct amvdec_core *core = sess->core; -+ u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */ -+ dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */ -+ int ret, i; -+ -+ for (i = 0; i < NUM_CANVAS_NV12; ++i) { -+ ret = canvas_alloc(sess, &canvas_id[i]); -+ if (ret) -+ return ret; -+ -+ buf_paddr[i] = -+ vb2_dma_contig_plane_dma_addr(vb, i); -+ } -+ -+ /* Y plane */ -+ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0], -+ width, height, MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); -+ -+ /* U/V plane */ -+ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1], -+ width, height / 2, MESON_CANVAS_WRAP_NONE, -+ MESON_CANVAS_BLKMODE_LINEAR, -+ MESON_CANVAS_ENDIAN_SWAP64); -+ -+ amvdec_write_dos(core, reg, -+ ((canvas_id[1]) << 16) | -+ ((canvas_id[1]) << 8) | -+ (canvas_id[0])); -+ -+ return 0; -+} -+ -+int amvdec_set_canvases(struct amvdec_session *sess, -+ u32 reg_base[], u32 reg_num[]) -+{ -+ struct v4l2_m2m_buffer *buf; -+ u32 pixfmt = sess->pixfmt_cap; -+ u32 width = ALIGN(sess->width, 64); -+ u32 height = ALIGN(sess->height, 64); -+ u32 reg_cur = reg_base[0]; -+ u32 reg_num_cur = 0; -+ u32 reg_base_cur = 0; -+ int ret; -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ if (!reg_base[reg_base_cur]) -+ return -EINVAL; -+ -+ reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4; -+ -+ switch (pixfmt) { -+ case V4L2_PIX_FMT_NV12M: -+ ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width, -+ height, reg_cur); -+ if (ret) -+ return ret; -+ break; -+ case V4L2_PIX_FMT_YUV420M: -+ ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width, -+ height, reg_cur); -+ if (ret) -+ return ret; -+ break; -+ default: -+ dev_err(sess->core->dev, "Unsupported pixfmt %08X\n", -+ pixfmt); -+ return -EINVAL; -+ } -+ -+ reg_num_cur++; -+ if (reg_num_cur >= reg_num[reg_base_cur]) { -+ reg_base_cur++; -+ reg_num_cur = 0; -+ } -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(amvdec_set_canvases); -+ -+void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset) -+{ -+ struct amvdec_timestamp *new_ts, *tmp; -+ unsigned long flags; -+ -+ new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL); -+ new_ts->ts = ts; -+ new_ts->offset = offset; -+ -+ spin_lock_irqsave(&sess->ts_spinlock, flags); -+ -+ if (list_empty(&sess->timestamps)) -+ goto add_tail; -+ -+ list_for_each_entry(tmp, &sess->timestamps, list) { -+ if (ts <= tmp->ts) { -+ list_add_tail(&new_ts->list, &tmp->list); -+ goto unlock; -+ } -+ } -+ -+add_tail: -+ list_add_tail(&new_ts->list, &sess->timestamps); -+unlock: -+ spin_unlock_irqrestore(&sess->ts_spinlock, flags); -+} -+EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder); -+ -+void amvdec_remove_ts(struct amvdec_session *sess, u64 ts) -+{ -+ struct amvdec_timestamp *tmp; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sess->ts_spinlock, flags); -+ list_for_each_entry(tmp, &sess->timestamps, list) { -+ if (tmp->ts == ts) { -+ list_del(&tmp->list); -+ kfree(tmp); -+ goto unlock; -+ } -+ } -+ dev_warn(sess->core->dev_dec, -+ "Couldn't remove buffer with timestamp %llu from list\n", ts); -+ -+unlock: -+ spin_unlock_irqrestore(&sess->ts_spinlock, flags); -+} -+EXPORT_SYMBOL_GPL(amvdec_remove_ts); -+ -+static void dst_buf_done(struct amvdec_session *sess, -+ struct vb2_v4l2_buffer *vbuf, -+ u32 field, -+ u64 timestamp) -+{ -+ struct device *dev = sess->core->dev_dec; -+ u32 output_size = amvdec_get_output_size(sess); -+ -+ switch (sess->pixfmt_cap) { -+ case V4L2_PIX_FMT_NV12M: -+ vbuf->vb2_buf.planes[0].bytesused = output_size; -+ vbuf->vb2_buf.planes[1].bytesused = output_size / 2; -+ break; -+ case V4L2_PIX_FMT_YUV420M: -+ vbuf->vb2_buf.planes[0].bytesused = output_size; -+ vbuf->vb2_buf.planes[1].bytesused = output_size / 4; -+ vbuf->vb2_buf.planes[2].bytesused = output_size / 4; -+ break; -+ } -+ -+ vbuf->vb2_buf.timestamp = timestamp; -+ vbuf->sequence = sess->sequence_cap++; -+ -+ if (sess->should_stop && -+ atomic_read(&sess->esparser_queued_bufs) <= 2) { -+ const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; -+ -+ dev_dbg(dev, "Signaling EOS\n"); -+ v4l2_event_queue_fh(&sess->fh, &ev); -+ vbuf->flags |= V4L2_BUF_FLAG_LAST; -+ } else if (sess->should_stop) -+ dev_dbg(dev, "should_stop, %u bufs remain\n", -+ atomic_read(&sess->esparser_queued_bufs)); -+ -+ dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index); -+ vbuf->field = field; -+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); -+ -+ /* Buffer done probably means the vififo got freed */ -+ schedule_work(&sess->esparser_queue_work); -+} -+ -+void amvdec_dst_buf_done(struct amvdec_session *sess, -+ struct vb2_v4l2_buffer *vbuf, u32 field) -+{ -+ struct device *dev = sess->core->dev_dec; -+ struct amvdec_timestamp *tmp; -+ struct list_head *timestamps = &sess->timestamps; -+ u64 timestamp; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sess->ts_spinlock, flags); -+ if (list_empty(timestamps)) { -+ dev_err(dev, "Buffer %u done but list is empty\n", -+ vbuf->vb2_buf.index); -+ -+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); -+ spin_unlock_irqrestore(&sess->ts_spinlock, flags); -+ return; -+ } -+ -+ tmp = list_first_entry(timestamps, struct amvdec_timestamp, list); -+ timestamp = tmp->ts; -+ list_del(&tmp->list); -+ kfree(tmp); -+ spin_unlock_irqrestore(&sess->ts_spinlock, flags); -+ -+ dst_buf_done(sess, vbuf, field, timestamp); -+ atomic_dec(&sess->esparser_queued_bufs); -+} -+EXPORT_SYMBOL_GPL(amvdec_dst_buf_done); -+ -+static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, -+ struct vb2_v4l2_buffer *vbuf, -+ u32 offset, -+ u32 field) -+{ -+ struct device *dev = sess->core->dev_dec; -+ struct amvdec_timestamp *match = NULL; -+ struct amvdec_timestamp *tmp, *n; -+ u64 timestamp = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sess->ts_spinlock, flags); -+ -+ /* Look for our vififo offset to get the corresponding timestamp. */ -+ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) { -+ s64 delta = (s64)offset - tmp->offset; -+ -+ /* Offsets reported by codecs usually differ slightly, -+ * so we need some wiggle room. -+ * 4KiB being the minimum packet size, there is no risk here. -+ */ -+ if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) { -+ match = tmp; -+ break; -+ } -+ -+ /* Delete any timestamp entry that appears before our target -+ * (not all src packets/timestamps lead to a frame) -+ */ -+ if (delta > 0 || delta < -1 * (s32)sess->vififo_size) { -+ atomic_dec(&sess->esparser_queued_bufs); -+ list_del(&tmp->list); -+ kfree(tmp); -+ } -+ } -+ -+ if (!match) { -+ dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n", -+ vbuf->vb2_buf.index, offset); -+ } else { -+ timestamp = match->ts; -+ list_del(&match->list); -+ kfree(match); -+ } -+ spin_unlock_irqrestore(&sess->ts_spinlock, flags); -+ -+ dst_buf_done(sess, vbuf, field, timestamp); -+ if (match) -+ atomic_dec(&sess->esparser_queued_bufs); -+} -+ -+void amvdec_dst_buf_done_idx(struct amvdec_session *sess, -+ u32 buf_idx, u32 offset, u32 field) -+{ -+ struct vb2_v4l2_buffer *vbuf; -+ struct device *dev = sess->core->dev_dec; -+ -+ vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, buf_idx); -+ if (!vbuf) { -+ dev_err(dev, -+ "Buffer %u done but it doesn't exist in m2m_ctx\n", -+ buf_idx); -+ return; -+ } -+ -+ if (offset != -1) -+ amvdec_dst_buf_done_offset(sess, vbuf, offset, field); -+ else -+ amvdec_dst_buf_done(sess, vbuf, field); -+} -+EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx); -+ -+void amvdec_set_par_from_dar(struct amvdec_session *sess, -+ u32 dar_num, u32 dar_den) -+{ -+ u32 div; -+ -+ sess->pixelaspect.numerator = sess->height * dar_num; -+ sess->pixelaspect.denominator = sess->width * dar_den; -+ div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator); -+ sess->pixelaspect.numerator /= div; -+ sess->pixelaspect.denominator /= div; -+} -+EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar); -+ -+void amvdec_src_change(struct amvdec_session *sess, u32 width, -+ u32 height, u32 dpb_size) -+{ -+ static const struct v4l2_event ev = { -+ .type = V4L2_EVENT_SOURCE_CHANGE, -+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; -+ -+ sess->dpb_size = dpb_size; -+ -+ /* Check if the capture queue is already configured well for our -+ * usecase. If so, keep decoding with it and do not send the event -+ */ -+ if (sess->width == width && -+ sess->height == height && -+ dpb_size <= sess->num_dst_bufs) { -+ sess->fmt_out->codec_ops->resume(sess); -+ return; -+ } -+ -+ sess->width = width; -+ sess->height = height; -+ sess->status = STATUS_NEEDS_RESUME; -+ -+ dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n", -+ width, height, dpb_size); -+ v4l2_event_queue_fh(&sess->fh, &ev); -+} -+EXPORT_SYMBOL_GPL(amvdec_src_change); -+ -+void amvdec_abort(struct amvdec_session *sess) -+{ -+ dev_info(sess->core->dev, "Aborting decoding session!\n"); -+ vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q); -+ vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q); -+} -+EXPORT_SYMBOL_GPL(amvdec_abort); -diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h -new file mode 100644 -index 0000000000000..87b39e048a0fc ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_helpers.h -@@ -0,0 +1,80 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_HELPERS_H_ -+#define __MESON_VDEC_HELPERS_H_ -+ -+#include "vdec.h" -+ -+/** -+ * amvdec_set_canvases() - Map VB2 buffers to canvases -+ * -+ * @sess: current session -+ * @reg_base: Registry bases of where to write the canvas indexes -+ * @reg_num: number of contiguous registers after each reg_base (including it) -+ */ -+int amvdec_set_canvases(struct amvdec_session *sess, -+ u32 reg_base[], u32 reg_num[]); -+ -+/* Helpers to read/write to the various IPs (DOS, PARSER) */ -+u32 amvdec_read_dos(struct amvdec_core *core, u32 reg); -+void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val); -+void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val); -+void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val); -+u32 amvdec_read_parser(struct amvdec_core *core, u32 reg); -+void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val); -+ -+/** -+ * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding -+ * -+ * @sess: current session -+ * @buf_idx: hardware buffer index -+ * @offset: VIFIFO bitstream offset corresponding to the buffer -+ * @field: V4L2 interlaced field -+ */ -+void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx, -+ u32 offset, u32 field); -+void amvdec_dst_buf_done(struct amvdec_session *sess, -+ struct vb2_v4l2_buffer *vbuf, u32 field); -+ -+/** -+ * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order -+ * -+ * @sess: current session -+ * @ts: timestamp to add -+ * @offset: offset in the VIFIFO where the associated packet was written -+ */ -+void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset); -+void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); -+ -+/** -+ * amvdec_set_par_from_dar() - Set Pixel Aspect Ratio from Display Aspect Ratio -+ * -+ * @sess: current session -+ * @dar_num: numerator of the DAR -+ * @dar_den: denominator of the DAR -+ */ -+void amvdec_set_par_from_dar(struct amvdec_session *sess, -+ u32 dar_num, u32 dar_den); -+ -+/** -+ * amvdec_src_change() - Notify new resolution/DPB size to the core -+ * -+ * @sess: current session -+ * @width: picture width detected by the hardware -+ * @height: picture height detected by the hardware -+ * @dpb_size: Decoded Picture Buffer size (= amount of buffers for decoding) -+ */ -+void amvdec_src_change(struct amvdec_session *sess, u32 width, -+ u32 height, u32 dpb_size); -+ -+/** -+ * amvdec_abort() - Abort the current decoding session -+ * -+ * @sess: current session -+ */ -+void amvdec_abort(struct amvdec_session *sess); -+#endif -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c -new file mode 100644 -index 0000000000000..bb8016266ab20 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_platform.c -@@ -0,0 +1,107 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#include "vdec_platform.h" -+#include "vdec.h" -+ -+#include "vdec_1.h" -+#include "codec_mpeg12.h" -+ -+static const struct amvdec_format vdec_formats_gxbb[] = { -+ { -+ .pixfmt = V4L2_PIX_FMT_MPEG1, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_MPEG2, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, -+}; -+ -+static const struct amvdec_format vdec_formats_gxl[] = { -+ { -+ .pixfmt = V4L2_PIX_FMT_MPEG1, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_MPEG2, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, -+}; -+ -+static const struct amvdec_format vdec_formats_gxm[] = { -+ { -+ .pixfmt = V4L2_PIX_FMT_MPEG1, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_MPEG2, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, -+}; -+ -+const struct vdec_platform vdec_platform_gxbb = { -+ .formats = vdec_formats_gxbb, -+ .num_formats = ARRAY_SIZE(vdec_formats_gxbb), -+ .revision = VDEC_REVISION_GXBB, -+}; -+ -+const struct vdec_platform vdec_platform_gxl = { -+ .formats = vdec_formats_gxl, -+ .num_formats = ARRAY_SIZE(vdec_formats_gxl), -+ .revision = VDEC_REVISION_GXL, -+}; -+ -+const struct vdec_platform vdec_platform_gxm = { -+ .formats = vdec_formats_gxm, -+ .num_formats = ARRAY_SIZE(vdec_formats_gxm), -+ .revision = VDEC_REVISION_GXM, -+}; -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.h b/drivers/media/platform/meson/vdec/vdec_platform.h -new file mode 100644 -index 0000000000000..f6025326db1d6 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_platform.h -@@ -0,0 +1,30 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_PLATFORM_H_ -+#define __MESON_VDEC_PLATFORM_H_ -+ -+#include "vdec.h" -+ -+struct amvdec_format; -+ -+enum vdec_revision { -+ VDEC_REVISION_GXBB, -+ VDEC_REVISION_GXL, -+ VDEC_REVISION_GXM, -+}; -+ -+struct vdec_platform { -+ const struct amvdec_format *formats; -+ const u32 num_formats; -+ enum vdec_revision revision; -+}; -+ -+extern const struct vdec_platform vdec_platform_gxbb; -+extern const struct vdec_platform vdec_platform_gxm; -+extern const struct vdec_platform vdec_platform_gxl; -+ -+#endif - -From d4c918a591d5cc7a7941d20d53e76b7043246485 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Mon, 25 Mar 2019 10:14:41 +0100 -Subject: [PATCH 206/249] WIP: MAINTAINERS: Add meson video decoder - -Add an entry for the meson video decoder for amlogic SoCs. - -Signed-off-by: Maxime Jourdan ---- - MAINTAINERS | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index ddc31a0716ab8..f620e30ba67cb 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -10068,6 +10068,14 @@ S: Maintained - F: drivers/mtd/nand/raw/meson_* - F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt - -+MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS -+M: Maxime Jourdan -+L: linux-media@lists.freedesktop.org -+L: linux-amlogic@lists.infradead.org -+S: Supported -+F: drivers/media/platform/meson/vdec/ -+T: git git://linuxtv.org/media_tree.git -+ - METHODE UDPU SUPPORT - M: Vladimir Vid - S: Maintained - -From 2f282c662b80bd2910b0186c5d82373f9b805ffe Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 29 Aug 2018 15:24:02 +0200 -Subject: [PATCH 207/249] WIP: arm64: dts: meson-gx: add vdec entry - -Add the video decoder dts entry - -Signed-off-by: Maxime Jourdan ---- - arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -index b7240ec8a4f5b..be7096869b2e7 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -@@ -437,6 +437,20 @@ - }; - }; - -+ vdec: video-decoder@c8820000 { -+ compatible = "amlogic,gx-vdec"; -+ reg = <0x0 0xc8820000 0x0 0x10000>, -+ <0x0 0xc110a580 0x0 0xe4>; -+ reg-names = "dos", "esparser"; -+ -+ interrupts = , -+ ; -+ interrupt-names = "vdec", "esparser"; -+ -+ amlogic,ao-sysctrl = <&sysctrl_AO>; -+ amlogic,canvas = <&canvas>; -+ }; -+ - periphs: periphs@c8834000 { - compatible = "simple-bus"; - reg = <0x0 0xc8834000 0x0 0x2000>; - -From 5de4d34650c1555c88ac01ae36f3e14e3ca00731 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 29 Aug 2018 15:24:22 +0200 -Subject: [PATCH 208/249] WIP: arm64: dts: meson: add vdec entries - -This enables the video decoder for gxbb, gxl and gxm chips - -Signed-off-by: Maxime Jourdan ---- - arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 11 +++++++++++ - arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 11 +++++++++++ - arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 4 ++++ - 3 files changed, 26 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -index a60d3652beee1..e900a93960fb6 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -@@ -830,3 +830,14 @@ - compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; - power-domains = <&pwrc_vpu>; - }; -+ -+&vdec { -+ compatible = "amlogic,gxbb-vdec"; -+ clocks = <&clkc CLKID_DOS_PARSER>, -+ <&clkc CLKID_DOS>, -+ <&clkc CLKID_VDEC_1>, -+ <&clkc CLKID_VDEC_HEVC>; -+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; -+ resets = <&reset RESET_PARSER>; -+ reset-names = "esparser"; -+}; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -index 3093ae421b177..1d105047661ed 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -@@ -833,3 +833,14 @@ - compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu"; - power-domains = <&pwrc_vpu>; - }; -+ -+&vdec { -+ compatible = "amlogic,gxl-vdec"; -+ clocks = <&clkc CLKID_DOS_PARSER>, -+ <&clkc CLKID_DOS>, -+ <&clkc CLKID_VDEC_1>, -+ <&clkc CLKID_VDEC_HEVC>; -+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; -+ resets = <&reset RESET_PARSER>; -+ reset-names = "esparser"; -+}; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi -index ed3a3d5adf316..d74cb4993bae2 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi -@@ -117,3 +117,7 @@ - &dwc3 { - phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>; - }; -+ -+&vdec { -+ compatible = "amlogic,gxm-vdec"; -+}; - -From 8d98a30268b99d94ae7affdb58f0b561cb9ec562 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 29 Aug 2018 15:42:56 +0200 -Subject: [PATCH 209/249] WIP: media: meson: vdec: add H.264 decoding support - -Add support for V4L2_PIX_FMT_H264 ---- - drivers/media/platform/meson/vdec/Makefile | 2 +- - .../media/platform/meson/vdec/codec_h264.c | 478 ++++++++++++++++++ - .../media/platform/meson/vdec/codec_h264.h | 13 + - .../media/platform/meson/vdec/vdec_platform.c | 31 ++ - 4 files changed, 523 insertions(+), 1 deletion(-) - create mode 100644 drivers/media/platform/meson/vdec/codec_h264.c - create mode 100644 drivers/media/platform/meson/vdec/codec_h264.h - -diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile -index eba86083aadb4..01dc9603abdd7 100644 ---- a/drivers/media/platform/meson/vdec/Makefile -+++ b/drivers/media/platform/meson/vdec/Makefile -@@ -3,6 +3,6 @@ - - meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o - meson-vdec-objs += vdec_1.o --meson-vdec-objs += codec_mpeg12.o -+meson-vdec-objs += codec_mpeg12.o codec_h264.o - - obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o -diff --git a/drivers/media/platform/meson/vdec/codec_h264.c b/drivers/media/platform/meson/vdec/codec_h264.c -new file mode 100644 -index 0000000000000..6ac0115afaa35 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_h264.c -@@ -0,0 +1,478 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#include -+#include -+ -+#include "vdec_helpers.h" -+#include "dos_regs.h" -+ -+#define SIZE_EXT_FW (20 * SZ_1K) -+#define SIZE_WORKSPACE 0x1ee000 -+#define SIZE_SEI (8 * SZ_1K) -+ -+/* Offset added by the firmware which must be substracted -+ * from the workspace phyaddr -+ */ -+#define WORKSPACE_BUF_OFFSET 0x1000000 -+ -+/* ISR status */ -+#define CMD_MASK GENMASK(7, 0) -+#define CMD_SRC_CHANGE 1 -+#define CMD_FRAMES_READY 2 -+#define CMD_FATAL_ERROR 6 -+#define CMD_BAD_WIDTH 7 -+#define CMD_BAD_HEIGHT 8 -+ -+#define SEI_DATA_READY BIT(15) -+ -+/* Picture type */ -+#define PIC_TOP_BOT 5 -+#define PIC_BOT_TOP 6 -+ -+/* Size of Motion Vector per macroblock */ -+#define MB_MV_SIZE 96 -+ -+/* Frame status data */ -+#define PIC_STRUCT_BIT 5 -+#define PIC_STRUCT_MASK GENMASK(2, 0) -+#define BUF_IDX_MASK GENMASK(4, 0) -+#define ERROR_FLAG BIT(9) -+#define OFFSET_BIT 16 -+#define OFFSET_MASK GENMASK(15, 0) -+ -+/* Bitstream parsed data */ -+#define MB_TOTAL_BIT 8 -+#define MB_TOTAL_MASK GENMASK(15, 0) -+#define MB_WIDTH_MASK GENMASK(7, 0) -+#define MAX_REF_BIT 24 -+#define MAX_REF_MASK GENMASK(6, 0) -+#define AR_IDC_BIT 16 -+#define AR_IDC_MASK GENMASK(7, 0) -+#define AR_PRESENT_FLAG BIT(0) -+#define AR_EXTEND 0xff -+ -+/* Buffer to send to the ESPARSER to signal End Of Stream for H.264. -+ * This is a 16x16 encoded picture that will trigger drain firmware-side. -+ * There is no known alternative. -+ */ -+static const u8 eos_sequence[SZ_1K] = { -+ 0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd, -+ 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, -+ 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, -+ 0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37, -+ 0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, -+ 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, -+ 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, -+ 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, -+ 0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, -+ 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, -+ 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, -+ 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, -+ 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65, -+ 0x66, 0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d, -+ 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, -+ 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, -+ 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, -+ 0x3d, 0x36, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, -+ 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, -+ 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, -+ 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, -+ 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, -+ 0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, -+ 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, -+ 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68, -+ 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, -+ 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, -+ 0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, -+ 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66, -+ 0x66, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, -+ 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, -+ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, -+ 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, -+ 0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69, -+ 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x20, 0x72, 0x61, 0x74, -+ 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f, -+ 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, -+ 0x6e, 0x3d, 0x31, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35, -+ 0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69, -+ 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30, -+ 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80, -+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20, -+ 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x51, 0xe2, 0x44, 0xd4, -+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01, -+ 0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6, -+ 0x57, 0xae, 0x49, 0x30, 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4, -+ 0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb, 0xd6, 0xbe, 0x5c, 0xd7, -+ 0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09, -+ 0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66, -+ 0xba, 0x9b, 0x82, 0x29, 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b -+}; -+ -+static const u8 *codec_h264_eos_sequence(u32 *len) -+{ -+ *len = ARRAY_SIZE(eos_sequence); -+ return eos_sequence; -+} -+ -+struct codec_h264 { -+ /* H.264 decoder requires an extended firmware */ -+ void *ext_fw_vaddr; -+ dma_addr_t ext_fw_paddr; -+ -+ /* Buffer for the H.264 Workspace */ -+ void *workspace_vaddr; -+ dma_addr_t workspace_paddr; -+ -+ /* Buffer for the H.264 references MV */ -+ void *ref_vaddr; -+ dma_addr_t ref_paddr; -+ u32 ref_size; -+ -+ /* Buffer for parsed SEI data */ -+ void *sei_vaddr; -+ dma_addr_t sei_paddr; -+ -+ u32 mb_width; -+ u32 mb_height; -+ u32 max_refs; -+}; -+ -+static int codec_h264_can_recycle(struct amvdec_core *core) -+{ -+ return !amvdec_read_dos(core, AV_SCRATCH_7) || -+ !amvdec_read_dos(core, AV_SCRATCH_8); -+} -+ -+static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx) -+{ -+ /* Tell the decoder he can recycle this buffer. -+ * AV_SCRATCH_8 serves the same purpose. -+ */ -+ if (!amvdec_read_dos(core, AV_SCRATCH_7)) -+ amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1); -+ else -+ amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1); -+} -+ -+static int codec_h264_start(struct amvdec_session *sess) { -+ u32 workspace_offset; -+ struct amvdec_core *core = sess->core; -+ struct codec_h264 *h264 = sess->priv; -+ -+ /* Allocate some memory for the H.264 decoder's state */ -+ h264->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, -+ &h264->workspace_paddr, GFP_KERNEL); -+ if (!h264->workspace_vaddr) { -+ dev_err(core->dev, "Failed to alloc H.264 Workspace\n"); -+ return -ENOMEM; -+ } -+ -+ /* Allocate some memory for the H.264 SEI dump */ -+ h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI, -+ &h264->sei_paddr, GFP_KERNEL); -+ if (!h264->sei_vaddr) { -+ dev_err(core->dev, "Failed to alloc H.264 SEI\n"); -+ return -ENOMEM; -+ } -+ -+ amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6)); -+ -+ workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET; -+ amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset); -+ amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr); -+ amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr - workspace_offset); -+ -+ /* Enable "error correction" */ -+ amvdec_write_dos(core, AV_SCRATCH_F, -+ (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) | -+ BIT(4) | BIT(7)); -+ -+ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa); -+ -+ return 0; -+} -+ -+static int codec_h264_stop(struct amvdec_session *sess) -+{ -+ struct codec_h264 *h264 = sess->priv; -+ struct amvdec_core *core = sess->core; -+ -+ if (h264->ext_fw_vaddr) -+ dma_free_coherent(core->dev, SIZE_EXT_FW, -+ h264->ext_fw_vaddr, h264->ext_fw_paddr); -+ -+ if (h264->workspace_vaddr) -+ dma_free_coherent(core->dev, SIZE_WORKSPACE, -+ h264->workspace_vaddr, h264->workspace_paddr); -+ -+ if (h264->ref_vaddr) -+ dma_free_coherent(core->dev, h264->ref_size, -+ h264->ref_vaddr, h264->ref_paddr); -+ -+ if (h264->sei_vaddr) -+ dma_free_coherent(core->dev, SIZE_SEI, -+ h264->sei_vaddr, h264->sei_paddr); -+ -+ return 0; -+} -+ -+static int codec_h264_load_extended_firmware(struct amvdec_session *sess, -+ const u8 *data, u32 len) -+{ -+ struct codec_h264 *h264; -+ struct amvdec_core *core = sess->core; -+ -+ if (len < SIZE_EXT_FW) -+ return -EINVAL; -+ -+ h264 = kzalloc(sizeof(*h264), GFP_KERNEL); -+ if (!h264) -+ return -ENOMEM; -+ -+ h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW, -+ &h264->ext_fw_paddr, GFP_KERNEL); -+ if (!h264->ext_fw_vaddr) { -+ dev_err(core->dev, "Failed to alloc H.264 extended fw\n"); -+ kfree(h264); -+ return -ENOMEM; -+ } -+ -+ memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW); -+ sess->priv = h264; -+ -+ return 0; -+} -+ -+static const struct v4l2_fract par_table[] = { -+ { 1, 1 }, { 1, 1 }, { 12, 11 }, { 10, 11 }, -+ { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 }, -+ { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 }, -+ { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 }, -+ { 2, 1 } -+}; -+ -+static void codec_h264_set_par(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2); -+ u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK; -+ -+ if (!(seq_info & AR_PRESENT_FLAG)) -+ return; -+ -+ if (ar_idc == AR_EXTEND) { -+ u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3); -+ sess->pixelaspect.numerator = ar_info & 0xffff; -+ sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff; -+ return; -+ } -+ -+ if (ar_idc >= ARRAY_SIZE(par_table)) -+ return; -+ -+ sess->pixelaspect = par_table[ar_idc]; -+} -+ -+static void codec_h264_resume(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_h264 *h264 = sess->priv; -+ u32 mb_width, mb_height, mb_total; -+ -+ amvdec_set_canvases(sess, (u32[]){ ANC0_CANVAS_ADDR, 0 }, -+ (u32[]){ 24, 0 }); -+ -+ dev_dbg(core->dev, -+ "max_refs = %u; actual_dpb_size = %u\n", -+ h264->max_refs, sess->num_dst_bufs); -+ -+ /* Align to a multiple of 4 macroblocks */ -+ mb_width = ALIGN(h264->mb_width, 4); -+ mb_height = ALIGN(h264->mb_height, 4); -+ mb_total = mb_width * mb_height; -+ -+ h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs; -+ h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size, -+ &h264->ref_paddr, GFP_KERNEL); -+ if (!h264->ref_vaddr) { -+ dev_err(core->dev, "Failed to alloc refs (%u)\n", -+ h264->ref_size); -+ amvdec_abort(sess); -+ return; -+ } -+ -+ /* Address to store the references' MVs */ -+ amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr); -+ /* End of ref MV */ -+ amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size); -+ -+ amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) | -+ (sess->num_dst_bufs << 16) | -+ ((h264->max_refs - 1) << 8)); -+} -+ -+/* Configure the H.264 decoder when the parser detected a parameter set change -+ */ -+static void codec_h264_src_change(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_h264 *h264 = sess->priv; -+ u32 parsed_info, mb_total; -+ u32 crop_infor, crop_bottom, crop_right; -+ u32 frame_width, frame_height; -+ -+ sess->keyframe_found = 1; -+ -+ parsed_info = amvdec_read_dos(core, AV_SCRATCH_1); -+ -+ /* Total number of 16x16 macroblocks */ -+ mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK; -+ /* Number of macroblocks per line */ -+ h264->mb_width = parsed_info & MB_WIDTH_MASK; -+ /* Number of macroblock lines */ -+ h264->mb_height = mb_total / h264->mb_width; -+ -+ h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1; -+ -+ crop_infor = amvdec_read_dos(core, AV_SCRATCH_6); -+ crop_bottom = (crop_infor & 0xff); -+ crop_right = (crop_infor >> 16) & 0xff; -+ -+ frame_width = h264->mb_width * 16 - crop_right; -+ frame_height = h264->mb_height * 16 - crop_bottom; -+ -+ dev_info(core->dev, "frame: %ux%u; crop: %u %u\n", -+ frame_width, frame_height, crop_right, crop_bottom); -+ -+ codec_h264_set_par(sess); -+ amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5); -+} -+ -+/** -+ * The offset is split in half in 2 different registers -+ */ -+static u32 get_offset_msb(struct amvdec_core *core, int frame_num) -+{ -+ int take_msb = frame_num % 2; -+ int reg_offset = (frame_num / 2) * 4; -+ u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset); -+ -+ if (take_msb) -+ return offset_msb & 0xffff0000; -+ -+ return (offset_msb & 0x0000ffff) << 16; -+} -+ -+static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status) -+{ -+ struct amvdec_core *core = sess->core; -+ int error_count; -+ int num_frames; -+ int i; -+ -+ error_count = amvdec_read_dos(core, AV_SCRATCH_D); -+ num_frames = (status >> 8) & 0xff; -+ if (error_count) { -+ dev_warn(core->dev, -+ "decoder error(s) happened, count %d\n", error_count); -+ amvdec_write_dos(core, AV_SCRATCH_D, 0); -+ } -+ -+ for (i = 0; i < num_frames; i++) { -+ u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4); -+ u32 buffer_index = frame_status & BUF_IDX_MASK; -+ u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) & -+ PIC_STRUCT_MASK; -+ u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK; -+ u32 field = V4L2_FIELD_NONE; -+ -+ /* A buffer decode error means it was decoded, -+ * but part of the picture will have artifacts. -+ * Typical reason is a temporarily corrupted bitstream -+ */ -+ if (frame_status & ERROR_FLAG) -+ dev_dbg(core->dev, "Buffer %d decode error\n", -+ buffer_index); -+ -+ if (pic_struct == PIC_TOP_BOT) -+ field = V4L2_FIELD_INTERLACED_TB; -+ else if (pic_struct == PIC_BOT_TOP) -+ field = V4L2_FIELD_INTERLACED_BT; -+ -+ offset |= get_offset_msb(core, i); -+ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field); -+ } -+} -+ -+static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 status; -+ u32 size; -+ u8 cmd; -+ -+ status = amvdec_read_dos(core, AV_SCRATCH_0); -+ cmd = status & CMD_MASK; -+ -+ switch (cmd) { -+ case CMD_SRC_CHANGE: -+ codec_h264_src_change(sess); -+ break; -+ case CMD_FRAMES_READY: -+ codec_h264_frames_ready(sess, status); -+ break; -+ case CMD_FATAL_ERROR: -+ dev_err(core->dev, "H.264 decoder fatal error\n"); -+ goto abort; -+ case CMD_BAD_WIDTH: -+ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; -+ dev_err(core->dev, "Unsupported video width: %u\n", size); -+ goto abort; -+ case CMD_BAD_HEIGHT: -+ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; -+ dev_err(core->dev, "Unsupported video height: %u\n", size); -+ goto abort; -+ case 0: /* Unused but not worth printing for */ -+ case 9: -+ break; -+ default: -+ dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd); -+ break; -+ } -+ -+ if (cmd && cmd != CMD_SRC_CHANGE) -+ amvdec_write_dos(core, AV_SCRATCH_0, 0); -+ -+ /* Decoder has some SEI data for us ; ignore */ -+ if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY) -+ amvdec_write_dos(core, AV_SCRATCH_J, 0); -+ -+ return IRQ_HANDLED; -+abort: -+ amvdec_abort(sess); -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t codec_h264_isr(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); -+ -+ return IRQ_WAKE_THREAD; -+} -+ -+struct amvdec_codec_ops codec_h264_ops = { -+ .start = codec_h264_start, -+ .stop = codec_h264_stop, -+ .load_extended_firmware = codec_h264_load_extended_firmware, -+ .isr = codec_h264_isr, -+ .threaded_isr = codec_h264_threaded_isr, -+ .can_recycle = codec_h264_can_recycle, -+ .recycle = codec_h264_recycle, -+ .eos_sequence = codec_h264_eos_sequence, -+ .resume = codec_h264_resume, -+}; -diff --git a/drivers/media/platform/meson/vdec/codec_h264.h b/drivers/media/platform/meson/vdec/codec_h264.h -new file mode 100644 -index 0000000000000..7a1597611faff ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_h264.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CODEC_H264_H_ -+#define __MESON_VDEC_CODEC_H264_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_codec_ops codec_h264_ops; -+ -+#endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c -index bb8016266ab20..2f25e14bdbad2 100644 ---- a/drivers/media/platform/meson/vdec/vdec_platform.c -+++ b/drivers/media/platform/meson/vdec/vdec_platform.c -@@ -9,9 +9,20 @@ - - #include "vdec_1.h" - #include "codec_mpeg12.h" -+#include "codec_h264.h" - - static const struct amvdec_format vdec_formats_gxbb[] = { - { -+ .pixfmt = V4L2_PIX_FMT_H264, -+ .min_buffers = 2, -+ .max_buffers = 24, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_h264_ops, -+ .firmware_path = "meson/gxbb/vh264_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MPEG1, - .min_buffers = 8, - .max_buffers = 8, -@@ -38,6 +49,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { - - static const struct amvdec_format vdec_formats_gxl[] = { - { -+ .pixfmt = V4L2_PIX_FMT_H264, -+ .min_buffers = 2, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_h264_ops, -+ .firmware_path = "meson/gxl/vh264_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MPEG1, - .min_buffers = 8, - .max_buffers = 8, -@@ -64,6 +85,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { - - static const struct amvdec_format vdec_formats_gxm[] = { - { -+ .pixfmt = V4L2_PIX_FMT_H264, -+ .min_buffers = 2, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_h264_ops, -+ .firmware_path = "meson/gxm/vh264_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MPEG1, - .min_buffers = 8, - .max_buffers = 8, - -From 0451e4b83f7a114f508c257c65d53cbd6664226e Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 29 Aug 2018 16:01:55 +0200 -Subject: [PATCH 210/249] WIP: media: meson: vdec: add MPEG4 decoding support - -Add support for V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID and -V4L2_PIX_FMT_H.263 ---- - drivers/media/platform/meson/vdec/Makefile | 2 +- - .../media/platform/meson/vdec/codec_mpeg4.c | 139 ++++++++++++++++++ - .../media/platform/meson/vdec/codec_mpeg4.h | 13 ++ - .../media/platform/meson/vdec/vdec_platform.c | 91 ++++++++++++ - 4 files changed, 244 insertions(+), 1 deletion(-) - create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.c - create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.h - -diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile -index 01dc9603abdd7..bb7a134e27280 100644 ---- a/drivers/media/platform/meson/vdec/Makefile -+++ b/drivers/media/platform/meson/vdec/Makefile -@@ -3,6 +3,6 @@ - - meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o - meson-vdec-objs += vdec_1.o --meson-vdec-objs += codec_mpeg12.o codec_h264.o -+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o - - obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o -diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.c b/drivers/media/platform/meson/vdec/codec_mpeg4.c -new file mode 100644 -index 0000000000000..1d574e5761125 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_mpeg4.c -@@ -0,0 +1,139 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#include -+#include -+ -+#include "vdec_helpers.h" -+#include "dos_regs.h" -+ -+#define SIZE_WORKSPACE SZ_1M -+/* Offset added by firmware, to substract from workspace paddr */ -+#define DCAC_BUFF_START_IP 0x02b00000 -+ -+/* map firmware registers to known MPEG4 functions */ -+#define MREG_BUFFERIN AV_SCRATCH_8 -+#define MREG_BUFFEROUT AV_SCRATCH_9 -+#define MP4_NOT_CODED_CNT AV_SCRATCH_A -+#define MP4_OFFSET_REG AV_SCRATCH_C -+#define MEM_OFFSET_REG AV_SCRATCH_F -+#define MREG_FATAL_ERROR AV_SCRATCH_L -+ -+#define BUF_IDX_MASK GENMASK(2, 0) -+#define INTERLACE_FLAG BIT(7) -+#define TOP_FIELD_FIRST_FLAG BIT(6) -+ -+struct codec_mpeg4 { -+ /* Buffer for the MPEG4 Workspace */ -+ void *workspace_vaddr; -+ dma_addr_t workspace_paddr; -+}; -+ -+static int codec_mpeg4_can_recycle(struct amvdec_core *core) -+{ -+ return !amvdec_read_dos(core, MREG_BUFFERIN); -+} -+ -+static void codec_mpeg4_recycle(struct amvdec_core *core, u32 buf_idx) -+{ -+ amvdec_write_dos(core, MREG_BUFFERIN, ~BIT(buf_idx)); -+} -+ -+static int codec_mpeg4_start(struct amvdec_session *sess) { -+ struct amvdec_core *core = sess->core; -+ struct codec_mpeg4 *mpeg4 = sess->priv; -+ int ret; -+ -+ mpeg4 = kzalloc(sizeof(*mpeg4), GFP_KERNEL); -+ if (!mpeg4) -+ return -ENOMEM; -+ -+ /* Allocate some memory for the MPEG4 decoder's state */ -+ mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, -+ &mpeg4->workspace_paddr, -+ GFP_KERNEL); -+ if (!mpeg4->workspace_vaddr) { -+ dev_err(core->dev, "Failed to request MPEG4 Workspace\n"); -+ ret = -ENOMEM; -+ goto free_mpeg4; -+ } -+ -+ /* Canvas regs: AV_SCRATCH_0-AV_SCRATCH_4;AV_SCRATCH_G-AV_SCRATCH_J */ -+ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, AV_SCRATCH_G, 0 }, -+ (u32[]){ 4, 4, 0 }); -+ -+ amvdec_write_dos(core, MEM_OFFSET_REG, -+ mpeg4->workspace_paddr - DCAC_BUFF_START_IP); -+ amvdec_write_dos(core, PSCALE_CTRL, 0); -+ amvdec_write_dos(core, MP4_NOT_CODED_CNT, 0); -+ amvdec_write_dos(core, MREG_BUFFERIN, 0); -+ amvdec_write_dos(core, MREG_BUFFEROUT, 0); -+ amvdec_write_dos(core, MREG_FATAL_ERROR, 0); -+ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa); -+ -+ sess->keyframe_found = 1; -+ sess->priv = mpeg4; -+ -+ return 0; -+ -+free_mpeg4: -+ kfree(mpeg4); -+ return ret; -+} -+ -+static int codec_mpeg4_stop(struct amvdec_session *sess) -+{ -+ struct codec_mpeg4 *mpeg4 = sess->priv; -+ struct amvdec_core *core = sess->core; -+ -+ if (mpeg4->workspace_vaddr) { -+ dma_free_coherent(core->dev, SIZE_WORKSPACE, -+ mpeg4->workspace_vaddr, -+ mpeg4->workspace_paddr); -+ mpeg4->workspace_vaddr = 0; -+ } -+ -+ return 0; -+} -+ -+static irqreturn_t codec_mpeg4_isr(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 reg; -+ u32 buffer_index; -+ u32 field = V4L2_FIELD_NONE; -+ -+ reg = amvdec_read_dos(core, MREG_FATAL_ERROR); -+ if (reg == 1) { -+ dev_err(core->dev, "mpeg4 fatal error\n"); -+ amvdec_abort(sess); -+ return IRQ_HANDLED; -+ } -+ -+ reg = amvdec_read_dos(core, MREG_BUFFEROUT); -+ if (!reg) -+ goto end; -+ -+ buffer_index = reg & BUF_IDX_MASK; -+ if (reg & INTERLACE_FLAG) -+ field = (reg & TOP_FIELD_FIRST_FLAG) ? -+ V4L2_FIELD_INTERLACED_TB : -+ V4L2_FIELD_INTERLACED_BT; -+ -+ amvdec_dst_buf_done_idx(sess, buffer_index, -1, field); -+ amvdec_write_dos(core, MREG_BUFFEROUT, 0); -+ -+end: -+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); -+ return IRQ_HANDLED; -+} -+ -+struct amvdec_codec_ops codec_mpeg4_ops = { -+ .start = codec_mpeg4_start, -+ .stop = codec_mpeg4_stop, -+ .isr = codec_mpeg4_isr, -+ .can_recycle = codec_mpeg4_can_recycle, -+ .recycle = codec_mpeg4_recycle, -+}; -diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.h b/drivers/media/platform/meson/vdec/codec_mpeg4.h -new file mode 100644 -index 0000000000000..b91b264131854 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_mpeg4.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CODEC_MPEG4_H_ -+#define __MESON_VDEC_CODEC_MPEG4_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_codec_ops codec_mpeg4_ops; -+ -+#endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c -index 2f25e14bdbad2..e1ab1914ddad9 100644 ---- a/drivers/media/platform/meson/vdec/vdec_platform.c -+++ b/drivers/media/platform/meson/vdec/vdec_platform.c -@@ -10,9 +10,40 @@ - #include "vdec_1.h" - #include "codec_mpeg12.h" - #include "codec_h264.h" -+#include "codec_mpeg4.h" - - static const struct amvdec_format vdec_formats_gxbb[] = { - { -+ .pixfmt = V4L2_PIX_FMT_MPEG4, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/vmpeg4_mc_5", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_H263, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/h263_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_XVID, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/vmpeg4_mc_5", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_H264, - .min_buffers = 2, - .max_buffers = 24, -@@ -49,6 +80,36 @@ static const struct amvdec_format vdec_formats_gxbb[] = { - - static const struct amvdec_format vdec_formats_gxl[] = { - { -+ .pixfmt = V4L2_PIX_FMT_MPEG4, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/vmpeg4_mc_5", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_H263, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/h263_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_XVID, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/vmpeg4_mc_5", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_H264, - .min_buffers = 2, - .max_buffers = 24, -@@ -85,6 +146,36 @@ static const struct amvdec_format vdec_formats_gxl[] = { - - static const struct amvdec_format vdec_formats_gxm[] = { - { -+ .pixfmt = V4L2_PIX_FMT_MPEG4, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/vmpeg4_mc_5", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_H263, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/h263_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_XVID, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/gx/vmpeg4_mc_5", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_H264, - .min_buffers = 2, - .max_buffers = 24, - -From 48544ff3f04e1102e51288a62f90f893becf308c Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Sun, 21 Oct 2018 15:14:27 +0200 -Subject: [PATCH 211/249] WIP: media: meson: vdec: add MJPEG decoding support - -Add support for V4L2_PIX_FMT_MJPEG ---- - drivers/media/platform/meson/vdec/Makefile | 2 +- - .../media/platform/meson/vdec/codec_mjpeg.c | 140 ++++++++++++++++++ - .../media/platform/meson/vdec/codec_mjpeg.h | 13 ++ - .../media/platform/meson/vdec/vdec_platform.c | 31 ++++ - 4 files changed, 185 insertions(+), 1 deletion(-) - create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.c - create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.h - -diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile -index bb7a134e27280..acf07f3c3dac6 100644 ---- a/drivers/media/platform/meson/vdec/Makefile -+++ b/drivers/media/platform/meson/vdec/Makefile -@@ -3,6 +3,6 @@ - - meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o - meson-vdec-objs += vdec_1.o --meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o -+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o - - obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o -diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.c b/drivers/media/platform/meson/vdec/codec_mjpeg.c -new file mode 100644 -index 0000000000000..abea9e3f944c2 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.c -@@ -0,0 +1,140 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#include -+#include -+ -+#include "vdec_helpers.h" -+#include "dos_regs.h" -+ -+/* map FW registers to known MJPEG functions */ -+#define MREG_DECODE_PARAM AV_SCRATCH_2 -+#define MREG_TO_AMRISC AV_SCRATCH_8 -+#define MREG_FROM_AMRISC AV_SCRATCH_9 -+#define MREG_FRAME_OFFSET AV_SCRATCH_A -+ -+static int codec_mjpeg_can_recycle(struct amvdec_core *core) -+{ -+ return !amvdec_read_dos(core, MREG_TO_AMRISC); -+} -+ -+static void codec_mjpeg_recycle(struct amvdec_core *core, u32 buf_idx) -+{ -+ amvdec_write_dos(core, MREG_TO_AMRISC, buf_idx + 1); -+} -+ -+/* 4 point triangle */ -+static const uint32_t filt_coef[] = { -+ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101, -+ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303, -+ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505, -+ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707, -+ 0x18382808, 0x18382808, 0x17372909, 0x17372909, -+ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b, -+ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d, -+ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f, -+ 0x10303010 -+}; -+ -+static void codec_mjpeg_init_scaler(struct amvdec_core *core) -+{ -+ int i; -+ -+ /* PSCALE cbus bmem enable */ -+ amvdec_write_dos(core, PSCALE_CTRL, 0xc000); -+ -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 0); -+ for (i = 0; i < ARRAY_SIZE(filt_coef); ++i) { -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, filt_coef[i]); -+ } -+ -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 74); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); -+ -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 82); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); -+ -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 78); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); -+ -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 86); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); -+ -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 73); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 81); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); -+ -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 77); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); -+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 85); -+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); -+ -+ amvdec_write_dos(core, PSCALE_RST, 0x7); -+ amvdec_write_dos(core, PSCALE_RST, 0); -+} -+ -+static int codec_mjpeg_start(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ amvdec_write_dos(core, AV_SCRATCH_0, 12); -+ amvdec_write_dos(core, AV_SCRATCH_1, 0x031a); -+ -+ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_4, 0 }, -+ (u32[]){ 4, 0 }); -+ codec_mjpeg_init_scaler(core); -+ -+ amvdec_write_dos(core, MREG_TO_AMRISC, 0); -+ amvdec_write_dos(core, MREG_FROM_AMRISC, 0); -+ amvdec_write_dos(core, MCPU_INTR_MSK, 0xffff); -+ amvdec_write_dos(core, MREG_DECODE_PARAM, -+ (sess->height << 4) | 0x8000); -+ amvdec_write_dos(core, VDEC_ASSIST_AMR1_INT8, 8); -+ -+ /* Intra-only codec */ -+ sess->keyframe_found = 1; -+ -+ return 0; -+} -+ -+static int codec_mjpeg_stop(struct amvdec_session *sess) -+{ -+ return 0; -+} -+ -+static irqreturn_t codec_mjpeg_isr(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 reg; -+ u32 buffer_index; -+ u32 offset; -+ -+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); -+ -+ reg = amvdec_read_dos(core, MREG_FROM_AMRISC); -+ if (!(reg & 0x7)) -+ return IRQ_HANDLED; -+ -+ buffer_index = ((reg & 0x7) - 1) & 3; -+ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET); -+ amvdec_dst_buf_done_idx(sess, buffer_index, offset, V4L2_FIELD_NONE); -+ -+ amvdec_write_dos(core, MREG_FROM_AMRISC, 0); -+ return IRQ_HANDLED; -+} -+ -+struct amvdec_codec_ops codec_mjpeg_ops = { -+ .start = codec_mjpeg_start, -+ .stop = codec_mjpeg_stop, -+ .isr = codec_mjpeg_isr, -+ .can_recycle = codec_mjpeg_can_recycle, -+ .recycle = codec_mjpeg_recycle, -+}; -diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.h b/drivers/media/platform/meson/vdec/codec_mjpeg.h -new file mode 100644 -index 0000000000000..cc1cf731050d1 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CODEC_MJPEG_H_ -+#define __MESON_VDEC_CODEC_MJPEG_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_codec_ops codec_mjpeg_ops; -+ -+#endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c -index e1ab1914ddad9..9cf978e9050d3 100644 ---- a/drivers/media/platform/meson/vdec/vdec_platform.c -+++ b/drivers/media/platform/meson/vdec/vdec_platform.c -@@ -11,9 +11,20 @@ - #include "codec_mpeg12.h" - #include "codec_h264.h" - #include "codec_mpeg4.h" -+#include "codec_mjpeg.h" - - static const struct amvdec_format vdec_formats_gxbb[] = { - { -+ .pixfmt = V4L2_PIX_FMT_MJPEG, -+ .min_buffers = 4, -+ .max_buffers = 4, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mjpeg_ops, -+ .firmware_path = "meson/gx/vmjpeg_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MPEG4, - .min_buffers = 8, - .max_buffers = 8, -@@ -80,6 +91,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { - - static const struct amvdec_format vdec_formats_gxl[] = { - { -+ .pixfmt = V4L2_PIX_FMT_MJPEG, -+ .min_buffers = 4, -+ .max_buffers = 4, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mjpeg_ops, -+ .firmware_path = "meson/gx/vmjpeg_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MPEG4, - .min_buffers = 8, - .max_buffers = 8, -@@ -146,6 +167,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { - - static const struct amvdec_format vdec_formats_gxm[] = { - { -+ .pixfmt = V4L2_PIX_FMT_MJPEG, -+ .min_buffers = 4, -+ .max_buffers = 4, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mjpeg_ops, -+ .firmware_path = "meson/gx/vmjpeg_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MPEG4, - .min_buffers = 8, - .max_buffers = 8, - -From 8737e27bae7e539ab69d24f8523a980c3dfc6941 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Sun, 21 Oct 2018 15:14:49 +0200 -Subject: [PATCH 212/249] WIP: media: videodev2.h: Add Amlogic compressed - format - -Add V4L2_PIX_FMT_AM21C which is a lossless, compressed framebuffer -format. - -It is used by the video decoding and the display IP on many Amlogic -SoCs. ---- - drivers/media/v4l2-core/v4l2-ioctl.c | 1 + - include/uapi/linux/videodev2.h | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c -index f6d663934648a..5148b0539c363 100644 ---- a/drivers/media/v4l2-core/v4l2-ioctl.c -+++ b/drivers/media/v4l2-core/v4l2-ioctl.c -@@ -1357,6 +1357,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) - case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; - case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; - case V4L2_PIX_FMT_SUNXI_TILED_NV12: descr = "Sunxi Tiled NV12 Format"; break; -+ case V4L2_PIX_FMT_AM21C: descr = "Amlogic Compressed Format"; break; - default: - if (fmt->description[0]) - return; -diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h -index 9c8a2d2e7bc62..aab7ec92b9f27 100644 ---- a/include/uapi/linux/videodev2.h -+++ b/include/uapi/linux/videodev2.h -@@ -701,6 +701,7 @@ struct v4l2_pix_format { - #define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */ - #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ - #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ -+#define V4L2_PIX_FMT_AM21C v4l2_fourcc('A', 'M', '2', '1') /* Amlogic compressed block mode */ - #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ - #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ - #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ - -From dbecbb71cf8bb2b0f9eb91fc1bda12394d4a5452 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Sun, 21 Oct 2018 15:15:26 +0200 -Subject: [PATCH 213/249] WIP: media: meson: vdec: add support for - V4L2_PIX_FMT_AM21C - -Support the lossless framebuffer compression format. ---- - drivers/media/platform/meson/vdec/vdec.c | 12 +++++++ - .../media/platform/meson/vdec/vdec_helpers.c | 31 +++++++++++++++++++ - .../media/platform/meson/vdec/vdec_helpers.h | 4 +++ - 3 files changed, 47 insertions(+) - -diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c -index da96a788ee5c6..dd5e6864fbdaa 100644 ---- a/drivers/media/platform/meson/vdec/vdec.c -+++ b/drivers/media/platform/meson/vdec/vdec.c -@@ -186,6 +186,7 @@ static int vdec_queue_setup(struct vb2_queue *q, - { - struct amvdec_session *sess = vb2_get_drv_priv(q); - u32 output_size = amvdec_get_output_size(sess); -+ u32 am21c_size = amvdec_am21c_size(sess->width, sess->height); - - if (*num_planes) { - switch (q->type) { -@@ -208,6 +209,10 @@ static int vdec_queue_setup(struct vb2_queue *q, - sizes[2] < output_size / 4) - return -EINVAL; - break; -+ case V4L2_PIX_FMT_AM21C: -+ if (*num_planes != 1 || sizes[0] < am21c_size) -+ return -EINVAL; -+ break; - default: - return -EINVAL; - } -@@ -237,6 +242,9 @@ static int vdec_queue_setup(struct vb2_queue *q, - sizes[2] = output_size / 4; - *num_planes = 3; - break; -+ case V4L2_PIX_FMT_AM21C: -+ sizes[0] = am21c_size; -+ *num_planes = 1; - default: - return -EINVAL; - } -@@ -508,6 +516,10 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size, - get_output_size(pixmp->width, pixmp->height) / 4; - pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2; - pixmp->num_planes = 3; -+ } else if (pixmp->pixelformat == V4L2_PIX_FMT_AM21C) { -+ pfmt[0].sizeimage = -+ amvdec_am21c_size(pixmp->width, pixmp->height); -+ pfmt[0].bytesperline = 0; - } - } else { - return NULL; -diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c -index 5adf9a378b32c..c57391421c301 100644 ---- a/drivers/media/platform/meson/vdec/vdec_helpers.c -+++ b/drivers/media/platform/meson/vdec/vdec_helpers.c -@@ -50,6 +50,33 @@ void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val) - } - EXPORT_SYMBOL_GPL(amvdec_write_parser); - -+/* 4 KiB per 64x32 block */ -+u32 amvdec_am21c_body_size(u32 width, u32 height) -+{ -+ u32 width_64 = ALIGN(width, 64) / 64; -+ u32 height_32 = ALIGN(height, 32) / 32; -+ -+ return SZ_4K * width_64 * height_32; -+} -+EXPORT_SYMBOL_GPL(amvdec_am21c_body_size); -+ -+/* 32 bytes per 128x64 block */ -+u32 amvdec_am21c_head_size(u32 width, u32 height) -+{ -+ u32 width_128 = ALIGN(width, 128) / 128; -+ u32 height_64 = ALIGN(height, 64) / 64; -+ -+ return 32 * width_128 * height_64; -+} -+EXPORT_SYMBOL_GPL(amvdec_am21c_head_size); -+ -+u32 amvdec_am21c_size(u32 width, u32 height) -+{ -+ return ALIGN(amvdec_am21c_body_size(width, height) + -+ amvdec_am21c_head_size(width, height), SZ_64K); -+} -+EXPORT_SYMBOL_GPL(amvdec_am21c_size); -+ - static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id) - { - int ret; -@@ -264,6 +291,10 @@ static void dst_buf_done(struct amvdec_session *sess, - vbuf->vb2_buf.planes[1].bytesused = output_size / 4; - vbuf->vb2_buf.planes[2].bytesused = output_size / 4; - break; -+ case V4L2_PIX_FMT_AM21C: -+ vbuf->vb2_buf.planes[0].bytesused = -+ amvdec_am21c_size(sess->width, sess->height); -+ break; - } - - vbuf->vb2_buf.timestamp = timestamp; -diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h -index 87b39e048a0fc..f1dee9e3447bd 100644 ---- a/drivers/media/platform/meson/vdec/vdec_helpers.h -+++ b/drivers/media/platform/meson/vdec/vdec_helpers.h -@@ -27,6 +27,10 @@ void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val); - u32 amvdec_read_parser(struct amvdec_core *core, u32 reg); - void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val); - -+u32 amvdec_am21c_body_size(u32 width, u32 height); -+u32 amvdec_am21c_head_size(u32 width, u32 height); -+u32 amvdec_am21c_size(u32 width, u32 height); -+ - /** - * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding - * - -From 89cd932da66a841641045631cc34c2d2744c32d0 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Tue, 13 Nov 2018 10:13:02 +0100 -Subject: [PATCH 214/249] WIP: meson: vdec: make amvdec_dst_buf_done_offset - public - -Needed for future commit ---- - drivers/media/platform/meson/vdec/vdec_helpers.c | 13 ++++++++----- - drivers/media/platform/meson/vdec/vdec_helpers.h | 3 +++ - 2 files changed, 11 insertions(+), 5 deletions(-) - -diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c -index c57391421c301..7bb7a6dad5874 100644 ---- a/drivers/media/platform/meson/vdec/vdec_helpers.c -+++ b/drivers/media/platform/meson/vdec/vdec_helpers.c -@@ -349,10 +349,9 @@ void amvdec_dst_buf_done(struct amvdec_session *sess, - } - EXPORT_SYMBOL_GPL(amvdec_dst_buf_done); - --static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, -- struct vb2_v4l2_buffer *vbuf, -- u32 offset, -- u32 field) -+void amvdec_dst_buf_done_offset(struct amvdec_session *sess, -+ struct vb2_v4l2_buffer *vbuf, -+ u32 offset, u32 field, bool allow_drop) - { - struct device *dev = sess->core->dev_dec; - struct amvdec_timestamp *match = NULL; -@@ -375,6 +374,9 @@ static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, - break; - } - -+ if (!allow_drop) -+ continue; -+ - /* Delete any timestamp entry that appears before our target - * (not all src packets/timestamps lead to a frame) - */ -@@ -399,6 +401,7 @@ static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, - if (match) - atomic_dec(&sess->esparser_queued_bufs); - } -+EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_offset); - - void amvdec_dst_buf_done_idx(struct amvdec_session *sess, - u32 buf_idx, u32 offset, u32 field) -@@ -415,7 +418,7 @@ void amvdec_dst_buf_done_idx(struct amvdec_session *sess, - } - - if (offset != -1) -- amvdec_dst_buf_done_offset(sess, vbuf, offset, field); -+ amvdec_dst_buf_done_offset(sess, vbuf, offset, field, true); - else - amvdec_dst_buf_done(sess, vbuf, field); - } -diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h -index f1dee9e3447bd..94d2c1ecfe149 100644 ---- a/drivers/media/platform/meson/vdec/vdec_helpers.h -+++ b/drivers/media/platform/meson/vdec/vdec_helpers.h -@@ -43,6 +43,9 @@ void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx, - u32 offset, u32 field); - void amvdec_dst_buf_done(struct amvdec_session *sess, - struct vb2_v4l2_buffer *vbuf, u32 field); -+void amvdec_dst_buf_done_offset(struct amvdec_session *sess, -+ struct vb2_v4l2_buffer *vbuf, -+ u32 offset, u32 field, bool allow_drop); - - /** - * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order - -From 4496f9d0499ced7f88510d6d9b39a73e4d46b087 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Wed, 29 Aug 2018 18:48:35 +0200 -Subject: [PATCH 215/249] WIP: media: meson: vdec: add HEVC decoding support - -Add support for V4L2_PIX_FMT_HEVC ---- - drivers/media/platform/meson/vdec/Makefile | 4 +- - .../media/platform/meson/vdec/codec_hevc.c | 1564 +++++++++++++++++ - .../media/platform/meson/vdec/codec_hevc.h | 13 + - drivers/media/platform/meson/vdec/hevc_regs.h | 205 +++ - drivers/media/platform/meson/vdec/vdec_hevc.c | 191 ++ - drivers/media/platform/meson/vdec/vdec_hevc.h | 22 + - .../media/platform/meson/vdec/vdec_platform.c | 32 + - 7 files changed, 2029 insertions(+), 2 deletions(-) - create mode 100644 drivers/media/platform/meson/vdec/codec_hevc.c - create mode 100644 drivers/media/platform/meson/vdec/codec_hevc.h - create mode 100644 drivers/media/platform/meson/vdec/hevc_regs.h - create mode 100644 drivers/media/platform/meson/vdec/vdec_hevc.c - create mode 100644 drivers/media/platform/meson/vdec/vdec_hevc.h - -diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile -index acf07f3c3dac6..ddcf38a7c3e65 100644 ---- a/drivers/media/platform/meson/vdec/Makefile -+++ b/drivers/media/platform/meson/vdec/Makefile -@@ -2,7 +2,7 @@ - # Makefile for Amlogic meson video decoder driver - - meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o --meson-vdec-objs += vdec_1.o --meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o -+meson-vdec-objs += vdec_1.o vdec_hevc.o -+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc.o - - obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o -diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c -new file mode 100644 -index 0000000000000..116e9ffc4560d ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_hevc.c -@@ -0,0 +1,1564 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. -+ */ -+ -+#include -+#include -+ -+#include "codec_hevc.h" -+#include "dos_regs.h" -+#include "hevc_regs.h" -+#include "vdec_helpers.h" -+ -+/* HEVC reg mapping */ -+#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 -+ #define HEVC_ACTION_DONE 0xff -+#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 -+#define HEVC_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2 -+#define HEVC_VPS_BUFFER HEVC_ASSIST_SCRATCH_3 -+#define HEVC_SPS_BUFFER HEVC_ASSIST_SCRATCH_4 -+#define HEVC_PPS_BUFFER HEVC_ASSIST_SCRATCH_5 -+#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6 -+#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 -+#define H265_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7 -+#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 -+#define HEVC_sao_mem_unit HEVC_ASSIST_SCRATCH_9 -+#define HEVC_SAO_ABV HEVC_ASSIST_SCRATCH_A -+#define HEVC_sao_vb_size HEVC_ASSIST_SCRATCH_B -+#define HEVC_SAO_VB HEVC_ASSIST_SCRATCH_C -+#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D -+#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E -+#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F -+#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F -+#define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G -+#define HEVC_DECODE_MODE2 HEVC_ASSIST_SCRATCH_H -+#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I -+#define HEVC_DECODE_MODE HEVC_ASSIST_SCRATCH_J -+ #define DECODE_MODE_SINGLE 0 -+#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K -+#define HEVC_AUX_ADR HEVC_ASSIST_SCRATCH_L -+#define HEVC_AUX_DATA_SIZE HEVC_ASSIST_SCRATCH_M -+#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N -+ -+#define AMRISC_MAIN_REQ 0x04 -+ -+/* HEVC Constants */ -+#define MAX_REF_PIC_NUM 24 -+#define MAX_REF_ACTIVE 16 -+#define MAX_TILE_COL_NUM 10 -+#define MAX_TILE_ROW_NUM 20 -+#define MAX_SLICE_NUM 800 -+#define INVALID_POC 0x80000000 -+ -+/* HEVC Workspace layout */ -+#define MPRED_MV_BUF_SIZE 0x120000 -+ -+#define IPP_SIZE 0x4000 -+#define SAO_ABV_SIZE 0x30000 -+#define SAO_VB_SIZE 0x30000 -+#define SH_TM_RPS_SIZE 0x800 -+#define VPS_SIZE 0x800 -+#define SPS_SIZE 0x800 -+#define PPS_SIZE 0x2000 -+#define SAO_UP_SIZE 0x2800 -+#define SWAP_BUF_SIZE 0x800 -+#define SWAP_BUF2_SIZE 0x800 -+#define SCALELUT_SIZE 0x8000 -+#define DBLK_PARA_SIZE 0x20000 -+#define DBLK_DATA_SIZE 0x40000 -+#define MMU_VBH_SIZE 0x5000 -+#define MPRED_ABV_SIZE 0x8000 -+#define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) -+#define RPM_BUF_SIZE 0x100 -+#define LMEM_SIZE 0xA00 -+ -+#define IPP_OFFSET 0x00 -+#define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) -+#define SAO_VB_OFFSET (SAO_ABV_OFFSET + SAO_ABV_SIZE) -+#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + SAO_VB_SIZE) -+#define VPS_OFFSET (SH_TM_RPS_OFFSET + SH_TM_RPS_SIZE) -+#define SPS_OFFSET (VPS_OFFSET + VPS_SIZE) -+#define PPS_OFFSET (SPS_OFFSET + SPS_SIZE) -+#define SAO_UP_OFFSET (PPS_OFFSET + PPS_SIZE) -+#define SWAP_BUF_OFFSET (SAO_UP_OFFSET + SAO_UP_SIZE) -+#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + SWAP_BUF_SIZE) -+#define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) -+#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) -+#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) -+#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) -+#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) -+#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) -+#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) -+#define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) -+ -+/* ISR decode status */ -+#define HEVC_DEC_IDLE 0x0 -+#define HEVC_NAL_UNIT_VPS 0x1 -+#define HEVC_NAL_UNIT_SPS 0x2 -+#define HEVC_NAL_UNIT_PPS 0x3 -+#define HEVC_NAL_UNIT_CODED_SLICE_SEGMENT 0x4 -+#define HEVC_CODED_SLICE_SEGMENT_DAT 0x5 -+#define HEVC_SLICE_DECODING 0x6 -+#define HEVC_NAL_UNIT_SEI 0x7 -+#define HEVC_SLICE_SEGMENT_DONE 0x8 -+#define HEVC_NAL_SEARCH_DONE 0x9 -+#define HEVC_DECPIC_DATA_DONE 0xa -+#define HEVC_DECPIC_DATA_ERROR 0xb -+#define HEVC_SEI_DAT 0xc -+#define HEVC_SEI_DAT_DONE 0xd -+ -+/* RPM misc_flag0 */ -+#define PCM_LOOP_FILTER_DISABLED_FLAG_BIT 0 -+#define PCM_ENABLE_FLAG_BIT 1 -+#define LOOP_FILER_ACROSS_TILES_ENABLED_FLAG_BIT 2 -+#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 3 -+#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT 4 -+#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 5 -+#define DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT 6 -+#define SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 7 -+#define SLICE_SAO_LUMA_FLAG_BIT 8 -+#define SLICE_SAO_CHROMA_FLAG_BIT 9 -+#define SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 10 -+ -+/* Constants for HEVC_MPRED_CTRL1 */ -+#define AMVP_MAX_NUM_CANDS_MEM 3 -+#define AMVP_MAX_NUM_CANDS 2 -+#define NUM_CHROMA_MODE 5 -+#define DM_CHROMA_IDX 36 -+ -+/* Buffer sizes */ -+#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + LMEM_SIZE, 64 * SZ_1K) -+#define SIZE_AUX (SZ_1K * 16) -+#define SIZE_FRAME_MMU (0x1200 * 4) -+#define RPM_SIZE 0x80 -+#define RPS_USED_BIT 14 -+ -+#define PARSER_CMD_SKIP_CFG_0 0x0000090b -+#define PARSER_CMD_SKIP_CFG_1 0x1b14140f -+#define PARSER_CMD_SKIP_CFG_2 0x001b1910 -+static const u16 parser_cmd[] = { -+ 0x0401, 0x8401, 0x0800, 0x0402, -+ 0x9002, 0x1423, 0x8CC3, 0x1423, -+ 0x8804, 0x9825, 0x0800, 0x04FE, -+ 0x8406, 0x8411, 0x1800, 0x8408, -+ 0x8409, 0x8C2A, 0x9C2B, 0x1C00, -+ 0x840F, 0x8407, 0x8000, 0x8408, -+ 0x2000, 0xA800, 0x8410, 0x04DE, -+ 0x840C, 0x840D, 0xAC00, 0xA000, -+ 0x08C0, 0x08E0, 0xA40E, 0xFC00, -+ 0x7C00 -+}; -+ -+/* Data received from the HW in this form, do not rearrange */ -+union rpm_param { -+ struct { -+ u16 data[RPM_SIZE]; -+ } l; -+ struct { -+ u16 CUR_RPS[MAX_REF_ACTIVE]; -+ u16 num_ref_idx_l0_active; -+ u16 num_ref_idx_l1_active; -+ u16 slice_type; -+ u16 slice_temporal_mvp_enable_flag; -+ u16 dependent_slice_segment_flag; -+ u16 slice_segment_address; -+ u16 num_title_rows_minus1; -+ u16 pic_width_in_luma_samples; -+ u16 pic_height_in_luma_samples; -+ u16 log2_min_coding_block_size_minus3; -+ u16 log2_diff_max_min_coding_block_size; -+ u16 log2_max_pic_order_cnt_lsb_minus4; -+ u16 POClsb; -+ u16 collocated_from_l0_flag; -+ u16 collocated_ref_idx; -+ u16 log2_parallel_merge_level; -+ u16 five_minus_max_num_merge_cand; -+ u16 sps_num_reorder_pics_0; -+ u16 modification_flag; -+ u16 tiles_flags; -+ u16 num_tile_columns_minus1; -+ u16 num_tile_rows_minus1; -+ u16 tile_width[8]; -+ u16 tile_height[8]; -+ u16 misc_flag0; -+ u16 pps_beta_offset_div2; -+ u16 pps_tc_offset_div2; -+ u16 slice_beta_offset_div2; -+ u16 slice_tc_offset_div2; -+ u16 pps_cb_qp_offset; -+ u16 pps_cr_qp_offset; -+ u16 first_slice_segment_in_pic_flag; -+ u16 m_temporalId; -+ u16 m_nalUnitType; -+ u16 vui_num_units_in_tick_hi; -+ u16 vui_num_units_in_tick_lo; -+ u16 vui_time_scale_hi; -+ u16 vui_time_scale_lo; -+ u16 bit_depth; -+ u16 profile_etc; -+ u16 sei_frame_field_info; -+ u16 video_signal_type; -+ u16 modification_list[0x20]; -+ u16 conformance_window_flag; -+ u16 conf_win_left_offset; -+ u16 conf_win_right_offset; -+ u16 conf_win_top_offset; -+ u16 conf_win_bottom_offset; -+ u16 chroma_format_idc; -+ u16 color_description; -+ u16 aspect_ratio_idc; -+ u16 sar_width; -+ u16 sar_height; -+ } p; -+}; -+ -+enum nal_unit_type { -+ NAL_UNIT_CODED_SLICE_BLA = 16, -+ NAL_UNIT_CODED_SLICE_BLANT = 17, -+ NAL_UNIT_CODED_SLICE_BLA_N_LP = 18, -+ NAL_UNIT_CODED_SLICE_IDR = 19, -+ NAL_UNIT_CODED_SLICE_IDR_N_LP = 20, -+}; -+ -+enum slice_type { -+ B_SLICE = 0, -+ P_SLICE = 1, -+ I_SLICE = 2, -+}; -+ -+/* A frame being decoded */ -+struct hevc_frame { -+ struct list_head list; -+ struct vb2_v4l2_buffer *vbuf; -+ u32 offset; -+ u32 poc; -+ -+ int referenced; -+ u32 num_reorder_pic; -+ -+ u32 cur_slice_idx; -+ u32 cur_slice_type; -+ -+ /* 2 lists (L0/L1) ; 800 slices ; 16 refs */ -+ u32 ref_poc_list[2][MAX_SLICE_NUM][MAX_REF_ACTIVE]; -+ u32 ref_num[2]; -+}; -+ -+struct codec_hevc { -+ struct mutex lock; -+ -+ /* Buffer for the HEVC Workspace */ -+ void *workspace_vaddr; -+ dma_addr_t workspace_paddr; -+ -+ /* AUX buffer */ -+ void *aux_vaddr; -+ dma_addr_t aux_paddr; -+ -+ /* Contains many information parsed from the bitstream */ -+ union rpm_param rpm_param; -+ -+ /* Information computed from the RPM */ -+ u32 lcu_size; // Largest Coding Unit -+ u32 lcu_x_num; -+ u32 lcu_y_num; -+ u32 lcu_total; -+ -+ /* Current Frame being handled */ -+ struct hevc_frame *cur_frame; -+ u32 curr_poc; -+ /* Collocated Reference Picture */ -+ struct hevc_frame *col_frame; -+ u32 col_poc; -+ -+ /* All ref frames used by the HW at a given time */ -+ struct list_head ref_frames_list; -+ u32 frames_num; -+ -+ /* Coded resolution reported by the hardware */ -+ u32 width, height; -+ /* Resolution minus the conformance window offsets */ -+ u32 dst_width, dst_height; -+ -+ u32 prev_tid0_poc; -+ u32 slice_segment_addr; -+ u32 slice_addr; -+ u32 ldc_flag; -+ -+ /* Whether we detected the bitstream as 10-bit */ -+ int is_10bit; -+ -+ /* In case of downsampling (decoding with FBC but outputting in NV12M), -+ * we need to allocate additional buffers for FBC. -+ */ -+ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; -+ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; -+}; -+ -+/* Returns 1 if we must use framebuffer compression */ -+static int codec_hevc_use_fbc(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ return sess->pixfmt_cap == V4L2_PIX_FMT_AM21C || hevc->is_10bit; -+} -+ -+/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ -+static int codec_hevc_use_downsample(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ return sess->pixfmt_cap == V4L2_PIX_FMT_NV12M && hevc->is_10bit; -+} -+ -+static u32 codec_hevc_num_pending_bufs(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc; -+ u32 ret; -+ -+ hevc = sess->priv; -+ if (!hevc) -+ return 0; -+ -+ mutex_lock(&hevc->lock); -+ ret = hevc->frames_num; -+ mutex_unlock(&hevc->lock); -+ -+ return ret; -+} -+ -+/* Update the L0 and L1 reference lists for a given frame */ -+static void codec_hevc_update_frame_refs(struct amvdec_session *sess, struct hevc_frame *frame) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ union rpm_param *params = &hevc->rpm_param; -+ int i; -+ int num_neg = 0; -+ int num_pos = 0; -+ int total_num; -+ int num_ref_idx_l0_active = -+ (params->p.num_ref_idx_l0_active > MAX_REF_ACTIVE) ? -+ MAX_REF_ACTIVE : params->p.num_ref_idx_l0_active; -+ int num_ref_idx_l1_active = -+ (params->p.num_ref_idx_l1_active > MAX_REF_ACTIVE) ? -+ MAX_REF_ACTIVE : params->p.num_ref_idx_l1_active; -+ int ref_picset0[MAX_REF_ACTIVE] = { 0 }; -+ int ref_picset1[MAX_REF_ACTIVE] = { 0 }; -+ -+ for (i = 0; i < MAX_REF_ACTIVE; i++) { -+ frame->ref_poc_list[0][frame->cur_slice_idx][i] = 0; -+ frame->ref_poc_list[1][frame->cur_slice_idx][i] = 0; -+ } -+ -+ for (i = 0; i < MAX_REF_ACTIVE; i++) { -+ u16 cur_rps = params->p.CUR_RPS[i]; -+ int delt = cur_rps & ((1 << (RPS_USED_BIT - 1)) - 1); -+ -+ if (cur_rps & 0x8000) -+ break; -+ -+ if (!((cur_rps >> RPS_USED_BIT) & 1)) -+ continue; -+ -+ if ((cur_rps >> (RPS_USED_BIT - 1)) & 1) { -+ ref_picset0[num_neg] = -+ frame->poc - ((1 << (RPS_USED_BIT - 1)) - delt); -+ num_neg++; -+ } else { -+ ref_picset1[num_pos] = frame->poc + delt; -+ num_pos++; -+ } -+ } -+ -+ total_num = num_neg + num_pos; -+ -+ if (total_num <= 0) -+ goto end; -+ -+ for (i = 0; i < num_ref_idx_l0_active; i++) { -+ int cidx; -+ if (params->p.modification_flag & 0x1) -+ cidx = params->p.modification_list[i]; -+ else -+ cidx = i % total_num; -+ -+ frame->ref_poc_list[0][frame->cur_slice_idx][i] = -+ cidx >= num_neg ? ref_picset1[cidx - num_neg] : -+ ref_picset0[cidx]; -+ } -+ -+ if (params->p.slice_type != B_SLICE) -+ goto end; -+ -+ if (params->p.modification_flag & 0x2) { -+ for (i = 0; i < num_ref_idx_l1_active; i++) { -+ int cidx; -+ if (params->p.modification_flag & 0x1) -+ cidx = -+ params->p.modification_list[num_ref_idx_l0_active + i]; -+ else -+ cidx = params->p.modification_list[i]; -+ -+ frame->ref_poc_list[1][frame->cur_slice_idx][i] = -+ (cidx >= num_pos) ? ref_picset0[cidx - num_pos] -+ : ref_picset1[cidx]; -+ } -+ } else { -+ for (i = 0; i < num_ref_idx_l1_active; i++) { -+ int cidx = i % total_num; -+ frame->ref_poc_list[1][frame->cur_slice_idx][i] = -+ cidx >= num_pos ? ref_picset0[cidx - num_pos] : -+ ref_picset1[cidx]; -+ } -+ } -+ -+end: -+ frame->ref_num[0] = num_ref_idx_l0_active; -+ frame->ref_num[1] = num_ref_idx_l1_active; -+ -+ dev_dbg(sess->core->dev, -+ "Frame %u; slice %u; slice_type %u; num_l0 %u; num_l1 %u\n", -+ frame->poc, frame->cur_slice_idx, params->p.slice_type, -+ frame->ref_num[0], frame->ref_num[1]); -+} -+ -+static void codec_hevc_update_ldc_flag(struct codec_hevc *hevc) -+{ -+ struct hevc_frame *frame = hevc->cur_frame; -+ u32 slice_type = frame->cur_slice_type; -+ u32 slice_idx = frame->cur_slice_idx; -+ int i; -+ -+ hevc->ldc_flag = 0; -+ -+ if (slice_type == I_SLICE) -+ return; -+ -+ hevc->ldc_flag = 1; -+ for (i = 0; (i < frame->ref_num[0]) && hevc->ldc_flag; i++) { -+ if (frame->ref_poc_list[0][slice_idx][i] > frame->poc) { -+ hevc->ldc_flag = 0; -+ break; -+ } -+ } -+ -+ if (slice_type == P_SLICE) -+ return; -+ -+ for (i = 0; (i < frame->ref_num[1]) && hevc->ldc_flag; i++) { -+ if (frame->ref_poc_list[1][slice_idx][i] > frame->poc) { -+ hevc->ldc_flag = 0; -+ break; -+ } -+ } -+} -+ -+/* Tag "old" frames that are no longer referenced */ -+static void codec_hevc_update_referenced(struct codec_hevc *hevc) -+{ -+ union rpm_param *param = &hevc->rpm_param; -+ struct hevc_frame *frame; -+ int i; -+ u32 curr_poc = hevc->curr_poc; -+ -+ list_for_each_entry(frame, &hevc->ref_frames_list, list) { -+ int is_referenced = 0; -+ u32 poc_tmp; -+ -+ if (!frame->referenced) -+ continue; -+ -+ for (i = 0; i < MAX_REF_ACTIVE; i++) { -+ int delt; -+ if (param->p.CUR_RPS[i] & 0x8000) -+ break; -+ -+ delt = param->p.CUR_RPS[i] & ((1 << (RPS_USED_BIT - 1)) - 1); -+ if (param->p.CUR_RPS[i] & (1 << (RPS_USED_BIT - 1))) { -+ poc_tmp = curr_poc - ((1 << (RPS_USED_BIT - 1)) - delt); -+ } else -+ poc_tmp = curr_poc + delt; -+ if (poc_tmp == frame->poc) { -+ is_referenced = 1; -+ break; -+ } -+ } -+ -+ frame->referenced = is_referenced; -+ } -+} -+ -+static struct hevc_frame * -+codec_hevc_get_lowest_poc_frame(struct codec_hevc *hevc) -+{ -+ struct hevc_frame *tmp, *ret = NULL; -+ u32 poc = INT_MAX; -+ -+ list_for_each_entry(tmp, &hevc->ref_frames_list, list) { -+ if (tmp->poc < poc) { -+ ret = tmp; -+ poc = tmp->poc; -+ } -+ } -+ -+ return ret; -+} -+ -+/* Try to output as many frames as possible */ -+static void codec_hevc_output_frames(struct amvdec_session *sess) -+{ -+ struct hevc_frame *tmp; -+ struct codec_hevc *hevc = sess->priv; -+ -+ while ((tmp = codec_hevc_get_lowest_poc_frame(hevc))) { -+ if (hevc->curr_poc && -+ (tmp->referenced || -+ tmp->num_reorder_pic >= hevc->frames_num)) -+ break; -+ -+ dev_dbg(sess->core->dev, "DONE frame poc %u; vbuf %u\n", -+ tmp->poc, tmp->vbuf->vb2_buf.index); -+ amvdec_dst_buf_done_offset(sess, tmp->vbuf, tmp->offset, -+ V4L2_FIELD_NONE, false); -+ list_del(&tmp->list); -+ kfree(tmp); -+ hevc->frames_num--; -+ } -+} -+ -+/* Configure decode head read mode */ -+static void codec_hevc_setup_decode_head(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); -+ u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); -+ -+ if (!codec_hevc_use_fbc(sess)) { -+ /* Enable 2-plane reference read mode */ -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); -+ return; -+ } -+ -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); -+ amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); -+ amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); -+ amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); -+} -+ -+static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_hevc *hevc = sess->priv; -+ struct v4l2_m2m_buffer *buf; -+ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -+ dma_addr_t buf_y_paddr = 0; -+ dma_addr_t buf_uv_paddr = 0; -+ u32 idx = 0; -+ u32 val; -+ int i; -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ idx = buf->vb.vb2_buf.index; -+ -+ if (codec_hevc_use_downsample(sess)) -+ buf_y_paddr = hevc->fbc_buffer_paddr[idx]; -+ else -+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -+ -+ if (codec_hevc_use_fbc(sess)) { -+ val = buf_y_paddr | (idx << 8) | 1; -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ } else { -+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -+ val = buf_y_paddr | ((idx * 2) << 8) | 1; -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ } -+ } -+ -+ if (codec_hevc_use_fbc(sess)) -+ val = buf_y_paddr | (idx << 8) | 1; -+ else -+ val = buf_y_paddr | ((idx * 2) << 8) | 1; -+ -+ /* Fill the remaining unused slots with the last buffer's Y addr */ -+ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -+ for (i = 0; i < 32; ++i) -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); -+} -+ -+static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_hevc *hevc = sess->priv; -+ struct v4l2_m2m_buffer *buf; -+ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -+ dma_addr_t buf_y_paddr = 0; -+ dma_addr_t buf_uv_paddr = 0; -+ int i; -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, -+ BIT(2) | BIT(1)); -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ u32 idx = buf->vb.vb2_buf.index; -+ -+ if (codec_hevc_use_downsample(sess)) -+ buf_y_paddr = hevc->fbc_buffer_paddr[idx]; -+ else -+ buf_y_paddr = -+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_y_paddr >> 5); -+ if (!codec_hevc_use_fbc(sess)) { -+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_uv_paddr >> 5); -+ } -+ } -+ -+ /* Fill the remaining unused slots with the last buffer's Y addr */ -+ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_y_paddr >> 5); -+ if (!codec_hevc_use_fbc(sess)) -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_uv_paddr >> 5); -+ } -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -+ for (i = 0; i < 32; ++i) -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); -+} -+ -+static void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ struct device *dev = sess->core->dev; -+ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); -+ int i; -+ -+ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { -+ if (hevc->fbc_buffer_vaddr[i]) { -+ dma_free_coherent(dev, am21_size, -+ hevc->fbc_buffer_vaddr[i], -+ hevc->fbc_buffer_paddr[i]); -+ hevc->fbc_buffer_vaddr[i] = NULL; -+ } -+ } -+} -+ -+static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ struct device *dev = sess->core->dev; -+ struct v4l2_m2m_buffer *buf; -+ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ u32 idx = buf->vb.vb2_buf.index; -+ dma_addr_t paddr; -+ void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, -+ GFP_KERNEL); -+ if (!vaddr) { -+ dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); -+ codec_hevc_free_fbc_buffers(sess); -+ return -ENOMEM; -+ } -+ -+ hevc->fbc_buffer_vaddr[idx] = vaddr; -+ hevc->fbc_buffer_paddr[idx] = paddr; -+ } -+ -+ return 0; -+} -+ -+static int codec_hevc_setup_buffers(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ int ret; -+ -+ if (codec_hevc_use_downsample(sess)) { -+ ret = codec_hevc_alloc_fbc_buffers(sess); -+ if (ret) -+ return ret; -+ } -+ -+ if (core->platform->revision == VDEC_REVISION_GXBB) -+ codec_hevc_setup_buffers_gxbb(sess); -+ else -+ codec_hevc_setup_buffers_gxl(sess); -+ -+ return 0; -+} -+ -+static int -+codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) -+{ -+ dma_addr_t wkaddr; -+ -+ /* Allocate some memory for the HEVC decoder's state */ -+ hevc->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, -+ &wkaddr, GFP_KERNEL); -+ if (!hevc->workspace_vaddr) { -+ dev_err(core->dev, "Failed to allocate HEVC Workspace\n"); -+ return -ENOMEM; -+ } -+ -+ hevc->workspace_paddr = wkaddr; -+ -+ amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); -+ amvdec_write_dos(core, HEVC_RPM_BUFFER, wkaddr + RPM_OFFSET); -+ amvdec_write_dos(core, HEVC_SHORT_TERM_RPS, wkaddr + SH_TM_RPS_OFFSET); -+ amvdec_write_dos(core, HEVC_VPS_BUFFER, wkaddr + VPS_OFFSET); -+ amvdec_write_dos(core, HEVC_SPS_BUFFER, wkaddr + SPS_OFFSET); -+ amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET); -+ amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET); -+ -+ /* No MMU */ -+ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, -+ wkaddr + SWAP_BUF_OFFSET); -+ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, -+ wkaddr + SWAP_BUF2_OFFSET); -+ amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); -+ amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); -+ amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); -+ -+ return 0; -+} -+ -+static int codec_hevc_start(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_hevc *hevc; -+ u32 val; -+ int i; -+ int ret; -+ -+ hevc = kzalloc(sizeof(*hevc), GFP_KERNEL); -+ if (!hevc) -+ return -ENOMEM; -+ -+ INIT_LIST_HEAD(&hevc->ref_frames_list); -+ hevc->curr_poc = INVALID_POC; -+ -+ ret = codec_hevc_setup_workspace(core, hevc); -+ if (ret) -+ goto free_hevc; -+ -+ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); -+ -+ val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; -+ val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | -+ BIT(0); -+ amvdec_write_dos(core, HEVC_PARSER_INT_CONTROL, val); -+ amvdec_write_dos_bits(core, HEVC_SHIFT_STATUS, BIT(1) | BIT(0)); -+ amvdec_write_dos(core, HEVC_SHIFT_CONTROL, -+ (3 << 6) | BIT(5) | BIT(2) | BIT(0)); -+ amvdec_write_dos(core, HEVC_CABAC_CONTROL, 1); -+ amvdec_write_dos(core, HEVC_PARSER_CORE_CONTROL, 1); -+ amvdec_write_dos(core, HEVC_DEC_STATUS_REG, 0); -+ -+ amvdec_write_dos(core, HEVC_IQIT_SCALELUT_WR_ADDR, 0); -+ for (i = 0; i < 1024; ++i) -+ amvdec_write_dos(core, HEVC_IQIT_SCALELUT_DATA, 0); -+ -+ amvdec_write_dos(core, HEVC_DECODE_SIZE, 0); -+ -+ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); -+ for (i = 0; i < ARRAY_SIZE(parser_cmd); ++i) -+ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, parser_cmd[i]); -+ -+ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); -+ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); -+ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2); -+ amvdec_write_dos(core, HEVC_PARSER_IF_CONTROL, -+ BIT(5) | BIT(2) | BIT(0)); -+ -+ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(0)); -+ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(1)); -+ -+ amvdec_write_dos(core, HEVC_WAIT_FLAG, 1); -+ -+ /* clear mailbox interrupt */ -+ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_CLR_REG, 1); -+ /* enable mailbox interrupt */ -+ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 1); -+ /* disable PSCALE for hardware sharing */ -+ amvdec_write_dos(core, HEVC_PSCALE_CTRL, 0); -+ /* Let the uCode do all the parsing */ -+ amvdec_write_dos(core, NAL_SEARCH_CTL, 0xc); -+ -+ amvdec_write_dos(core, DECODE_STOP_POS, 0); -+ amvdec_write_dos(core, HEVC_DECODE_MODE, DECODE_MODE_SINGLE); -+ amvdec_write_dos(core, HEVC_DECODE_MODE2, 0); -+ -+ /* AUX buffers */ -+ hevc->aux_vaddr = dma_alloc_coherent(core->dev, SIZE_AUX, -+ &hevc->aux_paddr, GFP_KERNEL); -+ if (!hevc->aux_vaddr) { -+ dev_err(core->dev, "Failed to request HEVC AUX\n"); -+ ret = -ENOMEM; -+ goto free_hevc; -+ } -+ -+ amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); -+ amvdec_write_dos(core, HEVC_AUX_DATA_SIZE, -+ (((SIZE_AUX) >> 4) << 16) | 0); -+ mutex_init(&hevc->lock); -+ sess->priv = hevc; -+ -+ return 0; -+ -+free_hevc: -+ kfree(hevc); -+ return ret; -+} -+ -+static void codec_hevc_flush_output(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ struct hevc_frame *tmp; -+ -+ while (!list_empty(&hevc->ref_frames_list)) { -+ tmp = codec_hevc_get_lowest_poc_frame(hevc); -+ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); -+ list_del(&tmp->list); -+ kfree(tmp); -+ hevc->frames_num--; -+ } -+} -+ -+static int codec_hevc_stop(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ struct amvdec_core *core = sess->core; -+ -+ mutex_lock(&hevc->lock); -+ codec_hevc_flush_output(sess); -+ -+ if (hevc->workspace_vaddr) -+ dma_free_coherent(core->dev, SIZE_WORKSPACE, -+ hevc->workspace_vaddr, -+ hevc->workspace_paddr); -+ -+ if (hevc->aux_vaddr) -+ dma_free_coherent(core->dev, SIZE_AUX, -+ hevc->aux_vaddr, hevc->aux_paddr); -+ -+ codec_hevc_free_fbc_buffers(sess); -+ mutex_unlock(&hevc->lock); -+ mutex_destroy(&hevc->lock); -+ -+ return 0; -+} -+ -+static struct hevc_frame * -+codec_hevc_get_frame_by_poc(struct codec_hevc *hevc, u32 poc) -+{ -+ struct hevc_frame *tmp; -+ -+ list_for_each_entry(tmp, &hevc->ref_frames_list, list) { -+ if (tmp->poc == poc) -+ return tmp; -+ } -+ -+ return NULL; -+} -+ -+static struct hevc_frame * -+codec_hevc_prepare_new_frame(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct hevc_frame *new_frame = NULL; -+ struct codec_hevc *hevc = sess->priv; -+ struct vb2_v4l2_buffer *vbuf; -+ union rpm_param *params = &hevc->rpm_param; -+ -+ new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL); -+ if (!new_frame) -+ return NULL; -+ -+ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); -+ if (!vbuf) { -+ dev_err(sess->core->dev, "No dst buffer available\n"); -+ return NULL; -+ } -+ -+ new_frame->vbuf = vbuf; -+ new_frame->referenced = 1; -+ new_frame->poc = hevc->curr_poc; -+ new_frame->cur_slice_type = params->p.slice_type; -+ new_frame->num_reorder_pic = params->p.sps_num_reorder_pics_0; -+ new_frame->offset = amvdec_read_dos(core, HEVC_SHIFT_BYTE_COUNT); -+ -+ list_add_tail(&new_frame->list, &hevc->ref_frames_list); -+ hevc->frames_num++; -+ -+ return new_frame; -+} -+ -+static void -+codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_hevc *hevc = sess->priv; -+ union rpm_param *param = &hevc->rpm_param; -+ u32 pic_height_cu = -+ (hevc->height + hevc->lcu_size - 1) / hevc->lcu_size; -+ u32 sao_mem_unit = (hevc->lcu_size == 16 ? 9 : -+ hevc->lcu_size == 32 ? 14 : 24) << 4; -+ u32 sao_vb_size = (sao_mem_unit + (2 << 4)) * pic_height_cu; -+ u32 misc_flag0 = param->p.misc_flag0; -+ dma_addr_t buf_y_paddr; -+ dma_addr_t buf_u_v_paddr; -+ u32 slice_deblocking_filter_disabled_flag; -+ u32 val, val_2; -+ -+ val = (amvdec_read_dos(core, HEVC_SAO_CTRL0) & ~0xf) | -+ ilog2(hevc->lcu_size); -+ amvdec_write_dos(core, HEVC_SAO_CTRL0, val); -+ -+ amvdec_write_dos(core, HEVC_SAO_PIC_SIZE, -+ hevc->width | (hevc->height << 16)); -+ amvdec_write_dos(core, HEVC_SAO_PIC_SIZE_LCU, -+ (hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); -+ -+ if (codec_hevc_use_downsample(sess)) -+ buf_y_paddr = -+ hevc->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; -+ else -+ buf_y_paddr = -+ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); -+ -+ if (codec_hevc_use_fbc(sess)) { -+ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; -+ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); -+ amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); -+ } -+ -+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { -+ buf_y_paddr = -+ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); -+ buf_u_v_paddr = -+ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 1); -+ amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr); -+ amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr); -+ amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr); -+ amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); -+ } -+ -+ amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, -+ amvdec_get_output_size(sess)); -+ amvdec_write_dos(core, HEVC_SAO_C_LENGTH, -+ (amvdec_get_output_size(sess) / 2)); -+ -+ if (frame->cur_slice_idx == 0) { -+ amvdec_write_dos(core, HEVC_DBLK_CFG2, -+ hevc->width | (hevc->height << 16)); -+ -+ val = 0; -+ if ((misc_flag0 >> PCM_ENABLE_FLAG_BIT) & 0x1) -+ val |= ((misc_flag0 >> PCM_LOOP_FILTER_DISABLED_FLAG_BIT) & 0x1) << 3; -+ -+ val |= (param->p.pps_cb_qp_offset & 0x1f) << 4; -+ val |= (param->p.pps_cr_qp_offset & 0x1f) << 9; -+ val |= (hevc->lcu_size == 64) ? 0 : ((hevc->lcu_size == 32) ? 1 : 2); -+ amvdec_write_dos(core, HEVC_DBLK_CFG1, val); -+ } -+ -+ val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; -+ val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ -+ if (!codec_hevc_use_fbc(sess)) -+ val |= BIT(0); /* disable cm compression */ -+ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) -+ val |= BIT(1); /* Disable double write */ -+ -+ amvdec_write_dos(core, HEVC_SAO_CTRL1, val); -+ -+ if (!codec_hevc_use_fbc(sess)) { -+ /* no downscale for NV12 */ -+ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; -+ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); -+ } -+ -+ val = amvdec_read_dos(core, HEVCD_IPP_AXIIF_CONFIG) & ~0x30; -+ val |= 0xf; -+ amvdec_write_dos(core, HEVCD_IPP_AXIIF_CONFIG, val); -+ -+ val = 0; -+ val_2 = amvdec_read_dos(core, HEVC_SAO_CTRL0); -+ val_2 &= (~0x300); -+ -+ slice_deblocking_filter_disabled_flag = (misc_flag0 >> -+ SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1; -+ if ((misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT)) -+ && (misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT))) { -+ val |= slice_deblocking_filter_disabled_flag << 2; -+ -+ if (!slice_deblocking_filter_disabled_flag) { -+ val |= (param->p.slice_beta_offset_div2 & 0xf) << 3; -+ val |= (param->p.slice_tc_offset_div2 & 0xf) << 7; -+ } -+ } else { -+ val |= -+ ((misc_flag0 >> -+ PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1) << 2; -+ -+ if (((misc_flag0 >> PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & -+ 0x1) == 0) { -+ val |= (param->p.pps_beta_offset_div2 & 0xf) << 3; -+ val |= (param->p.pps_tc_offset_div2 & 0xf) << 7; -+ } -+ } -+ if ((misc_flag0 & (1 << PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)) -+ && ((misc_flag0 & (1 << SLICE_SAO_LUMA_FLAG_BIT)) -+ || (misc_flag0 & (1 << SLICE_SAO_CHROMA_FLAG_BIT)) -+ || (!slice_deblocking_filter_disabled_flag))) { -+ val |= -+ ((misc_flag0 >> -+ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) -+ & 0x1) << 1; -+ val_2 |= -+ ((misc_flag0 >> -+ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) -+ & 0x1) << 9; -+ } else { -+ val |= -+ ((misc_flag0 >> -+ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) -+ & 0x1) << 1; -+ val_2 |= -+ ((misc_flag0 >> -+ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) -+ & 0x1) << 9; -+ } -+ -+ amvdec_write_dos(core, HEVC_DBLK_CFG9, val); -+ amvdec_write_dos(core, HEVC_SAO_CTRL0, val_2); -+ -+ amvdec_write_dos(core, HEVC_sao_mem_unit, sao_mem_unit); -+ amvdec_write_dos(core, HEVC_SAO_ABV, -+ hevc->workspace_paddr + SAO_ABV_OFFSET); -+ amvdec_write_dos(core, HEVC_sao_vb_size, sao_vb_size); -+ amvdec_write_dos(core, HEVC_SAO_VB, -+ hevc->workspace_paddr + SAO_VB_OFFSET); -+} -+ -+static dma_addr_t codec_hevc_get_frame_mv_paddr(struct codec_hevc *hevc, -+ struct hevc_frame *frame) -+{ -+ return hevc->workspace_paddr + MPRED_MV_OFFSET + -+ (frame->vbuf->vb2_buf.index * MPRED_MV_BUF_SIZE); -+} -+ -+static void -+codec_hevc_set_mpred_ctrl(struct amvdec_core *core, struct codec_hevc *hevc) -+{ -+ union rpm_param *param = &hevc->rpm_param; -+ u32 slice_type = param->p.slice_type; -+ u32 lcu_size_log2 = ilog2(hevc->lcu_size); -+ u32 val; -+ -+ val = slice_type | -+ MPRED_CTRL0_ABOVE_EN | -+ MPRED_CTRL0_MV_WR_EN | -+ MPRED_CTRL0_BUF_LINEAR | -+ (lcu_size_log2 << 16) | -+ (3 << 20) | /* cu_size_log2 */ -+ (param->p.log2_parallel_merge_level << 24); -+ -+ if (slice_type != I_SLICE) -+ val |= MPRED_CTRL0_MV_RD_EN; -+ -+ if (param->p.collocated_from_l0_flag) -+ val |= MPRED_CTRL0_COL_FROM_L0; -+ -+ if (param->p.slice_temporal_mvp_enable_flag) -+ val |= MPRED_CTRL0_TMVP; -+ -+ if (hevc->ldc_flag) -+ val |= MPRED_CTRL0_LDC; -+ -+ if (param->p.dependent_slice_segment_flag) -+ val |= MPRED_CTRL0_NEW_SLI_SEG; -+ -+ if (param->p.slice_segment_address == 0) -+ val |= MPRED_CTRL0_NEW_PIC | -+ MPRED_CTRL0_NEW_TILE; -+ -+ amvdec_write_dos(core, HEVC_MPRED_CTRL0, val); -+ -+ val = (5 - param->p.five_minus_max_num_merge_cand) | -+ (AMVP_MAX_NUM_CANDS << 4) | -+ (AMVP_MAX_NUM_CANDS_MEM << 8) | -+ (NUM_CHROMA_MODE << 12) | -+ (DM_CHROMA_IDX << 16); -+ amvdec_write_dos(core, HEVC_MPRED_CTRL1, val); -+} -+ -+static void codec_hevc_set_mpred_mv(struct amvdec_core *core, -+ struct codec_hevc *hevc, -+ struct hevc_frame *frame, -+ struct hevc_frame *col_frame) -+{ -+ union rpm_param *param = &hevc->rpm_param; -+ u32 lcu_size_log2 = ilog2(hevc->lcu_size); -+ u32 mv_mem_unit = lcu_size_log2 == 6 ? 0x200 : -+ lcu_size_log2 == 5 ? 0x80 : 0x20; -+ dma_addr_t col_mv_rd_start_addr, col_mv_rd_ptr, col_mv_rd_end_addr; -+ dma_addr_t mpred_mv_wr_ptr; -+ u32 val; -+ -+ val = amvdec_read_dos(core, HEVC_MPRED_CURR_LCU); -+ -+ col_mv_rd_start_addr = codec_hevc_get_frame_mv_paddr(hevc, col_frame); -+ mpred_mv_wr_ptr = codec_hevc_get_frame_mv_paddr(hevc, frame) + -+ (hevc->slice_addr * mv_mem_unit); -+ col_mv_rd_ptr = col_mv_rd_start_addr + -+ (hevc->slice_addr * mv_mem_unit); -+ col_mv_rd_end_addr = col_mv_rd_start_addr + -+ (hevc->lcu_total * mv_mem_unit); -+ -+ amvdec_write_dos(core, HEVC_MPRED_MV_WR_START_ADDR, -+ codec_hevc_get_frame_mv_paddr(hevc, frame)); -+ amvdec_write_dos(core, HEVC_MPRED_MV_RD_START_ADDR, -+ col_mv_rd_start_addr); -+ -+ if (param->p.slice_segment_address == 0) { -+ amvdec_write_dos(core, HEVC_MPRED_ABV_START_ADDR, -+ hevc->workspace_paddr + MPRED_ABV_OFFSET); -+ amvdec_write_dos(core, HEVC_MPRED_MV_WPTR, mpred_mv_wr_ptr); -+ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, -+ col_mv_rd_start_addr); -+ } else { -+ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, col_mv_rd_ptr); -+ } -+ -+ amvdec_write_dos(core, HEVC_MPRED_MV_RD_END_ADDR, col_mv_rd_end_addr); -+} -+ -+/* Update motion prediction with the current slice */ -+static void codec_hevc_set_mpred(struct amvdec_session *sess, -+ struct hevc_frame *frame, -+ struct hevc_frame *col_frame) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_hevc *hevc = sess->priv; -+ u32 *ref_num = frame->ref_num; -+ u32 *ref_poc_l0 = frame->ref_poc_list[0][frame->cur_slice_idx]; -+ u32 *ref_poc_l1 = frame->ref_poc_list[1][frame->cur_slice_idx]; -+ u32 val; -+ int i; -+ -+ codec_hevc_set_mpred_ctrl(core, hevc); -+ codec_hevc_set_mpred_mv(core, hevc, frame, col_frame); -+ -+ amvdec_write_dos(core, HEVC_MPRED_PIC_SIZE, -+ hevc->width | (hevc->height << 16)); -+ -+ val = ((hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); -+ amvdec_write_dos(core, HEVC_MPRED_PIC_SIZE_LCU, val); -+ -+ amvdec_write_dos(core, HEVC_MPRED_REF_NUM, -+ (ref_num[1] << 8) | ref_num[0]); -+ amvdec_write_dos(core, HEVC_MPRED_REF_EN_L0, (1 << ref_num[0]) - 1); -+ amvdec_write_dos(core, HEVC_MPRED_REF_EN_L1, (1 << ref_num[1]) - 1); -+ -+ amvdec_write_dos(core, HEVC_MPRED_CUR_POC, hevc->curr_poc); -+ amvdec_write_dos(core, HEVC_MPRED_COL_POC, hevc->col_poc); -+ -+ for (i = 0; i < MAX_REF_ACTIVE; ++i) { -+ amvdec_write_dos(core, HEVC_MPRED_L0_REF00_POC + i * 4, -+ ref_poc_l0[i]); -+ amvdec_write_dos(core, HEVC_MPRED_L1_REF00_POC + i * 4, -+ ref_poc_l1[i]); -+ } -+} -+ -+/* motion compensation reference cache controller */ -+static void codec_hevc_set_mcrcc(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_hevc *hevc = sess->priv; -+ u32 val, val_2; -+ int l0_cnt = 0; -+ int l1_cnt = 0x7fff; -+ -+ if (!codec_hevc_use_fbc(sess)) { -+ l0_cnt = hevc->cur_frame->ref_num[0]; -+ l1_cnt = hevc->cur_frame->ref_num[1]; -+ } -+ -+ if (hevc->cur_frame->cur_slice_type == I_SLICE) { -+ amvdec_write_dos(core, HEVCD_MCRCC_CTL1, 0); -+ return; -+ } -+ -+ if (hevc->cur_frame->cur_slice_type == P_SLICE) { -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, -+ BIT(1)); -+ val = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); -+ val &= 0xffff; -+ val |= (val << 16); -+ amvdec_write_dos(core, HEVCD_MCRCC_CTL2, val); -+ -+ if (l0_cnt == 1) { -+ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); -+ } else { -+ val = amvdec_read_dos(core, -+ HEVCD_MPP_ANC_CANVAS_DATA_ADDR); -+ val &= 0xffff; -+ val |= (val << 16); -+ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); -+ } -+ } else { /* B_SLICE */ -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 0); -+ val = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); -+ val &= 0xffff; -+ val |= (val << 16); -+ amvdec_write_dos(core, HEVCD_MCRCC_CTL2, val); -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, -+ BIT(12) | BIT(1)); -+ val_2 = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); -+ val_2 &= 0xffff; -+ val_2 |= (val_2 << 16); -+ if (val == val_2 && l1_cnt > 1) { -+ val_2 = amvdec_read_dos(core, -+ HEVCD_MPP_ANC_CANVAS_DATA_ADDR); -+ val_2 &= 0xffff; -+ val_2 |= (val_2 << 16); -+ } -+ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); -+ } -+ -+ /* enable mcrcc progressive-mode */ -+ amvdec_write_dos(core, HEVCD_MCRCC_CTL1, 0xff0); -+} -+ -+static void codec_hevc_set_ref_list(struct amvdec_session *sess, -+ u32 ref_num, u32 *ref_poc_list) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ struct hevc_frame *ref_frame; -+ struct amvdec_core *core = sess->core; -+ int i; -+ u32 buf_id_y; -+ u32 buf_id_uv; -+ -+ for (i = 0; i < ref_num; i++) { -+ ref_frame = codec_hevc_get_frame_by_poc(hevc, ref_poc_list[i]); -+ -+ if (!ref_frame) { -+ dev_warn(core->dev, "Couldn't find ref. frame %u\n", -+ ref_poc_list[i]); -+ continue; -+ } -+ -+ if (codec_hevc_use_fbc(sess)) { -+ buf_id_y = buf_id_uv = ref_frame->vbuf->vb2_buf.index; -+ } else { -+ buf_id_y = ref_frame->vbuf->vb2_buf.index * 2; -+ buf_id_uv = buf_id_y + 1; -+ } -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, -+ (buf_id_uv << 16) | -+ (buf_id_uv << 8) | -+ buf_id_y); -+ } -+} -+ -+static void codec_hevc_set_mc(struct amvdec_session *sess, struct hevc_frame *frame) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ if (frame->cur_slice_type == I_SLICE) -+ return; -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -+ codec_hevc_set_ref_list(sess, frame->ref_num[0], -+ frame->ref_poc_list[0][frame->cur_slice_idx]); -+ -+ if (frame->cur_slice_type == P_SLICE) -+ return; -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, -+ BIT(12) | BIT(0)); -+ codec_hevc_set_ref_list(sess, frame->ref_num[1], -+ frame->ref_poc_list[1][frame->cur_slice_idx]); -+} -+ -+static void codec_hevc_update_col_frame(struct codec_hevc *hevc) -+{ -+ struct hevc_frame *cur_frame = hevc->cur_frame; -+ union rpm_param *param = &hevc->rpm_param; -+ u32 list_no = 0; -+ u32 col_ref = param->p.collocated_ref_idx; -+ u32 col_from_l0 = param->p.collocated_from_l0_flag; -+ -+ if (cur_frame->cur_slice_type == B_SLICE) -+ list_no = 1 - col_from_l0; -+ -+ if (col_ref >= cur_frame->ref_num[list_no]) -+ hevc->col_poc = INVALID_POC; -+ else -+ hevc->col_poc = cur_frame->ref_poc_list[list_no][cur_frame->cur_slice_idx][col_ref]; -+ -+ if (cur_frame->cur_slice_type == I_SLICE) -+ goto end; -+ -+ if (hevc->col_poc != INVALID_POC) -+ hevc->col_frame = codec_hevc_get_frame_by_poc(hevc, hevc->col_poc); -+ else -+ hevc->col_frame = hevc->cur_frame; -+ -+end: -+ if (!hevc->col_frame) -+ hevc->col_frame = hevc->cur_frame; -+} -+ -+static void codec_hevc_update_pocs(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ union rpm_param *param = &hevc->rpm_param; -+ u32 nal_unit_type = param->p.m_nalUnitType; -+ u32 temporal_id = param->p.m_temporalId & 0x7; -+ int max_poc_lsb = -+ 1 << (param->p.log2_max_pic_order_cnt_lsb_minus4 + 4); -+ int prev_poc_lsb; -+ int prev_poc_msb; -+ int poc_msb; -+ int poc_lsb = param->p.POClsb; -+ -+ if (nal_unit_type == NAL_UNIT_CODED_SLICE_IDR || -+ nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) { -+ hevc->curr_poc = 0; -+ if ((temporal_id - 1) == 0) -+ hevc->prev_tid0_poc = hevc->curr_poc; -+ -+ return; -+ } -+ -+ prev_poc_lsb = hevc->prev_tid0_poc % max_poc_lsb; -+ prev_poc_msb = hevc->prev_tid0_poc - prev_poc_lsb; -+ -+ if ((poc_lsb < prev_poc_lsb) && -+ ((prev_poc_lsb - poc_lsb) >= (max_poc_lsb / 2))) -+ poc_msb = prev_poc_msb + max_poc_lsb; -+ else if ((poc_lsb > prev_poc_lsb) && -+ ((poc_lsb - prev_poc_lsb) > (max_poc_lsb / 2))) -+ poc_msb = prev_poc_msb - max_poc_lsb; -+ else -+ poc_msb = prev_poc_msb; -+ -+ if (nal_unit_type == NAL_UNIT_CODED_SLICE_BLA || -+ nal_unit_type == NAL_UNIT_CODED_SLICE_BLANT || -+ nal_unit_type == NAL_UNIT_CODED_SLICE_BLA_N_LP) -+ poc_msb = 0; -+ -+ hevc->curr_poc = (poc_msb + poc_lsb); -+ if ((temporal_id - 1) == 0) -+ hevc->prev_tid0_poc = hevc->curr_poc; -+} -+ -+static void codec_hevc_process_segment_header(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ union rpm_param *param = &hevc->rpm_param; -+ -+ if (param->p.first_slice_segment_in_pic_flag == 0) { -+ hevc->slice_segment_addr = param->p.slice_segment_address; -+ if (!param->p.dependent_slice_segment_flag) -+ hevc->slice_addr = hevc->slice_segment_addr; -+ } else { -+ hevc->slice_segment_addr = 0; -+ hevc->slice_addr = 0; -+ } -+ -+ codec_hevc_update_pocs(sess); -+} -+ -+static int codec_hevc_process_segment(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ struct amvdec_core *core = sess->core; -+ union rpm_param *param = &hevc->rpm_param; -+ u32 slice_segment_address = param->p.slice_segment_address; -+ -+ /* First slice: new frame */ -+ if (slice_segment_address == 0) { -+ codec_hevc_update_referenced(hevc); -+ codec_hevc_output_frames(sess); -+ -+ hevc->cur_frame = codec_hevc_prepare_new_frame(sess); -+ if (!hevc->cur_frame) -+ return -1; -+ } else { -+ hevc->cur_frame->cur_slice_idx++; -+ } -+ -+ codec_hevc_update_frame_refs(sess, hevc->cur_frame); -+ codec_hevc_update_col_frame(hevc); -+ codec_hevc_update_ldc_flag(hevc); -+ codec_hevc_set_mc(sess, hevc->cur_frame); -+ codec_hevc_set_mcrcc(sess); -+ codec_hevc_set_mpred(sess, hevc->cur_frame, hevc->col_frame); -+ codec_hevc_set_sao(sess, hevc->cur_frame); -+ -+ amvdec_write_dos_bits(core, HEVC_WAIT_FLAG, BIT(1)); -+ amvdec_write_dos(core, HEVC_DEC_STATUS_REG, -+ HEVC_CODED_SLICE_SEGMENT_DAT); -+ -+ /* Interrupt the firmware's processor */ -+ amvdec_write_dos(core, HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ); -+ -+ return 0; -+} -+ -+static int codec_hevc_process_rpm(struct codec_hevc *hevc) -+{ -+ union rpm_param *param = &hevc->rpm_param; -+ int src_changed = 0; -+ u32 dst_width, dst_height; -+ u32 lcu_size; -+ u32 is_10bit; -+ -+ if (param->p.slice_segment_address || -+ !param->p.pic_width_in_luma_samples || -+ !param->p.pic_height_in_luma_samples) -+ return 0; -+ -+ if (param->p.bit_depth) -+ is_10bit = 1; -+ -+ hevc->width = param->p.pic_width_in_luma_samples; -+ hevc->height = param->p.pic_height_in_luma_samples; -+ dst_width = hevc->width; -+ dst_height = hevc->height; -+ -+ lcu_size = 1 << (param->p.log2_min_coding_block_size_minus3 + -+ 3 + param->p.log2_diff_max_min_coding_block_size); -+ -+ hevc->lcu_x_num = (hevc->width + lcu_size - 1) / lcu_size; -+ hevc->lcu_y_num = (hevc->height + lcu_size - 1) / lcu_size; -+ hevc->lcu_total = hevc->lcu_x_num * hevc->lcu_y_num; -+ -+ if (param->p.conformance_window_flag) { -+ u32 sub_width = 1, sub_height = 1; -+ -+ switch (param->p.chroma_format_idc) { -+ case 1: -+ sub_height = 2; -+ case 2: -+ sub_width = 2; -+ break; -+ } -+ -+ dst_width -= sub_width * -+ (param->p.conf_win_left_offset + -+ param->p.conf_win_right_offset); -+ dst_height -= sub_height * -+ (param->p.conf_win_top_offset + -+ param->p.conf_win_bottom_offset); -+ } -+ -+ if (dst_width != hevc->dst_width || -+ dst_height != hevc->dst_height || -+ lcu_size != hevc->lcu_size || -+ is_10bit != hevc->is_10bit) -+ src_changed = 1; -+ -+ hevc->dst_width = dst_width; -+ hevc->dst_height = dst_height; -+ hevc->lcu_size = lcu_size; -+ hevc->is_10bit = is_10bit; -+ -+ return src_changed; -+} -+ -+/* The RPM section within the workspace contains -+ * many information regarding the parsed bitstream -+ */ -+static void codec_hevc_fetch_rpm(struct amvdec_session *sess) -+{ -+ struct codec_hevc *hevc = sess->priv; -+ u16 *rpm_vaddr = hevc->workspace_vaddr + RPM_OFFSET; -+ int i, j; -+ -+ for (i = 0; i < RPM_SIZE; i += 4) -+ for (j = 0; j < 4; j++) -+ hevc->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j]; -+} -+ -+static void codec_hevc_resume(struct amvdec_session *sess) -+{ -+ if (codec_hevc_setup_buffers(sess)) { -+ amvdec_abort(sess); -+ return; -+ } -+ -+ codec_hevc_setup_decode_head(sess); -+ codec_hevc_process_segment_header(sess); -+ if (codec_hevc_process_segment(sess)) -+ amvdec_abort(sess); -+} -+ -+static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_hevc *hevc = sess->priv; -+ u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG); -+ -+ if (!hevc) -+ return IRQ_HANDLED; -+ -+ mutex_lock(&hevc->lock); -+ if (dec_status != HEVC_SLICE_SEGMENT_DONE) { -+ dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n", -+ dec_status); -+ amvdec_abort(sess); -+ goto unlock; -+ } -+ -+ sess->keyframe_found = 1; -+ codec_hevc_fetch_rpm(sess); -+ if (codec_hevc_process_rpm(hevc)) { -+ amvdec_src_change(sess, hevc->dst_width, hevc->dst_height, 16); -+ goto unlock; -+ } -+ -+ codec_hevc_process_segment_header(sess); -+ if (codec_hevc_process_segment(sess)) -+ amvdec_abort(sess); -+ -+unlock: -+ mutex_unlock(&hevc->lock); -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t codec_hevc_isr(struct amvdec_session *sess) -+{ -+ return IRQ_WAKE_THREAD; -+} -+ -+struct amvdec_codec_ops codec_hevc_ops = { -+ .start = codec_hevc_start, -+ .stop = codec_hevc_stop, -+ .isr = codec_hevc_isr, -+ .threaded_isr = codec_hevc_threaded_isr, -+ .num_pending_bufs = codec_hevc_num_pending_bufs, -+ .drain = codec_hevc_flush_output, -+ .resume = codec_hevc_resume, -+}; -diff --git a/drivers/media/platform/meson/vdec/codec_hevc.h b/drivers/media/platform/meson/vdec/codec_hevc.h -new file mode 100644 -index 0000000000000..5017e874e3ddc ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_hevc.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CODEC_HEVC_H_ -+#define __MESON_VDEC_CODEC_HEVC_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_codec_ops codec_hevc_ops; -+ -+#endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h -new file mode 100644 -index 0000000000000..ba49f906be5a9 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/hevc_regs.h -@@ -0,0 +1,205 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. -+ */ -+ -+#ifndef __MESON_VDEC_HEVC_REGS_H_ -+#define __MESON_VDEC_HEVC_REGS_H_ -+ -+#define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4 -+#define HEVC_ASSIST_MBOX1_MASK 0xc1d8 -+ -+#define HEVC_ASSIST_SCRATCH_0 0xc300 -+#define HEVC_ASSIST_SCRATCH_1 0xc304 -+#define HEVC_ASSIST_SCRATCH_2 0xc308 -+#define HEVC_ASSIST_SCRATCH_3 0xc30c -+#define HEVC_ASSIST_SCRATCH_4 0xc310 -+#define HEVC_ASSIST_SCRATCH_5 0xc314 -+#define HEVC_ASSIST_SCRATCH_6 0xc318 -+#define HEVC_ASSIST_SCRATCH_7 0xc31c -+#define HEVC_ASSIST_SCRATCH_8 0xc320 -+#define HEVC_ASSIST_SCRATCH_9 0xc324 -+#define HEVC_ASSIST_SCRATCH_A 0xc328 -+#define HEVC_ASSIST_SCRATCH_B 0xc32c -+#define HEVC_ASSIST_SCRATCH_C 0xc330 -+#define HEVC_ASSIST_SCRATCH_D 0xc334 -+#define HEVC_ASSIST_SCRATCH_E 0xc338 -+#define HEVC_ASSIST_SCRATCH_F 0xc33c -+#define HEVC_ASSIST_SCRATCH_G 0xc340 -+#define HEVC_ASSIST_SCRATCH_H 0xc344 -+#define HEVC_ASSIST_SCRATCH_I 0xc348 -+#define HEVC_ASSIST_SCRATCH_J 0xc34c -+#define HEVC_ASSIST_SCRATCH_K 0xc350 -+#define HEVC_ASSIST_SCRATCH_L 0xc354 -+#define HEVC_ASSIST_SCRATCH_M 0xc358 -+#define HEVC_ASSIST_SCRATCH_N 0xc35c -+ -+#define HEVC_PARSER_VERSION 0xc400 -+#define HEVC_STREAM_CONTROL 0xc404 -+#define HEVC_STREAM_START_ADDR 0xc408 -+#define HEVC_STREAM_END_ADDR 0xc40c -+#define HEVC_STREAM_WR_PTR 0xc410 -+#define HEVC_STREAM_RD_PTR 0xc414 -+#define HEVC_STREAM_LEVEL 0xc418 -+#define HEVC_STREAM_FIFO_CTL 0xc41c -+#define HEVC_SHIFT_CONTROL 0xc420 -+#define HEVC_SHIFT_STARTCODE 0xc424 -+#define HEVC_SHIFT_EMULATECODE 0xc428 -+#define HEVC_SHIFT_STATUS 0xc42c -+#define HEVC_SHIFTED_DATA 0xc430 -+#define HEVC_SHIFT_BYTE_COUNT 0xc434 -+#define HEVC_SHIFT_COMMAND 0xc438 -+#define HEVC_ELEMENT_RESULT 0xc43c -+#define HEVC_CABAC_CONTROL 0xc440 -+#define HEVC_PARSER_SLICE_INFO 0xc444 -+#define HEVC_PARSER_CMD_WRITE 0xc448 -+#define HEVC_PARSER_CORE_CONTROL 0xc44c -+#define HEVC_PARSER_CMD_FETCH 0xc450 -+#define HEVC_PARSER_CMD_STATUS 0xc454 -+#define HEVC_PARSER_LCU_INFO 0xc458 -+#define HEVC_PARSER_HEADER_INFO 0xc45c -+#define HEVC_PARSER_INT_CONTROL 0xc480 -+#define HEVC_PARSER_INT_STATUS 0xc484 -+#define HEVC_PARSER_IF_CONTROL 0xc488 -+#define HEVC_PARSER_PICTURE_SIZE 0xc48c -+#define HEVC_PARSER_LCU_START 0xc490 -+#define HEVC_PARSER_HEADER_INFO2 0xc494 -+#define HEVC_PARSER_QUANT_READ 0xc498 -+#define HEVC_PARSER_RESERVED_27 0xc49c -+#define HEVC_PARSER_CMD_SKIP_0 0xc4a0 -+#define HEVC_PARSER_CMD_SKIP_1 0xc4a4 -+#define HEVC_PARSER_CMD_SKIP_2 0xc4a8 -+#define HEVC_SAO_IF_STATUS 0xc4c0 -+#define HEVC_SAO_IF_DATA_Y 0xc4c4 -+#define HEVC_SAO_IF_DATA_U 0xc4c8 -+#define HEVC_SAO_IF_DATA_V 0xc4cc -+#define HEVC_STREAM_SWAP_ADDR 0xc4d0 -+#define HEVC_STREAM_SWAP_CTRL 0xc4d4 -+#define HEVC_IQIT_IF_WAIT_CNT 0xc4d8 -+#define HEVC_MPRED_IF_WAIT_CNT 0xc4dc -+#define HEVC_SAO_IF_WAIT_CNT 0xc4e0 -+ -+#define HEVC_MPRED_VERSION 0xc800 -+#define HEVC_MPRED_CTRL0 0xc804 -+ #define MPRED_CTRL0_NEW_PIC BIT(2) -+ #define MPRED_CTRL0_NEW_TILE BIT(3) -+ #define MPRED_CTRL0_NEW_SLI_SEG BIT(4) -+ #define MPRED_CTRL0_TMVP BIT(5) -+ #define MPRED_CTRL0_LDC BIT(6) -+ #define MPRED_CTRL0_COL_FROM_L0 BIT(7) -+ #define MPRED_CTRL0_ABOVE_EN BIT(9) -+ #define MPRED_CTRL0_MV_WR_EN BIT(10) -+ #define MPRED_CTRL0_MV_RD_EN BIT(11) -+ #define MPRED_CTRL0_BUF_LINEAR BIT(13) -+#define HEVC_MPRED_CTRL1 0xc808 -+#define HEVC_MPRED_INT_EN 0xc80c -+#define HEVC_MPRED_INT_STATUS 0xc810 -+#define HEVC_MPRED_PIC_SIZE 0xc814 -+#define HEVC_MPRED_PIC_SIZE_LCU 0xc818 -+#define HEVC_MPRED_TILE_START 0xc81c -+#define HEVC_MPRED_TILE_SIZE_LCU 0xc820 -+#define HEVC_MPRED_REF_NUM 0xc824 -+#define HEVC_MPRED_REF_EN_L0 0xc830 -+#define HEVC_MPRED_REF_EN_L1 0xc834 -+#define HEVC_MPRED_COLREF_EN_L0 0xc838 -+#define HEVC_MPRED_COLREF_EN_L1 0xc83c -+#define HEVC_MPRED_AXI_WCTRL 0xc840 -+#define HEVC_MPRED_AXI_RCTRL 0xc844 -+#define HEVC_MPRED_ABV_START_ADDR 0xc848 -+#define HEVC_MPRED_MV_WR_START_ADDR 0xc84c -+#define HEVC_MPRED_MV_RD_START_ADDR 0xc850 -+#define HEVC_MPRED_MV_WPTR 0xc854 -+#define HEVC_MPRED_MV_RPTR 0xc858 -+#define HEVC_MPRED_MV_WR_ROW_JUMP 0xc85c -+#define HEVC_MPRED_MV_RD_ROW_JUMP 0xc860 -+#define HEVC_MPRED_CURR_LCU 0xc864 -+#define HEVC_MPRED_ABV_WPTR 0xc868 -+#define HEVC_MPRED_ABV_RPTR 0xc86c -+#define HEVC_MPRED_CTRL2 0xc870 -+#define HEVC_MPRED_CTRL3 0xc874 -+#define HEVC_MPRED_L0_REF00_POC 0xc880 -+#define HEVC_MPRED_L1_REF00_POC 0xc8c0 -+ -+#define HEVC_MPRED_CUR_POC 0xc980 -+#define HEVC_MPRED_COL_POC 0xc984 -+#define HEVC_MPRED_MV_RD_END_ADDR 0xc988 -+ -+#define HEVC_MSP 0xcc00 -+#define HEVC_MPSR 0xcc04 -+#define HEVC_MCPU_INTR_MSK 0xcc10 -+#define HEVC_MCPU_INTR_REQ 0xcc14 -+#define HEVC_CPSR 0xcc84 -+ -+#define HEVC_IMEM_DMA_CTRL 0xcd00 -+#define HEVC_IMEM_DMA_ADR 0xcd04 -+#define HEVC_IMEM_DMA_COUNT 0xcd08 -+ -+#define HEVCD_IPP_TOP_CNTL 0xd000 -+#define HEVCD_IPP_LINEBUFF_BASE 0xd024 -+#define HEVCD_IPP_AXIIF_CONFIG 0xd02c -+ -+#define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180 -+#define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184 -+#define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190 -+ -+#define HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR 0xd300 -+#define HEVCD_MPP_ANC_CANVAS_DATA_ADDR 0xd304 -+#define HEVCD_MPP_DECOMP_CTL1 0xd308 -+#define HEVCD_MPP_DECOMP_CTL2 0xd30c -+#define HEVCD_MCRCC_CTL1 0xd3c0 -+#define HEVCD_MCRCC_CTL2 0xd3c4 -+#define HEVCD_MCRCC_CTL3 0xd3c8 -+ -+#define HEVC_DBLK_CFG0 0xd400 -+#define HEVC_DBLK_CFG1 0xd404 -+#define HEVC_DBLK_CFG2 0xd408 -+#define HEVC_DBLK_CFG3 0xd40c -+#define HEVC_DBLK_CFG4 0xd410 -+#define HEVC_DBLK_CFG5 0xd414 -+#define HEVC_DBLK_CFG6 0xd418 -+#define HEVC_DBLK_CFG7 0xd41c -+#define HEVC_DBLK_CFG8 0xd420 -+#define HEVC_DBLK_CFG9 0xd424 -+#define HEVC_DBLK_CFGA 0xd428 -+#define HEVC_DBLK_STS0 0xd42c -+#define HEVC_DBLK_STS1 0xd430 -+ -+#define HEVC_SAO_VERSION 0xd800 -+#define HEVC_SAO_CTRL0 0xd804 -+#define HEVC_SAO_CTRL1 0xd808 -+#define HEVC_SAO_PIC_SIZE 0xd814 -+#define HEVC_SAO_PIC_SIZE_LCU 0xd818 -+#define HEVC_SAO_TILE_START 0xd81c -+#define HEVC_SAO_TILE_SIZE_LCU 0xd820 -+#define HEVC_SAO_Y_START_ADDR 0xd82c -+#define HEVC_SAO_Y_LENGTH 0xd830 -+#define HEVC_SAO_C_START_ADDR 0xd834 -+#define HEVC_SAO_C_LENGTH 0xd838 -+#define HEVC_SAO_Y_WPTR 0xd83c -+#define HEVC_SAO_C_WPTR 0xd840 -+#define HEVC_SAO_ABV_START_ADDR 0xd844 -+#define HEVC_SAO_VB_WR_START_ADDR 0xd848 -+#define HEVC_SAO_VB_RD_START_ADDR 0xd84c -+#define HEVC_SAO_ABV_WPTR 0xd850 -+#define HEVC_SAO_ABV_RPTR 0xd854 -+#define HEVC_SAO_VB_WPTR 0xd858 -+#define HEVC_SAO_VB_RPTR 0xd85c -+#define HEVC_SAO_CTRL2 0xd880 -+#define HEVC_SAO_CTRL3 0xd884 -+#define HEVC_SAO_CTRL4 0xd888 -+#define HEVC_SAO_CTRL5 0xd88c -+#define HEVC_SAO_CTRL6 0xd890 -+#define HEVC_SAO_CTRL7 0xd894 -+#define HEVC_CM_BODY_START_ADDR 0xd898 -+#define HEVC_CM_BODY_LENGTH 0xd89c -+#define HEVC_CM_HEADER_LENGTH 0xd8a4 -+#define HEVC_CM_HEADER_OFFSET 0xd8ac -+ -+#define HEVC_IQIT_CLK_RST_CTRL 0xdc00 -+#define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08 -+#define HEVC_IQIT_SCALELUT_RD_ADDR 0xdc0c -+#define HEVC_IQIT_SCALELUT_DATA 0xdc10 -+ -+#define HEVC_PSCALE_CTRL 0xe444 -+ -+#endif -diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.c b/drivers/media/platform/meson/vdec/vdec_hevc.c -new file mode 100644 -index 0000000000000..8872f58d39fea ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_hevc.c -@@ -0,0 +1,191 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ * -+ * VDEC_HEVC is a video decoding block that allows decoding of -+ * HEVC, VP9 -+ */ -+ -+#include -+#include -+ -+#include "vdec_1.h" -+#include "vdec_helpers.h" -+#include "hevc_regs.h" -+#include "dos_regs.h" -+ -+/* AO Registers */ -+#define AO_RTI_GEN_PWR_SLEEP0 0xe8 -+#define AO_RTI_GEN_PWR_ISO0 0xec -+ #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6)) -+ -+#define MC_SIZE (4096 * 4) -+ -+static int vdec_hevc_load_firmware(struct amvdec_session *sess, const char* fwname) -+{ -+ struct amvdec_core *core = sess->core; -+ struct device *dev = core->dev_dec; -+ const struct firmware *fw; -+ static void *mc_addr; -+ static dma_addr_t mc_addr_map; -+ int ret; -+ u32 i = 100; -+ -+ ret = request_firmware(&fw, fwname, dev); -+ if (ret < 0) { -+ dev_err(dev, "Unable to request firmware %s\n", fwname); -+ return ret; -+ } -+ -+ if (fw->size < MC_SIZE) { -+ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", -+ fw->size, MC_SIZE); -+ ret = -EINVAL; -+ goto release_firmware; -+ } -+ -+ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map, GFP_KERNEL); -+ if (!mc_addr) { -+ dev_err(dev, "Failed allocating memory for firmware loading\n"); -+ ret = -ENOMEM; -+ goto release_firmware; -+ } -+ -+ memcpy(mc_addr, fw->data, MC_SIZE); -+ -+ amvdec_write_dos(core, HEVC_MPSR, 0); -+ amvdec_write_dos(core, HEVC_CPSR, 0); -+ -+ amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map); -+ amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4); -+ amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); -+ -+ while (--i && readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000) { } -+ -+ if (i == 0) { -+ dev_err(dev, "Firmware load fail (DMA hang?)\n"); -+ ret = -ENODEV; -+ } -+ -+ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); -+release_firmware: -+ release_firmware(fw); -+ return ret; -+} -+ -+static void vdec_hevc_stbuf_init(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1); -+ amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr); -+ amvdec_write_dos(core, HEVC_STREAM_END_ADDR, sess->vififo_paddr + sess->vififo_size); -+ amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr); -+ amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr); -+} -+ -+/* VDEC_HEVC specific ESPARSER configuration */ -+static void vdec_hevc_conf_esparser(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ -+ /* set vififo_vbuf_rp_sel=>vdec_hevc */ -+ amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1); -+ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3)); -+ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1); -+ amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL, amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29)); -+} -+ -+static u32 vdec_hevc_vififo_level(struct amvdec_session *sess) -+{ -+ return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL); -+} -+ -+static int vdec_hevc_stop(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ -+ /* Disable interrupt */ -+ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0); -+ /* Disable firmware processor */ -+ amvdec_write_dos(core, HEVC_MPSR, 0); -+ -+ if (sess->priv) -+ codec_ops->stop(sess); -+ -+ /* Enable VDEC_HEVC Isolation */ -+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0xc00); -+ -+ /* VDEC_HEVC Memories */ -+ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL); -+ -+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); -+ -+ clk_disable_unprepare(core->vdec_hevc_clk); -+ -+ return 0; -+} -+ -+static int vdec_hevc_start(struct amvdec_session *sess) -+{ -+ int ret; -+ struct amvdec_core *core = sess->core; -+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; -+ -+ clk_set_rate(core->vdec_hevc_clk, 666666666); -+ ret = clk_prepare_enable(core->vdec_hevc_clk); -+ if (ret) -+ return ret; -+ -+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, -+ GEN_PWR_VDEC_HEVC, 0); -+ udelay(10); -+ -+ /* Reset VDEC_HEVC*/ -+ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); -+ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); -+ -+ amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff); -+ -+ /* VDEC_HEVC Memories */ -+ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000); -+ -+ /* Remove VDEC_HEVC Isolation */ -+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0); -+ -+ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); -+ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); -+ -+ vdec_hevc_stbuf_init(sess); -+ -+ ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path); -+ if (ret) -+ goto stop; -+ -+ ret = codec_ops->start(sess); -+ if (ret) -+ goto stop; -+ -+ amvdec_write_dos(core, DOS_SW_RESET3, BIT(12)|BIT(11)); -+ amvdec_write_dos(core, DOS_SW_RESET3, 0); -+ amvdec_read_dos(core, DOS_SW_RESET3); -+ -+ amvdec_write_dos(core, HEVC_MPSR, 1); -+ /* Let the firmware settle */ -+ udelay(10); -+ -+ return 0; -+ -+stop: -+ vdec_hevc_stop(sess); -+ return ret; -+} -+ -+struct amvdec_ops vdec_hevc_ops = { -+ .start = vdec_hevc_start, -+ .stop = vdec_hevc_stop, -+ .conf_esparser = vdec_hevc_conf_esparser, -+ .vififo_level = vdec_hevc_vififo_level, -+}; -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.h b/drivers/media/platform/meson/vdec/vdec_hevc.h -new file mode 100644 -index 0000000000000..f1ccad7d5f949 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/vdec_hevc.h -@@ -0,0 +1,22 @@ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * 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 __MESON_VDEC_VDEC_HEVC_H_ -+#define __MESON_VDEC_VDEC_HEVC_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_ops vdec_hevc_ops; -+ -+#endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c -index 9cf978e9050d3..8a76518cdcde7 100644 ---- a/drivers/media/platform/meson/vdec/vdec_platform.c -+++ b/drivers/media/platform/meson/vdec/vdec_platform.c -@@ -8,13 +8,25 @@ - #include "vdec.h" - - #include "vdec_1.h" -+#include "vdec_hevc.h" - #include "codec_mpeg12.h" - #include "codec_h264.h" - #include "codec_mpeg4.h" - #include "codec_mjpeg.h" -+#include "codec_hevc.h" - - static const struct amvdec_format vdec_formats_gxbb[] = { - { -+ .pixfmt = V4L2_PIX_FMT_HEVC, -+ .min_buffers = 16, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_hevc_ops, -+ .codec_ops = &codec_hevc_ops, -+ .firmware_path = "meson/gx/vh265_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MJPEG, - .min_buffers = 4, - .max_buffers = 4, -@@ -91,6 +103,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { - - static const struct amvdec_format vdec_formats_gxl[] = { - { -+ .pixfmt = V4L2_PIX_FMT_HEVC, -+ .min_buffers = 16, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_hevc_ops, -+ .codec_ops = &codec_hevc_ops, -+ .firmware_path = "meson/gx/vh265_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MJPEG, - .min_buffers = 4, - .max_buffers = 4, -@@ -167,6 +189,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { - - static const struct amvdec_format vdec_formats_gxm[] = { - { -+ .pixfmt = V4L2_PIX_FMT_HEVC, -+ .min_buffers = 16, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_hevc_ops, -+ .codec_ops = &codec_hevc_ops, -+ .firmware_path = "meson/gx/vh265_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, -+ }, { - .pixfmt = V4L2_PIX_FMT_MJPEG, - .min_buffers = 4, - .max_buffers = 4, - -From e7ad26a92d8e44a13848a89830ec6f264cd9d5be Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Mon, 3 Dec 2018 10:25:00 +0100 -Subject: [PATCH 216/249] WIP: meson: vdec: Map the Firmware buf idx <-> VB2 - buf idx - -The current code assumes the vb2 indexes are in order (0 -> n) when -iterating over them. This is very wrong and, in the case where they are -not in the perfect order, will generate mismatches between the firmware -internal buffer indexes and the VB2 ones. - -This fixes this bad assumption by explicitely mapping the buffer index. ---- - drivers/media/platform/meson/vdec/vdec.h | 1 + - drivers/media/platform/meson/vdec/vdec_helpers.c | 7 ++++++- - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h -index 9f1e307057220..6597e26cc855e 100644 ---- a/drivers/media/platform/meson/vdec/vdec.h -+++ b/drivers/media/platform/meson/vdec/vdec.h -@@ -255,6 +255,7 @@ struct amvdec_session { - u32 last_offset; - u32 wrap_count; - u32 dpb_size; -+ u32 fw_idx_to_vb2_idx[32]; - - enum amvdec_status status; - void *priv; -diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c -index 7bb7a6dad5874..0c233fd3b77d1 100644 ---- a/drivers/media/platform/meson/vdec/vdec_helpers.c -+++ b/drivers/media/platform/meson/vdec/vdec_helpers.c -@@ -186,6 +186,7 @@ int amvdec_set_canvases(struct amvdec_session *sess, - u32 reg_cur = reg_base[0]; - u32 reg_num_cur = 0; - u32 reg_base_cur = 0; -+ int i = 0; - int ret; - - v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -@@ -218,6 +219,8 @@ int amvdec_set_canvases(struct amvdec_session *sess, - reg_base_cur++; - reg_num_cur = 0; - } -+ -+ sess->fw_idx_to_vb2_idx[i++] = buf->vb.vb2_buf.index; - } - - return 0; -@@ -409,7 +412,9 @@ void amvdec_dst_buf_done_idx(struct amvdec_session *sess, - struct vb2_v4l2_buffer *vbuf; - struct device *dev = sess->core->dev_dec; - -- vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, buf_idx); -+ vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, -+ sess->fw_idx_to_vb2_idx[buf_idx]); -+ - if (!vbuf) { - dev_err(dev, - "Buffer %u done but it doesn't exist in m2m_ctx\n", - -From 3a03e68b4abd1676af681a4986b68ad05de1450d Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Thu, 17 Jan 2019 16:58:29 +0100 -Subject: [PATCH 217/249] WIP: media: meson: vdec: commonize some HEVC code - -Will be shared with the VP9 codebase. ---- - drivers/media/platform/meson/vdec/Makefile | 2 +- - .../media/platform/meson/vdec/codec_hevc.c | 239 ++---------------- - .../platform/meson/vdec/codec_hevc_common.c | 188 ++++++++++++++ - .../platform/meson/vdec/codec_hevc_common.h | 49 ++++ - drivers/media/platform/meson/vdec/vdec.h | 7 +- - 5 files changed, 260 insertions(+), 225 deletions(-) - create mode 100644 drivers/media/platform/meson/vdec/codec_hevc_common.c - create mode 100644 drivers/media/platform/meson/vdec/codec_hevc_common.h - -diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile -index ddcf38a7c3e65..4fba9e052f14f 100644 ---- a/drivers/media/platform/meson/vdec/Makefile -+++ b/drivers/media/platform/meson/vdec/Makefile -@@ -3,6 +3,6 @@ - - meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o - meson-vdec-objs += vdec_1.o vdec_hevc.o --meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc.o -+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o - - obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o -diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c -index 116e9ffc4560d..03f00f969f025 100644 ---- a/drivers/media/platform/meson/vdec/codec_hevc.c -+++ b/drivers/media/platform/meson/vdec/codec_hevc.c -@@ -1,6 +1,6 @@ - // SPDX-License-Identifier: GPL-2.0+ - /* -- * Copyright (C) 2018 Maxime Jourdan -+ * Copyright (C) 2018 Maxime Jourdan - * Copyright (C) 2015 Amlogic, Inc. All rights reserved. - */ - -@@ -11,6 +11,7 @@ - #include "dos_regs.h" - #include "hevc_regs.h" - #include "vdec_helpers.h" -+#include "codec_hevc_common.h" - - /* HEVC reg mapping */ - #define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 -@@ -135,22 +136,6 @@ - #define RPM_SIZE 0x80 - #define RPS_USED_BIT 14 - --#define PARSER_CMD_SKIP_CFG_0 0x0000090b --#define PARSER_CMD_SKIP_CFG_1 0x1b14140f --#define PARSER_CMD_SKIP_CFG_2 0x001b1910 --static const u16 parser_cmd[] = { -- 0x0401, 0x8401, 0x0800, 0x0402, -- 0x9002, 0x1423, 0x8CC3, 0x1423, -- 0x8804, 0x9825, 0x0800, 0x04FE, -- 0x8406, 0x8411, 0x1800, 0x8408, -- 0x8409, 0x8C2A, 0x9C2B, 0x1C00, -- 0x840F, 0x8407, 0x8000, 0x8408, -- 0x2000, 0xA800, 0x8410, 0x04DE, -- 0x840C, 0x840D, 0xAC00, 0xA000, -- 0x08C0, 0x08E0, 0xA40E, 0xFC00, -- 0x7C00 --}; -- - /* Data received from the HW in this form, do not rearrange */ - union rpm_param { - struct { -@@ -289,28 +274,8 @@ struct codec_hevc { - - /* Whether we detected the bitstream as 10-bit */ - int is_10bit; -- -- /* In case of downsampling (decoding with FBC but outputting in NV12M), -- * we need to allocate additional buffers for FBC. -- */ -- void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; -- dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; - }; - --/* Returns 1 if we must use framebuffer compression */ --static int codec_hevc_use_fbc(struct amvdec_session *sess) --{ -- struct codec_hevc *hevc = sess->priv; -- return sess->pixfmt_cap == V4L2_PIX_FMT_AM21C || hevc->is_10bit; --} -- --/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ --static int codec_hevc_use_downsample(struct amvdec_session *sess) --{ -- struct codec_hevc *hevc = sess->priv; -- return sess->pixfmt_cap == V4L2_PIX_FMT_NV12M && hevc->is_10bit; --} -- - static u32 codec_hevc_num_pending_bufs(struct amvdec_session *sess) - { - struct codec_hevc *hevc; -@@ -526,181 +491,6 @@ static void codec_hevc_output_frames(struct amvdec_session *sess) - } - } - --/* Configure decode head read mode */ --static void codec_hevc_setup_decode_head(struct amvdec_session *sess) --{ -- struct amvdec_core *core = sess->core; -- u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); -- u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); -- -- if (!codec_hevc_use_fbc(sess)) { -- /* Enable 2-plane reference read mode */ -- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); -- return; -- } -- -- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); -- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); -- amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); -- amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); -- amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); --} -- --static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess) --{ -- struct amvdec_core *core = sess->core; -- struct codec_hevc *hevc = sess->priv; -- struct v4l2_m2m_buffer *buf; -- u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -- dma_addr_t buf_y_paddr = 0; -- dma_addr_t buf_uv_paddr = 0; -- u32 idx = 0; -- u32 val; -- int i; -- -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); -- -- v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -- idx = buf->vb.vb2_buf.index; -- -- if (codec_hevc_use_downsample(sess)) -- buf_y_paddr = hevc->fbc_buffer_paddr[idx]; -- else -- buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -- -- if (codec_hevc_use_fbc(sess)) { -- val = buf_y_paddr | (idx << 8) | 1; -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -- } else { -- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -- val = buf_y_paddr | ((idx * 2) << 8) | 1; -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -- val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -- } -- } -- -- if (codec_hevc_use_fbc(sess)) -- val = buf_y_paddr | (idx << 8) | 1; -- else -- val = buf_y_paddr | ((idx * 2) << 8) | 1; -- -- /* Fill the remaining unused slots with the last buffer's Y addr */ -- for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -- -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); -- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -- for (i = 0; i < 32; ++i) -- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); --} -- --static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess) --{ -- struct amvdec_core *core = sess->core; -- struct codec_hevc *hevc = sess->priv; -- struct v4l2_m2m_buffer *buf; -- u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -- dma_addr_t buf_y_paddr = 0; -- dma_addr_t buf_uv_paddr = 0; -- int i; -- -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, -- BIT(2) | BIT(1)); -- -- v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -- u32 idx = buf->vb.vb2_buf.index; -- -- if (codec_hevc_use_downsample(sess)) -- buf_y_paddr = hevc->fbc_buffer_paddr[idx]; -- else -- buf_y_paddr = -- vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -- -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -- buf_y_paddr >> 5); -- if (!codec_hevc_use_fbc(sess)) { -- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -- buf_uv_paddr >> 5); -- } -- } -- -- /* Fill the remaining unused slots with the last buffer's Y addr */ -- for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -- buf_y_paddr >> 5); -- if (!codec_hevc_use_fbc(sess)) -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -- buf_uv_paddr >> 5); -- } -- -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); -- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -- for (i = 0; i < 32; ++i) -- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); --} -- --static void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) --{ -- struct codec_hevc *hevc = sess->priv; -- struct device *dev = sess->core->dev; -- u32 am21_size = amvdec_am21c_size(sess->width, sess->height); -- int i; -- -- for (i = 0; i < MAX_REF_PIC_NUM; ++i) { -- if (hevc->fbc_buffer_vaddr[i]) { -- dma_free_coherent(dev, am21_size, -- hevc->fbc_buffer_vaddr[i], -- hevc->fbc_buffer_paddr[i]); -- hevc->fbc_buffer_vaddr[i] = NULL; -- } -- } --} -- --static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) --{ -- struct codec_hevc *hevc = sess->priv; -- struct device *dev = sess->core->dev; -- struct v4l2_m2m_buffer *buf; -- u32 am21_size = amvdec_am21c_size(sess->width, sess->height); -- -- v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -- u32 idx = buf->vb.vb2_buf.index; -- dma_addr_t paddr; -- void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, -- GFP_KERNEL); -- if (!vaddr) { -- dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); -- codec_hevc_free_fbc_buffers(sess); -- return -ENOMEM; -- } -- -- hevc->fbc_buffer_vaddr[idx] = vaddr; -- hevc->fbc_buffer_paddr[idx] = paddr; -- } -- -- return 0; --} -- --static int codec_hevc_setup_buffers(struct amvdec_session *sess) --{ -- struct amvdec_core *core = sess->core; -- int ret; -- -- if (codec_hevc_use_downsample(sess)) { -- ret = codec_hevc_alloc_fbc_buffers(sess); -- if (ret) -- return ret; -- } -- -- if (core->platform->revision == VDEC_REVISION_GXBB) -- codec_hevc_setup_buffers_gxbb(sess); -- else -- codec_hevc_setup_buffers_gxl(sess); -- -- return 0; --} - - static int - codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) -@@ -776,8 +566,9 @@ static int codec_hevc_start(struct amvdec_session *sess) - amvdec_write_dos(core, HEVC_DECODE_SIZE, 0); - - amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); -- for (i = 0; i < ARRAY_SIZE(parser_cmd); ++i) -- amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, parser_cmd[i]); -+ for (i = 0; i < ARRAY_SIZE(vdec_hevc_parser_cmd); ++i) -+ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, -+ vdec_hevc_parser_cmd[i]); - - amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); - amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); -@@ -934,14 +725,14 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) - amvdec_write_dos(core, HEVC_SAO_PIC_SIZE_LCU, - (hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); - -- if (codec_hevc_use_downsample(sess)) -+ if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit)) - buf_y_paddr = -- hevc->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; -+ sess->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; - else - buf_y_paddr = - vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); - -- if (codec_hevc_use_fbc(sess)) { -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { - val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; - amvdec_write_dos(core, HEVC_SAO_CTRL5, val); - amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); -@@ -979,14 +770,14 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) - - val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; - val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ -- if (!codec_hevc_use_fbc(sess)) -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) - val |= BIT(0); /* disable cm compression */ - else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) - val |= BIT(1); /* Disable double write */ - - amvdec_write_dos(core, HEVC_SAO_CTRL1, val); - -- if (!codec_hevc_use_fbc(sess)) { -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { - /* no downscale for NV12 */ - val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; - amvdec_write_dos(core, HEVC_SAO_CTRL5, val); -@@ -1195,7 +986,7 @@ static void codec_hevc_set_mcrcc(struct amvdec_session *sess) - int l0_cnt = 0; - int l1_cnt = 0x7fff; - -- if (!codec_hevc_use_fbc(sess)) { -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { - l0_cnt = hevc->cur_frame->ref_num[0]; - l1_cnt = hevc->cur_frame->ref_num[1]; - } -@@ -1266,7 +1057,7 @@ static void codec_hevc_set_ref_list(struct amvdec_session *sess, - continue; - } - -- if (codec_hevc_use_fbc(sess)) { -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { - buf_id_y = buf_id_uv = ref_frame->vbuf->vb2_buf.index; - } else { - buf_id_y = ref_frame->vbuf->vb2_buf.index * 2; -@@ -1504,12 +1295,14 @@ static void codec_hevc_fetch_rpm(struct amvdec_session *sess) - - static void codec_hevc_resume(struct amvdec_session *sess) - { -- if (codec_hevc_setup_buffers(sess)) { -+ struct codec_hevc *hevc = sess->priv; -+ -+ if (codec_hevc_setup_buffers(sess, hevc->is_10bit)) { - amvdec_abort(sess); - return; - } - -- codec_hevc_setup_decode_head(sess); -+ codec_hevc_setup_decode_head(sess, hevc->is_10bit); - codec_hevc_process_segment_header(sess); - if (codec_hevc_process_segment(sess)) - amvdec_abort(sess); -diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.c b/drivers/media/platform/meson/vdec/codec_hevc_common.c -new file mode 100644 -index 0000000000000..2b296beb5d88a ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_hevc_common.c -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#include -+#include -+ -+#include "codec_hevc_common.h" -+#include "vdec_helpers.h" -+#include "hevc_regs.h" -+ -+/* Configure decode head read mode */ -+void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); -+ u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); -+ -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { -+ /* Enable 2-plane reference read mode */ -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); -+ return; -+ } -+ -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); -+ amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); -+ amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); -+ amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); -+} -+EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); -+ -+static void -+codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) -+{ -+ struct amvdec_core *core = sess->core; -+ struct v4l2_m2m_buffer *buf; -+ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -+ dma_addr_t buf_y_paddr = 0; -+ dma_addr_t buf_uv_paddr = 0; -+ u32 idx = 0; -+ u32 val; -+ int i; -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ idx = buf->vb.vb2_buf.index; -+ -+ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) -+ buf_y_paddr = sess->fbc_buffer_paddr[idx]; -+ else -+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -+ -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { -+ val = buf_y_paddr | (idx << 8) | 1; -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ } else { -+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -+ val = buf_y_paddr | ((idx * 2) << 8) | 1; -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ } -+ } -+ -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) -+ val = buf_y_paddr | (idx << 8) | 1; -+ else -+ val = buf_y_paddr | ((idx * 2) << 8) | 1; -+ -+ /* Fill the remaining unused slots with the last buffer's Y addr */ -+ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -+ for (i = 0; i < 32; ++i) -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); -+} -+ -+static void -+codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) -+{ -+ struct amvdec_core *core = sess->core; -+ struct v4l2_m2m_buffer *buf; -+ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -+ dma_addr_t buf_y_paddr = 0; -+ dma_addr_t buf_uv_paddr = 0; -+ int i; -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, -+ BIT(2) | BIT(1)); -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ u32 idx = buf->vb.vb2_buf.index; -+ -+ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) -+ buf_y_paddr = sess->fbc_buffer_paddr[idx]; -+ else -+ buf_y_paddr = -+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_y_paddr >> 5); -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { -+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_uv_paddr >> 5); -+ } -+ } -+ -+ /* Fill the remaining unused slots with the last buffer's Y addr */ -+ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_y_paddr >> 5); -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -+ buf_uv_paddr >> 5); -+ } -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -+ for (i = 0; i < 32; ++i) -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); -+} -+ -+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) -+{ -+ struct device *dev = sess->core->dev; -+ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); -+ int i; -+ -+ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { -+ if (sess->fbc_buffer_vaddr[i]) { -+ dma_free_coherent(dev, am21_size, -+ sess->fbc_buffer_vaddr[i], -+ sess->fbc_buffer_paddr[i]); -+ sess->fbc_buffer_vaddr[i] = NULL; -+ } -+ } -+} -+EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); -+ -+static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) -+{ -+ struct device *dev = sess->core->dev; -+ struct v4l2_m2m_buffer *buf; -+ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ u32 idx = buf->vb.vb2_buf.index; -+ dma_addr_t paddr; -+ void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, -+ GFP_KERNEL); -+ if (!vaddr) { -+ dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); -+ codec_hevc_free_fbc_buffers(sess); -+ return -ENOMEM; -+ } -+ -+ sess->fbc_buffer_vaddr[idx] = vaddr; -+ sess->fbc_buffer_paddr[idx] = paddr; -+ } -+ -+ return 0; -+} -+ -+int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit) -+{ -+ struct amvdec_core *core = sess->core; -+ int ret; -+ -+ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) { -+ ret = codec_hevc_alloc_fbc_buffers(sess); -+ if (ret) -+ return ret; -+ } -+ -+ if (core->platform->revision == VDEC_REVISION_GXBB) -+ codec_hevc_setup_buffers_gxbb(sess, is_10bit); -+ else -+ codec_hevc_setup_buffers_gxl(sess, is_10bit); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.h b/drivers/media/platform/meson/vdec/codec_hevc_common.h -new file mode 100644 -index 0000000000000..96493f9fe6995 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_hevc_common.h -@@ -0,0 +1,49 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 BayLibre, SAS -+ * Author: Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_HEVC_COMMON_H_ -+#define __MESON_VDEC_HEVC_COMMON_H_ -+ -+#include "vdec.h" -+ -+#define PARSER_CMD_SKIP_CFG_0 0x0000090b -+#define PARSER_CMD_SKIP_CFG_1 0x1b14140f -+#define PARSER_CMD_SKIP_CFG_2 0x001b1910 -+static const u16 vdec_hevc_parser_cmd[] = { -+ 0x0401, 0x8401, 0x0800, 0x0402, -+ 0x9002, 0x1423, 0x8CC3, 0x1423, -+ 0x8804, 0x9825, 0x0800, 0x04FE, -+ 0x8406, 0x8411, 0x1800, 0x8408, -+ 0x8409, 0x8C2A, 0x9C2B, 0x1C00, -+ 0x840F, 0x8407, 0x8000, 0x8408, -+ 0x2000, 0xA800, 0x8410, 0x04DE, -+ 0x840C, 0x840D, 0xAC00, 0xA000, -+ 0x08C0, 0x08E0, 0xA40E, 0xFC00, -+ 0x7C00 -+}; -+ -+/* Returns 1 if we must use framebuffer compression */ -+static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit) -+{ -+ return pixfmt == V4L2_PIX_FMT_AM21C || is_10bit; -+} -+ -+/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ -+static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit) -+{ -+ return pixfmt == V4L2_PIX_FMT_NV12M && is_10bit; -+} -+ -+/** -+ * Configure decode head read mode -+ */ -+void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit); -+ -+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess); -+ -+int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit); -+ -+#endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h -index 6597e26cc855e..885777e48142a 100644 ---- a/drivers/media/platform/meson/vdec/vdec.h -+++ b/drivers/media/platform/meson/vdec/vdec.h -@@ -17,7 +17,9 @@ - #include "vdec_platform.h" - - /* 32 buffers in 3-plane YUV420 */ --#define MAX_CANVAS (32 * 3) -+#define MAX_CANVAS (32 * 3) -+ -+#define MAX_REF_PIC_NUM 24 - - struct amvdec_buffer { - struct list_head list; -@@ -257,6 +259,9 @@ struct amvdec_session { - u32 dpb_size; - u32 fw_idx_to_vb2_idx[32]; - -+ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; -+ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; -+ - enum amvdec_status status; - void *priv; - }; - -From dd53ac3d055fccf7652483eacb5bf9e6e6a9602c Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Thu, 17 Jan 2019 16:59:11 +0100 -Subject: [PATCH 218/249] WIP: media: meson: vdec: add VP9 input support - -Amlogic VP9 decoder requires an additional 16-byte payload before every -frame header. ---- - drivers/media/platform/meson/vdec/esparser.c | 101 ++++++++++++++++++- - 1 file changed, 97 insertions(+), 4 deletions(-) - -diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c -index 24e08b01c88a1..d7ac51e08730d 100644 ---- a/drivers/media/platform/meson/vdec/esparser.c -+++ b/drivers/media/platform/meson/vdec/esparser.c -@@ -51,6 +51,7 @@ - #define PARSER_VIDEO_HOLE 0x90 - - #define SEARCH_PATTERN_LEN 512 -+#define VP9_HEADER_SIZE 16 - - static DECLARE_WAIT_QUEUE_HEAD(wq); - static int search_done; -@@ -73,14 +74,103 @@ static irqreturn_t esparser_isr(int irq, void *dev) - return IRQ_HANDLED; - } - -+/** -+ * VP9 frame headers need to be appended by a 16-byte long -+ * Amlogic custom header -+ */ -+static int vp9_update_header(struct vb2_buffer *buf) -+{ -+ uint8_t *dp; -+ uint8_t marker; -+ int dsize; -+ int num_frames, cur_frame; -+ int cur_mag, mag, mag_ptr; -+ int frame_size[8], tot_frame_size[8]; -+ int total_datasize = 0; -+ int new_frame_size; -+ unsigned char *old_header = NULL; -+ -+ dp = (uint8_t *) vb2_plane_vaddr(buf, 0); -+ dsize = vb2_get_plane_payload(buf, 0); -+ -+ marker = dp[dsize - 1]; -+ if ((marker & 0xe0) == 0xc0) { -+ num_frames = (marker & 0x7) + 1; -+ mag = ((marker >> 3) & 0x3) + 1; -+ mag_ptr = dsize - mag * num_frames - 2; -+ if (dp[mag_ptr] != marker) { -+ return 0; -+ } -+ mag_ptr++; -+ for (cur_frame = 0; cur_frame < num_frames; cur_frame++) { -+ frame_size[cur_frame] = 0; -+ for (cur_mag = 0; cur_mag < mag; cur_mag++) { -+ frame_size[cur_frame] |= (dp[mag_ptr] << (cur_mag * 8)); -+ mag_ptr++; -+ } -+ if (cur_frame == 0) -+ tot_frame_size[cur_frame] = frame_size[cur_frame]; -+ else -+ tot_frame_size[cur_frame] = tot_frame_size[cur_frame - 1] + frame_size[cur_frame]; -+ total_datasize += frame_size[cur_frame]; -+ } -+ } else { -+ num_frames = 1; -+ frame_size[0] = dsize; -+ tot_frame_size[0] = dsize; -+ total_datasize = dsize; -+ } -+ -+ new_frame_size = total_datasize + num_frames * VP9_HEADER_SIZE; -+ -+ for (cur_frame = num_frames - 1; cur_frame >= 0; cur_frame--) { -+ int framesize = frame_size[cur_frame]; -+ int framesize_header = framesize + 4; -+ int oldframeoff = tot_frame_size[cur_frame] - framesize; -+ int outheaderoff = oldframeoff + cur_frame * VP9_HEADER_SIZE; -+ uint8_t *fdata = dp + outheaderoff; -+ uint8_t *old_framedata = dp + oldframeoff; -+ -+ memmove(fdata + VP9_HEADER_SIZE, old_framedata, framesize); -+ -+ fdata[0] = (framesize_header >> 24) & 0xff; -+ fdata[1] = (framesize_header >> 16) & 0xff; -+ fdata[2] = (framesize_header >> 8) & 0xff; -+ fdata[3] = (framesize_header >> 0) & 0xff; -+ fdata[4] = ((framesize_header >> 24) & 0xff) ^0xff; -+ fdata[5] = ((framesize_header >> 16) & 0xff) ^0xff; -+ fdata[6] = ((framesize_header >> 8) & 0xff) ^0xff; -+ fdata[7] = ((framesize_header >> 0) & 0xff) ^0xff; -+ fdata[8] = 0; -+ fdata[9] = 0; -+ fdata[10] = 0; -+ fdata[11] = 1; -+ fdata[12] = 'A'; -+ fdata[13] = 'M'; -+ fdata[14] = 'L'; -+ fdata[15] = 'V'; -+ -+ if (!old_header) { -+ /* nothing */ -+ } else if (old_header > fdata + 16 + framesize) { -+ printk("data has gaps, setting to 0\n"); -+ memset(fdata + 16 + framesize, 0, (old_header - fdata + 16 + framesize)); -+ } else if (old_header < fdata + 16 + framesize) { -+ printk("data overwritten\n"); -+ } -+ old_header = fdata; -+ } -+ -+ return new_frame_size; -+} -+ - /* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger - * ISRs. - * Also append a start code 000001ff at the end to trigger - * the ESPARSER interrupt. - */ --static u32 esparser_pad_start_code(struct vb2_buffer *vb) -+static u32 esparser_pad_start_code(struct vb2_buffer *vb, u32 payload_size) - { -- u32 payload_size = vb2_get_plane_payload(vb, 0); - u32 pad_size = 0; - u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size; - -@@ -189,7 +279,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) - if (codec_ops->num_pending_bufs) - num_dst_bufs = codec_ops->num_pending_bufs(sess); - -- num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -+ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx) - 1; - - if (esparser_vififo_get_free_space(sess) < payload_size || - atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) -@@ -203,7 +293,10 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) - dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n", - vb->timestamp, payload_size, offset); - -- pad_size = esparser_pad_start_code(vb); -+ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) -+ payload_size = vp9_update_header(vb); -+ -+ pad_size = esparser_pad_start_code(vb, payload_size); - ret = esparser_write_data(core, phy, payload_size + pad_size); - - if (ret <= 0) { - -From f90e2c84b8c4a1cd6cb4524fc3c2027888c0b915 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Thu, 17 Jan 2019 17:00:11 +0100 -Subject: [PATCH 219/249] WIP: media: meson: vdec: add VP9 support - ---- - drivers/media/platform/meson/vdec/Makefile | 2 +- - drivers/media/platform/meson/vdec/codec_vp9.c | 1083 +++++++++++++++++ - drivers/media/platform/meson/vdec/codec_vp9.h | 13 + - drivers/media/platform/meson/vdec/esparser.c | 4 +- - drivers/media/platform/meson/vdec/hevc_regs.h | 7 + - .../media/platform/meson/vdec/vdec_platform.c | 23 + - 6 files changed, 1130 insertions(+), 2 deletions(-) - create mode 100644 drivers/media/platform/meson/vdec/codec_vp9.c - create mode 100644 drivers/media/platform/meson/vdec/codec_vp9.h - -diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile -index 4fba9e052f14f..c6b0c299c0377 100644 ---- a/drivers/media/platform/meson/vdec/Makefile -+++ b/drivers/media/platform/meson/vdec/Makefile -@@ -3,6 +3,6 @@ - - meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o - meson-vdec-objs += vdec_1.o vdec_hevc.o --meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o -+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o codec_vp9.o - - obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o -diff --git a/drivers/media/platform/meson/vdec/codec_vp9.c b/drivers/media/platform/meson/vdec/codec_vp9.c -new file mode 100644 -index 0000000000000..731119b9ee17a ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_vp9.c -@@ -0,0 +1,1083 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. -+ */ -+ -+#include -+#include -+ -+#include "codec_hevc.h" -+#include "dos_regs.h" -+#include "hevc_regs.h" -+#include "vdec_helpers.h" -+#include "codec_hevc_common.h" -+ -+/* HEVC reg mapping */ -+#define VP9_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 -+ #define VP9_10B_DECODE_SLICE 5 -+ #define VP9_HEAD_PARSER_DONE 0xf0 -+#define VP9_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 -+#define VP9_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2 -+#define VP9_ADAPT_PROB_REG HEVC_ASSIST_SCRATCH_3 -+#define VP9_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_4 -+#define VP9_PPS_BUFFER HEVC_ASSIST_SCRATCH_5 -+#define VP9_SAO_UP HEVC_ASSIST_SCRATCH_6 -+#define VP9_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 -+#define VP9_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 -+#define VP9_PROB_SWAP_BUFFER HEVC_ASSIST_SCRATCH_9 -+#define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A -+#define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B -+#define VP9_SCALELUT HEVC_ASSIST_SCRATCH_D -+#define VP9_WAIT_FLAG HEVC_ASSIST_SCRATCH_E -+#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F -+#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I -+#define VP9_DECODE_MODE HEVC_ASSIST_SCRATCH_J -+ #define DECODE_MODE_SINGLE 0 -+#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K -+#define HEVC_DECODE_COUNT HEVC_ASSIST_SCRATCH_M -+#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N -+ -+/* VP9 Constants */ -+#define LCU_SIZE 64 -+#define MAX_REF_PIC_NUM 24 -+#define REFS_PER_FRAME 3 -+#define REF_FRAMES 8 -+#define MV_MEM_UNIT 0x240 -+ -+enum FRAME_TYPE { -+ KEY_FRAME = 0, -+ INTER_FRAME = 1, -+ FRAME_TYPES, -+}; -+ -+/* VP9 Workspace layout */ -+#define MPRED_MV_BUF_SIZE 0x120000 -+ -+#define IPP_SIZE 0x4000 -+#define SAO_ABV_SIZE 0x30000 -+#define SAO_VB_SIZE 0x30000 -+#define SH_TM_RPS_SIZE 0x800 -+#define VPS_SIZE 0x800 -+#define SPS_SIZE 0x800 -+#define PPS_SIZE 0x2000 -+#define SAO_UP_SIZE 0x2800 -+#define SWAP_BUF_SIZE 0x800 -+#define SWAP_BUF2_SIZE 0x800 -+#define SCALELUT_SIZE 0x8000 -+#define DBLK_PARA_SIZE 0x80000 -+#define DBLK_DATA_SIZE 0x80000 -+#define SEG_MAP_SIZE 0xd800 -+#define PROB_SIZE 0x5000 -+#define COUNT_SIZE 0x3000 -+#define MMU_VBH_SIZE 0x5000 -+#define MPRED_ABV_SIZE 0x10000 -+#define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) -+#define RPM_BUF_SIZE 0x100 -+#define LMEM_SIZE 0x800 -+ -+#define IPP_OFFSET 0x00 -+#define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) -+#define SAO_VB_OFFSET (SAO_ABV_OFFSET + SAO_ABV_SIZE) -+#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + SAO_VB_SIZE) -+#define VPS_OFFSET (SH_TM_RPS_OFFSET + SH_TM_RPS_SIZE) -+#define SPS_OFFSET (VPS_OFFSET + VPS_SIZE) -+#define PPS_OFFSET (SPS_OFFSET + SPS_SIZE) -+#define SAO_UP_OFFSET (PPS_OFFSET + PPS_SIZE) -+#define SWAP_BUF_OFFSET (SAO_UP_OFFSET + SAO_UP_SIZE) -+#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + SWAP_BUF_SIZE) -+#define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) -+#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) -+#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) -+#define SEG_MAP_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) -+#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) -+#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) -+#define MMU_VBH_OFFSET (COUNT_OFFSET + COUNT_SIZE) -+#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) -+#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) -+#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) -+#define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) -+ -+#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + LMEM_SIZE, 64 * SZ_1K) -+ -+#define NONE -1 -+#define INTRA_FRAME 0 -+#define LAST_FRAME 1 -+#define GOLDEN_FRAME 2 -+#define ALTREF_FRAME 3 -+#define MAX_REF_FRAMES 4 -+ -+/* -+ * Defines, declarations, sub-functions for vp9 de-block loop -+ filter Thr/Lvl table update -+ * - struct segmentation is for loop filter only (removed something) -+ * - function "vp9_loop_filter_init" and "vp9_loop_filter_frame_init" will -+ be instantiated in C_Entry -+ * - vp9_loop_filter_init run once before decoding start -+ * - vp9_loop_filter_frame_init run before every frame decoding start -+ * - set video format to VP9 is in vp9_loop_filter_init -+ */ -+#define MAX_LOOP_FILTER 63 -+#define MAX_REF_LF_DELTAS 4 -+#define MAX_MODE_LF_DELTAS 2 -+#define SEGMENT_DELTADATA 0 -+#define SEGMENT_ABSDATA 1 -+#define MAX_SEGMENTS 8 -+ -+union rpm_param { -+ struct { -+ u16 data[RPM_BUF_SIZE]; -+ } l; -+ struct { -+ u16 profile; -+ u16 show_existing_frame; -+ u16 frame_to_show_idx; -+ u16 frame_type; /*1 bit*/ -+ u16 show_frame; /*1 bit*/ -+ u16 error_resilient_mode; /*1 bit*/ -+ u16 intra_only; /*1 bit*/ -+ u16 display_size_present; /*1 bit*/ -+ u16 reset_frame_context; -+ u16 refresh_frame_flags; -+ u16 width; -+ u16 height; -+ u16 display_width; -+ u16 display_height; -+ u16 ref_info; -+ u16 same_frame_size; -+ u16 mode_ref_delta_enabled; -+ u16 ref_deltas[4]; -+ u16 mode_deltas[2]; -+ u16 filter_level; -+ u16 sharpness_level; -+ u16 bit_depth; -+ u16 seg_quant_info[8]; -+ u16 seg_enabled; -+ u16 seg_abs_delta; -+ /* bit 15: feature enabled; bit 8, sign; bit[5:0], data */ -+ u16 seg_lf_info[8]; -+ } p; -+}; -+ -+enum SEG_LVL_FEATURES { -+ SEG_LVL_ALT_Q = 0, /* Use alternate Quantizer */ -+ SEG_LVL_ALT_LF = 1, /* Use alternate loop filter value */ -+ SEG_LVL_REF_FRAME = 2, /* Optional Segment reference frame */ -+ SEG_LVL_SKIP = 3, /* Optional Segment (0,0) + skip mode */ -+ SEG_LVL_MAX = 4 /* Number of features supported */ -+}; -+ -+struct segmentation { -+ uint8_t enabled; -+ uint8_t update_map; -+ uint8_t update_data; -+ uint8_t abs_delta; -+ uint8_t temporal_update; -+ int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX]; -+ unsigned int feature_mask[MAX_SEGMENTS]; -+}; -+ -+struct loop_filter_thresh { -+ uint8_t mblim; -+ uint8_t lim; -+ uint8_t hev_thr; -+}; -+ -+struct loop_filter_info_n { -+ struct loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1]; -+ uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS]; -+}; -+ -+struct loopfilter { -+ int filter_level; -+ -+ int sharpness_level; -+ int last_sharpness_level; -+ -+ uint8_t mode_ref_delta_enabled; -+ uint8_t mode_ref_delta_update; -+ -+ /*0 = Intra, Last, GF, ARF*/ -+ signed char ref_deltas[MAX_REF_LF_DELTAS]; -+ signed char last_ref_deltas[MAX_REF_LF_DELTAS]; -+ -+ /*0 = ZERO_MV, MV*/ -+ signed char mode_deltas[MAX_MODE_LF_DELTAS]; -+ signed char last_mode_deltas[MAX_MODE_LF_DELTAS]; -+}; -+ -+struct vp9_frame { -+ struct list_head list; -+ struct vb2_v4l2_buffer *vbuf; -+ int index; -+ int intra_only; -+ int show; -+ int type; -+ int done; -+}; -+ -+struct codec_vp9 { -+ struct mutex lock; -+ -+ /* Buffer for the VP9 Workspace */ -+ void *workspace_vaddr; -+ dma_addr_t workspace_paddr; -+ -+ /* Contains many information parsed from the bitstream */ -+ union rpm_param rpm_param; -+ -+ /* Whether we detected the bitstream as 10-bit */ -+ int is_10bit; -+ -+ /* Coded resolution reported by the hardware */ -+ u32 width, height; -+ -+ /* All ref frames used by the HW at a given time */ -+ struct list_head ref_frames_list; -+ u32 frames_num; -+ -+ /* In case of downsampling (decoding with FBC but outputting in NV12M), -+ * we need to allocate additional buffers for FBC. -+ */ -+ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; -+ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; -+ -+ int ref_frame_map[REF_FRAMES]; -+ int next_ref_frame_map[REF_FRAMES]; -+ struct vp9_frame* frame_refs[REFS_PER_FRAME]; -+ -+ u32 lcu_total; -+ -+ /* loop filter */ -+ int default_filt_lvl; -+ struct loop_filter_info_n lfi; -+ struct loopfilter lf; -+ struct segmentation seg_4lf; -+ -+ struct vp9_frame *cur_frame; -+ struct vp9_frame *prev_frame; -+}; -+ -+static int vp9_clamp(int value, int low, int high) -+{ -+ return value < low ? low : (value > high ? high : value); -+} -+ -+static int segfeature_active(struct segmentation *seg, -+ int segment_id, -+ enum SEG_LVL_FEATURES feature_id) -+{ -+ return seg->enabled && -+ (seg->feature_mask[segment_id] & (1 << feature_id)); -+} -+ -+static int get_segdata(struct segmentation *seg, int segment_id, -+ enum SEG_LVL_FEATURES feature_id) -+{ -+ return seg->feature_data[segment_id][feature_id]; -+} -+ -+static void vp9_update_sharpness(struct loop_filter_info_n *lfi, -+ int sharpness_lvl) -+{ -+ int lvl; -+ /*For each possible value for the loop filter fill out limits*/ -+ for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) { -+ /*Set loop filter parameters that control sharpness.*/ -+ int block_inside_limit = lvl >> ((sharpness_lvl > 0) + -+ (sharpness_lvl > 4)); -+ -+ if (sharpness_lvl > 0) { -+ if (block_inside_limit > (9 - sharpness_lvl)) -+ block_inside_limit = (9 - sharpness_lvl); -+ } -+ -+ if (block_inside_limit < 1) -+ block_inside_limit = 1; -+ -+ lfi->lfthr[lvl].lim = (uint8_t)block_inside_limit; -+ lfi->lfthr[lvl].mblim = (uint8_t)(2 * (lvl + 2) + -+ block_inside_limit); -+ } -+} -+ -+/*instantiate this function once when decode is started*/ -+static void -+vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9) -+{ -+ struct loop_filter_info_n *lfi = &vp9->lfi; -+ struct loopfilter *lf = &vp9->lf; -+ struct segmentation *seg_4lf = &vp9->seg_4lf; -+ int i; -+ -+ memset(lfi, 0, sizeof(struct loop_filter_info_n)); -+ memset(lf, 0, sizeof(struct loopfilter)); -+ memset(seg_4lf, 0, sizeof(struct segmentation)); -+ lf->sharpness_level = 0; -+ vp9_update_sharpness(lfi, lf->sharpness_level); -+ lf->last_sharpness_level = lf->sharpness_level; -+ -+ for (i = 0; i < 32; i++) { -+ unsigned int thr; -+ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f)<<8) | -+ (lfi->lfthr[i * 2 + 1].mblim & 0xff); -+ thr = (thr<<16) | ((lfi->lfthr[i*2].lim & 0x3f)<<8) | -+ (lfi->lfthr[i * 2].mblim & 0xff); -+ amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); -+ } -+ -+ amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); -+} -+ -+static void -+vp9_loop_filter_frame_init(struct amvdec_core *core, struct segmentation *seg, -+ struct loop_filter_info_n *lfi, -+ struct loopfilter *lf, int default_filt_lvl) -+{ -+ int i; -+ int seg_id; -+ /*n_shift is the multiplier for lf_deltas -+ the multiplier is 1 for when filter_lvl is between 0 and 31; -+ 2 when filter_lvl is between 32 and 63*/ -+ const int scale = 1 << (default_filt_lvl >> 5); -+ -+ /*update limits if sharpness has changed*/ -+ if (lf->last_sharpness_level != lf->sharpness_level) { -+ vp9_update_sharpness(lfi, lf->sharpness_level); -+ lf->last_sharpness_level = lf->sharpness_level; -+ -+ /*Write to register*/ -+ for (i = 0; i < 32; i++) { -+ unsigned int thr; -+ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f) << 8) -+ | (lfi->lfthr[i * 2 + 1].mblim & 0xff); -+ thr = (thr << 16) | ((lfi->lfthr[i * 2].lim & 0x3f) << 8) -+ | (lfi->lfthr[i * 2].mblim & 0xff); -+ amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); -+ } -+ } -+ -+ for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {/*MAX_SEGMENTS = 8*/ -+ int lvl_seg = default_filt_lvl; -+ if (segfeature_active(seg, seg_id, SEG_LVL_ALT_LF)) { -+ const int data = get_segdata(seg, seg_id, -+ SEG_LVL_ALT_LF); -+ lvl_seg = vp9_clamp(seg->abs_delta == SEGMENT_ABSDATA ? -+ data : default_filt_lvl + data, -+ 0, MAX_LOOP_FILTER); -+ } -+ -+ if (!lf->mode_ref_delta_enabled) { -+ /*we could get rid of this if we assume that deltas are set to -+ zero when not in use; encoder always uses deltas*/ -+ memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id])); -+ } else { -+ int ref, mode; -+ const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] -+ * scale; -+ lfi->lvl[seg_id][INTRA_FRAME][0] = -+ vp9_clamp(intra_lvl, 0, MAX_LOOP_FILTER); -+ -+ for (ref = LAST_FRAME; ref < MAX_REF_FRAMES; ++ref) { -+ /* LAST_FRAME = 1, MAX_REF_FRAMES = 4*/ -+ for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) { -+ /*MAX_MODE_LF_DELTAS = 2*/ -+ const int inter_lvl = -+ lvl_seg + lf->ref_deltas[ref] * scale -+ + lf->mode_deltas[mode] * scale; -+ lfi->lvl[seg_id][ref][mode] = -+ vp9_clamp(inter_lvl, 0, -+ MAX_LOOP_FILTER); -+ } -+ } -+ } -+ } -+ -+ for (i = 0; i < 16; i++) { -+ unsigned int level; -+ level = ((lfi->lvl[i >> 1][3][i & 1] & 0x3f) << 24) | -+ ((lfi->lvl[i >> 1][2][i & 1] & 0x3f) << 16) | -+ ((lfi->lvl[i >> 1][1][i & 1] & 0x3f) << 8) | -+ (lfi->lvl[i >> 1][0][i & 1] & 0x3f); -+ if (!default_filt_lvl) -+ level = 0; -+ amvdec_write_dos(core, HEVC_DBLK_CFGA, level); -+ } -+} -+ -+static void codec_vp9_flush_output(struct amvdec_session *sess) -+{ -+ struct codec_vp9 *vp9 = sess->priv; -+ struct vp9_frame *tmp, *n; -+ -+ list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) { -+ if (!tmp->done) { -+ if (tmp->show) -+ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); -+ else -+ v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf); -+ vp9->frames_num--; -+ } -+ -+ list_del(&tmp->list); -+ kfree(tmp); -+ } -+} -+ -+static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess) -+{ -+ struct codec_vp9 *vp9 = sess->priv; -+ -+ if (!vp9) -+ return 0; -+ -+ return vp9->frames_num; -+} -+ -+static int -+codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) -+{ -+ dma_addr_t wkaddr; -+ -+ /* Allocate some memory for the VP9 decoder's state */ -+ vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, -+ &wkaddr, GFP_KERNEL); -+ if (!vp9->workspace_vaddr) { -+ dev_err(core->dev, "Failed to allocate VP9 Workspace\n"); -+ return -ENOMEM; -+ } -+ -+ vp9->workspace_paddr = wkaddr; -+ -+ amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); -+ amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET); -+ amvdec_write_dos(core, VP9_SHORT_TERM_RPS, wkaddr + SH_TM_RPS_OFFSET); -+ amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET); -+ amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET); -+ -+ /* No MMU */ -+ amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER, -+ wkaddr + SWAP_BUF_OFFSET); -+ amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, -+ wkaddr + SWAP_BUF2_OFFSET); -+ amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET); -+ amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); -+ amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); -+ amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET); -+ amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET); -+ amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); -+ -+ return 0; -+} -+ -+static int codec_vp9_start(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_vp9 *vp9; -+ u32 val; -+ int i; -+ int ret; -+ -+ vp9 = kzalloc(sizeof(*vp9), GFP_KERNEL); -+ if (!vp9) -+ return -ENOMEM; -+ -+ ret = codec_vp9_setup_workspace(core, vp9); -+ if (ret) -+ goto free_vp9; -+ -+ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); -+ -+ val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff; -+ val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0); -+ amvdec_write_dos(core, HEVC_PARSER_INT_CONTROL, val); -+ amvdec_write_dos_bits(core, HEVC_SHIFT_STATUS, BIT(0)); -+ amvdec_write_dos(core, HEVC_SHIFT_CONTROL, BIT(10) | BIT(9) | -+ (3 << 6) | BIT(5) | BIT(2) | BIT(1) | BIT(0)); -+ amvdec_write_dos(core, HEVC_CABAC_CONTROL, BIT(0)); -+ amvdec_write_dos(core, HEVC_PARSER_CORE_CONTROL, BIT(0)); -+ amvdec_write_dos(core, HEVC_SHIFT_STARTCODE, 0x00000001); -+ -+ amvdec_write_dos(core, VP9_DEC_STATUS_REG, 0); -+ -+ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); -+ for (i = 0; i < ARRAY_SIZE(vdec_hevc_parser_cmd); ++i) -+ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, -+ vdec_hevc_parser_cmd[i]); -+ -+ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); -+ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); -+ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2); -+ amvdec_write_dos(core, HEVC_PARSER_IF_CONTROL, -+ BIT(5) | BIT(2) | BIT(0)); -+ -+ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(0)); -+ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(1)); -+ -+ amvdec_write_dos(core, VP9_WAIT_FLAG, 1); -+ -+ /* clear mailbox interrupt */ -+ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_CLR_REG, 1); -+ /* enable mailbox interrupt */ -+ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 1); -+ /* disable PSCALE for hardware sharing */ -+ amvdec_write_dos(core, HEVC_PSCALE_CTRL, 0); -+ /* Let the uCode do all the parsing */ -+ amvdec_write_dos(core, NAL_SEARCH_CTL, 0x8); -+ -+ amvdec_write_dos(core, DECODE_STOP_POS, 0); -+ amvdec_write_dos(core, VP9_DECODE_MODE, DECODE_MODE_SINGLE); -+ -+ printk("decode_count: %u; decode_size: %u\n", amvdec_read_dos(core, HEVC_DECODE_COUNT), amvdec_read_dos(core, HEVC_DECODE_SIZE)); -+ -+ vp9_loop_filter_init(core, vp9); -+ -+ INIT_LIST_HEAD(&vp9->ref_frames_list); -+ mutex_init(&vp9->lock); -+ memset(&vp9->ref_frame_map, -1, sizeof(vp9->ref_frame_map)); -+ memset(&vp9->next_ref_frame_map, -1, sizeof(vp9->next_ref_frame_map)); -+ sess->priv = vp9; -+ -+ return 0; -+ -+free_vp9: -+ kfree(vp9); -+ return ret; -+} -+ -+static int codec_vp9_stop(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_vp9 *vp9 = sess->priv; -+ -+ if (vp9->workspace_vaddr) -+ dma_free_coherent(core->dev, SIZE_WORKSPACE, -+ vp9->workspace_vaddr, -+ vp9->workspace_paddr); -+ -+ codec_hevc_free_fbc_buffers(sess); -+ return 0; -+} -+ -+static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_vp9 *vp9 = sess->priv; -+ -+ dma_addr_t buf_y_paddr; -+ dma_addr_t buf_u_v_paddr; -+ u32 val; -+ -+ if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit)) -+ buf_y_paddr = -+ sess->fbc_buffer_paddr[vb->index]; -+ else -+ buf_y_paddr = -+ vb2_dma_contig_plane_dma_addr(vb, 0); -+ -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { -+ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; -+ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); -+ amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); -+ } -+ -+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { -+ buf_y_paddr = -+ vb2_dma_contig_plane_dma_addr(vb, 0); -+ buf_u_v_paddr = -+ vb2_dma_contig_plane_dma_addr(vb, 1); -+ amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr); -+ amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr); -+ amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr); -+ amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); -+ } -+ -+ amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, -+ amvdec_get_output_size(sess)); -+ amvdec_write_dos(core, HEVC_SAO_C_LENGTH, -+ (amvdec_get_output_size(sess) / 2)); -+ -+ val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; -+ val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) -+ val |= BIT(0); /* disable cm compression */ -+ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) -+ val |= BIT(1); /* Disable double write */ -+ -+ amvdec_write_dos(core, HEVC_SAO_CTRL1, val); -+ -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { -+ /* no downscale for NV12 */ -+ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; -+ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); -+ } -+ -+ val = amvdec_read_dos(core, HEVCD_IPP_AXIIF_CONFIG) & ~0x30; -+ val |= 0xf; -+ amvdec_write_dos(core, HEVCD_IPP_AXIIF_CONFIG, val); -+} -+ -+static dma_addr_t codec_vp9_get_frame_mv_paddr(struct codec_vp9 *vp9, -+ struct vp9_frame *frame) -+{ -+ return vp9->workspace_paddr + MPRED_MV_OFFSET + -+ (frame->index * MPRED_MV_BUF_SIZE); -+} -+ -+static void codec_vp9_set_mpred_mv(struct amvdec_core *core, -+ struct codec_vp9 *vp9) -+{ -+ int mpred_mv_rd_end_addr; -+ int use_prev_frame_mvs = !vp9->prev_frame->intra_only && -+ vp9->prev_frame->show && -+ vp9->prev_frame->type != KEY_FRAME; -+ -+ amvdec_write_dos(core, HEVC_MPRED_CTRL3, 0x24122412); -+ amvdec_write_dos(core, HEVC_MPRED_ABV_START_ADDR, -+ vp9->workspace_paddr + MPRED_ABV_OFFSET); -+ -+ amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); -+ if (use_prev_frame_mvs) -+ amvdec_write_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); -+ -+ amvdec_write_dos(core, HEVC_MPRED_MV_WR_START_ADDR, -+ codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame)); -+ amvdec_write_dos(core, HEVC_MPRED_MV_WPTR, -+ codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame)); -+ -+ amvdec_write_dos(core, HEVC_MPRED_MV_RD_START_ADDR, -+ codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame)); -+ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, -+ codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame)); -+ -+ mpred_mv_rd_end_addr = codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame) -+ + (vp9->lcu_total * MV_MEM_UNIT); -+ amvdec_write_dos(core, HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr); -+} -+ -+static void codec_vp9_update_next_ref(struct codec_vp9 *vp9) -+{ -+ union rpm_param *param = &vp9->rpm_param; -+ u32 buf_idx = vp9->cur_frame->index; -+ int ref_index = 0; -+ int refresh_frame_flags; -+ int mask; -+ -+ refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ? 0xff : -+ param->p.refresh_frame_flags; -+ -+ for (mask = refresh_frame_flags; mask; mask >>= 1) { -+ //printk("mask=%08X; ref_index=%d\n", mask, ref_index); -+ if (mask & 1) -+ vp9->next_ref_frame_map[ref_index] = buf_idx; -+ else -+ vp9->next_ref_frame_map[ref_index] = -+ vp9->ref_frame_map[ref_index]; -+ -+ ++ref_index; -+ } -+ -+ for (; ref_index < REF_FRAMES; ++ref_index) -+ vp9->next_ref_frame_map[ref_index] = -+ vp9->ref_frame_map[ref_index]; -+} -+ -+static void codec_vp9_update_ref(struct codec_vp9 *vp9) -+{ -+ union rpm_param *param = &vp9->rpm_param; -+ int ref_index = 0; -+ int mask; -+ int refresh_frame_flags; -+ -+ if (!vp9->cur_frame) -+ return; -+ -+ refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ? -+ 0xff : -+ param->p.refresh_frame_flags; -+ -+ for (mask = refresh_frame_flags; mask; mask >>= 1) { -+ vp9->ref_frame_map[ref_index] = -+ vp9->next_ref_frame_map[ref_index]; -+ ++ref_index; -+ } -+ -+ if (param->p.show_existing_frame) -+ return; -+ -+ for (; ref_index < REF_FRAMES; ++ref_index) -+ vp9->ref_frame_map[ref_index] = -+ vp9->next_ref_frame_map[ref_index]; -+} -+ -+static struct vp9_frame * codec_vp9_get_frame_by_idx(struct codec_vp9 *vp9, int idx) -+{ -+ struct vp9_frame *frame; -+ -+ list_for_each_entry(frame, &vp9->ref_frames_list, list) { -+ if (frame->index == idx) -+ return frame; -+ } -+ -+ return NULL; -+} -+ -+static void codec_vp9_sync_ref(struct codec_vp9 *vp9) -+{ -+ union rpm_param *param = &vp9->rpm_param; -+ int i; -+ -+ for (i = 0; i < REFS_PER_FRAME; ++i) { -+ const int ref = (param->p.ref_info >> -+ (((REFS_PER_FRAME-i-1)*4)+1)) & 0x7; -+ const int idx = vp9->ref_frame_map[ref]; -+ -+ vp9->frame_refs[i] = codec_vp9_get_frame_by_idx(vp9, idx); -+ } -+} -+ -+static void codec_vp9_set_refs(struct amvdec_session *sess, -+ struct codec_vp9 *vp9) -+{ -+ struct amvdec_core *core = sess->core; -+ int i; -+ -+ for (i = 0; i < REFS_PER_FRAME; ++i) { -+ struct vp9_frame *frame = vp9->frame_refs[i]; -+ int id_y; -+ int id_u_v; -+ -+ if (!frame) -+ continue; -+ -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { -+ id_y = frame->index; -+ id_u_v = id_y; -+ } else { -+ id_y = frame->index * 2; -+ id_u_v = id_y + 1; -+ } -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, -+ (id_u_v << 16) | (id_u_v << 8) | id_y); -+ } -+} -+ -+static void codec_vp9_set_mc(struct amvdec_session *sess, -+ struct codec_vp9 *vp9) -+{ -+ struct amvdec_core *core = sess->core; -+ int i; -+ -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); -+ codec_vp9_set_refs(sess, vp9); -+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (16 << 8) | 1); -+ codec_vp9_set_refs(sess, vp9); -+ -+ amvdec_write_dos(core, VP9D_MPP_REFINFO_TBL_ACCCONFIG, BIT(2)); -+ for (i = 0; i < REFS_PER_FRAME; ++i) { -+ if (!vp9->frame_refs[i]) -+ continue; -+ -+ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, vp9->width); -+ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, vp9->height); -+ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, -+ (vp9->width << 14) / vp9->width); -+ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, -+ (vp9->height << 14) / vp9->height); -+ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, -+ amvdec_am21c_body_size(vp9->width, vp9->height) >> 5); -+ } -+ -+ amvdec_write_dos(core, VP9D_MPP_REF_SCALE_ENBL, 0); -+} -+ -+static struct vp9_frame *codec_vp9_get_new_frame(struct amvdec_session *sess) -+{ -+ struct codec_vp9 *vp9 = sess->priv; -+ union rpm_param *param = &vp9->rpm_param; -+ struct vb2_v4l2_buffer *vbuf; -+ struct vp9_frame *new_frame; -+ -+ new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL); -+ if (!new_frame) -+ return NULL; -+ -+ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); -+ if (!vbuf) { -+ dev_err(sess->core->dev, "No dst buffer available\n"); -+ kfree(new_frame); -+ return NULL; -+ } -+ -+ while (codec_vp9_get_frame_by_idx(vp9, vbuf->vb2_buf.index)) { -+ struct vb2_v4l2_buffer *old_vbuf = vbuf; -+ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); -+ v4l2_m2m_buf_queue(sess->m2m_ctx, old_vbuf); -+ if (!vbuf) { -+ dev_err(sess->core->dev, "No dst buffer available\n"); -+ kfree(new_frame); -+ return NULL; -+ } -+ } -+ -+ new_frame->vbuf = vbuf; -+ new_frame->index = vbuf->vb2_buf.index; -+ new_frame->intra_only = param->p.intra_only; -+ new_frame->show = param->p.show_frame; -+ new_frame->type = param->p.frame_type; -+ list_add_tail(&new_frame->list, &vp9->ref_frames_list); -+ vp9->frames_num++; -+ -+ return new_frame; -+} -+ -+static void codec_vp9_show_existing_frame(struct codec_vp9 *vp9) -+{ -+ union rpm_param *param = &vp9->rpm_param; -+ -+ if (!param->p.show_existing_frame) -+ return; -+ -+ printk("showing frame %u\n", param->p.frame_to_show_idx); -+} -+ -+static void codec_vp9_rm_noshow_frame(struct amvdec_session *sess) -+{ -+ struct codec_vp9 *vp9 = sess->priv; -+ struct vp9_frame *tmp; -+ -+ list_for_each_entry(tmp, &vp9->ref_frames_list, list) { -+ if (tmp->show) -+ continue; -+ -+ printk("rm noshow: %u\n", tmp->index); -+ v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf); -+ list_del(&tmp->list); -+ kfree(tmp); -+ vp9->frames_num--; -+ return; -+ } -+} -+ -+static void codec_vp9_process_frame(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_vp9 *vp9 = sess->priv; -+ union rpm_param *param = &vp9->rpm_param; -+ int intra_only; -+ -+ if (!param->p.show_frame) -+ codec_vp9_rm_noshow_frame(sess); -+ -+ vp9->cur_frame = codec_vp9_get_new_frame(sess); -+ if (!vp9->cur_frame) -+ return; -+ -+ printk("frame type: %08X; show_exist: %u; show: %u, intra_only: %u\n", param->p.frame_type, param->p.show_existing_frame, param->p.show_frame, param->p.intra_only); -+ codec_vp9_sync_ref(vp9); -+ codec_vp9_update_next_ref(vp9); -+ codec_vp9_show_existing_frame(vp9); -+ -+ intra_only = param->p.show_frame ? 0 : param->p.intra_only; -+ /* clear mpred (for keyframe only) */ -+ if (param->p.frame_type != KEY_FRAME && !intra_only) { -+ codec_vp9_set_mc(sess, vp9); -+ codec_vp9_set_mpred_mv(core, vp9); -+ } else { -+ amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); -+ } -+ -+ amvdec_write_dos(core, HEVC_PARSER_PICTURE_SIZE, -+ (vp9->height << 16) | vp9->width); -+ codec_vp9_set_sao(sess, &vp9->cur_frame->vbuf->vb2_buf); -+ -+ vp9_loop_filter_frame_init(core, &vp9->seg_4lf, -+ &vp9->lfi, &vp9->lf, vp9->default_filt_lvl); -+ -+ /* ask uCode to start decoding */ -+ amvdec_write_dos(core, VP9_DEC_STATUS_REG, VP9_10B_DECODE_SLICE); -+} -+ -+static void codec_vp9_process_lf(struct codec_vp9 *vp9) -+{ -+ union rpm_param *param = &vp9->rpm_param; -+ int i; -+ -+ vp9->lf.mode_ref_delta_enabled = param->p.mode_ref_delta_enabled; -+ vp9->lf.sharpness_level = param->p.sharpness_level; -+ vp9->default_filt_lvl = param->p.filter_level; -+ vp9->seg_4lf.enabled = param->p.seg_enabled; -+ vp9->seg_4lf.abs_delta = param->p.seg_abs_delta; -+ -+ for (i = 0; i < 4; i++) -+ vp9->lf.ref_deltas[i] = param->p.ref_deltas[i]; -+ -+ for (i = 0; i < 2; i++) -+ vp9->lf.mode_deltas[i] = param->p.mode_deltas[i]; -+ -+ for (i = 0; i < MAX_SEGMENTS; i++) -+ vp9->seg_4lf.feature_mask[i] = (param->p.seg_lf_info[i] & -+ 0x8000) ? (1 << SEG_LVL_ALT_LF) : 0; -+ -+ for (i = 0; i < MAX_SEGMENTS; i++) -+ vp9->seg_4lf.feature_data[i][SEG_LVL_ALT_LF] -+ = (param->p.seg_lf_info[i] -+ & 0x100) ? -(param->p.seg_lf_info[i] -+ & 0x3f) : (param->p.seg_lf_info[i] & 0x3f); -+} -+ -+static void codec_vp9_resume(struct amvdec_session *sess) -+{ -+ struct codec_vp9 *vp9 = sess->priv; -+ -+ if (codec_hevc_setup_buffers(sess, vp9->is_10bit)) { -+ amvdec_abort(sess); -+ return; -+ } -+ -+ codec_hevc_setup_decode_head(sess, vp9->is_10bit); -+ codec_vp9_process_lf(vp9); -+ codec_vp9_process_frame(sess); -+} -+ -+/** -+ * The RPM section within the workspace contains -+ * many information regarding the parsed bitstream -+ */ -+static void codec_vp9_fetch_rpm(struct amvdec_session *sess) -+{ -+ struct codec_vp9 *vp9 = sess->priv; -+ u16 *rpm_vaddr = vp9->workspace_vaddr + RPM_OFFSET; -+ int i, j; -+ -+ for (i = 0; i < RPM_BUF_SIZE; i += 4) -+ for (j = 0; j < 4; j++) -+ vp9->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j]; -+} -+ -+static int codec_vp9_process_rpm(struct codec_vp9 *vp9) -+{ -+ union rpm_param *param = &vp9->rpm_param; -+ int src_changed = 0; -+ int is_10bit = 0; -+ int pic_width_64 = ALIGN(param->p.width, 64); -+ int pic_height_32 = ALIGN(param->p.height, 32); -+ int pic_width_lcu = (pic_width_64 % LCU_SIZE) ? -+ pic_width_64 / LCU_SIZE + 1 -+ : pic_width_64 / LCU_SIZE; -+ int pic_height_lcu = (pic_height_32 % LCU_SIZE) ? -+ pic_height_32 / LCU_SIZE + 1 -+ : pic_height_32 / LCU_SIZE; -+ vp9->lcu_total = pic_width_lcu * pic_height_lcu; -+ -+ if (param->p.bit_depth == 10) -+ is_10bit = 1; -+ -+ if (vp9->width != param->p.width || -+ vp9->height != param->p.height || -+ vp9->is_10bit != is_10bit) -+ src_changed = 1; -+ -+ vp9->width = param->p.width; -+ vp9->height = param->p.height; -+ vp9->is_10bit = is_10bit; -+ -+ printk("width: %u; height: %u; is_10bit: %d; src_changed: %d\n", vp9->width, vp9->height, is_10bit, src_changed); -+ return src_changed; -+} -+ -+static bool codec_vp9_is_ref(struct codec_vp9 *vp9, struct vp9_frame *frame) -+{ -+ int i; -+ -+ for (i = 0; i < REFS_PER_FRAME; ++i) -+ if (vp9->frame_refs[i] == frame) -+ return true; -+ -+ return false; -+} -+ -+static void codec_vp9_show_frame(struct amvdec_session *sess) -+{ -+ struct codec_vp9 *vp9 = sess->priv; -+ struct vp9_frame *tmp, *n; -+ -+ list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) { -+ if (!tmp->show || tmp == vp9->cur_frame) -+ continue; -+ -+ if (!tmp->done) { -+ printk("Doning %u\n", tmp->index); -+ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); -+ tmp->done = 1; -+ vp9->frames_num--; -+ } -+ -+ if (codec_vp9_is_ref(vp9, tmp)) -+ continue; -+ -+ printk("deleting %d\n", tmp->index); -+ list_del(&tmp->list); -+ kfree(tmp); -+ } -+} -+ -+static irqreturn_t codec_vp9_threaded_isr(struct amvdec_session *sess) -+{ -+ struct amvdec_core *core = sess->core; -+ struct codec_vp9 *vp9 = sess->priv; -+ u32 dec_status = amvdec_read_dos(core, VP9_DEC_STATUS_REG); -+ u32 prob_status = amvdec_read_dos(core, VP9_ADAPT_PROB_REG); -+ int i; -+ -+ if (!vp9) -+ return IRQ_HANDLED; -+ -+ mutex_lock(&vp9->lock); -+ if (dec_status != VP9_HEAD_PARSER_DONE) { -+ dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n", -+ dec_status); -+ amvdec_abort(sess); -+ goto unlock; -+ } -+ -+ printk("ISR: %08X;%08X\n", dec_status, prob_status); -+ sess->keyframe_found = 1; -+ -+ /* Invalidate first 3 refs */ -+ for (i = 0; i < 3; ++i) -+ vp9->frame_refs[i] = NULL; -+ -+ vp9->prev_frame = vp9->cur_frame; -+ codec_vp9_update_ref(vp9); -+ -+ codec_vp9_fetch_rpm(sess); -+ if (codec_vp9_process_rpm(vp9)) { -+ amvdec_src_change(sess, vp9->width, vp9->height, 16); -+ goto unlock; -+ } -+ -+ codec_vp9_process_lf(vp9); -+ codec_vp9_process_frame(sess); -+ codec_vp9_show_frame(sess); -+ -+unlock: -+ mutex_unlock(&vp9->lock); -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t codec_vp9_isr(struct amvdec_session *sess) -+{ -+ return IRQ_WAKE_THREAD; -+} -+ -+struct amvdec_codec_ops codec_vp9_ops = { -+ .start = codec_vp9_start, -+ .stop = codec_vp9_stop, -+ .isr = codec_vp9_isr, -+ .threaded_isr = codec_vp9_threaded_isr, -+ .num_pending_bufs = codec_vp9_num_pending_bufs, -+ .drain = codec_vp9_flush_output, -+ .resume = codec_vp9_resume, -+}; -diff --git a/drivers/media/platform/meson/vdec/codec_vp9.h b/drivers/media/platform/meson/vdec/codec_vp9.h -new file mode 100644 -index 0000000000000..641cd75e323b8 ---- /dev/null -+++ b/drivers/media/platform/meson/vdec/codec_vp9.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Copyright (C) 2018 Maxime Jourdan -+ */ -+ -+#ifndef __MESON_VDEC_CODEC_VP9_H_ -+#define __MESON_VDEC_CODEC_VP9_H_ -+ -+#include "vdec.h" -+ -+extern struct amvdec_codec_ops codec_vp9_ops; -+ -+#endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c -index d7ac51e08730d..535015f1be5e1 100644 ---- a/drivers/media/platform/meson/vdec/esparser.c -+++ b/drivers/media/platform/meson/vdec/esparser.c -@@ -279,7 +279,9 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) - if (codec_ops->num_pending_bufs) - num_dst_bufs = codec_ops->num_pending_bufs(sess); - -- num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx) - 1; -+ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -+ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) -+ num_dst_bufs -= 2; - - if (esparser_vififo_get_free_space(sess) < payload_size || - atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) -diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h -index ba49f906be5a9..c80479d7c9c3b 100644 ---- a/drivers/media/platform/meson/vdec/hevc_regs.h -+++ b/drivers/media/platform/meson/vdec/hevc_regs.h -@@ -120,6 +120,8 @@ - #define HEVC_MPRED_L0_REF00_POC 0xc880 - #define HEVC_MPRED_L1_REF00_POC 0xc8c0 - -+#define HEVC_MPRED_CTRL4 0xc930 -+ - #define HEVC_MPRED_CUR_POC 0xc980 - #define HEVC_MPRED_COL_POC 0xc984 - #define HEVC_MPRED_MV_RD_END_ADDR 0xc988 -@@ -138,6 +140,10 @@ - #define HEVCD_IPP_LINEBUFF_BASE 0xd024 - #define HEVCD_IPP_AXIIF_CONFIG 0xd02c - -+#define VP9D_MPP_REF_SCALE_ENBL 0xd104 -+#define VP9D_MPP_REFINFO_TBL_ACCCONFIG 0xd108 -+#define VP9D_MPP_REFINFO_DATA 0xd10c -+ - #define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180 - #define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184 - #define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190 -@@ -162,6 +168,7 @@ - #define HEVC_DBLK_CFG9 0xd424 - #define HEVC_DBLK_CFGA 0xd428 - #define HEVC_DBLK_STS0 0xd42c -+#define HEVC_DBLK_CFGB 0xd42c - #define HEVC_DBLK_STS1 0xd430 - - #define HEVC_SAO_VERSION 0xd800 -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c -index 8a76518cdcde7..cca7c369c2588 100644 ---- a/drivers/media/platform/meson/vdec/vdec_platform.c -+++ b/drivers/media/platform/meson/vdec/vdec_platform.c -@@ -14,6 +14,7 @@ - #include "codec_mpeg4.h" - #include "codec_mjpeg.h" - #include "codec_hevc.h" -+#include "codec_vp9.h" - - static const struct amvdec_format vdec_formats_gxbb[] = { - { -@@ -102,6 +103,17 @@ static const struct amvdec_format vdec_formats_gxbb[] = { - }; - - static const struct amvdec_format vdec_formats_gxl[] = { -+ { -+ .pixfmt = V4L2_PIX_FMT_VP9, -+ .min_buffers = 16, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_hevc_ops, -+ .codec_ops = &codec_vp9_ops, -+ .firmware_path = "meson/gx/vvp9_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, -+ }, - { - .pixfmt = V4L2_PIX_FMT_HEVC, - .min_buffers = 16, -@@ -188,6 +200,17 @@ static const struct amvdec_format vdec_formats_gxl[] = { - }; - - static const struct amvdec_format vdec_formats_gxm[] = { -+ { -+ .pixfmt = V4L2_PIX_FMT_VP9, -+ .min_buffers = 16, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_hevc_ops, -+ .codec_ops = &codec_vp9_ops, -+ .firmware_path = "meson/gx/vvp9_mc", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, -+ }, - { - .pixfmt = V4L2_PIX_FMT_HEVC, - .min_buffers = 16, - -From ab712fac73f943456eb82c37ac126861ca9f1e93 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Thu, 7 Feb 2019 17:37:34 +0100 -Subject: [PATCH 220/249] WIP: media: meson: vdec: add g12a platform - ---- - .../media/platform/meson/vdec/codec_hevc.c | 38 ++++++- - .../platform/meson/vdec/codec_hevc_common.c | 9 -- - drivers/media/platform/meson/vdec/codec_vp9.c | 54 +++++++-- - drivers/media/platform/meson/vdec/hevc_regs.h | 1 + - drivers/media/platform/meson/vdec/vdec.c | 13 ++- - drivers/media/platform/meson/vdec/vdec.h | 1 + - drivers/media/platform/meson/vdec/vdec_hevc.c | 9 ++ - .../media/platform/meson/vdec/vdec_platform.c | 103 ++++++++++++++++++ - .../media/platform/meson/vdec/vdec_platform.h | 2 + - 9 files changed, 206 insertions(+), 24 deletions(-) - -diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c -index 03f00f969f025..e16e937d56e85 100644 ---- a/drivers/media/platform/meson/vdec/codec_hevc.c -+++ b/drivers/media/platform/meson/vdec/codec_hevc.c -@@ -68,7 +68,8 @@ - #define SWAP_BUF2_SIZE 0x800 - #define SCALELUT_SIZE 0x8000 - #define DBLK_PARA_SIZE 0x20000 --#define DBLK_DATA_SIZE 0x40000 -+#define DBLK_DATA_SIZE 0x80000 -+#define DBLK_DATA2_SIZE 0x80000 - #define MMU_VBH_SIZE 0x5000 - #define MPRED_ABV_SIZE 0x8000 - #define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) -@@ -88,7 +89,8 @@ - #define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) - #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) - #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) --#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) -+#define DBLK_DATA2_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) -+#define MMU_VBH_OFFSET (DBLK_DATA2_OFFSET + DBLK_DATA2_SIZE) - #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) - #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) - #define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) -@@ -523,6 +525,7 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) - amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); - amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); - amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); -+ amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); - - return 0; - } -@@ -547,6 +550,8 @@ static int codec_hevc_start(struct amvdec_session *sess) - goto free_hevc; - - amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); -+ if (core->platform->revision == VDEC_REVISION_G12A) -+ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, (0xf << 25)); - - val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; - val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | -@@ -755,6 +760,25 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) - (amvdec_get_output_size(sess) / 2)); - - if (frame->cur_slice_idx == 0) { -+ if (core->platform->revision >= VDEC_REVISION_G12A) { -+ val = 0x54 << 8; -+ -+ /* enable first, compressed write */ -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) -+ val |= BIT(8); -+ -+ /* enable second, uncompressed write */ -+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) -+ val |= BIT(9); -+ -+ /* dblk pipeline mode=1 for performance */ -+ if (hevc->width >= 1280) -+ val |= BIT(4); -+ -+ amvdec_write_dos(core, HEVC_DBLK_CFGB, val); -+ amvdec_write_dos(core, HEVC_DBLK_STS1 + 4, BIT(28)); -+ } -+ - amvdec_write_dos(core, HEVC_DBLK_CFG2, - hevc->width | (hevc->height << 16)); - -@@ -770,10 +794,12 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) - - val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; - val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ -- if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) -- val |= BIT(0); /* disable cm compression */ -- else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) -- val |= BIT(1); /* Disable double write */ -+ if (core->platform->revision < VDEC_REVISION_G12A) { -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) -+ val |= BIT(0); /* disable cm compression */ -+ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) -+ val |= BIT(1); /* Disable double write */ -+ } - - amvdec_write_dos(core, HEVC_SAO_CTRL1, val); - -diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.c b/drivers/media/platform/meson/vdec/codec_hevc_common.c -index 2b296beb5d88a..5c372a9b0f03c 100644 ---- a/drivers/media/platform/meson/vdec/codec_hevc_common.c -+++ b/drivers/media/platform/meson/vdec/codec_hevc_common.c -@@ -111,15 +111,6 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) - } - } - -- /* Fill the remaining unused slots with the last buffer's Y addr */ -- for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -- buf_y_paddr >> 5); -- if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, -- buf_uv_paddr >> 5); -- } -- - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); - amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); - for (i = 0; i < 32; ++i) -diff --git a/drivers/media/platform/meson/vdec/codec_vp9.c b/drivers/media/platform/meson/vdec/codec_vp9.c -index 731119b9ee17a..39e8eb5937bf0 100644 ---- a/drivers/media/platform/meson/vdec/codec_vp9.c -+++ b/drivers/media/platform/meson/vdec/codec_vp9.c -@@ -90,8 +90,8 @@ enum FRAME_TYPE { - #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) - #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) - #define SEG_MAP_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) --#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) --#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) -+#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) -+#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) - #define MMU_VBH_OFFSET (COUNT_OFFSET + COUNT_SIZE) - #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) - #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) -@@ -326,7 +326,11 @@ vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9) - amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); - } - -- amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); -+ if (core->platform->revision == VDEC_REVISION_G12A) -+ /* VP9 video format */ -+ amvdec_write_dos(core, HEVC_DBLK_CFGB, (0x54 << 8) | BIT(0)); -+ else -+ amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); - } - - static void -@@ -447,6 +451,13 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) - return -ENOMEM; - } - -+ memset(vp9->workspace_vaddr + DBLK_PARA_OFFSET, 0, DBLK_PARA_SIZE); -+ memset(vp9->workspace_vaddr + COUNT_OFFSET, 0, COUNT_SIZE); -+ memset(vp9->workspace_vaddr + PROB_OFFSET, 0, PROB_SIZE); -+ -+ printk("Workspace: %08X-%08X\n", wkaddr, wkaddr + SIZE_WORKSPACE); -+ printk("DBLK_PARA: %08X\n", wkaddr + DBLK_PARA_OFFSET); -+ - vp9->workspace_paddr = wkaddr; - - amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); -@@ -461,11 +472,17 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) - amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, - wkaddr + SWAP_BUF2_OFFSET); - amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET); -+ -+ if (core->platform->revision == VDEC_REVISION_G12A) -+ amvdec_write_dos(core, HEVC_DBLK_CFGE, -+ wkaddr + DBLK_PARA_OFFSET); -+ - amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); - amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); - amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET); - amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET); - amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); -+ amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); - - return 0; - } -@@ -487,6 +504,9 @@ static int codec_vp9_start(struct amvdec_session *sess) - goto free_vp9; - - amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); -+ // stream_fifo_hole -+ if (core->platform->revision == VDEC_REVISION_G12A) -+ amvdec_write_dos_bits(core, HEVC_STREAM_FIFO_CTL, BIT(29)); - - val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff; - val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0); -@@ -597,14 +617,34 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb - amvdec_write_dos(core, HEVC_SAO_C_LENGTH, - (amvdec_get_output_size(sess) / 2)); - -+ if (core->platform->revision >= VDEC_REVISION_G12A) { -+ amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, BIT(4) | BIT(5) | BIT(8) | BIT(9)); -+ /* enable first, compressed write */ -+ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) -+ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8)); -+ -+ /* enable second, uncompressed write */ -+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) -+ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(9)); -+ -+ /* dblk pipeline mode=1 for performance */ -+ if (sess->width >= 1280) -+ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4)); -+ -+ printk("HEVC_DBLK_CFGB: %08X\n", amvdec_read_dos(core, HEVC_DBLK_CFGB)); -+ } -+ - val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; - val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ -- if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) -- val |= BIT(0); /* disable cm compression */ -- else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) -- val |= BIT(1); /* Disable double write */ -+ if (core->platform->revision < VDEC_REVISION_G12A) { -+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) -+ val |= BIT(0); /* disable cm compression */ -+ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) -+ val |= BIT(1); /* Disable double write */ -+ } - - amvdec_write_dos(core, HEVC_SAO_CTRL1, val); -+ printk("HEVC_SAO_CTRL1: %08X\n", val); - - if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { - /* no downscale for NV12 */ -diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h -index c80479d7c9c3b..dc2c2e085b051 100644 ---- a/drivers/media/platform/meson/vdec/hevc_regs.h -+++ b/drivers/media/platform/meson/vdec/hevc_regs.h -@@ -170,6 +170,7 @@ - #define HEVC_DBLK_STS0 0xd42c - #define HEVC_DBLK_CFGB 0xd42c - #define HEVC_DBLK_STS1 0xd430 -+#define HEVC_DBLK_CFGE 0xd438 - - #define HEVC_SAO_VERSION 0xd800 - #define HEVC_SAO_CTRL0 0xd804 -diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c -index dd5e6864fbdaa..233604d322356 100644 ---- a/drivers/media/platform/meson/vdec/vdec.c -+++ b/drivers/media/platform/meson/vdec/vdec.c -@@ -941,6 +941,8 @@ static const struct of_device_id vdec_dt_match[] = { - .data = &vdec_platform_gxm }, - { .compatible = "amlogic,gxl-vdec", - .data = &vdec_platform_gxl }, -+ { .compatible = "amlogic,g12a-vdec", -+ .data = &vdec_platform_g12a }, - {} - }; - MODULE_DEVICE_TABLE(of, vdec_dt_match); -@@ -987,6 +989,15 @@ static int vdec_probe(struct platform_device *pdev) - if (!core->canvas) - return PTR_ERR(core->canvas); - -+ of_id = of_match_node(vdec_dt_match, dev->of_node); -+ core->platform = of_id->data; -+ -+ if (core->platform->revision == VDEC_REVISION_G12A) { -+ core->vdec_hevcf_clk = devm_clk_get(dev, "vdec_hevcf"); -+ if (IS_ERR(core->vdec_hevcf_clk)) -+ return -EPROBE_DEFER; -+ } -+ - core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); - if (IS_ERR(core->dos_parser_clk)) - return -EPROBE_DEFER; -@@ -1029,8 +1040,6 @@ static int vdec_probe(struct platform_device *pdev) - goto err_vdev_release; - } - -- of_id = of_match_node(vdec_dt_match, dev->of_node); -- core->platform = of_id->data; - core->vdev_dec = vdev; - core->dev_dec = dev; - mutex_init(&core->lock); -diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h -index 885777e48142a..69a5f82ae80f2 100644 ---- a/drivers/media/platform/meson/vdec/vdec.h -+++ b/drivers/media/platform/meson/vdec/vdec.h -@@ -76,6 +76,7 @@ struct amvdec_core { - struct clk *dos_clk; - struct clk *vdec_1_clk; - struct clk *vdec_hevc_clk; -+ struct clk *vdec_hevcf_clk; - - struct reset_control *esparser_reset; - -diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.c b/drivers/media/platform/meson/vdec/vdec_hevc.c -index 8872f58d39fea..a706dbf3ae8c4 100644 ---- a/drivers/media/platform/meson/vdec/vdec_hevc.c -+++ b/drivers/media/platform/meson/vdec/vdec_hevc.c -@@ -123,6 +123,8 @@ static int vdec_hevc_stop(struct amvdec_session *sess) - regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); - -+ if (core->platform->revision == VDEC_REVISION_G12A) -+ clk_disable_unprepare(core->vdec_hevcf_clk); - clk_disable_unprepare(core->vdec_hevc_clk); - - return 0; -@@ -139,6 +141,13 @@ static int vdec_hevc_start(struct amvdec_session *sess) - if (ret) - return ret; - -+ if (core->platform->revision == VDEC_REVISION_G12A) { -+ clk_set_rate(core->vdec_hevcf_clk, 666666666); -+ ret = clk_prepare_enable(core->vdec_hevcf_clk); -+ if (ret) -+ return ret; -+ } -+ - regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VDEC_HEVC, 0); - udelay(10); -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c -index cca7c369c2588..79ee96638552b 100644 ---- a/drivers/media/platform/meson/vdec/vdec_platform.c -+++ b/drivers/media/platform/meson/vdec/vdec_platform.c -@@ -296,6 +296,103 @@ static const struct amvdec_format vdec_formats_gxm[] = { - }, - }; - -+static const struct amvdec_format vdec_formats_g12a[] = { -+ { -+ .pixfmt = V4L2_PIX_FMT_VP9, -+ .min_buffers = 4, -+ .max_buffers = 16, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_hevc_ops, -+ .codec_ops = &codec_vp9_ops, -+ .firmware_path = "meson/vdec/g12a_vp9.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, -+ }, -+ { -+ .pixfmt = V4L2_PIX_FMT_HEVC, -+ .min_buffers = 16, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_hevc_ops, -+ .codec_ops = &codec_hevc_ops, -+ .firmware_path = "meson/vdec/g12a_hevc.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_MJPEG, -+ .min_buffers = 4, -+ .max_buffers = 4, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mjpeg_ops, -+ .firmware_path = "meson/vdec/gxl_mjpeg.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_MPEG4, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_H263, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/vdec/gxl_h263.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_XVID, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg4_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_H264, -+ .min_buffers = 2, -+ .max_buffers = 24, -+ .max_width = 3840, -+ .max_height = 2160, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_h264_ops, -+ .firmware_path = "meson/vdec/g12a_h264.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_MPEG1, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, { -+ .pixfmt = V4L2_PIX_FMT_MPEG2, -+ .min_buffers = 8, -+ .max_buffers = 8, -+ .max_width = 1920, -+ .max_height = 1080, -+ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, -+ .vdec_ops = &vdec_1_ops, -+ .codec_ops = &codec_mpeg12_ops, -+ .firmware_path = "meson/vdec/gxl_mpeg12.bin", -+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, -+ }, -+}; -+ - const struct vdec_platform vdec_platform_gxbb = { - .formats = vdec_formats_gxbb, - .num_formats = ARRAY_SIZE(vdec_formats_gxbb), -@@ -313,3 +410,9 @@ const struct vdec_platform vdec_platform_gxm = { - .num_formats = ARRAY_SIZE(vdec_formats_gxm), - .revision = VDEC_REVISION_GXM, - }; -+ -+const struct vdec_platform vdec_platform_g12a = { -+ .formats = vdec_formats_g12a, -+ .num_formats = ARRAY_SIZE(vdec_formats_g12a), -+ .revision = VDEC_REVISION_G12A, -+}; -diff --git a/drivers/media/platform/meson/vdec/vdec_platform.h b/drivers/media/platform/meson/vdec/vdec_platform.h -index f6025326db1d6..7c61b941b39f4 100644 ---- a/drivers/media/platform/meson/vdec/vdec_platform.h -+++ b/drivers/media/platform/meson/vdec/vdec_platform.h -@@ -15,6 +15,7 @@ enum vdec_revision { - VDEC_REVISION_GXBB, - VDEC_REVISION_GXL, - VDEC_REVISION_GXM, -+ VDEC_REVISION_G12A, - }; - - struct vdec_platform { -@@ -26,5 +27,6 @@ struct vdec_platform { - extern const struct vdec_platform vdec_platform_gxbb; - extern const struct vdec_platform vdec_platform_gxm; - extern const struct vdec_platform vdec_platform_gxl; -+extern const struct vdec_platform vdec_platform_g12a; - - #endif - -From e88e2fbf6b08d6d7d4702306878bbe7b503cda3c Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Fri, 1 Mar 2019 12:41:03 +0100 -Subject: [PATCH 221/249] WIP: media: meson: vp9: add IOMMU support - -Starting with GXL (S905X), the HEVC/VP9 decoder hardware supports an -IOMMU to access the decoded frames. This IOMMU is controlled by writing -the buffer's page IDs to the firmware, which then does the actual work. - -This commit adds support for using the IOMMU with VP9/HEVC on G12A, the -first SoC on which it becomes mandatory. ---- - .../media/platform/meson/vdec/codec_hevc.c | 35 ++-- - .../platform/meson/vdec/codec_hevc_common.c | 177 ++++++++++++++---- - .../platform/meson/vdec/codec_hevc_common.h | 31 ++- - drivers/media/platform/meson/vdec/codec_vp9.c | 71 ++++--- - drivers/media/platform/meson/vdec/hevc_regs.h | 5 + - drivers/media/platform/meson/vdec/vdec.h | 5 - - drivers/media/platform/meson/vdec/vdec_hevc.c | 14 +- - 7 files changed, 255 insertions(+), 83 deletions(-) - -diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c -index e16e937d56e85..65d2ad4d83459 100644 ---- a/drivers/media/platform/meson/vdec/codec_hevc.c -+++ b/drivers/media/platform/meson/vdec/codec_hevc.c -@@ -75,6 +75,7 @@ - #define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) - #define RPM_BUF_SIZE 0x100 - #define LMEM_SIZE 0xA00 -+#define MMU_MAP_SIZE 0x4800 - - #define IPP_OFFSET 0x00 - #define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) -@@ -95,6 +96,7 @@ - #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) - #define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) - #define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) -+#define MMU_MAP_OFFSET (LMEM_OFFSET + LMEM_SIZE) - - /* ISR decode status */ - #define HEVC_DEC_IDLE 0x0 -@@ -236,6 +238,9 @@ struct hevc_frame { - struct codec_hevc { - struct mutex lock; - -+ /* Common part of the HEVC decoder */ -+ struct codec_hevc_common common; -+ - /* Buffer for the HEVC Workspace */ - void *workspace_vaddr; - dma_addr_t workspace_paddr; -@@ -517,15 +522,20 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) - amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET); - amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET); - -+ if (core->platform->revision >= VDEC_REVISION_G12A) -+ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, -+ wkaddr + MMU_MAP_OFFSET); -+ - /* No MMU */ -- amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, -+ /*amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, - wkaddr + SWAP_BUF_OFFSET); - amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, -- wkaddr + SWAP_BUF2_OFFSET); -+ wkaddr + SWAP_BUF2_OFFSET);*/ - amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); - amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); - amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); - amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); -+ amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); - - return 0; - } -@@ -549,9 +559,10 @@ static int codec_hevc_start(struct amvdec_session *sess) - if (ret) - goto free_hevc; - -- amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); -- if (core->platform->revision == VDEC_REVISION_G12A) -- amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, (0xf << 25)); -+ val = BIT(0); /* stream_fetch_enable */ -+ if (core->platform->revision >= VDEC_REVISION_G12A) -+ val |= (0xf << 25); /* arwlen_axi_max */ -+ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, val); - - val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; - val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | -@@ -608,9 +619,9 @@ static int codec_hevc_start(struct amvdec_session *sess) - goto free_hevc; - } - -- amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); -+ /*amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); - amvdec_write_dos(core, HEVC_AUX_DATA_SIZE, -- (((SIZE_AUX) >> 4) << 16) | 0); -+ (((SIZE_AUX) >> 4) << 16) | 0);*/ - mutex_init(&hevc->lock); - sess->priv = hevc; - -@@ -652,7 +663,7 @@ static int codec_hevc_stop(struct amvdec_session *sess) - dma_free_coherent(core->dev, SIZE_AUX, - hevc->aux_vaddr, hevc->aux_paddr); - -- codec_hevc_free_fbc_buffers(sess); -+ codec_hevc_free_fbc_buffers(sess, &hevc->common); - mutex_unlock(&hevc->lock); - mutex_destroy(&hevc->lock); - -@@ -732,7 +743,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) - - if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit)) - buf_y_paddr = -- sess->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; -+ hevc->common.fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; - else - buf_y_paddr = - vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); -@@ -776,7 +787,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) - val |= BIT(4); - - amvdec_write_dos(core, HEVC_DBLK_CFGB, val); -- amvdec_write_dos(core, HEVC_DBLK_STS1 + 4, BIT(28)); -+ amvdec_write_dos(core, HEVC_DBLK_STS1 + 16, BIT(28)); - } - - amvdec_write_dos(core, HEVC_DBLK_CFG2, -@@ -1323,7 +1334,7 @@ static void codec_hevc_resume(struct amvdec_session *sess) - { - struct codec_hevc *hevc = sess->priv; - -- if (codec_hevc_setup_buffers(sess, hevc->is_10bit)) { -+ if (codec_hevc_setup_buffers(sess, &hevc->common, hevc->is_10bit)) { - amvdec_abort(sess); - return; - } -@@ -1340,6 +1351,8 @@ static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess) - struct codec_hevc *hevc = sess->priv; - u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG); - -+ printk("ISR!\n"); -+ - if (!hevc) - return IRQ_HANDLED; - -diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.c b/drivers/media/platform/meson/vdec/codec_hevc_common.c -index 5c372a9b0f03c..de7eb6cfbe858 100644 ---- a/drivers/media/platform/meson/vdec/codec_hevc_common.c -+++ b/drivers/media/platform/meson/vdec/codec_hevc_common.c -@@ -10,6 +10,9 @@ - #include "vdec_helpers.h" - #include "hevc_regs.h" - -+#define MMU_COMPRESS_HEADER_SIZE 0x48000 -+#define MMU_MAP_SIZE 0x4800 -+ - /* Configure decode head read mode */ - void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) - { -@@ -23,7 +26,12 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) - return; - } - -- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); -+ if (codec_hevc_use_mmu(core->platform->revision, -+ sess->pixfmt_cap, is_10bit)) -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4)); -+ else -+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); -+ - amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); - amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); - amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); -@@ -31,8 +39,9 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) - } - EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); - --static void --codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) -+static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, -+ struct codec_hevc_common *comm, -+ int is_10bit) - { - struct amvdec_core *core = sess->core; - struct v4l2_m2m_buffer *buf; -@@ -46,22 +55,26 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); - - v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -- idx = buf->vb.vb2_buf.index; -+ struct vb2_buffer *vb = &buf->vb.vb2_buf; -+ idx = vb->index; - - if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) -- buf_y_paddr = sess->fbc_buffer_paddr[idx]; -+ buf_y_paddr = comm->fbc_buffer_paddr[idx]; - else -- buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); - - if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { - val = buf_y_paddr | (idx << 8) | 1; -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, -+ val); - } else { -- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); - val = buf_y_paddr | ((idx * 2) << 8) | 1; -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, -+ val); - val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; -- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); -+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, -+ val); - } - } - -@@ -80,32 +93,37 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) - amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); - } - --static void --codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) -+static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, -+ struct codec_hevc_common *comm, -+ int is_10bit) - { - struct amvdec_core *core = sess->core; - struct v4l2_m2m_buffer *buf; -- u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); -- dma_addr_t buf_y_paddr = 0; -- dma_addr_t buf_uv_paddr = 0; -+ u32 revision = core->platform->revision; -+ u32 pixfmt_cap = sess->pixfmt_cap; - int i; - - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, - BIT(2) | BIT(1)); - - v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -- u32 idx = buf->vb.vb2_buf.index; -+ struct vb2_buffer *vb = &buf->vb.vb2_buf; -+ dma_addr_t buf_y_paddr = 0; -+ dma_addr_t buf_uv_paddr = 0; -+ u32 idx = vb->index; - -- if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) -- buf_y_paddr = sess->fbc_buffer_paddr[idx]; -+ if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit)) -+ buf_y_paddr = comm->mmu_header_paddr[idx]; -+ else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit)) -+ buf_y_paddr = comm->fbc_buffer_paddr[idx]; - else -- buf_y_paddr = -- vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); -+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); - - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, - buf_y_paddr >> 5); -- if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { -- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); -+ -+ if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) { -+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, - buf_uv_paddr >> 5); - } -@@ -117,24 +135,26 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) - amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); - } - --void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) -+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, -+ struct codec_hevc_common *comm) - { - struct device *dev = sess->core->dev; - u32 am21_size = amvdec_am21c_size(sess->width, sess->height); - int i; - - for (i = 0; i < MAX_REF_PIC_NUM; ++i) { -- if (sess->fbc_buffer_vaddr[i]) { -+ if (comm->fbc_buffer_vaddr[i]) { - dma_free_coherent(dev, am21_size, -- sess->fbc_buffer_vaddr[i], -- sess->fbc_buffer_paddr[i]); -- sess->fbc_buffer_vaddr[i] = NULL; -+ comm->fbc_buffer_vaddr[i], -+ comm->fbc_buffer_paddr[i]); -+ comm->fbc_buffer_vaddr[i] = NULL; - } - } - } - EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); - --static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) -+static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess, -+ struct codec_hevc_common *comm) - { - struct device *dev = sess->core->dev; - struct v4l2_m2m_buffer *buf; -@@ -147,33 +167,118 @@ static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) - GFP_KERNEL); - if (!vaddr) { - dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); -- codec_hevc_free_fbc_buffers(sess); -+ codec_hevc_free_fbc_buffers(sess, comm); -+ return -ENOMEM; -+ } -+ -+ comm->fbc_buffer_vaddr[idx] = vaddr; -+ comm->fbc_buffer_paddr[idx] = paddr; -+ } -+ -+ return 0; -+} -+ -+void codec_hevc_free_mmu_headers(struct amvdec_session *sess, -+ struct codec_hevc_common *comm) -+{ -+ struct device *dev = sess->core->dev; -+ int i; -+ -+ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { -+ if (comm->mmu_header_vaddr[i]) { -+ dma_free_coherent(dev, MMU_COMPRESS_HEADER_SIZE, -+ comm->mmu_header_vaddr[i], -+ comm->mmu_header_paddr[i]); -+ comm->mmu_header_vaddr[i] = NULL; -+ } -+ } -+ -+ if (comm->mmu_map_vaddr) { -+ dma_free_coherent(dev, MMU_MAP_SIZE, -+ comm->mmu_map_vaddr, -+ comm->mmu_map_paddr); -+ comm->mmu_map_vaddr = NULL; -+ } -+} -+EXPORT_SYMBOL_GPL(codec_hevc_free_mmu_headers); -+ -+static int codec_hevc_alloc_mmu_headers(struct amvdec_session *sess, -+ struct codec_hevc_common *comm) -+{ -+ struct device *dev = sess->core->dev; -+ struct v4l2_m2m_buffer *buf; -+ -+ comm->mmu_map_vaddr = dma_alloc_coherent(dev, MMU_MAP_SIZE, -+ &comm->mmu_map_paddr, -+ GFP_KERNEL); -+ if (!comm->mmu_map_vaddr) -+ return -ENOMEM; -+ -+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { -+ u32 idx = buf->vb.vb2_buf.index; -+ dma_addr_t paddr; -+ void *vaddr = dma_alloc_coherent(dev, MMU_COMPRESS_HEADER_SIZE, -+ &paddr, GFP_KERNEL); -+ if (!vaddr) { -+ dev_err(dev, "Couldn't allocate MMU header %u\n", idx); -+ codec_hevc_free_mmu_headers(sess, comm); - return -ENOMEM; - } - -- sess->fbc_buffer_vaddr[idx] = vaddr; -- sess->fbc_buffer_paddr[idx] = paddr; -+ comm->mmu_header_vaddr[idx] = vaddr; -+ comm->mmu_header_paddr[idx] = paddr; - } - - return 0; - } - --int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit) -+int codec_hevc_setup_buffers(struct amvdec_session *sess, -+ struct codec_hevc_common *comm, -+ int is_10bit) - { - struct amvdec_core *core = sess->core; - int ret; - - if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) { -- ret = codec_hevc_alloc_fbc_buffers(sess); -+ ret = codec_hevc_alloc_fbc_buffers(sess, comm); - if (ret) - return ret; - } - -+ if (codec_hevc_use_mmu(core->platform->revision, -+ sess->pixfmt_cap, is_10bit)) { -+ ret = codec_hevc_alloc_mmu_headers(sess, comm); -+ if (ret) { -+ codec_hevc_free_fbc_buffers(sess, comm); -+ return ret; -+ } -+ } -+ - if (core->platform->revision == VDEC_REVISION_GXBB) -- codec_hevc_setup_buffers_gxbb(sess, is_10bit); -+ codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit); - else -- codec_hevc_setup_buffers_gxl(sess, is_10bit); -+ codec_hevc_setup_buffers_gxl(sess, comm, is_10bit); - - return 0; - } --EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); -\ No newline at end of file -+EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); -+ -+void codec_hevc_fill_mmu_map(struct amvdec_session *sess, -+ struct codec_hevc_common *comm, -+ struct vb2_buffer *vb) -+{ -+ u32 size = amvdec_am21c_size(sess->width, sess->height); -+ u32 nb_pages = size / PAGE_SIZE; -+ u32 *mmu_map = comm->mmu_map_vaddr; -+ u32 first_page; -+ u32 i; -+ -+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) -+ first_page = comm->fbc_buffer_paddr[vb->index] >> PAGE_SHIFT; -+ else -+ first_page = vb2_dma_contig_plane_dma_addr(vb, 0) >> PAGE_SHIFT; -+ -+ for (i = 0; i < nb_pages; ++i) -+ mmu_map[i] = first_page + i; -+} -+EXPORT_SYMBOL_GPL(codec_hevc_fill_mmu_map); -diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.h b/drivers/media/platform/meson/vdec/codec_hevc_common.h -index 96493f9fe6995..e31aed5ee7b85 100644 ---- a/drivers/media/platform/meson/vdec/codec_hevc_common.h -+++ b/drivers/media/platform/meson/vdec/codec_hevc_common.h -@@ -25,6 +25,19 @@ static const u16 vdec_hevc_parser_cmd[] = { - 0x7C00 - }; - -+#define MAX_REF_PIC_NUM 24 -+ -+struct codec_hevc_common { -+ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; -+ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; -+ -+ void *mmu_header_vaddr[MAX_REF_PIC_NUM]; -+ dma_addr_t mmu_header_paddr[MAX_REF_PIC_NUM]; -+ -+ void *mmu_map_vaddr; -+ dma_addr_t mmu_map_paddr; -+}; -+ - /* Returns 1 if we must use framebuffer compression */ - static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit) - { -@@ -37,13 +50,27 @@ static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit) - return pixfmt == V4L2_PIX_FMT_NV12M && is_10bit; - } - -+/* Returns 1 if we are decoding using the IOMMU */ -+static inline int codec_hevc_use_mmu(u32 revision, u32 pixfmt, int is_10bit) -+{ -+ return revision >= VDEC_REVISION_G12A && -+ codec_hevc_use_fbc(pixfmt, is_10bit); -+} -+ - /** - * Configure decode head read mode - */ - void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit); - --void codec_hevc_free_fbc_buffers(struct amvdec_session *sess); -+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, -+ struct codec_hevc_common *comm); -+ -+int codec_hevc_setup_buffers(struct amvdec_session *sess, -+ struct codec_hevc_common *comm, -+ int is_10bit); - --int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit); -+void codec_hevc_fill_mmu_map(struct amvdec_session *sess, -+ struct codec_hevc_common *comm, -+ struct vb2_buffer *vb); - - #endif -\ No newline at end of file -diff --git a/drivers/media/platform/meson/vdec/codec_vp9.c b/drivers/media/platform/meson/vdec/codec_vp9.c -index 39e8eb5937bf0..b1643cc01f684 100644 ---- a/drivers/media/platform/meson/vdec/codec_vp9.c -+++ b/drivers/media/platform/meson/vdec/codec_vp9.c -@@ -219,6 +219,9 @@ struct vp9_frame { - struct codec_vp9 { - struct mutex lock; - -+ /* Common part with the HEVC decoder */ -+ struct codec_hevc_common common; -+ - /* Buffer for the VP9 Workspace */ - void *workspace_vaddr; - dma_addr_t workspace_paddr; -@@ -438,27 +441,26 @@ static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess) - return vp9->frames_num; - } - --static int --codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) -+static int codec_vp9_alloc_workspace(struct amvdec_core *core, -+ struct codec_vp9 *vp9) - { -- dma_addr_t wkaddr; -- - /* Allocate some memory for the VP9 decoder's state */ - vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, -- &wkaddr, GFP_KERNEL); -+ &vp9->workspace_paddr, GFP_KERNEL); - if (!vp9->workspace_vaddr) { - dev_err(core->dev, "Failed to allocate VP9 Workspace\n"); - return -ENOMEM; - } - -- memset(vp9->workspace_vaddr + DBLK_PARA_OFFSET, 0, DBLK_PARA_SIZE); -- memset(vp9->workspace_vaddr + COUNT_OFFSET, 0, COUNT_SIZE); -- memset(vp9->workspace_vaddr + PROB_OFFSET, 0, PROB_SIZE); -- -- printk("Workspace: %08X-%08X\n", wkaddr, wkaddr + SIZE_WORKSPACE); -- printk("DBLK_PARA: %08X\n", wkaddr + DBLK_PARA_OFFSET); -+ return 0; -+} - -- vp9->workspace_paddr = wkaddr; -+static void codec_vp9_setup_workspace(struct amvdec_session *sess, -+ struct codec_vp9 *vp9) -+{ -+ struct amvdec_core *core = sess->core; -+ u32 revision = core->platform->revision; -+ dma_addr_t wkaddr = vp9->workspace_paddr; - - amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); - amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET); -@@ -466,7 +468,6 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) - amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET); - amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET); - -- /* No MMU */ - amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER, - wkaddr + SWAP_BUF_OFFSET); - amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, -@@ -484,7 +485,19 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) - amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); - amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); - -- return 0; -+ if (codec_hevc_use_mmu(revision, sess->pixfmt_cap, vp9->is_10bit)) { -+ amvdec_write_dos(core, HEVC_SAO_MMU_VH0_ADDR, -+ wkaddr + MMU_VBH_OFFSET); -+ amvdec_write_dos(core, HEVC_SAO_MMU_VH1_ADDR, -+ wkaddr + MMU_VBH_OFFSET + (MMU_VBH_SIZE / 2)); -+ -+ if (revision >= VDEC_REVISION_G12A) -+ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, -+ vp9->common.mmu_map_paddr); -+ else -+ amvdec_write_dos(core, VP9_MMU_MAP_BUFFER, -+ vp9->common.mmu_map_paddr); -+ } - } - - static int codec_vp9_start(struct amvdec_session *sess) -@@ -499,10 +512,11 @@ static int codec_vp9_start(struct amvdec_session *sess) - if (!vp9) - return -ENOMEM; - -- ret = codec_vp9_setup_workspace(core, vp9); -+ ret = codec_vp9_alloc_workspace(core, vp9); - if (ret) - goto free_vp9; - -+ codec_vp9_setup_workspace(sess, vp9); - amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); - // stream_fifo_hole - if (core->platform->revision == VDEC_REVISION_G12A) -@@ -575,7 +589,7 @@ static int codec_vp9_stop(struct amvdec_session *sess) - vp9->workspace_vaddr, - vp9->workspace_paddr); - -- codec_hevc_free_fbc_buffers(sess); -+ codec_hevc_free_fbc_buffers(sess, &vp9->common); - return 0; - } - -@@ -590,7 +604,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb - - if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit)) - buf_y_paddr = -- sess->fbc_buffer_paddr[vb->index]; -+ vp9->common.fbc_buffer_paddr[vb->index]; - else - buf_y_paddr = - vb2_dma_contig_plane_dma_addr(vb, 0); -@@ -601,6 +615,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb - amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); - } - -+ - if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { - buf_y_paddr = - vb2_dma_contig_plane_dma_addr(vb, 0); -@@ -612,13 +627,22 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb - amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); - } - -+ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap, -+ vp9->is_10bit)) { -+ amvdec_write_dos(core, HEVC_CM_HEADER_START_ADDR, -+ vp9->common.mmu_header_paddr[vb->index]); -+ /* use HEVC_CM_HEADER_START_ADDR */ -+ amvdec_write_dos_bits(core, HEVC_SAO_CTRL5, BIT(10)); -+ } -+ - amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, - amvdec_get_output_size(sess)); - amvdec_write_dos(core, HEVC_SAO_C_LENGTH, - (amvdec_get_output_size(sess) / 2)); - - if (core->platform->revision >= VDEC_REVISION_G12A) { -- amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, BIT(4) | BIT(5) | BIT(8) | BIT(9)); -+ amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, -+ BIT(4) | BIT(5) | BIT(8) | BIT(9)); - /* enable first, compressed write */ - if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) - amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8)); -@@ -630,8 +654,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb - /* dblk pipeline mode=1 for performance */ - if (sess->width >= 1280) - amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4)); -- -- printk("HEVC_DBLK_CFGB: %08X\n", amvdec_read_dos(core, HEVC_DBLK_CFGB)); - } - - val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; -@@ -644,7 +666,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb - } - - amvdec_write_dos(core, HEVC_SAO_CTRL1, val); -- printk("HEVC_SAO_CTRL1: %08X\n", val); - - if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { - /* no downscale for NV12 */ -@@ -919,6 +940,11 @@ static void codec_vp9_process_frame(struct amvdec_session *sess) - codec_vp9_update_next_ref(vp9); - codec_vp9_show_existing_frame(vp9); - -+ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap, -+ vp9->is_10bit)) -+ codec_hevc_fill_mmu_map(sess, &vp9->common, -+ &vp9->cur_frame->vbuf->vb2_buf); -+ - intra_only = param->p.show_frame ? 0 : param->p.intra_only; - /* clear mpred (for keyframe only) */ - if (param->p.frame_type != KEY_FRAME && !intra_only) { -@@ -971,11 +997,12 @@ static void codec_vp9_resume(struct amvdec_session *sess) - { - struct codec_vp9 *vp9 = sess->priv; - -- if (codec_hevc_setup_buffers(sess, vp9->is_10bit)) { -+ if (codec_hevc_setup_buffers(sess, &vp9->common, vp9->is_10bit)) { - amvdec_abort(sess); - return; - } - -+ codec_vp9_setup_workspace(sess, vp9); - codec_hevc_setup_decode_head(sess, vp9->is_10bit); - codec_vp9_process_lf(vp9); - codec_vp9_process_frame(sess); -diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h -index dc2c2e085b051..0392f41a1eed5 100644 ---- a/drivers/media/platform/meson/vdec/hevc_regs.h -+++ b/drivers/media/platform/meson/vdec/hevc_regs.h -@@ -6,6 +6,8 @@ - #ifndef __MESON_VDEC_HEVC_REGS_H_ - #define __MESON_VDEC_HEVC_REGS_H_ - -+#define HEVC_ASSIST_MMU_MAP_ADDR 0xc024 -+ - #define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4 - #define HEVC_ASSIST_MBOX1_MASK 0xc1d8 - -@@ -200,8 +202,11 @@ - #define HEVC_SAO_CTRL7 0xd894 - #define HEVC_CM_BODY_START_ADDR 0xd898 - #define HEVC_CM_BODY_LENGTH 0xd89c -+#define HEVC_CM_HEADER_START_ADDR 0xd8a0 - #define HEVC_CM_HEADER_LENGTH 0xd8a4 - #define HEVC_CM_HEADER_OFFSET 0xd8ac -+#define HEVC_SAO_MMU_VH0_ADDR 0xd8e8 -+#define HEVC_SAO_MMU_VH1_ADDR 0xd8ec - - #define HEVC_IQIT_CLK_RST_CTRL 0xdc00 - #define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08 -diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h -index 69a5f82ae80f2..4d156159541f1 100644 ---- a/drivers/media/platform/meson/vdec/vdec.h -+++ b/drivers/media/platform/meson/vdec/vdec.h -@@ -19,8 +19,6 @@ - /* 32 buffers in 3-plane YUV420 */ - #define MAX_CANVAS (32 * 3) - --#define MAX_REF_PIC_NUM 24 -- - struct amvdec_buffer { - struct list_head list; - struct vb2_buffer *vb; -@@ -260,9 +258,6 @@ struct amvdec_session { - u32 dpb_size; - u32 fw_idx_to_vb2_idx[32]; - -- void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; -- dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; -- - enum amvdec_status status; - void *priv; - }; -diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.c b/drivers/media/platform/meson/vdec/vdec_hevc.c -index a706dbf3ae8c4..a26e9a02e0f55 100644 ---- a/drivers/media/platform/meson/vdec/vdec_hevc.c -+++ b/drivers/media/platform/meson/vdec/vdec_hevc.c -@@ -123,9 +123,9 @@ static int vdec_hevc_stop(struct amvdec_session *sess) - regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); - -+ clk_disable_unprepare(core->vdec_hevc_clk); - if (core->platform->revision == VDEC_REVISION_G12A) - clk_disable_unprepare(core->vdec_hevcf_clk); -- clk_disable_unprepare(core->vdec_hevc_clk); - - return 0; - } -@@ -136,11 +136,6 @@ static int vdec_hevc_start(struct amvdec_session *sess) - struct amvdec_core *core = sess->core; - struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; - -- clk_set_rate(core->vdec_hevc_clk, 666666666); -- ret = clk_prepare_enable(core->vdec_hevc_clk); -- if (ret) -- return ret; -- - if (core->platform->revision == VDEC_REVISION_G12A) { - clk_set_rate(core->vdec_hevcf_clk, 666666666); - ret = clk_prepare_enable(core->vdec_hevcf_clk); -@@ -148,6 +143,11 @@ static int vdec_hevc_start(struct amvdec_session *sess) - return ret; - } - -+ clk_set_rate(core->vdec_hevc_clk, 666666666); -+ ret = clk_prepare_enable(core->vdec_hevc_clk); -+ if (ret) -+ return ret; -+ - regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VDEC_HEVC, 0); - udelay(10); -@@ -177,7 +177,7 @@ static int vdec_hevc_start(struct amvdec_session *sess) - if (ret) - goto stop; - -- amvdec_write_dos(core, DOS_SW_RESET3, BIT(12)|BIT(11)); -+ amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11)); - amvdec_write_dos(core, DOS_SW_RESET3, 0); - amvdec_read_dos(core, DOS_SW_RESET3); - - -From 493a663243f42b86374cbd61cdcd9344f1a863b0 Mon Sep 17 00:00:00 2001 -From: Maxime Jourdan -Date: Tue, 5 Feb 2019 14:34:45 +0100 -Subject: [PATCH 222/249] WIP: arm64: dts: meson-g12a: add video decoder node - -Signed-off-by: Maxime Jourdan ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 23 +++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index 29db6ce2ccbb2..f57beffac1486 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -2165,6 +2165,29 @@ - }; - }; - -+ vdec: video-decoder@ff620000 { -+ compatible = "amlogic,g12a-vdec"; -+ reg = <0x0 0xff620000 0x0 0x10000>, -+ <0x0 0xffd0e180 0x0 0xe4>; -+ reg-names = "dos", "esparser"; -+ -+ interrupts = , -+ ; -+ interrupt-names = "vdec", "esparser"; -+ -+ amlogic,ao-sysctrl = <&rti>; -+ amlogic,canvas = <&canvas>; -+ -+ clocks = <&clkc CLKID_PARSER>, -+ <&clkc CLKID_DOS>, -+ <&clkc CLKID_VDEC_1>, -+ <&clkc CLKID_VDEC_HEVC>, -+ <&clkc CLKID_VDEC_HEVCF>; -+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc", "vdec_hevcf"; -+ resets = <&reset RESET_PARSER>; -+ reset-names = "esparser"; -+ }; -+ - vpu: vpu@ff900000 { - compatible = "amlogic,meson-g12a-vpu"; - reg = <0x0 0xff900000 0x0 0x100000>, - -From 8e35d74a7a0b3c6d855627b637ef773f6ccc7299 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 16 May 2019 15:25:03 +0200 -Subject: [PATCH 223/249] WIP: arm64: dts: meson-g12a-x96-max: add Audio nodes - for HDMI and S/PDIF - ---- - .../boot/dts/amlogic/meson-g12a-x96-max.dts | 164 ++++++++++++++++++ - 1 file changed, 164 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -index 648b7deed22d7..5776db88aa94b 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts -@@ -17,6 +17,14 @@ - serial0 = &uart_AO; - ethernet0 = ðmac; - }; -+ -+ spdif_dit: audio-codec-1 { -+ #sound-dai-cells = <0>; -+ compatible = "linux,spdif-dit"; -+ status = "okay"; -+ sound-name-prefix = "DIT"; -+ }; -+ - chosen { - stdout-path = "serial0:115200n8"; - }; -@@ -123,6 +131,99 @@ - regulator-always-on; - }; - -+ sound { -+ compatible = "amlogic,axg-sound-card"; -+ model = "G12A-X96-MAX"; -+ audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmout_c>; -+ audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", -+ "TDMOUT_A IN 1", "FRDDR_B OUT 0", -+ "TDMOUT_A IN 2", "FRDDR_C OUT 0", -+ "TDM_A Playback", "TDMOUT_A OUT", -+ "TDMOUT_B IN 0", "FRDDR_A OUT 1", -+ "TDMOUT_B IN 1", "FRDDR_B OUT 1", -+ "TDMOUT_B IN 2", "FRDDR_C OUT 1", -+ "TDM_B Playback", "TDMOUT_B OUT", -+ "TDMOUT_C IN 0", "FRDDR_A OUT 2", -+ "TDMOUT_C IN 1", "FRDDR_B OUT 2", -+ "TDMOUT_C IN 2", "FRDDR_C OUT 2", -+ "TDM_C Playback", "TDMOUT_C OUT", -+ "SPDIFOUT IN 0", "FRDDR_A OUT 3", -+ "SPDIFOUT IN 1", "FRDDR_B OUT 3", -+ "SPDIFOUT IN 2", "FRDDR_C OUT 3"; -+ -+ assigned-clocks = <&clkc CLKID_HIFI_PLL>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <589824000>, -+ <270950400>, -+ <393216000>; -+ -+ status = "okay"; -+ -+ dai-link-0 { -+ sound-dai = <&frddr_a>; -+ }; -+ -+ dai-link-1 { -+ sound-dai = <&frddr_b>; -+ }; -+ -+ dai-link-2 { -+ sound-dai = <&frddr_c>; -+ }; -+ -+ dai-link-3 { -+ sound-dai = <&tdmif_a>; -+ dai-format = "i2s"; -+ dai-tdm-slot-tx-mask-0 = <1 1>; -+ mclk-fs = <256>; -+ -+ codec@1 { -+ sound-dai = <&tohdmitx 0>; -+ }; -+ }; -+ -+ dai-link-4 { -+ sound-dai = <&tdmif_b>; -+ dai-format = "i2s"; -+ dai-tdm-slot-tx-mask-0 = <1 1>; -+ mclk-fs = <256>; -+ -+ codec@1 { -+ sound-dai = <&tohdmitx 1>; -+ }; -+ }; -+ -+ dai-link-5 { -+ sound-dai = <&spdifout>; -+ -+ codec@0 { -+ sound-dai = <&spdif_dit>; -+ }; -+ -+ codec@1 { -+ sound-dai = <&tohdmitx 4>; -+ }; -+ }; -+ -+ dai-link-6 { -+ sound-dai = <&spdifout_b>; -+ -+ codec { -+ sound-dai = <&tohdmitx 5>; -+ }; -+ }; -+ -+ dai-link-7 { -+ sound-dai = <&tohdmitx 3>; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+ - wifi32k: wifi32k { - compatible = "pwm-clock"; - #clock-cells = <0>; -@@ -131,6 +232,10 @@ - }; - }; - -+&arb { -+ status = "okay"; -+}; -+ - &cec_AO { - pinctrl-0 = <&cec_ao_a_h_pins>; - pinctrl-names = "default"; -@@ -145,12 +250,28 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&clkc_audio { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; - }; - }; - -+&frddr_a { -+ status = "okay"; -+}; -+ -+&frddr_b { -+ status = "okay"; -+}; -+ -+&frddr_c { -+ status = "okay"; -+}; -+ - &hdmi_tx { - status = "okay"; - pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -@@ -282,3 +403,46 @@ - vmmc-supply = <&vcc_3v3>; - vqmmc-supply = <&flash_1v8>; - }; -+ -+&spdifout { -+ pinctrl-0 = <&spdif_out_h_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&spdifout_b { -+ status = "okay"; -+}; -+ -+&tdmif_a { -+ pinctrl-0 = <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>, <&tdm_a_dout0_pins> ; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&tdmif_b { -+ pinctrl-0 = <&mclk0_a_pins>, <&tdm_b_fs_pins>, <&tdm_b_sclk_pins>, -+ <&tdm_b_dout0_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+}; -+ -+&tdmif_c { -+ status = "okay"; -+}; -+ -+&tdmout_a { -+ status = "okay"; -+}; -+ -+&tdmout_b { -+ status = "okay"; -+}; -+ -+&tdmout_c { -+ status = "okay"; -+}; -+ -+&tohdmitx { -+ status = "okay"; -+}; - -From be17028cf3bfa6b3a5ec8c4cf958a5178460b303 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 16 May 2019 17:04:21 +0200 -Subject: [PATCH 224/249] WIP: dts: meson: g12a: Add hwrng node - ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index f57beffac1486..c734324069e4f 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -198,6 +198,19 @@ - }; - }; - -+ apb_efuse: bus@30000 { -+ compatible = "simple-bus"; -+ reg = <0x0 0x30000 0x0 0x1000>; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges = <0x0 0x0 0x0 0x30000 0x0 0x1000>; -+ -+ hwrng: rng { -+ compatible = "amlogic,meson-rng"; -+ reg = <0x0 0x218 0x0 0x4>; -+ }; -+ }; -+ - periphs: bus@34400 { - compatible = "simple-bus"; - reg = <0x0 0x34400 0x0 0x400>; - -From 6d1fae305d2b70e389eabaef0a0c71cd11ba4d67 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 16 May 2019 17:34:22 +0200 -Subject: [PATCH 225/249] WIP: drm/meson: fix primary plane disabling - ---- - drivers/gpu/drm/meson/meson_crtc.c | 4 ---- - drivers/gpu/drm/meson/meson_plane.c | 4 +++- - 2 files changed, 3 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c -index 5579f8ac3e3f7..58f7abdc2299f 100644 ---- a/drivers/gpu/drm/meson/meson_crtc.c -+++ b/drivers/gpu/drm/meson/meson_crtc.c -@@ -119,8 +119,6 @@ static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, - priv->io_base + _REG(VPP_OUT_H_V_SIZE)); - - drm_crtc_vblank_on(crtc); -- -- priv->viu.osd1_enabled = true; - } - - static void meson_crtc_atomic_enable(struct drm_crtc *crtc, -@@ -149,8 +147,6 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, - priv->io_base + _REG(VPP_MISC)); - - drm_crtc_vblank_on(crtc); -- -- priv->viu.osd1_enabled = true; - } - - static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, -diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c -index 2f7f4dfce45be..9c3e522d31840 100644 ---- a/drivers/gpu/drm/meson/meson_plane.c -+++ b/drivers/gpu/drm/meson/meson_plane.c -@@ -331,6 +331,8 @@ static void meson_plane_atomic_update(struct drm_plane *plane, - meson_plane->enabled = true; - } - -+ priv->viu.osd1_enabled = true; -+ - spin_unlock_irqrestore(&priv->drm->event_lock, flags); - } - -@@ -349,7 +351,7 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, - priv->io_base + _REG(VPP_MISC)); - - meson_plane->enabled = false; -- -+ priv->viu.osd1_enabled = false; - } - - static const struct drm_plane_helper_funcs meson_plane_helper_funcs = { - -From d6aa8bfca2a4fc3c36b1343aa53f4fb7a5377a83 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Fri, 17 May 2019 11:38:01 +0200 -Subject: [PATCH 226/249] HACK: arm64: dts: : g12a: set cma pool to 896MB - ---- - arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -index c734324069e4f..bd85b604c78e7 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi -@@ -122,7 +122,7 @@ - linux,cma { - compatible = "shared-dma-pool"; - reusable; -- size = <0x0 0x10000000>; -+ size = <0x0 0x38000000>; - alignment = <0x0 0x400000>; - linux,cma-default; - }; - -From 6bd2d756676ab2103be444ecbc459a7ba120f13b Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Mon, 13 Nov 2017 12:09:40 +0100 -Subject: [PATCH 227/249] ARM64: defconfig: enable CEC support - -Turn on CONFIG_CEC_SUPPORT and CONFIG_CEC_PLATFORM_DRIVERS -Turn on CONFIG_VIDEO_MESON_AO_CEC as module -Turn on CONFIG_DRM_DW_HDMI_CEC as module - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - arch/arm64/configs/defconfig | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 2d9c39033c1aa..552868cb15ae5 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -469,6 +469,7 @@ CONFIG_MEDIA_SUPPORT=m - CONFIG_MEDIA_CAMERA_SUPPORT=y - CONFIG_MEDIA_ANALOG_TV_SUPPORT=y - CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -+CONFIG_MEDIA_CEC_SUPPORT=y - CONFIG_MEDIA_CONTROLLER=y - CONFIG_VIDEO_V4L2_SUBDEV_API=y - # CONFIG_DVB_NET is not set -@@ -482,6 +483,8 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m - CONFIG_VIDEO_SUN6I_CSI=m - CONFIG_VIDEO_RENESAS_FCP=m - CONFIG_VIDEO_RENESAS_VSP1=m -+CONFIG_CEC_PLATFORM_DRIVERS=y -+CONFIG_VIDEO_MESON_AO_CEC=m - CONFIG_DRM=m - CONFIG_DRM_NOUVEAU=m - CONFIG_DRM_EXYNOS=m -@@ -506,6 +509,7 @@ CONFIG_DRM_TEGRA=m - CONFIG_DRM_PANEL_SIMPLE=m - CONFIG_DRM_SII902X=m - CONFIG_DRM_I2C_ADV7511=m -+CONFIG_DRM_DW_HDMI_CEC=m - CONFIG_DRM_VC4=m - CONFIG_DRM_HISI_HIBMC=m - CONFIG_DRM_HISI_KIRIN=m - -From 55b9d37fe09e6608a53083a87b8c77dc678ee53c Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 30 Mar 2017 11:49:55 +0200 -Subject: [PATCH 228/249] ASoC: meson: add meson audio core driver - -This patch adds support for the audio core driver for the Amlogic Meson SoC -family. The purpose of this driver is to properly reset the audio block and -provide register access for the different devices scattered in this address -space. This includes output and input DMAs, pcm, i2s and spdif dai, card -level routing, internal codec for the gxl variant - -For more information, please refer to the section 5 of the public datasheet -of the S905 (gxbb). This datasheet is available here: [0]. - -[0]: http://dn.odroid.com/S905/DataSheet/S905_Public_Datasheet_V1.1.4.pdf - -Signed-off-by: Jerome Brunet ---- - sound/soc/Kconfig | 1 + - sound/soc/Makefile | 1 + - sound/soc/meson-gx/Kconfig | 11 ++ - sound/soc/meson-gx/Makefile | 3 + - sound/soc/meson-gx/audio-core.c | 180 ++++++++++++++++++++++++++++++++ - sound/soc/meson-gx/audio-core.h | 28 +++++ - 6 files changed, 224 insertions(+) - create mode 100644 sound/soc/meson-gx/Kconfig - create mode 100644 sound/soc/meson-gx/Makefile - create mode 100644 sound/soc/meson-gx/audio-core.c - create mode 100644 sound/soc/meson-gx/audio-core.h - -diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig -index aa35940f5c50b..06040d2db0ae6 100644 ---- a/sound/soc/Kconfig -+++ b/sound/soc/Kconfig -@@ -56,6 +56,7 @@ source "sound/soc/img/Kconfig" - source "sound/soc/intel/Kconfig" - source "sound/soc/mediatek/Kconfig" - source "sound/soc/meson/Kconfig" -+source "sound/soc/meson-gx/Kconfig" - source "sound/soc/mxs/Kconfig" - source "sound/soc/pxa/Kconfig" - source "sound/soc/qcom/Kconfig" -diff --git a/sound/soc/Makefile b/sound/soc/Makefile -index 974fb9821e172..9cd12249b0e87 100644 ---- a/sound/soc/Makefile -+++ b/sound/soc/Makefile -@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += img/ - obj-$(CONFIG_SND_SOC) += intel/ - obj-$(CONFIG_SND_SOC) += mediatek/ - obj-$(CONFIG_SND_SOC) += meson/ -+obj-$(CONFIG_SND_SOC) += meson-gx/ - obj-$(CONFIG_SND_SOC) += mxs/ - obj-$(CONFIG_SND_SOC) += nuc900/ - obj-$(CONFIG_SND_SOC) += kirkwood/ -diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig -new file mode 100644 -index 0000000000000..280e49e7c16fe ---- /dev/null -+++ b/sound/soc/meson-gx/Kconfig -@@ -0,0 +1,11 @@ -+menuconfig SND_SOC_MESON_GX -+ tristate "ASoC WIP support for Amlogic GX SoCs" -+ depends on ARCH_MESON -+ select MFD_CORE -+ select REGMAP_MMIO -+ help -+ Say Y or M if you want to add support for codecs attached to -+ the Amlogic Meson SoCs Audio interfaces. You will also need to -+ select the audio interfaces to support below. This WIP drivers -+ are kept separated from the actual upstream amlogic ASoC driver -+ to minimize conflicts until support is submitted and merged -diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile -new file mode 100644 -index 0000000000000..6f124c31a85cc ---- /dev/null -+++ b/sound/soc/meson-gx/Makefile -@@ -0,0 +1,3 @@ -+snd-soc-meson-audio-core-objs := audio-core.o -+ -+obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o -diff --git a/sound/soc/meson-gx/audio-core.c b/sound/soc/meson-gx/audio-core.c -new file mode 100644 -index 0000000000000..68f7e0e58f5f2 ---- /dev/null -+++ b/sound/soc/meson-gx/audio-core.c -@@ -0,0 +1,180 @@ -+/* -+ * Copyright (C) 2017 BayLibre, SAS -+ * Author: Jerome Brunet -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "audio-core.h" -+ -+#define DRV_NAME "meson-gx-audio-core" -+ -+static const char * const acore_clock_names[] = { "aiu_top", -+ "aiu_glue", -+ "audin" }; -+ -+static int meson_acore_init_clocks(struct device *dev) -+{ -+ struct clk *clock; -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(acore_clock_names); i++) { -+ clock = devm_clk_get(dev, acore_clock_names[i]); -+ if (IS_ERR(clock)) { -+ if (PTR_ERR(clock) != -EPROBE_DEFER) -+ dev_err(dev, "Failed to get %s clock\n", -+ acore_clock_names[i]); -+ return PTR_ERR(clock); -+ } -+ -+ ret = clk_prepare_enable(clock); -+ if (ret) { -+ dev_err(dev, "Failed to enable %s clock\n", -+ acore_clock_names[i]); -+ return ret; -+ } -+ -+ ret = devm_add_action_or_reset(dev, -+ (void(*)(void *))clk_disable_unprepare, -+ clock); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const char * const acore_reset_names[] = { "aiu", -+ "audin" }; -+ -+static int meson_acore_init_resets(struct device *dev) -+{ -+ struct reset_control *reset; -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(acore_reset_names); i++) { -+ reset = devm_reset_control_get_exclusive(dev, -+ acore_reset_names[i]); -+ if (IS_ERR(reset)) { -+ if (PTR_ERR(reset) != -EPROBE_DEFER) -+ dev_err(dev, "Failed to get %s reset\n", -+ acore_reset_names[i]); -+ return PTR_ERR(reset); -+ } -+ -+ ret = reset_control_reset(reset); -+ if (ret) { -+ dev_err(dev, "Failed to pulse %s reset\n", -+ acore_reset_names[i]); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct regmap_config meson_acore_regmap_config = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+}; -+ -+static const struct mfd_cell meson_acore_devs[] = { -+ { -+ .name = "meson-aiu-i2s", -+ .of_compatible = "amlogic,meson-aiu-i2s", -+ }, -+ { -+ .name = "meson-aiu-spdif", -+ .of_compatible = "amlogic,meson-aiu-spdif", -+ }, -+}; -+ -+static int meson_acore_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct meson_audio_core_data *data; -+ struct resource *res; -+ void __iomem *regs; -+ int ret; -+ -+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ platform_set_drvdata(pdev, data); -+ -+ ret = meson_acore_init_clocks(dev); -+ if (ret) -+ return ret; -+ -+ ret = meson_acore_init_resets(dev); -+ if (ret) -+ return ret; -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aiu"); -+ regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); -+ -+ data->aiu = devm_regmap_init_mmio(dev, regs, -+ &meson_acore_regmap_config); -+ if (IS_ERR(data->aiu)) { -+ dev_err(dev, "Couldn't create the AIU regmap\n"); -+ return PTR_ERR(data->aiu); -+ } -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audin"); -+ regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); -+ -+ data->audin = devm_regmap_init_mmio(dev, regs, -+ &meson_acore_regmap_config); -+ if (IS_ERR(data->audin)) { -+ dev_err(dev, "Couldn't create the AUDIN regmap\n"); -+ return PTR_ERR(data->audin); -+ } -+ -+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, meson_acore_devs, -+ ARRAY_SIZE(meson_acore_devs), NULL, 0, -+ NULL); -+} -+ -+static const struct of_device_id meson_acore_of_match[] = { -+ { .compatible = "amlogic,meson-gx-audio-core", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, meson_acore_of_match); -+ -+static struct platform_driver meson_acore_pdrv = { -+ .probe = meson_acore_probe, -+ .driver = { -+ .name = DRV_NAME, -+ .of_match_table = meson_acore_of_match, -+ }, -+}; -+module_platform_driver(meson_acore_pdrv); -+ -+MODULE_DESCRIPTION("Meson Audio Core Driver"); -+MODULE_AUTHOR("Jerome Brunet "); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/meson-gx/audio-core.h b/sound/soc/meson-gx/audio-core.h -new file mode 100644 -index 0000000000000..6e7a24cdc4a96 ---- /dev/null -+++ b/sound/soc/meson-gx/audio-core.h -@@ -0,0 +1,28 @@ -+/* -+ * Copyright (C) 2017 BayLibre, SAS -+ * Author: Jerome Brunet -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#ifndef _MESON_AUDIO_CORE_H_ -+#define _MESON_AUDIO_CORE_H_ -+ -+struct meson_audio_core_data { -+ struct regmap *aiu; -+ struct regmap *audin; -+}; -+ -+#endif /* _MESON_AUDIO_CORE_H_ */ - -From 057449a391589c802de24317d461e0a8ac61c7d1 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 30 Mar 2017 12:00:10 +0200 -Subject: [PATCH 229/249] ASoC: meson: add register definitions - -Add the register definition for the AIU and AUDIN blocks - -Signed-off-by: Jerome Brunet ---- - sound/soc/meson-gx/aiu-regs.h | 182 ++++++++++++++++++++++++++++++++ - sound/soc/meson-gx/audin-regs.h | 148 ++++++++++++++++++++++++++ - 2 files changed, 330 insertions(+) - create mode 100644 sound/soc/meson-gx/aiu-regs.h - create mode 100644 sound/soc/meson-gx/audin-regs.h - -diff --git a/sound/soc/meson-gx/aiu-regs.h b/sound/soc/meson-gx/aiu-regs.h -new file mode 100644 -index 0000000000000..67391e64fe1c2 ---- /dev/null -+++ b/sound/soc/meson-gx/aiu-regs.h -@@ -0,0 +1,182 @@ -+/* -+ * Copyright (C) 2017 BayLibre, SAS -+ * Author: Jerome Brunet -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#ifndef _AIU_REGS_H_ -+#define _AIU_REGS_H_ -+ -+#define AIU_958_BPF 0x000 -+#define AIU_958_BRST 0x004 -+#define AIU_958_LENGTH 0x008 -+#define AIU_958_PADDSIZE 0x00C -+#define AIU_958_MISC 0x010 -+#define AIU_958_FORCE_LEFT 0x014 /* Unknown */ -+#define AIU_958_DISCARD_NUM 0x018 -+#define AIU_958_DCU_FF_CTRL 0x01C -+#define AIU_958_CHSTAT_L0 0x020 -+#define AIU_958_CHSTAT_L1 0x024 -+#define AIU_958_CTRL 0x028 -+#define AIU_958_RPT 0x02C -+#define AIU_I2S_MUTE_SWAP 0x030 -+#define AIU_I2S_SOURCE_DESC 0x034 -+#define AIU_I2S_MED_CTRL 0x038 -+#define AIU_I2S_MED_THRESH 0x03C -+#define AIU_I2S_DAC_CFG 0x040 -+#define AIU_I2S_SYNC 0x044 /* Unknown */ -+#define AIU_I2S_MISC 0x048 -+#define AIU_I2S_OUT_CFG 0x04C -+#define AIU_I2S_FF_CTRL 0x050 /* Unknown */ -+#define AIU_RST_SOFT 0x054 -+#define AIU_CLK_CTRL 0x058 -+#define AIU_MIX_ADCCFG 0x05C -+#define AIU_MIX_CTRL 0x060 -+#define AIU_CLK_CTRL_MORE 0x064 -+#define AIU_958_POP 0x068 -+#define AIU_MIX_GAIN 0x06C -+#define AIU_958_SYNWORD1 0x070 -+#define AIU_958_SYNWORD2 0x074 -+#define AIU_958_SYNWORD3 0x078 -+#define AIU_958_SYNWORD1_MASK 0x07C -+#define AIU_958_SYNWORD2_MASK 0x080 -+#define AIU_958_SYNWORD3_MASK 0x084 -+#define AIU_958_FFRDOUT_THD 0x088 -+#define AIU_958_LENGTH_PER_PAUSE 0x08C -+#define AIU_958_PAUSE_NUM 0x090 -+#define AIU_958_PAUSE_PAYLOAD 0x094 -+#define AIU_958_AUTO_PAUSE 0x098 -+#define AIU_958_PAUSE_PD_LENGTH 0x09C -+#define AIU_CODEC_DAC_LRCLK_CTRL 0x0A0 -+#define AIU_CODEC_ADC_LRCLK_CTRL 0x0A4 -+#define AIU_HDMI_CLK_DATA_CTRL 0x0A8 -+#define AIU_CODEC_CLK_DATA_CTRL 0x0AC -+#define AIU_ACODEC_CTRL 0x0B0 -+#define AIU_958_CHSTAT_R0 0x0C0 -+#define AIU_958_CHSTAT_R1 0x0C4 -+#define AIU_958_VALID_CTRL 0x0C8 -+#define AIU_AUDIO_AMP_REG0 0x0F0 /* Unknown */ -+#define AIU_AUDIO_AMP_REG1 0x0F4 /* Unknown */ -+#define AIU_AUDIO_AMP_REG2 0x0F8 /* Unknown */ -+#define AIU_AUDIO_AMP_REG3 0x0FC /* Unknown */ -+#define AIU_AIFIFO2_CTRL 0x100 -+#define AIU_AIFIFO2_STATUS 0x104 -+#define AIU_AIFIFO2_GBIT 0x108 -+#define AIU_AIFIFO2_CLB 0x10C -+#define AIU_CRC_CTRL 0x110 -+#define AIU_CRC_STATUS 0x114 -+#define AIU_CRC_SHIFT_REG 0x118 -+#define AIU_CRC_IREG 0x11C -+#define AIU_CRC_CAL_REG1 0x120 -+#define AIU_CRC_CAL_REG0 0x124 -+#define AIU_CRC_POLY_COEF1 0x128 -+#define AIU_CRC_POLY_COEF0 0x12C -+#define AIU_CRC_BIT_SIZE1 0x130 -+#define AIU_CRC_BIT_SIZE0 0x134 -+#define AIU_CRC_BIT_CNT1 0x138 -+#define AIU_CRC_BIT_CNT0 0x13C -+#define AIU_AMCLK_GATE_HI 0x140 -+#define AIU_AMCLK_GATE_LO 0x144 -+#define AIU_AMCLK_MSR 0x148 -+#define AIU_AUDAC_CTRL0 0x14C /* Unknown */ -+#define AIU_DELTA_SIGMA0 0x154 /* Unknown */ -+#define AIU_DELTA_SIGMA1 0x158 /* Unknown */ -+#define AIU_DELTA_SIGMA2 0x15C /* Unknown */ -+#define AIU_DELTA_SIGMA3 0x160 /* Unknown */ -+#define AIU_DELTA_SIGMA4 0x164 /* Unknown */ -+#define AIU_DELTA_SIGMA5 0x168 /* Unknown */ -+#define AIU_DELTA_SIGMA6 0x16C /* Unknown */ -+#define AIU_DELTA_SIGMA7 0x170 /* Unknown */ -+#define AIU_DELTA_SIGMA_LCNTS 0x174 /* Unknown */ -+#define AIU_DELTA_SIGMA_RCNTS 0x178 /* Unknown */ -+#define AIU_MEM_I2S_START_PTR 0x180 -+#define AIU_MEM_I2S_RD_PTR 0x184 -+#define AIU_MEM_I2S_END_PTR 0x188 -+#define AIU_MEM_I2S_MASKS 0x18C -+#define AIU_MEM_I2S_CONTROL 0x190 -+#define AIU_MEM_IEC958_START_PTR 0x194 -+#define AIU_MEM_IEC958_RD_PTR 0x198 -+#define AIU_MEM_IEC958_END_PTR 0x19C -+#define AIU_MEM_IEC958_MASKS 0x1A0 -+#define AIU_MEM_IEC958_CONTROL 0x1A4 -+#define AIU_MEM_AIFIFO2_START_PTR 0x1A8 -+#define AIU_MEM_AIFIFO2_CURR_PTR 0x1AC -+#define AIU_MEM_AIFIFO2_END_PTR 0x1B0 -+#define AIU_MEM_AIFIFO2_BYTES_AVAIL 0x1B4 -+#define AIU_MEM_AIFIFO2_CONTROL 0x1B8 -+#define AIU_MEM_AIFIFO2_MAN_WP 0x1BC -+#define AIU_MEM_AIFIFO2_MAN_RP 0x1C0 -+#define AIU_MEM_AIFIFO2_LEVEL 0x1C4 -+#define AIU_MEM_AIFIFO2_BUF_CNTL 0x1C8 -+#define AIU_MEM_I2S_MAN_WP 0x1CC -+#define AIU_MEM_I2S_MAN_RP 0x1D0 -+#define AIU_MEM_I2S_LEVEL 0x1D4 -+#define AIU_MEM_I2S_BUF_CNTL 0x1D8 -+#define AIU_MEM_I2S_BUF_WRAP_COUNT 0x1DC -+#define AIU_MEM_I2S_MEM_CTL 0x1E0 -+#define AIU_MEM_IEC958_MEM_CTL 0x1E4 -+#define AIU_MEM_IEC958_WRAP_COUNT 0x1E8 -+#define AIU_MEM_IEC958_IRQ_LEVEL 0x1EC -+#define AIU_MEM_IEC958_MAN_WP 0x1F0 -+#define AIU_MEM_IEC958_MAN_RP 0x1F4 -+#define AIU_MEM_IEC958_LEVEL 0x1F8 -+#define AIU_MEM_IEC958_BUF_CNTL 0x1FC -+#define AIU_AIFIFO_CTRL 0x200 -+#define AIU_AIFIFO_STATUS 0x204 -+#define AIU_AIFIFO_GBIT 0x208 -+#define AIU_AIFIFO_CLB 0x20C -+#define AIU_MEM_AIFIFO_START_PTR 0x210 -+#define AIU_MEM_AIFIFO_CURR_PTR 0x214 -+#define AIU_MEM_AIFIFO_END_PTR 0x218 -+#define AIU_MEM_AIFIFO_BYTES_AVAIL 0x21C -+#define AIU_MEM_AIFIFO_CONTROL 0x220 -+#define AIU_MEM_AIFIFO_MAN_WP 0x224 -+#define AIU_MEM_AIFIFO_MAN_RP 0x228 -+#define AIU_MEM_AIFIFO_LEVEL 0x22C -+#define AIU_MEM_AIFIFO_BUF_CNTL 0x230 -+#define AIU_MEM_AIFIFO_BUF_WRAP_COUNT 0x234 -+#define AIU_MEM_AIFIFO2_BUF_WRAP_COUNT 0x238 -+#define AIU_MEM_AIFIFO_MEM_CTL 0x23C -+#define AIFIFO_TIME_STAMP_CNTL 0x240 -+#define AIFIFO_TIME_STAMP_SYNC_0 0x244 -+#define AIFIFO_TIME_STAMP_SYNC_1 0x248 -+#define AIFIFO_TIME_STAMP_0 0x24C -+#define AIFIFO_TIME_STAMP_1 0x250 -+#define AIFIFO_TIME_STAMP_2 0x254 -+#define AIFIFO_TIME_STAMP_3 0x258 -+#define AIFIFO_TIME_STAMP_LENGTH 0x25C -+#define AIFIFO2_TIME_STAMP_CNTL 0x260 -+#define AIFIFO2_TIME_STAMP_SYNC_0 0x264 -+#define AIFIFO2_TIME_STAMP_SYNC_1 0x268 -+#define AIFIFO2_TIME_STAMP_0 0x26C -+#define AIFIFO2_TIME_STAMP_1 0x270 -+#define AIFIFO2_TIME_STAMP_2 0x274 -+#define AIFIFO2_TIME_STAMP_3 0x278 -+#define AIFIFO2_TIME_STAMP_LENGTH 0x27C -+#define IEC958_TIME_STAMP_CNTL 0x280 -+#define IEC958_TIME_STAMP_SYNC_0 0x284 -+#define IEC958_TIME_STAMP_SYNC_1 0x288 -+#define IEC958_TIME_STAMP_0 0x28C -+#define IEC958_TIME_STAMP_1 0x290 -+#define IEC958_TIME_STAMP_2 0x294 -+#define IEC958_TIME_STAMP_3 0x298 -+#define IEC958_TIME_STAMP_LENGTH 0x29C -+#define AIU_MEM_AIFIFO2_MEM_CTL 0x2A0 -+#define AIU_I2S_CBUS_DDR_CNTL 0x2A4 -+#define AIU_I2S_CBUS_DDR_WDATA 0x2A8 -+#define AIU_I2S_CBUS_DDR_ADDR 0x2AC -+ -+#endif /* _AIU_REGS_H_ */ -diff --git a/sound/soc/meson-gx/audin-regs.h b/sound/soc/meson-gx/audin-regs.h -new file mode 100644 -index 0000000000000..f224610e80e73 ---- /dev/null -+++ b/sound/soc/meson-gx/audin-regs.h -@@ -0,0 +1,148 @@ -+/* -+ * Copyright (C) 2017 BayLibre, SAS -+ * Author: Jerome Brunet -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#ifndef _AUDIN_REGS_H_ -+#define _AUDIN_REGS_H_ -+ -+/* -+ * Note : -+ * Datasheet issue page 196 -+ * AUDIN_MUTE_VAL 0x35 => impossible: Already assigned to AUDIN_FIFO1_PTR -+ * AUDIN_FIFO1_PTR is more likely to be correct here since surrounding registers -+ * also deal with AUDIN_FIFO1 -+ * -+ * Clarification needed from Amlogic -+ */ -+ -+#define AUDIN_SPDIF_MODE 0x000 -+#define AUDIN_SPDIF_FS_CLK_RLTN 0x004 -+#define AUDIN_SPDIF_CHNL_STS_A 0x008 -+#define AUDIN_SPDIF_CHNL_STS_B 0x00C -+#define AUDIN_SPDIF_MISC 0x010 -+#define AUDIN_SPDIF_NPCM_PCPD 0x014 -+#define AUDIN_SPDIF_END 0x03C /* Unknown */ -+#define AUDIN_I2SIN_CTRL 0x040 -+#define AUDIN_SOURCE_SEL 0x044 -+#define AUDIN_DECODE_FORMAT 0x048 -+#define AUDIN_DECODE_CONTROL_STATUS 0x04C -+#define AUDIN_DECODE_CHANNEL_STATUS_A_0 0x050 -+#define AUDIN_DECODE_CHANNEL_STATUS_A_1 0x054 -+#define AUDIN_DECODE_CHANNEL_STATUS_A_2 0x058 -+#define AUDIN_DECODE_CHANNEL_STATUS_A_3 0x05C -+#define AUDIN_DECODE_CHANNEL_STATUS_A_4 0x060 -+#define AUDIN_DECODE_CHANNEL_STATUS_A_5 0x064 -+#define AUDIN_FIFO0_START 0x080 -+#define AUDIN_FIFO0_END 0x084 -+#define AUDIN_FIFO0_PTR 0x088 -+#define AUDIN_FIFO0_INTR 0x08C -+#define AUDIN_FIFO0_RDPTR 0x090 -+#define AUDIN_FIFO0_CTRL 0x094 -+#define AUDIN_FIFO0_CTRL1 0x098 -+#define AUDIN_FIFO0_LVL0 0x09C -+#define AUDIN_FIFO0_LVL1 0x0A0 -+#define AUDIN_FIFO0_LVL2 0x0A4 -+#define AUDIN_FIFO0_REQID 0x0C0 -+#define AUDIN_FIFO0_WRAP 0x0C4 -+#define AUDIN_FIFO1_START 0x0CC -+#define AUDIN_FIFO1_END 0x0D0 -+#define AUDIN_FIFO1_PTR 0x0D4 -+#define AUDIN_FIFO1_INTR 0x0D8 -+#define AUDIN_FIFO1_RDPTR 0x0DC -+#define AUDIN_FIFO1_CTRL 0x0E0 -+#define AUDIN_FIFO1_CTRL1 0x0E4 -+#define AUDIN_FIFO1_LVL0 0x100 -+#define AUDIN_FIFO1_LVL1 0x104 -+#define AUDIN_FIFO1_LVL2 0x108 -+#define AUDIN_FIFO1_REQID 0x10C -+#define AUDIN_FIFO1_WRAP 0x110 -+#define AUDIN_FIFO2_START 0x114 -+#define AUDIN_FIFO2_END 0x118 -+#define AUDIN_FIFO2_PTR 0x11C -+#define AUDIN_FIFO2_INTR 0x120 -+#define AUDIN_FIFO2_RDPTR 0x124 -+#define AUDIN_FIFO2_CTRL 0x128 -+#define AUDIN_FIFO2_CTRL1 0x12C -+#define AUDIN_FIFO2_LVL0 0x130 -+#define AUDIN_FIFO2_LVL1 0x134 -+#define AUDIN_FIFO2_LVL2 0x138 -+#define AUDIN_FIFO2_REQID 0x13C -+#define AUDIN_FIFO2_WRAP 0x140 -+#define AUDIN_INT_CTRL 0x144 -+#define AUDIN_FIFO_INT 0x148 -+#define PCMIN_CTRL0 0x180 -+#define PCMIN_CTRL1 0x184 -+#define PCMIN1_CTRL0 0x188 -+#define PCMIN1_CTRL1 0x18C -+#define PCMOUT_CTRL0 0x1C0 -+#define PCMOUT_CTRL1 0x1C4 -+#define PCMOUT_CTRL2 0x1C8 -+#define PCMOUT_CTRL3 0x1CC -+#define PCMOUT1_CTRL0 0x1D0 -+#define PCMOUT1_CTRL1 0x1D4 -+#define PCMOUT1_CTRL2 0x1D8 -+#define PCMOUT1_CTRL3 0x1DC -+#define AUDOUT_CTRL 0x200 -+#define AUDOUT_CTRL1 0x204 -+#define AUDOUT_BUF0_STA 0x208 -+#define AUDOUT_BUF0_EDA 0x20C -+#define AUDOUT_BUF0_WPTR 0x210 -+#define AUDOUT_BUF1_STA 0x214 -+#define AUDOUT_BUF1_EDA 0x218 -+#define AUDOUT_BUF1_WPTR 0x21C -+#define AUDOUT_FIFO_RPTR 0x220 -+#define AUDOUT_INTR_PTR 0x224 -+#define AUDOUT_FIFO_STS 0x228 -+#define AUDOUT1_CTRL 0x240 -+#define AUDOUT1_CTRL1 0x244 -+#define AUDOUT1_BUF0_STA 0x248 -+#define AUDOUT1_BUF0_EDA 0x24C -+#define AUDOUT1_BUF0_WPTR 0x250 -+#define AUDOUT1_BUF1_STA 0x254 -+#define AUDOUT1_BUF1_EDA 0x258 -+#define AUDOUT1_BUF1_WPTR 0x25C -+#define AUDOUT1_FIFO_RPTR 0x260 -+#define AUDOUT1_INTR_PTR 0x264 -+#define AUDOUT1_FIFO_STS 0x268 -+#define AUDIN_HDMI_MEAS_CTRL 0x280 -+#define AUDIN_HDMI_MEAS_CYCLES_M1 0x284 -+#define AUDIN_HDMI_MEAS_INTR_MASKN 0x288 -+#define AUDIN_HDMI_MEAS_INTR_STAT 0x28C -+#define AUDIN_HDMI_REF_CYCLES_STAT_0 0x290 -+#define AUDIN_HDMI_REF_CYCLES_STAT_1 0x294 -+#define AUDIN_HDMIRX_AFIFO_STAT 0x298 -+#define AUDIN_FIFO0_PIO_STS 0x2C0 -+#define AUDIN_FIFO0_PIO_RDL 0x2C4 -+#define AUDIN_FIFO0_PIO_RDH 0x2C8 -+#define AUDIN_FIFO1_PIO_STS 0x2CC -+#define AUDIN_FIFO1_PIO_RDL 0x2D0 -+#define AUDIN_FIFO1_PIO_RDH 0x2D4 -+#define AUDIN_FIFO2_PIO_STS 0x2D8 -+#define AUDIN_FIFO2_PIO_RDL 0x2DC -+#define AUDIN_FIFO2_PIO_RDH 0x2E0 -+#define AUDOUT_FIFO_PIO_STS 0x2E4 -+#define AUDOUT_FIFO_PIO_WRL 0x2E8 -+#define AUDOUT_FIFO_PIO_WRH 0x2EC -+#define AUDOUT1_FIFO_PIO_STS 0x2F0 /* Unknown */ -+#define AUDOUT1_FIFO_PIO_WRL 0x2F4 /* Unknown */ -+#define AUDOUT1_FIFO_PIO_WRH 0x2F8 /* Unknown */ -+#define AUD_RESAMPLE_CTRL0 0x2FC -+#define AUD_RESAMPLE_CTRL1 0x300 -+#define AUD_RESAMPLE_STATUS 0x304 -+ -+#endif /* _AUDIN_REGS_H_ */ - -From 55cee0743a8e0257f1afde8b79734fdaeea1b81a Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 30 Mar 2017 12:17:27 +0200 -Subject: [PATCH 230/249] ASoC: meson: add initial aiu i2s support - -Add support for the aiu i2s found on Amlogic Meson SoC family. -With this initial implementation, only playback is supported. -Capture will be part of furture work. - -Signed-off-by: Jerome Brunet ---- - sound/soc/meson-gx/Kconfig | 8 + - sound/soc/meson-gx/Makefile | 3 + - sound/soc/meson-gx/aiu-i2s.c | 749 +++++++++++++++++++++++++++++++++++ - 3 files changed, 760 insertions(+) - create mode 100644 sound/soc/meson-gx/aiu-i2s.c - -diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig -index 280e49e7c16fe..8ec683cdf3276 100644 ---- a/sound/soc/meson-gx/Kconfig -+++ b/sound/soc/meson-gx/Kconfig -@@ -9,3 +9,11 @@ menuconfig SND_SOC_MESON_GX - select the audio interfaces to support below. This WIP drivers - are kept separated from the actual upstream amlogic ASoC driver - to minimize conflicts until support is submitted and merged -+ -+config SND_SOC_MESON_GX_I2S -+ tristate "Meson i2s interface" -+ depends on SND_SOC_MESON_GX -+ help -+ Say Y or M if you want to add support for i2s driver for Amlogic -+ Meson SoCs. -+ -diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile -index 6f124c31a85cc..02f9c4df6348d 100644 ---- a/sound/soc/meson-gx/Makefile -+++ b/sound/soc/meson-gx/Makefile -@@ -1,3 +1,6 @@ - snd-soc-meson-audio-core-objs := audio-core.o -+snd-soc-meson-aiu-i2s-objs := aiu-i2s.o - - obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o -+obj-$(CONFIG_SND_SOC_MESON_GX_I2S) += snd-soc-meson-aiu-i2s.o -+ -diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c -new file mode 100644 -index 0000000000000..63d7821c2c72d ---- /dev/null -+++ b/sound/soc/meson-gx/aiu-i2s.c -@@ -0,0 +1,749 @@ -+/* -+ * Copyright (C) 2017 BayLibre, SAS -+ * Author: Jerome Brunet -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "aiu-regs.h" -+#include "audio-core.h" -+ -+#define DRV_NAME "meson-aiu-i2s" -+ -+struct meson_aiu_i2s { -+ struct meson_audio_core_data *core; -+ struct clk *mclk; -+ struct clk *bclks; -+ struct clk *iface; -+ struct clk *fast; -+ bool bclks_idle; -+ int irq; -+}; -+ -+#define AIU_MEM_I2S_BUF_CNTL_INIT BIT(0) -+#define AIU_MEM_I2S_CONTROL_INIT BIT(0) -+#define AIU_MEM_I2S_CONTROL_FILL_EN BIT(1) -+#define AIU_MEM_I2S_CONTROL_EMPTY_EN BIT(2) -+#define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6) -+#define AIU_MEM_I2S_CONTROL_BUSY BIT(7) -+#define AIU_MEM_I2S_CONTROL_DATA_READY BIT(8) -+#define AIU_MEM_I2S_CONTROL_LEVEL_CNTL BIT(9) -+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK_MASK GENMASK(31, 16) -+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK(n) ((n) << 16) -+#define AIU_MEM_I2S_MASKS_CH_MEM_MASK GENMASK(15, 8) -+#define AIU_MEM_I2S_MASKS_CH_MEM(ch) ((ch) << 8) -+#define AIU_MEM_I2S_MASKS_CH_RD_MASK GENMASK(7, 0) -+#define AIU_MEM_I2S_MASKS_CH_RD(ch) ((ch) << 0) -+#define AIU_RST_SOFT_I2S_FAST_DOMAIN BIT(0) -+#define AIU_RST_SOFT_I2S_SLOW_DOMAIN BIT(1) -+ -+/* -+ * The DMA works by i2s "blocks" (or DMA burst). The burst size and the memory -+ * layout expected depends on the mode of operation. -+ * -+ * - Normal mode: The channels are expected to be packed in 32 bytes groups -+ * interleaved the buffer. AIU_MEM_I2S_MASKS_CH_MEM is a bitfield representing -+ * the channels present in memory. AIU_MEM_I2S_MASKS_CH_MEM represents the -+ * channels read by the DMA. This is very flexible but the unsual memory layout -+ * makes it less easy to deal with. The burst size is 32 bytes times the number -+ * of channels read. -+ * -+ * - Split mode: -+ * Classical channel interleaved frame organisation. In this mode, -+ * AIU_MEM_I2S_MASKS_CH_MEM and AIU_MEM_I2S_MASKS_CH_MEM must be set to 0xff and -+ * the burst size is fixed to 256 bytes. The input can be either 2 or 8 -+ * channels. -+ * -+ * The following driver implements the split mode. -+ */ -+ -+#define AIU_I2S_DMA_BURST 256 -+ -+static struct snd_pcm_hardware meson_aiu_i2s_dma_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID | -+ SNDRV_PCM_INFO_PAUSE), -+ -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE), -+ -+ /* -+ * TODO: The DMA can change the endianness, the msb position -+ * and deal with unsigned - support this later on -+ */ -+ -+ .rate_min = 8000, -+ .rate_max = 192000, -+ .channels_min = 2, -+ .channels_max = 8, -+ .period_bytes_min = AIU_I2S_DMA_BURST, -+ .period_bytes_max = AIU_I2S_DMA_BURST * 65535, -+ .periods_min = 2, -+ .periods_max = UINT_MAX, -+ .buffer_bytes_max = 1 * 1024 * 1024, -+ .fifo_size = 0, -+}; -+ -+static struct meson_aiu_i2s *meson_aiu_i2s_dma_priv(struct snd_pcm_substream *s) -+{ -+ struct snd_soc_pcm_runtime *rtd = s->private_data; -+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); -+ -+ return snd_soc_component_get_drvdata(component); -+} -+ -+static snd_pcm_uframes_t -+meson_aiu_i2s_dma_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); -+ unsigned int addr; -+ int ret; -+ -+ ret = regmap_read(priv->core->aiu, AIU_MEM_I2S_RD_PTR, -+ &addr); -+ if (ret) -+ return 0; -+ -+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); -+} -+ -+static void __dma_enable(struct meson_aiu_i2s *priv, bool enable) -+{ -+ unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN | -+ AIU_MEM_I2S_CONTROL_EMPTY_EN); -+ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask, -+ enable ? en_mask : 0); -+ -+} -+ -+static int meson_aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ __dma_enable(priv, true); -+ break; -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ case SNDRV_PCM_TRIGGER_STOP: -+ __dma_enable(priv, false); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static void __dma_init_mem(struct meson_aiu_i2s *priv) -+{ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, -+ AIU_MEM_I2S_CONTROL_INIT, -+ AIU_MEM_I2S_CONTROL_INIT); -+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL, -+ AIU_MEM_I2S_BUF_CNTL_INIT, -+ AIU_MEM_I2S_BUF_CNTL_INIT); -+ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, -+ AIU_MEM_I2S_CONTROL_INIT, -+ 0); -+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL, -+ AIU_MEM_I2S_BUF_CNTL_INIT, -+ 0); -+} -+ -+static int meson_aiu_i2s_dma_prepare(struct snd_pcm_substream *substream) -+{ -+ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); -+ -+ __dma_init_mem(priv); -+ -+ return 0; -+} -+ -+static int meson_aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); -+ int ret; -+ u32 burst_num, mem_ctl; -+ dma_addr_t end_ptr; -+ -+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); -+ if (ret < 0) -+ return ret; -+ -+ /* Setup memory layout */ -+ if (params_physical_width(params) == 16) -+ mem_ctl = AIU_MEM_I2S_CONTROL_MODE_16BIT; -+ else -+ mem_ctl = 0; -+ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, -+ AIU_MEM_I2S_CONTROL_MODE_16BIT, -+ mem_ctl); -+ -+ /* Initialize memory pointers */ -+ regmap_write(priv->core->aiu, AIU_MEM_I2S_START_PTR, runtime->dma_addr); -+ regmap_write(priv->core->aiu, AIU_MEM_I2S_RD_PTR, runtime->dma_addr); -+ -+ /* The end pointer is the address of the last valid block */ -+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_I2S_DMA_BURST; -+ regmap_write(priv->core->aiu, AIU_MEM_I2S_END_PTR, end_ptr); -+ -+ /* Memory masks */ -+ burst_num = params_period_bytes(params) / AIU_I2S_DMA_BURST; -+ regmap_write(priv->core->aiu, AIU_MEM_I2S_MASKS, -+ AIU_MEM_I2S_MASKS_CH_RD(0xff) | -+ AIU_MEM_I2S_MASKS_CH_MEM(0xff) | -+ AIU_MEM_I2S_MASKS_IRQ_BLOCK(burst_num)); -+ -+ return 0; -+} -+ -+static int meson_aiu_i2s_dma_hw_free(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+ -+static irqreturn_t meson_aiu_i2s_dma_irq_block(int irq, void *dev_id) -+{ -+ struct snd_pcm_substream *playback = dev_id; -+ -+ snd_pcm_period_elapsed(playback); -+ -+ return IRQ_HANDLED; -+} -+ -+static int meson_aiu_i2s_dma_open(struct snd_pcm_substream *substream) -+{ -+ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); -+ int ret; -+ -+ snd_soc_set_runtime_hwparams(substream, &meson_aiu_i2s_dma_hw); -+ -+ /* -+ * Make sure the buffer and period size are multiple of the DMA burst -+ * size -+ */ -+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ AIU_I2S_DMA_BURST); -+ if (ret) -+ return ret; -+ -+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ AIU_I2S_DMA_BURST); -+ if (ret) -+ return ret; -+ -+ /* Request the I2S DDR irq */ -+ ret = request_irq(priv->irq, meson_aiu_i2s_dma_irq_block, 0, -+ DRV_NAME, substream); -+ if (ret) -+ return ret; -+ -+ /* Power up the i2s fast domain - can't write the registers w/o it */ -+ ret = clk_prepare_enable(priv->fast); -+ if (ret) -+ return ret; -+ -+ /* Make sure the dma is initially disabled */ -+ __dma_enable(priv, false); -+ -+ return 0; -+} -+ -+static int meson_aiu_i2s_dma_close(struct snd_pcm_substream *substream) -+{ -+ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); -+ -+ clk_disable_unprepare(priv->fast); -+ free_irq(priv->irq, substream); -+ -+ return 0; -+} -+ -+static const struct snd_pcm_ops meson_aiu_i2s_dma_ops = { -+ .open = meson_aiu_i2s_dma_open, -+ .close = meson_aiu_i2s_dma_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = meson_aiu_i2s_dma_hw_params, -+ .hw_free = meson_aiu_i2s_dma_hw_free, -+ .prepare = meson_aiu_i2s_dma_prepare, -+ .pointer = meson_aiu_i2s_dma_pointer, -+ .trigger = meson_aiu_i2s_dma_trigger, -+}; -+ -+static int meson_aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_card *card = rtd->card->snd_card; -+ size_t size = meson_aiu_i2s_dma_hw.buffer_bytes_max; -+ -+ snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, -+ SNDRV_DMA_TYPE_DEV, -+ card->dev, size, size); -+ -+ return 0; -+} -+ -+#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0) -+#define AIU_CLK_CTRL_I2S_DIV_MASK GENMASK(3, 2) -+#define AIU_CLK_CTRL_AOCLK_POLARITY_MASK BIT(6) -+#define AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL (0 << 6) -+#define AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED (1 << 6) -+#define AIU_CLK_CTRL_ALRCLK_POLARITY_MASK BIT(7) -+#define AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL (0 << 7) -+#define AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED (1 << 7) -+#define AIU_CLK_CTRL_ALRCLK_SKEW_MASK GENMASK(9, 8) -+#define AIU_CLK_CTRL_ALRCLK_LEFT_J (0 << 8) -+#define AIU_CLK_CTRL_ALRCLK_I2S (1 << 8) -+#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8) -+#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0) -+#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0) -+#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0) -+#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0) -+#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0) -+#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0) -+#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0) -+#define AIU_I2S_DAC_CFG_AOCLK_64 (3 << 0) -+#define AIU_I2S_MISC_HOLD_EN BIT(2) -+#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) -+#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) -+#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) -+#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11) -+ -+static void __hold(struct meson_aiu_i2s *priv, bool enable) -+{ -+ regmap_update_bits(priv->core->aiu, AIU_I2S_MISC, -+ AIU_I2S_MISC_HOLD_EN, -+ enable ? AIU_I2S_MISC_HOLD_EN : 0); -+} -+ -+static void __divider_enable(struct meson_aiu_i2s *priv, bool enable) -+{ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, -+ AIU_CLK_CTRL_I2S_DIV_EN, -+ enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0); -+} -+ -+static void __playback_start(struct meson_aiu_i2s *priv) -+{ -+ __divider_enable(priv, true); -+ __hold(priv, false); -+} -+ -+static void __playback_stop(struct meson_aiu_i2s *priv, bool clk_force) -+{ -+ __hold(priv, true); -+ /* Disable the bit clks if necessary */ -+ if (clk_force || !priv->bclks_idle) -+ __divider_enable(priv, false); -+} -+ -+static int meson_aiu_i2s_dai_trigger(struct snd_pcm_substream *substream, int cmd, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); -+ bool clk_force_stop = false; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ __playback_start(priv); -+ return 0; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ clk_force_stop = true; -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ __playback_stop(priv, clk_force_stop); -+ return 0; -+ -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int __bclks_set_rate(struct meson_aiu_i2s *priv, unsigned int srate, -+ unsigned int width) -+{ -+ unsigned int fs; -+ -+ /* Get the oversampling factor */ -+ fs = DIV_ROUND_CLOSEST(clk_get_rate(priv->mclk), srate); -+ -+ /* -+ * This DAI is usually connected to the dw-hdmi which does not support -+ * bclk being 32 * lrclk or 48 * lrclk -+ * Restrict to blck = 64 * lrclk -+ */ -+ if (fs % 64) -+ return -EINVAL; -+ -+ /* Set the divider between lrclk and bclk */ -+ regmap_update_bits(priv->core->aiu, AIU_I2S_DAC_CFG, -+ AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK, -+ AIU_I2S_DAC_CFG_AOCLK_64); -+ -+ regmap_update_bits(priv->core->aiu, AIU_CODEC_DAC_LRCLK_CTRL, -+ AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK, -+ AIU_CODEC_DAC_LRCLK_CTRL_DIV(64)); -+ -+ /* Use CLK_MORE for the i2s divider */ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, -+ AIU_CLK_CTRL_I2S_DIV_MASK, -+ 0); -+ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE, -+ AIU_CLK_CTRL_MORE_I2S_DIV_MASK, -+ AIU_CLK_CTRL_MORE_I2S_DIV(fs / 64)); -+ -+ return 0; -+} -+ -+static int __setup_desc(struct meson_aiu_i2s *priv, unsigned int width, -+ unsigned int channels) -+{ -+ u32 desc = 0; -+ -+ switch (width) { -+ case 24: -+ /* -+ * For some reason, 24 bits wide audio don't play well -+ * if the 32 bits mode is not set -+ */ -+ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT | -+ AIU_I2S_SOURCE_DESC_MODE_32BIT); -+ break; -+ case 16: -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ switch (channels) { -+ case 2: /* Nothing to do */ -+ break; -+ case 8: -+ /* TODO: Still requires testing ... */ -+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC, -+ AIU_I2S_SOURCE_DESC_MODE_8CH | -+ AIU_I2S_SOURCE_DESC_MODE_24BIT | -+ AIU_I2S_SOURCE_DESC_MODE_32BIT, -+ desc); -+ -+ return 0; -+} -+ -+static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); -+ unsigned int width = params_width(params); -+ unsigned int channels = params_channels(params); -+ unsigned int rate = params_rate(params); -+ int ret; -+ -+ ret = __setup_desc(priv, width, channels); -+ if (ret) { -+ dev_err(dai->dev, "Unable set to set i2s description\n"); -+ return ret; -+ } -+ -+ ret = __bclks_set_rate(priv, rate, width); -+ if (ret) { -+ dev_err(dai->dev, "Unable set to the i2s clock rates\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int meson_aiu_i2s_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -+{ -+ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); -+ u32 val; -+ -+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) -+ return -EINVAL; -+ -+ /* DAI output mode */ -+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: -+ val = AIU_CLK_CTRL_ALRCLK_I2S; -+ break; -+ case SND_SOC_DAIFMT_LEFT_J: -+ val = AIU_CLK_CTRL_ALRCLK_LEFT_J; -+ break; -+ case SND_SOC_DAIFMT_RIGHT_J: -+ val = AIU_CLK_CTRL_ALRCLK_RIGHT_J; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, -+ AIU_CLK_CTRL_ALRCLK_SKEW_MASK, -+ val); -+ -+ /* DAI clock polarity */ -+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { -+ case SND_SOC_DAIFMT_IB_IF: -+ /* Invert both clocks */ -+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED | -+ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED; -+ break; -+ case SND_SOC_DAIFMT_IB_NF: -+ /* Invert bit clock */ -+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL | -+ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED; -+ break; -+ case SND_SOC_DAIFMT_NB_IF: -+ /* Invert frame clock */ -+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED | -+ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL; -+ break; -+ case SND_SOC_DAIFMT_NB_NF: -+ /* Normal clocks */ -+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL | -+ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, -+ AIU_CLK_CTRL_ALRCLK_POLARITY_MASK | -+ AIU_CLK_CTRL_AOCLK_POLARITY_MASK, -+ val); -+ -+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { -+ case SND_SOC_DAIFMT_CONT: -+ priv->bclks_idle = true; -+ break; -+ case SND_SOC_DAIFMT_GATED: -+ priv->bclks_idle = false; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int meson_aiu_i2s_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, -+ unsigned int freq, int dir) -+{ -+ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); -+ int ret; -+ -+ if (WARN_ON(clk_id != 0)) -+ return -EINVAL; -+ -+ if (dir == SND_SOC_CLOCK_IN) -+ return 0; -+ -+ ret = clk_set_rate(priv->mclk, freq); -+ if (ret) { -+ dev_err(dai->dev, "Failed to set sysclk to %uHz", freq); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int meson_aiu_i2s_dai_startup(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); -+ int ret; -+ -+ /* Power up the i2s fast domain - can't write the registers w/o it */ -+ ret = clk_prepare_enable(priv->fast); -+ if (ret) -+ goto out_clk_fast; -+ -+ /* Make sure nothing gets out of the DAI yet */ -+ __hold(priv, true); -+ -+ /* I2S encoder needs the mixer interface gate */ -+ ret = clk_prepare_enable(priv->iface); -+ if (ret) -+ goto out_clk_iface; -+ -+ /* Enable the i2s master clock */ -+ ret = clk_prepare_enable(priv->mclk); -+ if (ret) -+ goto out_mclk; -+ -+ /* Enable the bit clock gate */ -+ ret = clk_prepare_enable(priv->bclks); -+ if (ret) -+ goto out_bclks; -+ -+ /* Make sure the interface expect a memory layout we can work with */ -+ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC, -+ AIU_I2S_SOURCE_DESC_MODE_SPLIT, -+ AIU_I2S_SOURCE_DESC_MODE_SPLIT); -+ -+ return 0; -+ -+out_bclks: -+ clk_disable_unprepare(priv->mclk); -+out_mclk: -+ clk_disable_unprepare(priv->iface); -+out_clk_iface: -+ clk_disable_unprepare(priv->fast); -+out_clk_fast: -+ return ret; -+} -+ -+static void meson_aiu_i2s_dai_shutdown(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); -+ -+ clk_disable_unprepare(priv->bclks); -+ clk_disable_unprepare(priv->mclk); -+ clk_disable_unprepare(priv->iface); -+ clk_disable_unprepare(priv->fast); -+} -+ -+static const struct snd_soc_dai_ops meson_aiu_i2s_dai_ops = { -+ .startup = meson_aiu_i2s_dai_startup, -+ .shutdown = meson_aiu_i2s_dai_shutdown, -+ .trigger = meson_aiu_i2s_dai_trigger, -+ .hw_params = meson_aiu_i2s_dai_hw_params, -+ .set_fmt = meson_aiu_i2s_dai_set_fmt, -+ .set_sysclk = meson_aiu_i2s_dai_set_sysclk, -+}; -+ -+static struct snd_soc_dai_driver meson_aiu_i2s_dai = { -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 2, -+ .channels_max = 8, -+ .rates = SNDRV_PCM_RATE_8000_192000, -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE) -+ }, -+ .ops = &meson_aiu_i2s_dai_ops, -+}; -+ -+static const struct snd_soc_component_driver meson_aiu_i2s_component = { -+ .ops = &meson_aiu_i2s_dma_ops, -+ .pcm_new = meson_aiu_i2s_dma_new, -+ .name = DRV_NAME, -+}; -+ -+static int meson_aiu_i2s_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct meson_aiu_i2s *priv; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, priv); -+ priv->core = dev_get_drvdata(dev->parent); -+ -+ priv->fast = devm_clk_get(dev, "fast"); -+ if (IS_ERR(priv->fast)) { -+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER) -+ dev_err(dev, "Can't get the i2s fast domain clock\n"); -+ return PTR_ERR(priv->fast); -+ } -+ -+ priv->iface = devm_clk_get(dev, "iface"); -+ if (IS_ERR(priv->iface)) { -+ if (PTR_ERR(priv->iface) != -EPROBE_DEFER) -+ dev_err(dev, "Can't get i2s dai clock gate\n"); -+ return PTR_ERR(priv->iface); -+ } -+ -+ priv->bclks = devm_clk_get(dev, "bclks"); -+ if (IS_ERR(priv->bclks)) { -+ if (PTR_ERR(priv->bclks) != -EPROBE_DEFER) -+ dev_err(dev, "Can't get bit clocks gate\n"); -+ return PTR_ERR(priv->bclks); -+ } -+ -+ priv->mclk = devm_clk_get(dev, "mclk"); -+ if (IS_ERR(priv->mclk)) { -+ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER) -+ dev_err(dev, "failed to get the i2s master clock\n"); -+ return PTR_ERR(priv->mclk); -+ } -+ -+ priv->irq = platform_get_irq(pdev, 0); -+ if (priv->irq <= 0) { -+ dev_err(dev, "Can't get i2s ddr irq\n"); -+ return priv->irq; -+ } -+ -+ return devm_snd_soc_register_component(dev, &meson_aiu_i2s_component, -+ &meson_aiu_i2s_dai, 1); -+} -+ -+static const struct of_device_id meson_aiu_i2s_of_match[] = { -+ { .compatible = "amlogic,meson-aiu-i2s", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, meson_aiu_i2s_of_match); -+ -+static struct platform_driver meson_aiu_i2s_pdrv = { -+ .probe = meson_aiu_i2s_probe, -+ .driver = { -+ .name = DRV_NAME, -+ .of_match_table = meson_aiu_i2s_of_match, -+ }, -+}; -+module_platform_driver(meson_aiu_i2s_pdrv); -+ -+MODULE_DESCRIPTION("Meson AIU i2s ASoC Driver"); -+MODULE_AUTHOR("Jerome Brunet "); -+MODULE_LICENSE("GPL v2"); - -From aea5536958e43c3908dbf31ddad800a8e03aaa37 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 30 Mar 2017 13:46:03 +0200 -Subject: [PATCH 231/249] ASoC: meson: add initial spdif support - -Add support for the spdif found on Amlogic Meson SoC family. -With this initial implementation, only uncompressed pcm playback -from the spdif dma is supported. Future work will add compressed -support, pcm playback from i2s dma and capture. - -Signed-off-by: Jerome Brunet ---- - sound/soc/meson-gx/Kconfig | 7 + - sound/soc/meson-gx/Makefile | 3 +- - sound/soc/meson-gx/aiu-spdif.c | 671 +++++++++++++++++++++++++++++++++ - 3 files changed, 680 insertions(+), 1 deletion(-) - create mode 100644 sound/soc/meson-gx/aiu-spdif.c - -diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig -index 8ec683cdf3276..141afabfaceaa 100644 ---- a/sound/soc/meson-gx/Kconfig -+++ b/sound/soc/meson-gx/Kconfig -@@ -17,3 +17,10 @@ config SND_SOC_MESON_GX_I2S - Say Y or M if you want to add support for i2s driver for Amlogic - Meson SoCs. - -+config SND_SOC_MESON_GX_SPDIF -+ tristate "Meson spdif interface" -+ depends on SND_SOC_MESON_GX -+ select SND_PCM_IEC958 -+ help -+ Say Y or M if you want to add support for spdif driver for Amlogic -+ Meson SoCs. -diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile -index 02f9c4df6348d..d37672ebe57bf 100644 ---- a/sound/soc/meson-gx/Makefile -+++ b/sound/soc/meson-gx/Makefile -@@ -1,6 +1,7 @@ - snd-soc-meson-audio-core-objs := audio-core.o - snd-soc-meson-aiu-i2s-objs := aiu-i2s.o -+snd-soc-meson-aiu-spdif-objs := aiu-spdif.o - - obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o - obj-$(CONFIG_SND_SOC_MESON_GX_I2S) += snd-soc-meson-aiu-i2s.o -- -+obj-$(CONFIG_SND_SOC_MESON_GX_SPDIF) += snd-soc-meson-aiu-spdif.o -diff --git a/sound/soc/meson-gx/aiu-spdif.c b/sound/soc/meson-gx/aiu-spdif.c -new file mode 100644 -index 0000000000000..748a9b1d680c0 ---- /dev/null -+++ b/sound/soc/meson-gx/aiu-spdif.c -@@ -0,0 +1,671 @@ -+/* -+ * Copyright (C) 2017 BayLibre, SAS -+ * Author: Jerome Brunet -+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "aiu-regs.h" -+#include "audio-core.h" -+ -+#define DRV_NAME "meson-aiu-spdif" -+ -+struct meson_aiu_spdif { -+ struct meson_audio_core_data *core; -+ struct clk *iface; -+ struct clk *fast; -+ struct clk *mclk_i958; -+ struct clk *mclk; -+ int irq; -+}; -+ -+ -+#define AIU_958_DCU_FF_CTRL_EN BIT(0) -+#define AIU_958_DCU_FF_CTRL_AUTO_DISABLE BIT(1) -+#define AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK GENMASK(3, 2) -+#define AIU_958_DCU_FF_CTRL_IRQ_OUT_THD BIT(2) -+#define AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ BIT(3) -+#define AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN BIT(4) -+#define AIU_958_DCU_FF_CTRL_BYTE_SEEK BIT(5) -+#define AIU_958_DCU_FF_CTRL_CONTINUE BIT(6) -+#define AIU_MEM_IEC958_BUF_CNTL_INIT BIT(0) -+#define AIU_MEM_IEC958_CONTROL_INIT BIT(0) -+#define AIU_MEM_IEC958_CONTROL_FILL_EN BIT(1) -+#define AIU_MEM_IEC958_CONTROL_EMPTY_EN BIT(2) -+#define AIU_MEM_IEC958_CONTROL_ENDIAN_MASK GENMASK(5, 3) -+#define AIU_MEM_IEC958_CONTROL_RD_DDR BIT(6) -+#define AIU_MEM_IEC958_CONTROL_MODE_16BIT BIT(7) -+#define AIU_MEM_IEC958_MASKS_CH_MEM_MASK GENMASK(15, 8) -+#define AIU_MEM_IEC958_MASKS_CH_MEM(ch) ((ch) << 8) -+#define AIU_MEM_IEC958_MASKS_CH_RD_MASK GENMASK(7, 0) -+#define AIU_MEM_IEC958_MASKS_CH_RD(ch) ((ch) << 0) -+ -+#define AIU_SPDIF_DMA_BURST 8 -+#define AIU_SPDIF_BPF_MAX USHRT_MAX -+ -+static struct snd_pcm_hardware meson_aiu_spdif_dma_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID | -+ SNDRV_PCM_INFO_PAUSE), -+ -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE), -+ -+ .rates = (SNDRV_PCM_RATE_32000 | -+ SNDRV_PCM_RATE_44100 | -+ SNDRV_PCM_RATE_48000 | -+ SNDRV_PCM_RATE_96000 | -+ SNDRV_PCM_RATE_192000), -+ /* -+ * TODO: The DMA can change the endianness, the msb position -+ * and deal with unsigned - support this later on -+ */ -+ -+ .channels_min = 2, -+ .channels_max = 2, -+ .period_bytes_min = AIU_SPDIF_DMA_BURST, -+ .period_bytes_max = AIU_SPDIF_BPF_MAX, -+ .periods_min = 2, -+ .periods_max = UINT_MAX, -+ .buffer_bytes_max = 1 * 1024 * 1024, -+ .fifo_size = 0, -+}; -+ -+static struct meson_aiu_spdif *meson_aiu_spdif_dma_priv(struct snd_pcm_substream *s) -+{ -+ struct snd_soc_pcm_runtime *rtd = s->private_data; -+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); -+ -+ return snd_soc_component_get_drvdata(component); -+} -+ -+static snd_pcm_uframes_t -+meson_aiu_spdif_dma_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); -+ unsigned int addr; -+ int ret; -+ -+ ret = regmap_read(priv->core->aiu, AIU_MEM_IEC958_RD_PTR, -+ &addr); -+ if (ret) -+ return 0; -+ -+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); -+} -+ -+static void __dma_enable(struct meson_aiu_spdif *priv, bool enable) -+{ -+ unsigned int en_mask = (AIU_MEM_IEC958_CONTROL_FILL_EN | -+ AIU_MEM_IEC958_CONTROL_EMPTY_EN); -+ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, en_mask, -+ enable ? en_mask : 0); -+} -+ -+static void __dcu_fifo_enable(struct meson_aiu_spdif *priv, bool enable) -+{ -+ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL, -+ AIU_958_DCU_FF_CTRL_EN, -+ enable ? AIU_958_DCU_FF_CTRL_EN : 0); -+} -+ -+static int meson_aiu_spdif_dma_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ __dcu_fifo_enable(priv, true); -+ __dma_enable(priv, true); -+ break; -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ case SNDRV_PCM_TRIGGER_STOP: -+ __dma_enable(priv, false); -+ __dcu_fifo_enable(priv, false); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static void __dma_init_mem(struct meson_aiu_spdif *priv) -+{ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, -+ AIU_MEM_IEC958_CONTROL_INIT, -+ AIU_MEM_IEC958_CONTROL_INIT); -+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL, -+ AIU_MEM_IEC958_BUF_CNTL_INIT, -+ AIU_MEM_IEC958_BUF_CNTL_INIT); -+ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, -+ AIU_MEM_IEC958_CONTROL_INIT, -+ 0); -+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL, -+ AIU_MEM_IEC958_BUF_CNTL_INIT, -+ 0); -+} -+ -+static int meson_aiu_spdif_dma_prepare(struct snd_pcm_substream *substream) -+{ -+ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); -+ -+ __dma_init_mem(priv); -+ -+ return 0; -+} -+ -+static int __setup_memory_layout(struct meson_aiu_spdif *priv, -+ unsigned int width) -+{ -+ u32 mem_ctl = AIU_MEM_IEC958_CONTROL_RD_DDR; -+ -+ if (width == 16) -+ mem_ctl |= AIU_MEM_IEC958_CONTROL_MODE_16BIT; -+ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, -+ AIU_MEM_IEC958_CONTROL_ENDIAN_MASK | -+ AIU_MEM_IEC958_CONTROL_MODE_16BIT | -+ AIU_MEM_IEC958_CONTROL_RD_DDR, -+ mem_ctl); -+ -+ return 0; -+} -+ -+static int meson_aiu_spdif_dma_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); -+ int ret; -+ dma_addr_t end_ptr; -+ -+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); -+ if (ret < 0) -+ return ret; -+ -+ ret = __setup_memory_layout(priv, params_physical_width(params)); -+ if (ret) -+ return ret; -+ -+ /* Initialize memory pointers */ -+ regmap_write(priv->core->aiu, -+ AIU_MEM_IEC958_START_PTR, runtime->dma_addr); -+ regmap_write(priv->core->aiu, -+ AIU_MEM_IEC958_RD_PTR, runtime->dma_addr); -+ -+ /* The end pointer is the address of the last valid block */ -+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_SPDIF_DMA_BURST; -+ regmap_write(priv->core->aiu, AIU_MEM_IEC958_END_PTR, end_ptr); -+ -+ /* Memory masks */ -+ regmap_write(priv->core->aiu, AIU_MEM_IEC958_MASKS, -+ AIU_MEM_IEC958_MASKS_CH_RD(0xff) | -+ AIU_MEM_IEC958_MASKS_CH_MEM(0xff)); -+ -+ /* Setup the number bytes read by the FIFO between each IRQ */ -+ regmap_write(priv->core->aiu, AIU_958_BPF, params_period_bytes(params)); -+ -+ /* -+ * AUTO_DISABLE and SYNC_HEAD are enabled by default but -+ * this should be disabled in PCM (uncompressed) mode -+ */ -+ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL, -+ AIU_958_DCU_FF_CTRL_AUTO_DISABLE | -+ AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK | -+ AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN, -+ AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ); -+ -+ return 0; -+} -+ -+static int meson_aiu_spdif_dma_hw_free(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+static irqreturn_t meson_aiu_spdif_dma_irq(int irq, void *dev_id) -+{ -+ struct snd_pcm_substream *playback = dev_id; -+ -+ snd_pcm_period_elapsed(playback); -+ -+ return IRQ_HANDLED; -+} -+ -+static int meson_aiu_spdif_dma_open(struct snd_pcm_substream *substream) -+{ -+ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); -+ int ret; -+ -+ snd_soc_set_runtime_hwparams(substream, &meson_aiu_spdif_dma_hw); -+ -+ /* -+ * Make sure the buffer and period size are multiple of the DMA burst -+ * size -+ */ -+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ AIU_SPDIF_DMA_BURST); -+ if (ret) -+ return ret; -+ -+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ AIU_SPDIF_DMA_BURST); -+ if (ret) -+ return ret; -+ -+ /* Request the SPDIF DDR irq */ -+ ret = request_irq(priv->irq, meson_aiu_spdif_dma_irq, 0, -+ DRV_NAME, substream); -+ if (ret) -+ return ret; -+ -+ /* Power up the spdif fast domain - can't write the register w/o it */ -+ ret = clk_prepare_enable(priv->fast); -+ if (ret) -+ return ret; -+ -+ /* Make sure the dma is initially halted */ -+ __dma_enable(priv, false); -+ __dcu_fifo_enable(priv, false); -+ -+ return 0; -+} -+ -+static int meson_aiu_spdif_dma_close(struct snd_pcm_substream *substream) -+{ -+ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); -+ -+ clk_disable_unprepare(priv->fast); -+ free_irq(priv->irq, substream); -+ -+ return 0; -+} -+ -+static const struct snd_pcm_ops meson_aiu_spdif_dma_ops = { -+ .open = meson_aiu_spdif_dma_open, -+ .close = meson_aiu_spdif_dma_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = meson_aiu_spdif_dma_hw_params, -+ .hw_free = meson_aiu_spdif_dma_hw_free, -+ .prepare = meson_aiu_spdif_dma_prepare, -+ .pointer = meson_aiu_spdif_dma_pointer, -+ .trigger = meson_aiu_spdif_dma_trigger, -+}; -+ -+static int meson_aiu_spdif_dma_new(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_card *card = rtd->card->snd_card; -+ size_t size = meson_aiu_spdif_dma_hw.buffer_bytes_max; -+ -+ snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, -+ SNDRV_DMA_TYPE_DEV, -+ card->dev, size, size); -+ -+ return 0; -+} -+ -+#define AIU_CLK_CTRL_958_DIV_EN BIT(1) -+#define AIU_CLK_CTRL_958_DIV_MASK GENMASK(5, 4) -+#define AIU_CLK_CTRL_958_DIV_MORE BIT(12) -+#define AIU_MEM_IEC958_CONTROL_MODE_LINEAR BIT(8) -+#define AIU_958_CTRL_HOLD_EN BIT(0) -+#define AIU_958_MISC_NON_PCM BIT(0) -+#define AIU_958_MISC_MODE_16BITS BIT(1) -+#define AIU_958_MISC_16BITS_ALIGN_MASK GENMASK(6, 5) -+#define AIU_958_MISC_16BITS_ALIGN(val) ((val) << 5) -+#define AIU_958_MISC_MODE_32BITS BIT(7) -+#define AIU_958_MISC_32BITS_SHIFT_MASK GENMASK(10, 8) -+#define AIU_958_MISC_32BITS_SHIFT(val) ((val) << 8) -+#define AIU_958_MISC_U_FROM_STREAM BIT(12) -+#define AIU_958_MISC_FORCE_LR BIT(13) -+ -+#define AIU_CS_WORD_LEN 4 -+ -+static void __hold(struct meson_aiu_spdif *priv, bool enable) -+{ -+ regmap_update_bits(priv->core->aiu, AIU_958_CTRL, -+ AIU_958_CTRL_HOLD_EN, -+ enable ? AIU_958_CTRL_HOLD_EN : 0); -+} -+ -+static void __divider_enable(struct meson_aiu_spdif *priv, bool enable) -+{ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, -+ AIU_CLK_CTRL_958_DIV_EN, -+ enable ? AIU_CLK_CTRL_958_DIV_EN : 0); -+} -+ -+static void __playback_start(struct meson_aiu_spdif *priv) -+{ -+ __divider_enable(priv, true); -+ __hold(priv, false); -+} -+ -+static void __playback_stop(struct meson_aiu_spdif *priv) -+{ -+ __hold(priv, true); -+ __divider_enable(priv, false); -+} -+ -+static int meson_aiu_spdif_dai_trigger(struct snd_pcm_substream *substream, int cmd, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ __playback_start(priv); -+ return 0; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ __playback_stop(priv); -+ return 0; -+ -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int __setup_spdif_clk(struct meson_aiu_spdif *priv, unsigned int rate) -+{ -+ unsigned int mrate; -+ -+ /* Leave the internal divisor alone */ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, -+ AIU_CLK_CTRL_958_DIV_MASK | -+ AIU_CLK_CTRL_958_DIV_MORE, -+ 0); -+ -+ /* 2 * 32bits per subframe * 2 channels = 128 */ -+ mrate = rate * 128; -+ return clk_set_rate(priv->mclk, mrate); -+} -+ -+static int __setup_cs_word(struct meson_aiu_spdif *priv, -+ struct snd_pcm_hw_params *params) -+{ -+ u8 cs[AIU_CS_WORD_LEN]; -+ u32 val; -+ int ret; -+ -+ ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, -+ AIU_CS_WORD_LEN); -+ if (ret < 0) -+ return -EINVAL; -+ -+ /* Write the 1st half word */ -+ val = cs[1] | cs[0] << 8; -+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L0, val); -+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R0, val); -+ -+ /* Write the 2nd half word */ -+ val = cs[3] | cs[2] << 8; -+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L1, val); -+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R1, val); -+ -+ return 0; -+} -+ -+static int __setup_pcm_fmt(struct meson_aiu_spdif *priv, -+ unsigned int width) -+{ -+ u32 val = 0; -+ -+ switch (width) { -+ case 16: -+ val |= AIU_958_MISC_MODE_16BITS; -+ val |= AIU_958_MISC_16BITS_ALIGN(2); -+ break; -+ case 32: -+ case 24: -+ /* -+ * Looks like this should only be set for 32bits mode, but the -+ * vendor kernel sets it like this for 24bits as well, let's -+ * try and see -+ */ -+ val |= AIU_958_MISC_MODE_32BITS; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* No idea what this actually does, copying the vendor kernel for now */ -+ val |= AIU_958_MISC_FORCE_LR; -+ val |= AIU_958_MISC_U_FROM_STREAM; -+ -+ regmap_update_bits(priv->core->aiu, AIU_958_MISC, -+ AIU_958_MISC_NON_PCM | -+ AIU_958_MISC_MODE_16BITS | -+ AIU_958_MISC_16BITS_ALIGN_MASK | -+ AIU_958_MISC_MODE_32BITS | -+ AIU_958_MISC_FORCE_LR, -+ val); -+ -+ return 0; -+} -+ -+static int meson_aiu_spdif_dai_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); -+ int ret; -+ -+ ret = __setup_spdif_clk(priv, params_rate(params)); -+ if (ret) { -+ dev_err(dai->dev, "Unable to set the spdif clock\n"); -+ return ret; -+ } -+ -+ ret = __setup_cs_word(priv, params); -+ if (ret) { -+ dev_err(dai->dev, "Unable to set the channel status word\n"); -+ return ret; -+ } -+ -+ ret = __setup_pcm_fmt(priv, params_width(params)); -+ if (ret) { -+ dev_err(dai->dev, "Unable to set the pcm format\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int meson_aiu_spdif_dai_startup(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); -+ int ret; -+ -+ /* Power up the spdif fast domain - can't write the registers w/o it */ -+ ret = clk_prepare_enable(priv->fast); -+ if (ret) -+ goto out_clk_fast; -+ -+ /* Make sure nothing gets out of the DAI yet*/ -+ __hold(priv, true); -+ -+ ret = clk_set_parent(priv->mclk, priv->mclk_i958); -+ if (ret) -+ return ret; -+ -+ /* Enable the clock gate */ -+ ret = clk_prepare_enable(priv->iface); -+ if (ret) -+ goto out_clk_iface; -+ -+ /* Enable the spdif clock */ -+ ret = clk_prepare_enable(priv->mclk); -+ if (ret) -+ goto out_mclk; -+ -+ /* -+ * Make sure the interface expect a memory layout we can work with -+ * MEM prefixed register usually belong to the DMA, but when the spdif -+ * DAI takes data from the i2s buffer, we need to make sure it works in -+ * split mode and not the "normal mode" (channel samples packed in -+ * 32 bytes groups) -+ */ -+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, -+ AIU_MEM_IEC958_CONTROL_MODE_LINEAR, -+ AIU_MEM_IEC958_CONTROL_MODE_LINEAR); -+ -+ return 0; -+ -+out_mclk: -+ clk_disable_unprepare(priv->iface); -+out_clk_iface: -+ clk_disable_unprepare(priv->fast); -+out_clk_fast: -+ return ret; -+} -+ -+static void meson_aiu_spdif_dai_shutdown(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); -+ -+ clk_disable_unprepare(priv->iface); -+ clk_disable_unprepare(priv->mclk); -+ clk_disable_unprepare(priv->fast); -+} -+ -+static const struct snd_soc_dai_ops meson_aiu_spdif_dai_ops = { -+ .startup = meson_aiu_spdif_dai_startup, -+ .shutdown = meson_aiu_spdif_dai_shutdown, -+ .trigger = meson_aiu_spdif_dai_trigger, -+ .hw_params = meson_aiu_spdif_dai_hw_params, -+}; -+ -+static struct snd_soc_dai_driver meson_aiu_spdif_dai = { -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = (SNDRV_PCM_RATE_32000 | -+ SNDRV_PCM_RATE_44100 | -+ SNDRV_PCM_RATE_48000 | -+ SNDRV_PCM_RATE_96000 | -+ SNDRV_PCM_RATE_192000), -+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE) -+ }, -+ .ops = &meson_aiu_spdif_dai_ops, -+}; -+ -+static const struct snd_soc_component_driver meson_aiu_spdif_component = { -+ .ops = &meson_aiu_spdif_dma_ops, -+ .pcm_new = meson_aiu_spdif_dma_new, -+ .name = DRV_NAME, -+}; -+ -+static int meson_aiu_spdif_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct meson_aiu_spdif *priv; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, priv); -+ priv->core = dev_get_drvdata(dev->parent); -+ -+ priv->fast = devm_clk_get(dev, "fast"); -+ if (IS_ERR(priv->fast)) { -+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER) -+ dev_err(dev, "Can't get spdif fast domain clockt\n"); -+ return PTR_ERR(priv->fast); -+ } -+ -+ priv->iface = devm_clk_get(dev, "iface"); -+ if (IS_ERR(priv->iface)) { -+ if (PTR_ERR(priv->iface) != -EPROBE_DEFER) -+ dev_err(dev, -+ "Can't get the dai clock gate\n"); -+ return PTR_ERR(priv->iface); -+ } -+ -+ priv->mclk_i958 = devm_clk_get(dev, "mclk_i958"); -+ if (IS_ERR(priv->mclk_i958)) { -+ if (PTR_ERR(priv->mclk_i958) != -EPROBE_DEFER) -+ dev_err(dev, "Can't get the spdif master clock\n"); -+ return PTR_ERR(priv->mclk_i958); -+ } -+ -+ /* -+ * TODO: the spdif dai can also get its data from the i2s fifo. -+ * For this use-case, the DAI driver will need to get the i2s master -+ * clock in order to reparent the spdif clock from cts_mclk_i958 to -+ * cts_amclk -+ */ -+ -+ priv->mclk = devm_clk_get(dev, "mclk"); -+ if (IS_ERR(priv->mclk)) { -+ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER) -+ dev_err(dev, "Can't get the spdif input mux clock\n"); -+ return PTR_ERR(priv->mclk); -+ } -+ -+ return devm_snd_soc_register_component(dev, &meson_aiu_spdif_component, -+ &meson_aiu_spdif_dai, 1); -+} -+ -+static const struct of_device_id meson_aiu_spdif_of_match[] = { -+ { .compatible = "amlogic,meson-aiu-spdif", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, meson_aiu_spdif_of_match); -+ -+static struct platform_driver meson_aiu_spdif_pdrv = { -+ .probe = meson_aiu_spdif_probe, -+ .driver = { -+ .name = DRV_NAME, -+ .of_match_table = meson_aiu_spdif_of_match, -+ }, -+}; -+module_platform_driver(meson_aiu_spdif_pdrv); -+ -+MODULE_DESCRIPTION("Meson AIU spdif ASoC Driver"); -+MODULE_AUTHOR("Jerome Brunet "); -+MODULE_LICENSE("GPL v2"); - -From 819f125da865f76477bd982abbafcf7e274e83fc Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 31 Mar 2017 15:55:03 +0200 -Subject: [PATCH 232/249] ARM64: defconfig: enable audio support for meson SoCs - as module - -Add audio support for meson SoCs. This includes the audio core -driver and the i2s and spdif output interfaces - -Signed-off-by: Jerome Brunet ---- - arch/arm64/configs/defconfig | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 552868cb15ae5..ad87d5dbf09e6 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -528,6 +528,9 @@ CONFIG_SOUND=y - CONFIG_SND=y - CONFIG_SND_SOC=y - CONFIG_SND_BCM2835_SOC_I2S=m -+CONFIG_SND_SOC_MESON_GX=m -+CONFIG_SND_SOC_MESON_GX_I2S=m -+CONFIG_SND_SOC_MESON_GX_SPDIF=m - CONFIG_SND_SOC_ROCKCHIP=m - CONFIG_SND_SOC_ROCKCHIP_SPDIF=m - CONFIG_SND_SOC_ROCKCHIP_RT5645=m - -From 463caeec5faa1fc46f8a07d970a1b8f97f9e549e Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Thu, 30 Mar 2017 15:19:04 +0200 -Subject: [PATCH 233/249] ARM64: dts: meson-gx: add audio controller nodes - -Add audio controller nodes for Amlogic meson gxbb and gxl. -This includes the audio-core node, the i2s and spdif DAIs - -Audio on this SoC family is still a work in progress. More nodes are likely -to be added later on (pcm DAIs, input DMAs, etc ...) - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 23 ++++++++++++++++++ - arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 27 +++++++++++++++++++++ - arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 27 +++++++++++++++++++++ - 3 files changed, 77 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -index be7096869b2e7..5984f75be4169 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi -@@ -225,6 +225,29 @@ - #reset-cells = <1>; - }; - -+ audio: audio@5400 { -+ compatible = "amlogic,meson-gx-audio-core"; -+ reg = <0x0 0x5400 0x0 0x2ac>, -+ <0x0 0xa000 0x0 0x304>; -+ reg-names = "aiu", "audin"; -+ status = "disabled"; -+ -+ aiu_i2s: audio-controller-0 { -+ #sound-dai-cells = <0>; -+ compatible = "amlogic,meson-aiu-i2s"; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ -+ aiu_spdif: audio-controller-1 { -+ #sound-dai-cells = <0>; -+ compatible = "amlogic,meson-aiu-spdif"; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ -+ }; -+ - uart_A: serial@84c0 { - compatible = "amlogic,meson-gx-uart"; - reg = <0x0 0x84c0 0x0 0x18>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -index e900a93960fb6..277beb6e4f0b2 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -@@ -709,6 +709,24 @@ - }; - }; - -+&audio { -+ clocks = <&clkc CLKID_AIU>, -+ <&clkc CLKID_AIU_GLUE>, -+ <&clkc CLKID_I2S_SPDIF>; -+ clock-names = "aiu_top", "aiu_glue", "audin"; -+ resets = <&reset RESET_AIU>, -+ <&reset RESET_AUDIN>; -+ reset-names = "aiu", "audin"; -+}; -+ -+&aiu_i2s { -+ clocks = <&clkc CLKID_I2S_OUT>, -+ <&clkc CLKID_MIXER_IFACE>, -+ <&clkc CLKID_AOCLK_GATE>, -+ <&clkc CLKID_CTS_AMCLK>; -+ clock-names = "fast", "iface", "bclks", "mclk"; -+}; -+ - &pwrc_vpu { - resets = <&reset RESET_VIU>, - <&reset RESET_VENC>, -@@ -797,6 +815,15 @@ - num-cs = <1>; - }; - -+&aiu_spdif { -+ clocks = <&clkc CLKID_IEC958>, -+ <&clkc CLKID_IEC958_GATE>, -+ <&clkc CLKID_CTS_MCLK_I958>, -+ <&clkc CLKID_CTS_AMCLK>, -+ <&clkc CLKID_CTS_I958>; -+ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk"; -+}; -+ - &spifc { - clocks = <&clkc CLKID_SPI>; - }; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -index 1d105047661ed..e30633e7824bc 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -@@ -712,6 +712,24 @@ - }; - }; - -+&audio { -+ clocks = <&clkc CLKID_AIU>, -+ <&clkc CLKID_AIU_GLUE>, -+ <&clkc CLKID_I2S_SPDIF>; -+ clock-names = "aiu_top", "aiu_glue", "audin"; -+ resets = <&reset RESET_AIU>, -+ <&reset RESET_AUDIN>; -+ reset-names = "aiu", "audin"; -+}; -+ -+&aiu_i2s { -+ clocks = <&clkc CLKID_I2S_OUT>, -+ <&clkc CLKID_MIXER_IFACE>, -+ <&clkc CLKID_AOCLK_GATE>, -+ <&clkc CLKID_CTS_AMCLK>; -+ clock-names = "fast", "iface", "bclks", "mclk"; -+}; -+ - &pwrc_vpu { - resets = <&reset RESET_VIU>, - <&reset RESET_VENC>, -@@ -800,6 +818,15 @@ - num-cs = <1>; - }; - -+&aiu_spdif { -+ clocks = <&clkc CLKID_IEC958>, -+ <&clkc CLKID_IEC958_GATE>, -+ <&clkc CLKID_CTS_MCLK_I958>, -+ <&clkc CLKID_CTS_AMCLK>, -+ <&clkc CLKID_CTS_I958>; -+ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk"; -+}; -+ - &spifc { - clocks = <&clkc CLKID_SPI>; - }; - -From 671225a756b59a2f8840744ba0ac876e8894daed Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Fri, 7 Jul 2017 17:39:21 +0200 -Subject: [PATCH 234/249] snd: meson: activate HDMI audio path - -Signed-off-by: Jerome Brunet ---- - sound/soc/meson-gx/aiu-i2s.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c -index 63d7821c2c72d..c6bfd5d8c8081 100644 ---- a/sound/soc/meson-gx/aiu-i2s.c -+++ b/sound/soc/meson-gx/aiu-i2s.c -@@ -334,8 +334,19 @@ static int meson_aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd) - #define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8) - #define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0) - #define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0) -+#define AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK BIT(6) -+#define AIU_CLK_CTRL_MORE_HDMI_TX_I958_CLK (0 << 6) -+#define AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK (1 << 6) - #define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0) - #define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0) -+#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK GENMASK(1, 0) -+#define AIU_HDMI_CLK_DATA_CTRL_CLK_DISABLE (0 << 0) -+#define AIU_HDMI_CLK_DATA_CTRL_CLK_PCM (1 << 0) -+#define AIU_HDMI_CLK_DATA_CTRL_CLK_I2S (2 << 0) -+#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK GENMASK(5, 4) -+#define AIU_HDMI_CLK_DATA_CTRL_DATA_MUTE (0 << 4) -+#define AIU_HDMI_CLK_DATA_CTRL_DATA_PCM (1 << 4) -+#define AIU_HDMI_CLK_DATA_CTRL_DATA_I2S (2 << 4) - #define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0) - #define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0) - #define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0) -@@ -499,6 +510,17 @@ static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, - return ret; - } - -+ /* Quick and dirty hack for HDMI */ -+ regmap_update_bits(priv->core->aiu, AIU_HDMI_CLK_DATA_CTRL, -+ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK | -+ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK, -+ AIU_HDMI_CLK_DATA_CTRL_CLK_I2S | -+ AIU_HDMI_CLK_DATA_CTRL_DATA_I2S); -+ -+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE, -+ AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK, -+ AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK); -+ - return 0; - } - - -From 2dadbc74cbfd814b3fb2c4ae5b189ba816975724 Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Wed, 20 Sep 2017 18:01:26 +0200 -Subject: [PATCH 235/249] ARM64: dts: meson-gx: add sound-dai-cells to HDMI - node - -Signed-off-by: Jerome Brunet ---- - arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 + - arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -index 277beb6e4f0b2..586f1a934b1a4 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi -@@ -330,6 +330,7 @@ - <&clkc CLKID_CLK81>, - <&clkc CLKID_GCLK_VENCI_INT0>; - clock-names = "isfr", "iahb", "venci"; -+ #sound-dai-cells = <0>; - }; - - &sysctrl { -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -index e30633e7824bc..54fd6af965eed 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi -@@ -280,6 +280,7 @@ - <&clkc CLKID_CLK81>, - <&clkc CLKID_GCLK_VENCI_INT0>; - clock-names = "isfr", "iahb", "venci"; -+ #sound-dai-cells = <0>; - }; - - &sysctrl { - -From d16b7150d1e7f6018ee4779d2caced3effc1163f Mon Sep 17 00:00:00 2001 -From: Jerome Brunet -Date: Wed, 20 Sep 2017 18:10:08 +0200 -Subject: [PATCH 236/249] ARM64: dts: meson: activate hdmi audio HDMI enabled - boards - -This patch activate audio over HDMI on selected boards - -Please note that this audio support is based on WIP changes -This should be considered as preview and it does not reflect -the audio I expect to see merged - -Signed-off-by: Jerome Brunet -Signed-off-by: Neil Armstrong ---- - .../boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 37 +++++++++++++++++++ - .../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 37 +++++++++++++++++++ - .../dts/amlogic/meson-gxbb-nexbox-a95x.dts | 37 +++++++++++++++++++ - .../boot/dts/amlogic/meson-gxbb-odroidc2.dts | 37 +++++++++++++++++++ - .../boot/dts/amlogic/meson-gxbb-p20x.dtsi | 37 +++++++++++++++++++ - .../boot/dts/amlogic/meson-gxbb-wetek.dtsi | 37 +++++++++++++++++++ - .../amlogic/meson-gxl-s905x-khadas-vim.dts | 37 +++++++++++++++++++ - .../amlogic/meson-gxl-s905x-libretech-cc.dts | 37 +++++++++++++++++++ - .../amlogic/meson-gxl-s905x-nexbox-a95x.dts | 37 +++++++++++++++++++ - .../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 37 +++++++++++++++++++ - .../dts/amlogic/meson-gxm-khadas-vim2.dts | 37 +++++++++++++++++++ - .../boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 37 +++++++++++++++++++ - 12 files changed, 444 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi -index 016641a41694a..398830b839bf1 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi -@@ -102,6 +102,35 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; - }; - - &cec_AO { -@@ -111,6 +140,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts -index ade2ee09ae962..d67ff037a25cf 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts -@@ -88,6 +88,35 @@ - clock-names = "ext_clock"; - }; - -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+ - vcc1v8: regulator-vcc1v8 { - compatible = "regulator-fixed"; - regulator-name = "VCC1.8V"; -@@ -131,6 +160,14 @@ - }; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cec_AO { - status = "okay"; - pinctrl-0 = <&ao_cec_pins>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts -index 25105ac96d559..6b01f7bb02c7e 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts -@@ -119,6 +119,35 @@ - clock-names = "ext_clock"; - }; - -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+ - cvbs-connector { - compatible = "composite-video-connector"; - -@@ -154,6 +183,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - ðmac { - status = "okay"; - pinctrl-0 = <ð_rmii_pins>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts -index 1cc9dc68ef00b..c3740edafdac4 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts -@@ -110,6 +110,35 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; - }; - - &cec_AO { -@@ -119,6 +148,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - ðmac { - status = "okay"; - pinctrl-0 = <ð_rgmii_pins>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi -index 0be0f2a5d2fe9..4a5db4380fe21 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi -@@ -113,6 +113,35 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; - }; - - &cec_AO { -@@ -122,6 +151,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -index 2d2db783c44c1..60ab0336d4cd7 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -@@ -105,6 +105,43 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+}; -+ -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; - }; - - &cec_AO { -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts -index 5499e8de5c74c..bf3453f549dc1 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts -@@ -65,6 +65,35 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; - }; - - &cec_AO { -@@ -74,6 +103,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &hdmi_tx { - status = "okay"; - pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts -index 255cede7b4476..79b09f637ccfb 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts -@@ -84,6 +84,35 @@ - regulator-always-on; - }; - -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+ - vcc_3v3: regulator-vcc_3v3 { - compatible = "regulator-fixed"; - regulator-name = "VCC_3V3"; -@@ -130,6 +159,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts -index 9cbdb85fb5917..7a5abee9e9096 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts -@@ -102,6 +102,35 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; - }; - - &cec_AO { -@@ -111,6 +140,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts -index 2602940c2077b..78c3060c5d567 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts -@@ -32,6 +32,35 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; - }; - - &cec_AO { -@@ -41,6 +70,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -index 3f086ed7de055..df101709d90c9 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -@@ -85,6 +85,35 @@ - }; - }; - -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+ - pwmleds { - compatible = "pwm-leds"; - -@@ -201,6 +230,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cpu0 { - #cooling-cells = <2>; - }; -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -index 8acfd40090d2e..93a968fa5a0d3 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -@@ -75,6 +75,35 @@ - }; - }; - }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "meson-gx-audio"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <256>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; - }; - - &cec_AO { -@@ -84,6 +113,14 @@ - hdmi-phandle = <&hdmi_tx>; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ - &cvbs_vdac_port { - cvbs_vdac_out: endpoint { - remote-endpoint = <&cvbs_connector_in>; - -From 7c9306b6ccfbc218bf2d9ac076cf7e06f351cf98 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 2 Jul 2018 12:21:55 +0200 -Subject: [PATCH 237/249] drm: bridge: dw-hdmi: Use AUTO CTS setup mode when - non-AHB audio - -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 41 ++++++++++++++--------- - 1 file changed, 26 insertions(+), 15 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index c68b6ed1bb35e..e4948dbcaa841 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -437,8 +437,12 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, - /* nshift factor = 0 */ - hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); - -- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | -- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); -+ /* Use Auto CTS mode with CTS is unknown */ -+ if (cts) -+ hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | -+ HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); -+ else -+ hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3); - hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); - hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); - -@@ -508,24 +512,31 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, - { - unsigned long ftdms = pixel_clk; - unsigned int n, cts; -+ u8 config3; - u64 tmp; - - n = hdmi_compute_n(sample_rate, pixel_clk); - -- /* -- * Compute the CTS value from the N value. Note that CTS and N -- * can be up to 20 bits in total, so we need 64-bit math. Also -- * note that our TDMS clock is not fully accurate; it is accurate -- * to kHz. This can introduce an unnecessary remainder in the -- * calculation below, so we don't try to warn about that. -- */ -- tmp = (u64)ftdms * n; -- do_div(tmp, 128 * sample_rate); -- cts = tmp; -+ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); - -- dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", -- __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000, -- n, cts); -+ if (config3 & HDMI_CONFIG3_AHBAUDDMA) { -+ /* -+ * Compute the CTS value from the N value. Note that CTS and N -+ * can be up to 20 bits in total, so we need 64-bit math. Also -+ * note that our TDMS clock is not fully accurate; it is -+ * accurate to kHz. This can introduce an unnecessary remainder -+ * in the calculation below, so we don't try to warn about that. -+ */ -+ tmp = (u64)ftdms * n; -+ do_div(tmp, 128 * sample_rate); -+ cts = tmp; -+ -+ dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", -+ __func__, sample_rate, -+ ftdms / 1000000, (ftdms / 1000) % 1000, -+ n, cts); -+ } else -+ cts = 0; - - spin_lock_irq(&hdmi->audio_lock); - hdmi->audio_n = n; - -From 7fe6319492989af793de178ecb44718186e232b7 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Mon, 25 Feb 2019 22:07:16 +0800 -Subject: [PATCH 238/249] drm: export drm_timeout_abs_to_jiffies - -For other driver like lima usage. - -Cc: Rob Herring -Signed-off-by: Qiang Yu -Signed-off-by: Rob Herring -Link: https://patchwork.freedesktop.org/patch/msgid/20190225140717.20586-2-yuq825@gmail.com -(cherry picked from commit 877b372996bfd4f195d363d22de89571c9faab38) ---- - drivers/gpu/drm/drm_syncobj.c | 3 ++- - include/drm/drm_utils.h | 4 ++++ - 2 files changed, 6 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c -index e19525af0ccee..5329e66598c63 100644 ---- a/drivers/gpu/drm/drm_syncobj.c -+++ b/drivers/gpu/drm/drm_syncobj.c -@@ -731,7 +731,7 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, - * - * Calculate the timeout in jiffies from an absolute time in sec/nsec. - */ --static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) -+signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) - { - ktime_t abs_timeout, now; - u64 timeout_ns, timeout_jiffies64; -@@ -755,6 +755,7 @@ static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) - - return timeout_jiffies64 + 1; - } -+EXPORT_SYMBOL(drm_timeout_abs_to_jiffies); - - static int drm_syncobj_array_wait(struct drm_device *dev, - struct drm_file *file_private, -diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h -index a803988d85792..70775748d243b 100644 ---- a/include/drm/drm_utils.h -+++ b/include/drm/drm_utils.h -@@ -10,6 +10,10 @@ - #ifndef __DRM_UTILS_H__ - #define __DRM_UTILS_H__ - -+#include -+ - int drm_get_panel_orientation_quirk(int width, int height); - -+signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec); -+ - #endif - -From d95904cfc1605336b6454acab8df4e932bdfc3df Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Tue, 27 Nov 2018 12:38:20 -0800 -Subject: [PATCH 239/249] drm: Add library for shmem backed GEM objects -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds a library for shmem backed GEM objects. - -v8: -- export drm_gem_shmem_create_with_handle -- call mapping_set_gfp_mask to set default zone to GFP_HIGHUSER -- Add helper drm_gem_shmem_get_pages_sgt() - -v7: -- Use write-combine for mmap instead. This is the more common - case. (robher) - -v6: -- Fix uninitialized variable issue in an error path (anholt). -- Add a drm_gem_shmem_vm_open() to the fops to get proper refcounting - of the pages (anholt). - -v5: -- Drop drm_gem_shmem_prime_mmap() (Daniel Vetter) -- drm_gem_shmem_mmap(): Subtract drm_vma_node_start() to get the real - vma->vm_pgoff -- drm_gem_shmem_fault(): Use vmf->pgoff now that vma->vm_pgoff is correct - -v4: -- Drop cache modes (Thomas Hellstrom) -- Add a GEM attached vtable - -v3: -- Grammar (Sam Ravnborg) -- s/drm_gem_shmem_put_pages_unlocked/drm_gem_shmem_put_pages_locked/ - (Sam Ravnborg) -- Add debug output in error path (Sam Ravnborg) - -Signed-off-by: Noralf Trønnes -Signed-off-by: Eric Anholt -Signed-off-by: Rob Herring - -shmem: set mapping zone - -Signed-off-by: Rob Herring - -shmem fixes - -(cherry picked from commit 403e85012e9ee0a2a113bec757f545df193cfb7a) ---- - Documentation/gpu/drm-kms-helpers.rst | 12 + - drivers/gpu/drm/Kconfig | 6 + - drivers/gpu/drm/Makefile | 1 + - drivers/gpu/drm/drm_gem_shmem_helper.c | 625 +++++++++++++++++++++++++ - include/drm/drm_gem_shmem_helper.h | 159 +++++++ - 5 files changed, 803 insertions(+) - create mode 100644 drivers/gpu/drm/drm_gem_shmem_helper.c - create mode 100644 include/drm/drm_gem_shmem_helper.h - -diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst -index 17ca7f8bf3d3c..58b375e47615b 100644 ---- a/Documentation/gpu/drm-kms-helpers.rst -+++ b/Documentation/gpu/drm-kms-helpers.rst -@@ -369,3 +369,15 @@ Legacy CRTC/Modeset Helper Functions Reference - - .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c - :export: -+ -+SHMEM GEM Helper Reference -+========================== -+ -+.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c -+ :doc: overview -+ -+.. kernel-doc:: include/drm/drm_gem_shmem_helper.h -+ :internal: -+ -+.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c -+ :export: -diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig -index bd943a71756ca..febdc102b75c2 100644 ---- a/drivers/gpu/drm/Kconfig -+++ b/drivers/gpu/drm/Kconfig -@@ -173,6 +173,12 @@ config DRM_KMS_CMA_HELPER - help - Choose this if you need the KMS CMA helper functions - -+config DRM_GEM_SHMEM_HELPER -+ bool -+ depends on DRM -+ help -+ Choose this if you need the GEM shmem helper functions -+ - config DRM_VM - bool - depends on DRM && MMU -diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile -index 1ac55c65eac0d..7476ed945e303 100644 ---- a/drivers/gpu/drm/Makefile -+++ b/drivers/gpu/drm/Makefile -@@ -25,6 +25,7 @@ drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o - drm-$(CONFIG_DRM_VM) += drm_vm.o - drm-$(CONFIG_COMPAT) += drm_ioc32.o - drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o -+drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o - drm-$(CONFIG_PCI) += ati_pcigart.o - drm-$(CONFIG_DRM_PANEL) += drm_panel.o - drm-$(CONFIG_OF) += drm_of.o -diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c -new file mode 100644 -index 0000000000000..3750a982aaf6b ---- /dev/null -+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c -@@ -0,0 +1,625 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright 2018 Noralf Trønnes -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * DOC: overview -+ * -+ * This library provides helpers for GEM objects backed by shmem buffers -+ * allocated using anonymous pageable memory. -+ */ -+ -+static const struct drm_gem_object_funcs drm_gem_shmem_funcs = { -+ .free = drm_gem_shmem_free_object, -+ .print_info = drm_gem_shmem_print_info, -+ .pin = drm_gem_shmem_pin, -+ .unpin = drm_gem_shmem_unpin, -+ .get_sg_table = drm_gem_shmem_get_sg_table, -+ .vmap = drm_gem_shmem_vmap, -+ .vunmap = drm_gem_shmem_vunmap, -+ .vm_ops = &drm_gem_shmem_vm_ops, -+}; -+ -+/** -+ * drm_gem_shmem_create - Allocate an object with the given size -+ * @dev: DRM device -+ * @size: Size of the object to allocate -+ * -+ * This function creates a shmem GEM object. -+ * -+ * Returns: -+ * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative -+ * error code on failure. -+ */ -+struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size) -+{ -+ struct drm_gem_shmem_object *shmem; -+ struct drm_gem_object *obj; -+ int ret; -+ -+ size = PAGE_ALIGN(size); -+ -+ if (dev->driver->gem_create_object) -+ obj = dev->driver->gem_create_object(dev, size); -+ else -+ obj = kzalloc(sizeof(*shmem), GFP_KERNEL); -+ if (!obj) -+ return ERR_PTR(-ENOMEM); -+ -+ if (!obj->funcs) -+ obj->funcs = &drm_gem_shmem_funcs; -+ -+ ret = drm_gem_object_init(dev, obj, size); -+ if (ret) -+ goto err_free; -+ -+ ret = drm_gem_create_mmap_offset(obj); -+ if (ret) -+ goto err_release; -+ -+ shmem = to_drm_gem_shmem_obj(obj); -+ mutex_init(&shmem->pages_lock); -+ mutex_init(&shmem->vmap_lock); -+ -+ /* -+ * Our buffers are kept pinned, so allocating them -+ * from the MOVABLE zone is a really bad idea, and -+ * conflicts with CMA. See comments above new_inode() -+ * why this is required _and_ expected if you're -+ * going to pin these pages. -+ */ -+ mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER | -+ __GFP_RETRY_MAYFAIL | __GFP_NOWARN); -+ -+ return shmem; -+ -+err_release: -+ drm_gem_object_release(obj); -+err_free: -+ kfree(obj); -+ -+ return ERR_PTR(ret); -+} -+EXPORT_SYMBOL_GPL(drm_gem_shmem_create); -+ -+/** -+ * drm_gem_shmem_free_object - Free resources associated with a shmem GEM object -+ * @obj: GEM object to free -+ * -+ * This function cleans up the GEM object state and frees the memory used to -+ * store the object itself. -+ */ -+void drm_gem_shmem_free_object(struct drm_gem_object *obj) -+{ -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ -+ WARN_ON(shmem->vmap_use_count); -+ -+ if (obj->import_attach) { -+ shmem->pages_use_count--; -+ drm_prime_gem_destroy(obj, shmem->sgt); -+ kvfree(shmem->pages); -+ } else { -+ if (shmem->sgt) { -+ dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl, -+ shmem->sgt->nents, DMA_BIDIRECTIONAL); -+ -+ drm_gem_shmem_put_pages(shmem); -+ sg_free_table(shmem->sgt); -+ kfree(shmem->sgt); -+ } -+ } -+ -+ WARN_ON(shmem->pages_use_count); -+ -+ drm_gem_object_release(obj); -+ mutex_destroy(&shmem->pages_lock); -+ mutex_destroy(&shmem->vmap_lock); -+ kfree(shmem); -+} -+EXPORT_SYMBOL_GPL(drm_gem_shmem_free_object); -+ -+static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem) -+{ -+ struct drm_gem_object *obj = &shmem->base; -+ struct page **pages; -+ -+ if (shmem->pages_use_count++ > 0) -+ return 0; -+ -+ pages = drm_gem_get_pages(obj); -+ if (IS_ERR(pages)) { -+ DRM_DEBUG_KMS("Failed to get pages (%ld)\n", PTR_ERR(pages)); -+ shmem->pages_use_count = 0; -+ return PTR_ERR(pages); -+ } -+ -+ shmem->pages = pages; -+ -+ return 0; -+} -+ -+/* -+ * drm_gem_shmem_get_pages - Allocate backing pages for a shmem GEM object -+ * @shmem: shmem GEM object -+ * -+ * This function makes sure that backing pages exists for the shmem GEM object -+ * and increases the use count. -+ * -+ * Returns: -+ * 0 on success or a negative error code on failure. -+ */ -+int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem) -+{ -+ int ret; -+ -+ ret = mutex_lock_interruptible(&shmem->pages_lock); -+ if (ret) -+ return ret; -+ ret = drm_gem_shmem_get_pages_locked(shmem); -+ mutex_unlock(&shmem->pages_lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(drm_gem_shmem_get_pages); -+ -+static void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem) -+{ -+ struct drm_gem_object *obj = &shmem->base; -+ -+ if (WARN_ON_ONCE(!shmem->pages_use_count)) -+ return; -+ -+ if (--shmem->pages_use_count > 0) -+ return; -+ -+ drm_gem_put_pages(obj, shmem->pages, -+ shmem->pages_mark_dirty_on_put, -+ shmem->pages_mark_accessed_on_put); -+ shmem->pages = NULL; -+} -+ -+/* -+ * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object -+ * @shmem: shmem GEM object -+ * -+ * This function decreases the use count and puts the backing pages when use drops to zero. -+ */ -+void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem) -+{ -+ mutex_lock(&shmem->pages_lock); -+ drm_gem_shmem_put_pages_locked(shmem); -+ mutex_unlock(&shmem->pages_lock); -+} -+EXPORT_SYMBOL(drm_gem_shmem_put_pages); -+ -+/** -+ * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object -+ * @obj: GEM object -+ * -+ * This function makes sure the backing pages are pinned in memory while the -+ * buffer is exported. -+ * -+ * Returns: -+ * 0 on success or a negative error code on failure. -+ */ -+int drm_gem_shmem_pin(struct drm_gem_object *obj) -+{ -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ -+ return drm_gem_shmem_get_pages(shmem); -+} -+EXPORT_SYMBOL(drm_gem_shmem_pin); -+ -+/** -+ * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object -+ * @obj: GEM object -+ * -+ * This function removes the requirement that the backing pages are pinned in -+ * memory. -+ */ -+void drm_gem_shmem_unpin(struct drm_gem_object *obj) -+{ -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ -+ drm_gem_shmem_put_pages(shmem); -+} -+EXPORT_SYMBOL(drm_gem_shmem_unpin); -+ -+static void *drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem) -+{ -+ struct drm_gem_object *obj = &shmem->base; -+ int ret; -+ -+ if (shmem->vmap_use_count++ > 0) -+ return shmem->vaddr; -+ -+ ret = drm_gem_shmem_get_pages(shmem); -+ if (ret) -+ goto err_zero_use; -+ -+ if (obj->import_attach) -+ shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf); -+ else -+ shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT, VM_MAP, PAGE_KERNEL); -+ -+ if (!shmem->vaddr) { -+ DRM_DEBUG_KMS("Failed to vmap pages\n"); -+ ret = -ENOMEM; -+ goto err_put_pages; -+ } -+ -+ return shmem->vaddr; -+ -+err_put_pages: -+ drm_gem_shmem_put_pages(shmem); -+err_zero_use: -+ shmem->vmap_use_count = 0; -+ -+ return ERR_PTR(ret); -+} -+ -+/* -+ * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object -+ * @shmem: shmem GEM object -+ * -+ * This function makes sure that a virtual address exists for the buffer backing -+ * the shmem GEM object. -+ * -+ * Returns: -+ * 0 on success or a negative error code on failure. -+ */ -+void *drm_gem_shmem_vmap(struct drm_gem_object *obj) -+{ -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ void *vaddr; -+ int ret; -+ -+ ret = mutex_lock_interruptible(&shmem->vmap_lock); -+ if (ret) -+ return ERR_PTR(ret); -+ vaddr = drm_gem_shmem_vmap_locked(shmem); -+ mutex_unlock(&shmem->vmap_lock); -+ -+ return vaddr; -+} -+EXPORT_SYMBOL(drm_gem_shmem_vmap); -+ -+static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem) -+{ -+ struct drm_gem_object *obj = &shmem->base; -+ -+ if (WARN_ON_ONCE(!shmem->vmap_use_count)) -+ return; -+ -+ if (--shmem->vmap_use_count > 0) -+ return; -+ -+ if (obj->import_attach) -+ dma_buf_vunmap(obj->import_attach->dmabuf, shmem->vaddr); -+ else -+ vunmap(shmem->vaddr); -+ -+ shmem->vaddr = NULL; -+ drm_gem_shmem_put_pages(shmem); -+} -+ -+/* -+ * drm_gem_shmem_vunmap - Unmap a virtual mapping fo a shmem GEM object -+ * @shmem: shmem GEM object -+ * -+ * This function removes the virtual address when use count drops to zero. -+ */ -+void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr) -+{ -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ -+ mutex_lock(&shmem->vmap_lock); -+ drm_gem_shmem_vunmap_locked(shmem); -+ mutex_unlock(&shmem->vmap_lock); -+} -+EXPORT_SYMBOL(drm_gem_shmem_vunmap); -+ -+struct drm_gem_shmem_object * -+drm_gem_shmem_create_with_handle(struct drm_file *file_priv, -+ struct drm_device *dev, size_t size, -+ uint32_t *handle) -+{ -+ struct drm_gem_shmem_object *shmem; -+ int ret; -+ -+ shmem = drm_gem_shmem_create(dev, size); -+ if (IS_ERR(shmem)) -+ return shmem; -+ -+ /* -+ * Allocate an id of idr table where the obj is registered -+ * and handle has the id what user can see. -+ */ -+ ret = drm_gem_handle_create(file_priv, &shmem->base, handle); -+ /* drop reference from allocate - handle holds it now. */ -+ drm_gem_object_put_unlocked(&shmem->base); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ return shmem; -+} -+EXPORT_SYMBOL(drm_gem_shmem_create_with_handle); -+ -+/** -+ * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object -+ * @file: DRM file structure to create the dumb buffer for -+ * @dev: DRM device -+ * @args: IOCTL data -+ * -+ * This function computes the pitch of the dumb buffer and rounds it up to an -+ * integer number of bytes per pixel. Drivers for hardware that doesn't have -+ * any additional restrictions on the pitch can directly use this function as -+ * their &drm_driver.dumb_create callback. -+ * -+ * For hardware with additional restrictions, drivers can adjust the fields -+ * set up by userspace before calling into this function. -+ * -+ * Returns: -+ * 0 on success or a negative error code on failure. -+ */ -+int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, -+ struct drm_mode_create_dumb *args) -+{ -+ u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); -+ struct drm_gem_shmem_object *shmem; -+ -+ if (!args->pitch || !args->size) { -+ args->pitch = min_pitch; -+ args->size = args->pitch * args->height; -+ } else { -+ /* ensure sane minimum values */ -+ if (args->pitch < min_pitch) -+ args->pitch = min_pitch; -+ if (args->size < args->pitch * args->height) -+ args->size = args->pitch * args->height; -+ } -+ -+ shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle); -+ -+ return PTR_ERR_OR_ZERO(shmem); -+} -+EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); -+ -+static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) -+{ -+ struct vm_area_struct *vma = vmf->vma; -+ struct drm_gem_object *obj = vma->vm_private_data; -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ loff_t num_pages = obj->size >> PAGE_SHIFT; -+ struct page *page; -+ -+ if (vmf->pgoff > num_pages || WARN_ON_ONCE(!shmem->pages)) -+ return VM_FAULT_SIGBUS; -+ -+ page = shmem->pages[vmf->pgoff]; -+ -+ return vmf_insert_page(vma, vmf->address, page); -+} -+ -+static void drm_gem_shmem_vm_open(struct vm_area_struct *vma) -+{ -+ struct drm_gem_object *obj = vma->vm_private_data; -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ int ret; -+ -+ ret = drm_gem_shmem_get_pages(shmem); -+ WARN_ON_ONCE(ret != 0); -+ -+ drm_gem_vm_open(vma); -+} -+ -+static void drm_gem_shmem_vm_close(struct vm_area_struct *vma) -+{ -+ struct drm_gem_object *obj = vma->vm_private_data; -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ -+ drm_gem_shmem_put_pages(shmem); -+ drm_gem_vm_close(vma); -+} -+ -+const struct vm_operations_struct drm_gem_shmem_vm_ops = { -+ .fault = drm_gem_shmem_fault, -+ .open = drm_gem_shmem_vm_open, -+ .close = drm_gem_shmem_vm_close, -+}; -+EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops); -+ -+/** -+ * drm_gem_shmem_mmap - Memory-map a shmem GEM object -+ * @filp: File object -+ * @vma: VMA for the area to be mapped -+ * -+ * This function implements an augmented version of the GEM DRM file mmap -+ * operation for shmem objects. Drivers which employ the shmem helpers should -+ * use this function as their &file_operations.mmap handler in the DRM device file's -+ * file_operations structure. -+ * -+ * Instead of directly referencing this function, drivers should use the -+ * DEFINE_DRM_GEM_SHMEM_FOPS() macro. -+ * -+ * Returns: -+ * 0 on success or a negative error code on failure. -+ */ -+int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma) -+{ -+ struct drm_gem_shmem_object *shmem; -+ int ret; -+ -+ ret = drm_gem_mmap(filp, vma); -+ if (ret) -+ return ret; -+ -+ shmem = to_drm_gem_shmem_obj(vma->vm_private_data); -+ -+ ret = drm_gem_shmem_get_pages(shmem); -+ if (ret) { -+ drm_gem_vm_close(vma); -+ return ret; -+ } -+ -+ /* VM_PFNMAP was set by drm_gem_mmap() */ -+ vma->vm_flags &= ~VM_PFNMAP; -+ vma->vm_flags |= VM_MIXEDMAP; -+ -+ /* Remove the fake offset */ -+ vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap); -+ -+/** -+ * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs -+ * @p: DRM printer -+ * @indent: Tab indentation level -+ * @obj: GEM object -+ */ -+void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent, -+ const struct drm_gem_object *obj) -+{ -+ const struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ -+ drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count); -+ drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count); -+ drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr); -+} -+EXPORT_SYMBOL(drm_gem_shmem_print_info); -+ -+/** -+ * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned -+ * pages for a shmem GEM object -+ * @obj: GEM object -+ * -+ * This function exports a scatter/gather table suitable for PRIME usage by -+ * calling the standard DMA mapping API. -+ * -+ * Returns: -+ * A pointer to the scatter/gather table of pinned pages or NULL on failure. -+ */ -+struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj) -+{ -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ -+ return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT); -+} -+EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table); -+ -+/** -+ * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a -+ * scatter/gather table for a shmem GEM object. -+ * @obj: GEM object -+ * -+ * This function returns a scatter/gather table suitable for driver usage. If -+ * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg -+ * table created. -+ * -+ * Returns: -+ * A pointer to the scatter/gather table of pinned pages or errno on failure. -+ */ -+struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_object *obj) -+{ -+ int ret; -+ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); -+ struct sg_table *sgt; -+ -+ if (shmem->sgt) -+ return shmem->sgt; -+ -+ WARN_ON(obj->import_attach); -+ -+ ret = drm_gem_shmem_get_pages(shmem); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ sgt = drm_gem_shmem_get_sg_table(&shmem->base); -+ if (IS_ERR(sgt)) { -+ ret = PTR_ERR(sgt); -+ goto err_put_pages; -+ } -+ /* Map the pages for use by the h/w. */ -+ dma_map_sg(obj->dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL); -+ -+ shmem->sgt = sgt; -+ -+ return sgt; -+ -+err_put_pages: -+ drm_gem_shmem_put_pages(shmem); -+ return ERR_PTR(ret); -+} -+EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt); -+ -+/** -+ * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from -+ * another driver's scatter/gather table of pinned pages -+ * @dev: Device to import into -+ * @attach: DMA-BUF attachment -+ * @sgt: Scatter/gather table of pinned pages -+ * -+ * This function imports a scatter/gather table exported via DMA-BUF by -+ * another driver. Drivers that use the shmem helpers should set this as their -+ * &drm_driver.gem_prime_import_sg_table callback. -+ * -+ * Returns: -+ * A pointer to a newly created GEM object or an ERR_PTR-encoded negative -+ * error code on failure. -+ */ -+struct drm_gem_object * -+drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, -+ struct dma_buf_attachment *attach, -+ struct sg_table *sgt) -+{ -+ size_t size = PAGE_ALIGN(attach->dmabuf->size); -+ size_t npages = size >> PAGE_SHIFT; -+ struct drm_gem_shmem_object *shmem; -+ int ret; -+ -+ shmem = drm_gem_shmem_create(dev, size); -+ if (IS_ERR(shmem)) -+ return ERR_CAST(shmem); -+ -+ shmem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); -+ if (!shmem->pages) { -+ ret = -ENOMEM; -+ goto err_free_gem; -+ } -+ -+ ret = drm_prime_sg_to_page_addr_arrays(sgt, shmem->pages, NULL, npages); -+ if (ret < 0) -+ goto err_free_array; -+ -+ shmem->sgt = sgt; -+ shmem->pages_use_count = 1; /* Permanently pinned from our point of view */ -+ -+ DRM_DEBUG_PRIME("size = %zu\n", size); -+ -+ return &shmem->base; -+ -+err_free_array: -+ kvfree(shmem->pages); -+err_free_gem: -+ drm_gem_object_put_unlocked(&shmem->base); -+ -+ return ERR_PTR(ret); -+} -+EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table); -diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h -new file mode 100644 -index 0000000000000..038b6d3134471 ---- /dev/null -+++ b/include/drm/drm_gem_shmem_helper.h -@@ -0,0 +1,159 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+#ifndef __DRM_GEM_SHMEM_HELPER_H__ -+#define __DRM_GEM_SHMEM_HELPER_H__ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+struct dma_buf_attachment; -+struct drm_mode_create_dumb; -+struct drm_printer; -+struct sg_table; -+ -+/** -+ * struct drm_gem_shmem_object - GEM object backed by shmem -+ */ -+struct drm_gem_shmem_object { -+ /** -+ * @base: Base GEM object -+ */ -+ struct drm_gem_object base; -+ -+ /** -+ * @pages_lock: Protects the page table and use count -+ */ -+ struct mutex pages_lock; -+ -+ /** -+ * @pages: Page table -+ */ -+ struct page **pages; -+ -+ /** -+ * @pages_use_count: -+ * -+ * Reference count on the pages table. -+ * The pages are put when the count reaches zero. -+ */ -+ unsigned int pages_use_count; -+ -+ /** -+ * @pages_mark_dirty_on_put: -+ * -+ * Mark pages as dirty when they are put. -+ */ -+ unsigned int pages_mark_dirty_on_put : 1; -+ -+ /** -+ * @pages_mark_accessed_on_put: -+ * -+ * Mark pages as accessed when they are put. -+ */ -+ unsigned int pages_mark_accessed_on_put : 1; -+ -+ /** -+ * @sgt: Scatter/gather table for imported PRIME buffers -+ */ -+ struct sg_table *sgt; -+ -+ /** -+ * @vmap_lock: Protects the vmap address and use count -+ */ -+ struct mutex vmap_lock; -+ -+ /** -+ * @vaddr: Kernel virtual address of the backing memory -+ */ -+ void *vaddr; -+ -+ /** -+ * @vmap_use_count: -+ * -+ * Reference count on the virtual address. -+ * The address are un-mapped when the count reaches zero. -+ */ -+ unsigned int vmap_use_count; -+}; -+ -+#define to_drm_gem_shmem_obj(obj) \ -+ container_of(obj, struct drm_gem_shmem_object, base) -+ -+/** -+ * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers -+ * @name: name for the generated structure -+ * -+ * This macro autogenerates a suitable &struct file_operations for shmem based -+ * drivers, which can be assigned to &drm_driver.fops. Note that this structure -+ * cannot be shared between drivers, because it contains a reference to the -+ * current module using THIS_MODULE. -+ * -+ * Note that the declaration is already marked as static - if you need a -+ * non-static version of this you're probably doing it wrong and will break the -+ * THIS_MODULE reference by accident. -+ */ -+#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \ -+ static const struct file_operations name = {\ -+ .owner = THIS_MODULE,\ -+ .open = drm_open,\ -+ .release = drm_release,\ -+ .unlocked_ioctl = drm_ioctl,\ -+ .compat_ioctl = drm_compat_ioctl,\ -+ .poll = drm_poll,\ -+ .read = drm_read,\ -+ .llseek = noop_llseek,\ -+ .mmap = drm_gem_shmem_mmap, \ -+ } -+ -+struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size); -+void drm_gem_shmem_free_object(struct drm_gem_object *obj); -+ -+int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem); -+void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem); -+int drm_gem_shmem_pin(struct drm_gem_object *obj); -+void drm_gem_shmem_unpin(struct drm_gem_object *obj); -+void *drm_gem_shmem_vmap(struct drm_gem_object *obj); -+void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr); -+ -+struct drm_gem_shmem_object * -+drm_gem_shmem_create_with_handle(struct drm_file *file_priv, -+ struct drm_device *dev, size_t size, -+ uint32_t *handle); -+int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, -+ struct drm_mode_create_dumb *args); -+ -+int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma); -+ -+extern const struct vm_operations_struct drm_gem_shmem_vm_ops; -+ -+void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent, -+ const struct drm_gem_object *obj); -+ -+struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj); -+struct drm_gem_object * -+drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, -+ struct dma_buf_attachment *attach, -+ struct sg_table *sgt); -+ -+struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_object *obj); -+ -+/** -+ * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations -+ * -+ * This macro provides a shortcut for setting the shmem GEM operations in -+ * the &drm_driver structure. -+ */ -+#define DRM_GEM_SHMEM_DRIVER_OPS \ -+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, \ -+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, \ -+ .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \ -+ .gem_prime_mmap = drm_gem_prime_mmap, \ -+ .dumb_create = drm_gem_shmem_dumb_create -+ -+#endif /* __DRM_GEM_SHMEM_HELPER_H__ */ - -From de612cb421aeed0335762c01e2c344ee6323504b Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Sat, 2 Feb 2019 09:41:54 -0600 -Subject: [PATCH 240/249] drm: Add reservation_object to drm_gem_object - -Many users of drm_gem_object embed a struct reservation_object into -their subclassed struct, so let's add one to struct drm_gem_object. -This will allow removing the reservation object from the subclasses -and removing the ->gem_prime_res_obj callback. - -With the addition, add a drm_gem_reservation_object_wait() helper -function for drivers to use in wait ioctls. - -Cc: Maarten Lankhorst -Cc: Maxime Ripard -Cc: Sean Paul -Cc: David Airlie -Cc: Daniel Vetter -Signed-off-by: Rob Herring -Acked-by: Daniel Vetter -Reviewed-by: Eric Anholt -Reviewed-by: Christian Gmeiner -Link: https://patchwork.freedesktop.org/patch/msgid/20190202154158.10443-2-robh@kernel.org -Signed-off-by: Maxime Ripard -(cherry picked from commit 1ba627148ef5d9dee879585687c4b0ee644f7ab5) ---- - Documentation/gpu/todo.rst | 8 +++---- - drivers/gpu/drm/drm_gem.c | 43 +++++++++++++++++++++++++++++++++++++ - drivers/gpu/drm/drm_prime.c | 1 + - include/drm/drm_gem.h | 21 ++++++++++++++++++ - 4 files changed, 69 insertions(+), 4 deletions(-) - -diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst -index 159a4aba49e6e..4afbc186f119c 100644 ---- a/Documentation/gpu/todo.rst -+++ b/Documentation/gpu/todo.rst -@@ -215,12 +215,12 @@ Might be good to also have some igt testcases for this. - - Contact: Daniel Vetter, Noralf Tronnes - --Put a reservation_object into drm_gem_object -+Remove the ->gem_prime_res_obj callback - -------------------------------------------- - --This would remove the need for the ->gem_prime_res_obj callback. It would also --allow us to implement generic helpers for waiting for a bo, allowing for quite a --bit of refactoring in the various wait ioctl implementations. -+The ->gem_prime_res_obj callback can be removed from drivers by using the -+reservation_object in the drm_gem_object. It may also be possible to use the -+generic drm_gem_reservation_object_wait helper for waiting for a bo. - - Contact: Daniel Vetter - -diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c -index d0b9f6a9953f3..ad124f5a6f4da 100644 ---- a/drivers/gpu/drm/drm_gem.c -+++ b/drivers/gpu/drm/drm_gem.c -@@ -171,6 +171,10 @@ void drm_gem_private_object_init(struct drm_device *dev, - kref_init(&obj->refcount); - obj->handle_count = 0; - obj->size = size; -+ reservation_object_init(&obj->_resv); -+ if (!obj->resv) -+ obj->resv = &obj->_resv; -+ - drm_vma_node_reset(&obj->vma_node); - } - EXPORT_SYMBOL(drm_gem_private_object_init); -@@ -687,6 +691,44 @@ drm_gem_object_lookup(struct drm_file *filp, u32 handle) - } - EXPORT_SYMBOL(drm_gem_object_lookup); - -+/** -+ * drm_gem_reservation_object_wait - Wait on GEM object's reservation's objects -+ * shared and/or exclusive fences. -+ * @filep: DRM file private date -+ * @handle: userspace handle -+ * @wait_all: if true, wait on all fences, else wait on just exclusive fence -+ * @timeout: timeout value in jiffies or zero to return immediately -+ * -+ * Returns: -+ * -+ * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or -+ * greater than 0 on success. -+ */ -+long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, -+ bool wait_all, unsigned long timeout) -+{ -+ long ret; -+ struct drm_gem_object *obj; -+ -+ obj = drm_gem_object_lookup(filep, handle); -+ if (!obj) { -+ DRM_DEBUG("Failed to look up GEM BO %d\n", handle); -+ return -EINVAL; -+ } -+ -+ ret = reservation_object_wait_timeout_rcu(obj->resv, wait_all, -+ true, timeout); -+ if (ret == 0) -+ ret = -ETIME; -+ else if (ret > 0) -+ ret = 0; -+ -+ drm_gem_object_put_unlocked(obj); -+ -+ return ret; -+} -+EXPORT_SYMBOL(drm_gem_reservation_object_wait); -+ - /** - * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl - * @dev: drm_device -@@ -851,6 +893,7 @@ drm_gem_object_release(struct drm_gem_object *obj) - if (obj->filp) - fput(obj->filp); - -+ reservation_object_fini(&obj->_resv); - drm_gem_free_mmap_offset(obj); - } - EXPORT_SYMBOL(drm_gem_object_release); -diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c -index 231e3f6d5f416..dc079efb3b0fc 100644 ---- a/drivers/gpu/drm/drm_prime.c -+++ b/drivers/gpu/drm/drm_prime.c -@@ -504,6 +504,7 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev, - .size = obj->size, - .flags = flags, - .priv = obj, -+ .resv = obj->resv, - }; - - if (dev->driver->gem_prime_res_obj) -diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h -index c957274252844..25f1ff2df464a 100644 ---- a/include/drm/drm_gem.h -+++ b/include/drm/drm_gem.h -@@ -35,6 +35,7 @@ - */ - - #include -+#include - - #include - -@@ -262,6 +263,24 @@ struct drm_gem_object { - */ - struct dma_buf_attachment *import_attach; - -+ /** -+ * @resv: -+ * -+ * Pointer to reservation object associated with the this GEM object. -+ * -+ * Normally (@resv == &@_resv) except for imported GEM objects. -+ */ -+ struct reservation_object *resv; -+ -+ /** -+ * @_resv: -+ * -+ * A reservation object for this GEM object. -+ * -+ * This is unused for imported GEM objects. -+ */ -+ struct reservation_object _resv; -+ - /** - * @funcs: - * -@@ -363,6 +382,8 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, - bool dirty, bool accessed); - - struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); -+long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, -+ bool wait_all, unsigned long timeout); - int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, - u32 handle, u64 *offset); - int drm_gem_dumb_destroy(struct drm_file *file, - -From bfd2175626cc4c247ad1a146a5c98674aaddf56c Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Fri, 8 Mar 2019 08:17:13 -0800 -Subject: [PATCH 241/249] drm: Add helpers for locking an array of BO - reservations. - -Now that we have the reservation object in the GEM object, it's easy -to provide a helper for this common case. Noticed while reviewing -panfrost and lima drivers. This particular version came out of v3d, -which in turn was a copy from vc4. - -v2: Fix kerneldoc warnings. - -Signed-off-by: Eric Anholt -Link: https://patchwork.freedesktop.org/patch/msgid/20190308161716.2466-2-eric@anholt.net -Acked-by: Rob Herring (v1) -(cherry picked from commit 7edc3e3b975b5b3b1de313f43670738acbcc8e1d) ---- - drivers/gpu/drm/drm_gem.c | 78 +++++++++++++++++++++++++++++++++++++++ - include/drm/drm_gem.h | 4 ++ - 2 files changed, 82 insertions(+) - -diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c -index ad124f5a6f4da..388b3742e562a 100644 ---- a/drivers/gpu/drm/drm_gem.c -+++ b/drivers/gpu/drm/drm_gem.c -@@ -1233,3 +1233,81 @@ void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr) - obj->dev->driver->gem_prime_vunmap(obj, vaddr); - } - EXPORT_SYMBOL(drm_gem_vunmap); -+ -+/** -+ * drm_gem_lock_reservations - Sets up the ww context and acquires -+ * the lock on an array of GEM objects. -+ * -+ * Once you've locked your reservations, you'll want to set up space -+ * for your shared fences (if applicable), submit your job, then -+ * drm_gem_unlock_reservations(). -+ * -+ * @objs: drm_gem_objects to lock -+ * @count: Number of objects in @objs -+ * @acquire_ctx: struct ww_acquire_ctx that will be initialized as -+ * part of tracking this set of locked reservations. -+ */ -+int -+drm_gem_lock_reservations(struct drm_gem_object **objs, int count, -+ struct ww_acquire_ctx *acquire_ctx) -+{ -+ int contended = -1; -+ int i, ret; -+ -+ ww_acquire_init(acquire_ctx, &reservation_ww_class); -+ -+retry: -+ if (contended != -1) { -+ struct drm_gem_object *obj = objs[contended]; -+ -+ ret = ww_mutex_lock_slow_interruptible(&obj->resv->lock, -+ acquire_ctx); -+ if (ret) { -+ ww_acquire_done(acquire_ctx); -+ return ret; -+ } -+ } -+ -+ for (i = 0; i < count; i++) { -+ if (i == contended) -+ continue; -+ -+ ret = ww_mutex_lock_interruptible(&objs[i]->resv->lock, -+ acquire_ctx); -+ if (ret) { -+ int j; -+ -+ for (j = 0; j < i; j++) -+ ww_mutex_unlock(&objs[j]->resv->lock); -+ -+ if (contended != -1 && contended >= i) -+ ww_mutex_unlock(&objs[contended]->resv->lock); -+ -+ if (ret == -EDEADLK) { -+ contended = i; -+ goto retry; -+ } -+ -+ ww_acquire_done(acquire_ctx); -+ return ret; -+ } -+ } -+ -+ ww_acquire_done(acquire_ctx); -+ -+ return 0; -+} -+EXPORT_SYMBOL(drm_gem_lock_reservations); -+ -+void -+drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, -+ struct ww_acquire_ctx *acquire_ctx) -+{ -+ int i; -+ -+ for (i = 0; i < count; i++) -+ ww_mutex_unlock(&objs[i]->resv->lock); -+ -+ ww_acquire_fini(acquire_ctx); -+} -+EXPORT_SYMBOL(drm_gem_unlock_reservations); -diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h -index 25f1ff2df464a..2955aaab3dca0 100644 ---- a/include/drm/drm_gem.h -+++ b/include/drm/drm_gem.h -@@ -384,6 +384,10 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, - struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); - long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, - bool wait_all, unsigned long timeout); -+int drm_gem_lock_reservations(struct drm_gem_object **objs, int count, -+ struct ww_acquire_ctx *acquire_ctx); -+void drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, -+ struct ww_acquire_ctx *acquire_ctx); - int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, - u32 handle, u64 *offset); - int drm_gem_dumb_destroy(struct drm_file *file, - -From 2400863a56ce5ad8ca29c3296e9ca46f9337013a Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Sat, 9 Mar 2019 20:20:12 +0800 -Subject: [PATCH 242/249] BACKPORT: drm/lima: driver for ARM Mali4xx GPUs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -- Mali 4xx GPUs have two kinds of processors GP and PP. GP is for - OpenGL vertex shader processing and PP is for fragment shader - processing. Each processor has its own MMU so prcessors work in - virtual address space. -- There's only one GP but multiple PP (max 4 for mali 400 and 8 - for mali 450) in the same mali 4xx GPU. All PPs are grouped - togather to handle a single fragment shader task divided by - FB output tiled pixels. Mali 400 user space driver is - responsible for assign target tiled pixels to each PP, but mali - 450 has a HW module called DLBU to dynamically balance each - PP's load. -- User space driver allocate buffer object and map into GPU - virtual address space, upload command stream and draw data with - CPU mmap of the buffer object, then submit task to GP/PP with - a register frame indicating where is the command stream and misc - settings. -- There's no command stream validation/relocation due to each user - process has its own GPU virtual address space. GP/PP's MMU switch - virtual address space before running two tasks from different - user process. Error or evil user space code just get MMU fault - or GP/PP error IRQ, then the HW/SW will be recovered. -- Use GEM+shmem for MM. Currently just alloc and pin memory when - gem object creation. GPU vm map of the buffer is also done in - the alloc stage in kernel space. We may delay the memory - allocation and real GPU vm map to command submission stage in the - furture as improvement. -- Use drm_sched for GPU task schedule. Each OpenGL context should - have a lima context object in the kernel to distinguish tasks - from different user. drm_sched gets task from each lima context - in a fair way. - -mesa driver can be found here before upstreamed: -https://gitlab.freedesktop.org/lima/mesa - -v8: -- add comments for in_sync -- fix ctx free miss mutex unlock - -v7: -- remove lima_fence_ops with default value -- move fence slab create to device probe -- check pad ioctl args to be zero -- add comments for user/kernel interface - -v6: -- fix comments by checkpatch.pl - -v5: -- export gp/pp version to userspace -- rebase on drm-misc-next - -v4: -- use get param interface to get info -- separate context create/free ioctl -- remove unused max sched task param -- update copyright time -- use xarray instead of idr -- stop using drmP.h - -v3: -- fix comments from kbuild robot -- restrict supported arch to tested ones - -v2: -- fix syscall argument check -- fix job finish fence leak since kernel 5.0 -- use drm syncobj to replace native fence -- move buffer object GPU va map into kernel -- reserve syscall argument space for future info -- remove kernel gem modifier -- switch TTM back to GEM+shmem MM -- use time based io poll -- use whole register name -- adopt gem reservation obj integration -- use drm_timeout_abs_to_jiffies - -Cc: Eric Anholt -Cc: Rob Herring -Cc: Christian König -Cc: Daniel Vetter -Cc: Alex Deucher -Cc: Sam Ravnborg -Cc: Rob Clark -Cc: Dave Airlie -Signed-off-by: Andreas Baierl -Signed-off-by: Erico Nunes -Signed-off-by: Heiko Stuebner -Signed-off-by: Marek Vasut -Signed-off-by: Neil Armstrong -Signed-off-by: Simon Shields -Signed-off-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu -Reviewed-by: Eric Anholt -Reviewed-by: Rob Herring -Signed-off-by: Eric Anholt -Link: https://patchwork.freedesktop.org/patch/291200/ -(cherry picked from commit a1d2a6339961efc078208dc3b2f006e9e9a8e119) - -Conflicts: - drivers/gpu/drm/Kconfig - drivers/gpu/drm/Makefile ---- - drivers/gpu/drm/Kconfig | 2 + - drivers/gpu/drm/Makefile | 1 + - drivers/gpu/drm/lima/Kconfig | 10 + - drivers/gpu/drm/lima/Makefile | 21 ++ - drivers/gpu/drm/lima/lima_bcast.c | 47 +++ - drivers/gpu/drm/lima/lima_bcast.h | 14 + - drivers/gpu/drm/lima/lima_ctx.c | 98 ++++++ - drivers/gpu/drm/lima/lima_ctx.h | 30 ++ - drivers/gpu/drm/lima/lima_device.c | 385 +++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_device.h | 131 ++++++++ - drivers/gpu/drm/lima/lima_dlbu.c | 58 ++++ - drivers/gpu/drm/lima/lima_dlbu.h | 18 ++ - drivers/gpu/drm/lima/lima_drv.c | 376 +++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_drv.h | 45 +++ - drivers/gpu/drm/lima/lima_gem.c | 381 +++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_gem.h | 25 ++ - drivers/gpu/drm/lima/lima_gem_prime.c | 47 +++ - drivers/gpu/drm/lima/lima_gem_prime.h | 13 + - drivers/gpu/drm/lima/lima_gp.c | 283 +++++++++++++++++ - drivers/gpu/drm/lima/lima_gp.h | 16 + - drivers/gpu/drm/lima/lima_l2_cache.c | 80 +++++ - drivers/gpu/drm/lima/lima_l2_cache.h | 14 + - drivers/gpu/drm/lima/lima_mmu.c | 142 +++++++++ - drivers/gpu/drm/lima/lima_mmu.h | 16 + - drivers/gpu/drm/lima/lima_object.c | 122 ++++++++ - drivers/gpu/drm/lima/lima_object.h | 36 +++ - drivers/gpu/drm/lima/lima_pmu.c | 60 ++++ - drivers/gpu/drm/lima/lima_pmu.h | 12 + - drivers/gpu/drm/lima/lima_pp.c | 427 ++++++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_pp.h | 19 ++ - drivers/gpu/drm/lima/lima_regs.h | 298 ++++++++++++++++++ - drivers/gpu/drm/lima/lima_sched.c | 404 ++++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_sched.h | 104 +++++++ - drivers/gpu/drm/lima/lima_vm.c | 282 +++++++++++++++++ - drivers/gpu/drm/lima/lima_vm.h | 62 ++++ - include/uapi/drm/lima_drm.h | 169 ++++++++++ - 36 files changed, 4248 insertions(+) - create mode 100644 drivers/gpu/drm/lima/Kconfig - create mode 100644 drivers/gpu/drm/lima/Makefile - create mode 100644 drivers/gpu/drm/lima/lima_bcast.c - create mode 100644 drivers/gpu/drm/lima/lima_bcast.h - create mode 100644 drivers/gpu/drm/lima/lima_ctx.c - create mode 100644 drivers/gpu/drm/lima/lima_ctx.h - create mode 100644 drivers/gpu/drm/lima/lima_device.c - create mode 100644 drivers/gpu/drm/lima/lima_device.h - create mode 100644 drivers/gpu/drm/lima/lima_dlbu.c - create mode 100644 drivers/gpu/drm/lima/lima_dlbu.h - create mode 100644 drivers/gpu/drm/lima/lima_drv.c - create mode 100644 drivers/gpu/drm/lima/lima_drv.h - create mode 100644 drivers/gpu/drm/lima/lima_gem.c - create mode 100644 drivers/gpu/drm/lima/lima_gem.h - create mode 100644 drivers/gpu/drm/lima/lima_gem_prime.c - create mode 100644 drivers/gpu/drm/lima/lima_gem_prime.h - create mode 100644 drivers/gpu/drm/lima/lima_gp.c - create mode 100644 drivers/gpu/drm/lima/lima_gp.h - create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.c - create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.h - create mode 100644 drivers/gpu/drm/lima/lima_mmu.c - create mode 100644 drivers/gpu/drm/lima/lima_mmu.h - create mode 100644 drivers/gpu/drm/lima/lima_object.c - create mode 100644 drivers/gpu/drm/lima/lima_object.h - create mode 100644 drivers/gpu/drm/lima/lima_pmu.c - create mode 100644 drivers/gpu/drm/lima/lima_pmu.h - create mode 100644 drivers/gpu/drm/lima/lima_pp.c - create mode 100644 drivers/gpu/drm/lima/lima_pp.h - create mode 100644 drivers/gpu/drm/lima/lima_regs.h - create mode 100644 drivers/gpu/drm/lima/lima_sched.c - create mode 100644 drivers/gpu/drm/lima/lima_sched.h - create mode 100644 drivers/gpu/drm/lima/lima_vm.c - create mode 100644 drivers/gpu/drm/lima/lima_vm.h - create mode 100644 include/uapi/drm/lima_drm.h - -diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig -index febdc102b75c2..433250cf2beb1 100644 ---- a/drivers/gpu/drm/Kconfig -+++ b/drivers/gpu/drm/Kconfig -@@ -335,6 +335,8 @@ source "drivers/gpu/drm/tve200/Kconfig" - - source "drivers/gpu/drm/xen/Kconfig" - -+source "drivers/gpu/drm/lima/Kconfig" -+ - # Keep legacy drivers last - - menuconfig DRM_LEGACY -diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile -index 7476ed945e303..00e0dcc9a2ef5 100644 ---- a/drivers/gpu/drm/Makefile -+++ b/drivers/gpu/drm/Makefile -@@ -110,3 +110,4 @@ obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ - obj-$(CONFIG_DRM_PL111) += pl111/ - obj-$(CONFIG_DRM_TVE200) += tve200/ - obj-$(CONFIG_DRM_XEN) += xen/ -+obj-$(CONFIG_DRM_LIMA) += lima/ -diff --git a/drivers/gpu/drm/lima/Kconfig b/drivers/gpu/drm/lima/Kconfig -new file mode 100644 -index 0000000000000..f113144480939 ---- /dev/null -+++ b/drivers/gpu/drm/lima/Kconfig -@@ -0,0 +1,10 @@ -+# SPDX-License-Identifier: GPL-2.0 OR MIT -+# Copyright 2017-2019 Qiang Yu -+ -+config DRM_LIMA -+ tristate "LIMA (DRM support for ARM Mali 400/450 GPU)" -+ depends on DRM -+ depends on ARM || ARM64 || COMPILE_TEST -+ select DRM_SCHED -+ help -+ DRM driver for ARM Mali 400/450 GPUs. -diff --git a/drivers/gpu/drm/lima/Makefile b/drivers/gpu/drm/lima/Makefile -new file mode 100644 -index 0000000000000..38cc70281ba5b ---- /dev/null -+++ b/drivers/gpu/drm/lima/Makefile -@@ -0,0 +1,21 @@ -+# SPDX-License-Identifier: GPL-2.0 OR MIT -+# Copyright 2017-2019 Qiang Yu -+ -+lima-y := \ -+ lima_drv.o \ -+ lima_device.o \ -+ lima_pmu.o \ -+ lima_l2_cache.o \ -+ lima_mmu.o \ -+ lima_gp.o \ -+ lima_pp.o \ -+ lima_gem.o \ -+ lima_vm.o \ -+ lima_sched.o \ -+ lima_ctx.o \ -+ lima_gem_prime.o \ -+ lima_dlbu.o \ -+ lima_bcast.o \ -+ lima_object.o -+ -+obj-$(CONFIG_DRM_LIMA) += lima.o -diff --git a/drivers/gpu/drm/lima/lima_bcast.c b/drivers/gpu/drm/lima/lima_bcast.c -new file mode 100644 -index 0000000000000..288398027bfa8 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_bcast.c -@@ -0,0 +1,47 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_bcast.h" -+#include "lima_regs.h" -+ -+#define bcast_write(reg, data) writel(data, ip->iomem + reg) -+#define bcast_read(reg) readl(ip->iomem + reg) -+ -+void lima_bcast_enable(struct lima_device *dev, int num_pp) -+{ -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ struct lima_ip *ip = dev->ip + lima_ip_bcast; -+ int i, mask = bcast_read(LIMA_BCAST_BROADCAST_MASK) & 0xffff0000; -+ -+ for (i = 0; i < num_pp; i++) { -+ struct lima_ip *pp = pipe->processor[i]; -+ -+ mask |= 1 << (pp->id - lima_ip_pp0); -+ } -+ -+ bcast_write(LIMA_BCAST_BROADCAST_MASK, mask); -+} -+ -+int lima_bcast_init(struct lima_ip *ip) -+{ -+ int i, mask = 0; -+ -+ for (i = lima_ip_pp0; i <= lima_ip_pp7; i++) { -+ if (ip->dev->ip[i].present) -+ mask |= 1 << (i - lima_ip_pp0); -+ } -+ -+ bcast_write(LIMA_BCAST_BROADCAST_MASK, mask << 16); -+ bcast_write(LIMA_BCAST_INTERRUPT_MASK, mask); -+ return 0; -+} -+ -+void lima_bcast_fini(struct lima_ip *ip) -+{ -+ -+} -+ -diff --git a/drivers/gpu/drm/lima/lima_bcast.h b/drivers/gpu/drm/lima/lima_bcast.h -new file mode 100644 -index 0000000000000..c47e58563d0a2 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_bcast.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#ifndef __LIMA_BCAST_H__ -+#define __LIMA_BCAST_H__ -+ -+struct lima_ip; -+ -+int lima_bcast_init(struct lima_ip *ip); -+void lima_bcast_fini(struct lima_ip *ip); -+ -+void lima_bcast_enable(struct lima_device *dev, int num_pp); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_ctx.c b/drivers/gpu/drm/lima/lima_ctx.c -new file mode 100644 -index 0000000000000..22fff6caa961b ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_ctx.c -@@ -0,0 +1,98 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#include -+ -+#include "lima_device.h" -+#include "lima_ctx.h" -+ -+int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id) -+{ -+ struct lima_ctx *ctx; -+ int i, err; -+ -+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; -+ ctx->dev = dev; -+ kref_init(&ctx->refcnt); -+ -+ for (i = 0; i < lima_pipe_num; i++) { -+ err = lima_sched_context_init(dev->pipe + i, ctx->context + i, &ctx->guilty); -+ if (err) -+ goto err_out0; -+ } -+ -+ err = xa_alloc(&mgr->handles, id, ctx, xa_limit_32b, GFP_KERNEL); -+ if (err < 0) -+ goto err_out0; -+ -+ return 0; -+ -+err_out0: -+ for (i--; i >= 0; i--) -+ lima_sched_context_fini(dev->pipe + i, ctx->context + i); -+ kfree(ctx); -+ return err; -+} -+ -+static void lima_ctx_do_release(struct kref *ref) -+{ -+ struct lima_ctx *ctx = container_of(ref, struct lima_ctx, refcnt); -+ int i; -+ -+ for (i = 0; i < lima_pipe_num; i++) -+ lima_sched_context_fini(ctx->dev->pipe + i, ctx->context + i); -+ kfree(ctx); -+} -+ -+int lima_ctx_free(struct lima_ctx_mgr *mgr, u32 id) -+{ -+ struct lima_ctx *ctx; -+ int ret = 0; -+ -+ mutex_lock(&mgr->lock); -+ ctx = xa_erase(&mgr->handles, id); -+ if (ctx) -+ kref_put(&ctx->refcnt, lima_ctx_do_release); -+ else -+ ret = -EINVAL; -+ mutex_unlock(&mgr->lock); -+ return ret; -+} -+ -+struct lima_ctx *lima_ctx_get(struct lima_ctx_mgr *mgr, u32 id) -+{ -+ struct lima_ctx *ctx; -+ -+ mutex_lock(&mgr->lock); -+ ctx = xa_load(&mgr->handles, id); -+ if (ctx) -+ kref_get(&ctx->refcnt); -+ mutex_unlock(&mgr->lock); -+ return ctx; -+} -+ -+void lima_ctx_put(struct lima_ctx *ctx) -+{ -+ kref_put(&ctx->refcnt, lima_ctx_do_release); -+} -+ -+void lima_ctx_mgr_init(struct lima_ctx_mgr *mgr) -+{ -+ mutex_init(&mgr->lock); -+ xa_init_flags(&mgr->handles, XA_FLAGS_ALLOC); -+} -+ -+void lima_ctx_mgr_fini(struct lima_ctx_mgr *mgr) -+{ -+ struct lima_ctx *ctx; -+ unsigned long id; -+ -+ xa_for_each(&mgr->handles, id, ctx) { -+ kref_put(&ctx->refcnt, lima_ctx_do_release); -+ } -+ -+ xa_destroy(&mgr->handles); -+ mutex_destroy(&mgr->lock); -+} -diff --git a/drivers/gpu/drm/lima/lima_ctx.h b/drivers/gpu/drm/lima/lima_ctx.h -new file mode 100644 -index 0000000000000..6154e5c9bfe49 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_ctx.h -@@ -0,0 +1,30 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#ifndef __LIMA_CTX_H__ -+#define __LIMA_CTX_H__ -+ -+#include -+ -+#include "lima_device.h" -+ -+struct lima_ctx { -+ struct kref refcnt; -+ struct lima_device *dev; -+ struct lima_sched_context context[lima_pipe_num]; -+ atomic_t guilty; -+}; -+ -+struct lima_ctx_mgr { -+ struct mutex lock; -+ struct xarray handles; -+}; -+ -+int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id); -+int lima_ctx_free(struct lima_ctx_mgr *mgr, u32 id); -+struct lima_ctx *lima_ctx_get(struct lima_ctx_mgr *mgr, u32 id); -+void lima_ctx_put(struct lima_ctx *ctx); -+void lima_ctx_mgr_init(struct lima_ctx_mgr *mgr); -+void lima_ctx_mgr_fini(struct lima_ctx_mgr *mgr); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -new file mode 100644 -index 0000000000000..570d0e93f9a99 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -0,0 +1,385 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_gp.h" -+#include "lima_pp.h" -+#include "lima_mmu.h" -+#include "lima_pmu.h" -+#include "lima_l2_cache.h" -+#include "lima_dlbu.h" -+#include "lima_bcast.h" -+#include "lima_vm.h" -+ -+struct lima_ip_desc { -+ char *name; -+ char *irq_name; -+ bool must_have[lima_gpu_num]; -+ int offset[lima_gpu_num]; -+ -+ int (*init)(struct lima_ip *ip); -+ void (*fini)(struct lima_ip *ip); -+}; -+ -+#define LIMA_IP_DESC(ipname, mst0, mst1, off0, off1, func, irq) \ -+ [lima_ip_##ipname] = { \ -+ .name = #ipname, \ -+ .irq_name = irq, \ -+ .must_have = { \ -+ [lima_gpu_mali400] = mst0, \ -+ [lima_gpu_mali450] = mst1, \ -+ }, \ -+ .offset = { \ -+ [lima_gpu_mali400] = off0, \ -+ [lima_gpu_mali450] = off1, \ -+ }, \ -+ .init = lima_##func##_init, \ -+ .fini = lima_##func##_fini, \ -+ } -+ -+static struct lima_ip_desc lima_ip_desc[lima_ip_num] = { -+ LIMA_IP_DESC(pmu, false, false, 0x02000, 0x02000, pmu, "pmu"), -+ LIMA_IP_DESC(l2_cache0, true, true, 0x01000, 0x10000, l2_cache, NULL), -+ LIMA_IP_DESC(l2_cache1, false, true, -1, 0x01000, l2_cache, NULL), -+ LIMA_IP_DESC(l2_cache2, false, false, -1, 0x11000, l2_cache, NULL), -+ LIMA_IP_DESC(gp, true, true, 0x00000, 0x00000, gp, "gp"), -+ LIMA_IP_DESC(pp0, true, true, 0x08000, 0x08000, pp, "pp0"), -+ LIMA_IP_DESC(pp1, false, false, 0x0A000, 0x0A000, pp, "pp1"), -+ LIMA_IP_DESC(pp2, false, false, 0x0C000, 0x0C000, pp, "pp2"), -+ LIMA_IP_DESC(pp3, false, false, 0x0E000, 0x0E000, pp, "pp3"), -+ LIMA_IP_DESC(pp4, false, false, -1, 0x28000, pp, "pp4"), -+ LIMA_IP_DESC(pp5, false, false, -1, 0x2A000, pp, "pp5"), -+ LIMA_IP_DESC(pp6, false, false, -1, 0x2C000, pp, "pp6"), -+ LIMA_IP_DESC(pp7, false, false, -1, 0x2E000, pp, "pp7"), -+ LIMA_IP_DESC(gpmmu, true, true, 0x03000, 0x03000, mmu, "gpmmu"), -+ LIMA_IP_DESC(ppmmu0, true, true, 0x04000, 0x04000, mmu, "ppmmu0"), -+ LIMA_IP_DESC(ppmmu1, false, false, 0x05000, 0x05000, mmu, "ppmmu1"), -+ LIMA_IP_DESC(ppmmu2, false, false, 0x06000, 0x06000, mmu, "ppmmu2"), -+ LIMA_IP_DESC(ppmmu3, false, false, 0x07000, 0x07000, mmu, "ppmmu3"), -+ LIMA_IP_DESC(ppmmu4, false, false, -1, 0x1C000, mmu, "ppmmu4"), -+ LIMA_IP_DESC(ppmmu5, false, false, -1, 0x1D000, mmu, "ppmmu5"), -+ LIMA_IP_DESC(ppmmu6, false, false, -1, 0x1E000, mmu, "ppmmu6"), -+ LIMA_IP_DESC(ppmmu7, false, false, -1, 0x1F000, mmu, "ppmmu7"), -+ LIMA_IP_DESC(dlbu, false, true, -1, 0x14000, dlbu, NULL), -+ LIMA_IP_DESC(bcast, false, true, -1, 0x13000, bcast, NULL), -+ LIMA_IP_DESC(pp_bcast, false, true, -1, 0x16000, pp_bcast, "pp"), -+ LIMA_IP_DESC(ppmmu_bcast, false, true, -1, 0x15000, mmu, NULL), -+}; -+ -+const char *lima_ip_name(struct lima_ip *ip) -+{ -+ return lima_ip_desc[ip->id].name; -+} -+ -+static int lima_clk_init(struct lima_device *dev) -+{ -+ int err; -+ unsigned long bus_rate, gpu_rate; -+ -+ dev->clk_bus = devm_clk_get(dev->dev, "bus"); -+ if (IS_ERR(dev->clk_bus)) { -+ dev_err(dev->dev, "get bus clk failed %ld\n", PTR_ERR(dev->clk_bus)); -+ return PTR_ERR(dev->clk_bus); -+ } -+ -+ dev->clk_gpu = devm_clk_get(dev->dev, "core"); -+ if (IS_ERR(dev->clk_gpu)) { -+ dev_err(dev->dev, "get core clk failed %ld\n", PTR_ERR(dev->clk_gpu)); -+ return PTR_ERR(dev->clk_gpu); -+ } -+ -+ bus_rate = clk_get_rate(dev->clk_bus); -+ dev_info(dev->dev, "bus rate = %lu\n", bus_rate); -+ -+ gpu_rate = clk_get_rate(dev->clk_gpu); -+ dev_info(dev->dev, "mod rate = %lu", gpu_rate); -+ -+ err = clk_prepare_enable(dev->clk_bus); -+ if (err) -+ return err; -+ -+ err = clk_prepare_enable(dev->clk_gpu); -+ if (err) -+ goto error_out0; -+ -+ dev->reset = devm_reset_control_get_optional(dev->dev, NULL); -+ if (IS_ERR(dev->reset)) { -+ err = PTR_ERR(dev->reset); -+ goto error_out1; -+ } else if (dev->reset != NULL) { -+ err = reset_control_deassert(dev->reset); -+ if (err) -+ goto error_out1; -+ } -+ -+ return 0; -+ -+error_out1: -+ clk_disable_unprepare(dev->clk_gpu); -+error_out0: -+ clk_disable_unprepare(dev->clk_bus); -+ return err; -+} -+ -+static void lima_clk_fini(struct lima_device *dev) -+{ -+ if (dev->reset != NULL) -+ reset_control_assert(dev->reset); -+ clk_disable_unprepare(dev->clk_gpu); -+ clk_disable_unprepare(dev->clk_bus); -+} -+ -+static int lima_regulator_init(struct lima_device *dev) -+{ -+ int ret; -+ -+ dev->regulator = devm_regulator_get_optional(dev->dev, "mali"); -+ if (IS_ERR(dev->regulator)) { -+ ret = PTR_ERR(dev->regulator); -+ dev->regulator = NULL; -+ if (ret == -ENODEV) -+ return 0; -+ dev_err(dev->dev, "failed to get regulator: %d\n", ret); -+ return ret; -+ } -+ -+ ret = regulator_enable(dev->regulator); -+ if (ret < 0) { -+ dev_err(dev->dev, "failed to enable regulator: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void lima_regulator_fini(struct lima_device *dev) -+{ -+ if (dev->regulator) -+ regulator_disable(dev->regulator); -+} -+ -+static int lima_init_ip(struct lima_device *dev, int index) -+{ -+ struct lima_ip_desc *desc = lima_ip_desc + index; -+ struct lima_ip *ip = dev->ip + index; -+ int offset = desc->offset[dev->id]; -+ bool must = desc->must_have[dev->id]; -+ int err; -+ -+ if (offset < 0) -+ return 0; -+ -+ ip->dev = dev; -+ ip->id = index; -+ ip->iomem = dev->iomem + offset; -+ if (desc->irq_name) { -+ err = platform_get_irq_byname(dev->pdev, desc->irq_name); -+ if (err < 0) -+ goto out; -+ ip->irq = err; -+ } -+ -+ err = desc->init(ip); -+ if (!err) { -+ ip->present = true; -+ return 0; -+ } -+ -+out: -+ return must ? err : 0; -+} -+ -+static void lima_fini_ip(struct lima_device *ldev, int index) -+{ -+ struct lima_ip_desc *desc = lima_ip_desc + index; -+ struct lima_ip *ip = ldev->ip + index; -+ -+ if (ip->present) -+ desc->fini(ip); -+} -+ -+static int lima_init_gp_pipe(struct lima_device *dev) -+{ -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; -+ int err; -+ -+ err = lima_sched_pipe_init(pipe, "gp"); -+ if (err) -+ return err; -+ -+ pipe->l2_cache[pipe->num_l2_cache++] = dev->ip + lima_ip_l2_cache0; -+ pipe->mmu[pipe->num_mmu++] = dev->ip + lima_ip_gpmmu; -+ pipe->processor[pipe->num_processor++] = dev->ip + lima_ip_gp; -+ -+ err = lima_gp_pipe_init(dev); -+ if (err) { -+ lima_sched_pipe_fini(pipe); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static void lima_fini_gp_pipe(struct lima_device *dev) -+{ -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; -+ -+ lima_gp_pipe_fini(dev); -+ lima_sched_pipe_fini(pipe); -+} -+ -+static int lima_init_pp_pipe(struct lima_device *dev) -+{ -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ int err, i; -+ -+ err = lima_sched_pipe_init(pipe, "pp"); -+ if (err) -+ return err; -+ -+ for (i = 0; i < LIMA_SCHED_PIPE_MAX_PROCESSOR; i++) { -+ struct lima_ip *pp = dev->ip + lima_ip_pp0 + i; -+ struct lima_ip *ppmmu = dev->ip + lima_ip_ppmmu0 + i; -+ struct lima_ip *l2_cache; -+ -+ if (dev->id == lima_gpu_mali400) -+ l2_cache = dev->ip + lima_ip_l2_cache0; -+ else -+ l2_cache = dev->ip + lima_ip_l2_cache1 + (i >> 2); -+ -+ if (pp->present && ppmmu->present && l2_cache->present) { -+ pipe->mmu[pipe->num_mmu++] = ppmmu; -+ pipe->processor[pipe->num_processor++] = pp; -+ if (!pipe->l2_cache[i >> 2]) -+ pipe->l2_cache[pipe->num_l2_cache++] = l2_cache; -+ } -+ } -+ -+ if (dev->ip[lima_ip_bcast].present) { -+ pipe->bcast_processor = dev->ip + lima_ip_pp_bcast; -+ pipe->bcast_mmu = dev->ip + lima_ip_ppmmu_bcast; -+ } -+ -+ err = lima_pp_pipe_init(dev); -+ if (err) { -+ lima_sched_pipe_fini(pipe); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static void lima_fini_pp_pipe(struct lima_device *dev) -+{ -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ -+ lima_pp_pipe_fini(dev); -+ lima_sched_pipe_fini(pipe); -+} -+ -+int lima_device_init(struct lima_device *ldev) -+{ -+ int err, i; -+ struct resource *res; -+ -+ dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32)); -+ -+ err = lima_clk_init(ldev); -+ if (err) { -+ dev_err(ldev->dev, "clk init fail %d\n", err); -+ return err; -+ } -+ -+ err = lima_regulator_init(ldev); -+ if (err) { -+ dev_err(ldev->dev, "regulator init fail %d\n", err); -+ goto err_out0; -+ } -+ -+ ldev->empty_vm = lima_vm_create(ldev); -+ if (!ldev->empty_vm) { -+ err = -ENOMEM; -+ goto err_out1; -+ } -+ -+ ldev->va_start = 0; -+ if (ldev->id == lima_gpu_mali450) { -+ ldev->va_end = LIMA_VA_RESERVE_START; -+ ldev->dlbu_cpu = dma_alloc_wc( -+ ldev->dev, LIMA_PAGE_SIZE, -+ &ldev->dlbu_dma, GFP_KERNEL); -+ if (!ldev->dlbu_cpu) { -+ err = -ENOMEM; -+ goto err_out2; -+ } -+ } else -+ ldev->va_end = LIMA_VA_RESERVE_END; -+ -+ res = platform_get_resource(ldev->pdev, IORESOURCE_MEM, 0); -+ ldev->iomem = devm_ioremap_resource(ldev->dev, res); -+ if (IS_ERR(ldev->iomem)) { -+ dev_err(ldev->dev, "fail to ioremap iomem\n"); -+ err = PTR_ERR(ldev->iomem); -+ goto err_out3; -+ } -+ -+ for (i = 0; i < lima_ip_num; i++) { -+ err = lima_init_ip(ldev, i); -+ if (err) -+ goto err_out4; -+ } -+ -+ err = lima_init_gp_pipe(ldev); -+ if (err) -+ goto err_out4; -+ -+ err = lima_init_pp_pipe(ldev); -+ if (err) -+ goto err_out5; -+ -+ return 0; -+ -+err_out5: -+ lima_fini_gp_pipe(ldev); -+err_out4: -+ while (--i >= 0) -+ lima_fini_ip(ldev, i); -+err_out3: -+ if (ldev->dlbu_cpu) -+ dma_free_wc(ldev->dev, LIMA_PAGE_SIZE, -+ ldev->dlbu_cpu, ldev->dlbu_dma); -+err_out2: -+ lima_vm_put(ldev->empty_vm); -+err_out1: -+ lima_regulator_fini(ldev); -+err_out0: -+ lima_clk_fini(ldev); -+ return err; -+} -+ -+void lima_device_fini(struct lima_device *ldev) -+{ -+ int i; -+ -+ lima_fini_pp_pipe(ldev); -+ lima_fini_gp_pipe(ldev); -+ -+ for (i = lima_ip_num - 1; i >= 0; i--) -+ lima_fini_ip(ldev, i); -+ -+ if (ldev->dlbu_cpu) -+ dma_free_wc(ldev->dev, LIMA_PAGE_SIZE, -+ ldev->dlbu_cpu, ldev->dlbu_dma); -+ -+ lima_vm_put(ldev->empty_vm); -+ -+ lima_regulator_fini(ldev); -+ -+ lima_clk_fini(ldev); -+} -diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h -new file mode 100644 -index 0000000000000..31158d86271c2 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_device.h -@@ -0,0 +1,131 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#ifndef __LIMA_DEVICE_H__ -+#define __LIMA_DEVICE_H__ -+ -+#include -+#include -+ -+#include "lima_sched.h" -+ -+enum lima_gpu_id { -+ lima_gpu_mali400 = 0, -+ lima_gpu_mali450, -+ lima_gpu_num, -+}; -+ -+enum lima_ip_id { -+ lima_ip_pmu, -+ lima_ip_gpmmu, -+ lima_ip_ppmmu0, -+ lima_ip_ppmmu1, -+ lima_ip_ppmmu2, -+ lima_ip_ppmmu3, -+ lima_ip_ppmmu4, -+ lima_ip_ppmmu5, -+ lima_ip_ppmmu6, -+ lima_ip_ppmmu7, -+ lima_ip_gp, -+ lima_ip_pp0, -+ lima_ip_pp1, -+ lima_ip_pp2, -+ lima_ip_pp3, -+ lima_ip_pp4, -+ lima_ip_pp5, -+ lima_ip_pp6, -+ lima_ip_pp7, -+ lima_ip_l2_cache0, -+ lima_ip_l2_cache1, -+ lima_ip_l2_cache2, -+ lima_ip_dlbu, -+ lima_ip_bcast, -+ lima_ip_pp_bcast, -+ lima_ip_ppmmu_bcast, -+ lima_ip_num, -+}; -+ -+struct lima_device; -+ -+struct lima_ip { -+ struct lima_device *dev; -+ enum lima_ip_id id; -+ bool present; -+ -+ void __iomem *iomem; -+ int irq; -+ -+ union { -+ /* gp/pp */ -+ bool async_reset; -+ /* l2 cache */ -+ spinlock_t lock; -+ } data; -+}; -+ -+enum lima_pipe_id { -+ lima_pipe_gp, -+ lima_pipe_pp, -+ lima_pipe_num, -+}; -+ -+struct lima_device { -+ struct device *dev; -+ struct drm_device *ddev; -+ struct platform_device *pdev; -+ -+ enum lima_gpu_id id; -+ u32 gp_version; -+ u32 pp_version; -+ int num_pp; -+ -+ void __iomem *iomem; -+ struct clk *clk_bus; -+ struct clk *clk_gpu; -+ struct reset_control *reset; -+ struct regulator *regulator; -+ -+ struct lima_ip ip[lima_ip_num]; -+ struct lima_sched_pipe pipe[lima_pipe_num]; -+ -+ struct lima_vm *empty_vm; -+ uint64_t va_start; -+ uint64_t va_end; -+ -+ u32 *dlbu_cpu; -+ dma_addr_t dlbu_dma; -+}; -+ -+static inline struct lima_device * -+to_lima_dev(struct drm_device *dev) -+{ -+ return dev->dev_private; -+} -+ -+int lima_device_init(struct lima_device *ldev); -+void lima_device_fini(struct lima_device *ldev); -+ -+const char *lima_ip_name(struct lima_ip *ip); -+ -+typedef int (*lima_poll_func_t)(struct lima_ip *); -+ -+static inline int lima_poll_timeout(struct lima_ip *ip, lima_poll_func_t func, -+ int sleep_us, int timeout_us) -+{ -+ ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); -+ -+ might_sleep_if(sleep_us); -+ while (1) { -+ if (func(ip)) -+ return 0; -+ -+ if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) -+ return -ETIMEDOUT; -+ -+ if (sleep_us) -+ usleep_range((sleep_us >> 2) + 1, sleep_us); -+ } -+ return 0; -+} -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_dlbu.c b/drivers/gpu/drm/lima/lima_dlbu.c -new file mode 100644 -index 0000000000000..8399ceffb94bb ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_dlbu.c -@@ -0,0 +1,58 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_dlbu.h" -+#include "lima_vm.h" -+#include "lima_regs.h" -+ -+#define dlbu_write(reg, data) writel(data, ip->iomem + reg) -+#define dlbu_read(reg) readl(ip->iomem + reg) -+ -+void lima_dlbu_enable(struct lima_device *dev, int num_pp) -+{ -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ struct lima_ip *ip = dev->ip + lima_ip_dlbu; -+ int i, mask = 0; -+ -+ for (i = 0; i < num_pp; i++) { -+ struct lima_ip *pp = pipe->processor[i]; -+ -+ mask |= 1 << (pp->id - lima_ip_pp0); -+ } -+ -+ dlbu_write(LIMA_DLBU_PP_ENABLE_MASK, mask); -+} -+ -+void lima_dlbu_disable(struct lima_device *dev) -+{ -+ struct lima_ip *ip = dev->ip + lima_ip_dlbu; -+ -+ dlbu_write(LIMA_DLBU_PP_ENABLE_MASK, 0); -+} -+ -+void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg) -+{ -+ dlbu_write(LIMA_DLBU_TLLIST_VBASEADDR, reg[0]); -+ dlbu_write(LIMA_DLBU_FB_DIM, reg[1]); -+ dlbu_write(LIMA_DLBU_TLLIST_CONF, reg[2]); -+ dlbu_write(LIMA_DLBU_START_TILE_POS, reg[3]); -+} -+ -+int lima_dlbu_init(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ -+ dlbu_write(LIMA_DLBU_MASTER_TLLIST_PHYS_ADDR, dev->dlbu_dma | 1); -+ dlbu_write(LIMA_DLBU_MASTER_TLLIST_VADDR, LIMA_VA_RESERVE_DLBU); -+ -+ return 0; -+} -+ -+void lima_dlbu_fini(struct lima_ip *ip) -+{ -+ -+} -diff --git a/drivers/gpu/drm/lima/lima_dlbu.h b/drivers/gpu/drm/lima/lima_dlbu.h -new file mode 100644 -index 0000000000000..16f877984466d ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_dlbu.h -@@ -0,0 +1,18 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#ifndef __LIMA_DLBU_H__ -+#define __LIMA_DLBU_H__ -+ -+struct lima_ip; -+struct lima_device; -+ -+void lima_dlbu_enable(struct lima_device *dev, int num_pp); -+void lima_dlbu_disable(struct lima_device *dev); -+ -+void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg); -+ -+int lima_dlbu_init(struct lima_ip *ip); -+void lima_dlbu_fini(struct lima_ip *ip); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -new file mode 100644 -index 0000000000000..f9a281a620831 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -0,0 +1,376 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lima_drv.h" -+#include "lima_gem.h" -+#include "lima_gem_prime.h" -+#include "lima_vm.h" -+ -+int lima_sched_timeout_ms; -+ -+MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms (0 = no timeout (default))"); -+module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); -+ -+static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) -+{ -+ struct drm_lima_get_param *args = data; -+ struct lima_device *ldev = to_lima_dev(dev); -+ -+ if (args->pad) -+ return -EINVAL; -+ -+ switch (args->param) { -+ case DRM_LIMA_PARAM_GPU_ID: -+ switch (ldev->id) { -+ case lima_gpu_mali400: -+ args->value = DRM_LIMA_PARAM_GPU_ID_MALI400; -+ break; -+ case lima_gpu_mali450: -+ args->value = DRM_LIMA_PARAM_GPU_ID_MALI450; -+ break; -+ default: -+ args->value = DRM_LIMA_PARAM_GPU_ID_UNKNOWN; -+ break; -+ } -+ break; -+ -+ case DRM_LIMA_PARAM_NUM_PP: -+ args->value = ldev->pipe[lima_pipe_pp].num_processor; -+ break; -+ -+ case DRM_LIMA_PARAM_GP_VERSION: -+ args->value = ldev->gp_version; -+ break; -+ -+ case DRM_LIMA_PARAM_PP_VERSION: -+ args->value = ldev->pp_version; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_file *file) -+{ -+ struct drm_lima_gem_create *args = data; -+ -+ if (args->pad) -+ return -EINVAL; -+ -+ if (args->flags) -+ return -EINVAL; -+ -+ if (args->size == 0) -+ return -EINVAL; -+ -+ return lima_gem_create_handle(dev, file, args->size, args->flags, &args->handle); -+} -+ -+static int lima_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file) -+{ -+ struct drm_lima_gem_info *args = data; -+ -+ return lima_gem_get_info(file, args->handle, &args->va, &args->offset); -+} -+ -+static int lima_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file) -+{ -+ struct drm_lima_gem_submit *args = data; -+ struct lima_device *ldev = to_lima_dev(dev); -+ struct lima_drm_priv *priv = file->driver_priv; -+ struct drm_lima_gem_submit_bo *bos; -+ struct lima_sched_pipe *pipe; -+ struct lima_sched_task *task; -+ struct lima_ctx *ctx; -+ struct lima_submit submit = {0}; -+ size_t size; -+ int err = 0; -+ -+ if (args->pipe >= lima_pipe_num || args->nr_bos == 0) -+ return -EINVAL; -+ -+ if (args->flags & ~(LIMA_SUBMIT_FLAG_EXPLICIT_FENCE)) -+ return -EINVAL; -+ -+ pipe = ldev->pipe + args->pipe; -+ if (args->frame_size != pipe->frame_size) -+ return -EINVAL; -+ -+ bos = kvcalloc(args->nr_bos, sizeof(*submit.bos) + sizeof(*submit.lbos), GFP_KERNEL); -+ if (!bos) -+ return -ENOMEM; -+ -+ size = args->nr_bos * sizeof(*submit.bos); -+ if (copy_from_user(bos, u64_to_user_ptr(args->bos), size)) { -+ err = -EFAULT; -+ goto out0; -+ } -+ -+ task = kmem_cache_zalloc(pipe->task_slab, GFP_KERNEL); -+ if (!task) { -+ err = -ENOMEM; -+ goto out0; -+ } -+ -+ task->frame = task + 1; -+ if (copy_from_user(task->frame, u64_to_user_ptr(args->frame), args->frame_size)) { -+ err = -EFAULT; -+ goto out1; -+ } -+ -+ err = pipe->task_validate(pipe, task); -+ if (err) -+ goto out1; -+ -+ ctx = lima_ctx_get(&priv->ctx_mgr, args->ctx); -+ if (!ctx) { -+ err = -ENOENT; -+ goto out1; -+ } -+ -+ submit.pipe = args->pipe; -+ submit.bos = bos; -+ submit.lbos = (void *)bos + size; -+ submit.nr_bos = args->nr_bos; -+ submit.task = task; -+ submit.ctx = ctx; -+ submit.flags = args->flags; -+ submit.in_sync[0] = args->in_sync[0]; -+ submit.in_sync[1] = args->in_sync[1]; -+ submit.out_sync = args->out_sync; -+ -+ err = lima_gem_submit(file, &submit); -+ -+ lima_ctx_put(ctx); -+out1: -+ if (err) -+ kmem_cache_free(pipe->task_slab, task); -+out0: -+ kvfree(bos); -+ return err; -+} -+ -+static int lima_ioctl_gem_wait(struct drm_device *dev, void *data, struct drm_file *file) -+{ -+ struct drm_lima_gem_wait *args = data; -+ -+ if (args->op & ~(LIMA_GEM_WAIT_READ|LIMA_GEM_WAIT_WRITE)) -+ return -EINVAL; -+ -+ return lima_gem_wait(file, args->handle, args->op, args->timeout_ns); -+} -+ -+static int lima_ioctl_ctx_create(struct drm_device *dev, void *data, struct drm_file *file) -+{ -+ struct drm_lima_ctx_create *args = data; -+ struct lima_drm_priv *priv = file->driver_priv; -+ struct lima_device *ldev = to_lima_dev(dev); -+ -+ if (args->_pad) -+ return -EINVAL; -+ -+ return lima_ctx_create(ldev, &priv->ctx_mgr, &args->id); -+} -+ -+static int lima_ioctl_ctx_free(struct drm_device *dev, void *data, struct drm_file *file) -+{ -+ struct drm_lima_ctx_create *args = data; -+ struct lima_drm_priv *priv = file->driver_priv; -+ -+ if (args->_pad) -+ return -EINVAL; -+ -+ return lima_ctx_free(&priv->ctx_mgr, args->id); -+} -+ -+static int lima_drm_driver_open(struct drm_device *dev, struct drm_file *file) -+{ -+ int err; -+ struct lima_drm_priv *priv; -+ struct lima_device *ldev = to_lima_dev(dev); -+ -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->vm = lima_vm_create(ldev); -+ if (!priv->vm) { -+ err = -ENOMEM; -+ goto err_out0; -+ } -+ -+ lima_ctx_mgr_init(&priv->ctx_mgr); -+ -+ file->driver_priv = priv; -+ return 0; -+ -+err_out0: -+ kfree(priv); -+ return err; -+} -+ -+static void lima_drm_driver_postclose(struct drm_device *dev, struct drm_file *file) -+{ -+ struct lima_drm_priv *priv = file->driver_priv; -+ -+ lima_ctx_mgr_fini(&priv->ctx_mgr); -+ lima_vm_put(priv->vm); -+ kfree(priv); -+} -+ -+static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = { -+ DRM_IOCTL_DEF_DRV(LIMA_GET_PARAM, lima_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW), -+ DRM_IOCTL_DEF_DRV(LIMA_GEM_CREATE, lima_ioctl_gem_create, DRM_AUTH|DRM_RENDER_ALLOW), -+ DRM_IOCTL_DEF_DRV(LIMA_GEM_INFO, lima_ioctl_gem_info, DRM_AUTH|DRM_RENDER_ALLOW), -+ DRM_IOCTL_DEF_DRV(LIMA_GEM_SUBMIT, lima_ioctl_gem_submit, DRM_AUTH|DRM_RENDER_ALLOW), -+ DRM_IOCTL_DEF_DRV(LIMA_GEM_WAIT, lima_ioctl_gem_wait, DRM_AUTH|DRM_RENDER_ALLOW), -+ DRM_IOCTL_DEF_DRV(LIMA_CTX_CREATE, lima_ioctl_ctx_create, DRM_AUTH|DRM_RENDER_ALLOW), -+ DRM_IOCTL_DEF_DRV(LIMA_CTX_FREE, lima_ioctl_ctx_free, DRM_AUTH|DRM_RENDER_ALLOW), -+}; -+ -+static const struct file_operations lima_drm_driver_fops = { -+ .owner = THIS_MODULE, -+ .open = drm_open, -+ .release = drm_release, -+ .unlocked_ioctl = drm_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = drm_compat_ioctl, -+#endif -+ .mmap = lima_gem_mmap, -+}; -+ -+static struct drm_driver lima_drm_driver = { -+ .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_PRIME | DRIVER_SYNCOBJ, -+ .open = lima_drm_driver_open, -+ .postclose = lima_drm_driver_postclose, -+ .ioctls = lima_drm_driver_ioctls, -+ .num_ioctls = ARRAY_SIZE(lima_drm_driver_ioctls), -+ .fops = &lima_drm_driver_fops, -+ .gem_free_object_unlocked = lima_gem_free_object, -+ .gem_open_object = lima_gem_object_open, -+ .gem_close_object = lima_gem_object_close, -+ .gem_vm_ops = &lima_gem_vm_ops, -+ .name = "lima", -+ .desc = "lima DRM", -+ .date = "20190217", -+ .major = 1, -+ .minor = 0, -+ .patchlevel = 0, -+ -+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, -+ .gem_prime_import_sg_table = lima_gem_prime_import_sg_table, -+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, -+ .gem_prime_get_sg_table = lima_gem_prime_get_sg_table, -+ .gem_prime_mmap = lima_gem_prime_mmap, -+}; -+ -+static int lima_pdev_probe(struct platform_device *pdev) -+{ -+ struct lima_device *ldev; -+ struct drm_device *ddev; -+ int err; -+ -+ err = lima_sched_slab_init(); -+ if (err) -+ return err; -+ -+ ldev = devm_kzalloc(&pdev->dev, sizeof(*ldev), GFP_KERNEL); -+ if (!ldev) { -+ err = -ENOMEM; -+ goto err_out0; -+ } -+ -+ ldev->pdev = pdev; -+ ldev->dev = &pdev->dev; -+ ldev->id = (enum lima_gpu_id)of_device_get_match_data(&pdev->dev); -+ -+ platform_set_drvdata(pdev, ldev); -+ -+ /* Allocate and initialize the DRM device. */ -+ ddev = drm_dev_alloc(&lima_drm_driver, &pdev->dev); -+ if (IS_ERR(ddev)) -+ return PTR_ERR(ddev); -+ -+ ddev->dev_private = ldev; -+ ldev->ddev = ddev; -+ -+ err = lima_device_init(ldev); -+ if (err) { -+ dev_err(&pdev->dev, "Fatal error during GPU init\n"); -+ goto err_out1; -+ } -+ -+ /* -+ * Register the DRM device with the core and the connectors with -+ * sysfs. -+ */ -+ err = drm_dev_register(ddev, 0); -+ if (err < 0) -+ goto err_out2; -+ -+ return 0; -+ -+err_out2: -+ lima_device_fini(ldev); -+err_out1: -+ drm_dev_put(ddev); -+err_out0: -+ lima_sched_slab_fini(); -+ return err; -+} -+ -+static int lima_pdev_remove(struct platform_device *pdev) -+{ -+ struct lima_device *ldev = platform_get_drvdata(pdev); -+ struct drm_device *ddev = ldev->ddev; -+ -+ drm_dev_unregister(ddev); -+ lima_device_fini(ldev); -+ drm_dev_put(ddev); -+ lima_sched_slab_fini(); -+ return 0; -+} -+ -+static const struct of_device_id dt_match[] = { -+ { .compatible = "arm,mali-400", .data = (void *)lima_gpu_mali400 }, -+ { .compatible = "arm,mali-450", .data = (void *)lima_gpu_mali450 }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, dt_match); -+ -+static struct platform_driver lima_platform_driver = { -+ .probe = lima_pdev_probe, -+ .remove = lima_pdev_remove, -+ .driver = { -+ .name = "lima", -+ .of_match_table = dt_match, -+ }, -+}; -+ -+static int __init lima_init(void) -+{ -+ return platform_driver_register(&lima_platform_driver); -+} -+module_init(lima_init); -+ -+static void __exit lima_exit(void) -+{ -+ platform_driver_unregister(&lima_platform_driver); -+} -+module_exit(lima_exit); -+ -+MODULE_AUTHOR("Lima Project Developers"); -+MODULE_DESCRIPTION("Lima DRM Driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h -new file mode 100644 -index 0000000000000..69c7344715c9b ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_drv.h -@@ -0,0 +1,45 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_DRV_H__ -+#define __LIMA_DRV_H__ -+ -+#include -+ -+#include "lima_ctx.h" -+ -+extern int lima_sched_timeout_ms; -+ -+struct lima_vm; -+struct lima_bo; -+struct lima_sched_task; -+ -+struct drm_lima_gem_submit_bo; -+ -+struct lima_drm_priv { -+ struct lima_vm *vm; -+ struct lima_ctx_mgr ctx_mgr; -+}; -+ -+struct lima_submit { -+ struct lima_ctx *ctx; -+ int pipe; -+ u32 flags; -+ -+ struct drm_lima_gem_submit_bo *bos; -+ struct lima_bo **lbos; -+ u32 nr_bos; -+ -+ u32 in_sync[2]; -+ u32 out_sync; -+ -+ struct lima_sched_task *task; -+}; -+ -+static inline struct lima_drm_priv * -+to_lima_drm_priv(struct drm_file *file) -+{ -+ return file->driver_priv; -+} -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c -new file mode 100644 -index 0000000000000..2d3cf96f6c58d ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_gem.c -@@ -0,0 +1,381 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+#include "lima_drv.h" -+#include "lima_gem.h" -+#include "lima_gem_prime.h" -+#include "lima_vm.h" -+#include "lima_object.h" -+ -+int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, -+ u32 size, u32 flags, u32 *handle) -+{ -+ int err; -+ struct lima_bo *bo; -+ struct lima_device *ldev = to_lima_dev(dev); -+ -+ bo = lima_bo_create(ldev, size, flags, NULL, NULL); -+ if (IS_ERR(bo)) -+ return PTR_ERR(bo); -+ -+ err = drm_gem_handle_create(file, &bo->gem, handle); -+ -+ /* drop reference from allocate - handle holds it now */ -+ drm_gem_object_put_unlocked(&bo->gem); -+ -+ return err; -+} -+ -+void lima_gem_free_object(struct drm_gem_object *obj) -+{ -+ struct lima_bo *bo = to_lima_bo(obj); -+ -+ if (!list_empty(&bo->va)) -+ dev_err(obj->dev->dev, "lima gem free bo still has va\n"); -+ -+ lima_bo_destroy(bo); -+} -+ -+int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file) -+{ -+ struct lima_bo *bo = to_lima_bo(obj); -+ struct lima_drm_priv *priv = to_lima_drm_priv(file); -+ struct lima_vm *vm = priv->vm; -+ -+ return lima_vm_bo_add(vm, bo, true); -+} -+ -+void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file) -+{ -+ struct lima_bo *bo = to_lima_bo(obj); -+ struct lima_drm_priv *priv = to_lima_drm_priv(file); -+ struct lima_vm *vm = priv->vm; -+ -+ lima_vm_bo_del(vm, bo); -+} -+ -+int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset) -+{ -+ struct drm_gem_object *obj; -+ struct lima_bo *bo; -+ struct lima_drm_priv *priv = to_lima_drm_priv(file); -+ struct lima_vm *vm = priv->vm; -+ int err; -+ -+ obj = drm_gem_object_lookup(file, handle); -+ if (!obj) -+ return -ENOENT; -+ -+ bo = to_lima_bo(obj); -+ -+ *va = lima_vm_get_va(vm, bo); -+ -+ err = drm_gem_create_mmap_offset(obj); -+ if (!err) -+ *offset = drm_vma_node_offset_addr(&obj->vma_node); -+ -+ drm_gem_object_put_unlocked(obj); -+ return err; -+} -+ -+static vm_fault_t lima_gem_fault(struct vm_fault *vmf) -+{ -+ struct vm_area_struct *vma = vmf->vma; -+ struct drm_gem_object *obj = vma->vm_private_data; -+ struct lima_bo *bo = to_lima_bo(obj); -+ pfn_t pfn; -+ pgoff_t pgoff; -+ -+ /* We don't use vmf->pgoff since that has the fake offset: */ -+ pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; -+ pfn = __pfn_to_pfn_t(page_to_pfn(bo->pages[pgoff]), PFN_DEV); -+ -+ return vmf_insert_mixed(vma, vmf->address, pfn); -+} -+ -+const struct vm_operations_struct lima_gem_vm_ops = { -+ .fault = lima_gem_fault, -+ .open = drm_gem_vm_open, -+ .close = drm_gem_vm_close, -+}; -+ -+void lima_set_vma_flags(struct vm_area_struct *vma) -+{ -+ pgprot_t prot = vm_get_page_prot(vma->vm_flags); -+ -+ vma->vm_flags |= VM_MIXEDMAP; -+ vma->vm_flags &= ~VM_PFNMAP; -+ vma->vm_page_prot = pgprot_writecombine(prot); -+} -+ -+int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma) -+{ -+ int ret; -+ -+ ret = drm_gem_mmap(filp, vma); -+ if (ret) -+ return ret; -+ -+ lima_set_vma_flags(vma); -+ return 0; -+} -+ -+static int lima_gem_sync_bo(struct lima_sched_task *task, struct lima_bo *bo, -+ bool write, bool explicit) -+{ -+ int err = 0; -+ -+ if (!write) { -+ err = reservation_object_reserve_shared(bo->gem.resv, 1); -+ if (err) -+ return err; -+ } -+ -+ /* explicit sync use user passed dep fence */ -+ if (explicit) -+ return 0; -+ -+ /* implicit sync use bo fence in resv obj */ -+ if (write) { -+ unsigned nr_fences; -+ struct dma_fence **fences; -+ int i; -+ -+ err = reservation_object_get_fences_rcu( -+ bo->gem.resv, NULL, &nr_fences, &fences); -+ if (err || !nr_fences) -+ return err; -+ -+ for (i = 0; i < nr_fences; i++) { -+ err = lima_sched_task_add_dep(task, fences[i]); -+ if (err) -+ break; -+ } -+ -+ /* for error case free remaining fences */ -+ for ( ; i < nr_fences; i++) -+ dma_fence_put(fences[i]); -+ -+ kfree(fences); -+ } else { -+ struct dma_fence *fence; -+ -+ fence = reservation_object_get_excl_rcu(bo->gem.resv); -+ if (fence) { -+ err = lima_sched_task_add_dep(task, fence); -+ if (err) -+ dma_fence_put(fence); -+ } -+ } -+ -+ return err; -+} -+ -+static int lima_gem_lock_bos(struct lima_bo **bos, u32 nr_bos, -+ struct ww_acquire_ctx *ctx) -+{ -+ int i, ret = 0, contended, slow_locked = -1; -+ -+ ww_acquire_init(ctx, &reservation_ww_class); -+ -+retry: -+ for (i = 0; i < nr_bos; i++) { -+ if (i == slow_locked) { -+ slow_locked = -1; -+ continue; -+ } -+ -+ ret = ww_mutex_lock_interruptible(&bos[i]->gem.resv->lock, ctx); -+ if (ret < 0) { -+ contended = i; -+ goto err; -+ } -+ } -+ -+ ww_acquire_done(ctx); -+ return 0; -+ -+err: -+ for (i--; i >= 0; i--) -+ ww_mutex_unlock(&bos[i]->gem.resv->lock); -+ -+ if (slow_locked >= 0) -+ ww_mutex_unlock(&bos[slow_locked]->gem.resv->lock); -+ -+ if (ret == -EDEADLK) { -+ /* we lost out in a seqno race, lock and retry.. */ -+ ret = ww_mutex_lock_slow_interruptible( -+ &bos[contended]->gem.resv->lock, ctx); -+ if (!ret) { -+ slow_locked = contended; -+ goto retry; -+ } -+ } -+ ww_acquire_fini(ctx); -+ -+ return ret; -+} -+ -+static void lima_gem_unlock_bos(struct lima_bo **bos, u32 nr_bos, -+ struct ww_acquire_ctx *ctx) -+{ -+ int i; -+ -+ for (i = 0; i < nr_bos; i++) -+ ww_mutex_unlock(&bos[i]->gem.resv->lock); -+ ww_acquire_fini(ctx); -+} -+ -+static int lima_gem_add_deps(struct drm_file *file, struct lima_submit *submit) -+{ -+ int i, err; -+ -+ for (i = 0; i < ARRAY_SIZE(submit->in_sync); i++) { -+ struct dma_fence *fence = NULL; -+ -+ if (!submit->in_sync[i]) -+ continue; -+ -+ err = drm_syncobj_find_fence(file, submit->in_sync[i], -+ 0, 0, &fence); -+ if (err) -+ return err; -+ -+ err = lima_sched_task_add_dep(submit->task, fence); -+ if (err) { -+ dma_fence_put(fence); -+ return err; -+ } -+ } -+ -+ return 0; -+} -+ -+int lima_gem_submit(struct drm_file *file, struct lima_submit *submit) -+{ -+ int i, err = 0; -+ struct ww_acquire_ctx ctx; -+ struct lima_drm_priv *priv = to_lima_drm_priv(file); -+ struct lima_vm *vm = priv->vm; -+ struct drm_syncobj *out_sync = NULL; -+ struct dma_fence *fence; -+ struct lima_bo **bos = submit->lbos; -+ -+ if (submit->out_sync) { -+ out_sync = drm_syncobj_find(file, submit->out_sync); -+ if (!out_sync) -+ return -ENOENT; -+ } -+ -+ for (i = 0; i < submit->nr_bos; i++) { -+ struct drm_gem_object *obj; -+ struct lima_bo *bo; -+ -+ obj = drm_gem_object_lookup(file, submit->bos[i].handle); -+ if (!obj) { -+ err = -ENOENT; -+ goto err_out0; -+ } -+ -+ bo = to_lima_bo(obj); -+ -+ /* increase refcnt of gpu va map to prevent unmapped when executing, -+ * will be decreased when task done -+ */ -+ err = lima_vm_bo_add(vm, bo, false); -+ if (err) { -+ drm_gem_object_put_unlocked(obj); -+ goto err_out0; -+ } -+ -+ bos[i] = bo; -+ } -+ -+ err = lima_gem_lock_bos(bos, submit->nr_bos, &ctx); -+ if (err) -+ goto err_out0; -+ -+ err = lima_sched_task_init( -+ submit->task, submit->ctx->context + submit->pipe, -+ bos, submit->nr_bos, vm); -+ if (err) -+ goto err_out1; -+ -+ err = lima_gem_add_deps(file, submit); -+ if (err) -+ goto err_out2; -+ -+ for (i = 0; i < submit->nr_bos; i++) { -+ err = lima_gem_sync_bo( -+ submit->task, bos[i], -+ submit->bos[i].flags & LIMA_SUBMIT_BO_WRITE, -+ submit->flags & LIMA_SUBMIT_FLAG_EXPLICIT_FENCE); -+ if (err) -+ goto err_out2; -+ } -+ -+ fence = lima_sched_context_queue_task( -+ submit->ctx->context + submit->pipe, submit->task); -+ -+ for (i = 0; i < submit->nr_bos; i++) { -+ if (submit->bos[i].flags & LIMA_SUBMIT_BO_WRITE) -+ reservation_object_add_excl_fence(bos[i]->gem.resv, fence); -+ else -+ reservation_object_add_shared_fence(bos[i]->gem.resv, fence); -+ } -+ -+ lima_gem_unlock_bos(bos, submit->nr_bos, &ctx); -+ -+ for (i = 0; i < submit->nr_bos; i++) -+ drm_gem_object_put_unlocked(&bos[i]->gem); -+ -+ if (out_sync) { -+ drm_syncobj_replace_fence(out_sync, fence); -+ drm_syncobj_put(out_sync); -+ } -+ -+ dma_fence_put(fence); -+ -+ return 0; -+ -+err_out2: -+ lima_sched_task_fini(submit->task); -+err_out1: -+ lima_gem_unlock_bos(bos, submit->nr_bos, &ctx); -+err_out0: -+ for (i = 0; i < submit->nr_bos; i++) { -+ if (!bos[i]) -+ break; -+ lima_vm_bo_del(vm, bos[i]); -+ drm_gem_object_put_unlocked(&bos[i]->gem); -+ } -+ if (out_sync) -+ drm_syncobj_put(out_sync); -+ return err; -+} -+ -+int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns) -+{ -+ bool write = op & LIMA_GEM_WAIT_WRITE; -+ long ret, timeout; -+ -+ if (!op) -+ return 0; -+ -+ timeout = drm_timeout_abs_to_jiffies(timeout_ns); -+ -+ ret = drm_gem_reservation_object_wait(file, handle, write, timeout); -+ if (ret == 0) -+ ret = timeout ? -ETIMEDOUT : -EBUSY; -+ -+ return ret; -+} -diff --git a/drivers/gpu/drm/lima/lima_gem.h b/drivers/gpu/drm/lima/lima_gem.h -new file mode 100644 -index 0000000000000..556111a01135d ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_gem.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_GEM_H__ -+#define __LIMA_GEM_H__ -+ -+struct lima_bo; -+struct lima_submit; -+ -+extern const struct vm_operations_struct lima_gem_vm_ops; -+ -+struct lima_bo *lima_gem_create_bo(struct drm_device *dev, u32 size, u32 flags); -+int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, -+ u32 size, u32 flags, u32 *handle); -+void lima_gem_free_object(struct drm_gem_object *obj); -+int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file); -+void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file); -+int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset); -+int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma); -+int lima_gem_submit(struct drm_file *file, struct lima_submit *submit); -+int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns); -+ -+void lima_set_vma_flags(struct vm_area_struct *vma); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_gem_prime.c b/drivers/gpu/drm/lima/lima_gem_prime.c -new file mode 100644 -index 0000000000000..9c6d9f1dba557 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_gem_prime.c -@@ -0,0 +1,47 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#include -+#include -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_object.h" -+#include "lima_gem.h" -+#include "lima_gem_prime.h" -+ -+struct drm_gem_object *lima_gem_prime_import_sg_table( -+ struct drm_device *dev, struct dma_buf_attachment *attach, -+ struct sg_table *sgt) -+{ -+ struct lima_device *ldev = to_lima_dev(dev); -+ struct lima_bo *bo; -+ -+ bo = lima_bo_create(ldev, attach->dmabuf->size, 0, sgt, -+ attach->dmabuf->resv); -+ if (IS_ERR(bo)) -+ return ERR_CAST(bo); -+ -+ return &bo->gem; -+} -+ -+struct sg_table *lima_gem_prime_get_sg_table(struct drm_gem_object *obj) -+{ -+ struct lima_bo *bo = to_lima_bo(obj); -+ int npages = obj->size >> PAGE_SHIFT; -+ -+ return drm_prime_pages_to_sg(bo->pages, npages); -+} -+ -+int lima_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) -+{ -+ int ret; -+ -+ ret = drm_gem_mmap_obj(obj, obj->size, vma); -+ if (ret) -+ return ret; -+ -+ lima_set_vma_flags(vma); -+ return 0; -+} -diff --git a/drivers/gpu/drm/lima/lima_gem_prime.h b/drivers/gpu/drm/lima/lima_gem_prime.h -new file mode 100644 -index 0000000000000..34b4d35c21e3e ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_gem_prime.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#ifndef __LIMA_GEM_PRIME_H__ -+#define __LIMA_GEM_PRIME_H__ -+ -+struct drm_gem_object *lima_gem_prime_import_sg_table( -+ struct drm_device *dev, struct dma_buf_attachment *attach, -+ struct sg_table *sgt); -+struct sg_table *lima_gem_prime_get_sg_table(struct drm_gem_object *obj); -+int lima_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c -new file mode 100644 -index 0000000000000..ccf49faedebf8 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_gp.c -@@ -0,0 +1,283 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "lima_device.h" -+#include "lima_gp.h" -+#include "lima_regs.h" -+ -+#define gp_write(reg, data) writel(data, ip->iomem + reg) -+#define gp_read(reg) readl(ip->iomem + reg) -+ -+static irqreturn_t lima_gp_irq_handler(int irq, void *data) -+{ -+ struct lima_ip *ip = data; -+ struct lima_device *dev = ip->dev; -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; -+ u32 state = gp_read(LIMA_GP_INT_STAT); -+ u32 status = gp_read(LIMA_GP_STATUS); -+ bool done = false; -+ -+ /* for shared irq case */ -+ if (!state) -+ return IRQ_NONE; -+ -+ if (state & LIMA_GP_IRQ_MASK_ERROR) { -+ dev_err(dev->dev, "gp error irq state=%x status=%x\n", -+ state, status); -+ -+ /* mask all interrupts before hard reset */ -+ gp_write(LIMA_GP_INT_MASK, 0); -+ -+ pipe->error = true; -+ done = true; -+ } else { -+ bool valid = state & (LIMA_GP_IRQ_VS_END_CMD_LST | -+ LIMA_GP_IRQ_PLBU_END_CMD_LST); -+ bool active = status & (LIMA_GP_STATUS_VS_ACTIVE | -+ LIMA_GP_STATUS_PLBU_ACTIVE); -+ done = valid && !active; -+ } -+ -+ gp_write(LIMA_GP_INT_CLEAR, state); -+ -+ if (done) -+ lima_sched_pipe_task_done(pipe); -+ -+ return IRQ_HANDLED; -+} -+ -+static void lima_gp_soft_reset_async(struct lima_ip *ip) -+{ -+ if (ip->data.async_reset) -+ return; -+ -+ gp_write(LIMA_GP_INT_MASK, 0); -+ gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_RESET_COMPLETED); -+ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_SOFT_RESET); -+ ip->data.async_reset = true; -+} -+ -+static int lima_gp_soft_reset_async_wait(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ u32 v; -+ -+ if (!ip->data.async_reset) -+ return 0; -+ -+ err = readl_poll_timeout(ip->iomem + LIMA_GP_INT_RAWSTAT, v, -+ v & LIMA_GP_IRQ_RESET_COMPLETED, -+ 0, 100); -+ if (err) { -+ dev_err(dev->dev, "gp soft reset time out\n"); -+ return err; -+ } -+ -+ gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL); -+ gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); -+ -+ ip->data.async_reset = false; -+ return 0; -+} -+ -+static int lima_gp_task_validate(struct lima_sched_pipe *pipe, -+ struct lima_sched_task *task) -+{ -+ struct drm_lima_gp_frame *frame = task->frame; -+ u32 *f = frame->frame; -+ (void)pipe; -+ -+ if (f[LIMA_GP_VSCL_START_ADDR >> 2] > -+ f[LIMA_GP_VSCL_END_ADDR >> 2] || -+ f[LIMA_GP_PLBUCL_START_ADDR >> 2] > -+ f[LIMA_GP_PLBUCL_END_ADDR >> 2] || -+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] > -+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]) -+ return -EINVAL; -+ -+ if (f[LIMA_GP_VSCL_START_ADDR >> 2] == -+ f[LIMA_GP_VSCL_END_ADDR >> 2] && -+ f[LIMA_GP_PLBUCL_START_ADDR >> 2] == -+ f[LIMA_GP_PLBUCL_END_ADDR >> 2]) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static void lima_gp_task_run(struct lima_sched_pipe *pipe, -+ struct lima_sched_task *task) -+{ -+ struct lima_ip *ip = pipe->processor[0]; -+ struct drm_lima_gp_frame *frame = task->frame; -+ u32 *f = frame->frame; -+ u32 cmd = 0; -+ int i; -+ -+ if (f[LIMA_GP_VSCL_START_ADDR >> 2] != -+ f[LIMA_GP_VSCL_END_ADDR >> 2]) -+ cmd |= LIMA_GP_CMD_START_VS; -+ if (f[LIMA_GP_PLBUCL_START_ADDR >> 2] != -+ f[LIMA_GP_PLBUCL_END_ADDR >> 2]) -+ cmd |= LIMA_GP_CMD_START_PLBU; -+ -+ /* before any hw ops, wait last success task async soft reset */ -+ lima_gp_soft_reset_async_wait(ip); -+ -+ for (i = 0; i < LIMA_GP_FRAME_REG_NUM; i++) -+ writel(f[i], ip->iomem + LIMA_GP_VSCL_START_ADDR + i * 4); -+ -+ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); -+ gp_write(LIMA_GP_CMD, cmd); -+} -+ -+static int lima_gp_hard_reset_poll(struct lima_ip *ip) -+{ -+ gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC01A0000); -+ return gp_read(LIMA_GP_PERF_CNT_0_LIMIT) == 0xC01A0000; -+} -+ -+static int lima_gp_hard_reset(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int ret; -+ -+ gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC0FFE000); -+ gp_write(LIMA_GP_INT_MASK, 0); -+ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_RESET); -+ ret = lima_poll_timeout(ip, lima_gp_hard_reset_poll, 10, 100); -+ if (ret) { -+ dev_err(dev->dev, "gp hard reset timeout\n"); -+ return ret; -+ } -+ -+ gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0); -+ gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL); -+ gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); -+ return 0; -+} -+ -+static void lima_gp_task_fini(struct lima_sched_pipe *pipe) -+{ -+ lima_gp_soft_reset_async(pipe->processor[0]); -+} -+ -+static void lima_gp_task_error(struct lima_sched_pipe *pipe) -+{ -+ struct lima_ip *ip = pipe->processor[0]; -+ -+ dev_err(ip->dev->dev, "gp task error int_state=%x status=%x\n", -+ gp_read(LIMA_GP_INT_STAT), gp_read(LIMA_GP_STATUS)); -+ -+ lima_gp_hard_reset(ip); -+} -+ -+static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe) -+{ -+ lima_sched_pipe_task_done(pipe); -+} -+ -+static void lima_gp_print_version(struct lima_ip *ip) -+{ -+ u32 version, major, minor; -+ char *name; -+ -+ version = gp_read(LIMA_GP_VERSION); -+ major = (version >> 8) & 0xFF; -+ minor = version & 0xFF; -+ switch (version >> 16) { -+ case 0xA07: -+ name = "mali200"; -+ break; -+ case 0xC07: -+ name = "mali300"; -+ break; -+ case 0xB07: -+ name = "mali400"; -+ break; -+ case 0xD07: -+ name = "mali450"; -+ break; -+ default: -+ name = "unknown"; -+ break; -+ } -+ dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n", -+ lima_ip_name(ip), name, major, minor); -+} -+ -+static struct kmem_cache *lima_gp_task_slab; -+static int lima_gp_task_slab_refcnt; -+ -+int lima_gp_init(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ -+ lima_gp_print_version(ip); -+ -+ ip->data.async_reset = false; -+ lima_gp_soft_reset_async(ip); -+ err = lima_gp_soft_reset_async_wait(ip); -+ if (err) -+ return err; -+ -+ err = devm_request_irq(dev->dev, ip->irq, lima_gp_irq_handler, -+ IRQF_SHARED, lima_ip_name(ip), ip); -+ if (err) { -+ dev_err(dev->dev, "gp %s fail to request irq\n", -+ lima_ip_name(ip)); -+ return err; -+ } -+ -+ dev->gp_version = gp_read(LIMA_GP_VERSION); -+ -+ return 0; -+} -+ -+void lima_gp_fini(struct lima_ip *ip) -+{ -+ -+} -+ -+int lima_gp_pipe_init(struct lima_device *dev) -+{ -+ int frame_size = sizeof(struct drm_lima_gp_frame); -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; -+ -+ if (!lima_gp_task_slab) { -+ lima_gp_task_slab = kmem_cache_create_usercopy( -+ "lima_gp_task", sizeof(struct lima_sched_task) + frame_size, -+ 0, SLAB_HWCACHE_ALIGN, sizeof(struct lima_sched_task), -+ frame_size, NULL); -+ if (!lima_gp_task_slab) -+ return -ENOMEM; -+ } -+ lima_gp_task_slab_refcnt++; -+ -+ pipe->frame_size = frame_size; -+ pipe->task_slab = lima_gp_task_slab; -+ -+ pipe->task_validate = lima_gp_task_validate; -+ pipe->task_run = lima_gp_task_run; -+ pipe->task_fini = lima_gp_task_fini; -+ pipe->task_error = lima_gp_task_error; -+ pipe->task_mmu_error = lima_gp_task_mmu_error; -+ -+ return 0; -+} -+ -+void lima_gp_pipe_fini(struct lima_device *dev) -+{ -+ if (!--lima_gp_task_slab_refcnt) { -+ kmem_cache_destroy(lima_gp_task_slab); -+ lima_gp_task_slab = NULL; -+ } -+} -diff --git a/drivers/gpu/drm/lima/lima_gp.h b/drivers/gpu/drm/lima/lima_gp.h -new file mode 100644 -index 0000000000000..516e5c1babbb4 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_gp.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_GP_H__ -+#define __LIMA_GP_H__ -+ -+struct lima_ip; -+struct lima_device; -+ -+int lima_gp_init(struct lima_ip *ip); -+void lima_gp_fini(struct lima_ip *ip); -+ -+int lima_gp_pipe_init(struct lima_device *dev); -+void lima_gp_pipe_fini(struct lima_device *dev); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_l2_cache.c b/drivers/gpu/drm/lima/lima_l2_cache.c -new file mode 100644 -index 0000000000000..6873a7af5a5ce ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_l2_cache.c -@@ -0,0 +1,80 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_l2_cache.h" -+#include "lima_regs.h" -+ -+#define l2_cache_write(reg, data) writel(data, ip->iomem + reg) -+#define l2_cache_read(reg) readl(ip->iomem + reg) -+ -+static int lima_l2_cache_wait_idle(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ u32 v; -+ -+ err = readl_poll_timeout(ip->iomem + LIMA_L2_CACHE_STATUS, v, -+ !(v & LIMA_L2_CACHE_STATUS_COMMAND_BUSY), -+ 0, 1000); -+ if (err) { -+ dev_err(dev->dev, "l2 cache wait command timeout\n"); -+ return err; -+ } -+ return 0; -+} -+ -+int lima_l2_cache_flush(struct lima_ip *ip) -+{ -+ int ret; -+ -+ spin_lock(&ip->data.lock); -+ l2_cache_write(LIMA_L2_CACHE_COMMAND, LIMA_L2_CACHE_COMMAND_CLEAR_ALL); -+ ret = lima_l2_cache_wait_idle(ip); -+ spin_unlock(&ip->data.lock); -+ return ret; -+} -+ -+int lima_l2_cache_init(struct lima_ip *ip) -+{ -+ int i, err; -+ u32 size; -+ struct lima_device *dev = ip->dev; -+ -+ /* l2_cache2 only exists when one of PP4-7 present */ -+ if (ip->id == lima_ip_l2_cache2) { -+ for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) { -+ if (dev->ip[i].present) -+ break; -+ } -+ if (i > lima_ip_pp7) -+ return -ENODEV; -+ } -+ -+ spin_lock_init(&ip->data.lock); -+ -+ size = l2_cache_read(LIMA_L2_CACHE_SIZE); -+ dev_info(dev->dev, "l2 cache %uK, %u-way, %ubyte cache line, %ubit external bus\n", -+ 1 << (((size >> 16) & 0xff) - 10), -+ 1 << ((size >> 8) & 0xff), -+ 1 << (size & 0xff), -+ 1 << ((size >> 24) & 0xff)); -+ -+ err = lima_l2_cache_flush(ip); -+ if (err) -+ return err; -+ -+ l2_cache_write(LIMA_L2_CACHE_ENABLE, -+ LIMA_L2_CACHE_ENABLE_ACCESS|LIMA_L2_CACHE_ENABLE_READ_ALLOCATE); -+ l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c); -+ -+ return 0; -+} -+ -+void lima_l2_cache_fini(struct lima_ip *ip) -+{ -+ -+} -diff --git a/drivers/gpu/drm/lima/lima_l2_cache.h b/drivers/gpu/drm/lima/lima_l2_cache.h -new file mode 100644 -index 0000000000000..c63fb676ff141 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_l2_cache.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_L2_CACHE_H__ -+#define __LIMA_L2_CACHE_H__ -+ -+struct lima_ip; -+ -+int lima_l2_cache_init(struct lima_ip *ip); -+void lima_l2_cache_fini(struct lima_ip *ip); -+ -+int lima_l2_cache_flush(struct lima_ip *ip); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c -new file mode 100644 -index 0000000000000..8e1651d6a61fa ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_mmu.c -@@ -0,0 +1,142 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_mmu.h" -+#include "lima_vm.h" -+#include "lima_object.h" -+#include "lima_regs.h" -+ -+#define mmu_write(reg, data) writel(data, ip->iomem + reg) -+#define mmu_read(reg) readl(ip->iomem + reg) -+ -+#define lima_mmu_send_command(cmd, addr, val, cond) \ -+({ \ -+ int __ret; \ -+ \ -+ mmu_write(LIMA_MMU_COMMAND, cmd); \ -+ __ret = readl_poll_timeout(ip->iomem + (addr), val, \ -+ cond, 0, 100); \ -+ if (__ret) \ -+ dev_err(dev->dev, \ -+ "mmu command %x timeout\n", cmd); \ -+ __ret; \ -+}) -+ -+static irqreturn_t lima_mmu_irq_handler(int irq, void *data) -+{ -+ struct lima_ip *ip = data; -+ struct lima_device *dev = ip->dev; -+ u32 status = mmu_read(LIMA_MMU_INT_STATUS); -+ struct lima_sched_pipe *pipe; -+ -+ /* for shared irq case */ -+ if (!status) -+ return IRQ_NONE; -+ -+ if (status & LIMA_MMU_INT_PAGE_FAULT) { -+ u32 fault = mmu_read(LIMA_MMU_PAGE_FAULT_ADDR); -+ -+ dev_err(dev->dev, "mmu page fault at 0x%x from bus id %d of type %s on %s\n", -+ fault, LIMA_MMU_STATUS_BUS_ID(status), -+ status & LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE ? "write" : "read", -+ lima_ip_name(ip)); -+ } -+ -+ if (status & LIMA_MMU_INT_READ_BUS_ERROR) -+ dev_err(dev->dev, "mmu %s irq bus error\n", lima_ip_name(ip)); -+ -+ /* mask all interrupts before resume */ -+ mmu_write(LIMA_MMU_INT_MASK, 0); -+ mmu_write(LIMA_MMU_INT_CLEAR, status); -+ -+ pipe = dev->pipe + (ip->id == lima_ip_gpmmu ? lima_pipe_gp : lima_pipe_pp); -+ lima_sched_pipe_mmu_error(pipe); -+ -+ return IRQ_HANDLED; -+} -+ -+int lima_mmu_init(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ u32 v; -+ -+ if (ip->id == lima_ip_ppmmu_bcast) -+ return 0; -+ -+ mmu_write(LIMA_MMU_DTE_ADDR, 0xCAFEBABE); -+ if (mmu_read(LIMA_MMU_DTE_ADDR) != 0xCAFEB000) { -+ dev_err(dev->dev, "mmu %s dte write test fail\n", lima_ip_name(ip)); -+ return -EIO; -+ } -+ -+ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET); -+ err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, -+ LIMA_MMU_DTE_ADDR, v, v == 0); -+ if (err) -+ return err; -+ -+ err = devm_request_irq(dev->dev, ip->irq, lima_mmu_irq_handler, -+ IRQF_SHARED, lima_ip_name(ip), ip); -+ if (err) { -+ dev_err(dev->dev, "mmu %s fail to request irq\n", lima_ip_name(ip)); -+ return err; -+ } -+ -+ mmu_write(LIMA_MMU_INT_MASK, LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); -+ mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); -+ return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, -+ LIMA_MMU_STATUS, v, -+ v & LIMA_MMU_STATUS_PAGING_ENABLED); -+} -+ -+void lima_mmu_fini(struct lima_ip *ip) -+{ -+ -+} -+ -+void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm) -+{ -+ struct lima_device *dev = ip->dev; -+ u32 v; -+ -+ lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_STALL, -+ LIMA_MMU_STATUS, v, -+ v & LIMA_MMU_STATUS_STALL_ACTIVE); -+ -+ if (vm) -+ mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma); -+ -+ /* flush the TLB */ -+ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE); -+ -+ lima_mmu_send_command(LIMA_MMU_COMMAND_DISABLE_STALL, -+ LIMA_MMU_STATUS, v, -+ !(v & LIMA_MMU_STATUS_STALL_ACTIVE)); -+} -+ -+void lima_mmu_page_fault_resume(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ u32 status = mmu_read(LIMA_MMU_STATUS); -+ u32 v; -+ -+ if (status & LIMA_MMU_STATUS_PAGE_FAULT_ACTIVE) { -+ dev_info(dev->dev, "mmu resume\n"); -+ -+ mmu_write(LIMA_MMU_INT_MASK, 0); -+ mmu_write(LIMA_MMU_DTE_ADDR, 0xCAFEBABE); -+ lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, -+ LIMA_MMU_DTE_ADDR, v, v == 0); -+ mmu_write(LIMA_MMU_INT_MASK, LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); -+ mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); -+ lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, -+ LIMA_MMU_STATUS, v, -+ v & LIMA_MMU_STATUS_PAGING_ENABLED); -+ } -+} -diff --git a/drivers/gpu/drm/lima/lima_mmu.h b/drivers/gpu/drm/lima/lima_mmu.h -new file mode 100644 -index 0000000000000..8c78319bcc8e2 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_mmu.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_MMU_H__ -+#define __LIMA_MMU_H__ -+ -+struct lima_ip; -+struct lima_vm; -+ -+int lima_mmu_init(struct lima_ip *ip); -+void lima_mmu_fini(struct lima_ip *ip); -+ -+void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm); -+void lima_mmu_page_fault_resume(struct lima_ip *ip); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_object.c b/drivers/gpu/drm/lima/lima_object.c -new file mode 100644 -index 0000000000000..5c41f859a72fa ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_object.c -@@ -0,0 +1,122 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#include -+#include -+#include -+ -+#include "lima_object.h" -+ -+void lima_bo_destroy(struct lima_bo *bo) -+{ -+ if (bo->sgt) { -+ kfree(bo->pages); -+ drm_prime_gem_destroy(&bo->gem, bo->sgt); -+ } else { -+ if (bo->pages_dma_addr) { -+ int i, npages = bo->gem.size >> PAGE_SHIFT; -+ -+ for (i = 0; i < npages; i++) { -+ if (bo->pages_dma_addr[i]) -+ dma_unmap_page(bo->gem.dev->dev, -+ bo->pages_dma_addr[i], -+ PAGE_SIZE, DMA_BIDIRECTIONAL); -+ } -+ } -+ -+ if (bo->pages) -+ drm_gem_put_pages(&bo->gem, bo->pages, true, true); -+ } -+ -+ kfree(bo->pages_dma_addr); -+ drm_gem_object_release(&bo->gem); -+ kfree(bo); -+} -+ -+static struct lima_bo *lima_bo_create_struct(struct lima_device *dev, u32 size, u32 flags, -+ struct reservation_object *resv) -+{ -+ struct lima_bo *bo; -+ int err; -+ -+ size = PAGE_ALIGN(size); -+ -+ bo = kzalloc(sizeof(*bo), GFP_KERNEL); -+ if (!bo) -+ return ERR_PTR(-ENOMEM); -+ -+ mutex_init(&bo->lock); -+ INIT_LIST_HEAD(&bo->va); -+ bo->gem.resv = resv; -+ -+ err = drm_gem_object_init(dev->ddev, &bo->gem, size); -+ if (err) { -+ kfree(bo); -+ return ERR_PTR(err); -+ } -+ -+ return bo; -+} -+ -+struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size, -+ u32 flags, struct sg_table *sgt, -+ struct reservation_object *resv) -+{ -+ int i, err; -+ size_t npages; -+ struct lima_bo *bo, *ret; -+ -+ bo = lima_bo_create_struct(dev, size, flags, resv); -+ if (IS_ERR(bo)) -+ return bo; -+ -+ npages = bo->gem.size >> PAGE_SHIFT; -+ -+ bo->pages_dma_addr = kcalloc(npages, sizeof(dma_addr_t), GFP_KERNEL); -+ if (!bo->pages_dma_addr) { -+ ret = ERR_PTR(-ENOMEM); -+ goto err_out; -+ } -+ -+ if (sgt) { -+ bo->sgt = sgt; -+ -+ bo->pages = kcalloc(npages, sizeof(*bo->pages), GFP_KERNEL); -+ if (!bo->pages) { -+ ret = ERR_PTR(-ENOMEM); -+ goto err_out; -+ } -+ -+ err = drm_prime_sg_to_page_addr_arrays( -+ sgt, bo->pages, bo->pages_dma_addr, npages); -+ if (err) { -+ ret = ERR_PTR(err); -+ goto err_out; -+ } -+ } else { -+ mapping_set_gfp_mask(bo->gem.filp->f_mapping, GFP_DMA32); -+ bo->pages = drm_gem_get_pages(&bo->gem); -+ if (IS_ERR(bo->pages)) { -+ ret = ERR_CAST(bo->pages); -+ bo->pages = NULL; -+ goto err_out; -+ } -+ -+ for (i = 0; i < npages; i++) { -+ dma_addr_t addr = dma_map_page(dev->dev, bo->pages[i], 0, -+ PAGE_SIZE, DMA_BIDIRECTIONAL); -+ if (dma_mapping_error(dev->dev, addr)) { -+ ret = ERR_PTR(-EFAULT); -+ goto err_out; -+ } -+ bo->pages_dma_addr[i] = addr; -+ } -+ -+ } -+ -+ return bo; -+ -+err_out: -+ lima_bo_destroy(bo); -+ return ret; -+} -diff --git a/drivers/gpu/drm/lima/lima_object.h b/drivers/gpu/drm/lima/lima_object.h -new file mode 100644 -index 0000000000000..6738724afb7b0 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_object.h -@@ -0,0 +1,36 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2018-2019 Qiang Yu */ -+ -+#ifndef __LIMA_OBJECT_H__ -+#define __LIMA_OBJECT_H__ -+ -+#include -+ -+#include "lima_device.h" -+ -+struct lima_bo { -+ struct drm_gem_object gem; -+ -+ struct page **pages; -+ dma_addr_t *pages_dma_addr; -+ struct sg_table *sgt; -+ void *vaddr; -+ -+ struct mutex lock; -+ struct list_head va; -+}; -+ -+static inline struct lima_bo * -+to_lima_bo(struct drm_gem_object *obj) -+{ -+ return container_of(obj, struct lima_bo, gem); -+} -+ -+struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size, -+ u32 flags, struct sg_table *sgt, -+ struct reservation_object *resv); -+void lima_bo_destroy(struct lima_bo *bo); -+void *lima_bo_vmap(struct lima_bo *bo); -+void lima_bo_vunmap(struct lima_bo *bo); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_pmu.c b/drivers/gpu/drm/lima/lima_pmu.c -new file mode 100644 -index 0000000000000..571f6d6615818 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_pmu.c -@@ -0,0 +1,60 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_pmu.h" -+#include "lima_regs.h" -+ -+#define pmu_write(reg, data) writel(data, ip->iomem + reg) -+#define pmu_read(reg) readl(ip->iomem + reg) -+ -+static int lima_pmu_wait_cmd(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ u32 v; -+ -+ err = readl_poll_timeout(ip->iomem + LIMA_PMU_INT_RAWSTAT, -+ v, v & LIMA_PMU_INT_CMD_MASK, -+ 100, 100000); -+ if (err) { -+ dev_err(dev->dev, "timeout wait pmd cmd\n"); -+ return err; -+ } -+ -+ pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK); -+ return 0; -+} -+ -+int lima_pmu_init(struct lima_ip *ip) -+{ -+ int err; -+ u32 stat; -+ -+ pmu_write(LIMA_PMU_INT_MASK, 0); -+ -+ /* If this value is too low, when in high GPU clk freq, -+ * GPU will be in unstable state. -+ */ -+ pmu_write(LIMA_PMU_SW_DELAY, 0xffff); -+ -+ /* status reg 1=off 0=on */ -+ stat = pmu_read(LIMA_PMU_STATUS); -+ -+ /* power up all ip */ -+ if (stat) { -+ pmu_write(LIMA_PMU_POWER_UP, stat); -+ err = lima_pmu_wait_cmd(ip); -+ if (err) -+ return err; -+ } -+ return 0; -+} -+ -+void lima_pmu_fini(struct lima_ip *ip) -+{ -+ -+} -diff --git a/drivers/gpu/drm/lima/lima_pmu.h b/drivers/gpu/drm/lima/lima_pmu.h -new file mode 100644 -index 0000000000000..a2a18775eb07d ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_pmu.h -@@ -0,0 +1,12 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_PMU_H__ -+#define __LIMA_PMU_H__ -+ -+struct lima_ip; -+ -+int lima_pmu_init(struct lima_ip *ip); -+void lima_pmu_fini(struct lima_ip *ip); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_pp.c b/drivers/gpu/drm/lima/lima_pp.c -new file mode 100644 -index 0000000000000..d29721e177bf9 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_pp.c -@@ -0,0 +1,427 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "lima_device.h" -+#include "lima_pp.h" -+#include "lima_dlbu.h" -+#include "lima_bcast.h" -+#include "lima_vm.h" -+#include "lima_regs.h" -+ -+#define pp_write(reg, data) writel(data, ip->iomem + reg) -+#define pp_read(reg) readl(ip->iomem + reg) -+ -+static void lima_pp_handle_irq(struct lima_ip *ip, u32 state) -+{ -+ struct lima_device *dev = ip->dev; -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ -+ if (state & LIMA_PP_IRQ_MASK_ERROR) { -+ u32 status = pp_read(LIMA_PP_STATUS); -+ -+ dev_err(dev->dev, "pp error irq state=%x status=%x\n", -+ state, status); -+ -+ pipe->error = true; -+ -+ /* mask all interrupts before hard reset */ -+ pp_write(LIMA_PP_INT_MASK, 0); -+ } -+ -+ pp_write(LIMA_PP_INT_CLEAR, state); -+} -+ -+static irqreturn_t lima_pp_irq_handler(int irq, void *data) -+{ -+ struct lima_ip *ip = data; -+ struct lima_device *dev = ip->dev; -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ u32 state = pp_read(LIMA_PP_INT_STATUS); -+ -+ /* for shared irq case */ -+ if (!state) -+ return IRQ_NONE; -+ -+ lima_pp_handle_irq(ip, state); -+ -+ if (atomic_dec_and_test(&pipe->task)) -+ lima_sched_pipe_task_done(pipe); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t lima_pp_bcast_irq_handler(int irq, void *data) -+{ -+ int i; -+ irqreturn_t ret = IRQ_NONE; -+ struct lima_ip *pp_bcast = data; -+ struct lima_device *dev = pp_bcast->dev; -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ struct drm_lima_m450_pp_frame *frame = pipe->current_task->frame; -+ -+ for (i = 0; i < frame->num_pp; i++) { -+ struct lima_ip *ip = pipe->processor[i]; -+ u32 status, state; -+ -+ if (pipe->done & (1 << i)) -+ continue; -+ -+ /* status read first in case int state change in the middle -+ * which may miss the interrupt handling -+ */ -+ status = pp_read(LIMA_PP_STATUS); -+ state = pp_read(LIMA_PP_INT_STATUS); -+ -+ if (state) { -+ lima_pp_handle_irq(ip, state); -+ ret = IRQ_HANDLED; -+ } else { -+ if (status & LIMA_PP_STATUS_RENDERING_ACTIVE) -+ continue; -+ } -+ -+ pipe->done |= (1 << i); -+ if (atomic_dec_and_test(&pipe->task)) -+ lima_sched_pipe_task_done(pipe); -+ } -+ -+ return ret; -+} -+ -+static void lima_pp_soft_reset_async(struct lima_ip *ip) -+{ -+ if (ip->data.async_reset) -+ return; -+ -+ pp_write(LIMA_PP_INT_MASK, 0); -+ pp_write(LIMA_PP_INT_RAWSTAT, LIMA_PP_IRQ_MASK_ALL); -+ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_SOFT_RESET); -+ ip->data.async_reset = true; -+} -+ -+static int lima_pp_soft_reset_poll(struct lima_ip *ip) -+{ -+ return !(pp_read(LIMA_PP_STATUS) & LIMA_PP_STATUS_RENDERING_ACTIVE) && -+ pp_read(LIMA_PP_INT_RAWSTAT) == LIMA_PP_IRQ_RESET_COMPLETED; -+} -+ -+static int lima_pp_soft_reset_async_wait_one(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int ret; -+ -+ ret = lima_poll_timeout(ip, lima_pp_soft_reset_poll, 0, 100); -+ if (ret) { -+ dev_err(dev->dev, "pp %s reset time out\n", lima_ip_name(ip)); -+ return ret; -+ } -+ -+ pp_write(LIMA_PP_INT_CLEAR, LIMA_PP_IRQ_MASK_ALL); -+ pp_write(LIMA_PP_INT_MASK, LIMA_PP_IRQ_MASK_USED); -+ return 0; -+} -+ -+static int lima_pp_soft_reset_async_wait(struct lima_ip *ip) -+{ -+ int i, err = 0; -+ -+ if (!ip->data.async_reset) -+ return 0; -+ -+ if (ip->id == lima_ip_pp_bcast) { -+ struct lima_device *dev = ip->dev; -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ struct drm_lima_m450_pp_frame *frame = pipe->current_task->frame; -+ -+ for (i = 0; i < frame->num_pp; i++) -+ err |= lima_pp_soft_reset_async_wait_one(pipe->processor[i]); -+ } else -+ err = lima_pp_soft_reset_async_wait_one(ip); -+ -+ ip->data.async_reset = false; -+ return err; -+} -+ -+static void lima_pp_write_frame(struct lima_ip *ip, u32 *frame, u32 *wb) -+{ -+ int i, j, n = 0; -+ -+ for (i = 0; i < LIMA_PP_FRAME_REG_NUM; i++) -+ writel(frame[i], ip->iomem + LIMA_PP_FRAME + i * 4); -+ -+ for (i = 0; i < 3; i++) { -+ for (j = 0; j < LIMA_PP_WB_REG_NUM; j++) -+ writel(wb[n++], ip->iomem + LIMA_PP_WB(i) + j * 4); -+ } -+} -+ -+static int lima_pp_hard_reset_poll(struct lima_ip *ip) -+{ -+ pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0xC01A0000); -+ return pp_read(LIMA_PP_PERF_CNT_0_LIMIT) == 0xC01A0000; -+} -+ -+static int lima_pp_hard_reset(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int ret; -+ -+ pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0xC0FFE000); -+ pp_write(LIMA_PP_INT_MASK, 0); -+ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_FORCE_RESET); -+ ret = lima_poll_timeout(ip, lima_pp_hard_reset_poll, 10, 100); -+ if (ret) { -+ dev_err(dev->dev, "pp hard reset timeout\n"); -+ return ret; -+ } -+ -+ pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0); -+ pp_write(LIMA_PP_INT_CLEAR, LIMA_PP_IRQ_MASK_ALL); -+ pp_write(LIMA_PP_INT_MASK, LIMA_PP_IRQ_MASK_USED); -+ return 0; -+} -+ -+static void lima_pp_print_version(struct lima_ip *ip) -+{ -+ u32 version, major, minor; -+ char *name; -+ -+ version = pp_read(LIMA_PP_VERSION); -+ major = (version >> 8) & 0xFF; -+ minor = version & 0xFF; -+ switch (version >> 16) { -+ case 0xC807: -+ name = "mali200"; -+ break; -+ case 0xCE07: -+ name = "mali300"; -+ break; -+ case 0xCD07: -+ name = "mali400"; -+ break; -+ case 0xCF07: -+ name = "mali450"; -+ break; -+ default: -+ name = "unknown"; -+ break; -+ } -+ dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n", -+ lima_ip_name(ip), name, major, minor); -+} -+ -+int lima_pp_init(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ -+ lima_pp_print_version(ip); -+ -+ ip->data.async_reset = false; -+ lima_pp_soft_reset_async(ip); -+ err = lima_pp_soft_reset_async_wait(ip); -+ if (err) -+ return err; -+ -+ err = devm_request_irq(dev->dev, ip->irq, lima_pp_irq_handler, -+ IRQF_SHARED, lima_ip_name(ip), ip); -+ if (err) { -+ dev_err(dev->dev, "pp %s fail to request irq\n", -+ lima_ip_name(ip)); -+ return err; -+ } -+ -+ dev->pp_version = pp_read(LIMA_PP_VERSION); -+ -+ return 0; -+} -+ -+void lima_pp_fini(struct lima_ip *ip) -+{ -+ -+} -+ -+int lima_pp_bcast_init(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ -+ err = devm_request_irq(dev->dev, ip->irq, lima_pp_bcast_irq_handler, -+ IRQF_SHARED, lima_ip_name(ip), ip); -+ if (err) { -+ dev_err(dev->dev, "pp %s fail to request irq\n", -+ lima_ip_name(ip)); -+ return err; -+ } -+ -+ return 0; -+} -+ -+void lima_pp_bcast_fini(struct lima_ip *ip) -+{ -+ -+} -+ -+static int lima_pp_task_validate(struct lima_sched_pipe *pipe, -+ struct lima_sched_task *task) -+{ -+ u32 num_pp; -+ -+ if (pipe->bcast_processor) { -+ struct drm_lima_m450_pp_frame *f = task->frame; -+ -+ num_pp = f->num_pp; -+ -+ if (f->_pad) -+ return -EINVAL; -+ } else { -+ struct drm_lima_m400_pp_frame *f = task->frame; -+ -+ num_pp = f->num_pp; -+ } -+ -+ if (num_pp == 0 || num_pp > pipe->num_processor) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static void lima_pp_task_run(struct lima_sched_pipe *pipe, -+ struct lima_sched_task *task) -+{ -+ if (pipe->bcast_processor) { -+ struct drm_lima_m450_pp_frame *frame = task->frame; -+ struct lima_device *dev = pipe->bcast_processor->dev; -+ struct lima_ip *ip = pipe->bcast_processor; -+ int i; -+ -+ pipe->done = 0; -+ atomic_set(&pipe->task, frame->num_pp); -+ -+ if (frame->use_dlbu) { -+ lima_dlbu_enable(dev, frame->num_pp); -+ -+ frame->frame[LIMA_PP_FRAME >> 2] = LIMA_VA_RESERVE_DLBU; -+ lima_dlbu_set_reg(dev->ip + lima_ip_dlbu, frame->dlbu_regs); -+ } else -+ lima_dlbu_disable(dev); -+ -+ lima_bcast_enable(dev, frame->num_pp); -+ -+ lima_pp_soft_reset_async_wait(ip); -+ -+ lima_pp_write_frame(ip, frame->frame, frame->wb); -+ -+ for (i = 0; i < frame->num_pp; i++) { -+ struct lima_ip *ip = pipe->processor[i]; -+ -+ pp_write(LIMA_PP_STACK, frame->fragment_stack_address[i]); -+ if (!frame->use_dlbu) -+ pp_write(LIMA_PP_FRAME, frame->plbu_array_address[i]); -+ } -+ -+ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_START_RENDERING); -+ } else { -+ struct drm_lima_m400_pp_frame *frame = task->frame; -+ int i; -+ -+ atomic_set(&pipe->task, frame->num_pp); -+ -+ for (i = 0; i < frame->num_pp; i++) { -+ struct lima_ip *ip = pipe->processor[i]; -+ -+ frame->frame[LIMA_PP_FRAME >> 2] = -+ frame->plbu_array_address[i]; -+ frame->frame[LIMA_PP_STACK >> 2] = -+ frame->fragment_stack_address[i]; -+ -+ lima_pp_soft_reset_async_wait(ip); -+ -+ lima_pp_write_frame(ip, frame->frame, frame->wb); -+ -+ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_START_RENDERING); -+ } -+ } -+} -+ -+static void lima_pp_task_fini(struct lima_sched_pipe *pipe) -+{ -+ if (pipe->bcast_processor) -+ lima_pp_soft_reset_async(pipe->bcast_processor); -+ else { -+ int i; -+ -+ for (i = 0; i < pipe->num_processor; i++) -+ lima_pp_soft_reset_async(pipe->processor[i]); -+ } -+} -+ -+static void lima_pp_task_error(struct lima_sched_pipe *pipe) -+{ -+ int i; -+ -+ for (i = 0; i < pipe->num_processor; i++) { -+ struct lima_ip *ip = pipe->processor[i]; -+ -+ dev_err(ip->dev->dev, "pp task error %d int_state=%x status=%x\n", -+ i, pp_read(LIMA_PP_INT_STATUS), pp_read(LIMA_PP_STATUS)); -+ -+ lima_pp_hard_reset(ip); -+ } -+} -+ -+static void lima_pp_task_mmu_error(struct lima_sched_pipe *pipe) -+{ -+ if (atomic_dec_and_test(&pipe->task)) -+ lima_sched_pipe_task_done(pipe); -+} -+ -+static struct kmem_cache *lima_pp_task_slab; -+static int lima_pp_task_slab_refcnt; -+ -+int lima_pp_pipe_init(struct lima_device *dev) -+{ -+ int frame_size; -+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; -+ -+ if (dev->id == lima_gpu_mali400) -+ frame_size = sizeof(struct drm_lima_m400_pp_frame); -+ else -+ frame_size = sizeof(struct drm_lima_m450_pp_frame); -+ -+ if (!lima_pp_task_slab) { -+ lima_pp_task_slab = kmem_cache_create_usercopy( -+ "lima_pp_task", sizeof(struct lima_sched_task) + frame_size, -+ 0, SLAB_HWCACHE_ALIGN, sizeof(struct lima_sched_task), -+ frame_size, NULL); -+ if (!lima_pp_task_slab) -+ return -ENOMEM; -+ } -+ lima_pp_task_slab_refcnt++; -+ -+ pipe->frame_size = frame_size; -+ pipe->task_slab = lima_pp_task_slab; -+ -+ pipe->task_validate = lima_pp_task_validate; -+ pipe->task_run = lima_pp_task_run; -+ pipe->task_fini = lima_pp_task_fini; -+ pipe->task_error = lima_pp_task_error; -+ pipe->task_mmu_error = lima_pp_task_mmu_error; -+ -+ return 0; -+} -+ -+void lima_pp_pipe_fini(struct lima_device *dev) -+{ -+ if (!--lima_pp_task_slab_refcnt) { -+ kmem_cache_destroy(lima_pp_task_slab); -+ lima_pp_task_slab = NULL; -+ } -+} -diff --git a/drivers/gpu/drm/lima/lima_pp.h b/drivers/gpu/drm/lima/lima_pp.h -new file mode 100644 -index 0000000000000..bf60c77b26338 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_pp.h -@@ -0,0 +1,19 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_PP_H__ -+#define __LIMA_PP_H__ -+ -+struct lima_ip; -+struct lima_device; -+ -+int lima_pp_init(struct lima_ip *ip); -+void lima_pp_fini(struct lima_ip *ip); -+ -+int lima_pp_bcast_init(struct lima_ip *ip); -+void lima_pp_bcast_fini(struct lima_ip *ip); -+ -+int lima_pp_pipe_init(struct lima_device *dev); -+void lima_pp_pipe_fini(struct lima_device *dev); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_regs.h b/drivers/gpu/drm/lima/lima_regs.h -new file mode 100644 -index 0000000000000..ace8ecefbe906 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_regs.h -@@ -0,0 +1,298 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2010-2017 ARM Limited. All rights reserved. -+ * Copyright 2017-2019 Qiang Yu -+ */ -+ -+#ifndef __LIMA_REGS_H__ -+#define __LIMA_REGS_H__ -+ -+/* This file's register definition is collected from the -+ * official ARM Mali Utgard GPU kernel driver source code -+ */ -+ -+/* PMU regs */ -+#define LIMA_PMU_POWER_UP 0x00 -+#define LIMA_PMU_POWER_DOWN 0x04 -+#define LIMA_PMU_POWER_GP0_MASK BIT(0) -+#define LIMA_PMU_POWER_L2_MASK BIT(1) -+#define LIMA_PMU_POWER_PP_MASK(i) BIT(2 + i) -+ -+/* -+ * On Mali450 each block automatically starts up its corresponding L2 -+ * and the PPs are not fully independent controllable. -+ * Instead PP0, PP1-3 and PP4-7 can be turned on or off. -+ */ -+#define LIMA450_PMU_POWER_PP0_MASK BIT(1) -+#define LIMA450_PMU_POWER_PP13_MASK BIT(2) -+#define LIMA450_PMU_POWER_PP47_MASK BIT(3) -+ -+#define LIMA_PMU_STATUS 0x08 -+#define LIMA_PMU_INT_MASK 0x0C -+#define LIMA_PMU_INT_RAWSTAT 0x10 -+#define LIMA_PMU_INT_CLEAR 0x18 -+#define LIMA_PMU_INT_CMD_MASK BIT(0) -+#define LIMA_PMU_SW_DELAY 0x1C -+ -+/* L2 cache regs */ -+#define LIMA_L2_CACHE_SIZE 0x0004 -+#define LIMA_L2_CACHE_STATUS 0x0008 -+#define LIMA_L2_CACHE_STATUS_COMMAND_BUSY BIT(0) -+#define LIMA_L2_CACHE_STATUS_DATA_BUSY BIT(1) -+#define LIMA_L2_CACHE_COMMAND 0x0010 -+#define LIMA_L2_CACHE_COMMAND_CLEAR_ALL BIT(0) -+#define LIMA_L2_CACHE_CLEAR_PAGE 0x0014 -+#define LIMA_L2_CACHE_MAX_READS 0x0018 -+#define LIMA_L2_CACHE_ENABLE 0x001C -+#define LIMA_L2_CACHE_ENABLE_ACCESS BIT(0) -+#define LIMA_L2_CACHE_ENABLE_READ_ALLOCATE BIT(1) -+#define LIMA_L2_CACHE_PERFCNT_SRC0 0x0020 -+#define LIMA_L2_CACHE_PERFCNT_VAL0 0x0024 -+#define LIMA_L2_CACHE_PERFCNT_SRC1 0x0028 -+#define LIMA_L2_CACHE_ERFCNT_VAL1 0x002C -+ -+/* GP regs */ -+#define LIMA_GP_VSCL_START_ADDR 0x00 -+#define LIMA_GP_VSCL_END_ADDR 0x04 -+#define LIMA_GP_PLBUCL_START_ADDR 0x08 -+#define LIMA_GP_PLBUCL_END_ADDR 0x0c -+#define LIMA_GP_PLBU_ALLOC_START_ADDR 0x10 -+#define LIMA_GP_PLBU_ALLOC_END_ADDR 0x14 -+#define LIMA_GP_CMD 0x20 -+#define LIMA_GP_CMD_START_VS BIT(0) -+#define LIMA_GP_CMD_START_PLBU BIT(1) -+#define LIMA_GP_CMD_UPDATE_PLBU_ALLOC BIT(4) -+#define LIMA_GP_CMD_RESET BIT(5) -+#define LIMA_GP_CMD_FORCE_HANG BIT(6) -+#define LIMA_GP_CMD_STOP_BUS BIT(9) -+#define LIMA_GP_CMD_SOFT_RESET BIT(10) -+#define LIMA_GP_INT_RAWSTAT 0x24 -+#define LIMA_GP_INT_CLEAR 0x28 -+#define LIMA_GP_INT_MASK 0x2C -+#define LIMA_GP_INT_STAT 0x30 -+#define LIMA_GP_IRQ_VS_END_CMD_LST BIT(0) -+#define LIMA_GP_IRQ_PLBU_END_CMD_LST BIT(1) -+#define LIMA_GP_IRQ_PLBU_OUT_OF_MEM BIT(2) -+#define LIMA_GP_IRQ_VS_SEM_IRQ BIT(3) -+#define LIMA_GP_IRQ_PLBU_SEM_IRQ BIT(4) -+#define LIMA_GP_IRQ_HANG BIT(5) -+#define LIMA_GP_IRQ_FORCE_HANG BIT(6) -+#define LIMA_GP_IRQ_PERF_CNT_0_LIMIT BIT(7) -+#define LIMA_GP_IRQ_PERF_CNT_1_LIMIT BIT(8) -+#define LIMA_GP_IRQ_WRITE_BOUND_ERR BIT(9) -+#define LIMA_GP_IRQ_SYNC_ERROR BIT(10) -+#define LIMA_GP_IRQ_AXI_BUS_ERROR BIT(11) -+#define LIMA_GP_IRQ_AXI_BUS_STOPPED BIT(12) -+#define LIMA_GP_IRQ_VS_INVALID_CMD BIT(13) -+#define LIMA_GP_IRQ_PLB_INVALID_CMD BIT(14) -+#define LIMA_GP_IRQ_RESET_COMPLETED BIT(19) -+#define LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW BIT(20) -+#define LIMA_GP_IRQ_SEMAPHORE_OVERFLOW BIT(21) -+#define LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS BIT(22) -+#define LIMA_GP_WRITE_BOUND_LOW 0x34 -+#define LIMA_GP_PERF_CNT_0_ENABLE 0x3C -+#define LIMA_GP_PERF_CNT_1_ENABLE 0x40 -+#define LIMA_GP_PERF_CNT_0_SRC 0x44 -+#define LIMA_GP_PERF_CNT_1_SRC 0x48 -+#define LIMA_GP_PERF_CNT_0_VALUE 0x4C -+#define LIMA_GP_PERF_CNT_1_VALUE 0x50 -+#define LIMA_GP_PERF_CNT_0_LIMIT 0x54 -+#define LIMA_GP_STATUS 0x68 -+#define LIMA_GP_STATUS_VS_ACTIVE BIT(1) -+#define LIMA_GP_STATUS_BUS_STOPPED BIT(2) -+#define LIMA_GP_STATUS_PLBU_ACTIVE BIT(3) -+#define LIMA_GP_STATUS_BUS_ERROR BIT(6) -+#define LIMA_GP_STATUS_WRITE_BOUND_ERR BIT(8) -+#define LIMA_GP_VERSION 0x6C -+#define LIMA_GP_VSCL_START_ADDR_READ 0x80 -+#define LIMA_GP_PLBCL_START_ADDR_READ 0x84 -+#define LIMA_GP_CONTR_AXI_BUS_ERROR_STAT 0x94 -+ -+#define LIMA_GP_IRQ_MASK_ALL \ -+ ( \ -+ LIMA_GP_IRQ_VS_END_CMD_LST | \ -+ LIMA_GP_IRQ_PLBU_END_CMD_LST | \ -+ LIMA_GP_IRQ_PLBU_OUT_OF_MEM | \ -+ LIMA_GP_IRQ_VS_SEM_IRQ | \ -+ LIMA_GP_IRQ_PLBU_SEM_IRQ | \ -+ LIMA_GP_IRQ_HANG | \ -+ LIMA_GP_IRQ_FORCE_HANG | \ -+ LIMA_GP_IRQ_PERF_CNT_0_LIMIT | \ -+ LIMA_GP_IRQ_PERF_CNT_1_LIMIT | \ -+ LIMA_GP_IRQ_WRITE_BOUND_ERR | \ -+ LIMA_GP_IRQ_SYNC_ERROR | \ -+ LIMA_GP_IRQ_AXI_BUS_ERROR | \ -+ LIMA_GP_IRQ_AXI_BUS_STOPPED | \ -+ LIMA_GP_IRQ_VS_INVALID_CMD | \ -+ LIMA_GP_IRQ_PLB_INVALID_CMD | \ -+ LIMA_GP_IRQ_RESET_COMPLETED | \ -+ LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW | \ -+ LIMA_GP_IRQ_SEMAPHORE_OVERFLOW | \ -+ LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS) -+ -+#define LIMA_GP_IRQ_MASK_ERROR \ -+ ( \ -+ LIMA_GP_IRQ_PLBU_OUT_OF_MEM | \ -+ LIMA_GP_IRQ_FORCE_HANG | \ -+ LIMA_GP_IRQ_WRITE_BOUND_ERR | \ -+ LIMA_GP_IRQ_SYNC_ERROR | \ -+ LIMA_GP_IRQ_AXI_BUS_ERROR | \ -+ LIMA_GP_IRQ_VS_INVALID_CMD | \ -+ LIMA_GP_IRQ_PLB_INVALID_CMD | \ -+ LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW | \ -+ LIMA_GP_IRQ_SEMAPHORE_OVERFLOW | \ -+ LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS) -+ -+#define LIMA_GP_IRQ_MASK_USED \ -+ ( \ -+ LIMA_GP_IRQ_VS_END_CMD_LST | \ -+ LIMA_GP_IRQ_PLBU_END_CMD_LST | \ -+ LIMA_GP_IRQ_MASK_ERROR) -+ -+/* PP regs */ -+#define LIMA_PP_FRAME 0x0000 -+#define LIMA_PP_RSW 0x0004 -+#define LIMA_PP_STACK 0x0030 -+#define LIMA_PP_STACK_SIZE 0x0034 -+#define LIMA_PP_ORIGIN_OFFSET_X 0x0040 -+#define LIMA_PP_WB(i) (0x0100 * (i + 1)) -+#define LIMA_PP_WB_SOURCE_SELECT 0x0000 -+#define LIMA_PP_WB_SOURCE_ADDR 0x0004 -+ -+#define LIMA_PP_VERSION 0x1000 -+#define LIMA_PP_CURRENT_REND_LIST_ADDR 0x1004 -+#define LIMA_PP_STATUS 0x1008 -+#define LIMA_PP_STATUS_RENDERING_ACTIVE BIT(0) -+#define LIMA_PP_STATUS_BUS_STOPPED BIT(4) -+#define LIMA_PP_CTRL 0x100c -+#define LIMA_PP_CTRL_STOP_BUS BIT(0) -+#define LIMA_PP_CTRL_FLUSH_CACHES BIT(3) -+#define LIMA_PP_CTRL_FORCE_RESET BIT(5) -+#define LIMA_PP_CTRL_START_RENDERING BIT(6) -+#define LIMA_PP_CTRL_SOFT_RESET BIT(7) -+#define LIMA_PP_INT_RAWSTAT 0x1020 -+#define LIMA_PP_INT_CLEAR 0x1024 -+#define LIMA_PP_INT_MASK 0x1028 -+#define LIMA_PP_INT_STATUS 0x102c -+#define LIMA_PP_IRQ_END_OF_FRAME BIT(0) -+#define LIMA_PP_IRQ_END_OF_TILE BIT(1) -+#define LIMA_PP_IRQ_HANG BIT(2) -+#define LIMA_PP_IRQ_FORCE_HANG BIT(3) -+#define LIMA_PP_IRQ_BUS_ERROR BIT(4) -+#define LIMA_PP_IRQ_BUS_STOP BIT(5) -+#define LIMA_PP_IRQ_CNT_0_LIMIT BIT(6) -+#define LIMA_PP_IRQ_CNT_1_LIMIT BIT(7) -+#define LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR BIT(8) -+#define LIMA_PP_IRQ_INVALID_PLIST_COMMAND BIT(9) -+#define LIMA_PP_IRQ_CALL_STACK_UNDERFLOW BIT(10) -+#define LIMA_PP_IRQ_CALL_STACK_OVERFLOW BIT(11) -+#define LIMA_PP_IRQ_RESET_COMPLETED BIT(12) -+#define LIMA_PP_WRITE_BOUNDARY_LOW 0x1044 -+#define LIMA_PP_BUS_ERROR_STATUS 0x1050 -+#define LIMA_PP_PERF_CNT_0_ENABLE 0x1080 -+#define LIMA_PP_PERF_CNT_0_SRC 0x1084 -+#define LIMA_PP_PERF_CNT_0_LIMIT 0x1088 -+#define LIMA_PP_PERF_CNT_0_VALUE 0x108c -+#define LIMA_PP_PERF_CNT_1_ENABLE 0x10a0 -+#define LIMA_PP_PERF_CNT_1_SRC 0x10a4 -+#define LIMA_PP_PERF_CNT_1_LIMIT 0x10a8 -+#define LIMA_PP_PERF_CNT_1_VALUE 0x10ac -+#define LIMA_PP_PERFMON_CONTR 0x10b0 -+#define LIMA_PP_PERFMON_BASE 0x10b4 -+ -+#define LIMA_PP_IRQ_MASK_ALL \ -+ ( \ -+ LIMA_PP_IRQ_END_OF_FRAME | \ -+ LIMA_PP_IRQ_END_OF_TILE | \ -+ LIMA_PP_IRQ_HANG | \ -+ LIMA_PP_IRQ_FORCE_HANG | \ -+ LIMA_PP_IRQ_BUS_ERROR | \ -+ LIMA_PP_IRQ_BUS_STOP | \ -+ LIMA_PP_IRQ_CNT_0_LIMIT | \ -+ LIMA_PP_IRQ_CNT_1_LIMIT | \ -+ LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR | \ -+ LIMA_PP_IRQ_INVALID_PLIST_COMMAND | \ -+ LIMA_PP_IRQ_CALL_STACK_UNDERFLOW | \ -+ LIMA_PP_IRQ_CALL_STACK_OVERFLOW | \ -+ LIMA_PP_IRQ_RESET_COMPLETED) -+ -+#define LIMA_PP_IRQ_MASK_ERROR \ -+ ( \ -+ LIMA_PP_IRQ_FORCE_HANG | \ -+ LIMA_PP_IRQ_BUS_ERROR | \ -+ LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR | \ -+ LIMA_PP_IRQ_INVALID_PLIST_COMMAND | \ -+ LIMA_PP_IRQ_CALL_STACK_UNDERFLOW | \ -+ LIMA_PP_IRQ_CALL_STACK_OVERFLOW) -+ -+#define LIMA_PP_IRQ_MASK_USED \ -+ ( \ -+ LIMA_PP_IRQ_END_OF_FRAME | \ -+ LIMA_PP_IRQ_MASK_ERROR) -+ -+/* MMU regs */ -+#define LIMA_MMU_DTE_ADDR 0x0000 -+#define LIMA_MMU_STATUS 0x0004 -+#define LIMA_MMU_STATUS_PAGING_ENABLED BIT(0) -+#define LIMA_MMU_STATUS_PAGE_FAULT_ACTIVE BIT(1) -+#define LIMA_MMU_STATUS_STALL_ACTIVE BIT(2) -+#define LIMA_MMU_STATUS_IDLE BIT(3) -+#define LIMA_MMU_STATUS_REPLAY_BUFFER_EMPTY BIT(4) -+#define LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE BIT(5) -+#define LIMA_MMU_STATUS_BUS_ID(x) ((x >> 6) & 0x1F) -+#define LIMA_MMU_COMMAND 0x0008 -+#define LIMA_MMU_COMMAND_ENABLE_PAGING 0x00 -+#define LIMA_MMU_COMMAND_DISABLE_PAGING 0x01 -+#define LIMA_MMU_COMMAND_ENABLE_STALL 0x02 -+#define LIMA_MMU_COMMAND_DISABLE_STALL 0x03 -+#define LIMA_MMU_COMMAND_ZAP_CACHE 0x04 -+#define LIMA_MMU_COMMAND_PAGE_FAULT_DONE 0x05 -+#define LIMA_MMU_COMMAND_HARD_RESET 0x06 -+#define LIMA_MMU_PAGE_FAULT_ADDR 0x000C -+#define LIMA_MMU_ZAP_ONE_LINE 0x0010 -+#define LIMA_MMU_INT_RAWSTAT 0x0014 -+#define LIMA_MMU_INT_CLEAR 0x0018 -+#define LIMA_MMU_INT_MASK 0x001C -+#define LIMA_MMU_INT_PAGE_FAULT BIT(0) -+#define LIMA_MMU_INT_READ_BUS_ERROR BIT(1) -+#define LIMA_MMU_INT_STATUS 0x0020 -+ -+#define LIMA_VM_FLAG_PRESENT BIT(0) -+#define LIMA_VM_FLAG_READ_PERMISSION BIT(1) -+#define LIMA_VM_FLAG_WRITE_PERMISSION BIT(2) -+#define LIMA_VM_FLAG_OVERRIDE_CACHE BIT(3) -+#define LIMA_VM_FLAG_WRITE_CACHEABLE BIT(4) -+#define LIMA_VM_FLAG_WRITE_ALLOCATE BIT(5) -+#define LIMA_VM_FLAG_WRITE_BUFFERABLE BIT(6) -+#define LIMA_VM_FLAG_READ_CACHEABLE BIT(7) -+#define LIMA_VM_FLAG_READ_ALLOCATE BIT(8) -+#define LIMA_VM_FLAG_MASK 0x1FF -+ -+#define LIMA_VM_FLAGS_CACHE ( \ -+ LIMA_VM_FLAG_PRESENT | \ -+ LIMA_VM_FLAG_READ_PERMISSION | \ -+ LIMA_VM_FLAG_WRITE_PERMISSION | \ -+ LIMA_VM_FLAG_OVERRIDE_CACHE | \ -+ LIMA_VM_FLAG_WRITE_CACHEABLE | \ -+ LIMA_VM_FLAG_WRITE_BUFFERABLE | \ -+ LIMA_VM_FLAG_READ_CACHEABLE | \ -+ LIMA_VM_FLAG_READ_ALLOCATE) -+ -+#define LIMA_VM_FLAGS_UNCACHE ( \ -+ LIMA_VM_FLAG_PRESENT | \ -+ LIMA_VM_FLAG_READ_PERMISSION | \ -+ LIMA_VM_FLAG_WRITE_PERMISSION) -+ -+/* DLBU regs */ -+#define LIMA_DLBU_MASTER_TLLIST_PHYS_ADDR 0x0000 -+#define LIMA_DLBU_MASTER_TLLIST_VADDR 0x0004 -+#define LIMA_DLBU_TLLIST_VBASEADDR 0x0008 -+#define LIMA_DLBU_FB_DIM 0x000C -+#define LIMA_DLBU_TLLIST_CONF 0x0010 -+#define LIMA_DLBU_START_TILE_POS 0x0014 -+#define LIMA_DLBU_PP_ENABLE_MASK 0x0018 -+ -+/* BCAST regs */ -+#define LIMA_BCAST_BROADCAST_MASK 0x0 -+#define LIMA_BCAST_INTERRUPT_MASK 0x4 -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -new file mode 100644 -index 0000000000000..97bd9c1deb871 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -0,0 +1,404 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+ -+#include "lima_drv.h" -+#include "lima_sched.h" -+#include "lima_vm.h" -+#include "lima_mmu.h" -+#include "lima_l2_cache.h" -+#include "lima_object.h" -+ -+struct lima_fence { -+ struct dma_fence base; -+ struct lima_sched_pipe *pipe; -+}; -+ -+static struct kmem_cache *lima_fence_slab; -+static int lima_fence_slab_refcnt; -+ -+int lima_sched_slab_init(void) -+{ -+ if (!lima_fence_slab) { -+ lima_fence_slab = kmem_cache_create( -+ "lima_fence", sizeof(struct lima_fence), 0, -+ SLAB_HWCACHE_ALIGN, NULL); -+ if (!lima_fence_slab) -+ return -ENOMEM; -+ } -+ -+ lima_fence_slab_refcnt++; -+ return 0; -+} -+ -+void lima_sched_slab_fini(void) -+{ -+ if (!--lima_fence_slab_refcnt) { -+ kmem_cache_destroy(lima_fence_slab); -+ lima_fence_slab = NULL; -+ } -+} -+ -+static inline struct lima_fence *to_lima_fence(struct dma_fence *fence) -+{ -+ return container_of(fence, struct lima_fence, base); -+} -+ -+static const char *lima_fence_get_driver_name(struct dma_fence *fence) -+{ -+ return "lima"; -+} -+ -+static const char *lima_fence_get_timeline_name(struct dma_fence *fence) -+{ -+ struct lima_fence *f = to_lima_fence(fence); -+ -+ return f->pipe->base.name; -+} -+ -+static void lima_fence_release_rcu(struct rcu_head *rcu) -+{ -+ struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); -+ struct lima_fence *fence = to_lima_fence(f); -+ -+ kmem_cache_free(lima_fence_slab, fence); -+} -+ -+static void lima_fence_release(struct dma_fence *fence) -+{ -+ struct lima_fence *f = to_lima_fence(fence); -+ -+ call_rcu(&f->base.rcu, lima_fence_release_rcu); -+} -+ -+static const struct dma_fence_ops lima_fence_ops = { -+ .get_driver_name = lima_fence_get_driver_name, -+ .get_timeline_name = lima_fence_get_timeline_name, -+ .release = lima_fence_release, -+}; -+ -+static struct lima_fence *lima_fence_create(struct lima_sched_pipe *pipe) -+{ -+ struct lima_fence *fence; -+ -+ fence = kmem_cache_zalloc(lima_fence_slab, GFP_KERNEL); -+ if (!fence) -+ return NULL; -+ -+ fence->pipe = pipe; -+ dma_fence_init(&fence->base, &lima_fence_ops, &pipe->fence_lock, -+ pipe->fence_context, ++pipe->fence_seqno); -+ -+ return fence; -+} -+ -+static inline struct lima_sched_task *to_lima_task(struct drm_sched_job *job) -+{ -+ return container_of(job, struct lima_sched_task, base); -+} -+ -+static inline struct lima_sched_pipe *to_lima_pipe(struct drm_gpu_scheduler *sched) -+{ -+ return container_of(sched, struct lima_sched_pipe, base); -+} -+ -+int lima_sched_task_init(struct lima_sched_task *task, -+ struct lima_sched_context *context, -+ struct lima_bo **bos, int num_bos, -+ struct lima_vm *vm) -+{ -+ int err, i; -+ -+ task->bos = kmemdup(bos, sizeof(*bos) * num_bos, GFP_KERNEL); -+ if (!task->bos) -+ return -ENOMEM; -+ -+ for (i = 0; i < num_bos; i++) -+ drm_gem_object_get(&bos[i]->gem); -+ -+ err = drm_sched_job_init(&task->base, &context->base, vm); -+ if (err) { -+ kfree(task->bos); -+ return err; -+ } -+ -+ task->num_bos = num_bos; -+ task->vm = lima_vm_get(vm); -+ return 0; -+} -+ -+void lima_sched_task_fini(struct lima_sched_task *task) -+{ -+ int i; -+ -+ drm_sched_job_cleanup(&task->base); -+ -+ for (i = 0; i < task->num_dep; i++) -+ dma_fence_put(task->dep[i]); -+ -+ kfree(task->dep); -+ -+ if (task->bos) { -+ for (i = 0; i < task->num_bos; i++) -+ drm_gem_object_put_unlocked(&task->bos[i]->gem); -+ kfree(task->bos); -+ } -+ -+ lima_vm_put(task->vm); -+} -+ -+int lima_sched_task_add_dep(struct lima_sched_task *task, struct dma_fence *fence) -+{ -+ int i, new_dep = 4; -+ -+ /* same context's fence is definitly earlier then this task */ -+ if (fence->context == task->base.s_fence->finished.context) { -+ dma_fence_put(fence); -+ return 0; -+ } -+ -+ if (task->dep && task->num_dep == task->max_dep) -+ new_dep = task->max_dep * 2; -+ -+ if (task->max_dep < new_dep) { -+ void *dep = krealloc(task->dep, sizeof(*task->dep) * new_dep, GFP_KERNEL); -+ -+ if (!dep) -+ return -ENOMEM; -+ -+ task->max_dep = new_dep; -+ task->dep = dep; -+ } -+ -+ for (i = 0; i < task->num_dep; i++) { -+ if (task->dep[i]->context == fence->context && -+ dma_fence_is_later(fence, task->dep[i])) { -+ dma_fence_put(task->dep[i]); -+ task->dep[i] = fence; -+ return 0; -+ } -+ } -+ -+ task->dep[task->num_dep++] = fence; -+ return 0; -+} -+ -+int lima_sched_context_init(struct lima_sched_pipe *pipe, -+ struct lima_sched_context *context, -+ atomic_t *guilty) -+{ -+ struct drm_sched_rq *rq = pipe->base.sched_rq + DRM_SCHED_PRIORITY_NORMAL; -+ -+ return drm_sched_entity_init(&context->base, &rq, 1, guilty); -+} -+ -+void lima_sched_context_fini(struct lima_sched_pipe *pipe, -+ struct lima_sched_context *context) -+{ -+ drm_sched_entity_fini(&context->base); -+} -+ -+struct dma_fence *lima_sched_context_queue_task(struct lima_sched_context *context, -+ struct lima_sched_task *task) -+{ -+ struct dma_fence *fence = dma_fence_get(&task->base.s_fence->finished); -+ -+ drm_sched_entity_push_job(&task->base, &context->base); -+ return fence; -+} -+ -+static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job, -+ struct drm_sched_entity *entity) -+{ -+ struct lima_sched_task *task = to_lima_task(job); -+ int i; -+ -+ for (i = 0; i < task->num_dep; i++) { -+ struct dma_fence *fence = task->dep[i]; -+ -+ if (!task->dep[i]) -+ continue; -+ -+ task->dep[i] = NULL; -+ -+ if (!dma_fence_is_signaled(fence)) -+ return fence; -+ -+ dma_fence_put(fence); -+ } -+ -+ return NULL; -+} -+ -+static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) -+{ -+ struct lima_sched_task *task = to_lima_task(job); -+ struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); -+ struct lima_fence *fence; -+ struct dma_fence *ret; -+ struct lima_vm *vm = NULL, *last_vm = NULL; -+ int i; -+ -+ /* after GPU reset */ -+ if (job->s_fence->finished.error < 0) -+ return NULL; -+ -+ fence = lima_fence_create(pipe); -+ if (!fence) -+ return NULL; -+ task->fence = &fence->base; -+ -+ /* for caller usage of the fence, otherwise irq handler -+ * may consume the fence before caller use it -+ */ -+ ret = dma_fence_get(task->fence); -+ -+ pipe->current_task = task; -+ -+ /* this is needed for MMU to work correctly, otherwise GP/PP -+ * will hang or page fault for unknown reason after running for -+ * a while. -+ * -+ * Need to investigate: -+ * 1. is it related to TLB -+ * 2. how much performance will be affected by L2 cache flush -+ * 3. can we reduce the calling of this function because all -+ * GP/PP use the same L2 cache on mali400 -+ * -+ * TODO: -+ * 1. move this to task fini to save some wait time? -+ * 2. when GP/PP use different l2 cache, need PP wait GP l2 -+ * cache flush? -+ */ -+ for (i = 0; i < pipe->num_l2_cache; i++) -+ lima_l2_cache_flush(pipe->l2_cache[i]); -+ -+ if (task->vm != pipe->current_vm) { -+ vm = lima_vm_get(task->vm); -+ last_vm = pipe->current_vm; -+ pipe->current_vm = task->vm; -+ } -+ -+ if (pipe->bcast_mmu) -+ lima_mmu_switch_vm(pipe->bcast_mmu, vm); -+ else { -+ for (i = 0; i < pipe->num_mmu; i++) -+ lima_mmu_switch_vm(pipe->mmu[i], vm); -+ } -+ -+ if (last_vm) -+ lima_vm_put(last_vm); -+ -+ pipe->error = false; -+ pipe->task_run(pipe, task); -+ -+ return task->fence; -+} -+ -+static void lima_sched_handle_error_task(struct lima_sched_pipe *pipe, -+ struct lima_sched_task *task) -+{ -+ drm_sched_stop(&pipe->base); -+ -+ if (task) -+ drm_sched_increase_karma(&task->base); -+ -+ pipe->task_error(pipe); -+ -+ if (pipe->bcast_mmu) -+ lima_mmu_page_fault_resume(pipe->bcast_mmu); -+ else { -+ int i; -+ -+ for (i = 0; i < pipe->num_mmu; i++) -+ lima_mmu_page_fault_resume(pipe->mmu[i]); -+ } -+ -+ if (pipe->current_vm) -+ lima_vm_put(pipe->current_vm); -+ -+ pipe->current_vm = NULL; -+ pipe->current_task = NULL; -+ -+ drm_sched_resubmit_jobs(&pipe->base); -+ drm_sched_start(&pipe->base, true); -+} -+ -+static void lima_sched_timedout_job(struct drm_sched_job *job) -+{ -+ struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); -+ struct lima_sched_task *task = to_lima_task(job); -+ -+ DRM_ERROR("lima job timeout\n"); -+ -+ lima_sched_handle_error_task(pipe, task); -+} -+ -+static void lima_sched_free_job(struct drm_sched_job *job) -+{ -+ struct lima_sched_task *task = to_lima_task(job); -+ struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); -+ struct lima_vm *vm = task->vm; -+ struct lima_bo **bos = task->bos; -+ int i; -+ -+ dma_fence_put(task->fence); -+ -+ for (i = 0; i < task->num_bos; i++) -+ lima_vm_bo_del(vm, bos[i]); -+ -+ lima_sched_task_fini(task); -+ kmem_cache_free(pipe->task_slab, task); -+} -+ -+const struct drm_sched_backend_ops lima_sched_ops = { -+ .dependency = lima_sched_dependency, -+ .run_job = lima_sched_run_job, -+ .timedout_job = lima_sched_timedout_job, -+ .free_job = lima_sched_free_job, -+}; -+ -+static void lima_sched_error_work(struct work_struct *work) -+{ -+ struct lima_sched_pipe *pipe = -+ container_of(work, struct lima_sched_pipe, error_work); -+ struct lima_sched_task *task = pipe->current_task; -+ -+ lima_sched_handle_error_task(pipe, task); -+} -+ -+int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) -+{ -+ long timeout; -+ -+ if (lima_sched_timeout_ms <= 0) -+ timeout = MAX_SCHEDULE_TIMEOUT; -+ else -+ timeout = msecs_to_jiffies(lima_sched_timeout_ms); -+ -+ pipe->fence_context = dma_fence_context_alloc(1); -+ spin_lock_init(&pipe->fence_lock); -+ -+ INIT_WORK(&pipe->error_work, lima_sched_error_work); -+ -+ return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, timeout, name); -+} -+ -+void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) -+{ -+ drm_sched_fini(&pipe->base); -+} -+ -+void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) -+{ -+ if (pipe->error) -+ schedule_work(&pipe->error_work); -+ else { -+ struct lima_sched_task *task = pipe->current_task; -+ -+ pipe->task_fini(pipe); -+ dma_fence_signal(task->fence); -+ } -+} -diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h -new file mode 100644 -index 0000000000000..b017cfa7e3276 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_sched.h -@@ -0,0 +1,104 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_SCHED_H__ -+#define __LIMA_SCHED_H__ -+ -+#include -+ -+struct lima_vm; -+ -+struct lima_sched_task { -+ struct drm_sched_job base; -+ -+ struct lima_vm *vm; -+ void *frame; -+ -+ struct dma_fence **dep; -+ int num_dep; -+ int max_dep; -+ -+ struct lima_bo **bos; -+ int num_bos; -+ -+ /* pipe fence */ -+ struct dma_fence *fence; -+}; -+ -+struct lima_sched_context { -+ struct drm_sched_entity base; -+}; -+ -+#define LIMA_SCHED_PIPE_MAX_MMU 8 -+#define LIMA_SCHED_PIPE_MAX_L2_CACHE 2 -+#define LIMA_SCHED_PIPE_MAX_PROCESSOR 8 -+ -+struct lima_ip; -+ -+struct lima_sched_pipe { -+ struct drm_gpu_scheduler base; -+ -+ u64 fence_context; -+ u32 fence_seqno; -+ spinlock_t fence_lock; -+ -+ struct lima_sched_task *current_task; -+ struct lima_vm *current_vm; -+ -+ struct lima_ip *mmu[LIMA_SCHED_PIPE_MAX_MMU]; -+ int num_mmu; -+ -+ struct lima_ip *l2_cache[LIMA_SCHED_PIPE_MAX_L2_CACHE]; -+ int num_l2_cache; -+ -+ struct lima_ip *processor[LIMA_SCHED_PIPE_MAX_PROCESSOR]; -+ int num_processor; -+ -+ struct lima_ip *bcast_processor; -+ struct lima_ip *bcast_mmu; -+ -+ u32 done; -+ bool error; -+ atomic_t task; -+ -+ int frame_size; -+ struct kmem_cache *task_slab; -+ -+ int (*task_validate)(struct lima_sched_pipe *pipe, struct lima_sched_task *task); -+ void (*task_run)(struct lima_sched_pipe *pipe, struct lima_sched_task *task); -+ void (*task_fini)(struct lima_sched_pipe *pipe); -+ void (*task_error)(struct lima_sched_pipe *pipe); -+ void (*task_mmu_error)(struct lima_sched_pipe *pipe); -+ -+ struct work_struct error_work; -+}; -+ -+int lima_sched_task_init(struct lima_sched_task *task, -+ struct lima_sched_context *context, -+ struct lima_bo **bos, int num_bos, -+ struct lima_vm *vm); -+void lima_sched_task_fini(struct lima_sched_task *task); -+int lima_sched_task_add_dep(struct lima_sched_task *task, struct dma_fence *fence); -+ -+int lima_sched_context_init(struct lima_sched_pipe *pipe, -+ struct lima_sched_context *context, -+ atomic_t *guilty); -+void lima_sched_context_fini(struct lima_sched_pipe *pipe, -+ struct lima_sched_context *context); -+struct dma_fence *lima_sched_context_queue_task(struct lima_sched_context *context, -+ struct lima_sched_task *task); -+ -+int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name); -+void lima_sched_pipe_fini(struct lima_sched_pipe *pipe); -+void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe); -+ -+static inline void lima_sched_pipe_mmu_error(struct lima_sched_pipe *pipe) -+{ -+ pipe->error = true; -+ pipe->task_mmu_error(pipe); -+} -+ -+int lima_sched_slab_init(void); -+void lima_sched_slab_fini(void); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c -new file mode 100644 -index 0000000000000..19e88ca165270 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_vm.c -@@ -0,0 +1,282 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_vm.h" -+#include "lima_object.h" -+#include "lima_regs.h" -+ -+struct lima_bo_va { -+ struct list_head list; -+ unsigned int ref_count; -+ -+ struct drm_mm_node node; -+ -+ struct lima_vm *vm; -+}; -+ -+#define LIMA_VM_PD_SHIFT 22 -+#define LIMA_VM_PT_SHIFT 12 -+#define LIMA_VM_PB_SHIFT (LIMA_VM_PD_SHIFT + LIMA_VM_NUM_PT_PER_BT_SHIFT) -+#define LIMA_VM_BT_SHIFT LIMA_VM_PT_SHIFT -+ -+#define LIMA_VM_PT_MASK ((1 << LIMA_VM_PD_SHIFT) - 1) -+#define LIMA_VM_BT_MASK ((1 << LIMA_VM_PB_SHIFT) - 1) -+ -+#define LIMA_PDE(va) (va >> LIMA_VM_PD_SHIFT) -+#define LIMA_PTE(va) ((va & LIMA_VM_PT_MASK) >> LIMA_VM_PT_SHIFT) -+#define LIMA_PBE(va) (va >> LIMA_VM_PB_SHIFT) -+#define LIMA_BTE(va) ((va & LIMA_VM_BT_MASK) >> LIMA_VM_BT_SHIFT) -+ -+ -+static void lima_vm_unmap_page_table(struct lima_vm *vm, u32 start, u32 end) -+{ -+ u32 addr; -+ -+ for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) { -+ u32 pbe = LIMA_PBE(addr); -+ u32 bte = LIMA_BTE(addr); -+ -+ vm->bts[pbe].cpu[bte] = 0; -+ } -+} -+ -+static int lima_vm_map_page_table(struct lima_vm *vm, dma_addr_t *dma, -+ u32 start, u32 end) -+{ -+ u64 addr; -+ int i = 0; -+ -+ for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) { -+ u32 pbe = LIMA_PBE(addr); -+ u32 bte = LIMA_BTE(addr); -+ -+ if (!vm->bts[pbe].cpu) { -+ dma_addr_t pts; -+ u32 *pd; -+ int j; -+ -+ vm->bts[pbe].cpu = dma_alloc_wc( -+ vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, -+ &vm->bts[pbe].dma, GFP_KERNEL | __GFP_ZERO); -+ if (!vm->bts[pbe].cpu) { -+ if (addr != start) -+ lima_vm_unmap_page_table(vm, start, addr - 1); -+ return -ENOMEM; -+ } -+ -+ pts = vm->bts[pbe].dma; -+ pd = vm->pd.cpu + (pbe << LIMA_VM_NUM_PT_PER_BT_SHIFT); -+ for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { -+ pd[j] = pts | LIMA_VM_FLAG_PRESENT; -+ pts += LIMA_PAGE_SIZE; -+ } -+ } -+ -+ vm->bts[pbe].cpu[bte] = dma[i++] | LIMA_VM_FLAGS_CACHE; -+ } -+ -+ return 0; -+} -+ -+static struct lima_bo_va * -+lima_vm_bo_find(struct lima_vm *vm, struct lima_bo *bo) -+{ -+ struct lima_bo_va *bo_va, *ret = NULL; -+ -+ list_for_each_entry(bo_va, &bo->va, list) { -+ if (bo_va->vm == vm) { -+ ret = bo_va; -+ break; -+ } -+ } -+ -+ return ret; -+} -+ -+int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create) -+{ -+ struct lima_bo_va *bo_va; -+ int err; -+ -+ mutex_lock(&bo->lock); -+ -+ bo_va = lima_vm_bo_find(vm, bo); -+ if (bo_va) { -+ bo_va->ref_count++; -+ mutex_unlock(&bo->lock); -+ return 0; -+ } -+ -+ /* should not create new bo_va if not asked by caller */ -+ if (!create) { -+ mutex_unlock(&bo->lock); -+ return -ENOENT; -+ } -+ -+ bo_va = kzalloc(sizeof(*bo_va), GFP_KERNEL); -+ if (!bo_va) { -+ err = -ENOMEM; -+ goto err_out0; -+ } -+ -+ bo_va->vm = vm; -+ bo_va->ref_count = 1; -+ -+ mutex_lock(&vm->lock); -+ -+ err = drm_mm_insert_node(&vm->mm, &bo_va->node, bo->gem.size); -+ if (err) -+ goto err_out1; -+ -+ err = lima_vm_map_page_table(vm, bo->pages_dma_addr, bo_va->node.start, -+ bo_va->node.start + bo_va->node.size - 1); -+ if (err) -+ goto err_out2; -+ -+ mutex_unlock(&vm->lock); -+ -+ list_add_tail(&bo_va->list, &bo->va); -+ -+ mutex_unlock(&bo->lock); -+ return 0; -+ -+err_out2: -+ drm_mm_remove_node(&bo_va->node); -+err_out1: -+ mutex_unlock(&vm->lock); -+ kfree(bo_va); -+err_out0: -+ mutex_unlock(&bo->lock); -+ return err; -+} -+ -+void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo) -+{ -+ struct lima_bo_va *bo_va; -+ -+ mutex_lock(&bo->lock); -+ -+ bo_va = lima_vm_bo_find(vm, bo); -+ if (--bo_va->ref_count > 0) { -+ mutex_unlock(&bo->lock); -+ return; -+ } -+ -+ mutex_lock(&vm->lock); -+ -+ lima_vm_unmap_page_table(vm, bo_va->node.start, -+ bo_va->node.start + bo_va->node.size - 1); -+ -+ drm_mm_remove_node(&bo_va->node); -+ -+ mutex_unlock(&vm->lock); -+ -+ list_del(&bo_va->list); -+ -+ mutex_unlock(&bo->lock); -+ -+ kfree(bo_va); -+} -+ -+u32 lima_vm_get_va(struct lima_vm *vm, struct lima_bo *bo) -+{ -+ struct lima_bo_va *bo_va; -+ u32 ret; -+ -+ mutex_lock(&bo->lock); -+ -+ bo_va = lima_vm_bo_find(vm, bo); -+ ret = bo_va->node.start; -+ -+ mutex_unlock(&bo->lock); -+ -+ return ret; -+} -+ -+struct lima_vm *lima_vm_create(struct lima_device *dev) -+{ -+ struct lima_vm *vm; -+ -+ vm = kzalloc(sizeof(*vm), GFP_KERNEL); -+ if (!vm) -+ return NULL; -+ -+ vm->dev = dev; -+ mutex_init(&vm->lock); -+ kref_init(&vm->refcount); -+ -+ vm->pd.cpu = dma_alloc_wc(dev->dev, LIMA_PAGE_SIZE, &vm->pd.dma, -+ GFP_KERNEL | __GFP_ZERO); -+ if (!vm->pd.cpu) -+ goto err_out0; -+ -+ if (dev->dlbu_cpu) { -+ int err = lima_vm_map_page_table( -+ vm, &dev->dlbu_dma, LIMA_VA_RESERVE_DLBU, -+ LIMA_VA_RESERVE_DLBU + LIMA_PAGE_SIZE - 1); -+ if (err) -+ goto err_out1; -+ } -+ -+ drm_mm_init(&vm->mm, dev->va_start, dev->va_end - dev->va_start); -+ -+ return vm; -+ -+err_out1: -+ dma_free_wc(dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma); -+err_out0: -+ kfree(vm); -+ return NULL; -+} -+ -+void lima_vm_release(struct kref *kref) -+{ -+ struct lima_vm *vm = container_of(kref, struct lima_vm, refcount); -+ int i; -+ -+ drm_mm_takedown(&vm->mm); -+ -+ for (i = 0; i < LIMA_VM_NUM_BT; i++) { -+ if (vm->bts[i].cpu) -+ dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, -+ vm->bts[i].cpu, vm->bts[i].dma); -+ } -+ -+ if (vm->pd.cpu) -+ dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma); -+ -+ kfree(vm); -+} -+ -+void lima_vm_print(struct lima_vm *vm) -+{ -+ int i, j, k; -+ u32 *pd, *pt; -+ -+ if (!vm->pd.cpu) -+ return; -+ -+ pd = vm->pd.cpu; -+ for (i = 0; i < LIMA_VM_NUM_BT; i++) { -+ if (!vm->bts[i].cpu) -+ continue; -+ -+ pt = vm->bts[i].cpu; -+ for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { -+ int idx = (i << LIMA_VM_NUM_PT_PER_BT_SHIFT) + j; -+ -+ printk(KERN_INFO "lima vm pd %03x:%08x\n", idx, pd[idx]); -+ -+ for (k = 0; k < LIMA_PAGE_ENT_NUM; k++) { -+ u32 pte = *pt++; -+ -+ if (pte) -+ printk(KERN_INFO " pt %03x:%08x\n", k, pte); -+ } -+ } -+ } -+} -diff --git a/drivers/gpu/drm/lima/lima_vm.h b/drivers/gpu/drm/lima/lima_vm.h -new file mode 100644 -index 0000000000000..caee2f8a29b40 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_vm.h -@@ -0,0 +1,62 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2017-2019 Qiang Yu */ -+ -+#ifndef __LIMA_VM_H__ -+#define __LIMA_VM_H__ -+ -+#include -+#include -+ -+#define LIMA_PAGE_SIZE 4096 -+#define LIMA_PAGE_MASK (LIMA_PAGE_SIZE - 1) -+#define LIMA_PAGE_ENT_NUM (LIMA_PAGE_SIZE / sizeof(u32)) -+ -+#define LIMA_VM_NUM_PT_PER_BT_SHIFT 3 -+#define LIMA_VM_NUM_PT_PER_BT (1 << LIMA_VM_NUM_PT_PER_BT_SHIFT) -+#define LIMA_VM_NUM_BT (LIMA_PAGE_ENT_NUM >> LIMA_VM_NUM_PT_PER_BT_SHIFT) -+ -+#define LIMA_VA_RESERVE_START 0xFFF00000 -+#define LIMA_VA_RESERVE_DLBU LIMA_VA_RESERVE_START -+#define LIMA_VA_RESERVE_END 0x100000000 -+ -+struct lima_device; -+ -+struct lima_vm_page { -+ u32 *cpu; -+ dma_addr_t dma; -+}; -+ -+struct lima_vm { -+ struct mutex lock; -+ struct kref refcount; -+ -+ struct drm_mm mm; -+ -+ struct lima_device *dev; -+ -+ struct lima_vm_page pd; -+ struct lima_vm_page bts[LIMA_VM_NUM_BT]; -+}; -+ -+int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create); -+void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo); -+ -+u32 lima_vm_get_va(struct lima_vm *vm, struct lima_bo *bo); -+ -+struct lima_vm *lima_vm_create(struct lima_device *dev); -+void lima_vm_release(struct kref *kref); -+ -+static inline struct lima_vm *lima_vm_get(struct lima_vm *vm) -+{ -+ kref_get(&vm->refcount); -+ return vm; -+} -+ -+static inline void lima_vm_put(struct lima_vm *vm) -+{ -+ kref_put(&vm->refcount, lima_vm_release); -+} -+ -+void lima_vm_print(struct lima_vm *vm); -+ -+#endif -diff --git a/include/uapi/drm/lima_drm.h b/include/uapi/drm/lima_drm.h -new file mode 100644 -index 0000000000000..95a00fb867e62 ---- /dev/null -+++ b/include/uapi/drm/lima_drm.h -@@ -0,0 +1,169 @@ -+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */ -+/* Copyright 2017-2018 Qiang Yu */ -+ -+#ifndef __LIMA_DRM_H__ -+#define __LIMA_DRM_H__ -+ -+#include "drm.h" -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+enum drm_lima_param_gpu_id { -+ DRM_LIMA_PARAM_GPU_ID_UNKNOWN, -+ DRM_LIMA_PARAM_GPU_ID_MALI400, -+ DRM_LIMA_PARAM_GPU_ID_MALI450, -+}; -+ -+enum drm_lima_param { -+ DRM_LIMA_PARAM_GPU_ID, -+ DRM_LIMA_PARAM_NUM_PP, -+ DRM_LIMA_PARAM_GP_VERSION, -+ DRM_LIMA_PARAM_PP_VERSION, -+}; -+ -+/** -+ * get various information of the GPU -+ */ -+struct drm_lima_get_param { -+ __u32 param; /* in, value in enum drm_lima_param */ -+ __u32 pad; /* pad, must be zero */ -+ __u64 value; /* out, parameter value */ -+}; -+ -+/** -+ * create a buffer for used by GPU -+ */ -+struct drm_lima_gem_create { -+ __u32 size; /* in, buffer size */ -+ __u32 flags; /* in, currently no flags, must be zero */ -+ __u32 handle; /* out, GEM buffer handle */ -+ __u32 pad; /* pad, must be zero */ -+}; -+ -+/** -+ * get information of a buffer -+ */ -+struct drm_lima_gem_info { -+ __u32 handle; /* in, GEM buffer handle */ -+ __u32 va; /* out, virtual address mapped into GPU MMU */ -+ __u64 offset; /* out, used to mmap this buffer to CPU */ -+}; -+ -+#define LIMA_SUBMIT_BO_READ 0x01 -+#define LIMA_SUBMIT_BO_WRITE 0x02 -+ -+/* buffer information used by one task */ -+struct drm_lima_gem_submit_bo { -+ __u32 handle; /* in, GEM buffer handle */ -+ __u32 flags; /* in, buffer read/write by GPU */ -+}; -+ -+#define LIMA_GP_FRAME_REG_NUM 6 -+ -+/* frame used to setup GP for each task */ -+struct drm_lima_gp_frame { -+ __u32 frame[LIMA_GP_FRAME_REG_NUM]; -+}; -+ -+#define LIMA_PP_FRAME_REG_NUM 23 -+#define LIMA_PP_WB_REG_NUM 12 -+ -+/* frame used to setup mali400 GPU PP for each task */ -+struct drm_lima_m400_pp_frame { -+ __u32 frame[LIMA_PP_FRAME_REG_NUM]; -+ __u32 num_pp; -+ __u32 wb[3 * LIMA_PP_WB_REG_NUM]; -+ __u32 plbu_array_address[4]; -+ __u32 fragment_stack_address[4]; -+}; -+ -+/* frame used to setup mali450 GPU PP for each task */ -+struct drm_lima_m450_pp_frame { -+ __u32 frame[LIMA_PP_FRAME_REG_NUM]; -+ __u32 num_pp; -+ __u32 wb[3 * LIMA_PP_WB_REG_NUM]; -+ __u32 use_dlbu; -+ __u32 _pad; -+ union { -+ __u32 plbu_array_address[8]; -+ __u32 dlbu_regs[4]; -+ }; -+ __u32 fragment_stack_address[8]; -+}; -+ -+#define LIMA_PIPE_GP 0x00 -+#define LIMA_PIPE_PP 0x01 -+ -+#define LIMA_SUBMIT_FLAG_EXPLICIT_FENCE (1 << 0) -+ -+/** -+ * submit a task to GPU -+ * -+ * User can always merge multi sync_file and drm_syncobj -+ * into one drm_syncobj as in_sync[0], but we reserve -+ * in_sync[1] for another task's out_sync to avoid the -+ * export/import/merge pass when explicit sync. -+ */ -+struct drm_lima_gem_submit { -+ __u32 ctx; /* in, context handle task is submitted to */ -+ __u32 pipe; /* in, which pipe to use, GP/PP */ -+ __u32 nr_bos; /* in, array length of bos field */ -+ __u32 frame_size; /* in, size of frame field */ -+ __u64 bos; /* in, array of drm_lima_gem_submit_bo */ -+ __u64 frame; /* in, GP/PP frame */ -+ __u32 flags; /* in, submit flags */ -+ __u32 out_sync; /* in, drm_syncobj handle used to wait task finish after submission */ -+ __u32 in_sync[2]; /* in, drm_syncobj handle used to wait before start this task */ -+}; -+ -+#define LIMA_GEM_WAIT_READ 0x01 -+#define LIMA_GEM_WAIT_WRITE 0x02 -+ -+/** -+ * wait pending GPU task finish of a buffer -+ */ -+struct drm_lima_gem_wait { -+ __u32 handle; /* in, GEM buffer handle */ -+ __u32 op; /* in, CPU want to read/write this buffer */ -+ __s64 timeout_ns; /* in, wait timeout in absulute time */ -+}; -+ -+/** -+ * create a context -+ */ -+struct drm_lima_ctx_create { -+ __u32 id; /* out, context handle */ -+ __u32 _pad; /* pad, must be zero */ -+}; -+ -+/** -+ * free a context -+ */ -+struct drm_lima_ctx_free { -+ __u32 id; /* in, context handle */ -+ __u32 _pad; /* pad, must be zero */ -+}; -+ -+#define DRM_LIMA_GET_PARAM 0x00 -+#define DRM_LIMA_GEM_CREATE 0x01 -+#define DRM_LIMA_GEM_INFO 0x02 -+#define DRM_LIMA_GEM_SUBMIT 0x03 -+#define DRM_LIMA_GEM_WAIT 0x04 -+#define DRM_LIMA_CTX_CREATE 0x05 -+#define DRM_LIMA_CTX_FREE 0x06 -+ -+#define DRM_IOCTL_LIMA_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GET_PARAM, struct drm_lima_get_param) -+#define DRM_IOCTL_LIMA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GEM_CREATE, struct drm_lima_gem_create) -+#define DRM_IOCTL_LIMA_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GEM_INFO, struct drm_lima_gem_info) -+#define DRM_IOCTL_LIMA_GEM_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_GEM_SUBMIT, struct drm_lima_gem_submit) -+#define DRM_IOCTL_LIMA_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_GEM_WAIT, struct drm_lima_gem_wait) -+#define DRM_IOCTL_LIMA_CTX_CREATE DRM_IOR(DRM_COMMAND_BASE + DRM_LIMA_CTX_CREATE, struct drm_lima_ctx_create) -+#define DRM_IOCTL_LIMA_CTX_FREE DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_CTX_FREE, struct drm_lima_ctx_free) -+ -+#if defined(__cplusplus) -+} -+#endif -+ -+#endif /* __LIMA_DRM_H__ */ - -From aee623b0324304230a81980cea78cc5d029502f9 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Tue, 9 Apr 2019 15:54:25 -0500 -Subject: [PATCH 243/249] iommu: io-pgtable: Add ARM Mali midgard MMU page - table format - -ARM Mali midgard GPU is similar to standard 64-bit stage 1 page tables, but -have a few differences. Add a new format type to represent the format. The -input address size is 48-bits and the output address size is 40-bits (and -possibly less?). Note that the later bifrost GPUs follow the standard -64-bit stage 1 format. - -The differences in the format compared to 64-bit stage 1 format are: - -The 3rd level page entry bits are 0x1 instead of 0x3 for page entries. - -The access flags are not read-only and unprivileged, but read and write. -This is similar to stage 2 entries, but the memory attributes field matches -stage 1 being an index. - -The nG bit is not set by the vendor driver. This one didn't seem to matter, -but we'll keep it aligned to the vendor driver. - -Cc: Will Deacon -Acked-by: Robin Murphy -Cc: Joerg Roedel -Cc: linux-arm-kernel@lists.infradead.org -Cc: iommu@lists.linux-foundation.org -Acked-by: Alyssa Rosenzweig -Signed-off-by: Rob Herring ---- - drivers/iommu/io-pgtable-arm.c | 91 ++++++++++++++++++++++++++-------- - drivers/iommu/io-pgtable.c | 1 + - include/linux/io-pgtable.h | 7 +++ - 3 files changed, 77 insertions(+), 22 deletions(-) - -diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c -index d3700ec15cbde..4e21efbc44595 100644 ---- a/drivers/iommu/io-pgtable-arm.c -+++ b/drivers/iommu/io-pgtable-arm.c -@@ -172,6 +172,10 @@ - #define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1 - #define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 - -+#define ARM_MALI_LPAE_TTBR_ADRMODE_TABLE (3u << 0) -+#define ARM_MALI_LPAE_TTBR_READ_INNER BIT(2) -+#define ARM_MALI_LPAE_TTBR_SHARE_OUTER BIT(4) -+ - /* IOPTE accessors */ - #define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d)) - -@@ -180,11 +184,6 @@ - - #define iopte_prot(pte) ((pte) & ARM_LPAE_PTE_ATTR_MASK) - --#define iopte_leaf(pte,l) \ -- (l == (ARM_LPAE_MAX_LEVELS - 1) ? \ -- (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_PAGE) : \ -- (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_BLOCK)) -- - struct arm_lpae_io_pgtable { - struct io_pgtable iop; - -@@ -198,6 +197,15 @@ struct arm_lpae_io_pgtable { - - typedef u64 arm_lpae_iopte; - -+static inline bool iopte_leaf(arm_lpae_iopte pte, int lvl, -+ enum io_pgtable_fmt fmt) -+{ -+ if (lvl == (ARM_LPAE_MAX_LEVELS - 1) && fmt != ARM_MALI_LPAE) -+ return iopte_type(pte, lvl) == ARM_LPAE_PTE_TYPE_PAGE; -+ -+ return iopte_type(pte, lvl) == ARM_LPAE_PTE_TYPE_BLOCK; -+} -+ - static arm_lpae_iopte paddr_to_iopte(phys_addr_t paddr, - struct arm_lpae_io_pgtable *data) - { -@@ -303,12 +311,14 @@ static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, - if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS) - pte |= ARM_LPAE_PTE_NS; - -- if (lvl == ARM_LPAE_MAX_LEVELS - 1) -+ if (data->iop.fmt != ARM_MALI_LPAE && lvl == ARM_LPAE_MAX_LEVELS - 1) - pte |= ARM_LPAE_PTE_TYPE_PAGE; - else - pte |= ARM_LPAE_PTE_TYPE_BLOCK; - -- pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS; -+ if (data->iop.fmt != ARM_MALI_LPAE) -+ pte |= ARM_LPAE_PTE_AF; -+ pte |= ARM_LPAE_PTE_SH_IS; - pte |= paddr_to_iopte(paddr, data); - - __arm_lpae_set_pte(ptep, pte, &data->iop.cfg); -@@ -321,7 +331,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, - { - arm_lpae_iopte pte = *ptep; - -- if (iopte_leaf(pte, lvl)) { -+ if (iopte_leaf(pte, lvl, data->iop.fmt)) { - /* We require an unmap first */ - WARN_ON(!selftest_running); - return -EEXIST; -@@ -409,7 +419,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, - __arm_lpae_sync_pte(ptep, cfg); - } - -- if (pte && !iopte_leaf(pte, lvl)) { -+ if (pte && !iopte_leaf(pte, lvl, data->iop.fmt)) { - cptep = iopte_deref(pte, data); - } else if (pte) { - /* We require an unmap first */ -@@ -429,31 +439,37 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, - if (data->iop.fmt == ARM_64_LPAE_S1 || - data->iop.fmt == ARM_32_LPAE_S1) { - pte = ARM_LPAE_PTE_nG; -- - if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) - pte |= ARM_LPAE_PTE_AP_RDONLY; -- - if (!(prot & IOMMU_PRIV)) - pte |= ARM_LPAE_PTE_AP_UNPRIV; -- -- if (prot & IOMMU_MMIO) -- pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV -- << ARM_LPAE_PTE_ATTRINDX_SHIFT); -- else if (prot & IOMMU_CACHE) -- pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE -- << ARM_LPAE_PTE_ATTRINDX_SHIFT); - } else { - pte = ARM_LPAE_PTE_HAP_FAULT; - if (prot & IOMMU_READ) - pte |= ARM_LPAE_PTE_HAP_READ; - if (prot & IOMMU_WRITE) - pte |= ARM_LPAE_PTE_HAP_WRITE; -+ } -+ -+ /* -+ * Note that this logic is structured to accommodate Mali LPAE -+ * having stage-1-like attributes but stage-2-like permissions. -+ */ -+ if (data->iop.fmt == ARM_64_LPAE_S2 || -+ data->iop.fmt == ARM_32_LPAE_S2) { - if (prot & IOMMU_MMIO) - pte |= ARM_LPAE_PTE_MEMATTR_DEV; - else if (prot & IOMMU_CACHE) - pte |= ARM_LPAE_PTE_MEMATTR_OIWB; - else - pte |= ARM_LPAE_PTE_MEMATTR_NC; -+ } else { -+ if (prot & IOMMU_MMIO) -+ pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV -+ << ARM_LPAE_PTE_ATTRINDX_SHIFT); -+ else if (prot & IOMMU_CACHE) -+ pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE -+ << ARM_LPAE_PTE_ATTRINDX_SHIFT); - } - - if (prot & IOMMU_NOEXEC) -@@ -511,7 +527,7 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, - while (ptep != end) { - arm_lpae_iopte pte = *ptep++; - -- if (!pte || iopte_leaf(pte, lvl)) -+ if (!pte || iopte_leaf(pte, lvl, data->iop.fmt)) - continue; - - __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); -@@ -602,7 +618,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, - if (size == ARM_LPAE_BLOCK_SIZE(lvl, data)) { - __arm_lpae_set_pte(ptep, 0, &iop->cfg); - -- if (!iopte_leaf(pte, lvl)) { -+ if (!iopte_leaf(pte, lvl, iop->fmt)) { - /* Also flush any partial walks */ - io_pgtable_tlb_add_flush(iop, iova, size, - ARM_LPAE_GRANULE(data), false); -@@ -621,7 +637,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, - } - - return size; -- } else if (iopte_leaf(pte, lvl)) { -+ } else if (iopte_leaf(pte, lvl, iop->fmt)) { - /* - * Insert a table at the next level to map the old region, - * minus the part we want to unmap -@@ -669,7 +685,7 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, - return 0; - - /* Leaf entry? */ -- if (iopte_leaf(pte,lvl)) -+ if (iopte_leaf(pte, lvl, data->iop.fmt)) - goto found_translation; - - /* Take it to the next level */ -@@ -995,6 +1011,32 @@ arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) - return iop; - } - -+static struct io_pgtable * -+arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) -+{ -+ struct io_pgtable *iop; -+ -+ if (cfg->ias != 48 || cfg->oas > 40) -+ return NULL; -+ -+ cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); -+ iop = arm_64_lpae_alloc_pgtable_s1(cfg, cookie); -+ if (iop) { -+ u64 mair, ttbr; -+ -+ /* Copy values as union fields overlap */ -+ mair = cfg->arm_lpae_s1_cfg.mair[0]; -+ ttbr = cfg->arm_lpae_s1_cfg.ttbr[0]; -+ -+ cfg->arm_mali_lpae_cfg.memattr = mair; -+ cfg->arm_mali_lpae_cfg.transtab = ttbr | -+ ARM_MALI_LPAE_TTBR_READ_INNER | -+ ARM_MALI_LPAE_TTBR_ADRMODE_TABLE; -+ } -+ -+ return iop; -+} -+ - struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = { - .alloc = arm_64_lpae_alloc_pgtable_s1, - .free = arm_lpae_free_pgtable, -@@ -1015,6 +1057,11 @@ struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns = { - .free = arm_lpae_free_pgtable, - }; - -+struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns = { -+ .alloc = arm_mali_lpae_alloc_pgtable, -+ .free = arm_lpae_free_pgtable, -+}; -+ - #ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST - - static struct io_pgtable_cfg *cfg_cookie; -diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c -index 93f2880be6c67..5227cfdbb65b5 100644 ---- a/drivers/iommu/io-pgtable.c -+++ b/drivers/iommu/io-pgtable.c -@@ -30,6 +30,7 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = { - [ARM_32_LPAE_S2] = &io_pgtable_arm_32_lpae_s2_init_fns, - [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns, - [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns, -+ [ARM_MALI_LPAE] = &io_pgtable_arm_mali_lpae_init_fns, - #endif - #ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S - [ARM_V7S] = &io_pgtable_arm_v7s_init_fns, -diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h -index 47d5ae5593297..76969a5648314 100644 ---- a/include/linux/io-pgtable.h -+++ b/include/linux/io-pgtable.h -@@ -12,6 +12,7 @@ enum io_pgtable_fmt { - ARM_64_LPAE_S1, - ARM_64_LPAE_S2, - ARM_V7S, -+ ARM_MALI_LPAE, - IO_PGTABLE_NUM_FMTS, - }; - -@@ -108,6 +109,11 @@ struct io_pgtable_cfg { - u32 nmrr; - u32 prrr; - } arm_v7s_cfg; -+ -+ struct { -+ u64 transtab; -+ u64 memattr; -+ } arm_mali_lpae_cfg; - }; - }; - -@@ -209,5 +215,6 @@ extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns; - extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns; - extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns; - extern struct io_pgtable_init_fns io_pgtable_arm_v7s_init_fns; -+extern struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns; - - #endif /* __IO_PGTABLE_H */ - -From c137ed8338c4206619299008ced60f1ba39976fb Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Tue, 9 Apr 2019 15:54:26 -0500 -Subject: [PATCH 244/249] drm: Add a drm_gem_objects_lookup helper - -Similar to the single handle drm_gem_object_lookup(), -drm_gem_objects_lookup() takes an array of handles and returns an array -of GEM objects. - -v2: -- Take the userspace pointer directly and allocate the array. -- Expand the function documentation. - -Cc: Maarten Lankhorst -Cc: Maxime Ripard -Cc: Sean Paul -Cc: David Airlie -Cc: Daniel Vetter -Acked-by: Alyssa Rosenzweig -Signed-off-by: Rob Herring -Acked-by: Tomeu Vizoso ---- - drivers/gpu/drm/drm_gem.c | 93 ++++++++++++++++++++++++++++++++++----- - include/drm/drm_gem.h | 2 + - 2 files changed, 85 insertions(+), 10 deletions(-) - -diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c -index 388b3742e562a..faa2718e85e8b 100644 ---- a/drivers/gpu/drm/drm_gem.c -+++ b/drivers/gpu/drm/drm_gem.c -@@ -663,6 +663,85 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, - } - EXPORT_SYMBOL(drm_gem_put_pages); - -+static int objects_lookup(struct drm_file *filp, u32 *handle, int count, -+ struct drm_gem_object **objs) -+{ -+ int i, ret = 0; -+ struct drm_gem_object *obj; -+ -+ spin_lock(&filp->table_lock); -+ -+ for (i = 0; i < count; i++) { -+ /* Check if we currently have a reference on the object */ -+ obj = idr_find(&filp->object_idr, handle[i]); -+ if (!obj) { -+ ret = -ENOENT; -+ break; -+ } -+ drm_gem_object_get(obj); -+ objs[i] = obj; -+ } -+ spin_unlock(&filp->table_lock); -+ -+ return ret; -+} -+ -+/** -+ * drm_gem_objects_lookup - look up GEM objects from an array of handles -+ * @filp: DRM file private date -+ * @bo_handles: user pointer to array of userspace handle -+ * @count: size of handle array -+ * @objs_out: returned pointer to array of drm_gem_object pointers -+ * -+ * Takes an array of userspace handles and returns a newly allocated array of -+ * GEM objects. -+ * -+ * For a single handle lookup, use drm_gem_object_lookup(). -+ * -+ * Returns: -+ * -+ * @objs filled in with GEM object pointers. Returned GEM objects need to be -+ * released with drm_gem_object_put(). -ENOENT is returned on a lookup -+ * failure. 0 is returned on success. -+ * -+ */ -+int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, -+ int count, struct drm_gem_object ***objs_out) -+{ -+ int ret; -+ u32 *handles; -+ struct drm_gem_object **objs; -+ -+ if (!count) -+ return 0; -+ -+ objs = kvmalloc_array(count, sizeof(struct drm_gem_object *), -+ GFP_KERNEL | __GFP_ZERO); -+ if (!objs) -+ return -ENOMEM; -+ -+ handles = kvmalloc_array(count, sizeof(u32), GFP_KERNEL); -+ if (!handles) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ if (copy_from_user(handles, bo_handles, count * sizeof(u32))) { -+ ret = -EFAULT; -+ DRM_DEBUG("Failed to copy in GEM handles\n"); -+ goto out; -+ } -+ -+ ret = objects_lookup(filp, handles, count, objs); -+ *objs_out = objs; -+ -+out: -+ kvfree(handles); -+ return ret; -+ -+} -+EXPORT_SYMBOL(drm_gem_objects_lookup); -+ - /** - * drm_gem_object_lookup - look up a GEM object from its handle - * @filp: DRM file private date -@@ -672,21 +751,15 @@ EXPORT_SYMBOL(drm_gem_put_pages); - * - * A reference to the object named by the handle if such exists on @filp, NULL - * otherwise. -+ * -+ * If looking up an array of handles, use drm_gem_objects_lookup(). - */ - struct drm_gem_object * - drm_gem_object_lookup(struct drm_file *filp, u32 handle) - { -- struct drm_gem_object *obj; -- -- spin_lock(&filp->table_lock); -- -- /* Check if we currently have a reference on the object */ -- obj = idr_find(&filp->object_idr, handle); -- if (obj) -- drm_gem_object_get(obj); -- -- spin_unlock(&filp->table_lock); -+ struct drm_gem_object *obj = NULL; - -+ objects_lookup(filp, &handle, 1, &obj); - return obj; - } - EXPORT_SYMBOL(drm_gem_object_lookup); -diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h -index 2955aaab3dca0..5ee85c9eaa9db 100644 ---- a/include/drm/drm_gem.h -+++ b/include/drm/drm_gem.h -@@ -381,6 +381,8 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj); - void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, - bool dirty, bool accessed); - -+int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, -+ int count, struct drm_gem_object ***objs_out); - struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); - long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, - bool wait_all, unsigned long timeout); - -From cbe2b4a4c7c5a9997aa78c19554be368c7d6ff49 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Tue, 9 Apr 2019 15:54:27 -0500 -Subject: [PATCH 245/249] FROMLIST: drm/panfrost: Add initial panfrost driver - -This adds the initial driver for panfrost which supports Arm Mali -Midgard and Bifrost family of GPUs. Currently, only the T860 and -T760 Midgard GPUs have been tested. - -v2: -- Add GPU reset on job hangs (Tomeu) -- Add RuntimePM and devfreq support (Tomeu) -- Fix T760 support (Tomeu) -- Add a TODO file (Rob, Tomeu) -- Support multiple in fences (Tomeu) -- Drop support for shared fences (Tomeu) -- Fill in MMU de-init (Rob) -- Move register definitions back to single header (Rob) -- Clean-up hardcoded job submit todos (Rob) -- Implement feature setup based on features/issues (Rob) -- Add remaining Midgard DT compatible strings (Rob) - -v3: -- Add support for reset lines (Neil) -- Add a MAINTAINERS entry (Rob) -- Call dma_set_mask_and_coherent (Rob) -- Do MMU invalidate on map and unmap. Restructure to do a single - operation per map/unmap call. (Rob) -- Add a missing explicit padding to struct drm_panfrost_create_bo (Rob) -- Fix 0-day error: "panfrost_devfreq.c:151:9-16: ERROR: PTR_ERR applied after initialization to constant on line 150" -- Drop HW_FEATURE_AARCH64_MMU conditional (Rob) -- s/DRM_PANFROST_PARAM_GPU_ID/DRM_PANFROST_PARAM_GPU_PROD_ID/ (Rob) -- Check drm_gem_shmem_prime_import_sg_table() error code (Rob) -- Re-order power on sequence (Rob) -- Move panfrost_acquire_object_fences() before scheduling job (Rob) -- Add NULL checks on array pointers in job clean-up (Rob) -- Rework devfreq (Tomeu) -- Fix devfreq init with no regulator (Rob) -- Various WS and comments clean-up (Rob) - -Cc: Maarten Lankhorst -Cc: Maxime Ripard -Cc: Sean Paul -Cc: David Airlie -Cc: Daniel Vetter -Cc: Lyude Paul -Reviewed-by: Alyssa Rosenzweig -Reviewed-by: Eric Anholt -Signed-off-by: Marty E. Plummer -Signed-off-by: Tomeu Vizoso -Signed-off-by: Neil Armstrong -Signed-off-by: Rob Herring -Reviewed-by: Steven Price ---- - MAINTAINERS | 9 + - drivers/gpu/drm/Kconfig | 2 + - drivers/gpu/drm/Makefile | 1 + - drivers/gpu/drm/panfrost/Kconfig | 14 + - drivers/gpu/drm/panfrost/Makefile | 12 + - drivers/gpu/drm/panfrost/TODO | 27 + - drivers/gpu/drm/panfrost/panfrost_devfreq.c | 218 ++++++++ - drivers/gpu/drm/panfrost/panfrost_devfreq.h | 14 + - drivers/gpu/drm/panfrost/panfrost_device.c | 252 +++++++++ - drivers/gpu/drm/panfrost/panfrost_device.h | 124 ++++ - drivers/gpu/drm/panfrost/panfrost_drv.c | 460 +++++++++++++++ - drivers/gpu/drm/panfrost/panfrost_features.h | 309 ++++++++++ - drivers/gpu/drm/panfrost/panfrost_gem.c | 95 ++++ - drivers/gpu/drm/panfrost/panfrost_gem.h | 29 + - drivers/gpu/drm/panfrost/panfrost_gpu.c | 362 ++++++++++++ - drivers/gpu/drm/panfrost/panfrost_gpu.h | 19 + - drivers/gpu/drm/panfrost/panfrost_issues.h | 176 ++++++ - drivers/gpu/drm/panfrost/panfrost_job.c | 560 +++++++++++++++++++ - drivers/gpu/drm/panfrost/panfrost_job.h | 51 ++ - drivers/gpu/drm/panfrost/panfrost_mmu.c | 369 ++++++++++++ - drivers/gpu/drm/panfrost/panfrost_mmu.h | 17 + - drivers/gpu/drm/panfrost/panfrost_regs.h | 298 ++++++++++ - include/uapi/drm/panfrost_drm.h | 142 +++++ - 23 files changed, 3560 insertions(+) - create mode 100644 drivers/gpu/drm/panfrost/Kconfig - create mode 100644 drivers/gpu/drm/panfrost/Makefile - create mode 100644 drivers/gpu/drm/panfrost/TODO - create mode 100644 drivers/gpu/drm/panfrost/panfrost_devfreq.c - create mode 100644 drivers/gpu/drm/panfrost/panfrost_devfreq.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_device.c - create mode 100644 drivers/gpu/drm/panfrost/panfrost_device.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_drv.c - create mode 100644 drivers/gpu/drm/panfrost/panfrost_features.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_gem.c - create mode 100644 drivers/gpu/drm/panfrost/panfrost_gem.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_gpu.c - create mode 100644 drivers/gpu/drm/panfrost/panfrost_gpu.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_issues.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_job.c - create mode 100644 drivers/gpu/drm/panfrost/panfrost_job.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_mmu.c - create mode 100644 drivers/gpu/drm/panfrost/panfrost_mmu.h - create mode 100644 drivers/gpu/drm/panfrost/panfrost_regs.h - create mode 100644 include/uapi/drm/panfrost_drm.h - -diff --git a/MAINTAINERS b/MAINTAINERS -index f620e30ba67cb..d5f4434338ae8 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -1180,6 +1180,15 @@ F: drivers/gpu/drm/arm/ - F: Documentation/devicetree/bindings/display/arm,malidp.txt - F: Documentation/gpu/afbc.rst - -+ARM MALI PANFROST DRM DRIVER -+M: Rob Herring -+M: Tomeu Vizoso -+L: dri-devel@lists.freedesktop.org -+S: Supported -+T: git git://anongit.freedesktop.org/drm/drm-misc -+F: drivers/gpu/drm/panfrost/ -+F: include/uapi/drm/panfrost_drm.h -+ - ARM MFM AND FLOPPY DRIVERS - M: Ian Molton - S: Maintained -diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig -index 433250cf2beb1..cfddf1f240714 100644 ---- a/drivers/gpu/drm/Kconfig -+++ b/drivers/gpu/drm/Kconfig -@@ -337,6 +337,8 @@ source "drivers/gpu/drm/xen/Kconfig" - - source "drivers/gpu/drm/lima/Kconfig" - -+source "drivers/gpu/drm/panfrost/Kconfig" -+ - # Keep legacy drivers last - - menuconfig DRM_LEGACY -diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile -index 00e0dcc9a2ef5..29a6835db74fe 100644 ---- a/drivers/gpu/drm/Makefile -+++ b/drivers/gpu/drm/Makefile -@@ -111,3 +111,4 @@ obj-$(CONFIG_DRM_PL111) += pl111/ - obj-$(CONFIG_DRM_TVE200) += tve200/ - obj-$(CONFIG_DRM_XEN) += xen/ - obj-$(CONFIG_DRM_LIMA) += lima/ -+obj-$(CONFIG_DRM_PANFROST) += panfrost/ -diff --git a/drivers/gpu/drm/panfrost/Kconfig b/drivers/gpu/drm/panfrost/Kconfig -new file mode 100644 -index 0000000000000..7f5e572daa2dd ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/Kconfig -@@ -0,0 +1,14 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+config DRM_PANFROST -+ tristate "Panfrost (DRM support for ARM Mali Midgard/Bifrost GPUs)" -+ depends on DRM -+ depends on ARM || ARM64 || COMPILE_TEST -+ depends on MMU -+ select DRM_SCHED -+ select IOMMU_SUPPORT -+ select IOMMU_IO_PGTABLE_LPAE -+ select DRM_GEM_SHMEM_HELPER -+ help -+ DRM driver for ARM Mali Midgard (T6xx, T7xx, T8xx) and -+ Bifrost (G3x, G5x, G7x) GPUs. -diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile -new file mode 100644 -index 0000000000000..6de72d13c58f8 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/Makefile -@@ -0,0 +1,12 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+panfrost-y := \ -+ panfrost_drv.o \ -+ panfrost_device.o \ -+ panfrost_devfreq.o \ -+ panfrost_gem.o \ -+ panfrost_gpu.o \ -+ panfrost_job.o \ -+ panfrost_mmu.o -+ -+obj-$(CONFIG_DRM_PANFROST) += panfrost.o -diff --git a/drivers/gpu/drm/panfrost/TODO b/drivers/gpu/drm/panfrost/TODO -new file mode 100644 -index 0000000000000..c2e44add37d89 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/TODO -@@ -0,0 +1,27 @@ -+- Thermal support. -+ -+- Bifrost support: -+ - DT bindings (Neil, WIP) -+ - MMU page table format and address space setup -+ - Bifrost specific feature and issue handling -+ - Coherent DMA support -+ -+- Support for 2MB pages. The io-pgtable code already supports this. Finishing -+ support involves either copying or adapting the iommu API to handle passing -+ aligned addresses and sizes to the io-pgtable code. -+ -+- Per FD address space support. The h/w supports multiple addresses spaces. -+ The hard part is handling when more address spaces are needed than what -+ the h/w provides. -+ -+- Support pinning pages on demand (GPU page faults). -+ -+- Support userspace controlled GPU virtual addresses. Needed for Vulkan. (Tomeu) -+ -+- Support for madvise and a shrinker. -+ -+- Compute job support. So called 'compute only' jobs need to be plumbed up to -+ userspace. -+ -+- Performance counter support. (Boris) -+ -diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c -new file mode 100644 -index 0000000000000..a8121ae67ee33 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c -@@ -0,0 +1,218 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright 2019 Collabora ltd. */ -+#include -+#include -+#include -+#include -+#include -+ -+#include "panfrost_device.h" -+#include "panfrost_features.h" -+#include "panfrost_issues.h" -+#include "panfrost_gpu.h" -+#include "panfrost_regs.h" -+ -+static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev, int slot); -+ -+static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, -+ u32 flags) -+{ -+ struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev)); -+ struct dev_pm_opp *opp; -+ unsigned long old_clk_rate = pfdev->devfreq.cur_freq; -+ unsigned long target_volt, target_rate; -+ int err; -+ -+ opp = devfreq_recommended_opp(dev, freq, flags); -+ if (IS_ERR(opp)) -+ return PTR_ERR(opp); -+ -+ target_rate = dev_pm_opp_get_freq(opp); -+ target_volt = dev_pm_opp_get_voltage(opp); -+ dev_pm_opp_put(opp); -+ -+ if (old_clk_rate == target_rate) -+ return 0; -+ -+ /* -+ * If frequency scaling from low to high, adjust voltage first. -+ * If frequency scaling from high to low, adjust frequency first. -+ */ -+ if (old_clk_rate < target_rate) { -+ err = regulator_set_voltage(pfdev->regulator, target_volt, -+ target_volt); -+ if (err) { -+ dev_err(dev, "Cannot set voltage %lu uV\n", -+ target_volt); -+ return err; -+ } -+ } -+ -+ err = clk_set_rate(pfdev->clock, target_rate); -+ if (err) { -+ dev_err(dev, "Cannot set frequency %lu (%d)\n", target_rate, -+ err); -+ regulator_set_voltage(pfdev->regulator, pfdev->devfreq.cur_volt, -+ pfdev->devfreq.cur_volt); -+ return err; -+ } -+ -+ if (old_clk_rate > target_rate) { -+ err = regulator_set_voltage(pfdev->regulator, target_volt, -+ target_volt); -+ if (err) -+ dev_err(dev, "Cannot set voltage %lu uV\n", target_volt); -+ } -+ -+ pfdev->devfreq.cur_freq = target_rate; -+ pfdev->devfreq.cur_volt = target_volt; -+ -+ return 0; -+} -+ -+static void panfrost_devfreq_reset(struct panfrost_device *pfdev) -+{ -+ ktime_t now = ktime_get(); -+ int i; -+ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) { -+ pfdev->devfreq.slot[i].busy_time = 0; -+ pfdev->devfreq.slot[i].idle_time = 0; -+ pfdev->devfreq.slot[i].time_last_update = now; -+ } -+} -+ -+static int panfrost_devfreq_get_dev_status(struct device *dev, -+ struct devfreq_dev_status *status) -+{ -+ struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev)); -+ int i; -+ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) { -+ panfrost_devfreq_update_utilization(pfdev, i); -+ } -+ -+ status->current_frequency = clk_get_rate(pfdev->clock); -+ status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.slot[0].busy_time, -+ pfdev->devfreq.slot[0].idle_time)); -+ -+ status->busy_time = 0; -+ for (i = 0; i < NUM_JOB_SLOTS; i++) { -+ status->busy_time += ktime_to_ns(pfdev->devfreq.slot[i].busy_time); -+ } -+ -+ /* We're scheduling only to one core atm, so don't divide for now */ -+ /* status->busy_time /= NUM_JOB_SLOTS; */ -+ -+ panfrost_devfreq_reset(pfdev); -+ -+ dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time, -+ status->total_time, -+ status->busy_time / (status->total_time / 100), -+ status->current_frequency / 1000 / 1000); -+ -+ return 0; -+} -+ -+static int panfrost_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) -+{ -+ struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev)); -+ -+ *freq = pfdev->devfreq.cur_freq; -+ -+ return 0; -+} -+ -+static struct devfreq_dev_profile panfrost_devfreq_profile = { -+ .polling_ms = 50, /* ~3 frames */ -+ .target = panfrost_devfreq_target, -+ .get_dev_status = panfrost_devfreq_get_dev_status, -+ .get_cur_freq = panfrost_devfreq_get_cur_freq, -+}; -+ -+int panfrost_devfreq_init(struct panfrost_device *pfdev) -+{ -+ int ret; -+ struct dev_pm_opp *opp; -+ -+ if (!pfdev->regulator) -+ return 0; -+ -+ ret = dev_pm_opp_of_add_table(&pfdev->pdev->dev); -+ if (ret == -ENODEV) /* Optional, continue without devfreq */ -+ return 0; -+ -+ panfrost_devfreq_reset(pfdev); -+ -+ pfdev->devfreq.cur_freq = clk_get_rate(pfdev->clock); -+ -+ opp = devfreq_recommended_opp(&pfdev->pdev->dev, &pfdev->devfreq.cur_freq, 0); -+ if (IS_ERR(opp)) -+ return PTR_ERR(opp); -+ -+ panfrost_devfreq_profile.initial_freq = pfdev->devfreq.cur_freq; -+ dev_pm_opp_put(opp); -+ -+ pfdev->devfreq.devfreq = devm_devfreq_add_device(&pfdev->pdev->dev, -+ &panfrost_devfreq_profile, "simple_ondemand", NULL); -+ if (IS_ERR(pfdev->devfreq.devfreq)) { -+ DRM_DEV_ERROR(&pfdev->pdev->dev, "Couldn't initialize GPU devfreq\n"); -+ ret = PTR_ERR(pfdev->devfreq.devfreq); -+ pfdev->devfreq.devfreq = NULL; -+ return ret; -+ } -+ -+ return 0; -+} -+ -+void panfrost_devfreq_resume(struct panfrost_device *pfdev) -+{ -+ int i; -+ -+ if (!pfdev->devfreq.devfreq) -+ return; -+ -+ panfrost_devfreq_reset(pfdev); -+ for (i = 0; i < NUM_JOB_SLOTS; i++) -+ pfdev->devfreq.slot[i].busy = false; -+ -+ devfreq_resume_device(pfdev->devfreq.devfreq); -+} -+ -+void panfrost_devfreq_suspend(struct panfrost_device *pfdev) -+{ -+ if (!pfdev->devfreq.devfreq) -+ return; -+ -+ devfreq_suspend_device(pfdev->devfreq.devfreq); -+} -+ -+static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev, int slot) -+{ -+ struct panfrost_devfreq_slot *devfreq_slot = &pfdev->devfreq.slot[slot]; -+ ktime_t now; -+ ktime_t last; -+ -+ if (!pfdev->devfreq.devfreq) -+ return; -+ -+ now = ktime_get(); -+ last = pfdev->devfreq.slot[slot].time_last_update; -+ -+ /* If we last recorded a transition to busy, we have been idle since */ -+ if (devfreq_slot->busy) -+ pfdev->devfreq.slot[slot].busy_time += ktime_sub(now, last); -+ else -+ pfdev->devfreq.slot[slot].idle_time += ktime_sub(now, last); -+ -+ pfdev->devfreq.slot[slot].time_last_update = now; -+} -+ -+/* The job scheduler is expected to call this at every transition busy <-> idle */ -+void panfrost_devfreq_record_transition(struct panfrost_device *pfdev, int slot) -+{ -+ struct panfrost_devfreq_slot *devfreq_slot = &pfdev->devfreq.slot[slot]; -+ -+ panfrost_devfreq_update_utilization(pfdev, slot); -+ devfreq_slot->busy = !devfreq_slot->busy; -+} -diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h -new file mode 100644 -index 0000000000000..eb999531ed900 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2019 Collabora ltd. */ -+ -+#ifndef __PANFROST_DEVFREQ_H__ -+#define __PANFROST_DEVFREQ_H__ -+ -+int panfrost_devfreq_init(struct panfrost_device *pfdev); -+ -+void panfrost_devfreq_resume(struct panfrost_device *pfdev); -+void panfrost_devfreq_suspend(struct panfrost_device *pfdev); -+ -+void panfrost_devfreq_record_transition(struct panfrost_device *pfdev, int slot); -+ -+#endif /* __PANFROST_DEVFREQ_H__ */ -diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c -new file mode 100644 -index 0000000000000..91e8fb0f2b25b ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_device.c -@@ -0,0 +1,252 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright 2018 Marty E. Plummer */ -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "panfrost_device.h" -+#include "panfrost_devfreq.h" -+#include "panfrost_features.h" -+#include "panfrost_gpu.h" -+#include "panfrost_job.h" -+#include "panfrost_mmu.h" -+ -+static int panfrost_reset_init(struct panfrost_device *pfdev) -+{ -+ int err; -+ -+ pfdev->rstc = devm_reset_control_array_get(pfdev->dev, false, true); -+ if (IS_ERR(pfdev->rstc)) { -+ dev_err(pfdev->dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc)); -+ return PTR_ERR(pfdev->rstc); -+ } -+ -+ err = reset_control_deassert(pfdev->rstc); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static void panfrost_reset_fini(struct panfrost_device *pfdev) -+{ -+ reset_control_assert(pfdev->rstc); -+} -+ -+static int panfrost_clk_init(struct panfrost_device *pfdev) -+{ -+ int err; -+ unsigned long rate; -+ -+ pfdev->clock = devm_clk_get(pfdev->dev, NULL); -+ if (IS_ERR(pfdev->clock)) { -+ dev_err(pfdev->dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock)); -+ return PTR_ERR(pfdev->clock); -+ } -+ -+ rate = clk_get_rate(pfdev->clock); -+ dev_info(pfdev->dev, "clock rate = %lu\n", rate); -+ -+ err = clk_prepare_enable(pfdev->clock); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static void panfrost_clk_fini(struct panfrost_device *pfdev) -+{ -+ clk_disable_unprepare(pfdev->clock); -+} -+ -+static int panfrost_regulator_init(struct panfrost_device *pfdev) -+{ -+ int ret; -+ -+ pfdev->regulator = devm_regulator_get_optional(pfdev->dev, "mali"); -+ if (IS_ERR(pfdev->regulator)) { -+ ret = PTR_ERR(pfdev->regulator); -+ pfdev->regulator = NULL; -+ if (ret == -ENODEV) -+ return 0; -+ dev_err(pfdev->dev, "failed to get regulator: %d\n", ret); -+ return ret; -+ } -+ -+ ret = regulator_enable(pfdev->regulator); -+ if (ret < 0) { -+ dev_err(pfdev->dev, "failed to enable regulator: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void panfrost_regulator_fini(struct panfrost_device *pfdev) -+{ -+ if (pfdev->regulator) -+ regulator_disable(pfdev->regulator); -+} -+ -+int panfrost_device_init(struct panfrost_device *pfdev) -+{ -+ int err; -+ struct resource *res; -+ -+ mutex_init(&pfdev->sched_lock); -+ INIT_LIST_HEAD(&pfdev->scheduled_jobs); -+ -+ spin_lock_init(&pfdev->hwaccess_lock); -+ -+ err = panfrost_clk_init(pfdev); -+ if (err) { -+ dev_err(pfdev->dev, "clk init failed %d\n", err); -+ return err; -+ } -+ -+ err = panfrost_regulator_init(pfdev); -+ if (err) { -+ dev_err(pfdev->dev, "regulator init failed %d\n", err); -+ goto err_out0; -+ } -+ -+ err = panfrost_reset_init(pfdev); -+ if (err) { -+ dev_err(pfdev->dev, "reset init failed %d\n", err); -+ goto err_out1; -+ } -+ -+ res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); -+ pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); -+ if (IS_ERR(pfdev->iomem)) { -+ dev_err(pfdev->dev, "failed to ioremap iomem\n"); -+ err = PTR_ERR(pfdev->iomem); -+ goto err_out2; -+ } -+ -+ err = panfrost_gpu_init(pfdev); -+ if (err) -+ goto err_out2; -+ -+ err = panfrost_mmu_init(pfdev); -+ if (err) -+ goto err_out3; -+ -+ err = panfrost_job_init(pfdev); -+ if (err) -+ goto err_out4; -+ -+ /* runtime PM will wake us up later */ -+ panfrost_gpu_power_off(pfdev); -+ -+ pm_runtime_set_active(pfdev->dev); -+ pm_runtime_get_sync(pfdev->dev); -+ pm_runtime_mark_last_busy(pfdev->dev); -+ pm_runtime_put_autosuspend(pfdev->dev); -+ -+ return 0; -+err_out4: -+ panfrost_mmu_fini(pfdev); -+err_out3: -+ panfrost_gpu_fini(pfdev); -+err_out2: -+ panfrost_reset_fini(pfdev); -+err_out1: -+ panfrost_regulator_fini(pfdev); -+err_out0: -+ panfrost_clk_fini(pfdev); -+ return err; -+} -+ -+void panfrost_device_fini(struct panfrost_device *pfdev) -+{ -+ panfrost_regulator_fini(pfdev); -+ panfrost_clk_fini(pfdev); -+} -+ -+const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code) -+{ -+ switch (exception_code) { -+ /* Non-Fault Status code */ -+ case 0x00: return "NOT_STARTED/IDLE/OK"; -+ case 0x01: return "DONE"; -+ case 0x02: return "INTERRUPTED"; -+ case 0x03: return "STOPPED"; -+ case 0x04: return "TERMINATED"; -+ case 0x08: return "ACTIVE"; -+ /* Job exceptions */ -+ case 0x40: return "JOB_CONFIG_FAULT"; -+ case 0x41: return "JOB_POWER_FAULT"; -+ case 0x42: return "JOB_READ_FAULT"; -+ case 0x43: return "JOB_WRITE_FAULT"; -+ case 0x44: return "JOB_AFFINITY_FAULT"; -+ case 0x48: return "JOB_BUS_FAULT"; -+ case 0x50: return "INSTR_INVALID_PC"; -+ case 0x51: return "INSTR_INVALID_ENC"; -+ case 0x52: return "INSTR_TYPE_MISMATCH"; -+ case 0x53: return "INSTR_OPERAND_FAULT"; -+ case 0x54: return "INSTR_TLS_FAULT"; -+ case 0x55: return "INSTR_BARRIER_FAULT"; -+ case 0x56: return "INSTR_ALIGN_FAULT"; -+ case 0x58: return "DATA_INVALID_FAULT"; -+ case 0x59: return "TILE_RANGE_FAULT"; -+ case 0x5A: return "ADDR_RANGE_FAULT"; -+ case 0x60: return "OUT_OF_MEMORY"; -+ /* GPU exceptions */ -+ case 0x80: return "DELAYED_BUS_FAULT"; -+ case 0x88: return "SHAREABILITY_FAULT"; -+ /* MMU exceptions */ -+ case 0xC1: return "TRANSLATION_FAULT_LEVEL1"; -+ case 0xC2: return "TRANSLATION_FAULT_LEVEL2"; -+ case 0xC3: return "TRANSLATION_FAULT_LEVEL3"; -+ case 0xC4: return "TRANSLATION_FAULT_LEVEL4"; -+ case 0xC8: return "PERMISSION_FAULT"; -+ case 0xC9 ... 0xCF: return "PERMISSION_FAULT"; -+ case 0xD1: return "TRANSTAB_BUS_FAULT_LEVEL1"; -+ case 0xD2: return "TRANSTAB_BUS_FAULT_LEVEL2"; -+ case 0xD3: return "TRANSTAB_BUS_FAULT_LEVEL3"; -+ case 0xD4: return "TRANSTAB_BUS_FAULT_LEVEL4"; -+ case 0xD8: return "ACCESS_FLAG"; -+ case 0xD9 ... 0xDF: return "ACCESS_FLAG"; -+ case 0xE0 ... 0xE7: return "ADDRESS_SIZE_FAULT"; -+ case 0xE8 ... 0xEF: return "MEMORY_ATTRIBUTES_FAULT"; -+ } -+ -+ return "UNKNOWN"; -+} -+ -+#ifdef CONFIG_PM -+int panfrost_device_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct panfrost_device *pfdev = platform_get_drvdata(pdev); -+ -+ panfrost_gpu_soft_reset(pfdev); -+ -+ /* TODO: Re-enable all other address spaces */ -+ panfrost_gpu_power_on(pfdev); -+ panfrost_mmu_enable(pfdev, 0); -+ panfrost_job_enable_interrupts(pfdev); -+ panfrost_devfreq_resume(pfdev); -+ -+ return 0; -+} -+ -+int panfrost_device_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct panfrost_device *pfdev = platform_get_drvdata(pdev); -+ -+ if (!panfrost_job_is_idle(pfdev)) -+ return -EBUSY; -+ -+ panfrost_devfreq_suspend(pfdev); -+ panfrost_gpu_power_off(pfdev); -+ -+ return 0; -+} -+#endif -diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h -new file mode 100644 -index 0000000000000..1ba48d105763d ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_device.h -@@ -0,0 +1,124 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2018 Marty E. Plummer */ -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+ -+#ifndef __PANFROST_DEVICE_H__ -+#define __PANFROST_DEVICE_H__ -+ -+#include -+#include -+#include -+#include -+ -+struct panfrost_device; -+struct panfrost_mmu; -+struct panfrost_job_slot; -+struct panfrost_job; -+ -+#define NUM_JOB_SLOTS 3 -+ -+struct panfrost_features { -+ u16 id; -+ u16 revision; -+ -+ u64 shader_present; -+ u64 tiler_present; -+ u64 l2_present; -+ u64 stack_present; -+ u32 as_present; -+ u32 js_present; -+ -+ u32 l2_features; -+ u32 core_features; -+ u32 tiler_features; -+ u32 mem_features; -+ u32 mmu_features; -+ u32 thread_features; -+ u32 max_threads; -+ u32 thread_max_workgroup_sz; -+ u32 thread_max_barrier_sz; -+ u32 coherency_features; -+ u32 texture_features[4]; -+ u32 js_features[16]; -+ -+ u32 nr_core_groups; -+ -+ unsigned long hw_features[64 / BITS_PER_LONG]; -+ unsigned long hw_issues[64 / BITS_PER_LONG]; -+}; -+ -+struct panfrost_devfreq_slot { -+ ktime_t busy_time; -+ ktime_t idle_time; -+ ktime_t time_last_update; -+ bool busy; -+}; -+ -+struct panfrost_device { -+ struct device *dev; -+ struct drm_device *ddev; -+ struct platform_device *pdev; -+ -+ spinlock_t hwaccess_lock; -+ -+ struct drm_mm mm; -+ spinlock_t mm_lock; -+ -+ void __iomem *iomem; -+ struct clk *clock; -+ struct regulator *regulator; -+ struct reset_control *rstc; -+ -+ struct panfrost_features features; -+ -+ struct panfrost_mmu *mmu; -+ struct panfrost_job_slot *js; -+ -+ struct panfrost_job *jobs[NUM_JOB_SLOTS]; -+ struct list_head scheduled_jobs; -+ -+ struct mutex sched_lock; -+ -+ struct { -+ struct devfreq *devfreq; -+ struct thermal_cooling_device *cooling; -+ unsigned long cur_freq; -+ unsigned long cur_volt; -+ struct panfrost_devfreq_slot slot[NUM_JOB_SLOTS]; -+ } devfreq; -+}; -+ -+struct panfrost_file_priv { -+ struct panfrost_device *pfdev; -+ -+ struct drm_sched_entity sched_entity[NUM_JOB_SLOTS]; -+}; -+ -+static inline struct panfrost_device *to_panfrost_device(struct drm_device *ddev) -+{ -+ return ddev->dev_private; -+} -+ -+static inline int panfrost_model_cmp(struct panfrost_device *pfdev, s32 id) -+{ -+ s32 match_id = pfdev->features.id; -+ -+ if (match_id & 0xf000) -+ match_id &= 0xf00f; -+ return match_id - id; -+} -+ -+static inline bool panfrost_model_eq(struct panfrost_device *pfdev, s32 id) -+{ -+ return !panfrost_model_cmp(pfdev, id); -+} -+ -+int panfrost_device_init(struct panfrost_device *pfdev); -+void panfrost_device_fini(struct panfrost_device *pfdev); -+ -+int panfrost_device_resume(struct device *dev); -+int panfrost_device_suspend(struct device *dev); -+ -+const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code); -+ -+#endif -diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c -new file mode 100644 -index 0000000000000..46da249edf32d ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c -@@ -0,0 +1,460 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright 2018 Marty E. Plummer */ -+/* Copyright 2019 Linaro, Ltd., Rob Herring */ -+/* Copyright 2019 Collabora ltd. */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "panfrost_device.h" -+#include "panfrost_devfreq.h" -+#include "panfrost_gem.h" -+#include "panfrost_mmu.h" -+#include "panfrost_job.h" -+#include "panfrost_gpu.h" -+ -+static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct drm_file *file) -+{ -+ struct drm_panfrost_get_param *param = data; -+ struct panfrost_device *pfdev = ddev->dev_private; -+ -+ if (param->pad != 0) -+ return -EINVAL; -+ -+ switch (param->param) { -+ case DRM_PANFROST_PARAM_GPU_PROD_ID: -+ param->value = pfdev->features.id; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, -+ struct drm_file *file) -+{ -+ int ret; -+ struct drm_gem_shmem_object *shmem; -+ struct drm_panfrost_create_bo *args = data; -+ -+ if (!args->size || args->flags) -+ return -EINVAL; -+ -+ shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, -+ &args->handle); -+ if (IS_ERR(shmem)) -+ return PTR_ERR(shmem); -+ -+ ret = panfrost_mmu_map(to_panfrost_bo(&shmem->base)); -+ if (ret) -+ goto err_free; -+ -+ args->offset = to_panfrost_bo(&shmem->base)->node.start << PAGE_SHIFT; -+ -+ return 0; -+ -+err_free: -+ drm_gem_object_put_unlocked(&shmem->base); -+ return ret; -+} -+ -+/** -+ * panfrost_lookup_bos() - Sets up job->bo[] with the GEM objects -+ * referenced by the job. -+ * @dev: DRM device -+ * @file_priv: DRM file for this fd -+ * @args: IOCTL args -+ * @job: job being set up -+ * -+ * Resolve handles from userspace to BOs and attach them to job. -+ * -+ * Note that this function doesn't need to unreference the BOs on -+ * failure, because that will happen at panfrost_job_cleanup() time. -+ */ -+static int -+panfrost_lookup_bos(struct drm_device *dev, -+ struct drm_file *file_priv, -+ struct drm_panfrost_submit *args, -+ struct panfrost_job *job) -+{ -+ job->bo_count = args->bo_handle_count; -+ -+ if (!job->bo_count) -+ return 0; -+ -+ job->implicit_fences = kvmalloc_array(job->bo_count, -+ sizeof(struct dma_fence *), -+ GFP_KERNEL | __GFP_ZERO); -+ if (!job->implicit_fences) -+ return -ENOMEM; -+ -+ return drm_gem_objects_lookup(file_priv, -+ (void __user *)(uintptr_t)args->bo_handles, -+ job->bo_count, &job->bos); -+} -+ -+/** -+ * panfrost_copy_in_sync() - Sets up job->in_fences[] with the sync objects -+ * referenced by the job. -+ * @dev: DRM device -+ * @file_priv: DRM file for this fd -+ * @args: IOCTL args -+ * @job: job being set up -+ * -+ * Resolve syncobjs from userspace to fences and attach them to job. -+ * -+ * Note that this function doesn't need to unreference the fences on -+ * failure, because that will happen at panfrost_job_cleanup() time. -+ */ -+static int -+panfrost_copy_in_sync(struct drm_device *dev, -+ struct drm_file *file_priv, -+ struct drm_panfrost_submit *args, -+ struct panfrost_job *job) -+{ -+ u32 *handles; -+ int ret = 0; -+ int i; -+ -+ job->in_fence_count = args->in_sync_count; -+ -+ if (!job->in_fence_count) -+ return 0; -+ -+ job->in_fences = kvmalloc_array(job->in_fence_count, -+ sizeof(struct dma_fence *), -+ GFP_KERNEL | __GFP_ZERO); -+ if (!job->in_fences) { -+ DRM_DEBUG("Failed to allocate job in fences\n"); -+ return -ENOMEM; -+ } -+ -+ handles = kvmalloc_array(job->in_fence_count, sizeof(u32), GFP_KERNEL); -+ if (!handles) { -+ ret = -ENOMEM; -+ DRM_DEBUG("Failed to allocate incoming syncobj handles\n"); -+ goto fail; -+ } -+ -+ if (copy_from_user(handles, -+ (void __user *)(uintptr_t)args->in_syncs, -+ job->in_fence_count * sizeof(u32))) { -+ ret = -EFAULT; -+ DRM_DEBUG("Failed to copy in syncobj handles\n"); -+ goto fail; -+ } -+ -+ for (i = 0; i < job->in_fence_count; i++) { -+ ret = drm_syncobj_find_fence(file_priv, handles[i], 0, 0, -+ &job->in_fences[i]); -+ if (ret == -EINVAL) -+ goto fail; -+ } -+ -+fail: -+ kvfree(handles); -+ return ret; -+} -+ -+static int panfrost_ioctl_submit(struct drm_device *dev, void *data, -+ struct drm_file *file) -+{ -+ struct panfrost_device *pfdev = dev->dev_private; -+ struct drm_panfrost_submit *args = data; -+ struct drm_syncobj *sync_out; -+ struct panfrost_job *job; -+ int ret = 0; -+ -+ job = kcalloc(1, sizeof(*job), GFP_KERNEL); -+ if (!job) -+ return -ENOMEM; -+ -+ kref_init(&job->refcount); -+ -+ job->pfdev = pfdev; -+ job->jc = args->jc; -+ job->requirements = args->requirements; -+ job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev); -+ job->file_priv = file->driver_priv; -+ -+ ret = panfrost_copy_in_sync(dev, file, args, job); -+ if (ret) -+ goto fail; -+ -+ ret = panfrost_lookup_bos(dev, file, args, job); -+ if (ret) -+ goto fail; -+ -+ ret = panfrost_job_push(job); -+ if (ret) -+ goto fail; -+ -+ /* Update the return sync object for the job */ -+ sync_out = drm_syncobj_find(file, args->out_sync); -+ if (sync_out) { -+ drm_syncobj_replace_fence(sync_out, job->render_done_fence); -+ drm_syncobj_put(sync_out); -+ } -+ -+fail: -+ panfrost_job_put(job); -+ -+ return ret; -+} -+ -+static int -+panfrost_ioctl_wait_bo(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ long ret; -+ struct drm_panfrost_wait_bo *args = data; -+ struct drm_gem_object *gem_obj; -+ unsigned long timeout = drm_timeout_abs_to_jiffies(args->timeout_ns); -+ -+ if (args->pad) -+ return -EINVAL; -+ -+ gem_obj = drm_gem_object_lookup(file_priv, args->handle); -+ if (!gem_obj) -+ return -ENOENT; -+ -+ ret = reservation_object_wait_timeout_rcu(gem_obj->resv, true, -+ true, timeout); -+ if (!ret) -+ ret = timeout ? -ETIMEDOUT : -EBUSY; -+ -+ drm_gem_object_put_unlocked(gem_obj); -+ -+ return ret; -+} -+ -+static int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct drm_panfrost_mmap_bo *args = data; -+ struct drm_gem_object *gem_obj; -+ int ret; -+ -+ if (args->flags != 0) { -+ DRM_INFO("unknown mmap_bo flags: %d\n", args->flags); -+ return -EINVAL; -+ } -+ -+ gem_obj = drm_gem_object_lookup(file_priv, args->handle); -+ if (!gem_obj) { -+ DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); -+ return -ENOENT; -+ } -+ -+ ret = drm_gem_create_mmap_offset(gem_obj); -+ if (ret == 0) -+ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); -+ drm_gem_object_put_unlocked(gem_obj); -+ -+ return ret; -+} -+ -+static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct drm_panfrost_get_bo_offset *args = data; -+ struct drm_gem_object *gem_obj; -+ struct panfrost_gem_object *bo; -+ -+ gem_obj = drm_gem_object_lookup(file_priv, args->handle); -+ if (!gem_obj) { -+ DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); -+ return -ENOENT; -+ } -+ bo = to_panfrost_bo(gem_obj); -+ -+ args->offset = bo->node.start << PAGE_SHIFT; -+ -+ drm_gem_object_put_unlocked(gem_obj); -+ return 0; -+} -+ -+static int -+panfrost_open(struct drm_device *dev, struct drm_file *file) -+{ -+ struct panfrost_device *pfdev = dev->dev_private; -+ struct panfrost_file_priv *panfrost_priv; -+ -+ panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL); -+ if (!panfrost_priv) -+ return -ENOMEM; -+ -+ panfrost_priv->pfdev = pfdev; -+ file->driver_priv = panfrost_priv; -+ -+ return panfrost_job_open(panfrost_priv); -+} -+ -+static void -+panfrost_postclose(struct drm_device *dev, struct drm_file *file) -+{ -+ struct panfrost_file_priv *panfrost_priv = file->driver_priv; -+ -+ panfrost_job_close(panfrost_priv); -+ -+ kfree(panfrost_priv); -+} -+ -+/* DRM_AUTH is required on SUBMIT for now, while all clients share a single -+ * address space. Note that render nodes would be able to submit jobs that -+ * could access BOs from clients authenticated with the master node. -+ */ -+static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { -+#define PANFROST_IOCTL(n, func, flags) \ -+ DRM_IOCTL_DEF_DRV(PANFROST_##n, panfrost_ioctl_##func, flags) -+ -+ PANFROST_IOCTL(SUBMIT, submit, DRM_RENDER_ALLOW | DRM_AUTH), -+ PANFROST_IOCTL(WAIT_BO, wait_bo, DRM_RENDER_ALLOW), -+ PANFROST_IOCTL(CREATE_BO, create_bo, DRM_RENDER_ALLOW), -+ PANFROST_IOCTL(MMAP_BO, mmap_bo, DRM_RENDER_ALLOW), -+ PANFROST_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), -+ PANFROST_IOCTL(GET_BO_OFFSET, get_bo_offset, DRM_RENDER_ALLOW), -+}; -+ -+DEFINE_DRM_GEM_SHMEM_FOPS(panfrost_drm_driver_fops); -+ -+static struct drm_driver panfrost_drm_driver = { -+ .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_PRIME | -+ DRIVER_SYNCOBJ, -+ .open = panfrost_open, -+ .postclose = panfrost_postclose, -+ .ioctls = panfrost_drm_driver_ioctls, -+ .num_ioctls = ARRAY_SIZE(panfrost_drm_driver_ioctls), -+ .fops = &panfrost_drm_driver_fops, -+ .name = "panfrost", -+ .desc = "panfrost DRM", -+ .date = "20180908", -+ .major = 1, -+ .minor = 0, -+ -+ .gem_create_object = panfrost_gem_create_object, -+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, -+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, -+ .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, -+ .gem_prime_mmap = drm_gem_prime_mmap, -+}; -+ -+static int panfrost_probe(struct platform_device *pdev) -+{ -+ struct panfrost_device *pfdev; -+ struct drm_device *ddev; -+ int err; -+ -+ pfdev = devm_kzalloc(&pdev->dev, sizeof(*pfdev), GFP_KERNEL); -+ if (!pfdev) -+ return -ENOMEM; -+ -+ pfdev->pdev = pdev; -+ pfdev->dev = &pdev->dev; -+ -+ platform_set_drvdata(pdev, pfdev); -+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); -+ -+ /* Allocate and initialze the DRM device. */ -+ ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev); -+ if (IS_ERR(ddev)) -+ return PTR_ERR(ddev); -+ -+ ddev->dev_private = pfdev; -+ pfdev->ddev = ddev; -+ -+ spin_lock_init(&pfdev->mm_lock); -+ -+ /* 4G enough for now. can be 48-bit */ -+ drm_mm_init(&pfdev->mm, SZ_32M >> PAGE_SHIFT, SZ_4G); -+ -+ pm_runtime_use_autosuspend(pfdev->dev); -+ pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */ -+ pm_runtime_enable(pfdev->dev); -+ -+ err = panfrost_device_init(pfdev); -+ if (err) { -+ dev_err(&pdev->dev, "Fatal error during GPU init\n"); -+ goto err_out0; -+ } -+ -+ err = panfrost_devfreq_init(pfdev); -+ if (err) { -+ dev_err(&pdev->dev, "Fatal error during devfreq init\n"); -+ goto err_out1; -+ } -+ -+ /* -+ * Register the DRM device with the core and the connectors with -+ * sysfs -+ */ -+ err = drm_dev_register(ddev, 0); -+ if (err < 0) -+ goto err_out1; -+ -+ return 0; -+ -+err_out1: -+ panfrost_device_fini(pfdev); -+err_out0: -+ drm_dev_put(ddev); -+ return err; -+} -+ -+static int panfrost_remove(struct platform_device *pdev) -+{ -+ struct panfrost_device *pfdev = platform_get_drvdata(pdev); -+ struct drm_device *ddev = pfdev->ddev; -+ -+ drm_dev_unregister(ddev); -+ pm_runtime_get_sync(pfdev->dev); -+ pm_runtime_put_sync_autosuspend(pfdev->dev); -+ pm_runtime_disable(pfdev->dev); -+ panfrost_device_fini(pfdev); -+ drm_dev_put(ddev); -+ return 0; -+} -+ -+static const struct of_device_id dt_match[] = { -+ { .compatible = "arm,mali-t604" }, -+ { .compatible = "arm,mali-t624" }, -+ { .compatible = "arm,mali-t628" }, -+ { .compatible = "arm,mali-t720" }, -+ { .compatible = "arm,mali-t760" }, -+ { .compatible = "arm,mali-t820" }, -+ { .compatible = "arm,mali-t830" }, -+ { .compatible = "arm,mali-t860" }, -+ { .compatible = "arm,mali-t880" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, dt_match); -+ -+static const struct dev_pm_ops panfrost_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(panfrost_device_suspend, panfrost_device_resume, NULL) -+}; -+ -+static struct platform_driver panfrost_driver = { -+ .probe = panfrost_probe, -+ .remove = panfrost_remove, -+ .driver = { -+ .name = "panfrost", -+ .pm = &panfrost_pm_ops, -+ .of_match_table = dt_match, -+ }, -+}; -+module_platform_driver(panfrost_driver); -+ -+MODULE_AUTHOR("Panfrost Project Developers"); -+MODULE_DESCRIPTION("Panfrost DRM Driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/gpu/drm/panfrost/panfrost_features.h b/drivers/gpu/drm/panfrost/panfrost_features.h -new file mode 100644 -index 0000000000000..5056777c77449 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_features.h -@@ -0,0 +1,309 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* (C) COPYRIGHT 2014-2018 ARM Limited. All rights reserved. */ -+/* Copyright 2019 Linaro, Ltd., Rob Herring */ -+#ifndef __PANFROST_FEATURES_H__ -+#define __PANFROST_FEATURES_H__ -+ -+#include -+ -+#include "panfrost_device.h" -+ -+enum panfrost_hw_feature { -+ HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ HW_FEATURE_XAFFINITY, -+ HW_FEATURE_OUT_OF_ORDER_EXEC, -+ HW_FEATURE_MRT, -+ HW_FEATURE_BRNDOUT_CC, -+ HW_FEATURE_INTERPIPE_REG_ALIASING, -+ HW_FEATURE_LD_ST_TILEBUFFER, -+ HW_FEATURE_MSAA_16X, -+ HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ HW_FEATURE_OPTIMIZED_COVERAGE_MASK, -+ HW_FEATURE_T7XX_PAIRING_RULES, -+ HW_FEATURE_LD_ST_LEA_TEX, -+ HW_FEATURE_LINEAR_FILTER_FLOAT, -+ HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4, -+ HW_FEATURE_IMAGES_IN_FRAGMENT_SHADERS, -+ HW_FEATURE_TEST4_DATUM_MODE, -+ HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ HW_FEATURE_BRNDOUT_KILL, -+ HW_FEATURE_WARPING, -+ HW_FEATURE_V4, -+ HW_FEATURE_FLUSH_REDUCTION, -+ HW_FEATURE_PROTECTED_MODE, -+ HW_FEATURE_COHERENCY_REG, -+ HW_FEATURE_PROTECTED_DEBUG_MODE, -+ HW_FEATURE_AARCH64_MMU, -+ HW_FEATURE_TLS_HASHING, -+ HW_FEATURE_THREAD_GROUP_SPLIT, -+ HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG, -+}; -+ -+#define hw_features_t600 (\ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_V4)) -+ -+#define hw_features_t620 (\ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_V4)) -+ -+#define hw_features_t720 (\ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_OPTIMIZED_COVERAGE_MASK) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_V4)) -+ -+ -+#define hw_features_t760 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) -+ -+// T860 -+#define hw_features_t860 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) -+ -+#define hw_features_t880 hw_features_t860 -+ -+#define hw_features_t830 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) -+ -+#define hw_features_t820 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) -+ -+#define hw_features_g71 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ -+ BIT_ULL(HW_FEATURE_COHERENCY_REG)) -+ -+#define hw_features_g72 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ -+ BIT_ULL(HW_FEATURE_COHERENCY_REG)) -+ -+#define hw_features_g51 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ -+ BIT_ULL(HW_FEATURE_COHERENCY_REG)) -+ -+#define hw_features_g52 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ -+ BIT_ULL(HW_FEATURE_COHERENCY_REG)) -+ -+#define hw_features_g76 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ -+ BIT_ULL(HW_FEATURE_COHERENCY_REG) | \ -+ BIT_ULL(HW_FEATURE_AARCH64_MMU) | \ -+ BIT_ULL(HW_FEATURE_TLS_HASHING) | \ -+ BIT_ULL(HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) -+ -+#define hw_features_g31 (\ -+ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ -+ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ -+ BIT_ULL(HW_FEATURE_XAFFINITY) | \ -+ BIT_ULL(HW_FEATURE_WARPING) | \ -+ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ -+ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ -+ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ -+ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ -+ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ -+ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ -+ BIT_ULL(HW_FEATURE_MRT) | \ -+ BIT_ULL(HW_FEATURE_MSAA_16X) | \ -+ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ -+ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ -+ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ -+ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ -+ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ -+ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ -+ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ -+ BIT_ULL(HW_FEATURE_COHERENCY_REG) | \ -+ BIT_ULL(HW_FEATURE_AARCH64_MMU) | \ -+ BIT_ULL(HW_FEATURE_TLS_HASHING) | \ -+ BIT_ULL(HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) -+ -+static inline bool panfrost_has_hw_feature(struct panfrost_device *pfdev, -+ enum panfrost_hw_feature feat) -+{ -+ return test_bit(feat, pfdev->features.hw_features); -+} -+ -+#endif -diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c -new file mode 100644 -index 0000000000000..8a0376283a215 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c -@@ -0,0 +1,95 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include "panfrost_device.h" -+#include "panfrost_gem.h" -+#include "panfrost_mmu.h" -+ -+/* Called DRM core on the last userspace/kernel unreference of the -+ * BO. -+ */ -+void panfrost_gem_free_object(struct drm_gem_object *obj) -+{ -+ struct panfrost_gem_object *bo = to_panfrost_bo(obj); -+ struct panfrost_device *pfdev = obj->dev->dev_private; -+ -+ panfrost_mmu_unmap(bo); -+ -+ spin_lock(&pfdev->mm_lock); -+ drm_mm_remove_node(&bo->node); -+ spin_unlock(&pfdev->mm_lock); -+ -+ drm_gem_shmem_free_object(obj); -+} -+ -+static const struct drm_gem_object_funcs panfrost_gem_funcs = { -+ .free = panfrost_gem_free_object, -+ .print_info = drm_gem_shmem_print_info, -+ .pin = drm_gem_shmem_pin, -+ .unpin = drm_gem_shmem_unpin, -+ .get_sg_table = drm_gem_shmem_get_sg_table, -+ .vmap = drm_gem_shmem_vmap, -+ .vunmap = drm_gem_shmem_vunmap, -+ .vm_ops = &drm_gem_shmem_vm_ops, -+}; -+ -+/** -+ * panfrost_gem_create_object - Implementation of driver->gem_create_object. -+ * @dev: DRM device -+ * @size: Size in bytes of the memory the object will reference -+ * -+ * This lets the GEM helpers allocate object structs for us, and keep -+ * our BO stats correct. -+ */ -+struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size) -+{ -+ int ret; -+ struct panfrost_device *pfdev = dev->dev_private; -+ struct panfrost_gem_object *obj; -+ -+ obj = kzalloc(sizeof(*obj), GFP_KERNEL); -+ if (!obj) -+ return NULL; -+ -+ obj->base.base.funcs = &panfrost_gem_funcs; -+ -+ spin_lock(&pfdev->mm_lock); -+ ret = drm_mm_insert_node(&pfdev->mm, &obj->node, -+ roundup(size, PAGE_SIZE) >> PAGE_SHIFT); -+ spin_unlock(&pfdev->mm_lock); -+ if (ret) -+ goto free_obj; -+ -+ return &obj->base.base; -+ -+free_obj: -+ kfree(obj); -+ return ERR_PTR(ret); -+} -+ -+struct drm_gem_object * -+panfrost_gem_prime_import_sg_table(struct drm_device *dev, -+ struct dma_buf_attachment *attach, -+ struct sg_table *sgt) -+{ -+ struct drm_gem_object *obj; -+ struct panfrost_gem_object *pobj; -+ -+ obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt); -+ if (IS_ERR(obj)) -+ return ERR_CAST(obj); -+ -+ pobj = to_panfrost_bo(obj); -+ -+ obj->resv = attach->dmabuf->resv; -+ -+ panfrost_mmu_map(pobj); -+ -+ return obj; -+} -diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h -new file mode 100644 -index 0000000000000..045000eb5fcfd ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h -@@ -0,0 +1,29 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+ -+#ifndef __PANFROST_GEM_H__ -+#define __PANFROST_GEM_H__ -+ -+#include -+#include -+ -+struct panfrost_gem_object { -+ struct drm_gem_shmem_object base; -+ -+ struct drm_mm_node node; -+}; -+ -+static inline -+struct panfrost_gem_object *to_panfrost_bo(struct drm_gem_object *obj) -+{ -+ return container_of(to_drm_gem_shmem_obj(obj), struct panfrost_gem_object, base); -+} -+ -+struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size); -+ -+struct drm_gem_object * -+panfrost_gem_prime_import_sg_table(struct drm_device *dev, -+ struct dma_buf_attachment *attach, -+ struct sg_table *sgt); -+ -+#endif /* __PANFROST_GEM_H__ */ -diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c -new file mode 100644 -index 0000000000000..aceaf6e44a099 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c -@@ -0,0 +1,362 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright 2018 Marty E. Plummer */ -+/* Copyright 2019 Linaro, Ltd., Rob Herring */ -+/* Copyright 2019 Collabora ltd. */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "panfrost_device.h" -+#include "panfrost_features.h" -+#include "panfrost_issues.h" -+#include "panfrost_gpu.h" -+#include "panfrost_regs.h" -+ -+#define gpu_write(dev, reg, data) writel(data, dev->iomem + reg) -+#define gpu_read(dev, reg) readl(dev->iomem + reg) -+ -+static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data) -+{ -+ struct panfrost_device *pfdev = data; -+ u32 state = gpu_read(pfdev, GPU_INT_STAT); -+ u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS); -+ -+ if (!state) -+ return IRQ_NONE; -+ -+ if (state & GPU_IRQ_MASK_ERROR) { -+ u64 address = (u64) gpu_read(pfdev, GPU_FAULT_ADDRESS_HI) << 32; -+ address |= gpu_read(pfdev, GPU_FAULT_ADDRESS_LO); -+ -+ dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n", -+ fault_status & 0xFF, panfrost_exception_name(pfdev, fault_status), -+ address); -+ -+ if (state & GPU_IRQ_MULTIPLE_FAULT) -+ dev_warn(pfdev->dev, "There were multiple GPU faults - some have not been reported\n"); -+ -+ gpu_write(pfdev, GPU_INT_MASK, 0); -+ } -+ -+ gpu_write(pfdev, GPU_INT_CLEAR, state); -+ -+ return IRQ_HANDLED; -+} -+ -+int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) -+{ -+ int ret; -+ u32 val; -+ -+ gpu_write(pfdev, GPU_INT_MASK, 0); -+ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); -+ gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); -+ -+ ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, -+ val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000); -+ -+ if (ret) { -+ dev_err(pfdev->dev, "gpu soft reset timed out\n"); -+ return ret; -+ } -+ -+ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL); -+ gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL); -+ -+ return 0; -+} -+ -+static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) -+{ -+ u32 quirks = 0; -+ -+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8443) || -+ panfrost_has_hw_issue(pfdev, HW_ISSUE_11035)) -+ quirks |= SC_LS_PAUSEBUFFER_DISABLE; -+ -+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10327)) -+ quirks |= SC_SDC_DISABLE_OQ_DISCARD; -+ -+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10797)) -+ quirks |= SC_ENABLE_TEXGRD_FLAGS; -+ -+ if (!panfrost_has_hw_issue(pfdev, GPUCORE_1619)) { -+ if (panfrost_model_cmp(pfdev, 0x750) < 0) /* T60x, T62x, T72x */ -+ quirks |= SC_LS_ATTR_CHECK_DISABLE; -+ else if (panfrost_model_cmp(pfdev, 0x880) <= 0) /* T76x, T8xx */ -+ quirks |= SC_LS_ALLOW_ATTR_TYPES; -+ } -+ -+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_TLS_HASHING)) -+ quirks |= SC_TLS_HASH_ENABLE; -+ -+ if (quirks) -+ gpu_write(pfdev, GPU_SHADER_CONFIG, quirks); -+ -+ -+ quirks = gpu_read(pfdev, GPU_TILER_CONFIG); -+ -+ /* Set tiler clock gate override if required */ -+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_T76X_3953)) -+ quirks |= TC_CLOCK_GATE_OVERRIDE; -+ -+ gpu_write(pfdev, GPU_TILER_CONFIG, quirks); -+ -+ -+ quirks = gpu_read(pfdev, GPU_L2_MMU_CONFIG); -+ -+ /* Limit read & write ID width for AXI */ -+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) -+ quirks &= ~(L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS | -+ L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES); -+ else -+ quirks &= ~(L2_MMU_CONFIG_LIMIT_EXTERNAL_READS | -+ L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES); -+ -+ gpu_write(pfdev, GPU_L2_MMU_CONFIG, quirks); -+ -+ quirks = 0; -+ if ((panfrost_model_eq(pfdev, 0x860) || panfrost_model_eq(pfdev, 0x880)) && -+ pfdev->features.revision >= 0x2000) -+ quirks |= JM_MAX_JOB_THROTTLE_LIMIT << JM_JOB_THROTTLE_LIMIT_SHIFT; -+ else if (panfrost_model_eq(pfdev, 0x6000) && -+ pfdev->features.coherency_features == COHERENCY_ACE) -+ quirks |= (COHERENCY_ACE_LITE | COHERENCY_ACE) << -+ JM_FORCE_COHERENCY_FEATURES_SHIFT; -+ -+ if (quirks) -+ gpu_write(pfdev, GPU_JM_CONFIG, quirks); -+} -+ -+#define MAX_HW_REVS 6 -+ -+struct panfrost_model { -+ const char *name; -+ u32 id; -+ u32 id_mask; -+ u64 features; -+ u64 issues; -+ struct { -+ u32 revision; -+ u64 issues; -+ } revs[MAX_HW_REVS]; -+}; -+ -+#define GPU_MODEL(_name, _id, ...) \ -+{\ -+ .name = __stringify(_name), \ -+ .id = _id, \ -+ .features = hw_features_##_name, \ -+ .issues = hw_issues_##_name, \ -+ .revs = { __VA_ARGS__ }, \ -+} -+ -+#define GPU_REV_EXT(name, _rev, _p, _s, stat) \ -+{\ -+ .revision = (_rev) << 12 | (_p) << 4 | (_s), \ -+ .issues = hw_issues_##name##_r##_rev##p##_p##stat, \ -+} -+#define GPU_REV(name, r, p) GPU_REV_EXT(name, r, p, 0, ) -+ -+static const struct panfrost_model gpu_models[] = { -+ /* T60x has an oddball version */ -+ GPU_MODEL(t600, 0x600, -+ GPU_REV_EXT(t600, 0, 0, 1, _15dev0)), -+ GPU_MODEL(t620, 0x620, -+ GPU_REV(t620, 0, 1), GPU_REV(t620, 1, 0)), -+ GPU_MODEL(t720, 0x720), -+ GPU_MODEL(t760, 0x750, -+ GPU_REV(t760, 0, 0), GPU_REV(t760, 0, 1), -+ GPU_REV_EXT(t760, 0, 1, 0, _50rel0), -+ GPU_REV(t760, 0, 2), GPU_REV(t760, 0, 3)), -+ GPU_MODEL(t820, 0x820), -+ GPU_MODEL(t830, 0x830), -+ GPU_MODEL(t860, 0x860), -+ GPU_MODEL(t880, 0x880), -+ -+ GPU_MODEL(g71, 0x6000, -+ GPU_REV_EXT(g71, 0, 0, 1, _05dev0)), -+ GPU_MODEL(g72, 0x6001), -+ GPU_MODEL(g51, 0x7000), -+ GPU_MODEL(g76, 0x7001), -+ GPU_MODEL(g52, 0x7002), -+ GPU_MODEL(g31, 0x7003, -+ GPU_REV(g31, 1, 0)), -+}; -+ -+static void panfrost_gpu_init_features(struct panfrost_device *pfdev) -+{ -+ u32 gpu_id, num_js, major, minor, status, rev; -+ const char *name = "unknown"; -+ u64 hw_feat = 0; -+ u64 hw_issues = hw_issues_all; -+ const struct panfrost_model *model; -+ int i; -+ -+ pfdev->features.l2_features = gpu_read(pfdev, GPU_L2_FEATURES); -+ pfdev->features.core_features = gpu_read(pfdev, GPU_CORE_FEATURES); -+ pfdev->features.tiler_features = gpu_read(pfdev, GPU_TILER_FEATURES); -+ pfdev->features.mem_features = gpu_read(pfdev, GPU_MEM_FEATURES); -+ pfdev->features.mmu_features = gpu_read(pfdev, GPU_MMU_FEATURES); -+ pfdev->features.thread_features = gpu_read(pfdev, GPU_THREAD_FEATURES); -+ pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES); -+ for (i = 0; i < 4; i++) -+ pfdev->features.texture_features[i] = gpu_read(pfdev, GPU_TEXTURE_FEATURES(i)); -+ -+ pfdev->features.as_present = gpu_read(pfdev, GPU_AS_PRESENT); -+ -+ pfdev->features.js_present = gpu_read(pfdev, GPU_JS_PRESENT); -+ num_js = hweight32(pfdev->features.js_present); -+ for (i = 0; i < num_js; i++) -+ pfdev->features.js_features[i] = gpu_read(pfdev, GPU_JS_FEATURES(i)); -+ -+ pfdev->features.shader_present = gpu_read(pfdev, GPU_SHADER_PRESENT_LO); -+ pfdev->features.shader_present |= (u64)gpu_read(pfdev, GPU_SHADER_PRESENT_HI) << 32; -+ -+ pfdev->features.tiler_present = gpu_read(pfdev, GPU_TILER_PRESENT_LO); -+ pfdev->features.tiler_present |= (u64)gpu_read(pfdev, GPU_TILER_PRESENT_HI) << 32; -+ -+ pfdev->features.l2_present = gpu_read(pfdev, GPU_L2_PRESENT_LO); -+ pfdev->features.l2_present |= (u64)gpu_read(pfdev, GPU_L2_PRESENT_HI) << 32; -+ pfdev->features.nr_core_groups = hweight64(pfdev->features.l2_present); -+ -+ pfdev->features.stack_present = gpu_read(pfdev, GPU_STACK_PRESENT_LO); -+ pfdev->features.stack_present |= (u64)gpu_read(pfdev, GPU_STACK_PRESENT_HI) << 32; -+ -+ gpu_id = gpu_read(pfdev, GPU_ID); -+ pfdev->features.revision = gpu_id & 0xffff; -+ pfdev->features.id = gpu_id >> 16; -+ -+ /* The T60x has an oddball ID value. Fix it up to the standard Midgard -+ * format so we (and userspace) don't have to special case it. -+ */ -+ if (pfdev->features.id == 0x6956) -+ pfdev->features.id = 0x0600; -+ -+ major = (pfdev->features.revision >> 12) & 0xf; -+ minor = (pfdev->features.revision >> 4) & 0xff; -+ status = pfdev->features.revision & 0xf; -+ rev = pfdev->features.revision; -+ -+ gpu_id = pfdev->features.id; -+ -+ for (model = gpu_models; model->name; model++) { -+ int best = -1; -+ -+ if (!panfrost_model_eq(pfdev, model->id)) -+ continue; -+ -+ name = model->name; -+ hw_feat = model->features; -+ hw_issues |= model->issues; -+ for (i = 0; i < MAX_HW_REVS; i++) { -+ if (model->revs[i].revision == rev) { -+ best = i; -+ break; -+ } else if (model->revs[i].revision == (rev & ~0xf)) -+ best = i; -+ } -+ -+ if (best >= 0) -+ hw_issues |= model->revs[best].issues; -+ -+ break; -+ } -+ -+ bitmap_from_u64(pfdev->features.hw_features, hw_feat); -+ bitmap_from_u64(pfdev->features.hw_issues, hw_issues); -+ -+ dev_info(pfdev->dev, "mali-%s id 0x%x major 0x%x minor 0x%x status 0x%x", -+ name, gpu_id, major, minor, status); -+ dev_info(pfdev->dev, "features: %64pb, issues: %64pb", -+ pfdev->features.hw_features, -+ pfdev->features.hw_issues); -+ -+ dev_info(pfdev->dev, "Features: L2:0x%08x Shader:0x%08x Tiler:0x%08x Mem:0x%0x MMU:0x%08x AS:0x%x JS:0x%x", -+ gpu_read(pfdev, GPU_L2_FEATURES), -+ gpu_read(pfdev, GPU_CORE_FEATURES), -+ gpu_read(pfdev, GPU_TILER_FEATURES), -+ gpu_read(pfdev, GPU_MEM_FEATURES), -+ gpu_read(pfdev, GPU_MMU_FEATURES), -+ gpu_read(pfdev, GPU_AS_PRESENT), -+ gpu_read(pfdev, GPU_JS_PRESENT)); -+ -+ dev_info(pfdev->dev, "shader_present=0x%0llx l2_present=0x%0llx", -+ pfdev->features.shader_present, pfdev->features.l2_present); -+} -+ -+void panfrost_gpu_power_on(struct panfrost_device *pfdev) -+{ -+ int ret; -+ u32 val; -+ -+ /* Just turn on everything for now */ -+ gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present); -+ ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, -+ val, val == pfdev->features.l2_present, 100, 1000); -+ -+ gpu_write(pfdev, STACK_PWRON_LO, pfdev->features.stack_present); -+ ret |= readl_relaxed_poll_timeout(pfdev->iomem + STACK_READY_LO, -+ val, val == pfdev->features.stack_present, 100, 1000); -+ -+ gpu_write(pfdev, SHADER_PWRON_LO, pfdev->features.shader_present); -+ ret |= readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, -+ val, val == pfdev->features.shader_present, 100, 1000); -+ -+ gpu_write(pfdev, TILER_PWRON_LO, pfdev->features.tiler_present); -+ ret |= readl_relaxed_poll_timeout(pfdev->iomem + TILER_READY_LO, -+ val, val == pfdev->features.tiler_present, 100, 1000); -+ -+ if (ret) -+ dev_err(pfdev->dev, "error powering up gpu"); -+} -+ -+void panfrost_gpu_power_off(struct panfrost_device *pfdev) -+{ -+ gpu_write(pfdev, TILER_PWROFF_LO, 0); -+ gpu_write(pfdev, SHADER_PWROFF_LO, 0); -+ gpu_write(pfdev, STACK_PWROFF_LO, 0); -+ gpu_write(pfdev, L2_PWROFF_LO, 0); -+} -+ -+int panfrost_gpu_init(struct panfrost_device *pfdev) -+{ -+ int err, irq; -+ -+ err = panfrost_gpu_soft_reset(pfdev); -+ if (err) -+ return err; -+ -+ panfrost_gpu_init_features(pfdev); -+ -+ irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); -+ if (irq <= 0) -+ return -ENODEV; -+ -+ err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler, -+ IRQF_SHARED, "gpu", pfdev); -+ if (err) { -+ dev_err(pfdev->dev, "failed to request gpu irq"); -+ return err; -+ } -+ -+ panfrost_gpu_init_quirks(pfdev); -+ panfrost_gpu_power_on(pfdev); -+ -+ return 0; -+} -+ -+void panfrost_gpu_fini(struct panfrost_device *pfdev) -+{ -+ panfrost_gpu_power_off(pfdev); -+} -+ -+u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) -+{ -+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) -+ return gpu_read(pfdev, GPU_LATEST_FLUSH_ID); -+ return 0; -+} -diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h -new file mode 100644 -index 0000000000000..4112412087b27 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h -@@ -0,0 +1,19 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2018 Marty E. Plummer */ -+/* Copyright 2019 Collabora ltd. */ -+ -+#ifndef __PANFROST_GPU_H__ -+#define __PANFROST_GPU_H__ -+ -+struct panfrost_device; -+ -+int panfrost_gpu_init(struct panfrost_device *pfdev); -+void panfrost_gpu_fini(struct panfrost_device *pfdev); -+ -+u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev); -+ -+int panfrost_gpu_soft_reset(struct panfrost_device *pfdev); -+void panfrost_gpu_power_on(struct panfrost_device *pfdev); -+void panfrost_gpu_power_off(struct panfrost_device *pfdev); -+ -+#endif -diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h -new file mode 100644 -index 0000000000000..cec6dcdadb5c3 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_issues.h -@@ -0,0 +1,176 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* (C) COPYRIGHT 2014-2018 ARM Limited. All rights reserved. */ -+/* Copyright 2019 Linaro, Ltd., Rob Herring */ -+#ifndef __PANFROST_ISSUES_H__ -+#define __PANFROST_ISSUES_H__ -+ -+#include -+ -+#include "panfrost_device.h" -+ -+/* -+ * This is not a complete list of issues, but only the ones the driver needs -+ * to care about. -+ */ -+enum panfrost_hw_issue { -+ HW_ISSUE_6367, -+ HW_ISSUE_6787, -+ HW_ISSUE_8186, -+ HW_ISSUE_8245, -+ HW_ISSUE_8316, -+ HW_ISSUE_8394, -+ HW_ISSUE_8401, -+ HW_ISSUE_8408, -+ HW_ISSUE_8443, -+ HW_ISSUE_8987, -+ HW_ISSUE_9435, -+ HW_ISSUE_9510, -+ HW_ISSUE_9630, -+ HW_ISSUE_10327, -+ HW_ISSUE_10649, -+ HW_ISSUE_10676, -+ HW_ISSUE_10797, -+ HW_ISSUE_10817, -+ HW_ISSUE_10883, -+ HW_ISSUE_10959, -+ HW_ISSUE_10969, -+ HW_ISSUE_11020, -+ HW_ISSUE_11024, -+ HW_ISSUE_11035, -+ HW_ISSUE_11056, -+ HW_ISSUE_T76X_3542, -+ HW_ISSUE_T76X_3953, -+ HW_ISSUE_TMIX_8463, -+ GPUCORE_1619, -+ HW_ISSUE_TMIX_8438, -+ HW_ISSUE_TGOX_R1_1234, -+ HW_ISSUE_END -+}; -+ -+#define hw_issues_all (\ -+ BIT_ULL(HW_ISSUE_9435)) -+ -+#define hw_issues_t600 (\ -+ BIT_ULL(HW_ISSUE_6367) | \ -+ BIT_ULL(HW_ISSUE_6787) | \ -+ BIT_ULL(HW_ISSUE_8408) | \ -+ BIT_ULL(HW_ISSUE_9510) | \ -+ BIT_ULL(HW_ISSUE_10649) | \ -+ BIT_ULL(HW_ISSUE_10676) | \ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_11020) | \ -+ BIT_ULL(HW_ISSUE_11035) | \ -+ BIT_ULL(HW_ISSUE_11056) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_t600_r0p0_15dev0 (\ -+ BIT_ULL(HW_ISSUE_8186) | \ -+ BIT_ULL(HW_ISSUE_8245) | \ -+ BIT_ULL(HW_ISSUE_8316) | \ -+ BIT_ULL(HW_ISSUE_8394) | \ -+ BIT_ULL(HW_ISSUE_8401) | \ -+ BIT_ULL(HW_ISSUE_8443) | \ -+ BIT_ULL(HW_ISSUE_8987) | \ -+ BIT_ULL(HW_ISSUE_9630) | \ -+ BIT_ULL(HW_ISSUE_10969) | \ -+ BIT_ULL(GPUCORE_1619)) -+ -+#define hw_issues_t620 (\ -+ BIT_ULL(HW_ISSUE_10649) | \ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_10959) | \ -+ BIT_ULL(HW_ISSUE_11056) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_t620_r0p1 (\ -+ BIT_ULL(HW_ISSUE_10327) | \ -+ BIT_ULL(HW_ISSUE_10676) | \ -+ BIT_ULL(HW_ISSUE_10817) | \ -+ BIT_ULL(HW_ISSUE_11020) | \ -+ BIT_ULL(HW_ISSUE_11024) | \ -+ BIT_ULL(HW_ISSUE_11035)) -+ -+#define hw_issues_t620_r1p0 (\ -+ BIT_ULL(HW_ISSUE_11020) | \ -+ BIT_ULL(HW_ISSUE_11024)) -+ -+#define hw_issues_t720 (\ -+ BIT_ULL(HW_ISSUE_10649) | \ -+ BIT_ULL(HW_ISSUE_10797) | \ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_11056) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_t760 (\ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_T76X_3953) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_t760_r0p0 (\ -+ BIT_ULL(HW_ISSUE_11020) | \ -+ BIT_ULL(HW_ISSUE_11024) | \ -+ BIT_ULL(HW_ISSUE_T76X_3542)) -+ -+#define hw_issues_t760_r0p1 (\ -+ BIT_ULL(HW_ISSUE_11020) | \ -+ BIT_ULL(HW_ISSUE_11024) | \ -+ BIT_ULL(HW_ISSUE_T76X_3542)) -+ -+#define hw_issues_t760_r0p1_50rel0 (\ -+ BIT_ULL(HW_ISSUE_T76X_3542)) -+ -+#define hw_issues_t760_r0p2 (\ -+ BIT_ULL(HW_ISSUE_11020) | \ -+ BIT_ULL(HW_ISSUE_11024) | \ -+ BIT_ULL(HW_ISSUE_T76X_3542)) -+ -+#define hw_issues_t760_r0p3 (\ -+ BIT_ULL(HW_ISSUE_T76X_3542)) -+ -+#define hw_issues_t820 (\ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_T76X_3953) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_t830 (\ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_T76X_3953) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_t860 (\ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_T76X_3953) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_t880 (\ -+ BIT_ULL(HW_ISSUE_10883) | \ -+ BIT_ULL(HW_ISSUE_T76X_3953) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_g31 0 -+ -+#define hw_issues_g31_r1p0 (\ -+ BIT_ULL(HW_ISSUE_TGOX_R1_1234)) -+ -+#define hw_issues_g51 0 -+ -+#define hw_issues_g52 0 -+ -+#define hw_issues_g71 (\ -+ BIT_ULL(HW_ISSUE_TMIX_8463) | \ -+ BIT_ULL(HW_ISSUE_TMIX_8438)) -+ -+#define hw_issues_g71_r0p0_05dev0 (\ -+ BIT_ULL(HW_ISSUE_T76X_3953)) -+ -+#define hw_issues_g72 0 -+ -+#define hw_issues_g76 0 -+ -+static inline bool panfrost_has_hw_issue(struct panfrost_device *pfdev, -+ enum panfrost_hw_issue issue) -+{ -+ return test_bit(issue, pfdev->features.hw_issues); -+} -+ -+#endif /* __PANFROST_ISSUES_H__ */ -diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c -new file mode 100644 -index 0000000000000..0a7ed04f7d52b ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_job.c -@@ -0,0 +1,560 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+/* Copyright 2019 Collabora ltd. */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "panfrost_device.h" -+#include "panfrost_devfreq.h" -+#include "panfrost_job.h" -+#include "panfrost_features.h" -+#include "panfrost_issues.h" -+#include "panfrost_gem.h" -+#include "panfrost_regs.h" -+#include "panfrost_gpu.h" -+#include "panfrost_mmu.h" -+ -+#define job_write(dev, reg, data) writel(data, dev->iomem + (reg)) -+#define job_read(dev, reg) readl(dev->iomem + (reg)) -+ -+struct panfrost_queue_state { -+ struct drm_gpu_scheduler sched; -+ -+ u64 fence_context; -+ u64 emit_seqno; -+}; -+ -+struct panfrost_job_slot { -+ struct panfrost_queue_state queue[NUM_JOB_SLOTS]; -+ spinlock_t job_lock; -+}; -+ -+static struct panfrost_job * -+to_panfrost_job(struct drm_sched_job *sched_job) -+{ -+ return container_of(sched_job, struct panfrost_job, base); -+} -+ -+struct panfrost_fence { -+ struct dma_fence base; -+ struct drm_device *dev; -+ /* panfrost seqno for signaled() test */ -+ u64 seqno; -+ int queue; -+}; -+ -+static inline struct panfrost_fence * -+to_panfrost_fence(struct dma_fence *fence) -+{ -+ return (struct panfrost_fence *)fence; -+} -+ -+static const char *panfrost_fence_get_driver_name(struct dma_fence *fence) -+{ -+ return "panfrost"; -+} -+ -+static const char *panfrost_fence_get_timeline_name(struct dma_fence *fence) -+{ -+ struct panfrost_fence *f = to_panfrost_fence(fence); -+ -+ switch (f->queue) { -+ case 0: -+ return "panfrost-js-0"; -+ case 1: -+ return "panfrost-js-1"; -+ case 2: -+ return "panfrost-js-2"; -+ default: -+ return NULL; -+ } -+} -+ -+static const struct dma_fence_ops panfrost_fence_ops = { -+ .get_driver_name = panfrost_fence_get_driver_name, -+ .get_timeline_name = panfrost_fence_get_timeline_name, -+}; -+ -+static struct dma_fence *panfrost_fence_create(struct panfrost_device *pfdev, int js_num) -+{ -+ struct panfrost_fence *fence; -+ struct panfrost_job_slot *js = pfdev->js; -+ -+ fence = kzalloc(sizeof(*fence), GFP_KERNEL); -+ if (!fence) -+ return ERR_PTR(-ENOMEM); -+ -+ fence->dev = pfdev->ddev; -+ fence->queue = js_num; -+ fence->seqno = ++js->queue[js_num].emit_seqno; -+ dma_fence_init(&fence->base, &panfrost_fence_ops, &js->job_lock, -+ js->queue[js_num].fence_context, fence->seqno); -+ -+ return &fence->base; -+} -+ -+static int panfrost_job_get_slot(struct panfrost_job *job) -+{ -+ /* JS0: fragment jobs. -+ * JS1: vertex/tiler jobs -+ * JS2: compute jobs -+ */ -+ if (job->requirements & PANFROST_JD_REQ_FS) -+ return 0; -+ -+/* Not exposed to userspace yet */ -+#if 0 -+ if (job->requirements & PANFROST_JD_REQ_ONLY_COMPUTE) { -+ if ((job->requirements & PANFROST_JD_REQ_CORE_GRP_MASK) && -+ (job->pfdev->features.nr_core_groups == 2)) -+ return 2; -+ if (panfrost_has_hw_issue(job->pfdev, HW_ISSUE_8987)) -+ return 2; -+ } -+#endif -+ return 1; -+} -+ -+static void panfrost_job_write_affinity(struct panfrost_device *pfdev, -+ u32 requirements, -+ int js) -+{ -+ u64 affinity; -+ -+ /* -+ * Use all cores for now. -+ * Eventually we may need to support tiler only jobs and h/w with -+ * multiple (2) coherent core groups -+ */ -+ affinity = pfdev->features.shader_present; -+ -+ job_write(pfdev, JS_AFFINITY_NEXT_LO(js), affinity & 0xFFFFFFFF); -+ job_write(pfdev, JS_AFFINITY_NEXT_HI(js), affinity >> 32); -+} -+ -+static void panfrost_job_hw_submit(struct panfrost_job *job, int js) -+{ -+ struct panfrost_device *pfdev = job->pfdev; -+ unsigned long flags; -+ u32 cfg; -+ u64 jc_head = job->jc; -+ int ret; -+ -+ ret = pm_runtime_get_sync(pfdev->dev); -+ if (ret < 0) -+ return; -+ -+ if (WARN_ON(job_read(pfdev, JS_COMMAND_NEXT(js)))) -+ goto end; -+ -+ panfrost_devfreq_record_transition(pfdev, js); -+ spin_lock_irqsave(&pfdev->hwaccess_lock, flags); -+ -+ job_write(pfdev, JS_HEAD_NEXT_LO(js), jc_head & 0xFFFFFFFF); -+ job_write(pfdev, JS_HEAD_NEXT_HI(js), jc_head >> 32); -+ -+ panfrost_job_write_affinity(pfdev, job->requirements, js); -+ -+ /* start MMU, medium priority, cache clean/flush on end, clean/flush on -+ * start */ -+ /* TODO: different address spaces */ -+ cfg = JS_CONFIG_THREAD_PRI(8) | -+ JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE | -+ JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE; -+ -+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) -+ cfg |= JS_CONFIG_ENABLE_FLUSH_REDUCTION; -+ -+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10649)) -+ cfg |= JS_CONFIG_START_MMU; -+ -+ job_write(pfdev, JS_CONFIG_NEXT(js), cfg); -+ -+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) -+ job_write(pfdev, JS_FLUSH_ID_NEXT(js), job->flush_id); -+ -+ /* GO ! */ -+ dev_dbg(pfdev->dev, "JS: Submitting atom %p to js[%d] with head=0x%llx", -+ job, js, jc_head); -+ -+ job_write(pfdev, JS_COMMAND_NEXT(js), JS_COMMAND_START); -+ -+ spin_unlock_irqrestore(&pfdev->hwaccess_lock, flags); -+ -+end: -+ pm_runtime_mark_last_busy(pfdev->dev); -+ pm_runtime_put_autosuspend(pfdev->dev); -+} -+ -+static void panfrost_acquire_object_fences(struct drm_gem_object **bos, -+ int bo_count, -+ struct dma_fence **implicit_fences) -+{ -+ int i; -+ -+ for (i = 0; i < bo_count; i++) -+ implicit_fences[i] = reservation_object_get_excl_rcu(bos[i]->resv); -+} -+ -+static void panfrost_attach_object_fences(struct drm_gem_object **bos, -+ int bo_count, -+ struct dma_fence *fence) -+{ -+ int i; -+ -+ for (i = 0; i < bo_count; i++) -+ reservation_object_add_excl_fence(bos[i]->resv, fence); -+} -+ -+int panfrost_job_push(struct panfrost_job *job) -+{ -+ struct panfrost_device *pfdev = job->pfdev; -+ int slot = panfrost_job_get_slot(job); -+ struct drm_sched_entity *entity = &job->file_priv->sched_entity[slot]; -+ struct ww_acquire_ctx acquire_ctx; -+ int ret = 0; -+ -+ mutex_lock(&pfdev->sched_lock); -+ -+ ret = drm_gem_lock_reservations(job->bos, job->bo_count, -+ &acquire_ctx); -+ if (ret) { -+ mutex_unlock(&pfdev->sched_lock); -+ return ret; -+ } -+ -+ ret = drm_sched_job_init(&job->base, entity, NULL); -+ if (ret) { -+ mutex_unlock(&pfdev->sched_lock); -+ goto unlock; -+ } -+ -+ job->render_done_fence = dma_fence_get(&job->base.s_fence->finished); -+ -+ kref_get(&job->refcount); /* put by scheduler job completion */ -+ -+ panfrost_acquire_object_fences(job->bos, job->bo_count, -+ job->implicit_fences); -+ -+ drm_sched_entity_push_job(&job->base, entity); -+ -+ mutex_unlock(&pfdev->sched_lock); -+ -+ panfrost_attach_object_fences(job->bos, job->bo_count, -+ job->render_done_fence); -+ -+unlock: -+ drm_gem_unlock_reservations(job->bos, job->bo_count, &acquire_ctx); -+ -+ return ret; -+} -+ -+static void panfrost_job_cleanup(struct kref *ref) -+{ -+ struct panfrost_job *job = container_of(ref, struct panfrost_job, -+ refcount); -+ unsigned int i; -+ -+ if (job->in_fences) { -+ for (i = 0; i < job->in_fence_count; i++) -+ dma_fence_put(job->in_fences[i]); -+ kvfree(job->in_fences); -+ } -+ if (job->implicit_fences) { -+ for (i = 0; i < job->bo_count; i++) -+ dma_fence_put(job->implicit_fences[i]); -+ kvfree(job->implicit_fences); -+ } -+ dma_fence_put(job->done_fence); -+ dma_fence_put(job->render_done_fence); -+ -+ if (job->bos) { -+ for (i = 0; i < job->bo_count; i++) -+ drm_gem_object_put_unlocked(job->bos[i]); -+ kvfree(job->bos); -+ } -+ -+ kfree(job); -+} -+ -+void panfrost_job_put(struct panfrost_job *job) -+{ -+ kref_put(&job->refcount, panfrost_job_cleanup); -+} -+ -+static void panfrost_job_free(struct drm_sched_job *sched_job) -+{ -+ struct panfrost_job *job = to_panfrost_job(sched_job); -+ -+ drm_sched_job_cleanup(sched_job); -+ -+ panfrost_job_put(job); -+} -+ -+static struct dma_fence *panfrost_job_dependency(struct drm_sched_job *sched_job, -+ struct drm_sched_entity *s_entity) -+{ -+ struct panfrost_job *job = to_panfrost_job(sched_job); -+ struct dma_fence *fence; -+ unsigned int i; -+ -+ /* Explicit fences */ -+ for (i = 0; i < job->in_fence_count; i++) { -+ if (job->in_fences[i]) { -+ fence = job->in_fences[i]; -+ job->in_fences[i] = NULL; -+ return fence; -+ } -+ } -+ -+ /* Implicit fences, max. one per BO */ -+ for (i = 0; i < job->bo_count; i++) { -+ if (job->implicit_fences[i]) { -+ fence = job->implicit_fences[i]; -+ job->implicit_fences[i] = NULL; -+ return fence; -+ } -+ } -+ -+ return NULL; -+} -+ -+static struct dma_fence *panfrost_job_run(struct drm_sched_job *sched_job) -+{ -+ struct panfrost_job *job = to_panfrost_job(sched_job); -+ struct panfrost_device *pfdev = job->pfdev; -+ int slot = panfrost_job_get_slot(job); -+ struct dma_fence *fence = NULL; -+ -+ if (unlikely(job->base.s_fence->finished.error)) -+ return NULL; -+ -+ pfdev->jobs[slot] = job; -+ -+ fence = panfrost_fence_create(pfdev, slot); -+ if (IS_ERR(fence)) -+ return NULL; -+ -+ if (job->done_fence) -+ dma_fence_put(job->done_fence); -+ job->done_fence = dma_fence_get(fence); -+ -+ panfrost_job_hw_submit(job, slot); -+ -+ return fence; -+} -+ -+void panfrost_job_enable_interrupts(struct panfrost_device *pfdev) -+{ -+ int j; -+ u32 irq_mask = 0; -+ -+ for (j = 0; j < NUM_JOB_SLOTS; j++) { -+ irq_mask |= MK_JS_MASK(j); -+ } -+ -+ job_write(pfdev, JOB_INT_CLEAR, irq_mask); -+ job_write(pfdev, JOB_INT_MASK, irq_mask); -+} -+ -+static void panfrost_job_timedout(struct drm_sched_job *sched_job) -+{ -+ struct panfrost_job *job = to_panfrost_job(sched_job); -+ struct panfrost_device *pfdev = job->pfdev; -+ int js = panfrost_job_get_slot(job); -+ int i; -+ -+ /* -+ * If the GPU managed to complete this jobs fence, the timeout is -+ * spurious. Bail out. -+ */ -+ if (dma_fence_is_signaled(job->done_fence)) -+ return; -+ -+ dev_err(pfdev->dev, "gpu sched timeout, js=%d, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p", -+ js, -+ job_read(pfdev, JS_STATUS(js)), -+ job_read(pfdev, JS_HEAD_LO(js)), -+ job_read(pfdev, JS_TAIL_LO(js)), -+ sched_job); -+ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) -+ drm_sched_stop(&pfdev->js->queue[i].sched); -+ -+ if (sched_job) -+ drm_sched_increase_karma(sched_job); -+ -+ /* panfrost_core_dump(pfdev); */ -+ -+ panfrost_devfreq_record_transition(pfdev, js); -+ panfrost_gpu_soft_reset(pfdev); -+ -+ /* TODO: Re-enable all other address spaces */ -+ panfrost_mmu_enable(pfdev, 0); -+ panfrost_gpu_power_on(pfdev); -+ panfrost_job_enable_interrupts(pfdev); -+ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) -+ drm_sched_resubmit_jobs(&pfdev->js->queue[i].sched); -+ -+ /* restart scheduler after GPU is usable again */ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) -+ drm_sched_start(&pfdev->js->queue[i].sched, true); -+} -+ -+static const struct drm_sched_backend_ops panfrost_sched_ops = { -+ .dependency = panfrost_job_dependency, -+ .run_job = panfrost_job_run, -+ .timedout_job = panfrost_job_timedout, -+ .free_job = panfrost_job_free -+}; -+ -+static irqreturn_t panfrost_job_irq_handler(int irq, void *data) -+{ -+ struct panfrost_device *pfdev = data; -+ u32 status = job_read(pfdev, JOB_INT_STAT); -+ int j; -+ -+ dev_dbg(pfdev->dev, "jobslot irq status=%x\n", status); -+ -+ if (!status) -+ return IRQ_NONE; -+ -+ pm_runtime_mark_last_busy(pfdev->dev); -+ -+ for (j = 0; status; j++) { -+ u32 mask = MK_JS_MASK(j); -+ -+ if (!(status & mask)) -+ continue; -+ -+ job_write(pfdev, JOB_INT_CLEAR, mask); -+ -+ if (status & JOB_INT_MASK_ERR(j)) { -+ job_write(pfdev, JS_COMMAND_NEXT(j), JS_COMMAND_NOP); -+ -+ dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x", -+ j, -+ panfrost_exception_name(pfdev, job_read(pfdev, JS_STATUS(j))), -+ job_read(pfdev, JS_HEAD_LO(j)), -+ job_read(pfdev, JS_TAIL_LO(j))); -+ -+ drm_sched_fault(&pfdev->js->queue[j].sched); -+ } -+ -+ if (status & JOB_INT_MASK_DONE(j)) { -+ panfrost_devfreq_record_transition(pfdev, j); -+ dma_fence_signal(pfdev->jobs[j]->done_fence); -+ } -+ -+ status &= ~mask; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+int panfrost_job_init(struct panfrost_device *pfdev) -+{ -+ struct panfrost_job_slot *js; -+ int ret, j, irq; -+ -+ pfdev->js = js = devm_kzalloc(pfdev->dev, sizeof(*js), GFP_KERNEL); -+ if (!js) -+ return -ENOMEM; -+ -+ spin_lock_init(&js->job_lock); -+ -+ irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "job"); -+ if (irq <= 0) -+ return -ENODEV; -+ -+ ret = devm_request_irq(pfdev->dev, irq, panfrost_job_irq_handler, -+ IRQF_SHARED, "job", pfdev); -+ if (ret) { -+ dev_err(pfdev->dev, "failed to request job irq"); -+ return ret; -+ } -+ -+ for (j = 0; j < NUM_JOB_SLOTS; j++) { -+ js->queue[j].fence_context = dma_fence_context_alloc(1); -+ -+ ret = drm_sched_init(&js->queue[j].sched, -+ &panfrost_sched_ops, -+ 1, 0, msecs_to_jiffies(500), -+ "pan_js"); -+ if (ret) { -+ dev_err(pfdev->dev, "Failed to create scheduler: %d.", ret); -+ goto err_sched; -+ } -+ } -+ -+ panfrost_job_enable_interrupts(pfdev); -+ -+ return 0; -+ -+err_sched: -+ for (j--; j >= 0; j--) -+ drm_sched_fini(&js->queue[j].sched); -+ -+ return ret; -+} -+ -+void panfrost_job_fini(struct panfrost_device *pfdev) -+{ -+ struct panfrost_job_slot *js = pfdev->js; -+ int j; -+ -+ job_write(pfdev, JOB_INT_MASK, 0); -+ -+ for (j = 0; j < NUM_JOB_SLOTS; j++) -+ drm_sched_fini(&js->queue[j].sched); -+ -+} -+ -+int panfrost_job_open(struct panfrost_file_priv *panfrost_priv) -+{ -+ struct panfrost_device *pfdev = panfrost_priv->pfdev; -+ struct panfrost_job_slot *js = pfdev->js; -+ struct drm_sched_rq *rq; -+ int ret, i; -+ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) { -+ rq = &js->queue[i].sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; -+ ret = drm_sched_entity_init(&panfrost_priv->sched_entity[i], &rq, 1, NULL); -+ if (WARN_ON(ret)) -+ return ret; -+ } -+ return 0; -+} -+ -+void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) -+{ -+ int i; -+ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) -+ drm_sched_entity_destroy(&panfrost_priv->sched_entity[i]); -+} -+ -+int panfrost_job_is_idle(struct panfrost_device *pfdev) -+{ -+ struct panfrost_job_slot *js = pfdev->js; -+ int i; -+ -+ for (i = 0; i < NUM_JOB_SLOTS; i++) { -+ /* If there are any jobs in the HW queue, we're not idle */ -+ if (atomic_read(&js->queue[i].sched.hw_rq_count)) -+ return false; -+ -+ /* Check whether the hardware is idle */ -+ if (pfdev->devfreq.slot[i].busy) -+ return false; -+ } -+ -+ return true; -+} -diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h -new file mode 100644 -index 0000000000000..62454128a792e ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_job.h -@@ -0,0 +1,51 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2019 Collabora ltd. */ -+ -+#ifndef __PANFROST_JOB_H__ -+#define __PANFROST_JOB_H__ -+ -+#include -+#include -+ -+struct panfrost_device; -+struct panfrost_gem_object; -+struct panfrost_file_priv; -+ -+struct panfrost_job { -+ struct drm_sched_job base; -+ -+ struct kref refcount; -+ -+ struct panfrost_device *pfdev; -+ struct panfrost_file_priv *file_priv; -+ -+ /* Optional fences userspace can pass in for the job to depend on. */ -+ struct dma_fence **in_fences; -+ u32 in_fence_count; -+ -+ /* Fence to be signaled by IRQ handler when the job is complete. */ -+ struct dma_fence *done_fence; -+ -+ __u64 jc; -+ __u32 requirements; -+ __u32 flush_id; -+ -+ /* Exclusive fences we have taken from the BOs to wait for */ -+ struct dma_fence **implicit_fences; -+ struct drm_gem_object **bos; -+ u32 bo_count; -+ -+ /* Fence to be signaled by drm-sched once its done with the job */ -+ struct dma_fence *render_done_fence; -+}; -+ -+int panfrost_job_init(struct panfrost_device *pfdev); -+void panfrost_job_fini(struct panfrost_device *pfdev); -+int panfrost_job_open(struct panfrost_file_priv *panfrost_priv); -+void panfrost_job_close(struct panfrost_file_priv *panfrost_priv); -+int panfrost_job_push(struct panfrost_job *job); -+void panfrost_job_put(struct panfrost_job *job); -+void panfrost_job_enable_interrupts(struct panfrost_device *pfdev); -+int panfrost_job_is_idle(struct panfrost_device *pfdev); -+ -+#endif -diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c -new file mode 100644 -index 0000000000000..9692c18df785e ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c -@@ -0,0 +1,369 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "panfrost_device.h" -+#include "panfrost_mmu.h" -+#include "panfrost_gem.h" -+#include "panfrost_features.h" -+#include "panfrost_regs.h" -+ -+#define mmu_write(dev, reg, data) writel(data, dev->iomem + reg) -+#define mmu_read(dev, reg) readl(dev->iomem + reg) -+ -+struct panfrost_mmu { -+ struct io_pgtable_cfg pgtbl_cfg; -+ struct io_pgtable_ops *pgtbl_ops; -+ struct mutex lock; -+}; -+ -+static int wait_ready(struct panfrost_device *pfdev, u32 as_nr) -+{ -+ int ret; -+ u32 val; -+ -+ /* Wait for the MMU status to indicate there is no active command, in -+ * case one is pending. */ -+ ret = readl_relaxed_poll_timeout_atomic(pfdev->iomem + AS_STATUS(as_nr), -+ val, !(val & AS_STATUS_AS_ACTIVE), 10, 1000); -+ -+ if (ret) -+ dev_err(pfdev->dev, "AS_ACTIVE bit stuck\n"); -+ -+ return ret; -+} -+ -+static int write_cmd(struct panfrost_device *pfdev, u32 as_nr, u32 cmd) -+{ -+ int status; -+ -+ /* write AS_COMMAND when MMU is ready to accept another command */ -+ status = wait_ready(pfdev, as_nr); -+ if (!status) -+ mmu_write(pfdev, AS_COMMAND(as_nr), cmd); -+ -+ return status; -+} -+ -+static void lock_region(struct panfrost_device *pfdev, u32 as_nr, -+ u64 iova, size_t size) -+{ -+ u8 region_width; -+ u64 region = iova & PAGE_MASK; -+ /* -+ * fls returns: -+ * 1 .. 32 -+ * -+ * 10 + fls(num_pages) -+ * results in the range (11 .. 42) -+ */ -+ -+ size = round_up(size, PAGE_SIZE); -+ -+ region_width = 10 + fls(size >> PAGE_SHIFT); -+ if ((size >> PAGE_SHIFT) != (1ul << (region_width - 11))) { -+ /* not pow2, so must go up to the next pow2 */ -+ region_width += 1; -+ } -+ region |= region_width; -+ -+ /* Lock the region that needs to be updated */ -+ mmu_write(pfdev, AS_LOCKADDR_LO(as_nr), region & 0xFFFFFFFFUL); -+ mmu_write(pfdev, AS_LOCKADDR_HI(as_nr), (region >> 32) & 0xFFFFFFFFUL); -+ write_cmd(pfdev, as_nr, AS_COMMAND_LOCK); -+} -+ -+ -+static int mmu_hw_do_operation(struct panfrost_device *pfdev, u32 as_nr, -+ u64 iova, size_t size, u32 op) -+{ -+ unsigned long flags; -+ int ret; -+ -+ spin_lock_irqsave(&pfdev->hwaccess_lock, flags); -+ -+ if (op != AS_COMMAND_UNLOCK) -+ lock_region(pfdev, as_nr, iova, size); -+ -+ /* Run the MMU operation */ -+ write_cmd(pfdev, as_nr, op); -+ -+ /* Wait for the flush to complete */ -+ ret = wait_ready(pfdev, as_nr); -+ -+ spin_unlock_irqrestore(&pfdev->hwaccess_lock, flags); -+ -+ return ret; -+} -+ -+void panfrost_mmu_enable(struct panfrost_device *pfdev, u32 as_nr) -+{ -+ struct io_pgtable_cfg *cfg = &pfdev->mmu->pgtbl_cfg; -+ u64 transtab = cfg->arm_mali_lpae_cfg.transtab; -+ u64 memattr = cfg->arm_mali_lpae_cfg.memattr; -+ -+ mmu_write(pfdev, MMU_INT_CLEAR, ~0); -+ mmu_write(pfdev, MMU_INT_MASK, ~0); -+ -+ mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), transtab & 0xffffffffUL); -+ mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), transtab >> 32); -+ -+ /* Need to revisit mem attrs. -+ * NC is the default, Mali driver is inner WT. -+ */ -+ mmu_write(pfdev, AS_MEMATTR_LO(as_nr), memattr & 0xffffffffUL); -+ mmu_write(pfdev, AS_MEMATTR_HI(as_nr), memattr >> 32); -+ -+ write_cmd(pfdev, as_nr, AS_COMMAND_UPDATE); -+} -+ -+static void mmu_disable(struct panfrost_device *pfdev, u32 as_nr) -+{ -+ mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), 0); -+ mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), 0); -+ -+ mmu_write(pfdev, AS_MEMATTR_LO(as_nr), 0); -+ mmu_write(pfdev, AS_MEMATTR_HI(as_nr), 0); -+ -+ write_cmd(pfdev, as_nr, AS_COMMAND_UPDATE); -+} -+ -+int panfrost_mmu_map(struct panfrost_gem_object *bo) -+{ -+ struct drm_gem_object *obj = &bo->base.base; -+ struct panfrost_device *pfdev = to_panfrost_device(obj->dev); -+ struct io_pgtable_ops *ops = pfdev->mmu->pgtbl_ops; -+ u64 iova = bo->node.start << PAGE_SHIFT; -+ unsigned int count; -+ struct scatterlist *sgl; -+ struct sg_table *sgt; -+ int ret; -+ -+ sgt = drm_gem_shmem_get_pages_sgt(obj); -+ if (WARN_ON(IS_ERR(sgt))) -+ return PTR_ERR(sgt); -+ -+ ret = pm_runtime_get_sync(pfdev->dev); -+ if (ret < 0) -+ return ret; -+ -+ mutex_lock(&pfdev->mmu->lock); -+ -+ for_each_sg(sgt->sgl, sgl, sgt->nents, count) { -+ unsigned long paddr = sg_dma_address(sgl); -+ size_t len = sg_dma_len(sgl); -+ -+ dev_dbg(pfdev->dev, "map: iova=%llx, paddr=%lx, len=%zx", iova, paddr, len); -+ -+ while (len) { -+ ops->map(ops, iova, paddr, SZ_4K, IOMMU_WRITE | IOMMU_READ); -+ iova += SZ_4K; -+ paddr += SZ_4K; -+ len -= SZ_4K; -+ } -+ } -+ -+ mmu_hw_do_operation(pfdev, 0, bo->node.start << PAGE_SHIFT, -+ bo->node.size << PAGE_SHIFT, AS_COMMAND_FLUSH_PT); -+ -+ mutex_unlock(&pfdev->mmu->lock); -+ -+ pm_runtime_mark_last_busy(pfdev->dev); -+ pm_runtime_put_autosuspend(pfdev->dev); -+ -+ return 0; -+} -+ -+void panfrost_mmu_unmap(struct panfrost_gem_object *bo) -+{ -+ struct drm_gem_object *obj = &bo->base.base; -+ struct panfrost_device *pfdev = to_panfrost_device(obj->dev); -+ struct io_pgtable_ops *ops = pfdev->mmu->pgtbl_ops; -+ u64 iova = bo->node.start << PAGE_SHIFT; -+ size_t len = bo->node.size << PAGE_SHIFT; -+ size_t unmapped_len = 0; -+ int ret; -+ -+ dev_dbg(pfdev->dev, "unmap: iova=%llx, len=%zx", iova, len); -+ -+ ret = pm_runtime_get_sync(pfdev->dev); -+ if (ret < 0) -+ return; -+ -+ mutex_lock(&pfdev->mmu->lock); -+ -+ while (unmapped_len < len) { -+ ops->unmap(ops, iova, SZ_4K); -+ iova += SZ_4K; -+ unmapped_len += SZ_4K; -+ } -+ -+ mmu_hw_do_operation(pfdev, 0, bo->node.start << PAGE_SHIFT, -+ bo->node.size << PAGE_SHIFT, AS_COMMAND_FLUSH_PT); -+ -+ mutex_unlock(&pfdev->mmu->lock); -+ -+ pm_runtime_mark_last_busy(pfdev->dev); -+ pm_runtime_put_autosuspend(pfdev->dev); -+} -+ -+static void mmu_tlb_inv_context_s1(void *cookie) -+{ -+ struct panfrost_device *pfdev = cookie; -+ -+ mmu_hw_do_operation(pfdev, 0, 0, ~0UL, AS_COMMAND_FLUSH_MEM); -+} -+ -+static void mmu_tlb_inv_range_nosync(unsigned long iova, size_t size, -+ size_t granule, bool leaf, void *cookie) -+{} -+ -+static void mmu_tlb_sync_context(void *cookie) -+{ -+ //struct panfrost_device *pfdev = cookie; -+ // TODO: Wait 1000 GPU cycles for HW_ISSUE_6367/T60X -+} -+ -+static const struct iommu_gather_ops mmu_tlb_ops = { -+ .tlb_flush_all = mmu_tlb_inv_context_s1, -+ .tlb_add_flush = mmu_tlb_inv_range_nosync, -+ .tlb_sync = mmu_tlb_sync_context, -+}; -+ -+static const char *access_type_name(struct panfrost_device *pfdev, -+ u32 fault_status) -+{ -+ switch (fault_status & AS_FAULTSTATUS_ACCESS_TYPE_MASK) { -+ case AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC: -+ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_AARCH64_MMU)) -+ return "ATOMIC"; -+ else -+ return "UNKNOWN"; -+ case AS_FAULTSTATUS_ACCESS_TYPE_READ: -+ return "READ"; -+ case AS_FAULTSTATUS_ACCESS_TYPE_WRITE: -+ return "WRITE"; -+ case AS_FAULTSTATUS_ACCESS_TYPE_EX: -+ return "EXECUTE"; -+ default: -+ WARN_ON(1); -+ return NULL; -+ } -+} -+ -+static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data) -+{ -+ struct panfrost_device *pfdev = data; -+ u32 status = mmu_read(pfdev, MMU_INT_STAT); -+ int i; -+ -+ if (!status) -+ return IRQ_NONE; -+ -+ dev_err(pfdev->dev, "mmu irq status=%x\n", status); -+ -+ for (i = 0; status; i++) { -+ u32 mask = BIT(i) | BIT(i + 16); -+ u64 addr; -+ u32 fault_status; -+ u32 exception_type; -+ u32 access_type; -+ u32 source_id; -+ -+ if (!(status & mask)) -+ continue; -+ -+ fault_status = mmu_read(pfdev, AS_FAULTSTATUS(i)); -+ addr = mmu_read(pfdev, AS_FAULTADDRESS_LO(i)); -+ addr |= (u64)mmu_read(pfdev, AS_FAULTADDRESS_HI(i)) << 32; -+ -+ /* decode the fault status */ -+ exception_type = fault_status & 0xFF; -+ access_type = (fault_status >> 8) & 0x3; -+ source_id = (fault_status >> 16); -+ -+ /* terminal fault, print info about the fault */ -+ dev_err(pfdev->dev, -+ "Unhandled Page fault in AS%d at VA 0x%016llX\n" -+ "Reason: %s\n" -+ "raw fault status: 0x%X\n" -+ "decoded fault status: %s\n" -+ "exception type 0x%X: %s\n" -+ "access type 0x%X: %s\n" -+ "source id 0x%X\n", -+ i, addr, -+ "TODO", -+ fault_status, -+ (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"), -+ exception_type, panfrost_exception_name(pfdev, exception_type), -+ access_type, access_type_name(pfdev, fault_status), -+ source_id); -+ -+ mmu_write(pfdev, MMU_INT_CLEAR, mask); -+ -+ status &= ~mask; -+ } -+ -+ return IRQ_HANDLED; -+}; -+ -+int panfrost_mmu_init(struct panfrost_device *pfdev) -+{ -+ struct io_pgtable_ops *pgtbl_ops; -+ int err, irq; -+ -+ pfdev->mmu = devm_kzalloc(pfdev->dev, sizeof(*pfdev->mmu), GFP_KERNEL); -+ if (!pfdev->mmu) -+ return -ENOMEM; -+ -+ mutex_init(&pfdev->mmu->lock); -+ -+ irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu"); -+ if (irq <= 0) -+ return -ENODEV; -+ -+ err = devm_request_irq(pfdev->dev, irq, panfrost_mmu_irq_handler, -+ IRQF_SHARED, "mmu", pfdev); -+ -+ if (err) { -+ dev_err(pfdev->dev, "failed to request mmu irq"); -+ return err; -+ } -+ mmu_write(pfdev, MMU_INT_CLEAR, ~0); -+ mmu_write(pfdev, MMU_INT_MASK, ~0); -+ -+ pfdev->mmu->pgtbl_cfg = (struct io_pgtable_cfg) { -+ .pgsize_bitmap = SZ_4K, // | SZ_2M | SZ_1G), -+ .ias = 48, -+ .oas = 40, -+ .tlb = &mmu_tlb_ops, -+ .iommu_dev = pfdev->dev, -+ }; -+ -+ pgtbl_ops = alloc_io_pgtable_ops(ARM_MALI_LPAE, &pfdev->mmu->pgtbl_cfg, -+ pfdev); -+ if (!pgtbl_ops) -+ return -ENOMEM; -+ -+ pfdev->mmu->pgtbl_ops = pgtbl_ops; -+ -+ panfrost_mmu_enable(pfdev, 0); -+ -+ return 0; -+} -+ -+void panfrost_mmu_fini(struct panfrost_device *pfdev) -+{ -+ mmu_write(pfdev, MMU_INT_MASK, 0); -+ mmu_disable(pfdev, 0); -+ -+ free_io_pgtable_ops(pfdev->mmu->pgtbl_ops); -+} -diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.h b/drivers/gpu/drm/panfrost/panfrost_mmu.h -new file mode 100644 -index 0000000000000..f5878d86a5cea ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+ -+#ifndef __PANFROST_MMU_H__ -+#define __PANFROST_MMU_H__ -+ -+struct panfrost_gem_object; -+ -+int panfrost_mmu_map(struct panfrost_gem_object *bo); -+void panfrost_mmu_unmap(struct panfrost_gem_object *bo); -+ -+int panfrost_mmu_init(struct panfrost_device *pfdev); -+void panfrost_mmu_fini(struct panfrost_device *pfdev); -+ -+void panfrost_mmu_enable(struct panfrost_device *pfdev, u32 as_nr); -+ -+#endif -diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h -new file mode 100644 -index 0000000000000..578c5fc2188b6 ---- /dev/null -+++ b/drivers/gpu/drm/panfrost/panfrost_regs.h -@@ -0,0 +1,298 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2018 Marty E. Plummer */ -+/* Copyright 2019 Linaro, Ltd, Rob Herring */ -+/* -+ * Register definitions based on mali_midg_regmap.h -+ * (C) COPYRIGHT 2010-2018 ARM Limited. All rights reserved. -+ */ -+#ifndef __PANFROST_REGS_H__ -+#define __PANFROST_REGS_H__ -+ -+#define GPU_ID 0x00 -+#define GPU_L2_FEATURES 0x004 /* (RO) Level 2 cache features */ -+#define GPU_CORE_FEATURES 0x008 /* (RO) Shader Core Features */ -+#define GPU_TILER_FEATURES 0x00C /* (RO) Tiler Features */ -+#define GPU_MEM_FEATURES 0x010 /* (RO) Memory system features */ -+#define GROUPS_L2_COHERENT BIT(0) /* Cores groups are l2 coherent */ -+ -+#define GPU_MMU_FEATURES 0x014 /* (RO) MMU features */ -+#define GPU_AS_PRESENT 0x018 /* (RO) Address space slots present */ -+#define GPU_JS_PRESENT 0x01C /* (RO) Job slots present */ -+ -+#define GPU_INT_RAWSTAT 0x20 -+#define GPU_INT_CLEAR 0x24 -+#define GPU_INT_MASK 0x28 -+#define GPU_INT_STAT 0x2c -+#define GPU_IRQ_FAULT BIT(0) -+#define GPU_IRQ_MULTIPLE_FAULT BIT(7) -+#define GPU_IRQ_RESET_COMPLETED BIT(8) -+#define GPU_IRQ_POWER_CHANGED BIT(9) -+#define GPU_IRQ_POWER_CHANGED_ALL BIT(10) -+#define GPU_IRQ_PERFCNT_SAMPLE_COMPLETED BIT(16) -+#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17) -+#define GPU_IRQ_MASK_ALL \ -+ (GPU_IRQ_FAULT |\ -+ GPU_IRQ_MULTIPLE_FAULT |\ -+ GPU_IRQ_RESET_COMPLETED |\ -+ GPU_IRQ_POWER_CHANGED |\ -+ GPU_IRQ_POWER_CHANGED_ALL |\ -+ GPU_IRQ_PERFCNT_SAMPLE_COMPLETED |\ -+ GPU_IRQ_CLEAN_CACHES_COMPLETED) -+#define GPU_IRQ_MASK_ERROR \ -+ ( \ -+ GPU_IRQ_FAULT |\ -+ GPU_IRQ_MULTIPLE_FAULT) -+#define GPU_CMD 0x30 -+#define GPU_CMD_SOFT_RESET 0x01 -+#define GPU_STATUS 0x34 -+#define GPU_LATEST_FLUSH_ID 0x38 -+#define GPU_FAULT_STATUS 0x3C -+#define GPU_FAULT_ADDRESS_LO 0x40 -+#define GPU_FAULT_ADDRESS_HI 0x44 -+ -+#define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ -+#define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ -+#define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ -+#define GPU_THREAD_FEATURES 0x0AC /* (RO) Thread features */ -+#define GPU_THREAD_TLS_ALLOC 0x310 /* (RO) Number of threads per core that -+ * TLS must be allocated for */ -+ -+#define GPU_TEXTURE_FEATURES(n) (0x0B0 + ((n) * 4)) -+#define GPU_JS_FEATURES(n) (0x0C0 + ((n) * 4)) -+ -+#define GPU_SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */ -+#define GPU_SHADER_PRESENT_HI 0x104 /* (RO) Shader core present bitmap, high word */ -+#define GPU_TILER_PRESENT_LO 0x110 /* (RO) Tiler core present bitmap, low word */ -+#define GPU_TILER_PRESENT_HI 0x114 /* (RO) Tiler core present bitmap, high word */ -+ -+#define GPU_L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */ -+#define GPU_L2_PRESENT_HI 0x124 /* (RO) Level 2 cache present bitmap, high word */ -+ -+#define GPU_COHERENCY_FEATURES 0x300 /* (RO) Coherency features present */ -+#define COHERENCY_ACE_LITE BIT(0) -+#define COHERENCY_ACE BIT(1) -+ -+#define GPU_STACK_PRESENT_LO 0xE00 /* (RO) Core stack present bitmap, low word */ -+#define GPU_STACK_PRESENT_HI 0xE04 /* (RO) Core stack present bitmap, high word */ -+ -+#define SHADER_READY_LO 0x140 /* (RO) Shader core ready bitmap, low word */ -+#define SHADER_READY_HI 0x144 /* (RO) Shader core ready bitmap, high word */ -+ -+#define TILER_READY_LO 0x150 /* (RO) Tiler core ready bitmap, low word */ -+#define TILER_READY_HI 0x154 /* (RO) Tiler core ready bitmap, high word */ -+ -+#define L2_READY_LO 0x160 /* (RO) Level 2 cache ready bitmap, low word */ -+#define L2_READY_HI 0x164 /* (RO) Level 2 cache ready bitmap, high word */ -+ -+#define STACK_READY_LO 0xE10 /* (RO) Core stack ready bitmap, low word */ -+#define STACK_READY_HI 0xE14 /* (RO) Core stack ready bitmap, high word */ -+ -+ -+#define SHADER_PWRON_LO 0x180 /* (WO) Shader core power on bitmap, low word */ -+#define SHADER_PWRON_HI 0x184 /* (WO) Shader core power on bitmap, high word */ -+ -+#define TILER_PWRON_LO 0x190 /* (WO) Tiler core power on bitmap, low word */ -+#define TILER_PWRON_HI 0x194 /* (WO) Tiler core power on bitmap, high word */ -+ -+#define L2_PWRON_LO 0x1A0 /* (WO) Level 2 cache power on bitmap, low word */ -+#define L2_PWRON_HI 0x1A4 /* (WO) Level 2 cache power on bitmap, high word */ -+ -+#define STACK_PWRON_LO 0xE20 /* (RO) Core stack power on bitmap, low word */ -+#define STACK_PWRON_HI 0xE24 /* (RO) Core stack power on bitmap, high word */ -+ -+ -+#define SHADER_PWROFF_LO 0x1C0 /* (WO) Shader core power off bitmap, low word */ -+#define SHADER_PWROFF_HI 0x1C4 /* (WO) Shader core power off bitmap, high word */ -+ -+#define TILER_PWROFF_LO 0x1D0 /* (WO) Tiler core power off bitmap, low word */ -+#define TILER_PWROFF_HI 0x1D4 /* (WO) Tiler core power off bitmap, high word */ -+ -+#define L2_PWROFF_LO 0x1E0 /* (WO) Level 2 cache power off bitmap, low word */ -+#define L2_PWROFF_HI 0x1E4 /* (WO) Level 2 cache power off bitmap, high word */ -+ -+#define STACK_PWROFF_LO 0xE30 /* (RO) Core stack power off bitmap, low word */ -+#define STACK_PWROFF_HI 0xE34 /* (RO) Core stack power off bitmap, high word */ -+ -+ -+#define SHADER_PWRTRANS_LO 0x200 /* (RO) Shader core power transition bitmap, low word */ -+#define SHADER_PWRTRANS_HI 0x204 /* (RO) Shader core power transition bitmap, high word */ -+ -+#define TILER_PWRTRANS_LO 0x210 /* (RO) Tiler core power transition bitmap, low word */ -+#define TILER_PWRTRANS_HI 0x214 /* (RO) Tiler core power transition bitmap, high word */ -+ -+#define L2_PWRTRANS_LO 0x220 /* (RO) Level 2 cache power transition bitmap, low word */ -+#define L2_PWRTRANS_HI 0x224 /* (RO) Level 2 cache power transition bitmap, high word */ -+ -+#define STACK_PWRTRANS_LO 0xE40 /* (RO) Core stack power transition bitmap, low word */ -+#define STACK_PWRTRANS_HI 0xE44 /* (RO) Core stack power transition bitmap, high word */ -+ -+ -+#define SHADER_PWRACTIVE_LO 0x240 /* (RO) Shader core active bitmap, low word */ -+#define SHADER_PWRACTIVE_HI 0x244 /* (RO) Shader core active bitmap, high word */ -+ -+#define TILER_PWRACTIVE_LO 0x250 /* (RO) Tiler core active bitmap, low word */ -+#define TILER_PWRACTIVE_HI 0x254 /* (RO) Tiler core active bitmap, high word */ -+ -+#define L2_PWRACTIVE_LO 0x260 /* (RO) Level 2 cache active bitmap, low word */ -+#define L2_PWRACTIVE_HI 0x264 /* (RO) Level 2 cache active bitmap, high word */ -+ -+#define GPU_JM_CONFIG 0xF00 /* (RW) Job Manager configuration register (Implementation specific register) */ -+#define GPU_SHADER_CONFIG 0xF04 /* (RW) Shader core configuration settings (Implementation specific register) */ -+#define GPU_TILER_CONFIG 0xF08 /* (RW) Tiler core configuration settings (Implementation specific register) */ -+#define GPU_L2_MMU_CONFIG 0xF0C /* (RW) Configuration of the L2 cache and MMU (Implementation specific register) */ -+ -+/* L2_MMU_CONFIG register */ -+#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT 23 -+#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY (0x1 << L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT 24 -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_OCTANT (0x1 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_QUARTER (0x2 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_HALF (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+ -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT 26 -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_OCTANT (0x1 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_QUARTER (0x2 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_HALF (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+ -+#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS_SHIFT 12 -+#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS (0x7 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+ -+#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES_SHIFT 15 -+#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES (0x7 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+ -+/* SHADER_CONFIG register */ -+#define SC_ALT_COUNTERS BIT(3) -+#define SC_OVERRIDE_FWD_PIXEL_KILL BIT(4) -+#define SC_SDC_DISABLE_OQ_DISCARD BIT(6) -+#define SC_LS_ALLOW_ATTR_TYPES BIT(16) -+#define SC_LS_PAUSEBUFFER_DISABLE BIT(16) -+#define SC_TLS_HASH_ENABLE BIT(17) -+#define SC_LS_ATTR_CHECK_DISABLE BIT(18) -+#define SC_ENABLE_TEXGRD_FLAGS BIT(25) -+/* End SHADER_CONFIG register */ -+ -+/* TILER_CONFIG register */ -+#define TC_CLOCK_GATE_OVERRIDE BIT(0) -+ -+/* JM_CONFIG register */ -+#define JM_TIMESTAMP_OVERRIDE BIT(0) -+#define JM_CLOCK_GATE_OVERRIDE BIT(1) -+#define JM_JOB_THROTTLE_ENABLE BIT(2) -+#define JM_JOB_THROTTLE_LIMIT_SHIFT 3 -+#define JM_MAX_JOB_THROTTLE_LIMIT 0x3F -+#define JM_FORCE_COHERENCY_FEATURES_SHIFT 2 -+#define JM_IDVS_GROUP_SIZE_SHIFT 16 -+#define JM_MAX_IDVS_GROUP_SIZE 0x3F -+ -+ -+/* Job Control regs */ -+#define JOB_INT_RAWSTAT 0x1000 -+#define JOB_INT_CLEAR 0x1004 -+#define JOB_INT_MASK 0x1008 -+#define JOB_INT_STAT 0x100c -+#define JOB_INT_JS_STATE 0x1010 -+#define JOB_INT_THROTTLE 0x1014 -+ -+#define MK_JS_MASK(j) (0x10001 << (j)) -+#define JOB_INT_MASK_ERR(j) BIT((j) + 16) -+#define JOB_INT_MASK_DONE(j) BIT(j) -+ -+#define JS_BASE 0x1800 -+#define JS_HEAD_LO(n) (JS_BASE + ((n) * 0x80) + 0x00) -+#define JS_HEAD_HI(n) (JS_BASE + ((n) * 0x80) + 0x04) -+#define JS_TAIL_LO(n) (JS_BASE + ((n) * 0x80) + 0x08) -+#define JS_TAIL_HI(n) (JS_BASE + ((n) * 0x80) + 0x0c) -+#define JS_AFFINITY_LO(n) (JS_BASE + ((n) * 0x80) + 0x10) -+#define JS_AFFINITY_HI(n) (JS_BASE + ((n) * 0x80) + 0x14) -+#define JS_CONFIG(n) (JS_BASE + ((n) * 0x80) + 0x18) -+#define JS_XAFFINITY(n) (JS_BASE + ((n) * 0x80) + 0x1c) -+#define JS_COMMAND(n) (JS_BASE + ((n) * 0x80) + 0x20) -+#define JS_STATUS(n) (JS_BASE + ((n) * 0x80) + 0x24) -+#define JS_HEAD_NEXT_LO(n) (JS_BASE + ((n) * 0x80) + 0x40) -+#define JS_HEAD_NEXT_HI(n) (JS_BASE + ((n) * 0x80) + 0x44) -+#define JS_AFFINITY_NEXT_LO(n) (JS_BASE + ((n) * 0x80) + 0x50) -+#define JS_AFFINITY_NEXT_HI(n) (JS_BASE + ((n) * 0x80) + 0x54) -+#define JS_CONFIG_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x58) -+#define JS_COMMAND_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x60) -+#define JS_FLUSH_ID_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x70) -+ -+/* Possible values of JS_CONFIG and JS_CONFIG_NEXT registers */ -+#define JS_CONFIG_START_FLUSH_CLEAN BIT(8) -+#define JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE (3u << 8) -+#define JS_CONFIG_START_MMU BIT(10) -+#define JS_CONFIG_JOB_CHAIN_FLAG BIT(11) -+#define JS_CONFIG_END_FLUSH_CLEAN BIT(12) -+#define JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE (3u << 12) -+#define JS_CONFIG_ENABLE_FLUSH_REDUCTION BIT(14) -+#define JS_CONFIG_DISABLE_DESCRIPTOR_WR_BK BIT(15) -+#define JS_CONFIG_THREAD_PRI(n) ((n) << 16) -+ -+#define JS_COMMAND_NOP 0x00 -+#define JS_COMMAND_START 0x01 -+#define JS_COMMAND_SOFT_STOP 0x02 /* Gently stop processing a job chain */ -+#define JS_COMMAND_HARD_STOP 0x03 /* Rudely stop processing a job chain */ -+#define JS_COMMAND_SOFT_STOP_0 0x04 /* Execute SOFT_STOP if JOB_CHAIN_FLAG is 0 */ -+#define JS_COMMAND_HARD_STOP_0 0x05 /* Execute HARD_STOP if JOB_CHAIN_FLAG is 0 */ -+#define JS_COMMAND_SOFT_STOP_1 0x06 /* Execute SOFT_STOP if JOB_CHAIN_FLAG is 1 */ -+#define JS_COMMAND_HARD_STOP_1 0x07 /* Execute HARD_STOP if JOB_CHAIN_FLAG is 1 */ -+ -+#define JS_STATUS_EVENT_ACTIVE 0x08 -+ -+ -+/* MMU regs */ -+#define MMU_INT_RAWSTAT 0x2000 -+#define MMU_INT_CLEAR 0x2004 -+#define MMU_INT_MASK 0x2008 -+#define MMU_INT_STAT 0x200c -+ -+/* AS_COMMAND register commands */ -+#define AS_COMMAND_NOP 0x00 /* NOP Operation */ -+#define AS_COMMAND_UPDATE 0x01 /* Broadcasts the values in AS_TRANSTAB and ASn_MEMATTR to all MMUs */ -+#define AS_COMMAND_LOCK 0x02 /* Issue a lock region command to all MMUs */ -+#define AS_COMMAND_UNLOCK 0x03 /* Issue a flush region command to all MMUs */ -+#define AS_COMMAND_FLUSH 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs -+ (deprecated - only for use with T60x) */ -+#define AS_COMMAND_FLUSH_PT 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs */ -+#define AS_COMMAND_FLUSH_MEM 0x05 /* Wait for memory accesses to complete, flush all the L1s cache then -+ flush all L2 caches then issue a flush region command to all MMUs */ -+ -+#define MMU_AS(as) (0x2400 + ((as) << 6)) -+ -+#define AS_TRANSTAB_LO(as) (MMU_AS(as) + 0x00) /* (RW) Translation Table Base Address for address space n, low word */ -+#define AS_TRANSTAB_HI(as) (MMU_AS(as) + 0x04) /* (RW) Translation Table Base Address for address space n, high word */ -+#define AS_MEMATTR_LO(as) (MMU_AS(as) + 0x08) /* (RW) Memory attributes for address space n, low word. */ -+#define AS_MEMATTR_HI(as) (MMU_AS(as) + 0x0C) /* (RW) Memory attributes for address space n, high word. */ -+#define AS_LOCKADDR_LO(as) (MMU_AS(as) + 0x10) /* (RW) Lock region address for address space n, low word */ -+#define AS_LOCKADDR_HI(as) (MMU_AS(as) + 0x14) /* (RW) Lock region address for address space n, high word */ -+#define AS_COMMAND(as) (MMU_AS(as) + 0x18) /* (WO) MMU command register for address space n */ -+#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C) /* (RO) MMU fault status register for address space n */ -+#define AS_FAULTADDRESS_LO(as) (MMU_AS(as) + 0x20) /* (RO) Fault Address for address space n, low word */ -+#define AS_FAULTADDRESS_HI(as) (MMU_AS(as) + 0x24) /* (RO) Fault Address for address space n, high word */ -+#define AS_STATUS(as) (MMU_AS(as) + 0x28) /* (RO) Status flags for address space n */ -+/* Additional Bifrost AS regsiters */ -+#define AS_TRANSCFG_LO(as) (MMU_AS(as) + 0x30) /* (RW) Translation table configuration for address space n, low word */ -+#define AS_TRANSCFG_HI(as) (MMU_AS(as) + 0x34) /* (RW) Translation table configuration for address space n, high word */ -+#define AS_FAULTEXTRA_LO(as) (MMU_AS(as) + 0x38) /* (RO) Secondary fault address for address space n, low word */ -+#define AS_FAULTEXTRA_HI(as) (MMU_AS(as) + 0x3C) /* (RO) Secondary fault address for address space n, high word */ -+ -+/* -+ * Begin LPAE MMU TRANSTAB register values -+ */ -+#define AS_TRANSTAB_LPAE_ADDR_SPACE_MASK 0xfffffffffffff000 -+#define AS_TRANSTAB_LPAE_ADRMODE_IDENTITY 0x2 -+#define AS_TRANSTAB_LPAE_ADRMODE_TABLE 0x3 -+#define AS_TRANSTAB_LPAE_ADRMODE_MASK 0x3 -+#define AS_TRANSTAB_LPAE_READ_INNER BIT(2) -+#define AS_TRANSTAB_LPAE_SHARE_OUTER BIT(4) -+ -+#define AS_STATUS_AS_ACTIVE 0x01 -+ -+#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) -+ -+#endif -diff --git a/include/uapi/drm/panfrost_drm.h b/include/uapi/drm/panfrost_drm.h -new file mode 100644 -index 0000000000000..a52e0283b90d5 ---- /dev/null -+++ b/include/uapi/drm/panfrost_drm.h -@@ -0,0 +1,142 @@ -+/* SPDX-License-Identifier: MIT */ -+/* -+ * Copyright © 2014-2018 Broadcom -+ * Copyright © 2019 Collabora ltd. -+ */ -+#ifndef _PANFROST_DRM_H_ -+#define _PANFROST_DRM_H_ -+ -+#include "drm.h" -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+#define DRM_PANFROST_SUBMIT 0x00 -+#define DRM_PANFROST_WAIT_BO 0x01 -+#define DRM_PANFROST_CREATE_BO 0x02 -+#define DRM_PANFROST_MMAP_BO 0x03 -+#define DRM_PANFROST_GET_PARAM 0x04 -+#define DRM_PANFROST_GET_BO_OFFSET 0x05 -+ -+#define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) -+#define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) -+#define DRM_IOCTL_PANFROST_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_CREATE_BO, struct drm_panfrost_create_bo) -+#define DRM_IOCTL_PANFROST_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_MMAP_BO, struct drm_panfrost_mmap_bo) -+#define DRM_IOCTL_PANFROST_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_PARAM, struct drm_panfrost_get_param) -+#define DRM_IOCTL_PANFROST_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_BO_OFFSET, struct drm_panfrost_get_bo_offset) -+ -+#define PANFROST_JD_REQ_FS (1 << 0) -+/** -+ * struct drm_panfrost_submit - ioctl argument for submitting commands to the 3D -+ * engine. -+ * -+ * This asks the kernel to have the GPU execute a render command list. -+ */ -+struct drm_panfrost_submit { -+ -+ /** Address to GPU mapping of job descriptor */ -+ __u64 jc; -+ -+ /** An optional array of sync objects to wait on before starting this job. */ -+ __u64 in_syncs; -+ -+ /** Number of sync objects to wait on before starting this job. */ -+ __u32 in_sync_count; -+ -+ /** An optional sync object to place the completion fence in. */ -+ __u32 out_sync; -+ -+ /** Pointer to a u32 array of the BOs that are referenced by the job. */ -+ __u64 bo_handles; -+ -+ /** Number of BO handles passed in (size is that times 4). */ -+ __u32 bo_handle_count; -+ -+ /** A combination of PANFROST_JD_REQ_* */ -+ __u32 requirements; -+}; -+ -+/** -+ * struct drm_panfrost_wait_bo - ioctl argument for waiting for -+ * completion of the last DRM_PANFROST_SUBMIT on a BO. -+ * -+ * This is useful for cases where multiple processes might be -+ * rendering to a BO and you want to wait for all rendering to be -+ * completed. -+ */ -+struct drm_panfrost_wait_bo { -+ __u32 handle; -+ __u32 pad; -+ __s64 timeout_ns; /* absolute */ -+}; -+ -+/** -+ * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. -+ * -+ * There are currently no values for the flags argument, but it may be -+ * used in a future extension. -+ */ -+struct drm_panfrost_create_bo { -+ __u32 size; -+ __u32 flags; -+ /** Returned GEM handle for the BO. */ -+ __u32 handle; -+ /* Pad, must be zero-filled. */ -+ __u32 pad; -+ /** -+ * Returned offset for the BO in the GPU address space. This offset -+ * is private to the DRM fd and is valid for the lifetime of the GEM -+ * handle. -+ * -+ * This offset value will always be nonzero, since various HW -+ * units treat 0 specially. -+ */ -+ __u64 offset; -+}; -+ -+/** -+ * struct drm_panfrost_mmap_bo - ioctl argument for mapping Panfrost BOs. -+ * -+ * This doesn't actually perform an mmap. Instead, it returns the -+ * offset you need to use in an mmap on the DRM device node. This -+ * means that tools like valgrind end up knowing about the mapped -+ * memory. -+ * -+ * There are currently no values for the flags argument, but it may be -+ * used in a future extension. -+ */ -+struct drm_panfrost_mmap_bo { -+ /** Handle for the object being mapped. */ -+ __u32 handle; -+ __u32 flags; -+ /** offset into the drm node to use for subsequent mmap call. */ -+ __u64 offset; -+}; -+ -+enum drm_panfrost_param { -+ DRM_PANFROST_PARAM_GPU_PROD_ID, -+}; -+ -+struct drm_panfrost_get_param { -+ __u32 param; -+ __u32 pad; -+ __u64 value; -+}; -+ -+/** -+ * Returns the offset for the BO in the GPU address space for this DRM fd. -+ * This is the same value returned by drm_panfrost_create_bo, if that was called -+ * from this DRM fd. -+ */ -+struct drm_panfrost_get_bo_offset { -+ __u32 handle; -+ __u32 pad; -+ __u64 offset; -+}; -+ -+#if defined(__cplusplus) -+} -+#endif -+ -+#endif /* _PANFROST_DRM_H_ */ - -From d6082cb08bbb55d68dfe56584a5779caa8e0878a Mon Sep 17 00:00:00 2001 -From: Christian Hewitt -Date: Thu, 6 Dec 2018 14:26:00 +0100 -Subject: [PATCH 246/249] arm64: dts: meson-gxm: Add Mali-T820 node - -The Amlogic Meson GXM SoC embeds an ARM Mali T820 GPU. - -This patch adds the node with all the needed properties to power -on the GPU. - -This has been tested with the work-in-progress PanFrost project -aiming support for ARM Mali Midgard and later GPUs. - -Signed-off-by: Christian Hewitt -Signed-off-by: Neil Armstrong -(cherry picked from commit a21b179e7eba2ab96ecd66ddc782f3c5ecd21cfb) ---- - arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 27 ++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi -index d74cb4993bae2..13e76d4136c05 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi -@@ -91,6 +91,33 @@ - reset-names = "phy"; - status = "okay"; - }; -+ -+ mali: gpu@c0000 { -+ compatible = "amlogic,meson-gxm-mali", "arm,mali-t820"; -+ reg = <0x0 0xc0000 0x0 0x40000>; -+ interrupt-parent = <&gic>; -+ interrupts = , -+ , -+ ; -+ interrupt-names = "gpu", "mmu", "job"; -+ clocks = <&clkc CLKID_MALI>; -+ resets = <&reset RESET_MALI_CAPB3>, <&reset RESET_MALI>; -+ -+ /* -+ * Mali clocking is provided by two identical clock paths -+ * MALI_0 and MALI_1 muxed to a single clock by a glitch -+ * free mux to safely change frequency while running. -+ */ -+ assigned-clocks = <&clkc CLKID_MALI_0_SEL>, -+ <&clkc CLKID_MALI_0>, -+ <&clkc CLKID_MALI>; /* Glitch free mux */ -+ assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, -+ <0>, /* Do Nothing */ -+ <&clkc CLKID_MALI_0>; -+ assigned-clock-rates = <0>, /* Do Nothing */ -+ <666666666>, -+ <0>; /* Do Nothing */ -+ }; - }; - - &clkc_AO { - -From 5a848cbeaeb7cbbe4d93ec64b0ddf6783973ba1f Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Mon, 10 Dec 2018 14:00:23 +0100 -Subject: [PATCH 247/249] arm64: dts: meson-gxm-nexbox-a1: Enable USB - -(cherry picked from commit d8b1846fbdec9b43b2655e01fcd58086538da2d0) ---- - arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -index 93a968fa5a0d3..b8eb7f7c3dff6 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -@@ -215,3 +215,7 @@ - pinctrl-0 = <&uart_ao_a_pins>; - pinctrl-names = "default"; - }; -+ -+&usb0 { -+ status = "okay"; -+}; - -From aedb35fe0a4ab763d69f50174317734b388bc125 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 13 Mar 2019 17:34:09 +0100 -Subject: [PATCH 248/249] arm64: dts: meson-gxm-nexbox-a1: disable cvbs - -(cherry picked from commit 43a438462f00880abaa6ac5241f78644d2b4da07) ---- - arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -index b8eb7f7c3dff6..fe6d84319e948 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts -@@ -57,6 +57,7 @@ - - cvbs-connector { - compatible = "composite-video-connector"; -+ status = "disabled"; - - port { - cvbs_connector_in: endpoint { - -From df28223b151155ab0edd8419b0347a7135443fd3 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Thu, 14 Mar 2019 09:37:38 +0100 -Subject: [PATCH 249/249] [WiP] drm/panfrost: add support for custom soft-reset - on Amlogic GXM - -(cherry picked from commit 2e5230c1bf9cf01f035da72291cc460cb3b37096) ---- - drivers/gpu/drm/panfrost/panfrost_gpu.c | 13 ++++++++++++- - drivers/gpu/drm/panfrost/panfrost_regs.h | 4 ++++ - 2 files changed, 16 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c -index aceaf6e44a099..9cd02cba54206 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_gpu.c -+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c -@@ -5,7 +5,9 @@ - #include - #include - #include -+#include - #include -+#include - #include - #include - -@@ -53,7 +55,16 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) - - gpu_write(pfdev, GPU_INT_MASK, 0); - gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); -- gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); -+ -+ if (of_device_is_compatible(pfdev->dev->of_node, "amlogic,meson-gxm-mali")) { -+ reset_control_assert(pfdev->rstc); -+ udelay(10); -+ reset_control_deassert(pfdev->rstc); -+ -+ gpu_write(pfdev, GPU_PWR_KEY, 0x2968A819); -+ gpu_write(pfdev, GPU_PWR_OVERRIDE1, 0xfff | (0x20 << 16)); -+ } else -+ gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); - - ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, - val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000); -diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h -index 578c5fc2188b6..d61b2cd0a99b6 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_regs.h -+++ b/drivers/gpu/drm/panfrost/panfrost_regs.h -@@ -50,6 +50,10 @@ - #define GPU_FAULT_ADDRESS_LO 0x40 - #define GPU_FAULT_ADDRESS_HI 0x44 - -+#define GPU_PWR_KEY 0x050 /* (WO) Power manager key register */ -+#define GPU_PWR_OVERRIDE0 0x054 /* (RW) Power manager override settings */ -+#define GPU_PWR_OVERRIDE1 0x058 /* (RW) Power manager override settings */ -+ - #define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ - #define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ - #define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ diff --git a/projects/Amlogic/patches/linux/c-hdmi-audio-and-cec.patch b/projects/Amlogic/patches/linux/c-hdmi-audio-and-cec.patch deleted file mode 100644 index 507ff9b4d3..0000000000 --- a/projects/Amlogic/patches/linux/c-hdmi-audio-and-cec.patch +++ /dev/null @@ -1,1150 +0,0 @@ -From 995ea27fe624bf8a3e7522bf8121a7443c73ef84 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 10:22:09 +0100 -Subject: [PATCH 01/15] drm: dw-hdmi: extract dw_hdmi_connector_update_edid() - -Extract code that updates EDID into a dw_hdmi_connector_update_edid() helper, -it will be called from dw_hdmi_connector_detect(). - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index e4948db..daa4351 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2084,7 +2084,8 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); - } - --static int dw_hdmi_connector_get_modes(struct drm_connector *connector) -+static int dw_hdmi_connector_update_edid(struct drm_connector *connector, -+ bool add_modes) - { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); -@@ -2103,7 +2104,8 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) - hdmi->sink_has_audio = drm_detect_monitor_audio(edid); - drm_connector_update_edid_property(connector, edid); - cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); -- ret = drm_add_edid_modes(connector, edid); -+ if (add_modes) -+ ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } else { - dev_dbg(hdmi->dev, "failed to get edid\n"); -@@ -2112,6 +2114,11 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) - return ret; - } - -+static int dw_hdmi_connector_get_modes(struct drm_connector *connector) -+{ -+ return dw_hdmi_connector_update_edid(connector, true); -+} -+ - static void dw_hdmi_connector_force(struct drm_connector *connector) - { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, --- -2.7.4 - - -From ccf5389b259e8b30ce30ccfcbf573004dfd6a888 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 11:38:43 +0100 -Subject: [PATCH 02/15] drm: dw-hdmi: move dw_hdmi_connector_detect() - -Move dw_hdmi_connector_detect() it will call dw_hdmi_connector_update_edid(). - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index daa4351..6e20041 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2069,21 +2069,6 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) - hdmi->rxsense); - } - --static enum drm_connector_status --dw_hdmi_connector_detect(struct drm_connector *connector, bool force) --{ -- struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, -- connector); -- -- mutex_lock(&hdmi->mutex); -- hdmi->force = DRM_FORCE_UNSPECIFIED; -- dw_hdmi_update_power(hdmi); -- dw_hdmi_update_phy_mask(hdmi); -- mutex_unlock(&hdmi->mutex); -- -- return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); --} -- - static int dw_hdmi_connector_update_edid(struct drm_connector *connector, - bool add_modes) - { -@@ -2114,6 +2099,21 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, - return ret; - } - -+static enum drm_connector_status -+dw_hdmi_connector_detect(struct drm_connector *connector, bool force) -+{ -+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, -+ connector); -+ -+ mutex_lock(&hdmi->mutex); -+ hdmi->force = DRM_FORCE_UNSPECIFIED; -+ dw_hdmi_update_power(hdmi); -+ dw_hdmi_update_phy_mask(hdmi); -+ mutex_unlock(&hdmi->mutex); -+ -+ return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); -+} -+ - static int dw_hdmi_connector_get_modes(struct drm_connector *connector) - { - return dw_hdmi_connector_update_edid(connector, true); --- -2.7.4 - - -From b589578b0dd467100be6165258ce8a34fd1d7ca2 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 10:22:09 +0100 -Subject: [PATCH 03/15] drm: dw-hdmi: update CEC phys addr and EDID on HPD - event - -Update CEC phys addr and EDID on HPD event, fixes lost CEC phys addr and -stale EDID when HDMI cable is unplugged/replugged or AVR is powered on/off. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 14 +++++++++----- - 1 file changed, 9 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 6e20041..c438142 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2102,6 +2102,7 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, - static enum drm_connector_status - dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - { -+ enum drm_connector_status status; - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); - -@@ -2111,7 +2112,14 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - dw_hdmi_update_phy_mask(hdmi); - mutex_unlock(&hdmi->mutex); - -- return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); -+ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); -+ -+ if (status == connector_status_connected) -+ dw_hdmi_connector_update_edid(connector, false); -+ else -+ cec_notifier_set_phys_addr(hdmi->cec_notifier, CEC_PHYS_ADDR_INVALID); -+ -+ return status; - } - - static int dw_hdmi_connector_get_modes(struct drm_connector *connector) -@@ -2326,10 +2334,6 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) - dw_hdmi_setup_rx_sense(hdmi, - phy_stat & HDMI_PHY_HPD, - phy_stat & HDMI_PHY_RX_SENSE); -- -- if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0) -- cec_notifier_set_phys_addr(hdmi->cec_notifier, -- CEC_PHYS_ADDR_INVALID); - } - - if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { --- -2.7.4 - - -From c168ef33a8f989a7a05879ae1f79c30e5d54dc1e Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 10:22:09 +0100 -Subject: [PATCH 04/15] Revert "drm/edid: make drm_edid_to_eld() static" - -drm_edid_to_eld() is needed to update stale connector ELD on HPD event. - -This reverts part of commit 79436a1c9bccf5e38cb6ea26e4e4b9283baf2e20. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/drm_edid.c | 5 +++-- - include/drm/drm_edid.h | 1 + - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c -index 990b190..288534e 100644 ---- a/drivers/gpu/drm/drm_edid.c -+++ b/drivers/gpu/drm/drm_edid.c -@@ -3906,7 +3906,7 @@ static void clear_eld(struct drm_connector *connector) - connector->audio_latency[1] = 0; - } - --/* -+/** - * drm_edid_to_eld - build ELD from EDID - * @connector: connector corresponding to the HDMI/DP sink - * @edid: EDID to parse -@@ -3914,7 +3914,7 @@ static void clear_eld(struct drm_connector *connector) - * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The - * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. - */ --static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) -+void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) - { - uint8_t *eld = connector->eld; - u8 *cea; -@@ -3999,6 +3999,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) - DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", - drm_eld_size(eld), total_sad_count); - } -+EXPORT_SYMBOL(drm_edid_to_eld); - - /** - * drm_edid_to_sad - extracts SADs from EDID -diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h -index 8dc1a08..4784784 100644 ---- a/include/drm/drm_edid.h -+++ b/include/drm/drm_edid.h -@@ -333,6 +333,7 @@ struct drm_encoder; - struct drm_connector; - struct drm_display_mode; - -+void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid); - int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads); - int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb); - int drm_av_sync_delay(struct drm_connector *connector, --- -2.7.4 - - -From a632d4ce08386c9929fa0f81eecccab200dc1577 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 10:22:09 +0100 -Subject: [PATCH 05/15] drm: dw-hdmi: update ELD on HPD event - -Update connector ELD on HPD event, fixes stale ELD when -HDMI cable is unplugged/replugged or AVR is powered on/off. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index c438142..efd4399 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2091,6 +2091,8 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, - cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); - if (add_modes) - ret = drm_add_edid_modes(connector, edid); -+ else -+ drm_edid_to_eld(connector, edid); - kfree(edid); - } else { - dev_dbg(hdmi->dev, "failed to get edid\n"); --- -2.7.4 - - -From 99ee583dce02d6f2432390f2af4c6c3ecb2c81a8 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 10:22:09 +0100 -Subject: [PATCH 06/15] ASoC: hdmi-codec: add hdmi_codec_eld_notify() - -Add helper that will notify userspace when ELD control has changed. - -Signed-off-by: Jonas Karlman ---- - include/sound/hdmi-codec.h | 2 ++ - sound/soc/codecs/hdmi-codec.c | 26 ++++++++++++++++++++++---- - 2 files changed, 24 insertions(+), 4 deletions(-) - -diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h -index 9483c55..7cf66a4 100644 ---- a/include/sound/hdmi-codec.h -+++ b/include/sound/hdmi-codec.h -@@ -107,6 +107,8 @@ struct hdmi_codec_pdata { - void *data; - }; - -+void hdmi_codec_eld_notify(struct device *dev); -+ - #define HDMI_CODEC_DRV_NAME "hdmi-audio-codec" - - #endif /* __HDMI_CODEC_H__ */ -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 6a0cc8d..367e663 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -282,6 +282,8 @@ struct hdmi_codec_priv { - struct snd_pcm_chmap *chmap_info; - unsigned int chmap_idx; - struct mutex lock; -+ struct snd_card *snd_card; -+ struct snd_kcontrol *kctl; - }; - - static const struct snd_soc_dapm_widget hdmi_widgets[] = { -@@ -614,7 +616,6 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, - { - struct snd_soc_dai_driver *drv = dai->driver; - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); -- struct snd_kcontrol *kctl; - struct snd_kcontrol_new hdmi_eld_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE, -@@ -641,12 +642,29 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - - /* add ELD ctl with the device number corresponding to the PCM stream */ -- kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); -- if (!kctl) -+ hcp->kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); -+ if (!hcp->kctl) - return -ENOMEM; - -- return snd_ctl_add(rtd->card->snd_card, kctl); -+ hcp->snd_card = rtd->card->snd_card; -+ -+ return snd_ctl_add(hcp->snd_card, hcp->kctl); -+} -+ -+void hdmi_codec_eld_notify(struct device *dev) -+{ -+ struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); -+ struct snd_ctl_elem_id id; -+ -+ if (!hcp || -+ !hcp->snd_card || -+ !hcp->kctl) -+ return; -+ -+ id = hcp->kctl->id; -+ snd_ctl_notify(hcp->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &id); - } -+EXPORT_SYMBOL_GPL(hdmi_codec_eld_notify); - - static int hdmi_dai_probe(struct snd_soc_dai *dai) - { --- -2.7.4 - - -From 93719d8e794d72ac21c2a433360b4cf9813fbd04 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 12:56:33 +0100 -Subject: [PATCH 07/15] drm: dw-hdmi: add dw_hdmi_update_eld() callback - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 15 +++++++++++++++ - include/drm/bridge/dw_hdmi.h | 2 ++ - 2 files changed, 17 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index efd4399..3a031d1 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -188,6 +188,7 @@ struct dw_hdmi { - struct regmap *regm; - void (*enable_audio)(struct dw_hdmi *hdmi); - void (*disable_audio)(struct dw_hdmi *hdmi); -+ void (*update_eld)(struct device *dev, u8 *eld); - - struct cec_notifier *cec_notifier; - }; -@@ -624,6 +625,19 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi) - } - EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); - -+static void dw_hdmi_update_eld(struct dw_hdmi *hdmi, u8 *eld) -+{ -+ if (hdmi->audio && hdmi->update_eld) -+ hdmi->update_eld(&hdmi->audio->dev, eld); -+} -+ -+void dw_hdmi_set_update_eld(struct dw_hdmi *hdmi, -+ void (*update_eld)(struct device *dev, u8 *eld)) -+{ -+ hdmi->update_eld = update_eld; -+} -+EXPORT_SYMBOL_GPL(dw_hdmi_set_update_eld); -+ - static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format) - { - switch (bus_format) { -@@ -2093,6 +2107,7 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, - ret = drm_add_edid_modes(connector, edid); - else - drm_edid_to_eld(connector, edid); -+ dw_hdmi_update_eld(hdmi, connector->eld); - kfree(edid); - } else { - dev_dbg(hdmi->dev, "failed to get edid\n"); -diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h -index ede8bff..57e2d18 100644 ---- a/include/drm/bridge/dw_hdmi.h -+++ b/include/drm/bridge/dw_hdmi.h -@@ -165,6 +165,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); - void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); - void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); - void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); -+void dw_hdmi_set_update_eld(struct dw_hdmi *hdmi, -+ void (*update_eld)(struct device *dev, u8 *eld)); - void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi); - - /* PHY configuration */ --- -2.7.4 - - -From ae1a9144f7dce398403f8cb6f0539fc0a387d53a Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 16 Dec 2018 10:22:09 +0100 -Subject: [PATCH 08/15] drm: dw-hdmi-i2s: add .get_eld callback for ALSA SoC - -Add get_eld() callback and call hdmi_codec_eld_notify() when ELD has changed. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 + - .../gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 36 +++++++++++++++++++++- - 2 files changed, 36 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h -index 63b5756..69b8a97 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h -@@ -14,6 +14,7 @@ struct dw_hdmi_audio_data { - - struct dw_hdmi_i2s_audio_data { - struct dw_hdmi *hdmi; -+ u8 eld[128]; - - void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); - u8 (*read)(struct dw_hdmi *hdmi, int offset); -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -index cdb1480..2eab862 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -@@ -104,6 +104,32 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) - hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); - } - -+static void dw_hdmi_i2s_update_eld(struct device *dev, u8 *eld) -+{ -+ struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(dev); -+ struct platform_device *hcpdev = dev_get_drvdata(dev); -+ -+ if (!audio || !hcpdev) -+ return; -+ -+ if (!memcmp(audio->eld, eld, sizeof(audio->eld))) -+ return; -+ -+ memcpy(audio->eld, eld, sizeof(audio->eld)); -+ -+ hdmi_codec_eld_notify(&hcpdev->dev); -+} -+ -+static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, -+ u8 *buf, size_t len) -+{ -+ struct dw_hdmi_i2s_audio_data *audio = data; -+ -+ memcpy(buf, audio->eld, min(sizeof(audio->eld), len)); -+ -+ return 0; -+} -+ - static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) - { -@@ -127,16 +153,19 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - static struct hdmi_codec_ops dw_hdmi_i2s_ops = { - .hw_params = dw_hdmi_i2s_hw_params, - .audio_shutdown = dw_hdmi_i2s_audio_shutdown, -+ .get_eld = dw_hdmi_i2s_get_eld, - .get_dai_id = dw_hdmi_i2s_get_dai_id, - }; - - static int snd_dw_hdmi_probe(struct platform_device *pdev) - { -- struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data; -+ struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(&pdev->dev); - struct platform_device_info pdevinfo; - struct hdmi_codec_pdata pdata; - struct platform_device *platform; - -+ memset(audio->eld, 0, sizeof(audio->eld)); -+ - pdata.ops = &dw_hdmi_i2s_ops; - pdata.i2s = 1; - pdata.max_i2s_channels = 8; -@@ -156,13 +185,18 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) - - dev_set_drvdata(&pdev->dev, platform); - -+ dw_hdmi_set_update_eld(audio->hdmi, dw_hdmi_i2s_update_eld); -+ - return 0; - } - - static int snd_dw_hdmi_remove(struct platform_device *pdev) - { -+ struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(&pdev->dev); - struct platform_device *platform = dev_get_drvdata(&pdev->dev); - -+ dw_hdmi_set_update_eld(audio->hdmi, NULL); -+ - platform_device_unregister(platform); - - return 0; --- -2.7.4 - - -From 743a2323412554e399fcb833c1554b5e9deefc37 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 25 Mar 2018 22:17:06 +0200 -Subject: [PATCH 09/15] ASoC: hdmi-codec: reorder channel allocation list - -Wrong channel allocation is selected by hdmi_codec_get_ch_alloc_table_idx(). - -E.g when ELD reports FL|FR|LFE|FC|RL|RR or FL|FR|LFE|FC|RL|RR|RC|RLC|RRC - -ca_id 0x01 with speaker mask FL|FR|LFE gets selected instead of -ca_id 0x03 with speaker mask FL|FR|LFE|FC for 4 channels - -and - -ca_id 0x04 with speaker mask FL|FR|RC gets selected instead of -ca_id 0x0b with speaker mask FL|FR|LFE|FC|RL|RR for 6 channels - -Fix this by reorder the channel allocation list with -most specific speaker mask at the top. - -Signed-off-by: Jonas Karlman ---- - sound/soc/codecs/hdmi-codec.c | 115 +++++++++++++++++++----------------------- - 1 file changed, 53 insertions(+), 62 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 367e663..4cacade 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -196,84 +196,75 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { - /* - * hdmi_codec_channel_alloc: speaker configuration available for CEA - * -- * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct -+ * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps - * The preceding ones have better chances to be selected by - * hdmi_codec_get_ch_alloc_table_idx(). - */ - static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { - { .ca_id = 0x00, .n_ch = 2, -- .mask = FL | FR}, -- /* 2.1 */ -- { .ca_id = 0x01, .n_ch = 4, -- .mask = FL | FR | LFE}, -- /* Dolby Surround */ -+ .mask = FL | FR }, -+ { .ca_id = 0x03, .n_ch = 4, -+ .mask = FL | FR | LFE | FC }, - { .ca_id = 0x02, .n_ch = 4, - .mask = FL | FR | FC }, -- /* surround51 */ -+ { .ca_id = 0x01, .n_ch = 4, -+ .mask = FL | FR | LFE }, - { .ca_id = 0x0b, .n_ch = 6, -- .mask = FL | FR | LFE | FC | RL | RR}, -- /* surround40 */ -- { .ca_id = 0x08, .n_ch = 6, -- .mask = FL | FR | RL | RR }, -- /* surround41 */ -- { .ca_id = 0x09, .n_ch = 6, -- .mask = FL | FR | LFE | RL | RR }, -- /* surround50 */ -+ .mask = FL | FR | LFE | FC | RL | RR }, - { .ca_id = 0x0a, .n_ch = 6, - .mask = FL | FR | FC | RL | RR }, -- /* 6.1 */ -- { .ca_id = 0x0f, .n_ch = 8, -- .mask = FL | FR | LFE | FC | RL | RR | RC }, -- /* surround71 */ -+ { .ca_id = 0x09, .n_ch = 6, -+ .mask = FL | FR | LFE | RL | RR }, -+ { .ca_id = 0x08, .n_ch = 6, -+ .mask = FL | FR | RL | RR }, -+ { .ca_id = 0x07, .n_ch = 6, -+ .mask = FL | FR | LFE | FC | RC }, -+ { .ca_id = 0x06, .n_ch = 6, -+ .mask = FL | FR | FC | RC }, -+ { .ca_id = 0x05, .n_ch = 6, -+ .mask = FL | FR | LFE | RC }, -+ { .ca_id = 0x04, .n_ch = 6, -+ .mask = FL | FR | RC }, - { .ca_id = 0x13, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, -- /* others */ -- { .ca_id = 0x03, .n_ch = 8, -- .mask = FL | FR | LFE | FC }, -- { .ca_id = 0x04, .n_ch = 8, -- .mask = FL | FR | RC}, -- { .ca_id = 0x05, .n_ch = 8, -- .mask = FL | FR | LFE | RC }, -- { .ca_id = 0x06, .n_ch = 8, -- .mask = FL | FR | FC | RC }, -- { .ca_id = 0x07, .n_ch = 8, -- .mask = FL | FR | LFE | FC | RC }, -- { .ca_id = 0x0c, .n_ch = 8, -- .mask = FL | FR | RC | RL | RR }, -- { .ca_id = 0x0d, .n_ch = 8, -- .mask = FL | FR | LFE | RL | RR | RC }, -- { .ca_id = 0x0e, .n_ch = 8, -- .mask = FL | FR | FC | RL | RR | RC }, -- { .ca_id = 0x10, .n_ch = 8, -- .mask = FL | FR | RL | RR | RLC | RRC }, -- { .ca_id = 0x11, .n_ch = 8, -- .mask = FL | FR | LFE | RL | RR | RLC | RRC }, -+ { .ca_id = 0x1f, .n_ch = 8, -+ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, - { .ca_id = 0x12, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | RLC | RRC }, -- { .ca_id = 0x14, .n_ch = 8, -- .mask = FL | FR | FLC | FRC }, -- { .ca_id = 0x15, .n_ch = 8, -- .mask = FL | FR | LFE | FLC | FRC }, -- { .ca_id = 0x16, .n_ch = 8, -- .mask = FL | FR | FC | FLC | FRC }, -- { .ca_id = 0x17, .n_ch = 8, -- .mask = FL | FR | LFE | FC | FLC | FRC }, -- { .ca_id = 0x18, .n_ch = 8, -- .mask = FL | FR | RC | FLC | FRC }, -- { .ca_id = 0x19, .n_ch = 8, -- .mask = FL | FR | LFE | RC | FLC | FRC }, -- { .ca_id = 0x1a, .n_ch = 8, -- .mask = FL | FR | RC | FC | FLC | FRC }, -- { .ca_id = 0x1b, .n_ch = 8, -- .mask = FL | FR | LFE | RC | FC | FLC | FRC }, -- { .ca_id = 0x1c, .n_ch = 8, -- .mask = FL | FR | RL | RR | FLC | FRC }, -- { .ca_id = 0x1d, .n_ch = 8, -- .mask = FL | FR | LFE | RL | RR | FLC | FRC }, - { .ca_id = 0x1e, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | FLC | FRC }, -- { .ca_id = 0x1f, .n_ch = 8, -- .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, -+ { .ca_id = 0x11, .n_ch = 8, -+ .mask = FL | FR | LFE | RL | RR | RLC | RRC }, -+ { .ca_id = 0x1d, .n_ch = 8, -+ .mask = FL | FR | LFE | RL | RR | FLC | FRC }, -+ { .ca_id = 0x10, .n_ch = 8, -+ .mask = FL | FR | RL | RR | RLC | RRC }, -+ { .ca_id = 0x1c, .n_ch = 8, -+ .mask = FL | FR | RL | RR | FLC | FRC }, -+ { .ca_id = 0x0f, .n_ch = 8, -+ .mask = FL | FR | LFE | FC | RL | RR | RC }, -+ { .ca_id = 0x1b, .n_ch = 8, -+ .mask = FL | FR | LFE | RC | FC | FLC | FRC }, -+ { .ca_id = 0x0e, .n_ch = 8, -+ .mask = FL | FR | FC | RL | RR | RC }, -+ { .ca_id = 0x1a, .n_ch = 8, -+ .mask = FL | FR | RC | FC | FLC | FRC }, -+ { .ca_id = 0x0d, .n_ch = 8, -+ .mask = FL | FR | LFE | RL | RR | RC }, -+ { .ca_id = 0x19, .n_ch = 8, -+ .mask = FL | FR | LFE | RC | FLC | FRC }, -+ { .ca_id = 0x0c, .n_ch = 8, -+ .mask = FL | FR | RC | RL | RR }, -+ { .ca_id = 0x18, .n_ch = 8, -+ .mask = FL | FR | RC | FLC | FRC }, -+ { .ca_id = 0x17, .n_ch = 8, -+ .mask = FL | FR | LFE | FC | FLC | FRC }, -+ { .ca_id = 0x16, .n_ch = 8, -+ .mask = FL | FR | FC | FLC | FRC }, -+ { .ca_id = 0x15, .n_ch = 8, -+ .mask = FL | FR | LFE | FLC | FRC }, -+ { .ca_id = 0x14, .n_ch = 8, -+ .mask = FL | FR | FLC | FRC }, - }; - - struct hdmi_codec_priv { --- -2.7.4 - - -From 16b832719367b751845159338b64dd0f31d00fd2 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 10 Jul 2018 20:54:33 +0200 -Subject: [PATCH 10/15] drm: dw-hdmi-i2s: add multi-channel lpcm support - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 + - .../gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 73 +++++++++++++++++++++- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 + - drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 24 +++++++ - 4 files changed, 97 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h -index 69b8a97..9e9cbf9 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h -@@ -18,6 +18,7 @@ struct dw_hdmi_i2s_audio_data { - - void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); - u8 (*read)(struct dw_hdmi *hdmi, int offset); -+ void (*mod)(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg); - }; - - #endif -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -index 2eab862..4bc97ab 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -@@ -33,6 +33,14 @@ static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset) - return audio->read(hdmi, offset); - } - -+static inline void hdmi_update_bits(struct dw_hdmi_i2s_audio_data *audio, -+ u8 data, u8 mask, unsigned int reg) -+{ -+ struct dw_hdmi *hdmi = audio->hdmi; -+ -+ audio->mod(hdmi, data, mask, reg); -+} -+ - static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, - struct hdmi_codec_daifmt *fmt, - struct hdmi_codec_params *hparms) -@@ -42,6 +50,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, - u8 conf0 = 0; - u8 conf1 = 0; - u8 inputclkfs = 0; -+ u8 val; - - /* it cares I2S only */ - if (fmt->bit_clk_master | fmt->frame_clk_master) { -@@ -49,8 +58,23 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, - return -EINVAL; - } - -- inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; -- conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; -+ inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; -+ -+ switch (hparms->channels) { -+ case 2: -+ conf0 = HDMI_AUD_CONF0_I2S_2CHANNEL_ENABLE; -+ break; -+ case 4: -+ conf0 = HDMI_AUD_CONF0_I2S_4CHANNEL_ENABLE; -+ break; -+ case 6: -+ conf0 = HDMI_AUD_CONF0_I2S_6CHANNEL_ENABLE; -+ break; -+ case 8: -+ default: -+ conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; -+ break; -+ } - - switch (hparms->sample_width) { - case 16: -@@ -83,12 +107,56 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, - return -EINVAL; - } - -+ hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET, -+ HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); -+ hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); -+ - dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); - - hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); - hdmi_write(audio, conf0, HDMI_AUD_CONF0); - hdmi_write(audio, conf1, HDMI_AUD_CONF1); - -+ val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0; -+ if (hparms->channels > 2) -+ val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1; -+ hdmi_update_bits(audio, val, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK, -+ HDMI_FC_AUDSCONF); -+ -+ switch (hparms->sample_rate) { -+ case 32000: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_32K; -+ break; -+ case 44100: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_441K; -+ break; -+ case 48000: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_48K; -+ break; -+ case 88200: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_882K; -+ break; -+ case 96000: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_96K; -+ break; -+ case 176400: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_1764K; -+ break; -+ case 192000: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_192K; -+ break; -+ default: -+ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_441K; -+ break; -+ } -+ -+ hdmi_update_bits(audio, val, HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK, -+ HDMI_FC_AUDSCHNLS7); -+ hdmi_update_bits(audio, -+ (hparms->channels - 1) << HDMI_FC_AUDICONF0_CC_OFFSET, -+ HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0); -+ hdmi_write(audio, hparms->cea.channel_allocation, HDMI_FC_AUDICONF2); -+ - dw_hdmi_audio_enable(hdmi); - - return 0; -@@ -102,6 +170,7 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) - dw_hdmi_audio_disable(hdmi); - - hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); -+ hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); - } - - static void dw_hdmi_i2s_update_eld(struct device *dev, u8 *eld) -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 3a031d1..69ad730 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2717,6 +2717,7 @@ __dw_hdmi_probe(struct platform_device *pdev, - audio.hdmi = hdmi; - audio.write = hdmi_writeb; - audio.read = hdmi_readb; -+ audio.mod = hdmi_modb; - hdmi->enable_audio = dw_hdmi_i2s_audio_enable; - hdmi->disable_audio = dw_hdmi_i2s_audio_disable; - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -index 6ff14dc..5c4cbd5 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -@@ -162,6 +162,15 @@ - #define HDMI_FC_SPDDEVICEINF 0x1062 - #define HDMI_FC_AUDSCONF 0x1063 - #define HDMI_FC_AUDSSTAT 0x1064 -+#define HDMI_FC_AUDSCHNLS0 0x1067 -+#define HDMI_FC_AUDSCHNLS1 0x1068 -+#define HDMI_FC_AUDSCHNLS2 0x1069 -+#define HDMI_FC_AUDSCHNLS3 0x106a -+#define HDMI_FC_AUDSCHNLS4 0x106b -+#define HDMI_FC_AUDSCHNLS5 0x106c -+#define HDMI_FC_AUDSCHNLS6 0x106d -+#define HDMI_FC_AUDSCHNLS7 0x106e -+#define HDMI_FC_AUDSCHNLS8 0x106f - #define HDMI_FC_DATACH0FILL 0x1070 - #define HDMI_FC_DATACH1FILL 0x1071 - #define HDMI_FC_DATACH2FILL 0x1072 -@@ -710,6 +719,8 @@ enum { - /* HDMI_FC_AUDSCHNLS7 field values */ - HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4, - HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30, -+ HDMI_FC_AUDSCHNLS7_SAMPFREQ_OFFSET = 0, -+ HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK = 0x0f, - - /* HDMI_FC_AUDSCHNLS8 field values */ - HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0, -@@ -717,6 +728,15 @@ enum { - HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f, - HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0, - -+/* HDMI_FC_AUDSCHNLS sampling frequency */ -+ HDMI_FC_AUDSCHNLS_SAMPFREQ_32K = 0x3, -+ HDMI_FC_AUDSCHNLS_SAMPFREQ_441K = 0x0, -+ HDMI_FC_AUDSCHNLS_SAMPFREQ_48K = 0x2, -+ HDMI_FC_AUDSCHNLS_SAMPFREQ_882K = 0x8, -+ HDMI_FC_AUDSCHNLS_SAMPFREQ_96K = 0xa, -+ HDMI_FC_AUDSCHNLS_SAMPFREQ_1764K = 0xc, -+ HDMI_FC_AUDSCHNLS_SAMPFREQ_192K = 0xe, -+ - /* FC_AUDSCONF field values */ - HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0, - HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4, -@@ -869,6 +889,9 @@ enum { - - /* AUD_CONF0 field values */ - HDMI_AUD_CONF0_SW_RESET = 0x80, -+ HDMI_AUD_CONF0_I2S_2CHANNEL_ENABLE = 0x21, -+ HDMI_AUD_CONF0_I2S_4CHANNEL_ENABLE = 0x23, -+ HDMI_AUD_CONF0_I2S_6CHANNEL_ENABLE = 0x27, - HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F, - - /* AUD_CONF1 field values */ -@@ -944,6 +967,7 @@ enum { - HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1, - - /* MC_SWRSTZ field values */ -+ HDMI_MC_SWRSTZ_I2SSWRST_REQ = 0x08, - HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02, - - /* MC_FLOWCTRL field values */ --- -2.7.4 - - -From 0e4dfdd42b6b9c2efe9adc199177336bdf1593c7 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Mon, 9 Jul 2018 21:25:15 +0200 -Subject: [PATCH 11/15] drm: dw-hdmi: call hdmi_set_cts_n after clock is - enabled - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 69ad730..844fd4b 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -578,6 +578,11 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) - else - hdmi->mc_clkdis |= HDMI_MC_CLKDIS_AUDCLK_DISABLE; - hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); -+ -+ if (enable) { -+ hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0); -+ hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); -+ } - } - - static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) --- -2.7.4 - - -From 8b260e3406c683012df816bfd59766b1f365b804 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 23 Dec 2018 02:24:38 +0100 -Subject: [PATCH 12/15] fix chmap_idx - ---- - sound/soc/codecs/hdmi-codec.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index 4cacade..3b04f84 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -370,7 +370,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct hdmi_codec_priv *hcp = info->private_data; - -- map = info->chmap[hcp->chmap_idx].map; -+ if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN) -+ map = info->chmap[hcp->chmap_idx].map; - - for (i = 0; i < info->max_channels; i++) { - if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) --- -2.7.4 - - -From 7039ea0f6f9fffbfe942903df3cb5bfa70ced5ed Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Wed, 2 Jan 2019 23:08:59 +0100 -Subject: [PATCH 13/15] media: cec-notifier: debounce callback setting invalid - phys addr - ---- - drivers/media/cec/cec-notifier.c | 19 ++++++++++++++++++- - 1 file changed, 18 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c -index 9598c77..1b665a9 100644 ---- a/drivers/media/cec/cec-notifier.c -+++ b/drivers/media/cec/cec-notifier.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -27,11 +28,23 @@ struct cec_notifier { - void (*callback)(struct cec_adapter *adap, u16 pa); - - u16 phys_addr; -+ struct delayed_work work; - }; - - static LIST_HEAD(cec_notifiers); - static DEFINE_MUTEX(cec_notifiers_lock); - -+static void cec_notifier_delayed_work(struct work_struct *work) -+{ -+ struct cec_notifier *n = -+ container_of(to_delayed_work(work), struct cec_notifier, work); -+ -+ mutex_lock(&n->lock); -+ if (n->callback) -+ n->callback(n->cec_adap, n->phys_addr); -+ mutex_unlock(&n->lock); -+} -+ - struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) - { - struct cec_notifier *n; -@@ -52,6 +65,7 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) - if (conn) - n->conn = kstrdup(conn, GFP_KERNEL); - n->phys_addr = CEC_PHYS_ADDR_INVALID; -+ INIT_DELAYED_WORK(&n->work, cec_notifier_delayed_work); - mutex_init(&n->lock); - kref_init(&n->kref); - list_add_tail(&n->head, &cec_notifiers); -@@ -84,9 +98,12 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) - if (n == NULL) - return; - -+ cancel_delayed_work_sync(&n->work); - mutex_lock(&n->lock); - n->phys_addr = pa; -- if (n->callback) -+ if (pa == CEC_PHYS_ADDR_INVALID) -+ schedule_delayed_work(&n->work, msecs_to_jiffies(5000)); -+ else if (n->callback) - n->callback(n->cec_adap, n->phys_addr); - mutex_unlock(&n->lock); - } --- -2.7.4 - - -From e9001fa0bf51038a9cbdf69cca5453cdb09b1aa4 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 26 Feb 2019 20:45:14 +0000 -Subject: [PATCH 14/15] WIP: dw-hdmi-cec: sleep 100ms on error - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 18 ++++++++++++++++-- - 1 file changed, 16 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c -index 6c32351..b5a1a85 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c -@@ -7,6 +7,7 @@ - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -+#include - #include - #include - #include -@@ -132,8 +133,15 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) - - dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0); - -- if (stat & CEC_STAT_ERROR_INIT) { -- cec->tx_status = CEC_TX_STATUS_ERROR; -+ /* Status with both done and error_initiator bits have been seen -+ * on Rockchip RK3328 devices, transmit attempt seems to have failed -+ * when this happens, report as low drive and block cec-framework -+ * 100ms before core retransmits the failed message, this seems to -+ * mitigate the issue with failed transmit attempts. -+ */ -+ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) { -+ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat); -+ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; - cec->tx_done = true; - ret = IRQ_WAKE_THREAD; - } else if (stat & CEC_STAT_DONE) { -@@ -144,6 +152,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) - cec->tx_status = CEC_TX_STATUS_NACK; - cec->tx_done = true; - ret = IRQ_WAKE_THREAD; -+ } else if (stat & CEC_STAT_ERROR_INIT) { -+ cec->tx_status = CEC_TX_STATUS_ERROR; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; - } - - if (stat & CEC_STAT_EOM) { -@@ -176,6 +188,8 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) - - if (cec->tx_done) { - cec->tx_done = false; -+ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) -+ msleep(100); - cec_transmit_attempt_done(adap, cec->tx_status); - } - if (cec->rx_done) { --- -2.7.4 - - -From 3f12c4a5852b51439fcea2bb6f0d4e2ae5e7f863 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 3 May 2019 01:34:16 +0000 -Subject: [PATCH 15/15] drm: dw-hdmi-i2s: add .digital_mute callback for ALSA - SoC - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -index 4bc97ab..c526860 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c -@@ -173,6 +173,17 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) - hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); - } - -+static int dw_hdmi_i2s_digital_mute(struct device *dev, void *data, bool enable) -+{ -+ struct dw_hdmi_i2s_audio_data *audio = data; -+ -+ hdmi_update_bits(audio, enable ? 0 : 0xf, -+ HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK, -+ HDMI_FC_AUDSCONF); -+ -+ return 0; -+} -+ - static void dw_hdmi_i2s_update_eld(struct device *dev, u8 *eld) - { - struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(dev); -@@ -222,6 +233,7 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - static struct hdmi_codec_ops dw_hdmi_i2s_ops = { - .hw_params = dw_hdmi_i2s_hw_params, - .audio_shutdown = dw_hdmi_i2s_audio_shutdown, -+ .digital_mute = dw_hdmi_i2s_digital_mute, - .get_eld = dw_hdmi_i2s_get_eld, - .get_dai_id = dw_hdmi_i2s_get_dai_id, - }; --- -2.7.4 - diff --git a/projects/Amlogic/patches/linux/e-0011-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-many-.patch b/projects/Amlogic/patches/linux/e-0011-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-many-.patch deleted file mode 100644 index 0897ef34d9..0000000000 --- a/projects/Amlogic/patches/linux/e-0011-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-many-.patch +++ /dev/null @@ -1,255 +0,0 @@ -From d724c862a105e5921abf71275d1e250bb4331a3d Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Sat, 13 Apr 2019 06:18:39 +0000 -Subject: [PATCH 11/37] arm64: dts: meson-gxbb-vega-s95: update dtsi with many - changes - -Signed-off-by: Christian Hewitt ---- - .../boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 133 ++++++++++++++++-- - 1 file changed, 119 insertions(+), 14 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi -index d8c262b9be01..58aaa196d576 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi -@@ -4,12 +4,15 @@ - */ - - #include "meson-gxbb.dtsi" -+#include -+#include - - / { - compatible = "tronsmart,vega-s95", "amlogic,meson-gxbb"; - - aliases { - serial0 = &uart_AO; -+ serial1 = &uart_A; - ethernet0 = ðmac; - }; - -@@ -28,10 +31,10 @@ - }; - }; - -- usb_vbus: regulator-usb0-vbus { -+ usb_pwr: regulator-usb-pwrs { - compatible = "regulator-fixed"; - -- regulator-name = "USB0_VBUS"; -+ regulator-name = "USB_PWR"; - - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; -@@ -40,20 +43,34 @@ - enable-active-high; - }; - -- vcc_3v3: regulator-vcc_3v3 { -+ vddio_boot: regulator-vddio_boot { - compatible = "regulator-fixed"; -- regulator-name = "VCC_3V3"; -+ regulator-name = "VDDIO_BOOT"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ }; -+ -+ vddao_3v3: regulator-vddao_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - -- vcc_1v8: regulator-vcc_1v8 { -+ vddio_ao18: regulator-vddio_ao18 { - compatible = "regulator-fixed"; -- regulator-name = "VCC_1V8"; -+ regulator-name = "VDDIO_AO18"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - -+ vcc_3v3: regulator-vcc_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ }; -+ - emmc_pwrseq: emmc-pwrseq { - compatible = "mmc-pwrseq-emmc"; - reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; -@@ -66,15 +83,69 @@ - pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ - }; - -+ hdmi-connector { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi_connector_in: endpoint { -+ remote-endpoint = <&hdmi_tx_tmds_out>; -+ }; -+ }; -+ }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "HDMI"; -+ -+ assigned-clocks = <&clkc CLKID_MPLL2>, -+ <&clkc CLKID_MPLL0>, -+ <&clkc CLKID_MPLL1>; -+ assigned-clock-parents = <0>, <0>, <0>; -+ assigned-clock-rates = <294912000>, -+ <270950400>, -+ <393216000>; -+ -+ simple-audio-card,dai-link@0 { -+ /* HDMI Output */ -+ format = "i2s"; -+ mclk-fs = <128>; -+ bitclock-master = <&aiu_i2s>; -+ frame-master = <&aiu_i2s>; -+ -+ cpu { -+ sound-dai = <&aiu_i2s>; -+ }; -+ -+ codec { -+ sound-dai = <&hdmi_tx>; -+ }; -+ }; -+ }; -+ - sdio_pwrseq: sdio-pwrseq { - compatible = "mmc-pwrseq-simple"; -- reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>, -- <&gpio GPIOX_20 GPIO_ACTIVE_LOW>; -+ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; - clocks = <&wifi32k>; - clock-names = "ext_clock"; - }; - }; - -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ -+&cec_AO { -+ status = "okay"; -+ pinctrl-0 = <&ao_cec_pins>; -+ pinctrl-names = "default"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ - ðmac { - status = "okay"; - pinctrl-0 = <ð_rgmii_pins>; -@@ -97,10 +168,25 @@ - eth_phy0: ethernet-phy@0 { - /* Realtek RTL8211F (0x001cc916) */ - reg = <0>; -+ interrupt-parent = <&gpio_intc>; -+ /* MAC_INTR on GPIOZ_15 */ -+ interrupts = <29 IRQ_TYPE_LEVEL_LOW>; - }; - }; - }; - -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ - &ir { - status = "okay"; - pinctrl-0 = <&remote_input_ao_pins>; -@@ -115,10 +201,15 @@ - clock-names = "clkin0"; - }; - -+&saradc { -+ status = "okay"; -+ vref-supply = <&vddio_ao18>; -+}; -+ - /* Wireless SDIO Module */ - &sd_emmc_a { - status = "okay"; -- pinctrl-0 = <&sdio_pins &sdio_irq_pins>; -+ pinctrl-0 = <&sdio_pins>; - pinctrl-1 = <&sdio_clk_gate_pins>; - pinctrl-names = "default", "clk-gate"; - #address-cells = <1>; -@@ -133,8 +224,8 @@ - - mmc-pwrseq = <&sdio_pwrseq>; - -- vmmc-supply = <&vcc_3v3>; -- vqmmc-supply = <&vcc_1v8>; -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddio_boot>; - - brcmf: wifi@1 { - reg = <1>; -@@ -156,7 +247,8 @@ - - cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>; - -- vmmc-supply = <&vcc_3v3>; -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vcc_3v3>; - }; - - /* eMMC */ -@@ -176,9 +268,22 @@ - - mmc-pwrseq = <&emmc_pwrseq>; - vmmc-supply = <&vcc_3v3>; -- vmmcq-sumpply = <&vcc_1v8>; -+ vqmmc-supply = <&vddio_boot>; -+}; -+ -+/* This is connected to the Bluetooth module: */ -+&uart_A { -+ status = "okay"; -+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; -+ pinctrl-names = "default"; -+ -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ shutdown-gpios = <&gpio GPIOX_20 GPIO_ACTIVE_HIGH>; -+ }; - }; - -+/* This UART is brought out to the DB9 connector */ - &uart_AO { - status = "okay"; - pinctrl-0 = <&uart_ao_a_pins>; -@@ -187,7 +292,7 @@ - - &usb0_phy { - status = "okay"; -- phy-supply = <&usb_vbus>; -+ phy-supply = <&usb_pwr>; - }; - - &usb1_phy { --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0012-arm64-dts-meson-gxbb-wetek.dtsi-enable-bluetooth.patch b/projects/Amlogic/patches/linux/e-0012-arm64-dts-meson-gxbb-wetek.dtsi-enable-bluetooth.patch deleted file mode 100644 index 2e947837f3..0000000000 --- a/projects/Amlogic/patches/linux/e-0012-arm64-dts-meson-gxbb-wetek.dtsi-enable-bluetooth.patch +++ /dev/null @@ -1,50 +0,0 @@ -From ecffab2a2ca4471b37d984bda5c356ed811c46c1 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Sat, 13 Apr 2019 06:50:48 +0000 -Subject: [PATCH 12/37] arm64: dts: meson-gxbb-wetek.dtsi: enable bluetooth - -This enables Bluetooth support for the following models: - -AP6335 in the WeTek Hub rev1 - BCM4335C0.hcd -AP6255 in the WeTek Hub rev2 - BCM4345C0.hcd -AP6330 in the WeTek Play 2 - BCM4330B1.hcd (TBC) - -Signed-off-by: Christian Hewitt ---- - arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -index ff9b182afac7..5cdca2eed7d9 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -@@ -10,6 +10,7 @@ - / { - aliases { - serial0 = &uart_AO; -+ serial1 = &uart_A; - ethernet0 = ðmac; - }; - -@@ -274,6 +275,18 @@ - vqmmc-supply = <&vddio_boot>; - }; - -+/* This is connected to the Bluetooth module: */ -+&uart_A { -+ status = "okay"; -+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; -+ pinctrl-names = "default"; -+ -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ shutdown-gpios = <&gpio GPIOX_20 GPIO_ACTIVE_HIGH>; -+ }; -+}; -+ - /* This UART is brought out to the DB9 connector */ - &uart_AO { - status = "okay"; --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0013-arm64-dts-meson-gxbb-wetek.dtsi-enable-saradc-node.patch b/projects/Amlogic/patches/linux/e-0013-arm64-dts-meson-gxbb-wetek.dtsi-enable-saradc-node.patch deleted file mode 100644 index 736dfb27d8..0000000000 --- a/projects/Amlogic/patches/linux/e-0013-arm64-dts-meson-gxbb-wetek.dtsi-enable-saradc-node.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 17bb4637c8f9a78cab585b9f0d55960784fb90ed Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Sat, 13 Apr 2019 06:58:59 +0000 -Subject: [PATCH 13/37] arm64: dts: meson-gxbb-wetek.dtsi: enable saradc node - -Signed-off-by: Christian Hewitt ---- - arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -index 5cdca2eed7d9..e7d27daa1357 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi -@@ -60,6 +60,13 @@ - regulator-max-microvolt = <3300000>; - }; - -+ vddio_ao18: regulator-vddio_ao18 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDIO_AO18"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ }; -+ - vcc_3v3: regulator-vcc_3v3 { - compatible = "regulator-fixed"; - regulator-name = "VCC_3V3"; -@@ -210,6 +217,11 @@ - clock-names = "clkin0"; - }; - -+&saradc { -+ status = "okay"; -+ vref-supply = <&vddio_ao18>; -+}; -+ - /* Wireless SDIO Module */ - &sd_emmc_a { - status = "okay"; --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0016-arm64-dts-meson-gxbb-odroid-set-rc-odroid-ir-keymap.patch b/projects/Amlogic/patches/linux/e-0016-arm64-dts-meson-gxbb-odroid-set-rc-odroid-ir-keymap.patch deleted file mode 100644 index 3822b4b823..0000000000 --- a/projects/Amlogic/patches/linux/e-0016-arm64-dts-meson-gxbb-odroid-set-rc-odroid-ir-keymap.patch +++ /dev/null @@ -1,25 +0,0 @@ -From dd2f7889db3a060d67849344d33ed0693fdd3aef Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Wed, 24 Apr 2019 03:26:16 +0000 -Subject: [PATCH 16/37] arm64: dts: meson-gxbb-odroid: set rc-odroid ir keymap - -Signed-off-by: Christian Hewitt ---- - arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts -index 88816c20800f..723cd5a114aa 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts -@@ -220,6 +220,7 @@ - status = "okay"; - pinctrl-0 = <&remote_input_ao_pins>; - pinctrl-names = "default"; -+ linux,rc-map-name = "rc-odroid"; - }; - - &gpio_ao { --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0023-arm64-dts-meson-gxm-khadas-vim2-set-eee-broken-1000t.patch b/projects/Amlogic/patches/linux/e-0023-arm64-dts-meson-gxm-khadas-vim2-set-eee-broken-1000t.patch deleted file mode 100644 index bcb2dc5526..0000000000 --- a/projects/Amlogic/patches/linux/e-0023-arm64-dts-meson-gxm-khadas-vim2-set-eee-broken-1000t.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 05a9bf407fae671f1994d2a4504c23093b769f9f Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Sat, 13 Apr 2019 08:27:53 +0000 -Subject: [PATCH 23/37] arm64: dts: meson-gxm-khadas-vim2: set eee-broken-1000t - -Signed-off-by: Christian Hewitt ---- - arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -index b2dad05b89fe..dc6e33636082 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -@@ -297,6 +297,7 @@ - interrupt-parent = <&gpio_intc>; - /* MAC_INTR on GPIOZ_15 */ - interrupts = <25 IRQ_TYPE_LEVEL_LOW>; -+ eee-broken-1000t; - }; - }; - --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0024-arm64-dts-meson-gxm-khadas-vim2-fix-address-size-cel.patch b/projects/Amlogic/patches/linux/e-0024-arm64-dts-meson-gxm-khadas-vim2-fix-address-size-cel.patch deleted file mode 100644 index 80c60e170c..0000000000 --- a/projects/Amlogic/patches/linux/e-0024-arm64-dts-meson-gxm-khadas-vim2-fix-address-size-cel.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 688f83acbd11367a6ced2894329c462ee5a9caa6 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Tue, 16 Apr 2019 13:15:32 +0000 -Subject: [PATCH 24/37] arm64: dts: meson-gxm-khadas-vim2: fix address/size - cells dtc warnings - -Fix DTC warnings: - -arch/arm/dts/meson-gxm-khadas-vim2.dtb: Warning (avoid_unnecessary_addr_size): - /gpio-keys-polled: unnecessary #address-cells/#size-cells - without "ranges" or child "reg" property - -Signed-off-by: Christian Hewitt ---- - arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -index dc6e33636082..79981bf85678 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -@@ -63,8 +63,6 @@ - - gpio-keys-polled { - compatible = "gpio-keys-polled"; -- #address-cells = <1>; -- #size-cells = <0>; - poll-interval = <100>; - - button@0 { --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0025-arm64-dts-meson-gxm-khadas-vim2-set-bt-compatible.patch b/projects/Amlogic/patches/linux/e-0025-arm64-dts-meson-gxm-khadas-vim2-set-bt-compatible.patch deleted file mode 100644 index 40e6ee43da..0000000000 --- a/projects/Amlogic/patches/linux/e-0025-arm64-dts-meson-gxm-khadas-vim2-set-bt-compatible.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 10508df1fa03e4a4f3e46d3b3d3dcc2d29e15281 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Wed, 24 Apr 2019 13:58:32 +0000 -Subject: [PATCH 25/37] arm64: dts: meson-gxm-khadas-vim2: set bt compatible - -Signed-off-by: Christian Hewitt ---- - arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -index 79981bf85678..a4ab5615a603 100644 ---- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts -@@ -440,8 +440,14 @@ - /* This one is connected to the Bluetooth module */ - &uart_A { - status = "okay"; -- pinctrl-0 = <&uart_a_pins>; -+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; - pinctrl-names = "default"; -+ uart-has-rtscts; -+ -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; -+ }; - }; - - /* This is brought out on the Linux_RX (18) and Linux_TX (19) pins: */ --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0029-media-rc-add-keymap-for-KHAMSIN-remote.patch b/projects/Amlogic/patches/linux/e-0029-media-rc-add-keymap-for-KHAMSIN-remote.patch deleted file mode 100644 index 602f14cb0d..0000000000 --- a/projects/Amlogic/patches/linux/e-0029-media-rc-add-keymap-for-KHAMSIN-remote.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 63247dd85895163effd5cffeab10a9e080aa38d6 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Fri, 12 Apr 2019 12:26:30 +0000 -Subject: [PATCH 29/37] media: rc: add keymap for KHAMSIN remote - -Add an IR keymap for the KHAMSIN IR/BT remote supplied with the SmartLabs -SML-5442TW set-top box. The IR keymap allows basic GUI navigation to pair -the more functional BT mode of the remote. - -Signed-off-by: Christian Hewitt ---- - drivers/media/rc/keymaps/rc-khamsin.c | 76 +++++++++++++++++++++++++++ - 1 file changed, 76 insertions(+) - create mode 100644 drivers/media/rc/keymaps/rc-khamsin.c - -diff --git a/drivers/media/rc/keymaps/rc-khamsin.c b/drivers/media/rc/keymaps/rc-khamsin.c -new file mode 100644 -index 000000000000..c5c031f54414 ---- /dev/null -+++ b/drivers/media/rc/keymaps/rc-khamsin.c -@@ -0,0 +1,76 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// Copyright (c) 2019 Christian Hewitt -+ -+#include -+#include -+ -+/* -+ * KHAMSIN is an IR/Bluetooth RCU supplied with the SmartLabs -+ * SML-5442TW DVB-S/VOD box. The RCU has separate IR (TV) and -+ * BT (STB) modes. This keymap adds IR controls so that users -+ * can navigate and initiate BT pairing. -+ */ -+ -+static struct rc_map_table khamsin[] = { -+ { 0x70702, KEY_POWER}, -+ -+ { 0x70701, KEY_VIDEO}, // source -+ -+ { 0x7076c, KEY_RED}, -+ { 0x70714, KEY_GREEN}, -+ { 0x70715, KEY_YELLOW}, -+ { 0x70716, KEY_BLUE}, -+ -+ { 0x7071a, KEY_MENU}, -+ { 0x7074f, KEY_EPG}, -+ -+ { 0x70760, KEY_UP }, -+ { 0x70761, KEY_DOWN }, -+ { 0x70765, KEY_LEFT }, -+ { 0x70762, KEY_RIGHT }, -+ { 0x70768, KEY_ENTER }, -+ -+ { 0x7072d, KEY_ESC }, // back -+ -+ { 0x70707, KEY_VOLUMEUP }, -+ { 0x7070b, KEY_VOLUMEDOWN }, -+ { 0x7070f, KEY_MUTE }, -+ { 0x70712, KEY_CHANNELUP }, -+ { 0x70710, KEY_CHANNELDOWN }, -+ -+ { 0x70704, KEY_1 }, -+ { 0x70705, KEY_2 }, -+ { 0x70706, KEY_3 }, -+ { 0x70708, KEY_4 }, -+ { 0x70709, KEY_5 }, -+ { 0x7070a, KEY_6 }, -+ { 0x7070c, KEY_7 }, -+ { 0x7070d, KEY_8 }, -+ { 0x7070e, KEY_9 }, -+ { 0x70711, KEY_0 }, -+}; -+ -+static struct rc_map_list khamsin_map = { -+ .map = { -+ .scan = khamsin, -+ .size = ARRAY_SIZE(khamsin), -+ .rc_proto = RC_PROTO_NEC, -+ .name = RC_MAP_KHAMSIN, -+ } -+}; -+ -+static int __init init_rc_map_khamsin(void) -+{ -+ return rc_map_register(&khamsin_map); -+} -+ -+static void __exit exit_rc_map_khamsin(void) -+{ -+ rc_map_unregister(&khamsin_map); -+} -+ -+module_init(init_rc_map_khamsin) -+module_exit(exit_rc_map_khamsin) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Christian Hewitt "); --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0030-media-rc-add-keymap-for-Philips-RC242-remote.patch b/projects/Amlogic/patches/linux/e-0030-media-rc-add-keymap-for-Philips-RC242-remote.patch deleted file mode 100644 index d58653960c..0000000000 --- a/projects/Amlogic/patches/linux/e-0030-media-rc-add-keymap-for-Philips-RC242-remote.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 252bc63a831762e232d708d32207e866ec8a2193 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Fri, 12 Apr 2019 12:32:11 +0000 -Subject: [PATCH 30/37] media: rc: add keymap for Philips RC242 remote - -Add an IR keymap for the Philips RC242 remote used with some IPTV/VOD STB's. - -Signed-off-by: Christian Hewitt ---- - drivers/media/rc/keymaps/Makefile | 1 + - drivers/media/rc/keymaps/rc-philips-rc242.c | 93 +++++++++++++++++++++ - include/media/rc-map.h | 1 + - 3 files changed, 95 insertions(+) - create mode 100644 drivers/media/rc/keymaps/rc-philips-rc242.c - -diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 7cd930b43e9b..b29353476d0d 100644 ---- a/drivers/media/rc/keymaps/Makefile -+++ b/drivers/media/rc/keymaps/Makefile -@@ -79,6 +79,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-npgtech.o \ - rc-odroid.o \ - rc-pctv-sedna.o \ -+ rc-philips-rc242.o \ - rc-pinnacle-color.o \ - rc-pinnacle-grey.o \ - rc-pinnacle-pctv-hd.o \ -diff --git a/drivers/media/rc/keymaps/rc-philips-rc242.c b/drivers/media/rc/keymaps/rc-philips-rc242.c -new file mode 100644 -index 000000000000..7821eb122419 ---- /dev/null -+++ b/drivers/media/rc/keymaps/rc-philips-rc242.c -@@ -0,0 +1,93 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// Copyright (c) 2019 Christian Hewitt -+ -+#include -+#include -+ -+/* -+ * The Philips RC242 remote ships is used with the IPTV/VOD STB -+ * from O2 Czech Republic. -+ */ -+ -+static struct rc_map_table philips_rc242[] = { -+ -+ { 0x40c, KEY_POWER }, -+ { 0x44a, KEY_INFO }, -+ { 0x461, KEY_FAVORITES }, -+ -+ { 0x401, KEY_1 }, -+ { 0x402, KEY_2 }, -+ { 0x403, KEY_3 }, -+ -+ { 0x404, KEY_4 }, -+ { 0x405, KEY_5 }, -+ { 0x406, KEY_6 }, -+ -+ { 0x407, KEY_7 }, -+ { 0x408, KEY_8 }, -+ { 0x409, KEY_9 }, -+ -+ { 0x448, KEY_ZOOM }, -+ { 0x400, KEY_0 }, -+ { 0x441, KEY_EPG }, -+ -+ { 0x412, KEY_CONTEXT_MENU }, -+ { 0x437, KEY_RECORD }, -+ { 0x430, KEY_PAUSE }, -+ { 0x41d, KEY_ZOOM }, -+ -+ { 0x410, KEY_UP }, -+ { 0x411, KEY_DOWN }, -+ { 0x415, KEY_LEFT }, -+ { 0x416, KEY_RIGHT }, -+ { 0x424, KEY_OK }, -+ -+ { 0x414, KEY_VOLUMEUP }, -+ { 0x41f, KEY_BACK }, -+ { 0x40e, KEY_CHANNELUP }, -+ -+ { 0x417, KEY_VOLUMEDOWN }, -+ { 0x40d, KEY_MUTE }, -+ { 0x40a, KEY_CHANNELDOWN }, -+ -+ { 0x432, KEY_REWIND }, -+ { 0x435, KEY_PLAYPAUSE }, -+ { 0x436, KEY_STOP }, -+ { 0x434, KEY_FORWARD }, -+ -+ { 0x451, KEY_PREVIOUSSONG }, -+ { 0x43c, KEY_SUBTITLE }, -+ { 0x40f, KEY_LANGUAGE }, -+ { 0x450, KEY_NEXTSONG }, -+ -+ { 0x46b, KEY_RED }, -+ { 0x46c, KEY_GREEN }, -+ { 0x46d, KEY_YELLOW }, -+ { 0x46e, KEY_BLUE }, -+ -+}; -+ -+static struct rc_map_list philips_rc242_map = { -+ .map = { -+ .scan = philips_rc242, -+ .size = ARRAY_SIZE(philips_rc242), -+ .rc_proto = RC_PROTO_RC5, -+ .name = RC_MAP_PHILIPS_RC242, -+ } -+}; -+ -+static int __init init_rc_map_philips_rc242(void) -+{ -+ return rc_map_register(&philips_rc242_map); -+} -+ -+static void __exit exit_rc_map_philips_rc242(void) -+{ -+ rc_map_unregister(&philips_rc242_map); -+} -+ -+module_init(init_rc_map_philips_rc242) -+module_exit(exit_rc_map_philips_rc242) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Christian Hewitt "); -diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index 2e4b83be000c..bd7738bf197f 100644 ---- a/include/media/rc-map.h -+++ b/include/media/rc-map.h -@@ -247,6 +247,7 @@ struct rc_map *rc_map_get(const char *name); - #define RC_MAP_NPGTECH "rc-npgtech" - #define RC_MAP_ODROID "rc-odroid" - #define RC_MAP_PCTV_SEDNA "rc-pctv-sedna" -+#define RC_MAP_PHILIPS_RC242 "rc-philips-rc242" - #define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color" - #define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey" - #define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd" --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0034-ASoC-meson-correct-i2s-error-messages.patch b/projects/Amlogic/patches/linux/e-0034-ASoC-meson-correct-i2s-error-messages.patch deleted file mode 100644 index 2fb8244e41..0000000000 --- a/projects/Amlogic/patches/linux/e-0034-ASoC-meson-correct-i2s-error-messages.patch +++ /dev/null @@ -1,35 +0,0 @@ -From b6595329084bcfdb5ac3192b8abd5ccf1a1e5531 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Sun, 14 Apr 2019 03:25:54 +0000 -Subject: [PATCH 34/37] ASoC: meson: correct i2s error messages - -Reorder words so they read correctly. - -Signed-off-by: Christian Hewitt ---- - sound/soc/meson-gx/aiu-i2s.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c -index c6bfd5d8c808..3d1937946db0 100644 ---- a/sound/soc/meson-gx/aiu-i2s.c -+++ b/sound/soc/meson-gx/aiu-i2s.c -@@ -500,13 +500,13 @@ static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, - - ret = __setup_desc(priv, width, channels); - if (ret) { -- dev_err(dai->dev, "Unable set to set i2s description\n"); -+ dev_err(dai->dev, "Unable to set i2s description\n"); - return ret; - } - - ret = __bclks_set_rate(priv, rate, width); - if (ret) { -- dev_err(dai->dev, "Unable set to the i2s clock rates\n"); -+ dev_err(dai->dev, "Unable to set i2s clock rates\n"); - return ret; - } - --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0035-dt-bindings-Add-vendor-prefix-for-SmartLabs-LLC.patch b/projects/Amlogic/patches/linux/e-0035-dt-bindings-Add-vendor-prefix-for-SmartLabs-LLC.patch deleted file mode 100644 index cc41eabf75..0000000000 --- a/projects/Amlogic/patches/linux/e-0035-dt-bindings-Add-vendor-prefix-for-SmartLabs-LLC.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 301268ffe271846dbd8aad357ac1cc727d5d2259 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Wed, 24 Apr 2019 10:49:48 +0000 -Subject: [PATCH 35/37] dt-bindings: Add vendor prefix for SmartLabs LLC. - -SmartLabs LLC. are an integrator of Interactive TV solutions and IPTV/STB -devices (https://www.smartlabs.tv/en/about/) for Telco/ISP customers. - -Signed-off-by: Christian Hewitt ---- - Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt -index 8162b0eb4b50..1de094caec5c 100644 ---- a/Documentation/devicetree/bindings/vendor-prefixes.txt -+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt -@@ -374,6 +374,7 @@ sirf SiRF Technology, Inc. - sis Silicon Integrated Systems Corp. - sitronix Sitronix Technology Corporation - skyworks Skyworks Solutions, Inc. -+smartlabs SmartLabs LLC. - smsc Standard Microsystems Corporation - snps Synopsys, Inc. - socionext Socionext Inc. --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0036-dt-bindings-arm-amlogic-Add-support-for-the-SmartLab.patch b/projects/Amlogic/patches/linux/e-0036-dt-bindings-arm-amlogic-Add-support-for-the-SmartLab.patch deleted file mode 100644 index e8bfef73b0..0000000000 --- a/projects/Amlogic/patches/linux/e-0036-dt-bindings-arm-amlogic-Add-support-for-the-SmartLab.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 30ae92c1678dcab79407fd2a03635d11141e666c Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Wed, 24 Apr 2019 10:52:06 +0000 -Subject: [PATCH 36/37] dt-bindings: arm: amlogic: Add support for the - SmartLabs SML-5442TW - -The SmartLabs SML-5442TW is the next-gen/4K IPTV/DVB-S STB for O2 Czech based -on the Amlogic P231 reference design using the S905D chipset with widevine L1 -license. Hardware specification: - -- 2GB DDR3 RAM -- 8GB eMMC storage -- 10/100 Base-T Ethernet -- 802.11 a/b/g/n/ac + BT 4.1 HS sdio wireless module (QCA9377) -- 2x single colour and 1x dual colour LEDs on the front panel -- 1x reset button on the front panel -- HDMI 2.0 (4k@60p) video -- Composite video + 2-channel audio output on 3.5mm jack -- S/PDIF audio output -- Single DVB-S tuner (AVL6762/MxL608) -- 2x USB 2.0 ports -- 1x micro SD card slot -- UART pins (internal) - -Signed-off-by: Christian Hewitt ---- - Documentation/devicetree/bindings/arm/amlogic.txt | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt -index 7f40cb5f490b..2e706c6dd175 100644 ---- a/Documentation/devicetree/bindings/arm/amlogic.txt -+++ b/Documentation/devicetree/bindings/arm/amlogic.txt -@@ -92,6 +92,7 @@ Board compatible values (alphabetically, grouped by SoC): - - "amlogic,p230" (Meson gxl s905d) - - "amlogic,p231" (Meson gxl s905d) - - "phicomm,n1" (Meson gxl s905d) -+ - "smartlabs,sml5442tw" (Meson gxl s905d) - - - "amlogic,p241" (Meson gxl s805x) - - "libretech,aml-s805x-ac" (Meson gxl s805x) --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/e-0037-ARM64-dts-meson-gxl-Add-support-for-the-SmartLabs-SM.patch b/projects/Amlogic/patches/linux/e-0037-ARM64-dts-meson-gxl-Add-support-for-the-SmartLabs-SM.patch deleted file mode 100644 index 8d07a51acd..0000000000 --- a/projects/Amlogic/patches/linux/e-0037-ARM64-dts-meson-gxl-Add-support-for-the-SmartLabs-SM.patch +++ /dev/null @@ -1,334 +0,0 @@ -From eec12dffbedb498597b8eb3b7f6fad76cd24d0d7 Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Wed, 24 Apr 2019 10:56:33 +0000 -Subject: [PATCH 37/37] ARM64: dts: meson-gxl: Add support for the SmartLabs - SML-5442TW - -The SmartLabs SML-5442TW is broadly similar to the P231 reference design -but with the following differences: - -- Yellow and Blue front-panel LEDs are available but disabled -- Red/Green LED is used to signal off/on status -- GPIOX_17 is set high to enable the QCA9377 wireless module -- uart_AO can be accessed after opening the case; soldered pins exist - -Signed-off-by: Christian Hewitt ---- - arch/arm64/boot/dts/amlogic/Makefile | 1 + - .../meson-gxl-s905d-smartlabs-sml5442tw.dts | 202 ++++++++++++++++++ - drivers/media/rc/keymaps/Makefile | 1 + - drivers/media/rc/keymaps/rc-vega-s95.c | 56 +++++ - include/media/rc-map.h | 1 + - 5 files changed, 261 insertions(+) - create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts - create mode 100644 drivers/media/rc/keymaps/rc-vega-s95.c - -diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile -index 0821fed4c074..8a948b6b4f5d 100644 ---- a/arch/arm64/boot/dts/amlogic/Makefile -+++ b/arch/arm64/boot/dts/amlogic/Makefile -@@ -21,6 +21,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-phicomm-n1.dtb -+dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-smartlabs-sml5442tw.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s805x-p241.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-p281.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-tx3-mini.dtb -diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts -new file mode 100644 -index 000000000000..a574fdc17dd3 ---- /dev/null -+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts -@@ -0,0 +1,202 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) Christian Hewitt -+ */ -+ -+/dts-v1/; -+ -+#include "meson-gxl-s905d-p231.dts" -+ -+/ { -+ compatible = "smartlabs,sml5442tw", "amlogic,s905d", "amlogic,meson-gxl"; -+ model = "SmartLabs SML-5442TW for O2.cz"; -+ -+ aliases { -+ serial1 = &uart_A; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ yellow { -+ label = "sml5442tw:yellow"; -+ gpios = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ -+ blue { -+ label = "sml5442tw:blue"; -+ gpios = <&gpio GPIODV_28 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ -+ green { -+ label = "sml5442tw:green"; -+ gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ red { -+ label = "sml5442tw:red"; -+ gpios = <&gpio GPIODV_27 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+}; -+ -+&cec_AO { -+ status = "okay"; -+ pinctrl-0 = <&ao_cec_pins>; -+ pinctrl-names = "default"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&audio { -+ status = "okay"; -+}; -+ -+&aiu_i2s { -+ status = "okay"; -+}; -+ -+&cvbs_vdac_port { -+ cvbs_vdac_out: endpoint { -+ remote-endpoint = <&cvbs_connector_in>; -+ }; -+}; -+ -+ðmac { -+ status = "okay"; -+ phy-mode = "rmii"; -+ phy-handle = <&internal_phy>; -+}; -+ -+/* This will enable the bluetooth module */ -+&gpio { -+ bt-en { -+ gpio-hog; -+ gpios = ; -+ output-high; -+ line-name = "bt-en"; -+ }; -+}; -+ -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ -+&i2c_A { -+ status = "okay"; -+ pinctrl-0 = <&i2c_a_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&internal_phy { -+ pinctrl-0 = <ð_link_led_pins>, <ð_act_led_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&ir { -+ status = "okay"; -+ pinctrl-0 = <&remote_input_ao_pins>; -+ pinctrl-names = "default"; -+ linux,rc-map-name = "rc-khamsin"; -+}; -+ -+&pwm_ef { -+ status = "okay"; -+ pinctrl-0 = <&pwm_e_pins>; -+ pinctrl-names = "default"; -+ clocks = <&clkc CLKID_FCLK_DIV4>; -+ clock-names = "clkin0"; -+}; -+ -+&saradc { -+ status = "okay"; -+ vref-supply = <&vddio_ao18>; -+}; -+ -+/* Wireless SDIO Module */ -+&sd_emmc_a { -+ status = "okay"; -+ pinctrl-0 = <&sdio_pins>; -+ pinctrl-1 = <&sdio_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ max-frequency = <100000000>; -+ -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&sdio_pwrseq>; -+ -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddio_boot>; -+}; -+ -+/* SD card */ -+&sd_emmc_b { -+ status = "okay"; -+ pinctrl-0 = <&sdcard_pins>; -+ pinctrl-1 = <&sdcard_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ max-frequency = <100000000>; -+ disable-wp; -+ -+ cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>; -+ -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddio_boot>; -+}; -+ -+/* eMMC */ -+&sd_emmc_c { -+ status = "okay"; -+ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; -+ pinctrl-1 = <&emmc_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ max-frequency = <200000000>; -+ non-removable; -+ disable-wp; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ -+ mmc-pwrseq = <&emmc_pwrseq>; -+ vmmc-supply = <&vcc_3v3>; -+ vqmmc-supply = <&vddio_boot>; -+}; -+ -+/* This is connected to the Bluetooth module: */ -+&uart_A { -+ status = "okay"; -+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&uart_AO { -+ status = "okay"; -+ pinctrl-0 = <&uart_ao_a_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&usb0 { -+ status = "okay"; -+}; -diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index b2c13dac1755..ce4dff101355 100644 ---- a/drivers/media/rc/keymaps/Makefile -+++ b/drivers/media/rc/keymaps/Makefile -@@ -118,6 +118,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-videomate-m1f.o \ - rc-videomate-s350.o \ - rc-videomate-tv-pvr.o \ -+ rc-vega-s95.o \ - rc-wetek-hub.o \ - rc-wetek-play2.o \ - rc-winfast.o \ -diff --git a/drivers/media/rc/keymaps/rc-vega-s95.c b/drivers/media/rc/keymaps/rc-vega-s95.c -new file mode 100644 -index 000000000000..533464ecf932 ---- /dev/null -+++ b/drivers/media/rc/keymaps/rc-vega-s95.c -@@ -0,0 +1,56 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// -+// Copyright (c) 2018 Christian Hewitt -+ -+#include -+#include -+ -+/* -+ * This keymap is used with the Tronsmart Vega S95 Android STB -+ */ -+ -+static struct rc_map_table vega_s95[] = { -+ -+ { 0x18, KEY_POWER }, -+ { 0x17, KEY_INFO }, // mouse -+ -+ { 0x46, KEY_UP }, -+ { 0x16, KEY_DOWN }, -+ { 0x47, KEY_LEFT }, -+ { 0x15, KEY_RIGHT }, -+ { 0x55, KEY_OK }, -+ -+ { 0x06, KEY_HOME }, -+ { 0x42, KEY_PLAYPAUSE}, -+ { 0x40, KEY_BACK }, -+ -+ { 0x14, KEY_VOLUMEDOWN }, -+ { 0x04, KEY_MENU }, -+ { 0x10, KEY_VOLUMEUP }, -+ -+}; -+ -+static struct rc_map_list vega_s95_map = { -+ .map = { -+ .scan = vega_s95, -+ .size = ARRAY_SIZE(vega_s95), -+ .rc_proto = RC_PROTO_NEC, -+ .name = RC_MAP_VEGA_S95, -+ } -+}; -+ -+static int __init init_rc_map_vega_s95(void) -+{ -+ return rc_map_register(&vega_s95_map); -+} -+ -+static void __exit exit_rc_map_vega_s95(void) -+{ -+ rc_map_unregister(&vega_s95_map); -+} -+ -+module_init(init_rc_map_vega_s95) -+module_exit(exit_rc_map_vega_s95) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Christian Hewitt "); -diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index 49fe4e73b28b..491ef0382575 100644 ---- a/include/media/rc-map.h -+++ b/include/media/rc-map.h -@@ -284,6 +284,7 @@ struct rc_map *rc_map_get(const char *name); - #define RC_MAP_TT_1500 "rc-tt-1500" - #define RC_MAP_TWINHAN_DTV_CAB_CI "rc-twinhan-dtv-cab-ci" - #define RC_MAP_TWINHAN_VP1027_DVBS "rc-twinhan1027" -+#define RC_MAP_VEGA_S95 "rc-vega-s95" - #define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100" - #define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350" - #define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" --- -2.17.1 - diff --git a/projects/Amlogic/patches/linux/f-0005-arm64-dts-add-meson-g12a-x96-max-rmii-dts.patch b/projects/Amlogic/patches/linux/f-0005-arm64-dts-add-meson-g12a-x96-max-rmii-dts.patch deleted file mode 100644 index 0abdbc8096..0000000000 --- a/projects/Amlogic/patches/linux/f-0005-arm64-dts-add-meson-g12a-x96-max-rmii-dts.patch +++ /dev/null @@ -1,332 +0,0 @@ -From 3dc28e080cbd6da0d9d908266aff6d14c053dbda Mon Sep 17 00:00:00 2001 -From: chewitt -Date: Mon, 22 Apr 2019 07:17:31 +0000 -Subject: [PATCH 5/6] arm64: dts: add meson-g12a-x96-max-rmii dts - -Some variants of the X96 max use the internal rmii PHY instead of external -rgmii PHY so provide a device-tree for them. - -Signed-off-by: Christian Hewitt ---- - .../devicetree/bindings/arm/amlogic.txt | 3 +- - arch/arm64/boot/dts/amlogic/Makefile | 1 + - .../dts/amlogic/meson-g12a-x96-max-rmii.dts | 281 ++++++++++++++++++ - 3 files changed, 284 insertions(+), 1 deletion(-) - create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts - -diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt -index eff41128268e..b78220bb3feb 100644 ---- a/Documentation/devicetree/bindings/arm/amlogic.txt -+++ b/Documentation/devicetree/bindings/arm/amlogic.txt -@@ -113,7 +113,8 @@ Board compatible values (alphabetically, grouped by SoC): - - "amlogic,s400" (Meson axg a113d) - - - "amlogic,u200" (Meson g12a s905d2) -- - "amediatech,x96-max" (Meson g12a s905x2) -+ - "amediatech,x96-max" (Meson g12a s905x2 using external PHY) -+ - "amediatech,x96-max-rmii" (Meson g12a s905x2 using internal PHY) - - "seirobotics,sei510" (Meson g12a s905x2) - - - "hardkernel,odroid-n2" (Meson g12b s922x) -diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile -index 07b861fe5fa5..3eeda866ced1 100644 ---- a/arch/arm64/boot/dts/amlogic/Makefile -+++ b/arch/arm64/boot/dts/amlogic/Makefile -@@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb -+dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max-rmii.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb - dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb -diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts -new file mode 100644 -index 000000000000..72751bfe88d3 ---- /dev/null -+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts -@@ -0,0 +1,281 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2018 BayLibre SAS. All rights reserved. -+ */ -+ -+/dts-v1/; -+ -+#include "meson-g12a.dtsi" -+#include -+#include -+ -+/ { -+ compatible = "amediatech,x96-max-rmii", "amlogic,u200", "amlogic,g12a"; -+ model = "Shenzhen Amediatech Technology Co., Ltd X96 Max"; -+ -+ aliases { -+ serial0 = &uart_AO; -+ ethernet0 = ðmac; -+ }; -+ chosen { -+ stdout-path = "serial0:115200n8"; -+ }; -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x0 0x0 0x40000000>; -+ }; -+ -+ cvbs-connector { -+ compatible = "composite-video-connector"; -+ -+ port { -+ cvbs_connector_in: endpoint { -+ remote-endpoint = <&cvbs_vdac_out>; -+ }; -+ }; -+ }; -+ -+ hdmi-connector { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi_connector_in: endpoint { -+ remote-endpoint = <&hdmi_tx_tmds_out>; -+ }; -+ }; -+ }; -+ -+ emmc_pwrseq: emmc-pwrseq { -+ compatible = "mmc-pwrseq-emmc"; -+ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; -+ }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; -+ clocks = <&wifi32k>; -+ clock-names = "ext_clock"; -+ }; -+ -+ flash_1v8: regulator-flash_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "FLASH_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ -+ dc_in: regulator-dc_in { -+ compatible = "regulator-fixed"; -+ regulator-name = "DC_IN"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ }; -+ -+ vcc_1v8: regulator-vcc_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vcc_3v3>; -+ regulator-always-on; -+ }; -+ -+ vcc_3v3: regulator-vcc_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ /* FIXME: actually controlled by VDDCPU_B_EN */ -+ }; -+ -+ vcc_5v: regulator-vcc_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ vin-supply = <&dc_in>; -+ -+ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; -+ enable-active-low; -+ }; -+ -+ vddao_1v8: regulator-vddao_1v8 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ vin-supply = <&vddao_3v3>; -+ regulator-always-on; -+ }; -+ -+ vddao_3v3: regulator-vddao_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VDDAO_3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&dc_in>; -+ regulator-always-on; -+ }; -+ -+ wifi32k: wifi32k { -+ compatible = "pwm-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <32768>; -+ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ -+ }; -+}; -+ -+&cec_AO { -+ pinctrl-0 = <&cec_ao_a_h_pins>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cecb_AO { -+ pinctrl-0 = <&cec_ao_b_h_pins>; -+ pinctrl-names = "default"; -+ status = "okay"; -+ hdmi-phandle = <&hdmi_tx>; -+}; -+ -+&cvbs_vdac_port { -+ cvbs_vdac_out: endpoint { -+ remote-endpoint = <&cvbs_connector_in>; -+ }; -+}; -+ -+&hdmi_tx { -+ status = "okay"; -+ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; -+ pinctrl-names = "default"; -+ hdmi-supply = <&vcc_5v>; -+}; -+ -+&hdmi_tx_tmds_port { -+ hdmi_tx_tmds_out: endpoint { -+ remote-endpoint = <&hdmi_connector_in>; -+ }; -+}; -+ -+&ir { -+ status = "okay"; -+ pinctrl-0 = <&remote_input_ao_pins>; -+ pinctrl-names = "default"; -+ linux,rc-map-name = "rc-x96max"; -+}; -+ -+&ext_mdio { -+ external_phy: ethernet-phy@0 { -+ compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ max-speed = <1000>; -+ eee-broken-1000t; -+ }; -+}; -+ -+ðmac { -+ status = "okay"; -+ pinctrl-0 = <ð_leds_pins>; -+ pinctrl-names = "default"; -+ phy-handle = <&internal_ephy>; -+ phy-mode = "rmii"; -+}; -+ -+&pwm_ef { -+ status = "okay"; -+ pinctrl-0 = <&pwm_e_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&uart_A { -+ status = "okay"; -+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; -+ pinctrl-names = "default"; -+ uart-has-rtscts; -+ -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; -+ }; -+}; -+ -+&uart_AO { -+ status = "okay"; -+ pinctrl-0 = <&uart_ao_a_pins>; -+ pinctrl-names = "default"; -+}; -+ -+&usb { -+ status = "okay"; -+ dr_mode = "host"; -+}; -+ -+/* SDIO */ -+&sd_emmc_a { -+ status = "okay"; -+ pinctrl-0 = <&sdio_pins>; -+ pinctrl-1 = <&sdio_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ sd-uhs-sdr50; -+ max-frequency = <100000000>; -+ -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&sdio_pwrseq>; -+ -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddao_1v8>; -+ -+ brcmf: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ }; -+}; -+ -+/* SD card */ -+&sd_emmc_b { -+ status = "okay"; -+ pinctrl-0 = <&sdcard_c_pins>; -+ pinctrl-1 = <&sdcard_clk_gate_c_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <4>; -+ cap-sd-highspeed; -+ max-frequency = <100000000>; -+ disable-wp; -+ -+ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; -+ vmmc-supply = <&vddao_3v3>; -+ vqmmc-supply = <&vddao_3v3>; -+}; -+ -+/* eMMC */ -+&sd_emmc_c { -+ status = "okay"; -+ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; -+ pinctrl-1 = <&emmc_clk_gate_pins>; -+ pinctrl-names = "default", "clk-gate"; -+ -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ max-frequency = <100000000>; -+ non-removable; -+ disable-wp; -+ -+ mmc-pwrseq = <&emmc_pwrseq>; -+ vmmc-supply = <&vcc_3v3>; -+ vqmmc-supply = <&flash_1v8>; -+}; --- -2.17.1 -