Hi Neil,
DISCLAIMER: none of these patches is meant to be applied anywhere! their purpose is to document what I found out so far (things that are not documented in any public datasheet that I am aware of).
I was curious and wanted to see if there are any differences between the video IP blocks between Meson8/Meson8b/Meson8m2 and GXBB/GXL/GXM.
after reading your gpu/drm/meson/meson_vclk.c I stumbled across the first problem (which is a big one): the 32-bit SoCs don't have the HHI_VID_PLL_CLK_DIV register. unfortunately there is no documentation in the public S805 datasheet that describes the video clock path on Meson8b. some of the registers that are documented in the GXM datasheet published by Khadas (which also contains a nice video clock tree documentation). so I tried to take a different approach: extending the clock controller driver so I could play around until I could read the clock frequencies set by u-boot (which displays an image on the CVBS output). the result of this is the clock patch from this series, which gives me the following output in /sys/kernel/debug/clk/clk_summary: vid_pll 0 0 648000000 0 0 vid_pll_pre_div 0 0 108000000 0 0 vid_pll_post_sel 0 0 108000000 0 0 vid_pll_post_en 0 0 108000000 0 0 vclk2_sel 0 0 108000000 0 0 vclk2_en0 0 0 108000000 0 0 vclk2_xd0 0 0 54000000 0 0 vclk2_clk_div_en 0 0 54000000 0 0 vclk2_div12 0 0 4500000 0 0 vclk2_div12_en 0 0 4500000 0 0 vclk2_div6 0 0 9000000 0 0 vclk2_div6_en 0 0 9000000 0 0 vclk2_div4 0 0 13500000 0 0 vclk2_div4_en 0 0 13500000 0 0 vclk2_div2 0 0 27000000 0 0 vclk2_div2_en 0 0 27000000 0 0 hdmi_tx_pixel_sel 0 0 27000000 0 0 hdmi_tx_pixel_en 0 0 27000000 0 0 vdac0_sel 0 0 27000000 0 0 vdac0_en 0 0 27000000 0 0 vclk2_div1_en 0 0 54000000 0 0 encl_sel 0 0 54000000 0 0 encl_en 0 0 54000000 0 0 vclk_sel 0 0 108000000 0 0 vclk_en0 0 0 108000000 0 0 vclk_xd0 0 0 27000000 0 0 vclk_clk_div_en 0 0 27000000 0 0 vclk_div12 0 0 2250000 0 0 vclk_div12_en 0 0 2250000 0 0 vclk_div6 0 0 4500000 0 0 vclk_div6_en 0 0 4500000 0 0 vclk_div4 0 0 6750000 0 0 vclk_div4_en 0 0 6750000 0 0 vclk_div2 0 0 13500000 0 0 vclk_div2_en 0 0 13500000 0 0 enci_sel 0 0 13500000 0 0 enci_en 0 0 13500000 0 0 vclk_div1_en 0 0 27000000 0 0 encp_sel 0 0 27000000 0 0 encp_en 0 0 27000000 0 0 enct_sel 0 0 27000000 0 0 enct_en 0 0 27000000 0 0 vid_pll_post_div 0 0 108000000 0 0
I am not sure whether the ENCI clock is supposed to be 27MHz. at least the VDAC0 clock is 27MHz, which is definitely correct (in my opinion ;)) "clkmsr" in u-boot (which I don't trust by the way, but I'll document my results here for the sake of completeness) shows these video related clocks: - [ 216 MHz] VID_PLL_CLK(6) - [ 54 MHz] CTS_ENCP_CLK(8) - [ 54 MHz] CTS_ENCL_CLK(9) - [ 24 MHz] CTS_HDMI_SYS_CLK(19) - [ 27 MHz] CTS_HDMI_TX_PIXEL_CLK(36)
after having fun with the clock driver I discovered that the CVBS output turns black when I boot a kernel with the .dts VPU node. a bit later I found out that we must not overwrite VIU_OSD2_CTRL_STAT with 0 and that some of the code in gpu/drm/meson/meson_vpp.c didn't seem to be compatible with the 32-bit SoCs so I simply "#if 0" that code. even later I found out that the 32-bit SoCs seem to use OSD2 (instead of OSD1) for the CVBS output. a small hack in meson_plane.c and meson_canvas.c later I am now able to send my own images through the CVBS output (colors are slightly incorrect and the image is cut off, but you have to start small: [0])
are you planning to support OSD2 at some point?
Regards Martin
[0] https://abload.de/img/vlcsnap-2018-01-01-22b1uym.png
Martin Blumenstingl (2): gpu: drm: meson: HACK - Meson8/Meson8b/Meson8m2 support - WiP clk: meson: meson8b: add the video clock trees - WiP
.../bindings/display/amlogic,meson-vpu.txt | 18 +- drivers/clk/meson/meson8b.c | 637 +++++++++++++++++++++ drivers/clk/meson/meson8b.h | 7 +- drivers/gpu/drm/meson/meson_canvas.c | 11 + drivers/gpu/drm/meson/meson_canvas.h | 4 +- drivers/gpu/drm/meson/meson_drv.c | 3 + drivers/gpu/drm/meson/meson_plane.c | 5 +- drivers/gpu/drm/meson/meson_vclk.c | 21 +- drivers/gpu/drm/meson/meson_venc_cvbs.c | 5 +- drivers/gpu/drm/meson/meson_viu.c | 5 +- drivers/gpu/drm/meson/meson_vpp.c | 28 + include/dt-bindings/clock/meson8b-clkc.h | 42 ++ 12 files changed, 771 insertions(+), 15 deletions(-)
TODO: - canvas registers offsets on Meson8 / Meson8b are different - hardcoded register values - OSD2 is used for CVBS on Meson8 (at least on Meson8m2)
Signed-off-by: Martin Blumenstingl martin.blumenstingl@googlemail.com --- .../bindings/display/amlogic,meson-vpu.txt | 18 +++++++++----- drivers/gpu/drm/meson/meson_canvas.c | 11 +++++++++ drivers/gpu/drm/meson/meson_canvas.h | 4 ++-- drivers/gpu/drm/meson/meson_drv.c | 3 +++ drivers/gpu/drm/meson/meson_plane.c | 5 ++-- drivers/gpu/drm/meson/meson_vclk.c | 21 ++++++++++++++-- drivers/gpu/drm/meson/meson_venc_cvbs.c | 5 +++- drivers/gpu/drm/meson/meson_viu.c | 5 +++- drivers/gpu/drm/meson/meson_vpp.c | 28 ++++++++++++++++++++++ 9 files changed, 86 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt index 00f74bad1e95..f416cdc88f25 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt @@ -53,6 +53,9 @@ VPU: Video Processing Unit
Required properties: - compatible: value should be different for each SoC family as : + - Meson8 (S802) : "amlogic,meson8-vpu" + - Meson8b (S805) : "amlogic,meson8b-vpu" + - Meson8m2 (S812) : "amlogic,meson8m2-vpu" - GXBB (S905) : "amlogic,meson-gxbb-vpu" - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" - GXM (S912) : "amlogic,meson-gxm-vpu" @@ -72,12 +75,15 @@ bindings specified in Documentation/devicetree/bindings/graph.txt. The following table lists for each supported model the port number corresponding to each VPU output.
- Port 0 Port 1 ------------------------------------------ - S905 (GXBB) CVBS VDAC HDMI-TX - S905X (GXL) CVBS VDAC HDMI-TX - S905D (GXL) CVBS VDAC HDMI-TX - S912 (GXM) CVBS VDAC HDMI-TX + Port 0 Port 1 +----------------------------------------------------------- + S802 (Meson8) CVBS VDAC not implemented yet + S805 (Meson8b) CVBS VDAC not implemented yet + S812 (Meson8m2) CVBS VDAC not implemented yet + S905 (GXBB) CVBS VDAC HDMI-TX + S905X (GXL) CVBS VDAC HDMI-TX + S905D (GXL) CVBS VDAC HDMI-TX + S912 (GXM) CVBS VDAC HDMI-TX
Example:
diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c index 08f6073d967e..cc741d06ccc4 100644 --- a/drivers/gpu/drm/meson/meson_canvas.c +++ b/drivers/gpu/drm/meson/meson_canvas.c @@ -43,6 +43,17 @@ #define CANVAS_LUT_WR_EN (0x2 << 8) #define CANVAS_LUT_RD_EN (0x1 << 8)
+u8 meson_canvas_id_osd1(struct meson_drm *priv) +{ + if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) { + return 0x43; // HACK: OSD1 = 0x40, OSD2 = 0x43 + } else { + return 0x4e; + } +} + void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h index af1759da4b27..4f594c8a6f80 100644 --- a/drivers/gpu/drm/meson/meson_canvas.h +++ b/drivers/gpu/drm/meson/meson_canvas.h @@ -22,8 +22,6 @@ #ifndef __MESON_CANVAS_H #define __MESON_CANVAS_H
-#define MESON_CANVAS_ID_OSD1 0x4e - /* Canvas configuration. */ #define MESON_CANVAS_WRAP_NONE 0x00 #define MESON_CANVAS_WRAP_X 0x01 @@ -33,6 +31,8 @@ #define MESON_CANVAS_BLKMODE_32x32 0x01 #define MESON_CANVAS_BLKMODE_64x64 0x02
+u8 meson_canvas_id_osd1(struct meson_drm *priv); + void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 3b804fdaf7a0..96c77498ef55 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -378,6 +378,9 @@ static int meson_drv_probe(struct platform_device *pdev) };
static const struct of_device_id dt_match[] = { + { .compatible = "amlogic,meson8-vpu" }, + { .compatible = "amlogic,meson8b-vpu" }, + { .compatible = "amlogic,meson8m2-vpu" }, { .compatible = "amlogic,meson-gxbb-vpu" }, { .compatible = "amlogic,meson-gxl-vpu" }, { .compatible = "amlogic,meson-gxm-vpu" }, diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 17e96fa47868..9d9a491c4eba 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -93,6 +93,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, .x2 = state->crtc_x + state->crtc_w, .y2 = state->crtc_y + state->crtc_h, }; + u8 canvas_index = meson_canvas_id_osd1(priv); unsigned long flags;
/* @@ -109,7 +110,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, OSD_BLK0_ENABLE;
/* Set up BLK0 to point to the right canvas */ - priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) | + priv->viu.osd1_blk0_cfg[0] = ((canvas_index << OSD_CANVAS_SEL) | OSD_ENDIANNESS_LE);
/* On GXBB, Use the old non-HDR RGB2YUV converter */ @@ -164,7 +165,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, /* Update Canvas with buffer address */ gem = drm_fb_cma_get_gem_obj(fb, 0);
- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, + meson_canvas_setup(priv, canvas_index, gem->paddr, fb->pitches[0], fb->height, MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR); diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 47677047e42d..1b1e379501d4 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -247,7 +247,20 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) unsigned int val;
/* Setup PLL to output 1.485GHz */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) { +#if 0 + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x2001042d); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x814d3928); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x6b425012); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x00000110); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0001042d); +#else + /* TODO! */ + return; +#endif + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); @@ -428,7 +441,11 @@ void meson_hdmi_pll_set(struct meson_drm *priv, { unsigned int val;
- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) { + return; // TODO + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { switch (base) { case 2970000: regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 79d95ca8a0c0..1affa6b19170 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -179,7 +179,10 @@ 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,meson8-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu") || + 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")) diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index 6bcfa527c180..4b65f9166d78 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -303,9 +303,12 @@ void meson_viu_init(struct meson_drm *priv) /* Disable OSDs */ writel_bits_relaxed(BIT(0) | BIT(21), 0, priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); +#if 0 writel_bits_relaxed(BIT(0) | BIT(21), 0, priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); - +#else + printk("%s: VIU_OSD2_CTRL_STAT = 0x%08x\n", __func__, readl(priv->io_base + _REG(VIU_OSD2_CTRL_STAT))); +#endif /* On GXL/GXM, Use the 10bit HDR conversion matrix */ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index 27356f81a0ab..c66c16473989 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -61,6 +61,7 @@ void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux) void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv, struct drm_rect *input) { +#if 0 writel_relaxed(BIT(3) /* Enable scaler */ | BIT(2), /* Select OSD1 */ priv->io_base + _REG(VPP_OSD_SC_CTRL0)); @@ -79,6 +80,33 @@ void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv, writel_relaxed(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); +#else + printk("%s: VPP_OSD_SC_CTRL0 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SC_CTRL0))); + printk("%s: VPP_OSD_SCI_WH_M1 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCI_WH_M1))); + printk("%s: VPP_OSD_SCO_H_START_END = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCO_H_START_END))); + printk("%s: VPP_OSD_SCO_V_START_END = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCO_V_START_END))); + printk("%s: VPP_OSD_VSC_INI_PHASE = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE))); + printk("%s: VPP_OSD_VSC_PHASE_STEP = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP))); + printk("%s: VPP_OSD_HSC_CTRL0 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_HSC_CTRL0))); + + writel_relaxed(BIT(3) /* Enable scaler */ | + BIT(0), /* Select OSD2 - FIXME */ + priv->io_base + _REG(VPP_OSD_SC_CTRL0)); + +// writel_relaxed(((drm_rect_width(input) - 1) << 16) | +// (drm_rect_height(input) - 1), +// priv->io_base + _REG(VPP_OSD_SCI_WH_M1)); + +// writel_relaxed((drm_rect_height(input) - 1), +// priv->io_base + _REG(VPP_OSD_SCO_H_START_END)); + + writel_relaxed(0x04ff02cf, priv->io_base + _REG(VPP_OSD_SCI_WH_M1)); + writel_relaxed(0x000002cf, priv->io_base + _REG(VPP_OSD_SCO_H_START_END)); + writel_relaxed(0x0000011f, priv->io_base + _REG(VPP_OSD_SCO_V_START_END)); + writel_relaxed(0x40000000, priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)); + writel_relaxed(0x02800000, priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)); + writel_relaxed(0x00400124, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); +#endif
writel_relaxed((4 << 0) /* osd_vsc_bank_length */ | (4 << 3) /* osd_vsc_top_ini_rcv_num0 */ |
Hi Martin,
Thanks for the research !!!
Let me clarify this OSD1/2 stuff.
There is 2 OSD planes (that can get single-buffer input), and 2 Video plane that can get multi-planar video like YUV or NV12. Only the OSD1 is enabled since it needs the Super Scaler in passthrought to automatically change the interlace field needed when you output in interlace mode on CVBS.
So : - the OSD1 needs a CANVAS id where to get the data from, with other infos in the VIU_OSD1_BLK0_CFG_W0 reg - the CANVAS id is only a logical id to define an entry in the CANVAS Manager where you can store every planes, so you only change the CANVAS ID in the VIU_OSD1_BLK0_CFG_W0 reg - the Super Scaler needs a source to be configured from, my code is incorrect, I should not enable BIT(2), bits 0-1 should be 0 - The VPP_MISC register describes which OSD is enabled, and en eventual ordering, you may check in the kernel source if this register layout is the same
Looking at your code, you seem to still use ISD1, and only change a virtual logical CANVAS id, and you changed the Super Scaler register to use OSD2 as source, but it may be disabled.
Neil
On 01/01/2018 22:35, Martin Blumenstingl wrote:
TODO:
- canvas registers offsets on Meson8 / Meson8b are different
- hardcoded register values
- OSD2 is used for CVBS on Meson8 (at least on Meson8m2)
Signed-off-by: Martin Blumenstingl martin.blumenstingl@googlemail.com
.../bindings/display/amlogic,meson-vpu.txt | 18 +++++++++----- drivers/gpu/drm/meson/meson_canvas.c | 11 +++++++++ drivers/gpu/drm/meson/meson_canvas.h | 4 ++-- drivers/gpu/drm/meson/meson_drv.c | 3 +++ drivers/gpu/drm/meson/meson_plane.c | 5 ++-- drivers/gpu/drm/meson/meson_vclk.c | 21 ++++++++++++++-- drivers/gpu/drm/meson/meson_venc_cvbs.c | 5 +++- drivers/gpu/drm/meson/meson_viu.c | 5 +++- drivers/gpu/drm/meson/meson_vpp.c | 28 ++++++++++++++++++++++ 9 files changed, 86 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt index 00f74bad1e95..f416cdc88f25 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt @@ -53,6 +53,9 @@ VPU: Video Processing Unit
Required properties:
- compatible: value should be different for each SoC family as :
- Meson8 (S802) : "amlogic,meson8-vpu"
- Meson8b (S805) : "amlogic,meson8b-vpu"
- Meson8m2 (S812) : "amlogic,meson8m2-vpu"
- GXBB (S905) : "amlogic,meson-gxbb-vpu"
- GXL (S905X, S905D) : "amlogic,meson-gxl-vpu"
- GXM (S912) : "amlogic,meson-gxm-vpu"
@@ -72,12 +75,15 @@ bindings specified in Documentation/devicetree/bindings/graph.txt. The following table lists for each supported model the port number corresponding to each VPU output.
Port 0 Port 1
- S905 (GXBB) CVBS VDAC HDMI-TX
- S905X (GXL) CVBS VDAC HDMI-TX
- S905D (GXL) CVBS VDAC HDMI-TX
- S912 (GXM) CVBS VDAC HDMI-TX
Port 0 Port 1
+-----------------------------------------------------------
- S802 (Meson8) CVBS VDAC not implemented yet
- S805 (Meson8b) CVBS VDAC not implemented yet
- S812 (Meson8m2) CVBS VDAC not implemented yet
Maybe N/A is better.
- S905 (GXBB) CVBS VDAC HDMI-TX
- S905X (GXL) CVBS VDAC HDMI-TX
- S905D (GXL) CVBS VDAC HDMI-TX
- S912 (GXM) CVBS VDAC HDMI-TX
Example:
diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c index 08f6073d967e..cc741d06ccc4 100644 --- a/drivers/gpu/drm/meson/meson_canvas.c +++ b/drivers/gpu/drm/meson/meson_canvas.c @@ -43,6 +43,17 @@ #define CANVAS_LUT_WR_EN (0x2 << 8) #define CANVAS_LUT_RD_EN (0x1 << 8)
+u8 meson_canvas_id_osd1(struct meson_drm *priv) +{
- if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) {
return 0x43; // HACK: OSD1 = 0x40, OSD2 = 0x43
- } else {
return 0x4e;
- }
+}
This canvas ID is purely logical and any number should work here, since this same number is used to update the OSD config register aswell.
void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h index af1759da4b27..4f594c8a6f80 100644 --- a/drivers/gpu/drm/meson/meson_canvas.h +++ b/drivers/gpu/drm/meson/meson_canvas.h @@ -22,8 +22,6 @@ #ifndef __MESON_CANVAS_H #define __MESON_CANVAS_H
-#define MESON_CANVAS_ID_OSD1 0x4e
/* Canvas configuration. */ #define MESON_CANVAS_WRAP_NONE 0x00 #define MESON_CANVAS_WRAP_X 0x01 @@ -33,6 +31,8 @@ #define MESON_CANVAS_BLKMODE_32x32 0x01 #define MESON_CANVAS_BLKMODE_64x64 0x02
+u8 meson_canvas_id_osd1(struct meson_drm *priv);
void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 3b804fdaf7a0..96c77498ef55 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -378,6 +378,9 @@ static int meson_drv_probe(struct platform_device *pdev) };
static const struct of_device_id dt_match[] = {
- { .compatible = "amlogic,meson8-vpu" },
- { .compatible = "amlogic,meson8b-vpu" },
- { .compatible = "amlogic,meson8m2-vpu" }, { .compatible = "amlogic,meson-gxbb-vpu" }, { .compatible = "amlogic,meson-gxl-vpu" }, { .compatible = "amlogic,meson-gxm-vpu" },
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 17e96fa47868..9d9a491c4eba 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -93,6 +93,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, .x2 = state->crtc_x + state->crtc_w, .y2 = state->crtc_y + state->crtc_h, };
u8 canvas_index = meson_canvas_id_osd1(priv); unsigned long flags;
/*
@@ -109,7 +110,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, OSD_BLK0_ENABLE;
/* Set up BLK0 to point to the right canvas */
- priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
priv->viu.osd1_blk0_cfg[0] = ((canvas_index << OSD_CANVAS_SEL) | OSD_ENDIANNESS_LE);
/* On GXBB, Use the old non-HDR RGB2YUV converter */
@@ -164,7 +165,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, /* Update Canvas with buffer address */ gem = drm_fb_cma_get_gem_obj(fb, 0);
- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
- meson_canvas_setup(priv, canvas_index, gem->paddr, fb->pitches[0], fb->height, MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR);
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 47677047e42d..1b1e379501d4 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -247,7 +247,20 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) unsigned int val;
/* Setup PLL to output 1.485GHz */
- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
- if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) {
+#if 0
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x2001042d);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x814d3928);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x6b425012);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x00000110);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0001042d);
+#else
The HDMI PLL should also be totally different.
/* TODO! */
return;
+#endif
- } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
@@ -428,7 +441,11 @@ void meson_hdmi_pll_set(struct meson_drm *priv, { unsigned int val;
- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
- if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) {
return; // TODO
- } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { switch (base) { case 2970000: regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 79d95ca8a0c0..1affa6b19170 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -179,7 +179,10 @@ 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,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-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"))meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index 6bcfa527c180..4b65f9166d78 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -303,9 +303,12 @@ void meson_viu_init(struct meson_drm *priv) /* Disable OSDs */ writel_bits_relaxed(BIT(0) | BIT(21), 0, priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); +#if 0 writel_bits_relaxed(BIT(0) | BIT(21), 0, priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
+#else
- printk("%s: VIU_OSD2_CTRL_STAT = 0x%08x\n", __func__, readl(priv->io_base + _REG(VIU_OSD2_CTRL_STAT)));
+#endif
You should try enabling/disabled each OSD to see if something shows.
/* On GXL/GXM, Use the 10bit HDR conversion matrix */ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index 27356f81a0ab..c66c16473989 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -61,6 +61,7 @@ void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux) void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv, struct drm_rect *input) { +#if 0 writel_relaxed(BIT(3) /* Enable scaler */ | BIT(2), /* Select OSD1 */ priv->io_base + _REG(VPP_OSD_SC_CTRL0)); @@ -79,6 +80,33 @@ void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv, writel_relaxed(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
The scaler is used here to change the interlace field automatically, otherwise we should change it using an irq handler....
In fact the :
BIT(2), /* Select OSD1 */
is false....
The bits 0-1 are : osd_sc_sel, 00: select osd1 input, 01: select osd2 input, 10: select vd1 input, 11: select vd2 input after matrix
I wonder why I set BIT(2) here... I must got it from the u-boot source.
U-boot 2016-08-18 has : /* enable osd scaler path */ if (index == OSD1) data32 = 8; else { data32 = 1; /* select osd2 input */ data32 |= 1 << 3; /* enable osd scaler path */ }
in drivers/display/osd/osd_hw.c
+#else
- printk("%s: VPP_OSD_SC_CTRL0 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SC_CTRL0)));
- printk("%s: VPP_OSD_SCI_WH_M1 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCI_WH_M1)));
- printk("%s: VPP_OSD_SCO_H_START_END = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCO_H_START_END)));
- printk("%s: VPP_OSD_SCO_V_START_END = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCO_V_START_END)));
- printk("%s: VPP_OSD_VSC_INI_PHASE = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)));
- printk("%s: VPP_OSD_VSC_PHASE_STEP = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)));
- printk("%s: VPP_OSD_HSC_CTRL0 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_HSC_CTRL0)));
- writel_relaxed(BIT(3) /* Enable scaler */ |
BIT(0), /* Select OSD2 - FIXME */
priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+// writel_relaxed(((drm_rect_width(input) - 1) << 16) | +// (drm_rect_height(input) - 1), +// priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
+// writel_relaxed((drm_rect_height(input) - 1), +// priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
- writel_relaxed(0x04ff02cf, priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
- writel_relaxed(0x000002cf, priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
- writel_relaxed(0x0000011f, priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
- writel_relaxed(0x40000000, priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
- writel_relaxed(0x02800000, priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
- writel_relaxed(0x00400124, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+#endif
writel_relaxed((4 << 0) /* osd_vsc_bank_length */ | (4 << 3) /* osd_vsc_top_ini_rcv_num0 */ |
Hi Neil,
On Tue, Jan 2, 2018 at 12:01 PM, Neil Armstrong narmstrong@baylibre.com wrote:
Hi Martin,
Thanks for the research !!!
you're welcome - I'm slowly starting to understand why implementing video drivers takes a long time...
Let me clarify this OSD1/2 stuff.
There is 2 OSD planes (that can get single-buffer input), and 2 Video plane that can get multi-planar video like YUV or NV12. Only the OSD1 is enabled since it needs the Super Scaler in passthrought to automatically change the interlace field needed when you output in interlace mode on CVBS.
So :
- the OSD1 needs a CANVAS id where to get the data from, with other infos in the VIU_OSD1_BLK0_CFG_W0 reg
this matches with what I've seen: if I undo that canvas ID change then the image from u-boot is visible ("fbv test-image.png" does not draw over it or clear it)
- the CANVAS id is only a logical id to define an entry in the CANVAS Manager where you can store every planes, so you only change the CANVAS ID in the VIU_OSD1_BLK0_CFG_W0 reg
- the Super Scaler needs a source to be configured from, my code is incorrect, I should not enable BIT(2), bits 0-1 should be 0
so VPP_OSD_SC_CTRL0 is "VPP OSD Super Scaler Control 0"
- The VPP_MISC register describes which OSD is enabled, and en eventual ordering, you may check in the kernel source if this register layout is the same
the documentation in uboot-2015-01-15-23a3562521/arch/arm/include/asm/arch-m8/register.h for the VPP_MISC matches the documentation that can be found in Khadas' GXM (S912) datasheet
Looking at your code, you seem to still use ISD1, and only change a virtual logical CANVAS id, and you changed the Super Scaler register to use OSD2 as source, but it may be disabled.
actually my code *should* change it to OSD2: writel_relaxed(BIT(3) /* Enable scaler */ | BIT(0), /* Select OSD2 - FIXME */ priv->io_base + _REG(VPP_OSD_SC_CTRL0)); which matches OSD2 from your description: - 00: select osd1 input - 01: select osd2 input - 10: select vd1 input - 11: select vd2 input after matrix
maybe I tricked you with the name meson_canvas_id_osd1() - a better name would have been meson_canvas_id_HACK(): return 0x43; // HACK: OSD1 = 0x40, OSD2 = 0x43 so I'm actually returning the ID for OSD2 (I took these OSD IDs from uboot-2015-01-15-23a3562521/arch/arm/include/asm/arch-m8/canvas.h)
Neil
On 01/01/2018 22:35, Martin Blumenstingl wrote:
TODO:
- canvas registers offsets on Meson8 / Meson8b are different
- hardcoded register values
- OSD2 is used for CVBS on Meson8 (at least on Meson8m2)
Signed-off-by: Martin Blumenstingl martin.blumenstingl@googlemail.com
.../bindings/display/amlogic,meson-vpu.txt | 18 +++++++++----- drivers/gpu/drm/meson/meson_canvas.c | 11 +++++++++ drivers/gpu/drm/meson/meson_canvas.h | 4 ++-- drivers/gpu/drm/meson/meson_drv.c | 3 +++ drivers/gpu/drm/meson/meson_plane.c | 5 ++-- drivers/gpu/drm/meson/meson_vclk.c | 21 ++++++++++++++-- drivers/gpu/drm/meson/meson_venc_cvbs.c | 5 +++- drivers/gpu/drm/meson/meson_viu.c | 5 +++- drivers/gpu/drm/meson/meson_vpp.c | 28 ++++++++++++++++++++++ 9 files changed, 86 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt index 00f74bad1e95..f416cdc88f25 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt @@ -53,6 +53,9 @@ VPU: Video Processing Unit
Required properties:
- compatible: value should be different for each SoC family as :
- Meson8 (S802) : "amlogic,meson8-vpu"
- Meson8b (S805) : "amlogic,meson8b-vpu"
- Meson8m2 (S812) : "amlogic,meson8m2-vpu" - GXBB (S905) : "amlogic,meson-gxbb-vpu" - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" - GXM (S912) : "amlogic,meson-gxm-vpu"
@@ -72,12 +75,15 @@ bindings specified in Documentation/devicetree/bindings/graph.txt. The following table lists for each supported model the port number corresponding to each VPU output.
Port 0 Port 1
- S905 (GXBB) CVBS VDAC HDMI-TX
- S905X (GXL) CVBS VDAC HDMI-TX
- S905D (GXL) CVBS VDAC HDMI-TX
- S912 (GXM) CVBS VDAC HDMI-TX
Port 0 Port 1
+-----------------------------------------------------------
- S802 (Meson8) CVBS VDAC not implemented yet
- S805 (Meson8b) CVBS VDAC not implemented yet
- S812 (Meson8m2) CVBS VDAC not implemented yet
Maybe N/A is better.
- S905 (GXBB) CVBS VDAC HDMI-TX
- S905X (GXL) CVBS VDAC HDMI-TX
- S905D (GXL) CVBS VDAC HDMI-TX
- S912 (GXM) CVBS VDAC HDMI-TX
Example:
diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c index 08f6073d967e..cc741d06ccc4 100644 --- a/drivers/gpu/drm/meson/meson_canvas.c +++ b/drivers/gpu/drm/meson/meson_canvas.c @@ -43,6 +43,17 @@ #define CANVAS_LUT_WR_EN (0x2 << 8) #define CANVAS_LUT_RD_EN (0x1 << 8)
+u8 meson_canvas_id_osd1(struct meson_drm *priv) +{
if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) {
return 0x43; // HACK: OSD1 = 0x40, OSD2 = 0x43
} else {
return 0x4e;
}
+}
This canvas ID is purely logical and any number should work here, since this same number is used to update the OSD config register aswell.
I guess you are referring to meson_plane_atomic_update() where priv->viu.osd1_blk0_cfg[0] is being set this sets the canvas ID for OSD1 though (if I understand the code correctly), but I believe OSD2 is used to display content
void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h index af1759da4b27..4f594c8a6f80 100644 --- a/drivers/gpu/drm/meson/meson_canvas.h +++ b/drivers/gpu/drm/meson/meson_canvas.h @@ -22,8 +22,6 @@ #ifndef __MESON_CANVAS_H #define __MESON_CANVAS_H
-#define MESON_CANVAS_ID_OSD1 0x4e
/* Canvas configuration. */ #define MESON_CANVAS_WRAP_NONE 0x00 #define MESON_CANVAS_WRAP_X 0x01 @@ -33,6 +31,8 @@ #define MESON_CANVAS_BLKMODE_32x32 0x01 #define MESON_CANVAS_BLKMODE_64x64 0x02
+u8 meson_canvas_id_osd1(struct meson_drm *priv);
void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 3b804fdaf7a0..96c77498ef55 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -378,6 +378,9 @@ static int meson_drv_probe(struct platform_device *pdev) };
static const struct of_device_id dt_match[] = {
{ .compatible = "amlogic,meson8-vpu" },
{ .compatible = "amlogic,meson8b-vpu" },
{ .compatible = "amlogic,meson8m2-vpu" }, { .compatible = "amlogic,meson-gxbb-vpu" }, { .compatible = "amlogic,meson-gxl-vpu" }, { .compatible = "amlogic,meson-gxm-vpu" },
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 17e96fa47868..9d9a491c4eba 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -93,6 +93,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, .x2 = state->crtc_x + state->crtc_w, .y2 = state->crtc_y + state->crtc_h, };
u8 canvas_index = meson_canvas_id_osd1(priv); unsigned long flags; /*
@@ -109,7 +110,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, OSD_BLK0_ENABLE;
/* Set up BLK0 to point to the right canvas */
priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
priv->viu.osd1_blk0_cfg[0] = ((canvas_index << OSD_CANVAS_SEL) | OSD_ENDIANNESS_LE); /* On GXBB, Use the old non-HDR RGB2YUV converter */
@@ -164,7 +165,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, /* Update Canvas with buffer address */ gem = drm_fb_cma_get_gem_obj(fb, 0);
meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
meson_canvas_setup(priv, canvas_index, gem->paddr, fb->pitches[0], fb->height, MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR);
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 47677047e42d..1b1e379501d4 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -247,7 +247,20 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) unsigned int val;
/* Setup PLL to output 1.485GHz */
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) {
+#if 0
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x2001042d);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x814d3928);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x6b425012);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x00000110);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0001042d);
+#else
The HDMI PLL should also be totally different.
yes, this is where/why I started extending the meson8b clock driver... :)
/* TODO! */
return;
+#endif
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
@@ -428,7 +441,11 @@ void meson_hdmi_pll_set(struct meson_drm *priv, { unsigned int val;
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
if (meson_vpu_is_compatible(priv, "amlogic,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu")) {
return; // TODO
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { switch (base) { case 2970000: regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 79d95ca8a0c0..1affa6b19170 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -179,7 +179,10 @@ 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,meson8-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8b-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson8m2-vpu") ||
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"))
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index 6bcfa527c180..4b65f9166d78 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -303,9 +303,12 @@ void meson_viu_init(struct meson_drm *priv) /* Disable OSDs */ writel_bits_relaxed(BIT(0) | BIT(21), 0, priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); +#if 0 writel_bits_relaxed(BIT(0) | BIT(21), 0, priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
+#else
printk("%s: VIU_OSD2_CTRL_STAT = 0x%08x\n", __func__, readl(priv->io_base + _REG(VIU_OSD2_CTRL_STAT)));
+#endif
You should try enabling/disabled each OSD to see if something shows.
if I disable OSD2 (by turning that "#if 0" into "#if 1" then the boot-logo from u-boot disappears and the screen goes blank
/* On GXL/GXM, Use the 10bit HDR conversion matrix */ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index 27356f81a0ab..c66c16473989 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -61,6 +61,7 @@ void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux) void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv, struct drm_rect *input) { +#if 0 writel_relaxed(BIT(3) /* Enable scaler */ | BIT(2), /* Select OSD1 */ priv->io_base + _REG(VPP_OSD_SC_CTRL0)); @@ -79,6 +80,33 @@ void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv, writel_relaxed(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
The scaler is used here to change the interlace field automatically, otherwise we should change it using an irq handler....
In fact the :
BIT(2), /* Select OSD1 */
is false....
The bits 0-1 are : osd_sc_sel, 00: select osd1 input, 01: select osd2 input, 10: select vd1 input, 11: select vd2 input after matrix
I wonder why I set BIT(2) here... I must got it from the u-boot source.
U-boot 2016-08-18 has : /* enable osd scaler path */ if (index == OSD1) data32 = 8; else { data32 = 1; /* select osd2 input */ data32 |= 1 << 3; /* enable osd scaler path */ }
in drivers/display/osd/osd_hw.c
I just rewarded myself with a cookie (for making you spot a bug, which is a good thing... I hope) :)
+#else
printk("%s: VPP_OSD_SC_CTRL0 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SC_CTRL0)));
printk("%s: VPP_OSD_SCI_WH_M1 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCI_WH_M1)));
printk("%s: VPP_OSD_SCO_H_START_END = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCO_H_START_END)));
printk("%s: VPP_OSD_SCO_V_START_END = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_SCO_V_START_END)));
printk("%s: VPP_OSD_VSC_INI_PHASE = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)));
printk("%s: VPP_OSD_VSC_PHASE_STEP = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)));
printk("%s: VPP_OSD_HSC_CTRL0 = 0x%08x\n", __func__, readl(priv->io_base + _REG(VPP_OSD_HSC_CTRL0)));
writel_relaxed(BIT(3) /* Enable scaler */ |
BIT(0), /* Select OSD2 - FIXME */
priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+// writel_relaxed(((drm_rect_width(input) - 1) << 16) | +// (drm_rect_height(input) - 1), +// priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
+// writel_relaxed((drm_rect_height(input) - 1), +// priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
writel_relaxed(0x04ff02cf, priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
writel_relaxed(0x000002cf, priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
writel_relaxed(0x0000011f, priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
writel_relaxed(0x40000000, priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
writel_relaxed(0x02800000, priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
writel_relaxed(0x00400124, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+#endif
writel_relaxed((4 << 0) /* osd_vsc_bank_length */ | (4 << 3) /* osd_vsc_top_ini_rcv_num0 */ |
please let me know if you're interested in more information (just let me know what you need)
Regards Martin
vdac0 shows 27MHz on Meson8m2 1080P HDMI mode shows weird results (not verified yet)
differences to the video clocks in the GX SoCs: - HHI_VID_DIVIDER_CNTL is unique to Meson8/Meson8b/Meson8m2. the GX SoCs use some other logic and the HHI_VID_PLL_CLK_DIV register instead - the final ENCT/ENCP/ENCI/ENCL/VDAC0/HDMI_TX_PIXEL clocks can not use both, vclk and vclk2 as input (ENCT, ENCP and ENCI are defined in HHI_VID_CLK_DIV so they use the vclk dividers, while ENCL, VDAC0 and HDMI_TX_PIXEL are defined in HHI_VIID_CLK_DIV and HHI_HDMI_CLK_CNTL so they use the vclk2 dividers)
WiP
Signed-off-by: Martin Blumenstingl martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 637 +++++++++++++++++++++++++++++++ drivers/clk/meson/meson8b.h | 7 +- include/dt-bindings/clock/meson8b-clkc.h | 42 ++ 3 files changed, 685 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 365092a30b37..6642412808c8 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -515,6 +515,567 @@ struct clk_gate meson8b_nand_clk_gate = { }, };
+struct clk_divider meson8b_vid_pll_pre_div = { + .reg = (void *)HHI_VID_DIVIDER_CNTL, + .shift = 4, + .width = 3, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_pre_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vid_pll" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_divider meson8b_vid_pll_post_div = { + .reg = (void *)HHI_VID_DIVIDER_CNTL, + .shift = 12, + .width = 3, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_post_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vid_pll_pre_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_mux meson8b_vid_pll_post_sel = { + .reg = (void *)HHI_VID_DIVIDER_CNTL, + .mask = 0x3, + .shift = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_post_sel", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "vid_pll_pre_div", + "vid_pll_post_div" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_gate meson8b_vid_pll_post_en = { + .reg = (void *)HHI_VID_DIVIDER_CNTL, + .bit_idx = 16, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_post_en", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "vid_pll_post_sel", }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static const char * const meson8b_vclk_mux_parents[] = { + "vid_pll_post_en", "fclk_div4", "fclk_div3", "fclk_div5", + "vid_pll_post_en", "fclk_div7", "mpll1" +}; + +struct clk_mux meson8b_vclk_sel = { + .reg = (void *)HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_gate meson8b_vclk_en0_gate = { + .reg = (void *)HHI_VID_CLK_CNTL, + .bit_idx = 19, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_en0", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "vclk_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_divider meson8b_vclk_xd0_div = { + .reg = (void *)HHI_VID_CLK_DIV, + .shift = 0, + .width = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_xd0", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vclk_en0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_gate meson8b_vclk_clk_div_gate = { + .reg = (void *)HHI_VID_CLK_DIV, + .bit_idx = 16, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_clk_div_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk_xd0" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_gate meson8b_vclk_div1_gate = { + .reg = (void *)HHI_VID_CLK_DIV, + .bit_idx = 0, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div1_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk_clk_div_en" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk_div2_gate = { + .reg = (void *)HHI_VID_CLK_DIV, + .bit_idx = 1, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk_div2" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk_div4_gate = { + .reg = (void *)HHI_VID_CLK_DIV, + .bit_idx = 2, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk_div4" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk_div6_gate = { + .reg = (void *)HHI_VID_CLK_DIV, + .bit_idx = 3, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk_div6" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk_div12_gate = { + .reg = (void *)HHI_VID_CLK_DIV, + .bit_idx = 4, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk_div12" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_mux meson8b_vclk2_sel = { + .reg = (void *)HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_gate meson8b_vclk2_en0_gate = { + .reg = (void *)HHI_VID_CLK_CNTL, + .bit_idx = 19, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_en0", + .ops = &clk_mux_ops, + .parent_names = (const char *[]){ "vclk2_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_divider meson8b_vclk2_xd0_div = { + .reg = (void *)HHI_VIID_CLK_DIV, + .shift = 0, + .width = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_xd0", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vclk2_en0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +struct clk_gate meson8b_vclk2_clk_div_gate = { + .reg = (void *)HHI_VIID_CLK_DIV, + .bit_idx = 16, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_clk_div_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk2_xd0" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_gate meson8b_vclk2_div1_gate = { + .reg = (void *)HHI_VIID_CLK_DIV, + .bit_idx = 0, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div1_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk2_clk_div_en" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk2_div2_gate = { + .reg = (void *)HHI_VIID_CLK_DIV, + .bit_idx = 1, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk2_div2" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk2_div4_gate = { + .reg = (void *)HHI_VIID_CLK_DIV, + .bit_idx = 2, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk2_div4" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk2_div6_gate = { + .reg = (void *)HHI_VIID_CLK_DIV, + .bit_idx = 3, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk2_div6" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_clk_div_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +struct clk_gate meson8b_vclk2_div12_gate = { + .reg = (void *)HHI_VIID_CLK_DIV, + .bit_idx = 4, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vclk2_div12" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static const char * const meson8b_vclk_enc_mux_parents[] = { + "vclk_div1_en", "vclk_div2_en", "vclk_div4_en", "vclk_div6_en", + "vclk_div12_en", +}; + +struct clk_mux meson8b_enct_sel = { + .reg = (void *)HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 20, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "enct_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + }, +}; + +struct clk_gate meson8b_enct_gate = { + .reg = (void *)HHI_VID_CLK_CNTL2, + .bit_idx = 1, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "enct_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "enct_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_mux meson8b_encp_sel = { + .reg = (void *)HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "encp_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + }, +}; + +struct clk_gate meson8b_encp_gate = { + .reg = (void *)HHI_VID_CLK_CNTL2, + .bit_idx = 2, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "encp_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "encp_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_mux meson8b_enci_sel = { + .reg = (void *)HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "enci_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + }, +}; + +struct clk_gate meson8b_enci_gate = { + .reg = (void *)HHI_VID_CLK_CNTL2, + .bit_idx = 0, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "enci_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "enci_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +static const char * const meson8b_vclk2_enc_mux_parents[] = { + "vclk2_div1_en", "vclk2_div2_en", "vclk2_div4_en", "vclk2_div6_en", + "vclk2_div12_en", +}; + +struct clk_mux meson8b_encl_sel = { + .reg = (void *)HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "encl_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk2_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), + }, +}; + +struct clk_gate meson8b_encl_gate = { + .reg = (void *)HHI_VID_CLK_CNTL2, + .bit_idx = 3, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "encl_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "encl_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_mux meson8b_vdac0_sel = { + .reg = (void *)HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdac0_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk2_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), + }, +}; + +struct clk_gate meson8b_vdac0_gate = { + .reg = (void *)HHI_VID_CLK_CNTL2, + .bit_idx = 4, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdac0_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vdac0_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + +struct clk_mux meson8b_hdmi_tx_pixel_sel = { + .reg = (void *)HHI_HDMI_CLK_CNTL, + .mask = 0xf, + .shift = 16, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel_sel", + .ops = &clk_mux_ops, + .parent_names = meson8b_vclk2_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), + }, +}; + +struct clk_gate meson8b_hdmi_tx_pixel_gate = { + .reg = (void *)HHI_VID_CLK_CNTL2, + .bit_idx = 5, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel_en", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hdmi_tx_pixel_sel" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), + }, +}; + /* Everything Else (EE) domain gates */
static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); @@ -703,6 +1264,48 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_SYS_PLL_DIV3] = &meson8b_sys_pll_div3.hw, [CLKID_SYS_PLL_SCALE_DIV] = &meson8b_sys_pll_scale_div.hw, [CLKID_SYS_PLL_SCALE_SEL] = &meson8b_sys_pll_scale_out_sel.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_POST_SEL] = &meson8b_vid_pll_post_sel.hw, + [CLKID_VID_PLL_POST_EN] = &meson8b_vid_pll_post_en.hw, + [CLKID_VCLK_SEL] = &meson8b_vclk_sel.hw, + [CLKID_VCLK_EN0] = &meson8b_vclk_en0_gate.hw, + [CLKID_VCLK_XD0_DIV] = &meson8b_vclk_xd0_div.hw, + [CLKID_VCLK_CLK_DIV_EN] = &meson8b_vclk_clk_div_gate.hw, + [CLKID_VCLK_DIV1_EN] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV2_EN] = &meson8b_vclk_div2_gate.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2.hw, + [CLKID_VCLK_DIV4_EN] = &meson8b_vclk_div4_gate.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4.hw, + [CLKID_VCLK_DIV6_EN] = &meson8b_vclk_div6_gate.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6.hw, + [CLKID_VCLK_DIV12_EN] = &meson8b_vclk_div12_gate.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12.hw, + [CLKID_VCLK2_SEL] = &meson8b_vclk2_sel.hw, + [CLKID_VCLK2_EN0] = &meson8b_vclk2_en0_gate.hw, + [CLKID_VCLK2_XD0_DIV] = &meson8b_vclk2_xd0_div.hw, + [CLKID_VCLK2_CLK_DIV_EN] = &meson8b_vclk2_clk_div_gate.hw, + [CLKID_VCLK2_DIV1_EN] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_DIV2_EN] = &meson8b_vclk2_div2_gate.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2.hw, + [CLKID_VCLK2_DIV4_EN] = &meson8b_vclk2_div4_gate.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4.hw, + [CLKID_VCLK2_DIV6_EN] = &meson8b_vclk2_div6_gate.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6.hw, + [CLKID_VCLK2_DIV12_EN] = &meson8b_vclk2_div12_gate.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12.hw, + [CLKID_ENCT_SEL] = &meson8b_enct_sel.hw, + [CLKID_ENCT_EN] = &meson8b_enct_gate.hw, + [CLKID_ENCP_SEL] = &meson8b_encp_sel.hw, + [CLKID_ENCP_EN] = &meson8b_encp_gate.hw, + [CLKID_ENCI_SEL] = &meson8b_enci_sel.hw, + [CLKID_ENCI_EN] = &meson8b_enci_gate.hw, + [CLKID_ENCL_SEL] = &meson8b_encl_sel.hw, + [CLKID_ENCL_EN] = &meson8b_encl_gate.hw, + [CLKID_VDAC0_SEL] = &meson8b_vdac0_sel.hw, + [CLKID_VDAC0_EN] = &meson8b_vdac0_gate.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL_EN] = &meson8b_hdmi_tx_pixel_gate.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -800,11 +1403,41 @@ static struct clk_gate *const meson8b_clk_gates[] = { &meson8b_ao_ahb_bus, &meson8b_ao_iface, &meson8b_nand_clk_gate, + &meson8b_vid_pll_post_en, + &meson8b_vclk_en0_gate, + &meson8b_vclk_clk_div_gate, + &meson8b_vclk_div1_gate, + &meson8b_vclk_div2_gate, + &meson8b_vclk_div4_gate, + &meson8b_vclk_div6_gate, + &meson8b_vclk_div12_gate, + &meson8b_vclk2_en0_gate, + &meson8b_vclk2_clk_div_gate, + &meson8b_vclk2_div1_gate, + &meson8b_vclk2_div2_gate, + &meson8b_vclk2_div4_gate, + &meson8b_vclk2_div6_gate, + &meson8b_vclk2_div12_gate, + &meson8b_enct_gate, + &meson8b_encp_gate, + &meson8b_enci_gate, + &meson8b_encl_gate, + &meson8b_vdac0_gate, + &meson8b_hdmi_tx_pixel_gate, };
static struct clk_mux *const meson8b_clk_muxes[] = { &meson8b_mpeg_clk_sel, &meson8b_nand_clk_sel, + &meson8b_vid_pll_post_sel, + &meson8b_vclk_sel, + &meson8b_vclk2_sel, + &meson8b_enct_sel, + &meson8b_encp_sel, + &meson8b_enci_sel, + &meson8b_encl_sel, + &meson8b_vdac0_sel, + &meson8b_hdmi_tx_pixel_sel, &meson8b_sys_pll_scale_out_sel, &meson8b_cpu_clk_sel, }; @@ -812,6 +1445,10 @@ static struct clk_mux *const meson8b_clk_muxes[] = { static struct clk_divider *const meson8b_clk_dividers[] = { &meson8b_mpeg_clk_div, &meson8b_nand_clk_div, + &meson8b_vid_pll_pre_div, + &meson8b_vid_pll_post_div, + &meson8b_vclk_xd0_div, + &meson8b_vclk2_xd0_div, &meson8b_sys_pll_scale_div, };
diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 4ac593a174a7..3833890d351c 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -30,16 +30,21 @@ * * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf */ +#define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */ +#define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */ #define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */ #define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in data sheet */ #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ #define HHI_GCLK_OTHER 0x150 /* 0x54 offset in data sheet */ #define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ +#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ #define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ #define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ +#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ #define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */ +#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */ #define HHI_NAND_CLK_CNTL 0x25c /* 0x97 offset in data sheet */ #define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ @@ -70,7 +75,7 @@ * will remain defined here. */
-#define CLK_NR_CLKS 103 +#define CLK_NR_CLKS 145
/* * include the CLKID and RESETID that have diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h index ffbc3dabbd84..fc48315f0822 100644 --- a/include/dt-bindings/clock/meson8b-clkc.h +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -109,5 +109,47 @@ #define CLKID_SYS_PLL_DIV3 100 #define CLKID_SYS_PLL_SCALE_DIV 101 #define CLKID_SYS_PLL_SCALE_SEL 102 +#define CLKID_VID_PLL_PRE_DIV 103 +#define CLKID_VID_PLL_POST_DIV 104 +#define CLKID_VID_PLL_POST_SEL 105 +#define CLKID_VID_PLL_POST_EN 106 +#define CLKID_VCLK_SEL 107 +#define CLKID_VCLK_EN0 108 +#define CLKID_VCLK_XD0_DIV 109 +#define CLKID_VCLK_CLK_DIV_EN 110 +#define CLKID_VCLK_DIV1_EN 111 +#define CLKID_VCLK_DIV2_EN 112 +#define CLKID_VCLK_DIV2 113 +#define CLKID_VCLK_DIV4_EN 114 +#define CLKID_VCLK_DIV4 115 +#define CLKID_VCLK_DIV6_EN 116 +#define CLKID_VCLK_DIV6 117 +#define CLKID_VCLK_DIV12_EN 118 +#define CLKID_VCLK_DIV12 119 +#define CLKID_VCLK2_SEL 120 +#define CLKID_VCLK2_EN0 121 +#define CLKID_VCLK2_XD0_DIV 122 +#define CLKID_VCLK2_CLK_DIV_EN 123 +#define CLKID_VCLK2_DIV1_EN 124 +#define CLKID_VCLK2_DIV2_EN 125 +#define CLKID_VCLK2_DIV2 126 +#define CLKID_VCLK2_DIV4_EN 127 +#define CLKID_VCLK2_DIV4 128 +#define CLKID_VCLK2_DIV6_EN 129 +#define CLKID_VCLK2_DIV6 130 +#define CLKID_VCLK2_DIV12_EN 131 +#define CLKID_VCLK2_DIV12 132 +#define CLKID_ENCT_SEL 133 +#define CLKID_ENCT_EN 134 +#define CLKID_ENCP_SEL 135 +#define CLKID_ENCP_EN 136 +#define CLKID_ENCI_SEL 137 +#define CLKID_ENCI_EN 138 +#define CLKID_ENCL_SEL 139 +#define CLKID_ENCL_EN 140 +#define CLKID_VDAC0_SEL 141 +#define CLKID_VDAC0_EN 142 +#define CLKID_HDMI_TX_PIXEL_SEL 143 +#define CLKID_HDMI_TX_PIXEL_EN 144
#endif /* __MESON8B_CLKC_H */
dri-devel@lists.freedesktop.org