* [PATCH 01/19] drm/sun4i: call drm_vblank_init with correct number of crtcs
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 03/19] drm/sun4i: tcon: Add support for demuxing TCON output on A31 Chen-Yu Tsai
` (15 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
If we want to have vblank on both pipelines at the same time, we need
to call drm_vblank_init with num_crtcs = 2.
Instead, since the crtc init calls correctly set mode_config.num_crtc,
we can move the drm_vblank_init call to after the crtc init code is
called, which is the component bind part. Then we can just pass
mode_config.num_crtc in.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_drv.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index f19100c91c2b..ed75a779ae4b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -100,11 +100,6 @@ static int sun4i_drv_bind(struct device *dev)
goto free_drm;
}
- /* drm_vblank_init calls kcalloc, which can fail */
- ret = drm_vblank_init(drm, 1);
- if (ret)
- goto free_mem_region;
-
drm_mode_config_init(drm);
ret = component_bind_all(drm->dev, drm);
@@ -113,6 +108,11 @@ static int sun4i_drv_bind(struct device *dev)
goto cleanup_mode_config;
}
+ /* drm_vblank_init calls kcalloc, which can fail */
+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ if (ret)
+ goto free_mem_region;
+
drm->irq_enabled = true;
/* Remove early framebuffers (ie. simplefb) */
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 03/19] drm/sun4i: tcon: Add support for demuxing TCON output on A31
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
2017-06-02 10:10 ` [PATCH 01/19] drm/sun4i: call drm_vblank_init with correct number of crtcs Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 04/19] drm/sun4i: hdmi: Disable clks in bind function error path and unbind function Chen-Yu Tsai
` (14 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
On systems with 2 TCONs such as the A31, it is possible to demux the
output of the TCONs to one encoder.
Add support for this for the A31.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 61 ++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index d9791292553e..21bd7fab7aaa 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -14,9 +14,12 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder.h>
#include <drm/drm_modes.h>
#include <drm/drm_of.h>
+#include <uapi/drm/drm_mode.h>
+
#include <linux/component.h>
#include <linux/ioport.h>
#include <linux/of_address.h>
@@ -109,11 +112,69 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
}
EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
+static struct sun4i_tcon *sun4i_get_first_tcon(struct drm_device *drm)
+{
+ struct sun4i_drv *drv = drm->dev_private;
+ struct sun4i_tcon *tcon;
+
+ list_for_each_entry(tcon, &drv->tcon_list, list)
+ if (tcon->id == 0)
+ return tcon;
+
+ dev_warn(drm->dev,
+ "TCON0 not found, display output muxing may not work\n");
+
+ return tcon;
+}
+
+static int _sun6i_tcon_set_mux(struct drm_encoder *encoder)
+{
+ struct sun4i_tcon *tcon = sun4i_get_first_tcon(encoder->dev);
+ int tcon_id = drm_crtc_to_sun4i_crtc(encoder->crtc)->tcon->id;
+ u32 shift;
+
+ DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s (TCON %d)\n",
+ encoder->name, encoder->crtc->name, tcon_id);
+
+ /* Only 2 TCONs */
+ if (tcon_id >= 2)
+ return -EINVAL;
+
+ switch (encoder->encoder_type) {
+ case DRM_MODE_ENCODER_TMDS:
+ /* HDMI */
+ shift = 8;
+ break;
+ case DRM_MODE_ENCODER_DSI:
+ /* No MIPI DSI on A31s */
+ if (of_device_is_compatible(tcon->dev->of_node,
+ "allwinner,sun6i-a31s-tcon"))
+ return -EINVAL;
+ shift = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(tcon->regs, SUN4I_TCON_MUX_CTRL_REG,
+ 0x3 << shift, tcon_id << shift);
+
+ return 0;
+}
+
void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
struct drm_encoder *encoder)
{
+ /* Get the device node of the display engine */
+ struct device_node *node = encoder->dev->dev->of_node;
u32 val;
+ if (of_device_is_compatible(node, "allwinner,sun6i-a31-display-engine") ||
+ of_device_is_compatible(node, "allwinner,sun6i-a31s-display-engine")) {
+ _sun6i_tcon_set_mux(encoder);
+ return;
+ }
+
if (!tcon->quirks->has_unknown_mux)
return;
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 04/19] drm/sun4i: hdmi: Disable clks in bind function error path and unbind function
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
2017-06-02 10:10 ` [PATCH 01/19] drm/sun4i: call drm_vblank_init with correct number of crtcs Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 03/19] drm/sun4i: tcon: Add support for demuxing TCON output on A31 Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 05/19] drm/sun4i: hdmi: Allow using second PLL as TMDS clk parent Chen-Yu Tsai
` (13 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The HDMI driver enables the bus and mod clocks in the bind function, but
does not disable them if it then bails our due to any errors. Neither
does it disable the clocks in the unbind function.
Fix this by adding a proper error path to the bind function, and
clk_disable_unprepare calls to the unbind function.
Also rename the err_cleanup_connector label to err_cleanup_encoder,
since it is the encoder that gets cleaned up.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index d3398f6250ef..457614073501 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -350,26 +350,29 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
hdmi->mod_clk = devm_clk_get(dev, "mod");
if (IS_ERR(hdmi->mod_clk)) {
dev_err(dev, "Couldn't get the HDMI mod clock\n");
- return PTR_ERR(hdmi->mod_clk);
+ ret = PTR_ERR(hdmi->mod_clk);
+ goto err_disable_bus_clk;
}
clk_prepare_enable(hdmi->mod_clk);
hdmi->pll0_clk = devm_clk_get(dev, "pll-0");
if (IS_ERR(hdmi->pll0_clk)) {
dev_err(dev, "Couldn't get the HDMI PLL 0 clock\n");
- return PTR_ERR(hdmi->pll0_clk);
+ ret = PTR_ERR(hdmi->pll0_clk);
+ goto err_disable_mod_clk;
}
hdmi->pll1_clk = devm_clk_get(dev, "pll-1");
if (IS_ERR(hdmi->pll1_clk)) {
dev_err(dev, "Couldn't get the HDMI PLL 1 clock\n");
- return PTR_ERR(hdmi->pll1_clk);
+ ret = PTR_ERR(hdmi->pll1_clk);
+ goto err_disable_mod_clk;
}
ret = sun4i_tmds_create(hdmi);
if (ret) {
dev_err(dev, "Couldn't create the TMDS clock\n");
- return ret;
+ goto err_disable_mod_clk;
}
writel(SUN4I_HDMI_CTRL_ENABLE, hdmi->base + SUN4I_HDMI_CTRL_REG);
@@ -410,7 +413,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
ret = sun4i_ddc_create(hdmi, hdmi->tmds_clk);
if (ret) {
dev_err(dev, "Couldn't create the DDC clock\n");
- return ret;
+ goto err_disable_mod_clk;
}
drm_encoder_helper_add(&hdmi->encoder,
@@ -428,7 +431,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
hdmi->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm,
dev->of_node);
if (!hdmi->encoder.possible_crtcs)
- return -EPROBE_DEFER;
+ goto err_disable_mod_clk;
drm_connector_helper_add(&hdmi->connector,
&sun4i_hdmi_connector_helper_funcs);
@@ -438,7 +441,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
if (ret) {
dev_err(dev,
"Couldn't initialise the HDMI connector\n");
- goto err_cleanup_connector;
+ goto err_cleanup_encoder;
}
/* There is no HPD interrupt, so we need to poll the controller */
@@ -449,8 +452,12 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
return 0;
-err_cleanup_connector:
+err_cleanup_encoder:
drm_encoder_cleanup(&hdmi->encoder);
+err_disable_mod_clk:
+ clk_disable_unprepare(hdmi->mod_clk);
+err_disable_bus_clk:
+ clk_disable_unprepare(hdmi->bus_clk);
return ret;
}
@@ -461,6 +468,8 @@ static void sun4i_hdmi_unbind(struct device *dev, struct device *master,
drm_connector_cleanup(&hdmi->connector);
drm_encoder_cleanup(&hdmi->encoder);
+ clk_disable_unprepare(hdmi->mod_clk);
+ clk_disable_unprepare(hdmi->bus_clk);
}
static const struct component_ops sun4i_hdmi_ops = {
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 05/19] drm/sun4i: hdmi: Allow using second PLL as TMDS clk parent
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (2 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 04/19] drm/sun4i: hdmi: Disable clks in bind function error path and unbind function Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 06/19] dt-bindings: display: sun4i: Add binding for A31 HDMI controller Chen-Yu Tsai
` (12 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
On SoCs with two display pipelines, it is possible that the two
pipelines are active at the same time, with potentially incompatible
dot clocks.
Let the HDMI encoder's TMDS clock go through all of its parents when
calculating possible clock rates. This allows usage of the second video
PLL as its parent.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c | 51 ++++++++++++++++-------------
1 file changed, 28 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
index 5cf2527bffc8..5692e41833ae 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
@@ -71,7 +71,7 @@ static int sun4i_tmds_determine_rate(struct clk_hw *hw,
unsigned long best_parent = 0;
unsigned long rate = req->rate;
int best_div = 1, best_half = 1;
- int i, j;
+ int i, j, p;
/*
* We only consider PLL3, since the TCON is very likely to be
@@ -79,32 +79,37 @@ static int sun4i_tmds_determine_rate(struct clk_hw *hw,
* clock, so we should not need to do anything.
*/
- parent = clk_hw_get_parent_by_index(hw, 0);
- if (!parent)
- return -EINVAL;
-
- for (i = 1; i < 3; i++) {
- for (j = 1; j < 16; j++) {
- unsigned long ideal = rate * i * j;
- unsigned long rounded;
-
- rounded = clk_hw_round_rate(parent, ideal);
-
- if (rounded == ideal) {
- best_parent = rounded;
- best_half = i;
- best_div = j;
- goto out;
- }
-
- if (abs(rate - rounded / i) <
- abs(rate - best_parent / best_div)) {
- best_parent = rounded;
- best_div = i;
+ for (p = 0; p < clk_hw_get_num_parents(hw); p++) {
+ parent = clk_hw_get_parent_by_index(hw, p);
+ if (!parent)
+ continue;
+
+ for (i = 1; i < 3; i++) {
+ for (j = 1; j < 16; j++) {
+ unsigned long ideal = rate * i * j;
+ unsigned long rounded;
+
+ rounded = clk_hw_round_rate(parent, ideal);
+
+ if (rounded == ideal) {
+ best_parent = rounded;
+ best_half = i;
+ best_div = j;
+ goto out;
+ }
+
+ if (abs(rate - rounded / i) <
+ abs(rate - best_parent / best_div)) {
+ best_parent = rounded;
+ best_div = i;
+ }
}
}
}
+ if (!parent)
+ return -EINVAL;
+
out:
req->rate = best_parent / best_half / best_div;
req->best_parent_rate = best_parent;
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 06/19] dt-bindings: display: sun4i: Add binding for A31 HDMI controller
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (3 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 05/19] drm/sun4i: hdmi: Allow using second PLL as TMDS clk parent Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
[not found] ` <20170602101024.18940-7-wens-jdAy2FN1RRM@public.gmane.org>
2017-06-02 10:10 ` [PATCH 08/19] drm/sun4i: hdmi: Support the TMDS clock in the A31's " Chen-Yu Tsai
` (11 subsequent siblings)
16 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The HDMI controller in the A31 SoC is slightly different from the
earlier version. In addition to the TMDS clock and DDC controls,
this version now takes a second DDC clock input.
Add a compatible string for it, and add the DDC clock input to the
list of clocks required.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index b83e6018041d..d23e7cad19d0 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -23,14 +23,17 @@ CEC. It is one end of the pipeline.
Required properties:
- compatible: value must be one of:
* allwinner,sun5i-a10s-hdmi
+ * allwinner,sun6i-a31-hdmi
- reg: base address and size of memory-mapped region
- interrupts: interrupt associated to this IP
- clocks: phandles to the clocks feeding the HDMI encoder
* ahb: the HDMI interface clock
* mod: the HDMI module clock
+ * ddc: the HDMI ddc clock (A31 only)
* pll-0: the first video PLL
* pll-1: the second video PLL
- clock-names: the clock names mentioned above
+ - resets: phandle to the reset control for the HDMI encoder (A31 only)
- dmas: phandles to the DMA channels used by the HDMI encoder
* ddc-tx: The channel for DDC transmission
* ddc-rx: The channel for DDC reception
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 08/19] drm/sun4i: hdmi: Support the TMDS clock in the A31's HDMI controller
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (4 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 06/19] dt-bindings: display: sun4i: Add binding for A31 HDMI controller Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 09/19] drm/sun4i: hdmi: Support different variants of the DDC clock Chen-Yu Tsai
` (10 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The A31's HDMI controller's TMDS clock is slightly different.
There is an offset of 1 between the divider value and the actual
value programmed into the registers.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi.h | 1 +
drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c | 7 +++++++
2 files changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
index 2f2f2ff1ea63..3a4987ab8da8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
@@ -153,5 +153,6 @@ struct sun4i_hdmi {
int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *clk);
int sun4i_tmds_create(struct sun4i_hdmi *hdmi);
+int sun6i_tmds_create(struct sun4i_hdmi *hdmi);
#endif /* _SUN4I_HDMI_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
index 3c304e1fbe3b..6f25c7bd887e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
@@ -240,3 +240,10 @@ int sun4i_tmds_create(struct sun4i_hdmi *hdmi)
{
return _sun4i_tmds_create(hdmi, 0);
}
+
+/* sun6i variant has a different value offset for the divider */
+
+int sun6i_tmds_create(struct sun4i_hdmi *hdmi)
+{
+ return _sun4i_tmds_create(hdmi, 1);
+}
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 09/19] drm/sun4i: hdmi: Support different variants of the DDC clock
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (5 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 08/19] drm/sun4i: hdmi: Support the TMDS clock in the A31's " Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 10/19] drm/sun4i: hdmi: Rename internal DDC clock to avoid name collision Chen-Yu Tsai
` (9 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
On the A31, the HDMI DDC block is different from the one in the
other SoCs. As far as the DDC clock goes, it has no pre-divider,
as it is clocked from a slower parent clock, not the TMDS clock.
The divider offset from the register value is different. And the
clock control register is at a different offset.
This patch adds support for different variants of the DDC clock.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 42 ++++++++++++++++++++++++------
1 file changed, 34 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
index 4692e8c345ed..e1071838f487 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
@@ -15,9 +15,16 @@
#include "sun4i_tcon.h"
#include "sun4i_hdmi.h"
+struct sun4i_ddc_variant {
+ u32 reg_offset;
+ u8 pre_divider;
+ u8 m_offset;
+};
+
struct sun4i_ddc {
struct clk_hw hw;
struct sun4i_hdmi *hdmi;
+ const struct sun4i_ddc_variant *variant;
};
static inline struct sun4i_ddc *hw_to_ddc(struct clk_hw *hw)
@@ -27,6 +34,7 @@ static inline struct sun4i_ddc *hw_to_ddc(struct clk_hw *hw)
static unsigned long sun4i_ddc_calc_divider(unsigned long rate,
unsigned long parent_rate,
+ const struct sun4i_ddc_variant *variant,
u8 *m, u8 *n)
{
unsigned long best_rate = 0;
@@ -36,7 +44,8 @@ static unsigned long sun4i_ddc_calc_divider(unsigned long rate,
for (_n = 0; _n < 8; _n++) {
unsigned long tmp_rate;
- tmp_rate = (((parent_rate / 2) / 10) >> _n) / (_m + 1);
+ tmp_rate = (((parent_rate / variant->pre_divider) /
+ 10) >> _n) / (_m + variant->m_offset);
if (tmp_rate > rate)
continue;
@@ -60,7 +69,9 @@ static unsigned long sun4i_ddc_calc_divider(unsigned long rate,
static long sun4i_ddc_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
- return sun4i_ddc_calc_divider(rate, *prate, NULL, NULL);
+ struct sun4i_ddc *ddc = hw_to_ddc(hw);
+
+ return sun4i_ddc_calc_divider(rate, *prate, ddc->variant, NULL, NULL);
}
static unsigned long sun4i_ddc_recalc_rate(struct clk_hw *hw,
@@ -70,11 +81,12 @@ static unsigned long sun4i_ddc_recalc_rate(struct clk_hw *hw,
u32 reg;
u8 m, n;
- reg = readl(ddc->hdmi->base + SUN4I_HDMI_DDC_CLK_REG);
- m = (reg >> 3) & 0x7;
+ reg = readl(ddc->hdmi->base + ddc->variant->reg_offset);
+ m = (reg >> 3) & 0xf;
n = reg & 0x7;
- return (((parent_rate / 2) / 10) >> n) / (m + 1);
+ return (((parent_rate / ddc->variant->pre_divider) / 10) >> n) /
+ (m + ddc->variant->m_offset);
}
static int sun4i_ddc_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -83,10 +95,11 @@ static int sun4i_ddc_set_rate(struct clk_hw *hw, unsigned long rate,
struct sun4i_ddc *ddc = hw_to_ddc(hw);
u8 div_m, div_n;
- sun4i_ddc_calc_divider(rate, parent_rate, &div_m, &div_n);
+ sun4i_ddc_calc_divider(rate, parent_rate, ddc->variant,
+ &div_m, &div_n);
writel(SUN4I_HDMI_DDC_CLK_M(div_m) | SUN4I_HDMI_DDC_CLK_N(div_n),
- ddc->hdmi->base + SUN4I_HDMI_DDC_CLK_REG);
+ ddc->hdmi->base + ddc->variant->reg_offset);
return 0;
}
@@ -97,7 +110,8 @@ static const struct clk_ops sun4i_ddc_ops = {
.set_rate = sun4i_ddc_set_rate,
};
-int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent)
+static int _sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent,
+ const struct sun4i_ddc_variant *variant)
{
struct clk_init_data init;
struct sun4i_ddc *ddc;
@@ -117,6 +131,7 @@ int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent)
init.num_parents = 1;
ddc->hdmi = hdmi;
+ ddc->variant = variant;
ddc->hw.init = &init;
hdmi->ddc_clk = devm_clk_register(hdmi->dev, &ddc->hw);
@@ -125,3 +140,14 @@ int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent)
return 0;
}
+
+static const struct sun4i_ddc_variant sun4i_variant = {
+ .reg_offset = SUN4I_HDMI_DDC_CLK_REG,
+ .pre_divider = 2,
+ .m_offset = 1,
+};
+
+int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent)
+{
+ return _sun4i_ddc_create(hdmi, parent, &sun4i_variant);
+}
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 10/19] drm/sun4i: hdmi: Rename internal DDC clock to avoid name collision
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (6 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 09/19] drm/sun4i: hdmi: Support different variants of the DDC clock Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 19:30 ` Maxime Ripard
2017-06-02 10:10 ` [PATCH 11/19] drm/sun4i: hdmi: Add A31 specific DDC register definitions Chen-Yu Tsai
` (8 subsequent siblings)
16 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The DDC parent clock on the A31 SoC is also conveniently named
"hdmi-ddc", which results in a name collision when the hdmi driver
registers its internal DDC divider clock.
Rename the internal clock to "hdmi-ddc-divider".
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
index e1071838f487..9a6b6243e977 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
@@ -125,7 +125,7 @@ static int _sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent,
if (!ddc)
return -ENOMEM;
- init.name = "hdmi-ddc";
+ init.name = "hdmi-ddc-divider";
init.ops = &sun4i_ddc_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 10/19] drm/sun4i: hdmi: Rename internal DDC clock to avoid name collision
2017-06-02 10:10 ` [PATCH 10/19] drm/sun4i: hdmi: Rename internal DDC clock to avoid name collision Chen-Yu Tsai
@ 2017-06-02 19:30 ` Maxime Ripard
2017-06-03 14:33 ` Chen-Yu Tsai
0 siblings, 1 reply; 38+ messages in thread
From: Maxime Ripard @ 2017-06-02 19:30 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: David Airlie, Rob Herring, Michael Turquette, Stephen Boyd,
dri-devel, linux-arm-kernel, devicetree, linux-clk, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 1178 bytes --]
On Fri, Jun 02, 2017 at 06:10:15PM +0800, Chen-Yu Tsai wrote:
> The DDC parent clock on the A31 SoC is also conveniently named
> "hdmi-ddc", which results in a name collision when the hdmi driver
> registers its internal DDC divider clock.
>
> Rename the internal clock to "hdmi-ddc-divider".
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
> index e1071838f487..9a6b6243e977 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
> @@ -125,7 +125,7 @@ static int _sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent,
> if (!ddc)
> return -ENOMEM;
>
> - init.name = "hdmi-ddc";
> + init.name = "hdmi-ddc-divider";
Can't we rename the CCU clock instead? Having the clock called
hdmi-ddc being the actual clock output on the DDC bus feels more
natural.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 10/19] drm/sun4i: hdmi: Rename internal DDC clock to avoid name collision
2017-06-02 19:30 ` Maxime Ripard
@ 2017-06-03 14:33 ` Chen-Yu Tsai
[not found] ` <CAGb2v64Vgdjm1MAwn+L0PVc0CA0QOCn=0RONKoGDWLpzVBzvmQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-03 14:33 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd, dri-devel, linux-arm-kernel, devicetree, linux-clk,
linux-sunxi
On Sat, Jun 3, 2017 at 3:30 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Fri, Jun 02, 2017 at 06:10:15PM +0800, Chen-Yu Tsai wrote:
>> The DDC parent clock on the A31 SoC is also conveniently named
>> "hdmi-ddc", which results in a name collision when the hdmi driver
>> registers its internal DDC divider clock.
>>
>> Rename the internal clock to "hdmi-ddc-divider".
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
>> index e1071838f487..9a6b6243e977 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
>> @@ -125,7 +125,7 @@ static int _sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent,
>> if (!ddc)
>> return -ENOMEM;
>>
>> - init.name = "hdmi-ddc";
>> + init.name = "hdmi-ddc-divider";
>
> Can't we rename the CCU clock instead? Having the clock called
> hdmi-ddc being the actual clock output on the DDC bus feels more
> natural.
Do you have any suggestions? The manual labels the conflicting one
in the CCU as "HDMI_DDC"...
ChenYu
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 11/19] drm/sun4i: hdmi: Add A31 specific DDC register definitions
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (7 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 10/19] drm/sun4i: hdmi: Rename internal DDC clock to avoid name collision Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 12/19] drm/sun4i: hdmi: Support the DDC clock in the A31's HDMI controller Chen-Yu Tsai
` (7 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The DDC block for the HDMI controller is different on the A31.
This patch adds the register definitions.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
index 3a4987ab8da8..08c514672fd3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
@@ -124,6 +124,32 @@
#define SUN4I_HDMI_DDC_FIFO_SIZE 16
+/* A31 specific */
+#define SUN6I_HDMI_DDC_CTRL_REG 0x500
+#define SUN6I_HDMI_DDC_CTRL_RESET BIT(31)
+#define SUN6I_HDMI_DDC_CTRL_START_CMD BIT(27)
+#define SUN6I_HDMI_DDC_CTRL_SDA_ENABLE BIT(6)
+#define SUN6I_HDMI_DDC_CTRL_SCL_ENABLE BIT(4)
+#define SUN6I_HDMI_DDC_CTRL_ENABLE BIT(0)
+
+#define SUN6I_HDMI_DDC_CMD_REG 0x508
+#define SUN6I_HDMI_DDC_CMD_EXPLICIT_EDDC_READ 6
+#define SUN6I_HDMI_DDC_CMD_BYTE_COUNT(count) ((count) << 16)
+
+#define SUN6I_HDMI_DDC_ADDR_REG 0x50c
+#define SUN6I_HDMI_DDC_ADDR_SEGMENT(seg) (((seg) & 0xff) << 24)
+#define SUN6I_HDMI_DDC_ADDR_EDDC(addr) (((addr) & 0xff) << 16)
+#define SUN6I_HDMI_DDC_ADDR_OFFSET(off) (((off) & 0xff) << 8)
+#define SUN6I_HDMI_DDC_ADDR_SLAVE(addr) (((addr) & 0xff) << 1)
+
+#define SUN6I_HDMI_DDC_FIFO_CTRL_REG 0x518
+#define SUN6I_HDMI_DDC_FIFO_CTRL_CLEAR BIT(15)
+
+#define SUN6I_HDMI_DDC_CLK_REG 0x520
+/* DDC CLK bit fields are the same, but the formula is not */
+
+#define SUN6I_HDMI_DDC_FIFO_DATA_REG 0x580
+
enum sun4i_hdmi_pkt_type {
SUN4I_HDMI_PKT_AVI = 2,
SUN4I_HDMI_PKT_END = 15,
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 12/19] drm/sun4i: hdmi: Support the DDC clock in the A31's HDMI controller
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (8 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 11/19] drm/sun4i: hdmi: Add A31 specific DDC register definitions Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
[not found] ` <20170602101024.18940-13-wens-jdAy2FN1RRM@public.gmane.org>
2017-06-02 10:10 ` [PATCH 13/19] drm/sun4i: hdmi: Add support for controller hardware variants Chen-Yu Tsai
` (6 subsequent siblings)
16 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
On the A31, the HDMI DDC block is different from the one in the
other SoCs. As far as the DDC clock goes, it has no pre-divider,
as it is clocked from a slower parent clock, not the TMDS clock.
The divider offset from the register value is different. And the
clock control register is at a different offset.
This patch adds support for this variant.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi.h | 1 +
drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
index 08c514672fd3..c39c2a245339 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
@@ -178,6 +178,7 @@ struct sun4i_hdmi {
};
int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *clk);
+int sun6i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *clk);
int sun4i_tmds_create(struct sun4i_hdmi *hdmi);
int sun6i_tmds_create(struct sun4i_hdmi *hdmi);
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
index 9a6b6243e977..b1395e7b242c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
@@ -151,3 +151,14 @@ int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent)
{
return _sun4i_ddc_create(hdmi, parent, &sun4i_variant);
}
+
+static const struct sun4i_ddc_variant sun6i_variant = {
+ .reg_offset = SUN6I_HDMI_DDC_CLK_REG,
+ .pre_divider = 1,
+ .m_offset = 2,
+};
+
+int sun6i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent)
+{
+ return _sun4i_ddc_create(hdmi, parent, &sun6i_variant);
+}
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 13/19] drm/sun4i: hdmi: Add support for controller hardware variants
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (9 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 12/19] drm/sun4i: hdmi: Support the DDC clock in the A31's HDMI controller Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 19:38 ` Maxime Ripard
2017-06-02 10:10 ` [PATCH 14/19] drm/sun4i: hdmi: Add support for A31's HDMI controller Chen-Yu Tsai
` (5 subsequent siblings)
16 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The HDMI controller found in earlier Allwinner SoCs have slight
differences:
- Need different initial values for the PLL related registers
- Different behavior of the DDC and TMDS clocks
- Different register layout for the DDC portion
- Separate DDC parent clock on the A31
- Explicit reset control
The clock variants are supported within their implementations,
which only expose a create function for each variant.
The different layout of the DDC registers necessitates a separate
version of struct drm_connector_helper_funcs.
A new variant data structure is created to store pointers to the
above functions, structures, and the different initial values.
Another flag notates whether there is a separate DDC parent clock.
If not, the TMDS clock is passed to the DDC clock create function,
as before.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/clk/sunxi-ng/ccu-sun6i-a31.c | 2 +-
drivers/gpu/drm/sun4i/sun4i_hdmi.h | 8 +++
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 114 ++++++++++++++++++++++++++-------
3 files changed, 100 insertions(+), 24 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
index 4d6078fca9ac..e48186985a51 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
@@ -610,7 +610,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", lcd_ch1_parents,
static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(30), 0);
-static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0);
+static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x154, BIT(31), 0);
static const char * const mbus_parents[] = { "osc24M", "pll-periph",
"pll-ddr" };
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
index c39c2a245339..c63d0bd95963 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
@@ -155,6 +155,8 @@ enum sun4i_hdmi_pkt_type {
SUN4I_HDMI_PKT_END = 15,
};
+struct sun4i_hdmi_variant;
+
struct sun4i_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
@@ -162,9 +164,13 @@ struct sun4i_hdmi {
void __iomem *base;
+ /* Reset control */
+ struct reset_control *reset;
+
/* Parent clocks */
struct clk *bus_clk;
struct clk *mod_clk;
+ struct clk *ddc_parent_clk;
struct clk *pll0_clk;
struct clk *pll1_clk;
@@ -175,6 +181,8 @@ struct sun4i_hdmi {
struct sun4i_drv *drv;
bool hdmi_monitor;
+
+ const struct sun4i_hdmi_variant *variant;
};
int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *clk);
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 457614073501..9ded40aaed32 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -20,8 +20,10 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/iopoll.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include "sun4i_backend.h"
#include "sun4i_crtc.h"
@@ -315,6 +317,56 @@ static const struct drm_connector_funcs sun4i_hdmi_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
+struct sun4i_hdmi_variant {
+ const struct drm_connector_helper_funcs *connector_helpers;
+ int (*ddc_create)(struct sun4i_hdmi *hdmi, struct clk *clk);
+ int (*tmds_create)(struct sun4i_hdmi *hdmi);
+ bool has_ddc_parent_clk;
+ bool has_reset_control;
+
+ u32 pad_ctrl0_init_val;
+ u32 pad_ctrl1_init_val;
+ u32 pll_ctrl_init_val;
+};
+
+#define SUN4I_HDMI_PAD_CTRL1_MASK (GENMASK(24, 7) | GENMASK(5, 0))
+#define SUN4I_HDMI_PLL_CTRL_MASK (GENMASK(31, 8) | GENMASK(3, 0))
+
+static const struct sun4i_hdmi_variant sun5i_variant = {
+ .connector_helpers = &sun4i_hdmi_connector_helper_funcs,
+ .ddc_create = sun4i_ddc_create,
+ .tmds_create = sun4i_tmds_create,
+ .has_ddc_parent_clk = false,
+ .has_reset_control = false,
+ .pad_ctrl0_init_val = SUN4I_HDMI_PAD_CTRL0_TXEN |
+ SUN4I_HDMI_PAD_CTRL0_CKEN |
+ SUN4I_HDMI_PAD_CTRL0_PWENG |
+ SUN4I_HDMI_PAD_CTRL0_PWEND |
+ SUN4I_HDMI_PAD_CTRL0_PWENC |
+ SUN4I_HDMI_PAD_CTRL0_LDODEN |
+ SUN4I_HDMI_PAD_CTRL0_LDOCEN |
+ SUN4I_HDMI_PAD_CTRL0_BIASEN,
+ .pad_ctrl1_init_val = SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) |
+ SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) |
+ SUN4I_HDMI_PAD_CTRL1_REG_DENCK |
+ SUN4I_HDMI_PAD_CTRL1_REG_DEN |
+ SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT |
+ SUN4I_HDMI_PAD_CTRL1_EMP_OPT |
+ SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT |
+ SUN4I_HDMI_PAD_CTRL1_AMP_OPT,
+ .pll_ctrl_init_val = SUN4I_HDMI_PLL_CTRL_VCO_S(8) |
+ SUN4I_HDMI_PLL_CTRL_CS(7) |
+ SUN4I_HDMI_PLL_CTRL_CP_S(15) |
+ SUN4I_HDMI_PLL_CTRL_S(7) |
+ SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) |
+ SUN4I_HDMI_PLL_CTRL_SDIV2 |
+ SUN4I_HDMI_PLL_CTRL_LDO2_EN |
+ SUN4I_HDMI_PLL_CTRL_LDO1_EN |
+ SUN4I_HDMI_PLL_CTRL_HV_IS_33 |
+ SUN4I_HDMI_PLL_CTRL_BWS |
+ SUN4I_HDMI_PLL_CTRL_PLL_EN,
+};
+
static int sun4i_hdmi_bind(struct device *dev, struct device *master,
void *data)
{
@@ -333,6 +385,10 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
hdmi->dev = dev;
hdmi->drv = drv;
+ hdmi->variant = of_device_get_match_data(&pdev->dev);
+ if (!hdmi->variant)
+ return -EINVAL;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi->base = devm_ioremap_resource(dev, res);
if (IS_ERR(hdmi->base)) {
@@ -340,10 +396,25 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
return PTR_ERR(hdmi->base);
}
+ if (hdmi->variant->has_reset_control) {
+ hdmi->reset = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(hdmi->reset)) {
+ dev_err(dev, "Couldn't get the HDMI reset control\n");
+ return PTR_ERR(hdmi->reset);
+ }
+
+ ret = reset_control_deassert(hdmi->reset);
+ if (ret) {
+ dev_err(dev, "Couldn't deassert HDMI reset\n");
+ return ret;
+ }
+ }
+
hdmi->bus_clk = devm_clk_get(dev, "ahb");
if (IS_ERR(hdmi->bus_clk)) {
dev_err(dev, "Couldn't get the HDMI bus clock\n");
- return PTR_ERR(hdmi->bus_clk);
+ ret = PTR_ERR(hdmi->bus_clk);
+ goto err_assert_reset;
}
clk_prepare_enable(hdmi->bus_clk);
@@ -369,18 +440,25 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
goto err_disable_mod_clk;
}
- ret = sun4i_tmds_create(hdmi);
+ ret = hdmi->variant->tmds_create(hdmi);
if (ret) {
dev_err(dev, "Couldn't create the TMDS clock\n");
goto err_disable_mod_clk;
}
+ if (hdmi->variant->has_ddc_parent_clk) {
+ hdmi->ddc_parent_clk = devm_clk_get(dev, "ddc");
+ if (IS_ERR(hdmi->ddc_parent_clk)) {
+ dev_err(dev, "Couldn't get the HDMI DDC clock\n");
+ return PTR_ERR(hdmi->ddc_parent_clk);
+ }
+ } else {
+ hdmi->ddc_parent_clk = hdmi->tmds_clk;
+ }
+
writel(SUN4I_HDMI_CTRL_ENABLE, hdmi->base + SUN4I_HDMI_CTRL_REG);
- writel(SUN4I_HDMI_PAD_CTRL0_TXEN | SUN4I_HDMI_PAD_CTRL0_CKEN |
- SUN4I_HDMI_PAD_CTRL0_PWENG | SUN4I_HDMI_PAD_CTRL0_PWEND |
- SUN4I_HDMI_PAD_CTRL0_PWENC | SUN4I_HDMI_PAD_CTRL0_LDODEN |
- SUN4I_HDMI_PAD_CTRL0_LDOCEN | SUN4I_HDMI_PAD_CTRL0_BIASEN,
+ writel(hdmi->variant->pad_ctrl0_init_val,
hdmi->base + SUN4I_HDMI_PAD_CTRL0_REG);
/*
@@ -390,27 +468,15 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
*/
reg = readl(hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG);
reg &= SUN4I_HDMI_PAD_CTRL1_HALVE_CLK;
- reg |= SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) |
- SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) |
- SUN4I_HDMI_PAD_CTRL1_REG_DENCK |
- SUN4I_HDMI_PAD_CTRL1_REG_DEN |
- SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT |
- SUN4I_HDMI_PAD_CTRL1_EMP_OPT |
- SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT |
- SUN4I_HDMI_PAD_CTRL1_AMP_OPT;
+ reg |= hdmi->variant->pad_ctrl1_init_val;
writel(reg, hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG);
reg = readl(hdmi->base + SUN4I_HDMI_PLL_CTRL_REG);
reg &= SUN4I_HDMI_PLL_CTRL_DIV_MASK;
- reg |= SUN4I_HDMI_PLL_CTRL_VCO_S(8) | SUN4I_HDMI_PLL_CTRL_CS(7) |
- SUN4I_HDMI_PLL_CTRL_CP_S(15) | SUN4I_HDMI_PLL_CTRL_S(7) |
- SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) | SUN4I_HDMI_PLL_CTRL_SDIV2 |
- SUN4I_HDMI_PLL_CTRL_LDO2_EN | SUN4I_HDMI_PLL_CTRL_LDO1_EN |
- SUN4I_HDMI_PLL_CTRL_HV_IS_33 | SUN4I_HDMI_PLL_CTRL_BWS |
- SUN4I_HDMI_PLL_CTRL_PLL_EN;
+ reg |= hdmi->variant->pll_ctrl_init_val;
writel(reg, hdmi->base + SUN4I_HDMI_PLL_CTRL_REG);
- ret = sun4i_ddc_create(hdmi, hdmi->tmds_clk);
+ ret = hdmi->variant->ddc_create(hdmi, hdmi->ddc_parent_clk);
if (ret) {
dev_err(dev, "Couldn't create the DDC clock\n");
goto err_disable_mod_clk;
@@ -434,7 +500,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
goto err_disable_mod_clk;
drm_connector_helper_add(&hdmi->connector,
- &sun4i_hdmi_connector_helper_funcs);
+ hdmi->variant->connector_helpers);
ret = drm_connector_init(drm, &hdmi->connector,
&sun4i_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -458,6 +524,8 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
clk_disable_unprepare(hdmi->mod_clk);
err_disable_bus_clk:
clk_disable_unprepare(hdmi->bus_clk);
+err_assert_reset:
+ reset_control_assert(hdmi->reset);
return ret;
}
@@ -490,7 +558,7 @@ static int sun4i_hdmi_remove(struct platform_device *pdev)
}
static const struct of_device_id sun4i_hdmi_of_table[] = {
- { .compatible = "allwinner,sun5i-a10s-hdmi" },
+ { .compatible = "allwinner,sun5i-a10s-hdmi", .data = &sun5i_variant, },
{ }
};
MODULE_DEVICE_TABLE(of, sun4i_hdmi_of_table);
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 13/19] drm/sun4i: hdmi: Add support for controller hardware variants
2017-06-02 10:10 ` [PATCH 13/19] drm/sun4i: hdmi: Add support for controller hardware variants Chen-Yu Tsai
@ 2017-06-02 19:38 ` Maxime Ripard
[not found] ` <20170602193827.rnjum6x5ra4x5wef-ZC1Zs529Oq4@public.gmane.org>
0 siblings, 1 reply; 38+ messages in thread
From: Maxime Ripard @ 2017-06-02 19:38 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: David Airlie, Rob Herring, Michael Turquette, Stephen Boyd,
dri-devel, linux-arm-kernel, devicetree, linux-clk, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 4740 bytes --]
On Fri, Jun 02, 2017 at 06:10:18PM +0800, Chen-Yu Tsai wrote:
> The HDMI controller found in earlier Allwinner SoCs have slight
> differences:
>
> - Need different initial values for the PLL related registers
>
> - Different behavior of the DDC and TMDS clocks
>
> - Different register layout for the DDC portion
>
> - Separate DDC parent clock on the A31
>
> - Explicit reset control
>
> The clock variants are supported within their implementations,
> which only expose a create function for each variant.
>
> The different layout of the DDC registers necessitates a separate
> version of struct drm_connector_helper_funcs.
>
> A new variant data structure is created to store pointers to the
> above functions, structures, and the different initial values.
> Another flag notates whether there is a separate DDC parent clock.
> If not, the TMDS clock is passed to the DDC clock create function,
> as before.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> drivers/clk/sunxi-ng/ccu-sun6i-a31.c | 2 +-
> drivers/gpu/drm/sun4i/sun4i_hdmi.h | 8 +++
> drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 114 ++++++++++++++++++++++++++-------
> 3 files changed, 100 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
> index 4d6078fca9ac..e48186985a51 100644
> --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
> +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c
> @@ -610,7 +610,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", lcd_ch1_parents,
>
> static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(30), 0);
>
> -static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0);
> +static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x154, BIT(31), 0);
Unrelated change?
>
> static const char * const mbus_parents[] = { "osc24M", "pll-periph",
> "pll-ddr" };
> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> index c39c2a245339..c63d0bd95963 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> @@ -155,6 +155,8 @@ enum sun4i_hdmi_pkt_type {
> SUN4I_HDMI_PKT_END = 15,
> };
>
> +struct sun4i_hdmi_variant;
> +
> struct sun4i_hdmi {
> struct drm_connector connector;
> struct drm_encoder encoder;
> @@ -162,9 +164,13 @@ struct sun4i_hdmi {
>
> void __iomem *base;
>
> + /* Reset control */
> + struct reset_control *reset;
> +
> /* Parent clocks */
> struct clk *bus_clk;
> struct clk *mod_clk;
> + struct clk *ddc_parent_clk;
> struct clk *pll0_clk;
> struct clk *pll1_clk;
>
> @@ -175,6 +181,8 @@ struct sun4i_hdmi {
> struct sun4i_drv *drv;
>
> bool hdmi_monitor;
> +
> + const struct sun4i_hdmi_variant *variant;
> };
>
> int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *clk);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
> index 457614073501..9ded40aaed32 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
> @@ -20,8 +20,10 @@
> #include <linux/clk.h>
> #include <linux/component.h>
> #include <linux/iopoll.h>
> +#include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/pm_runtime.h>
> +#include <linux/reset.h>
>
> #include "sun4i_backend.h"
> #include "sun4i_crtc.h"
> @@ -315,6 +317,56 @@ static const struct drm_connector_funcs sun4i_hdmi_connector_funcs = {
> .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> };
>
> +struct sun4i_hdmi_variant {
> + const struct drm_connector_helper_funcs *connector_helpers;
> + int (*ddc_create)(struct sun4i_hdmi *hdmi, struct clk *clk);
> + int (*tmds_create)(struct sun4i_hdmi *hdmi);
> + bool has_ddc_parent_clk;
> + bool has_reset_control;
> +
> + u32 pad_ctrl0_init_val;
> + u32 pad_ctrl1_init_val;
> + u32 pll_ctrl_init_val;
> +};
> +
> +#define SUN4I_HDMI_PAD_CTRL1_MASK (GENMASK(24, 7) | GENMASK(5, 0))
> +#define SUN4I_HDMI_PLL_CTRL_MASK (GENMASK(31, 8) | GENMASK(3, 0))
> +
> +static const struct sun4i_hdmi_variant sun5i_variant = {
> + .connector_helpers = &sun4i_hdmi_connector_helper_funcs,
> + .ddc_create = sun4i_ddc_create,
> + .tmds_create = sun4i_tmds_create,
If we store the variants info for those clocks in that structure, we
don't need those functions anymore. This would be cleaner imho.
> + .has_ddc_parent_clk = false,
> + .has_reset_control = false,
Those two are the default values
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 14/19] drm/sun4i: hdmi: Add support for A31's HDMI controller
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (10 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 13/19] drm/sun4i: hdmi: Add support for controller hardware variants Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 19:41 ` Maxime Ripard
2017-06-02 10:10 ` [PATCH 15/19] clk: sunxi-ng: sun6i: Export video PLLs Chen-Yu Tsai
` (4 subsequent siblings)
16 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The HDMI controller found in the A31 SoCs is slightly different
from the one already supported, which is found in the A10s:
- Need different initial values for the PLL related registers
- Different behavior of the DDC and TMDS clocks
- Different register layout for the DDC portion
- Separate DDC parent clock
This patch adds support for it.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/gpu/drm/sun4i/sun4i_hdmi.h | 3 +
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 141 +++++++++++++++++++++++++++++++++
2 files changed, 144 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
index c63d0bd95963..2589bc92be59 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
@@ -56,10 +56,13 @@
#define SUN4I_HDMI_PAD_CTRL0_TXEN BIT(23)
#define SUN4I_HDMI_PAD_CTRL1_REG 0x204
+#define SUN4I_HDMI_PAD_CTRL1_UNKNOWN BIT(24) /* set on A31 */
#define SUN4I_HDMI_PAD_CTRL1_AMP_OPT BIT(23)
#define SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT BIT(22)
#define SUN4I_HDMI_PAD_CTRL1_EMP_OPT BIT(20)
#define SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT BIT(19)
+#define SUN4I_HDMI_PAD_CTRL1_PWSCK BIT(18)
+#define SUN4I_HDMI_PAD_CTRL1_PWSDT BIT(17)
#define SUN4I_HDMI_PAD_CTRL1_REG_DEN BIT(15)
#define SUN4I_HDMI_PAD_CTRL1_REG_DENCK BIT(14)
#define SUN4I_HDMI_PAD_CTRL1_REG_EMP(n) (((n) & 7) << 10)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 9ded40aaed32..e9abf93eb41c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -293,6 +293,109 @@ static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs
.get_modes = sun4i_hdmi_get_modes,
};
+static int sun6i_hdmi_read_sub_block(struct sun4i_hdmi *hdmi,
+ unsigned int blk, unsigned int offset,
+ u8 *buf, unsigned int count)
+{
+ unsigned long reg;
+ int i;
+
+ reg = readl(hdmi->base + SUN6I_HDMI_DDC_FIFO_CTRL_REG);
+ writel(reg | SUN6I_HDMI_DDC_FIFO_CTRL_CLEAR,
+ hdmi->base + SUN6I_HDMI_DDC_FIFO_CTRL_REG);
+ writel(SUN6I_HDMI_DDC_ADDR_SEGMENT(offset >> 8) |
+ SUN6I_HDMI_DDC_ADDR_EDDC(DDC_SEGMENT_ADDR << 1) |
+ SUN6I_HDMI_DDC_ADDR_OFFSET(offset) |
+ SUN6I_HDMI_DDC_ADDR_SLAVE(DDC_ADDR),
+ hdmi->base + SUN6I_HDMI_DDC_ADDR_REG);
+
+ writel(SUN6I_HDMI_DDC_CMD_EXPLICIT_EDDC_READ |
+ SUN6I_HDMI_DDC_CMD_BYTE_COUNT(count),
+ hdmi->base + SUN6I_HDMI_DDC_CMD_REG);
+
+ reg = readl(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
+ writel(reg | SUN6I_HDMI_DDC_CTRL_START_CMD,
+ hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
+
+ if (readl_poll_timeout(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG, reg,
+ !(reg & SUN6I_HDMI_DDC_CTRL_START_CMD),
+ 100, 100000))
+ return -EIO;
+
+ for (i = 0; i < count; i++)
+ buf[i] = readb(hdmi->base + SUN6I_HDMI_DDC_FIFO_DATA_REG);
+
+ return 0;
+}
+
+static int sun6i_hdmi_read_edid_block(void *data, u8 *buf, unsigned int blk,
+ size_t length)
+{
+ struct sun4i_hdmi *hdmi = data;
+ int retry = 2, i;
+
+ do {
+ for (i = 0; i < length; i += SUN4I_HDMI_DDC_FIFO_SIZE) {
+ unsigned char offset = blk * EDID_LENGTH + i;
+ unsigned int count = min((unsigned int)SUN4I_HDMI_DDC_FIFO_SIZE,
+ length - i);
+ int ret;
+
+ ret = sun6i_hdmi_read_sub_block(hdmi, blk, offset,
+ buf + i, count);
+ if (ret)
+ return ret;
+ }
+ } while (!drm_edid_block_valid(buf, blk, true, NULL) && (retry--));
+
+ return 0;
+}
+
+static int sun6i_hdmi_get_modes(struct drm_connector *connector)
+{
+ struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
+ u32 reg;
+ struct edid *edid;
+ int ret;
+
+ clk_set_rate(hdmi->ddc_clk, 100000);
+ clk_prepare_enable(hdmi->ddc_clk);
+
+ /* Reset i2c controller */
+ writel(SUN6I_HDMI_DDC_CTRL_ENABLE | SUN6I_HDMI_DDC_CTRL_RESET |
+ SUN6I_HDMI_DDC_CTRL_SDA_ENABLE |
+ SUN6I_HDMI_DDC_CTRL_SCL_ENABLE,
+ hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
+ if (readl_poll_timeout(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG, reg,
+ !(reg & SUN6I_HDMI_DDC_CTRL_RESET),
+ 100, 2000)) {
+ dev_err(hdmi->dev, "DDC reset timeout: %08x\n", reg);
+ clk_disable_unprepare(hdmi->ddc_clk);
+ return -EIO;
+ }
+
+ edid = drm_do_get_edid(connector, sun6i_hdmi_read_edid_block, hdmi);
+
+ clk_disable_unprepare(hdmi->ddc_clk);
+
+ if (!edid)
+ return 0;
+
+ hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+ DRM_DEBUG_DRIVER("Monitor is %s monitor\n",
+ hdmi->hdmi_monitor ? "an HDMI" : "a DVI");
+
+ drm_mode_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+
+ return ret;
+}
+
+static const struct drm_connector_helper_funcs sun6i_hdmi_connector_helper_funcs = {
+ .get_modes = sun6i_hdmi_get_modes,
+};
+
static enum drm_connector_status
sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
@@ -367,6 +470,43 @@ static const struct sun4i_hdmi_variant sun5i_variant = {
SUN4I_HDMI_PLL_CTRL_PLL_EN,
};
+static const struct sun4i_hdmi_variant sun6i_variant = {
+ .connector_helpers = &sun6i_hdmi_connector_helper_funcs,
+ .ddc_create = sun6i_ddc_create,
+ .tmds_create = sun6i_tmds_create,
+ .has_ddc_parent_clk = true,
+ .has_reset_control = true,
+ .pad_ctrl0_init_val = 0xff |
+ SUN4I_HDMI_PAD_CTRL0_TXEN |
+ SUN4I_HDMI_PAD_CTRL0_CKEN |
+ SUN4I_HDMI_PAD_CTRL0_PWENG |
+ SUN4I_HDMI_PAD_CTRL0_PWEND |
+ SUN4I_HDMI_PAD_CTRL0_PWENC |
+ SUN4I_HDMI_PAD_CTRL0_LDODEN |
+ SUN4I_HDMI_PAD_CTRL0_LDOCEN,
+ .pad_ctrl1_init_val = SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) |
+ SUN4I_HDMI_PAD_CTRL1_REG_EMP(4) |
+ SUN4I_HDMI_PAD_CTRL1_REG_DENCK |
+ SUN4I_HDMI_PAD_CTRL1_REG_DEN |
+ SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT |
+ SUN4I_HDMI_PAD_CTRL1_EMP_OPT |
+ SUN4I_HDMI_PAD_CTRL1_PWSDT |
+ SUN4I_HDMI_PAD_CTRL1_PWSCK |
+ SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT |
+ SUN4I_HDMI_PAD_CTRL1_AMP_OPT |
+ SUN4I_HDMI_PAD_CTRL1_UNKNOWN,
+ .pll_ctrl_init_val = SUN4I_HDMI_PLL_CTRL_VCO_S(8) |
+ SUN4I_HDMI_PLL_CTRL_CS(3) |
+ SUN4I_HDMI_PLL_CTRL_CP_S(10) |
+ SUN4I_HDMI_PLL_CTRL_S(4) |
+ SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) |
+ SUN4I_HDMI_PLL_CTRL_SDIV2 |
+ SUN4I_HDMI_PLL_CTRL_LDO2_EN |
+ SUN4I_HDMI_PLL_CTRL_LDO1_EN |
+ SUN4I_HDMI_PLL_CTRL_HV_IS_33 |
+ SUN4I_HDMI_PLL_CTRL_PLL_EN,
+};
+
static int sun4i_hdmi_bind(struct device *dev, struct device *master,
void *data)
{
@@ -559,6 +699,7 @@ static int sun4i_hdmi_remove(struct platform_device *pdev)
static const struct of_device_id sun4i_hdmi_of_table[] = {
{ .compatible = "allwinner,sun5i-a10s-hdmi", .data = &sun5i_variant, },
+ { .compatible = "allwinner,sun6i-a31-hdmi", .data = &sun6i_variant, },
{ }
};
MODULE_DEVICE_TABLE(of, sun4i_hdmi_of_table);
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 14/19] drm/sun4i: hdmi: Add support for A31's HDMI controller
2017-06-02 10:10 ` [PATCH 14/19] drm/sun4i: hdmi: Add support for A31's HDMI controller Chen-Yu Tsai
@ 2017-06-02 19:41 ` Maxime Ripard
2017-06-03 15:19 ` Chen-Yu Tsai
0 siblings, 1 reply; 38+ messages in thread
From: Maxime Ripard @ 2017-06-02 19:41 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: David Airlie, Rob Herring, Michael Turquette, Stephen Boyd,
dri-devel, linux-arm-kernel, devicetree, linux-clk, linux-sunxi
[-- Attachment #1: Type: text/plain, Size: 6107 bytes --]
On Fri, Jun 02, 2017 at 06:10:19PM +0800, Chen-Yu Tsai wrote:
> The HDMI controller found in the A31 SoCs is slightly different
> from the one already supported, which is found in the A10s:
>
> - Need different initial values for the PLL related registers
>
> - Different behavior of the DDC and TMDS clocks
>
> - Different register layout for the DDC portion
>
> - Separate DDC parent clock
>
> This patch adds support for it.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> drivers/gpu/drm/sun4i/sun4i_hdmi.h | 3 +
> drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 141 +++++++++++++++++++++++++++++++++
> 2 files changed, 144 insertions(+)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> index c63d0bd95963..2589bc92be59 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
> @@ -56,10 +56,13 @@
> #define SUN4I_HDMI_PAD_CTRL0_TXEN BIT(23)
>
> #define SUN4I_HDMI_PAD_CTRL1_REG 0x204
> +#define SUN4I_HDMI_PAD_CTRL1_UNKNOWN BIT(24) /* set on A31 */
> #define SUN4I_HDMI_PAD_CTRL1_AMP_OPT BIT(23)
> #define SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT BIT(22)
> #define SUN4I_HDMI_PAD_CTRL1_EMP_OPT BIT(20)
> #define SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT BIT(19)
> +#define SUN4I_HDMI_PAD_CTRL1_PWSCK BIT(18)
> +#define SUN4I_HDMI_PAD_CTRL1_PWSDT BIT(17)
> #define SUN4I_HDMI_PAD_CTRL1_REG_DEN BIT(15)
> #define SUN4I_HDMI_PAD_CTRL1_REG_DENCK BIT(14)
> #define SUN4I_HDMI_PAD_CTRL1_REG_EMP(n) (((n) & 7) << 10)
> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
> index 9ded40aaed32..e9abf93eb41c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
> @@ -293,6 +293,109 @@ static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs
> .get_modes = sun4i_hdmi_get_modes,
> };
>
> +static int sun6i_hdmi_read_sub_block(struct sun4i_hdmi *hdmi,
> + unsigned int blk, unsigned int offset,
> + u8 *buf, unsigned int count)
> +{
> + unsigned long reg;
> + int i;
> +
> + reg = readl(hdmi->base + SUN6I_HDMI_DDC_FIFO_CTRL_REG);
> + writel(reg | SUN6I_HDMI_DDC_FIFO_CTRL_CLEAR,
> + hdmi->base + SUN6I_HDMI_DDC_FIFO_CTRL_REG);
> + writel(SUN6I_HDMI_DDC_ADDR_SEGMENT(offset >> 8) |
> + SUN6I_HDMI_DDC_ADDR_EDDC(DDC_SEGMENT_ADDR << 1) |
> + SUN6I_HDMI_DDC_ADDR_OFFSET(offset) |
> + SUN6I_HDMI_DDC_ADDR_SLAVE(DDC_ADDR),
> + hdmi->base + SUN6I_HDMI_DDC_ADDR_REG);
> +
> + writel(SUN6I_HDMI_DDC_CMD_EXPLICIT_EDDC_READ |
> + SUN6I_HDMI_DDC_CMD_BYTE_COUNT(count),
> + hdmi->base + SUN6I_HDMI_DDC_CMD_REG);
> +
> + reg = readl(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
> + writel(reg | SUN6I_HDMI_DDC_CTRL_START_CMD,
> + hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
> +
> + if (readl_poll_timeout(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG, reg,
> + !(reg & SUN6I_HDMI_DDC_CTRL_START_CMD),
> + 100, 100000))
> + return -EIO;
> +
> + for (i = 0; i < count; i++)
> + buf[i] = readb(hdmi->base + SUN6I_HDMI_DDC_FIFO_DATA_REG);
> +
> + return 0;
> +}
> +
> +static int sun6i_hdmi_read_edid_block(void *data, u8 *buf, unsigned int blk,
> + size_t length)
> +{
> + struct sun4i_hdmi *hdmi = data;
> + int retry = 2, i;
> +
> + do {
> + for (i = 0; i < length; i += SUN4I_HDMI_DDC_FIFO_SIZE) {
> + unsigned char offset = blk * EDID_LENGTH + i;
> + unsigned int count = min((unsigned int)SUN4I_HDMI_DDC_FIFO_SIZE,
> + length - i);
> + int ret;
> +
> + ret = sun6i_hdmi_read_sub_block(hdmi, blk, offset,
> + buf + i, count);
> + if (ret)
> + return ret;
> + }
> + } while (!drm_edid_block_valid(buf, blk, true, NULL) && (retry--));
> +
> + return 0;
> +}
> +
> +static int sun6i_hdmi_get_modes(struct drm_connector *connector)
> +{
> + struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
> + u32 reg;
> + struct edid *edid;
> + int ret;
> +
> + clk_set_rate(hdmi->ddc_clk, 100000);
> + clk_prepare_enable(hdmi->ddc_clk);
> +
> + /* Reset i2c controller */
> + writel(SUN6I_HDMI_DDC_CTRL_ENABLE | SUN6I_HDMI_DDC_CTRL_RESET |
> + SUN6I_HDMI_DDC_CTRL_SDA_ENABLE |
> + SUN6I_HDMI_DDC_CTRL_SCL_ENABLE,
> + hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
> + if (readl_poll_timeout(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG, reg,
> + !(reg & SUN6I_HDMI_DDC_CTRL_RESET),
> + 100, 2000)) {
> + dev_err(hdmi->dev, "DDC reset timeout: %08x\n", reg);
> + clk_disable_unprepare(hdmi->ddc_clk);
> + return -EIO;
> + }
> +
> + edid = drm_do_get_edid(connector, sun6i_hdmi_read_edid_block, hdmi);
> +
> + clk_disable_unprepare(hdmi->ddc_clk);
> +
> + if (!edid)
> + return 0;
> +
> + hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid);
> + DRM_DEBUG_DRIVER("Monitor is %s monitor\n",
> + hdmi->hdmi_monitor ? "an HDMI" : "a DVI");
> +
> + drm_mode_connector_update_edid_property(connector, edid);
> + ret = drm_add_edid_modes(connector, edid);
> + kfree(edid);
> +
> + return ret;
> +}
> +
> +static const struct drm_connector_helper_funcs sun6i_hdmi_connector_helper_funcs = {
> + .get_modes = sun6i_hdmi_get_modes,
> +};
> +
Every thing here can be handled through regfield without having to
duplicate the logic.
> static enum drm_connector_status
> sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force)
> {
> @@ -367,6 +470,43 @@ static const struct sun4i_hdmi_variant sun5i_variant = {
> SUN4I_HDMI_PLL_CTRL_PLL_EN,
> };
>
> +static const struct sun4i_hdmi_variant sun6i_variant = {
> + .connector_helpers = &sun6i_hdmi_connector_helper_funcs,
> + .ddc_create = sun6i_ddc_create,
> + .tmds_create = sun6i_tmds_create,
> + .has_ddc_parent_clk = true,
> + .has_reset_control = true,
> + .pad_ctrl0_init_val = 0xff |
What is this 0xff for?
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 14/19] drm/sun4i: hdmi: Add support for A31's HDMI controller
2017-06-02 19:41 ` Maxime Ripard
@ 2017-06-03 15:19 ` Chen-Yu Tsai
[not found] ` <CAGb2v65eFAmAybmHkQcKjF+ZKxh+_G6q9i2GPzMs5854X8bQug-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-03 15:19 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd, dri-devel, linux-arm-kernel, devicetree, linux-clk,
linux-sunxi
On Sat, Jun 3, 2017 at 3:41 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Fri, Jun 02, 2017 at 06:10:19PM +0800, Chen-Yu Tsai wrote:
>> The HDMI controller found in the A31 SoCs is slightly different
>> from the one already supported, which is found in the A10s:
>>
>> - Need different initial values for the PLL related registers
>>
>> - Different behavior of the DDC and TMDS clocks
>>
>> - Different register layout for the DDC portion
>>
>> - Separate DDC parent clock
>>
>> This patch adds support for it.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> drivers/gpu/drm/sun4i/sun4i_hdmi.h | 3 +
>> drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 141 +++++++++++++++++++++++++++++++++
>> 2 files changed, 144 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
>> index c63d0bd95963..2589bc92be59 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
>> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
>> @@ -56,10 +56,13 @@
>> #define SUN4I_HDMI_PAD_CTRL0_TXEN BIT(23)
>>
>> #define SUN4I_HDMI_PAD_CTRL1_REG 0x204
>> +#define SUN4I_HDMI_PAD_CTRL1_UNKNOWN BIT(24) /* set on A31 */
>> #define SUN4I_HDMI_PAD_CTRL1_AMP_OPT BIT(23)
>> #define SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT BIT(22)
>> #define SUN4I_HDMI_PAD_CTRL1_EMP_OPT BIT(20)
>> #define SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT BIT(19)
>> +#define SUN4I_HDMI_PAD_CTRL1_PWSCK BIT(18)
>> +#define SUN4I_HDMI_PAD_CTRL1_PWSDT BIT(17)
>> #define SUN4I_HDMI_PAD_CTRL1_REG_DEN BIT(15)
>> #define SUN4I_HDMI_PAD_CTRL1_REG_DENCK BIT(14)
>> #define SUN4I_HDMI_PAD_CTRL1_REG_EMP(n) (((n) & 7) << 10)
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
>> index 9ded40aaed32..e9abf93eb41c 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
>> @@ -293,6 +293,109 @@ static const struct drm_connector_helper_funcs sun4i_hdmi_connector_helper_funcs
>> .get_modes = sun4i_hdmi_get_modes,
>> };
>>
>> +static int sun6i_hdmi_read_sub_block(struct sun4i_hdmi *hdmi,
>> + unsigned int blk, unsigned int offset,
>> + u8 *buf, unsigned int count)
>> +{
>> + unsigned long reg;
>> + int i;
>> +
>> + reg = readl(hdmi->base + SUN6I_HDMI_DDC_FIFO_CTRL_REG);
>> + writel(reg | SUN6I_HDMI_DDC_FIFO_CTRL_CLEAR,
>> + hdmi->base + SUN6I_HDMI_DDC_FIFO_CTRL_REG);
>> + writel(SUN6I_HDMI_DDC_ADDR_SEGMENT(offset >> 8) |
>> + SUN6I_HDMI_DDC_ADDR_EDDC(DDC_SEGMENT_ADDR << 1) |
>> + SUN6I_HDMI_DDC_ADDR_OFFSET(offset) |
>> + SUN6I_HDMI_DDC_ADDR_SLAVE(DDC_ADDR),
>> + hdmi->base + SUN6I_HDMI_DDC_ADDR_REG);
>> +
>> + writel(SUN6I_HDMI_DDC_CMD_EXPLICIT_EDDC_READ |
>> + SUN6I_HDMI_DDC_CMD_BYTE_COUNT(count),
>> + hdmi->base + SUN6I_HDMI_DDC_CMD_REG);
>> +
>> + reg = readl(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
>> + writel(reg | SUN6I_HDMI_DDC_CTRL_START_CMD,
>> + hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
>> +
>> + if (readl_poll_timeout(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG, reg,
>> + !(reg & SUN6I_HDMI_DDC_CTRL_START_CMD),
>> + 100, 100000))
>> + return -EIO;
>> +
>> + for (i = 0; i < count; i++)
>> + buf[i] = readb(hdmi->base + SUN6I_HDMI_DDC_FIFO_DATA_REG);
>> +
>> + return 0;
>> +}
>> +
>> +static int sun6i_hdmi_read_edid_block(void *data, u8 *buf, unsigned int blk,
>> + size_t length)
>> +{
>> + struct sun4i_hdmi *hdmi = data;
>> + int retry = 2, i;
>> +
>> + do {
>> + for (i = 0; i < length; i += SUN4I_HDMI_DDC_FIFO_SIZE) {
>> + unsigned char offset = blk * EDID_LENGTH + i;
>> + unsigned int count = min((unsigned int)SUN4I_HDMI_DDC_FIFO_SIZE,
>> + length - i);
>> + int ret;
>> +
>> + ret = sun6i_hdmi_read_sub_block(hdmi, blk, offset,
>> + buf + i, count);
>> + if (ret)
>> + return ret;
>> + }
>> + } while (!drm_edid_block_valid(buf, blk, true, NULL) && (retry--));
>> +
>> + return 0;
>> +}
>> +
>> +static int sun6i_hdmi_get_modes(struct drm_connector *connector)
>> +{
>> + struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
>> + u32 reg;
>> + struct edid *edid;
>> + int ret;
>> +
>> + clk_set_rate(hdmi->ddc_clk, 100000);
>> + clk_prepare_enable(hdmi->ddc_clk);
>> +
>> + /* Reset i2c controller */
>> + writel(SUN6I_HDMI_DDC_CTRL_ENABLE | SUN6I_HDMI_DDC_CTRL_RESET |
>> + SUN6I_HDMI_DDC_CTRL_SDA_ENABLE |
>> + SUN6I_HDMI_DDC_CTRL_SCL_ENABLE,
>> + hdmi->base + SUN6I_HDMI_DDC_CTRL_REG);
>> + if (readl_poll_timeout(hdmi->base + SUN6I_HDMI_DDC_CTRL_REG, reg,
>> + !(reg & SUN6I_HDMI_DDC_CTRL_RESET),
>> + 100, 2000)) {
>> + dev_err(hdmi->dev, "DDC reset timeout: %08x\n", reg);
>> + clk_disable_unprepare(hdmi->ddc_clk);
>> + return -EIO;
>> + }
>> +
>> + edid = drm_do_get_edid(connector, sun6i_hdmi_read_edid_block, hdmi);
>> +
>> + clk_disable_unprepare(hdmi->ddc_clk);
>> +
>> + if (!edid)
>> + return 0;
>> +
>> + hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid);
>> + DRM_DEBUG_DRIVER("Monitor is %s monitor\n",
>> + hdmi->hdmi_monitor ? "an HDMI" : "a DVI");
>> +
>> + drm_mode_connector_update_edid_property(connector, edid);
>> + ret = drm_add_edid_modes(connector, edid);
>> + kfree(edid);
>> +
>> + return ret;
>> +}
>> +
>> +static const struct drm_connector_helper_funcs sun6i_hdmi_connector_helper_funcs = {
>> + .get_modes = sun6i_hdmi_get_modes,
>> +};
>> +
>
> Every thing here can be handled through regfield without having to
> duplicate the logic.
Hmm... You're right. Does that mean we should convert the entire driver to
using regmap? Or just the DDC bits here, since they won't conflict with
any other access patterns in the whole HDMI driver?
>
>> static enum drm_connector_status
>> sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force)
>> {
>> @@ -367,6 +470,43 @@ static const struct sun4i_hdmi_variant sun5i_variant = {
>> SUN4I_HDMI_PLL_CTRL_PLL_EN,
>> };
>>
>> +static const struct sun4i_hdmi_variant sun6i_variant = {
>> + .connector_helpers = &sun6i_hdmi_connector_helper_funcs,
>> + .ddc_create = sun6i_ddc_create,
>> + .tmds_create = sun6i_tmds_create,
>> + .has_ddc_parent_clk = true,
>> + .has_reset_control = true,
>> + .pad_ctrl0_init_val = 0xff |
>
> What is this 0xff for?
Unknown. It is set in the mainline U-boot driver.
Looking at an old 3.3 kernel from the BSP, it seems the higher 4 bits
control the transmitter. But the lower 4 bits are still unknown.
ChenYu
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 15/19] clk: sunxi-ng: sun6i: Export video PLLs
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (11 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 14/19] drm/sun4i: hdmi: Add support for A31's HDMI controller Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 16/19] ARM: sun6i: a31: Add device node for HDMI controller Chen-Yu Tsai
` (3 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The 2x outputs of the 2 video PLL clocks are directly used by the
HDMI controller block.
Export them so they can be referenced in the device tree.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/clk/sunxi-ng/ccu-sun6i-a31.h | 8 ++++++--
include/dt-bindings/clock/sun6i-a31-ccu.h | 4 ++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.h b/drivers/clk/sunxi-ng/ccu-sun6i-a31.h
index 4e434011e9e7..27e6ad4133ab 100644
--- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.h
+++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.h
@@ -27,7 +27,9 @@
#define CLK_PLL_AUDIO_4X 4
#define CLK_PLL_AUDIO_8X 5
#define CLK_PLL_VIDEO0 6
-#define CLK_PLL_VIDEO0_2X 7
+
+/* The PLL_VIDEO0_2X clock is exported */
+
#define CLK_PLL_VE 8
#define CLK_PLL_DDR 9
@@ -35,7 +37,9 @@
#define CLK_PLL_PERIPH_2X 11
#define CLK_PLL_VIDEO1 12
-#define CLK_PLL_VIDEO1_2X 13
+
+/* The PLL_VIDEO1_2X clock is exported */
+
#define CLK_PLL_GPU 14
#define CLK_PLL_MIPI 15
#define CLK_PLL9 16
diff --git a/include/dt-bindings/clock/sun6i-a31-ccu.h b/include/dt-bindings/clock/sun6i-a31-ccu.h
index 4482530fb6f5..c5d13340184a 100644
--- a/include/dt-bindings/clock/sun6i-a31-ccu.h
+++ b/include/dt-bindings/clock/sun6i-a31-ccu.h
@@ -43,8 +43,12 @@
#ifndef _DT_BINDINGS_CLK_SUN6I_A31_H_
#define _DT_BINDINGS_CLK_SUN6I_A31_H_
+#define CLK_PLL_VIDEO0_2X 7
+
#define CLK_PLL_PERIPH 10
+#define CLK_PLL_VIDEO1_2X 13
+
#define CLK_CPU 18
#define CLK_AHB1_MIPIDSI 23
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 16/19] ARM: sun6i: a31: Add device node for HDMI controller
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (12 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 15/19] clk: sunxi-ng: sun6i: Export video PLLs Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 17/19] ARM: sun6i: a31: Enable HDMI support on the A31 Hummingbird Chen-Yu Tsai
` (2 subsequent siblings)
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
Now that we support the HDMI controller on the A31 SoC, we can add it
to the device tree.
This adds a device node for the HDMI controller, and the of_graph nodes
connecting it to the 2 TCONs.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
arch/arm/boot/dts/sun6i-a31.dtsi | 55 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index d0cede5aaeb5..36bfb6ad6578 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -284,6 +284,12 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
+
+ tcon0_out_hdmi: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&hdmi_in_tcon0>;
+ allwinner,tcon-channel = <1>;
+ };
};
};
};
@@ -321,6 +327,12 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
+
+ tcon1_out_hdmi: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&hdmi_in_tcon1>;
+ allwinner,tcon-channel = <1>;
+ };
};
};
};
@@ -401,6 +413,49 @@
#size-cells = <0>;
};
+ hdmi: hdmi@01c16000 {
+ compatible = "allwinner,sun6i-a31-hdmi";
+ reg = <0x01c16000 0x1000>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_AHB1_HDMI>, <&ccu CLK_HDMI>,
+ <&ccu CLK_HDMI_DDC>,
+ <&ccu CLK_PLL_VIDEO0_2X>,
+ <&ccu CLK_PLL_VIDEO1_2X>;
+ clock-names = "ahb", "mod", "ddc", "pll-0", "pll-1";
+ resets = <&ccu RST_AHB1_HDMI>;
+ reset-names = "ahb";
+ dma-names = "ddc-tx", "ddc-rx", "audio-tx";
+ dmas = <&dma 13>, <&dma 13>, <&dma 14>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ hdmi_in_tcon0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_out_hdmi>;
+ };
+
+ hdmi_in_tcon1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&tcon1_out_hdmi>;
+ };
+ };
+
+ hdmi_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+ };
+ };
+
usb_otg: usb@01c19000 {
compatible = "allwinner,sun6i-a31-musb";
reg = <0x01c19000 0x0400>;
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 17/19] ARM: sun6i: a31: Enable HDMI support on the A31 Hummingbird
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (13 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 16/19] ARM: sun6i: a31: Add device node for HDMI controller Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 18/19] ARM: sun6i: a31s: Enable HDMI display output on the Sinlinx SinA31s Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 19/19] ARM: sun6i: a31s: Enable HDMI display output on the MSI Primo81 tablet Chen-Yu Tsai
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The A31 Humminbird has an HDMI connector wired to the HDMI pins
on the SoC. Enable HDMI support for this board.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
arch/arm/boot/dts/sun6i-a31-hummingbird.dts | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 9ecb5f0b3f83..19e382a11297 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -62,6 +62,17 @@
stdout-path = "serial0:115200n8";
};
+ hdmi-connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
vga-connector {
compatible = "vga-connector";
@@ -162,6 +173,16 @@
};
};
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 18/19] ARM: sun6i: a31s: Enable HDMI display output on the Sinlinx SinA31s
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (14 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 17/19] ARM: sun6i: a31: Enable HDMI support on the A31 Hummingbird Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
2017-06-02 10:10 ` [PATCH 19/19] ARM: sun6i: a31s: Enable HDMI display output on the MSI Primo81 tablet Chen-Yu Tsai
16 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The Sinlinx SinA31s has an HDMI connector wired to the HDMI pins
from the SoC.
Enable the display pipeline and the HDMI output.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
arch/arm/boot/dts/sun6i-a31s-sina31s.dts | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
index b3d98222bd81..298476485bb4 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
@@ -53,6 +53,17 @@
stdout-path = "serial0:115200n8";
};
+ hdmi-connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
@@ -90,6 +101,10 @@
status = "okay";
};
+&de {
+ status = "okay";
+};
+
&ehci0 {
/* USB 2.0 4 port hub IC */
status = "okay";
@@ -112,6 +127,16 @@
};
};
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 19/19] ARM: sun6i: a31s: Enable HDMI display output on the MSI Primo81 tablet
[not found] ` <20170602101024.18940-1-wens-jdAy2FN1RRM@public.gmane.org>
` (15 preceding siblings ...)
2017-06-02 10:10 ` [PATCH 18/19] ARM: sun6i: a31s: Enable HDMI display output on the Sinlinx SinA31s Chen-Yu Tsai
@ 2017-06-02 10:10 ` Chen-Yu Tsai
[not found] ` <20170602101024.18940-20-wens-jdAy2FN1RRM@public.gmane.org>
16 siblings, 1 reply; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-06-02 10:10 UTC (permalink / raw)
To: Maxime Ripard, David Airlie, Rob Herring, Michael Turquette,
Stephen Boyd
Cc: Chen-Yu Tsai, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
The MSI Primo81 tablet has a micro HDMI connector at the bottom.
This is connected to the SoCs HDMI output.
Enable the display pipeline and the HDMI output.
Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
arch/arm/boot/dts/sun6i-a31s-primo81.dts | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
index f3712753fa42..26154b2f87a3 100644
--- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
@@ -52,17 +52,42 @@
/ {
model = "MSI Primo81 tablet";
compatible = "msi,primo81", "allwinner,sun6i-a31s";
+
+ hdmi-connector {
+ compatible = "hdmi-connector";
+ type = "c";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
};
&cpu0 {
cpu-supply = <®_dcdc3>;
};
+&de {
+ status = "okay";
+};
+
&ehci0 {
/* rtl8188etv wifi is connected here */
status = "okay";
};
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&i2c0 {
/* pull-ups and device VDDIO use AXP221 DLDO3 */
pinctrl-names = "default";
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread