Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1686553 > unrolled thread
| Started by | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| First post | 2017-07-13 16:20 +0200 |
| Last post | 2017-07-20 15:10 +0200 |
| Articles | 20 on this page of 41 — 5 participants |
Back to article view | Back to linux.kernel
[PATCH 00/18] drm/sun4i: Allwinner MIPI-DSI support Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
[PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:50 +0200
Re: [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-20 15:30 +0200
[PATCH 04/18] drm/sun4i: Remove useless atomic_check Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:20 +0200
Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 10:50 +0200
[PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver Andrzej Hajda <a.hajda@samsung.com> - 2017-07-14 11:30 +0200
[PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:00 +0200
[PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:00 +0200
Re: [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-20 15:40 +0200
[PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup kbuild test robot <lkp@intel.com> - 2017-07-14 12:00 +0200
Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup Chen-Yu Tsai <wens@csie.org> - 2017-07-18 05:50 +0200
Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-20 16:00 +0200
[PATCH 16/18] arm: dts: sun8i: a33: Add the DSI-related nodes Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
[PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:20 +0200
Re: [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-20 17:00 +0200
Re: [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range Chen-Yu Tsai <wens@csie.org> - 2017-07-20 17:20 +0200
[PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:50 +0200
Re: [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 11:10 +0200
[PATCH 13/18] dt-bindings: vendor: Add Huarui Lighting Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 13/18] dt-bindings: vendor: Add Huarui Lighting Chen-Yu Tsai <wens@csie.org> - 2017-07-14 10:00 +0200
Re: [PATCH 13/18] dt-bindings: vendor: Add Huarui Lighting Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-20 15:40 +0200
[PATCH 01/18] regmap: mmio: Add function to attach a clock Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 01/18] regmap: mmio: Add function to attach a clock Mark Brown <broonie@kernel.org> - 2017-07-13 18:10 +0200
Re: [PATCH 01/18] regmap: mmio: Add function to attach a clock Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 11:10 +0200
Re: [PATCH 01/18] regmap: mmio: Add function to attach a clock Mark Brown <broonie@kernel.org> - 2017-07-18 15:30 +0200
Re: [PATCH 01/18] regmap: mmio: Add function to attach a clock Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-20 16:50 +0200
[PATCH 02/18] drm/sun4i: Add if statement instead of depends on Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 02/18] drm/sun4i: Add if statement instead of depends on Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:10 +0200
Re: [PATCH 02/18] drm/sun4i: Add if statement instead of depends on Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 10:50 +0200
[PATCH 18/18] [DO NOT MERGE] arm: dts: sun8i: bpi-m2m: Add DSI display Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
[PATCH 03/18] drm/sun4i: Realign Makefile padding and reorder it Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
Re: [PATCH 03/18] drm/sun4i: Realign Makefile padding and reorder it Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:20 +0200
Re: [PATCH 03/18] drm/sun4i: Realign Makefile padding and reorder it Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-20 15:10 +0200
Page 1 of 3 [1] 2 3 Next page →
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 00/18] drm/sun4i: Allwinner MIPI-DSI support |
| Message-ID | <u2N8d-6Ff-3@gated-at.bofh.it> |
Hi, Here is an preliminary version of the MIPI-DSI support for the Allwinner SoCs. This controller can be found on a number of recent SoCs, such as the A31, A33 or the A64. Given the sparse documentation, there's a number of obscure areas, but the current implementation has been tested with a 4-lanes DSI panel on an A33. In order to support properly the DSI controller, we also had to rework a bit the TCON code to ease the encoders support. The support is a bit rough around the edges at the time, and some artifacts are still shown on the screen for some reasons. Wider testing with different display will hopefully nail those down. It depends for the moment on the clock protection serie sent by Jerome Brunet: http://lists.infradead.org/pipermail/linux-amlogic/2017-June/004059.html Let me know what you think, Maxime Maxime Ripard (18): regmap: mmio: Add function to attach a clock drm/sun4i: Add if statement instead of depends on drm/sun4i: Realign Makefile padding and reorder it drm/sun4i: Remove useless atomic_check drm/sun4i: tcon: remove unused function drm/sun4i: tcon: Don't rely on encoders to enable the TCON drm/sun4i: tcon: Don't rely on encoders to set the TCON mode drm/sun4i: tcon: Add TRI finish interrupt for vblank drm/sun4i: tcon: Adjust dotclock dividers range drm/sun4i: tcon: Move out the tcon0 common setup dt-bindings: display: Add Allwinner MIPI-DSI bindings drm/sun4i: Add Allwinner A31 MIPI-DSI controller support dt-bindings: vendor: Add Huarui Lighting dt-bindings: panel: Add Huarui LHR050H41 panel documentation drm/panel: Add Huarui LHR050H41 panel driver arm: dts: sun8i: a33: Add the DSI-related nodes arm: dts: sun8i: Add BananaPI M2-Magic DTS [DO NOT MERGE] arm: dts: sun8i: bpi-m2m: Add DSI display Documentation/devicetree/bindings/display/panel/huarui,lhr050h41.txt | 19 +- Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt | 85 ++++++- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +- arch/arm/boot/dts/Makefile | 1 +- arch/arm/boot/dts/sun8i-a33.dtsi | 50 ++- arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts | 360 ++++++++++++++++++++++++- drivers/base/regmap/regmap-mmio.c | 24 ++- drivers/gpu/drm/panel/Kconfig | 9 +- drivers/gpu/drm/panel/Makefile | 1 +- drivers/gpu/drm/panel/panel-huarui-lhr050h41.c | 444 +++++++++++++++++++++++++++++- drivers/gpu/drm/sun4i/Kconfig | 17 +- drivers/gpu/drm/sun4i/Makefile | 31 +- drivers/gpu/drm/sun4i/sun4i_crtc.c | 33 +- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 20 +- drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 1 +- drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 15 +- drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c | 1 +- drivers/gpu/drm/sun4i/sun4i_layer.c | 7 +- drivers/gpu/drm/sun4i/sun4i_rgb.c | 37 +-- drivers/gpu/drm/sun4i/sun4i_tcon.c | 275 ++++++++++++------ drivers/gpu/drm/sun4i/sun4i_tcon.h | 68 ++-- drivers/gpu/drm/sun4i/sun4i_tv.c | 20 +- drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c | 297 +++++++++++++++++++- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 1098 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 67 ++++- include/linux/regmap.h | 4 +- 26 files changed, 2783 insertions(+), 202 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/huarui,lhr050h41.txt create mode 100644 Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt create mode 100644 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts create mode 100644 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c create mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c create mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c create mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h base-commit: d3d855e7c4ffaaa6c2cb221849da65e979d8aa80 -- git-series 0.9.1
[toc] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON |
| Message-ID | <u2N8e-6Ff-9@gated-at.bofh.it> |
| In reply to | #1686553 |
So far, we've required all the TCON-connected encoders to call the TCON
enable and disable functions.
This was made this way because in the RGB/LVDS case, the TCON is the CRTC
and the encoder. However, in all the other cases (HDMI, TV, DSI, etc.), we
have another encoder down the road that needs to be programmed.
We also needed to know which channel the encoder is connected to, which is
encoder-specific.
The CRTC's enable and disable callbacks can work just fine for our use
case, and we can get the channel to use just by looking at the type of
encoder, since that is fixed. Implement those callbacks, which will
remove some of the encoder boilerplate.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_crtc.c | 22 ++++++-
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 8 +--
drivers/gpu/drm/sun4i/sun4i_rgb.c | 14 +---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 91 +++++++++++++--------------
drivers/gpu/drm/sun4i/sun4i_tcon.h | 10 +---
drivers/gpu/drm/sun4i/sun4i_tv.c | 6 +--
6 files changed, 70 insertions(+), 81 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index f8c70439d1e2..30c7568dde5c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -30,6 +30,22 @@
#include "sunxi_engine.h"
#include "sun4i_tcon.h"
+/*
+ * While this isn't really working in the DRM theory, in practice we
+ * can only ever have one encoder per TCON since we have a mux in our
+ * TCON.
+ */
+static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
+{
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder(encoder, crtc->dev)
+ if (encoder->crtc == crtc)
+ return encoder;
+
+ return NULL;
+}
+
static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -71,11 +87,12 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
static void sun4i_crtc_disable(struct drm_crtc *crtc)
{
+ struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
DRM_DEBUG_DRIVER("Disabling the CRTC\n");
- sun4i_tcon_disable(scrtc->tcon);
+ sun4i_tcon_set_status(scrtc->tcon, encoder, false);
if (crtc->state->event && !crtc->state->active) {
spin_lock_irq(&crtc->dev->event_lock);
@@ -88,11 +105,12 @@ static void sun4i_crtc_disable(struct drm_crtc *crtc)
static void sun4i_crtc_enable(struct drm_crtc *crtc)
{
+ struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
DRM_DEBUG_DRIVER("Enabling the CRTC\n");
- sun4i_tcon_enable(scrtc->tcon);
+ sun4i_tcon_set_status(scrtc->tcon, encoder, true);
}
static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index d3398f6250ef..06af2f6d0b31 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -85,8 +85,6 @@ static int sun4i_hdmi_atomic_check(struct drm_encoder *encoder,
static void sun4i_hdmi_disable(struct drm_encoder *encoder)
{
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
- struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
- struct sun4i_tcon *tcon = crtc->tcon;
u32 val;
DRM_DEBUG_DRIVER("Disabling the HDMI Output\n");
@@ -94,22 +92,16 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder)
val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
val &= ~SUN4I_HDMI_VID_CTRL_ENABLE;
writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
-
- sun4i_tcon_channel_disable(tcon, 1);
}
static void sun4i_hdmi_enable(struct drm_encoder *encoder)
{
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
- struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
- struct sun4i_tcon *tcon = crtc->tcon;
u32 val = 0;
DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
- sun4i_tcon_channel_enable(tcon, 1);
-
sun4i_hdmi_setup_avi_infoframes(hdmi, mode);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index 76362c09c608..ecce1f5b50ab 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -135,13 +135,10 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Enabling RGB output\n");
- if (!IS_ERR(tcon->panel))
+ if (!IS_ERR(tcon->panel)) {
drm_panel_prepare(tcon->panel);
-
- sun4i_tcon_channel_enable(tcon, 0);
-
- if (!IS_ERR(tcon->panel))
drm_panel_enable(tcon->panel);
+ }
}
static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
@@ -151,13 +148,10 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Disabling RGB output\n");
- if (!IS_ERR(tcon->panel))
+ if (!IS_ERR(tcon->panel)) {
drm_panel_disable(tcon->panel);
-
- sun4i_tcon_channel_disable(tcon, 0);
-
- if (!IS_ERR(tcon->panel))
drm_panel_unprepare(tcon->panel);
+ }
}
static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index d9791292553e..dc70bc2a42a5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -14,6 +14,7 @@
#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>
@@ -32,66 +33,62 @@
#include "sun4i_tcon.h"
#include "sunxi_engine.h"
-void sun4i_tcon_disable(struct sun4i_tcon *tcon)
+static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
+ bool enabled)
{
- DRM_DEBUG_DRIVER("Disabling TCON\n");
+ struct clk *clk;
- /* Disable the TCON */
- regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
- SUN4I_TCON_GCTL_TCON_ENABLE, 0);
-}
-EXPORT_SYMBOL(sun4i_tcon_disable);
-
-void sun4i_tcon_enable(struct sun4i_tcon *tcon)
-{
- DRM_DEBUG_DRIVER("Enabling TCON\n");
-
- /* Enable the TCON */
- regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
- SUN4I_TCON_GCTL_TCON_ENABLE,
- SUN4I_TCON_GCTL_TCON_ENABLE);
-}
-EXPORT_SYMBOL(sun4i_tcon_enable);
-
-void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
-{
- DRM_DEBUG_DRIVER("Disabling TCON channel %d\n", channel);
-
- /* Disable the TCON's channel */
- if (channel == 0) {
+ switch (channel) {
+ case 0:
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
- SUN4I_TCON0_CTL_TCON_ENABLE, 0);
- clk_disable_unprepare(tcon->dclk);
+ SUN4I_TCON0_CTL_TCON_ENABLE,
+ enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
+ clk = tcon->dclk;
+ break;
+ case 1:
+ WARN_ON(!tcon->quirks->has_channel_1);
+ regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+ SUN4I_TCON1_CTL_TCON_ENABLE,
+ enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
+ clk = tcon->sclk1;
+ break;
+ default:
+ DRM_DEBUG_DRIVER("Unknown channel... doing nothing\n");
return;
}
- WARN_ON(!tcon->quirks->has_channel_1);
- regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
- SUN4I_TCON1_CTL_TCON_ENABLE, 0);
- clk_disable_unprepare(tcon->sclk1);
+ if (enabled)
+ clk_prepare_enable(clk);
+ else
+ clk_disable_unprepare(clk);
}
-EXPORT_SYMBOL(sun4i_tcon_channel_disable);
-void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)
+void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
+ struct drm_encoder *encoder,
+ bool enabled)
{
- DRM_DEBUG_DRIVER("Enabling TCON channel %d\n", channel);
-
- /* Enable the TCON's channel */
- if (channel == 0) {
- regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
- SUN4I_TCON0_CTL_TCON_ENABLE,
- SUN4I_TCON0_CTL_TCON_ENABLE);
- clk_prepare_enable(tcon->dclk);
+ int channel;
+
+ switch (encoder->encoder_type) {
+ case DRM_MODE_ENCODER_NONE:
+ channel = 0;
+ break;
+ case DRM_MODE_ENCODER_TMDS:
+ case DRM_MODE_ENCODER_TVDAC:
+ channel = 1;
+ break;
+ default:
+ DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
return;
}
- WARN_ON(!tcon->quirks->has_channel_1);
- regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
- SUN4I_TCON1_CTL_TCON_ENABLE,
- SUN4I_TCON1_CTL_TCON_ENABLE);
- clk_prepare_enable(tcon->sclk1);
+ sun4i_tcon_channel_set_status(tcon, channel, enabled);
+
+ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+ SUN4I_TCON_GCTL_TCON_ENABLE,
+ enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
}
-EXPORT_SYMBOL(sun4i_tcon_channel_enable);
+EXPORT_SYMBOL(sun4i_tcon_set_status);
void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
{
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 552c88ec16be..824732c90a2a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -183,15 +183,9 @@ struct sun4i_tcon {
struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
-/* Global Control */
-void sun4i_tcon_disable(struct sun4i_tcon *tcon);
-void sun4i_tcon_enable(struct sun4i_tcon *tcon);
-
-/* Channel Control */
-void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel);
-void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel);
-
void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
+void sun4i_tcon_set_status(struct sun4i_tcon *crtc, struct drm_encoder *encoder,
+ bool enable);
/* Mode Related Controls */
void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 73bfe7b1cd78..78d6cf77fdd3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -345,12 +345,9 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
{
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
- struct sun4i_tcon *tcon = crtc->tcon;
DRM_DEBUG_DRIVER("Disabling the TV Output\n");
- sun4i_tcon_channel_disable(tcon, 1);
-
regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
SUN4I_TVE_EN_ENABLE,
0);
@@ -362,7 +359,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
{
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
- struct sun4i_tcon *tcon = crtc->tcon;
DRM_DEBUG_DRIVER("Enabling the TV Output\n");
@@ -371,8 +367,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
SUN4I_TVE_EN_ENABLE,
SUN4I_TVE_EN_ENABLE);
-
- sun4i_tcon_channel_enable(tcon, 1);
}
static void sun4i_tv_mode_set(struct drm_encoder *encoder,
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Chen-Yu Tsai <wens@csie.org> |
|---|---|
| Date | 2017-07-14 05:50 +0200 |
| Subject | Re: [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON |
| Message-ID | <u2ZM5-66v-3@gated-at.bofh.it> |
| In reply to | #1686554 |
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> So far, we've required all the TCON-connected encoders to call the TCON
> enable and disable functions.
>
> This was made this way because in the RGB/LVDS case, the TCON is the CRTC
> and the encoder. However, in all the other cases (HDMI, TV, DSI, etc.), we
> have another encoder down the road that needs to be programmed.
>
> We also needed to know which channel the encoder is connected to, which is
> encoder-specific.
>
> The CRTC's enable and disable callbacks can work just fine for our use
> case, and we can get the channel to use just by looking at the type of
> encoder, since that is fixed. Implement those callbacks, which will
> remove some of the encoder boilerplate.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Overall this looks good. A few minor comments below.
> ---
> drivers/gpu/drm/sun4i/sun4i_crtc.c | 22 ++++++-
> drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 8 +--
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 14 +---
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 91 +++++++++++++--------------
> drivers/gpu/drm/sun4i/sun4i_tcon.h | 10 +---
> drivers/gpu/drm/sun4i/sun4i_tv.c | 6 +--
> 6 files changed, 70 insertions(+), 81 deletions(-)
>
[...]
> static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index d9791292553e..dc70bc2a42a5 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -14,6 +14,7 @@
> #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>
>
> @@ -32,66 +33,62 @@
> #include "sun4i_tcon.h"
> #include "sunxi_engine.h"
>
> -void sun4i_tcon_disable(struct sun4i_tcon *tcon)
> +static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
> + bool enabled)
> {
> - DRM_DEBUG_DRIVER("Disabling TCON\n");
> + struct clk *clk;
>
> - /* Disable the TCON */
> - regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> - SUN4I_TCON_GCTL_TCON_ENABLE, 0);
> -}
> -EXPORT_SYMBOL(sun4i_tcon_disable);
> -
> -void sun4i_tcon_enable(struct sun4i_tcon *tcon)
> -{
> - DRM_DEBUG_DRIVER("Enabling TCON\n");
> -
> - /* Enable the TCON */
> - regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> - SUN4I_TCON_GCTL_TCON_ENABLE,
> - SUN4I_TCON_GCTL_TCON_ENABLE);
> -}
> -EXPORT_SYMBOL(sun4i_tcon_enable);
> -
> -void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
> -{
> - DRM_DEBUG_DRIVER("Disabling TCON channel %d\n", channel);
> -
> - /* Disable the TCON's channel */
> - if (channel == 0) {
> + switch (channel) {
> + case 0:
> regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> - SUN4I_TCON0_CTL_TCON_ENABLE, 0);
> - clk_disable_unprepare(tcon->dclk);
> + SUN4I_TCON0_CTL_TCON_ENABLE,
> + enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
> + clk = tcon->dclk;
> + break;
> + case 1:
> + WARN_ON(!tcon->quirks->has_channel_1);
> + regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> + SUN4I_TCON1_CTL_TCON_ENABLE,
> + enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
> + clk = tcon->sclk1;
> + break;
> + default:
> + DRM_DEBUG_DRIVER("Unknown channel... doing nothing\n");
> return;
> }
>
> - WARN_ON(!tcon->quirks->has_channel_1);
> - regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> - SUN4I_TCON1_CTL_TCON_ENABLE, 0);
> - clk_disable_unprepare(tcon->sclk1);
> + if (enabled)
> + clk_prepare_enable(clk);
I wonder if it's better to enable the clk before the TCON?
> + else
> + clk_disable_unprepare(clk);
> }
> -EXPORT_SYMBOL(sun4i_tcon_channel_disable);
>
> -void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)
> +void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
> + struct drm_encoder *encoder,
> + bool enabled)
> {
> - DRM_DEBUG_DRIVER("Enabling TCON channel %d\n", channel);
> -
> - /* Enable the TCON's channel */
> - if (channel == 0) {
> - regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> - SUN4I_TCON0_CTL_TCON_ENABLE,
> - SUN4I_TCON0_CTL_TCON_ENABLE);
> - clk_prepare_enable(tcon->dclk);
> + int channel;
> +
> + switch (encoder->encoder_type) {
> + case DRM_MODE_ENCODER_NONE:
> + channel = 0;
> + break;
> + case DRM_MODE_ENCODER_TMDS:
> + case DRM_MODE_ENCODER_TVDAC:
> + channel = 1;
> + break;
> + default:
> + DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
We could simply add all the possible types, and print a big warning
if someone does something unexpected. IMHO this is better than having
the user enable some hidden debug flag to figure why the display isn't
working properly.
> return;
> }
>
> - WARN_ON(!tcon->quirks->has_channel_1);
> - regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> - SUN4I_TCON1_CTL_TCON_ENABLE,
> - SUN4I_TCON1_CTL_TCON_ENABLE);
> - clk_prepare_enable(tcon->sclk1);
> + sun4i_tcon_channel_set_status(tcon, channel, enabled);
> +
> + regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> + SUN4I_TCON_GCTL_TCON_ENABLE,
> + enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
The global enable bit should be set first.
Also the manual says "When it’s disabled, the module will be reset to
idle state."
so you might get away with just disabling the global enable bit and returning
directly after disabling the clock?
> }
> -EXPORT_SYMBOL(sun4i_tcon_channel_enable);
> +EXPORT_SYMBOL(sun4i_tcon_set_status);
The TCON and CRTC code are part of the same module.
There is no need to export this function.
ChenYu
>
> void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
> {
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> index 552c88ec16be..824732c90a2a 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> @@ -183,15 +183,9 @@ struct sun4i_tcon {
> struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
> struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
>
> -/* Global Control */
> -void sun4i_tcon_disable(struct sun4i_tcon *tcon);
> -void sun4i_tcon_enable(struct sun4i_tcon *tcon);
> -
> -/* Channel Control */
> -void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel);
> -void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel);
> -
> void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
> +void sun4i_tcon_set_status(struct sun4i_tcon *crtc, struct drm_encoder *encoder,
> + bool enable);
>
> /* Mode Related Controls */
> void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
> index 73bfe7b1cd78..78d6cf77fdd3 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
> @@ -345,12 +345,9 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
> {
> struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
> struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
> - struct sun4i_tcon *tcon = crtc->tcon;
>
> DRM_DEBUG_DRIVER("Disabling the TV Output\n");
>
> - sun4i_tcon_channel_disable(tcon, 1);
> -
> regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
> SUN4I_TVE_EN_ENABLE,
> 0);
> @@ -362,7 +359,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
> {
> struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
> struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
> - struct sun4i_tcon *tcon = crtc->tcon;
>
> DRM_DEBUG_DRIVER("Enabling the TV Output\n");
>
> @@ -371,8 +367,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
> regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
> SUN4I_TVE_EN_ENABLE,
> SUN4I_TVE_EN_ENABLE);
> -
> - sun4i_tcon_channel_enable(tcon, 1);
> }
>
> static void sun4i_tv_mode_set(struct drm_encoder *encoder,
> --
> git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-20 15:30 +0200 |
| Subject | Re: [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON |
| Message-ID | <u5jGF-81X-1@gated-at.bofh.it> |
| In reply to | #1687050 |
[Multipart message — attachments visible in raw view] — view raw
Hi Chen-Yu,
On Fri, Jul 14, 2017 at 11:40:07AM +0800, Chen-Yu Tsai wrote:
> > static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > index d9791292553e..dc70bc2a42a5 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > @@ -14,6 +14,7 @@
> > #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>
> >
> > @@ -32,66 +33,62 @@
> > #include "sun4i_tcon.h"
> > #include "sunxi_engine.h"
> >
> > -void sun4i_tcon_disable(struct sun4i_tcon *tcon)
> > +static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
> > + bool enabled)
> > {
> > - DRM_DEBUG_DRIVER("Disabling TCON\n");
> > + struct clk *clk;
> >
> > - /* Disable the TCON */
> > - regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> > - SUN4I_TCON_GCTL_TCON_ENABLE, 0);
> > -}
> > -EXPORT_SYMBOL(sun4i_tcon_disable);
> > -
> > -void sun4i_tcon_enable(struct sun4i_tcon *tcon)
> > -{
> > - DRM_DEBUG_DRIVER("Enabling TCON\n");
> > -
> > - /* Enable the TCON */
> > - regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> > - SUN4I_TCON_GCTL_TCON_ENABLE,
> > - SUN4I_TCON_GCTL_TCON_ENABLE);
> > -}
> > -EXPORT_SYMBOL(sun4i_tcon_enable);
> > -
> > -void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
> > -{
> > - DRM_DEBUG_DRIVER("Disabling TCON channel %d\n", channel);
> > -
> > - /* Disable the TCON's channel */
> > - if (channel == 0) {
> > + switch (channel) {
> > + case 0:
> > regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> > - SUN4I_TCON0_CTL_TCON_ENABLE, 0);
> > - clk_disable_unprepare(tcon->dclk);
> > + SUN4I_TCON0_CTL_TCON_ENABLE,
> > + enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
> > + clk = tcon->dclk;
> > + break;
> > + case 1:
> > + WARN_ON(!tcon->quirks->has_channel_1);
> > + regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> > + SUN4I_TCON1_CTL_TCON_ENABLE,
> > + enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
> > + clk = tcon->sclk1;
> > + break;
> > + default:
> > + DRM_DEBUG_DRIVER("Unknown channel... doing nothing\n");
> > return;
> > }
> >
> > - WARN_ON(!tcon->quirks->has_channel_1);
> > - regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> > - SUN4I_TCON1_CTL_TCON_ENABLE, 0);
> > - clk_disable_unprepare(tcon->sclk1);
> > + if (enabled)
> > + clk_prepare_enable(clk);
>
> I wonder if it's better to enable the clk before the TCON?
I think I kept the current behaviour, which seemed to work fine with
that regard.
>
> > + else
> > + clk_disable_unprepare(clk);
> > }
> > -EXPORT_SYMBOL(sun4i_tcon_channel_disable);
> >
> > -void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)
> > +void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
> > + struct drm_encoder *encoder,
> > + bool enabled)
> > {
> > - DRM_DEBUG_DRIVER("Enabling TCON channel %d\n", channel);
> > -
> > - /* Enable the TCON's channel */
> > - if (channel == 0) {
> > - regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> > - SUN4I_TCON0_CTL_TCON_ENABLE,
> > - SUN4I_TCON0_CTL_TCON_ENABLE);
> > - clk_prepare_enable(tcon->dclk);
> > + int channel;
> > +
> > + switch (encoder->encoder_type) {
> > + case DRM_MODE_ENCODER_NONE:
> > + channel = 0;
> > + break;
> > + case DRM_MODE_ENCODER_TMDS:
> > + case DRM_MODE_ENCODER_TVDAC:
> > + channel = 1;
> > + break;
> > + default:
> > + DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
>
> We could simply add all the possible types, and print a big warning
> if someone does something unexpected. IMHO this is better than having
> the user enable some hidden debug flag to figure why the display isn't
> working properly.
I'm not sure about all types of encoders, but you're right, it should
be a warning.
> > return;
> > }
> >
> > - WARN_ON(!tcon->quirks->has_channel_1);
> > - regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> > - SUN4I_TCON1_CTL_TCON_ENABLE,
> > - SUN4I_TCON1_CTL_TCON_ENABLE);
> > - clk_prepare_enable(tcon->sclk1);
> > + sun4i_tcon_channel_set_status(tcon, channel, enabled);
> > +
> > + regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> > + SUN4I_TCON_GCTL_TCON_ENABLE,
> > + enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
>
> The global enable bit should be set first.
ACK
> Also the manual says "When it’s disabled, the module will be reset to
> idle state."
> so you might get away with just disabling the global enable bit and returning
> directly after disabling the clock?
I'd rather keep an explicit disable, just in case one SoC is broken,
just like the DE is...
> > }
> > -EXPORT_SYMBOL(sun4i_tcon_channel_enable);
> > +EXPORT_SYMBOL(sun4i_tcon_set_status);
>
> The TCON and CRTC code are part of the same module.
> There is no need to export this function.
Ah, right. I'll remove it. Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 04/18] drm/sun4i: Remove useless atomic_check |
| Message-ID | <u2N8e-6Ff-11@gated-at.bofh.it> |
| In reply to | #1686553 |
The atomic_check callback is optional, and we don't implement anything in
some parts of our drivers. Let's remove it.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_layer.c | 7 -------
drivers/gpu/drm/sun4i/sun4i_rgb.c | 8 --------
drivers/gpu/drm/sun4i/sun4i_tv.c | 8 --------
3 files changed, 23 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index ead4f9d4c1ee..62b08cb47ccd 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,12 +25,6 @@ struct sun4i_plane_desc {
uint32_t nformats;
};
-static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- return 0;
-}
-
static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@@ -53,7 +47,6 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
}
static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
- .atomic_check = sun4i_backend_layer_atomic_check,
.atomic_disable = sun4i_backend_layer_atomic_disable,
.atomic_update = sun4i_backend_layer_atomic_update,
};
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index 422b191faa77..76362c09c608 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -128,13 +128,6 @@ static struct drm_connector_funcs sun4i_rgb_con_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
-static int sun4i_rgb_atomic_check(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
-{
- return 0;
-}
-
static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
{
struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
@@ -182,7 +175,6 @@ static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
}
static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
- .atomic_check = sun4i_rgb_atomic_check,
.mode_set = sun4i_rgb_encoder_mode_set,
.disable = sun4i_rgb_encoder_disable,
.enable = sun4i_rgb_encoder_enable,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 338b9e5bb2a3..73bfe7b1cd78 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -341,13 +341,6 @@ static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
mode->vtotal = mode->vsync_end + tv_mode->vback_porch;
}
-static int sun4i_tv_atomic_check(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
-{
- return 0;
-}
-
static void sun4i_tv_disable(struct drm_encoder *encoder)
{
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
@@ -489,7 +482,6 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
}
static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
- .atomic_check = sun4i_tv_atomic_check,
.disable = sun4i_tv_disable,
.enable = sun4i_tv_enable,
.mode_set = sun4i_tv_mode_set,
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Chen-Yu Tsai <wens@csie.org> |
|---|---|
| Date | 2017-07-14 05:20 +0200 |
| Subject | Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check |
| Message-ID | <u2Zj3-5X9-7@gated-at.bofh.it> |
| In reply to | #1686555 |
On Thu, Jul 13, 2017 at 10:12 PM, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: > The atomic_check callback is optional, and we don't implement anything in > some parts of our drivers. Let's remove it. > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Reviewed-by: Chen-Yu Tsai <wens@csie.org>
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-17 10:50 +0200 |
| Subject | Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check |
| Message-ID | <u49T4-2FF-23@gated-at.bofh.it> |
| In reply to | #1687043 |
[Multipart message — attachments visible in raw view] — view raw
On Fri, Jul 14, 2017 at 11:15:18AM +0800, Chen-Yu Tsai wrote: > On Thu, Jul 13, 2017 at 10:12 PM, Maxime Ripard > <maxime.ripard@free-electrons.com> wrote: > > The atomic_check callback is optional, and we don't implement anything in > > some parts of our drivers. Let's remove it. > > > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> > > Reviewed-by: Chen-Yu Tsai <wens@csie.org> Applied, thanks! Maxime -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver |
| Message-ID | <u2N8e-6Ff-15@gated-at.bofh.it> |
| In reply to | #1686553 |
The LHR050H41 panel is the panel shipped with the BananaPi M2-Magic. Add a
driver for it.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/panel/Kconfig | 9 +-
drivers/gpu/drm/panel/Makefile | 1 +-
drivers/gpu/drm/panel/panel-huarui-lhr050h41.c | 444 ++++++++++++++++++-
3 files changed, 454 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d84a031fae24..eaa6e102775a 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -28,6 +28,15 @@ config DRM_PANEL_SIMPLE
that it can be automatically turned off when the panel goes into a
low power state.
+config DRM_PANEL_HUARUI_LHR050H41
+ tristate "Huarui LHR050H41 panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y if you want to enable support for the Huarui Lighting
+ LHR05041 DSI panel. The panel has a 1280x720 resolution.
+
config DRM_PANEL_INNOLUX_P079ZCA
tristate "Innolux P079ZCA panel"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 9f6610d08b00..58de7a853898 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_HUARUI_LHR050H41) += panel-huarui-lhr050h41.o
obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
diff --git a/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
new file mode 100644
index 000000000000..eb675eb9ee7d
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
@@ -0,0 +1,444 @@
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/gpio/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+struct lhr050h41 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+
+ struct backlight_device *backlight;
+ struct gpio_desc *power;
+ struct gpio_desc *reset;
+};
+
+static inline struct lhr050h41 *panel_to_lhr050h41(struct drm_panel *panel)
+{
+ return container_of(panel, struct lhr050h41, panel);
+}
+
+static int lhr050h41_switch_page(struct lhr050h41 *ctx, u8 page)
+{
+ u8 buf[4] = { 0xff, 0x98, 0x81, page };
+
+ return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
+}
+
+static int lhr050h41_send_cmd_data(struct lhr050h41 *ctx, u8 cmd, u8 data)
+{
+ u8 buf[2] = { cmd, data };
+
+ return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
+}
+
+static int lhr050h41_send_init_sequence(struct lhr050h41 *ctx)
+{
+ lhr050h41_switch_page(ctx, 3);
+
+ lhr050h41_send_cmd_data(ctx, 0x01, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x02, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x03, 0x73);
+ lhr050h41_send_cmd_data(ctx, 0x04, 0x03);
+ lhr050h41_send_cmd_data(ctx, 0x05, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x06, 0x06);
+ lhr050h41_send_cmd_data(ctx, 0x07, 0x06);
+ lhr050h41_send_cmd_data(ctx, 0x08, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x09, 0x18);
+ lhr050h41_send_cmd_data(ctx, 0x0a, 0x04);
+ lhr050h41_send_cmd_data(ctx, 0x0b, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x0c, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x0d, 0x03);
+ lhr050h41_send_cmd_data(ctx, 0x0e, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x0f, 0x25);
+ lhr050h41_send_cmd_data(ctx, 0x10, 0x25);
+ lhr050h41_send_cmd_data(ctx, 0x11, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x12, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x13, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x14, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x15, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x16, 0x0C);
+ lhr050h41_send_cmd_data(ctx, 0x17, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x18, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x19, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x1a, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x1b, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x1c, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x1d, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x1e, 0xC0);
+ lhr050h41_send_cmd_data(ctx, 0x1f, 0x80);
+ lhr050h41_send_cmd_data(ctx, 0x20, 0x04);
+ lhr050h41_send_cmd_data(ctx, 0x21, 0x01);
+ lhr050h41_send_cmd_data(ctx, 0x22, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x23, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x24, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x25, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x26, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x27, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x28, 0x33);
+ lhr050h41_send_cmd_data(ctx, 0x29, 0x03);
+ lhr050h41_send_cmd_data(ctx, 0x2a, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x2b, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x2c, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x2d, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x2e, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x2f, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x30, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x31, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x32, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x33, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x34, 0x04);
+ lhr050h41_send_cmd_data(ctx, 0x35, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x36, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x37, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x38, 0x3C);
+ lhr050h41_send_cmd_data(ctx, 0x39, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x3a, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x3b, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x3c, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x3d, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x3e, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x3f, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x40, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x41, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x42, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x43, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x44, 0x00);
+
+ lhr050h41_send_cmd_data(ctx, 0x50, 0x01);
+ lhr050h41_send_cmd_data(ctx, 0x51, 0x23);
+ lhr050h41_send_cmd_data(ctx, 0x52, 0x45);
+ lhr050h41_send_cmd_data(ctx, 0x53, 0x67);
+ lhr050h41_send_cmd_data(ctx, 0x54, 0x89);
+ lhr050h41_send_cmd_data(ctx, 0x55, 0xab);
+ lhr050h41_send_cmd_data(ctx, 0x56, 0x01);
+ lhr050h41_send_cmd_data(ctx, 0x57, 0x23);
+ lhr050h41_send_cmd_data(ctx, 0x58, 0x45);
+ lhr050h41_send_cmd_data(ctx, 0x59, 0x67);
+ lhr050h41_send_cmd_data(ctx, 0x5a, 0x89);
+ lhr050h41_send_cmd_data(ctx, 0x5b, 0xab);
+ lhr050h41_send_cmd_data(ctx, 0x5c, 0xcd);
+ lhr050h41_send_cmd_data(ctx, 0x5d, 0xef);
+
+ lhr050h41_send_cmd_data(ctx, 0x5e, 0x11);
+ lhr050h41_send_cmd_data(ctx, 0x5f, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x60, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x61, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x62, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x63, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x64, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x65, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x66, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x67, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x68, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x69, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x6a, 0x0C);
+ lhr050h41_send_cmd_data(ctx, 0x6b, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x6c, 0x0F);
+ lhr050h41_send_cmd_data(ctx, 0x6d, 0x0E);
+ lhr050h41_send_cmd_data(ctx, 0x6e, 0x0D);
+ lhr050h41_send_cmd_data(ctx, 0x6f, 0x06);
+ lhr050h41_send_cmd_data(ctx, 0x70, 0x07);
+ lhr050h41_send_cmd_data(ctx, 0x71, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x72, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x73, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x74, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x75, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x76, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x77, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x78, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x79, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x7a, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x7b, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x7c, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x7d, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x7e, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x7f, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x80, 0x0C);
+ lhr050h41_send_cmd_data(ctx, 0x81, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x82, 0x0F);
+ lhr050h41_send_cmd_data(ctx, 0x83, 0x0E);
+ lhr050h41_send_cmd_data(ctx, 0x84, 0x0D);
+ lhr050h41_send_cmd_data(ctx, 0x85, 0x06);
+ lhr050h41_send_cmd_data(ctx, 0x86, 0x07);
+ lhr050h41_send_cmd_data(ctx, 0x87, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x88, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x89, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x8A, 0x02);
+
+ lhr050h41_switch_page(ctx, 4);
+ lhr050h41_send_cmd_data(ctx, 0x6C, 0x15);
+ lhr050h41_send_cmd_data(ctx, 0x6E, 0x22);
+ lhr050h41_send_cmd_data(ctx, 0x6F, 0x33);
+ lhr050h41_send_cmd_data(ctx, 0x3A, 0xA4);
+ lhr050h41_send_cmd_data(ctx, 0x8D, 0x0D);
+ lhr050h41_send_cmd_data(ctx, 0x87, 0xBA);
+ lhr050h41_send_cmd_data(ctx, 0x26, 0x76);
+ lhr050h41_send_cmd_data(ctx, 0xB2, 0xD1);
+
+ lhr050h41_switch_page(ctx, 1);
+ lhr050h41_send_cmd_data(ctx, 0x22, 0x0A);
+ lhr050h41_send_cmd_data(ctx, 0x53, 0xDC);
+ lhr050h41_send_cmd_data(ctx, 0x55, 0xA7);
+ lhr050h41_send_cmd_data(ctx, 0x50, 0x78);
+ lhr050h41_send_cmd_data(ctx, 0x51, 0x78);
+ lhr050h41_send_cmd_data(ctx, 0x31, 0x02);
+ lhr050h41_send_cmd_data(ctx, 0x60, 0x14);
+ lhr050h41_send_cmd_data(ctx, 0xA0, 0x2A);
+ lhr050h41_send_cmd_data(ctx, 0xA1, 0x39);
+ lhr050h41_send_cmd_data(ctx, 0xA2, 0x46);
+ lhr050h41_send_cmd_data(ctx, 0xA3, 0x0e);
+ lhr050h41_send_cmd_data(ctx, 0xA4, 0x12);
+ lhr050h41_send_cmd_data(ctx, 0xA5, 0x25);
+ lhr050h41_send_cmd_data(ctx, 0xA6, 0x19);
+ lhr050h41_send_cmd_data(ctx, 0xA7, 0x1d);
+ lhr050h41_send_cmd_data(ctx, 0xA8, 0xa6);
+ lhr050h41_send_cmd_data(ctx, 0xA9, 0x1C);
+ lhr050h41_send_cmd_data(ctx, 0xAA, 0x29);
+ lhr050h41_send_cmd_data(ctx, 0xAB, 0x85);
+ lhr050h41_send_cmd_data(ctx, 0xAC, 0x1C);
+ lhr050h41_send_cmd_data(ctx, 0xAD, 0x1B);
+ lhr050h41_send_cmd_data(ctx, 0xAE, 0x51);
+ lhr050h41_send_cmd_data(ctx, 0xAF, 0x22);
+ lhr050h41_send_cmd_data(ctx, 0xB0, 0x2d);
+ lhr050h41_send_cmd_data(ctx, 0xB1, 0x4f);
+ lhr050h41_send_cmd_data(ctx, 0xB2, 0x59);
+ lhr050h41_send_cmd_data(ctx, 0xB3, 0x3F);
+ lhr050h41_send_cmd_data(ctx, 0xC0, 0x2A);
+ lhr050h41_send_cmd_data(ctx, 0xC1, 0x3a);
+ lhr050h41_send_cmd_data(ctx, 0xC2, 0x45);
+ lhr050h41_send_cmd_data(ctx, 0xC3, 0x0e);
+ lhr050h41_send_cmd_data(ctx, 0xC4, 0x11);
+ lhr050h41_send_cmd_data(ctx, 0xC5, 0x24);
+ lhr050h41_send_cmd_data(ctx, 0xC6, 0x1a);
+ lhr050h41_send_cmd_data(ctx, 0xC7, 0x1c);
+ lhr050h41_send_cmd_data(ctx, 0xC8, 0xaa);
+ lhr050h41_send_cmd_data(ctx, 0xC9, 0x1C);
+ lhr050h41_send_cmd_data(ctx, 0xCA, 0x29);
+ lhr050h41_send_cmd_data(ctx, 0xCB, 0x96);
+ lhr050h41_send_cmd_data(ctx, 0xCC, 0x1C);
+ lhr050h41_send_cmd_data(ctx, 0xCD, 0x1B);
+ lhr050h41_send_cmd_data(ctx, 0xCE, 0x51);
+ lhr050h41_send_cmd_data(ctx, 0xCF, 0x22);
+ lhr050h41_send_cmd_data(ctx, 0xD0, 0x2b);
+ lhr050h41_send_cmd_data(ctx, 0xD1, 0x4b);
+ lhr050h41_send_cmd_data(ctx, 0xD2, 0x59);
+ lhr050h41_send_cmd_data(ctx, 0xD3, 0x3F);
+
+ lhr050h41_switch_page(ctx, 0);
+ lhr050h41_send_cmd_data(ctx, 0x35, 0x00);
+ lhr050h41_send_cmd_data(ctx, 0x11, 0x00);
+
+ mdelay(120);
+
+ lhr050h41_send_cmd_data(ctx, 0x29, 0x00);
+
+ mdelay(20);
+
+ return 0;
+}
+
+static int lhr050h41_prepare(struct drm_panel *panel)
+{
+ struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+ /* Power the panel */
+ gpiod_set_value(ctx->power, 1);
+ mdelay(5);
+
+ /* And reset it */
+ gpiod_set_value(ctx->reset, 1);
+ mdelay(20);
+
+ gpiod_set_value(ctx->reset, 0);
+ mdelay(20);
+
+ lhr050h41_send_init_sequence(ctx);
+
+ return 0;
+}
+
+static void lhr050h41_enable_bl(struct lhr050h41 *ctx, bool enable)
+{
+ if (!ctx->backlight)
+ return;
+
+ if (enable) {
+ ctx->backlight->props.state &= ~BL_CORE_FBBLANK;
+ ctx->backlight->props.power = FB_BLANK_UNBLANK;
+ } else {
+ ctx->backlight->props.power = FB_BLANK_POWERDOWN;
+ ctx->backlight->props.state |= BL_CORE_FBBLANK;
+ }
+
+ backlight_update_status(ctx->backlight);
+}
+
+static int lhr050h41_enable(struct drm_panel *panel)
+{
+ struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+ lhr050h41_enable_bl(ctx, true);
+
+ return 0;
+}
+
+static int lhr050h41_disable(struct drm_panel *panel)
+{
+ struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+ lhr050h41_enable_bl(ctx, false);
+
+ return mipi_dsi_dcs_set_display_off(ctx->dsi);
+}
+
+static int lhr050h41_unprepare(struct drm_panel *panel)
+{
+ struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+ mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+ gpiod_set_value(ctx->power, 0);
+ gpiod_set_value(ctx->reset, 1);
+
+ return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+ .clock = 62000,
+ .vrefresh = 60,
+
+ .hdisplay = 720,
+ .hsync_start = 720 + 10,
+ .hsync_end = 720 + 10 + 20,
+ .htotal = 720 + 10 + 20 + 30,
+
+ .vdisplay = 1280,
+ .vsync_start = 1280 + 10,
+ .vsync_end = 1280 + 10 + 10,
+ .vtotal = 1280 + 10 + 10 + 20,
+};
+
+static int lhr050h41_get_modes(struct drm_panel *panel)
+{
+ struct drm_connector *connector = panel->connector;
+ struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(panel->drm, &default_mode);
+ if (!mode) {
+ dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ default_mode.vrefresh);
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+
+ panel->connector->display_info.width_mm = 62;
+ panel->connector->display_info.height_mm = 110;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs lhr050h41_funcs = {
+ .prepare = lhr050h41_prepare,
+ .unprepare = lhr050h41_unprepare,
+ .enable = lhr050h41_enable,
+ .disable = lhr050h41_disable,
+ .get_modes = lhr050h41_get_modes,
+};
+
+static int lhr050h41_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ struct device_node *np;
+ struct lhr050h41 *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ mipi_dsi_set_drvdata(dsi, ctx);
+ ctx->dsi = dsi;
+
+ drm_panel_init(&ctx->panel);
+ ctx->panel.dev = &dsi->dev;
+ ctx->panel.funcs = &lhr050h41_funcs;
+
+ ctx->power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->power)) {
+ dev_err(&dsi->dev, "Couldn't get our power GPIO\n");
+ return PTR_ERR(ctx->power);
+ }
+
+ ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset)) {
+ dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
+ return PTR_ERR(ctx->reset);
+ }
+
+ np = of_parse_phandle(dsi->dev.of_node, "backlight", 0);
+ if (np) {
+ ctx->backlight = of_find_backlight_by_node(np);
+ of_node_put(np);
+
+ if (!ctx->backlight)
+ return -EPROBE_DEFER;
+ }
+
+ ret = drm_panel_add(&ctx->panel);
+ if (ret < 0)
+ return ret;
+
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->lanes = 4;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static int lhr050h41_dsi_remove(struct mipi_dsi_device *dsi)
+{
+ struct lhr050h41 *ctx = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_panel_remove(&ctx->panel);
+
+ if (ctx->backlight)
+ put_device(&ctx->backlight->dev);
+
+ return 0;
+}
+
+static const struct of_device_id lhr050h41_of_match[] = {
+ { .compatible = "huarui,lhr050h41" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lhr050h41_of_match);
+
+static struct mipi_dsi_driver lhr050h41_dsi_driver = {
+ .probe = lhr050h41_dsi_probe,
+ .remove = lhr050h41_dsi_remove,
+ .driver = {
+ .name = "lhr050h41-dsi",
+ .of_match_table = lhr050h41_of_match,
+ },
+};
+module_mipi_dsi_driver(lhr050h41_dsi_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Huarui LHR050H41 LCD Driver");
+MODULE_LICENSE("GPL v2");
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Andrzej Hajda <a.hajda@samsung.com> |
|---|---|
| Date | 2017-07-14 11:30 +0200 |
| Subject | Re: [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver |
| Message-ID | <u3559-1oP-33@gated-at.bofh.it> |
| In reply to | #1686556 |
On 13.07.2017 16:13, Maxime Ripard wrote:
> The LHR050H41 panel is the panel shipped with the BananaPi M2-Magic. Add a
> driver for it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> drivers/gpu/drm/panel/Kconfig | 9 +-
> drivers/gpu/drm/panel/Makefile | 1 +-
> drivers/gpu/drm/panel/panel-huarui-lhr050h41.c | 444 ++++++++++++++++++-
> 3 files changed, 454 insertions(+)
> create mode 100644 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
>
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index d84a031fae24..eaa6e102775a 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -28,6 +28,15 @@ config DRM_PANEL_SIMPLE
> that it can be automatically turned off when the panel goes into a
> low power state.
>
> +config DRM_PANEL_HUARUI_LHR050H41
> + tristate "Huarui LHR050H41 panel"
> + depends on OF
> + depends on DRM_MIPI_DSI
> + depends on BACKLIGHT_CLASS_DEVICE
> + help
> + Say Y if you want to enable support for the Huarui Lighting
> + LHR05041 DSI panel. The panel has a 1280x720 resolution.
> +
> config DRM_PANEL_INNOLUX_P079ZCA
> tristate "Innolux P079ZCA panel"
> depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index 9f6610d08b00..58de7a853898 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -1,5 +1,6 @@
> obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
> obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
> +obj-$(CONFIG_DRM_PANEL_HUARUI_LHR050H41) += panel-huarui-lhr050h41.o
> obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
> obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
> obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
> diff --git a/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
> new file mode 100644
> index 000000000000..eb675eb9ee7d
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
> @@ -0,0 +1,444 @@
No copyright/license/description at the beginning of the file.
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/fb.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include <linux/gpio/consumer.h>
It can be put in alphabetical order.
> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_modes.h>
> +#include <drm/drm_panel.h>
> +
> +#include <video/mipi_display.h>
> +
> +struct lhr050h41 {
> + struct drm_panel panel;
> + struct mipi_dsi_device *dsi;
> +
> + struct backlight_device *backlight;
> + struct gpio_desc *power;
> + struct gpio_desc *reset;
> +};
> +
> +static inline struct lhr050h41 *panel_to_lhr050h41(struct drm_panel *panel)
> +{
> + return container_of(panel, struct lhr050h41, panel);
> +}
> +
> +static int lhr050h41_switch_page(struct lhr050h41 *ctx, u8 page)
> +{
> + u8 buf[4] = { 0xff, 0x98, 0x81, page };
> +
> + return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
> +}
> +
> +static int lhr050h41_send_cmd_data(struct lhr050h41 *ctx, u8 cmd, u8 data)
> +{
> + u8 buf[2] = { cmd, data };
> +
> + return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
> +}
> +
> +static int lhr050h41_send_init_sequence(struct lhr050h41 *ctx)
> +{
> + lhr050h41_switch_page(ctx, 3);
No error checking, here and below in most places.
> +
> + lhr050h41_send_cmd_data(ctx, 0x01, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x02, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x03, 0x73);
> + lhr050h41_send_cmd_data(ctx, 0x04, 0x03);
> + lhr050h41_send_cmd_data(ctx, 0x05, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x06, 0x06);
> + lhr050h41_send_cmd_data(ctx, 0x07, 0x06);
> + lhr050h41_send_cmd_data(ctx, 0x08, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x09, 0x18);
> + lhr050h41_send_cmd_data(ctx, 0x0a, 0x04);
> + lhr050h41_send_cmd_data(ctx, 0x0b, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x0c, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x0d, 0x03);
> + lhr050h41_send_cmd_data(ctx, 0x0e, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x0f, 0x25);
> + lhr050h41_send_cmd_data(ctx, 0x10, 0x25);
> + lhr050h41_send_cmd_data(ctx, 0x11, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x12, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x13, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x14, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x15, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x16, 0x0C);
> + lhr050h41_send_cmd_data(ctx, 0x17, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x18, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x19, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x1a, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x1b, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x1c, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x1d, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x1e, 0xC0);
> + lhr050h41_send_cmd_data(ctx, 0x1f, 0x80);
> + lhr050h41_send_cmd_data(ctx, 0x20, 0x04);
> + lhr050h41_send_cmd_data(ctx, 0x21, 0x01);
> + lhr050h41_send_cmd_data(ctx, 0x22, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x23, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x24, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x25, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x26, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x27, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x28, 0x33);
> + lhr050h41_send_cmd_data(ctx, 0x29, 0x03);
> + lhr050h41_send_cmd_data(ctx, 0x2a, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x2b, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x2c, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x2d, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x2e, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x2f, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x30, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x31, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x32, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x33, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x34, 0x04);
> + lhr050h41_send_cmd_data(ctx, 0x35, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x36, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x37, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x38, 0x3C);
> + lhr050h41_send_cmd_data(ctx, 0x39, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x3a, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x3b, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x3c, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x3d, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x3e, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x3f, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x40, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x41, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x42, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x43, 0x00);
> + lhr050h41_send_cmd_data(ctx, 0x44, 0x00);
> +
> + lhr050h41_send_cmd_data(ctx, 0x50, 0x01);
> + lhr050h41_send_cmd_data(ctx, 0x51, 0x23);
> + lhr050h41_send_cmd_data(ctx, 0x52, 0x45);
> + lhr050h41_send_cmd_data(ctx, 0x53, 0x67);
> + lhr050h41_send_cmd_data(ctx, 0x54, 0x89);
> + lhr050h41_send_cmd_data(ctx, 0x55, 0xab);
> + lhr050h41_send_cmd_data(ctx, 0x56, 0x01);
> + lhr050h41_send_cmd_data(ctx, 0x57, 0x23);
> + lhr050h41_send_cmd_data(ctx, 0x58, 0x45);
> + lhr050h41_send_cmd_data(ctx, 0x59, 0x67);
> + lhr050h41_send_cmd_data(ctx, 0x5a, 0x89);
> + lhr050h41_send_cmd_data(ctx, 0x5b, 0xab);
> + lhr050h41_send_cmd_data(ctx, 0x5c, 0xcd);
> + lhr050h41_send_cmd_data(ctx, 0x5d, 0xef);
> +
> + lhr050h41_send_cmd_data(ctx, 0x5e, 0x11);
> + lhr050h41_send_cmd_data(ctx, 0x5f, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x60, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x61, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x62, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x63, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x64, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x65, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x66, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x67, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x68, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x69, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x6a, 0x0C);
> + lhr050h41_send_cmd_data(ctx, 0x6b, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x6c, 0x0F);
> + lhr050h41_send_cmd_data(ctx, 0x6d, 0x0E);
> + lhr050h41_send_cmd_data(ctx, 0x6e, 0x0D);
> + lhr050h41_send_cmd_data(ctx, 0x6f, 0x06);
> + lhr050h41_send_cmd_data(ctx, 0x70, 0x07);
> + lhr050h41_send_cmd_data(ctx, 0x71, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x72, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x73, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x74, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x75, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x76, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x77, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x78, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x79, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x7a, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x7b, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x7c, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x7d, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x7e, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x7f, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x80, 0x0C);
> + lhr050h41_send_cmd_data(ctx, 0x81, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x82, 0x0F);
> + lhr050h41_send_cmd_data(ctx, 0x83, 0x0E);
> + lhr050h41_send_cmd_data(ctx, 0x84, 0x0D);
> + lhr050h41_send_cmd_data(ctx, 0x85, 0x06);
> + lhr050h41_send_cmd_data(ctx, 0x86, 0x07);
> + lhr050h41_send_cmd_data(ctx, 0x87, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x88, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x89, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x8A, 0x02);
> +
> + lhr050h41_switch_page(ctx, 4);
> + lhr050h41_send_cmd_data(ctx, 0x6C, 0x15);
> + lhr050h41_send_cmd_data(ctx, 0x6E, 0x22);
> + lhr050h41_send_cmd_data(ctx, 0x6F, 0x33);
> + lhr050h41_send_cmd_data(ctx, 0x3A, 0xA4);
> + lhr050h41_send_cmd_data(ctx, 0x8D, 0x0D);
> + lhr050h41_send_cmd_data(ctx, 0x87, 0xBA);
> + lhr050h41_send_cmd_data(ctx, 0x26, 0x76);
> + lhr050h41_send_cmd_data(ctx, 0xB2, 0xD1);
> +
> + lhr050h41_switch_page(ctx, 1);
> + lhr050h41_send_cmd_data(ctx, 0x22, 0x0A);
> + lhr050h41_send_cmd_data(ctx, 0x53, 0xDC);
> + lhr050h41_send_cmd_data(ctx, 0x55, 0xA7);
> + lhr050h41_send_cmd_data(ctx, 0x50, 0x78);
> + lhr050h41_send_cmd_data(ctx, 0x51, 0x78);
> + lhr050h41_send_cmd_data(ctx, 0x31, 0x02);
> + lhr050h41_send_cmd_data(ctx, 0x60, 0x14);
> + lhr050h41_send_cmd_data(ctx, 0xA0, 0x2A);
> + lhr050h41_send_cmd_data(ctx, 0xA1, 0x39);
> + lhr050h41_send_cmd_data(ctx, 0xA2, 0x46);
> + lhr050h41_send_cmd_data(ctx, 0xA3, 0x0e);
> + lhr050h41_send_cmd_data(ctx, 0xA4, 0x12);
> + lhr050h41_send_cmd_data(ctx, 0xA5, 0x25);
> + lhr050h41_send_cmd_data(ctx, 0xA6, 0x19);
> + lhr050h41_send_cmd_data(ctx, 0xA7, 0x1d);
> + lhr050h41_send_cmd_data(ctx, 0xA8, 0xa6);
> + lhr050h41_send_cmd_data(ctx, 0xA9, 0x1C);
> + lhr050h41_send_cmd_data(ctx, 0xAA, 0x29);
> + lhr050h41_send_cmd_data(ctx, 0xAB, 0x85);
> + lhr050h41_send_cmd_data(ctx, 0xAC, 0x1C);
> + lhr050h41_send_cmd_data(ctx, 0xAD, 0x1B);
> + lhr050h41_send_cmd_data(ctx, 0xAE, 0x51);
> + lhr050h41_send_cmd_data(ctx, 0xAF, 0x22);
> + lhr050h41_send_cmd_data(ctx, 0xB0, 0x2d);
> + lhr050h41_send_cmd_data(ctx, 0xB1, 0x4f);
> + lhr050h41_send_cmd_data(ctx, 0xB2, 0x59);
> + lhr050h41_send_cmd_data(ctx, 0xB3, 0x3F);
> + lhr050h41_send_cmd_data(ctx, 0xC0, 0x2A);
> + lhr050h41_send_cmd_data(ctx, 0xC1, 0x3a);
> + lhr050h41_send_cmd_data(ctx, 0xC2, 0x45);
> + lhr050h41_send_cmd_data(ctx, 0xC3, 0x0e);
> + lhr050h41_send_cmd_data(ctx, 0xC4, 0x11);
> + lhr050h41_send_cmd_data(ctx, 0xC5, 0x24);
> + lhr050h41_send_cmd_data(ctx, 0xC6, 0x1a);
> + lhr050h41_send_cmd_data(ctx, 0xC7, 0x1c);
> + lhr050h41_send_cmd_data(ctx, 0xC8, 0xaa);
> + lhr050h41_send_cmd_data(ctx, 0xC9, 0x1C);
> + lhr050h41_send_cmd_data(ctx, 0xCA, 0x29);
> + lhr050h41_send_cmd_data(ctx, 0xCB, 0x96);
> + lhr050h41_send_cmd_data(ctx, 0xCC, 0x1C);
> + lhr050h41_send_cmd_data(ctx, 0xCD, 0x1B);
> + lhr050h41_send_cmd_data(ctx, 0xCE, 0x51);
> + lhr050h41_send_cmd_data(ctx, 0xCF, 0x22);
> + lhr050h41_send_cmd_data(ctx, 0xD0, 0x2b);
> + lhr050h41_send_cmd_data(ctx, 0xD1, 0x4b);
> + lhr050h41_send_cmd_data(ctx, 0xD2, 0x59);
> + lhr050h41_send_cmd_data(ctx, 0xD3, 0x3F);
I think you can put all above codes into some array and call it in loop,
with error checking.
> +
> + lhr050h41_switch_page(ctx, 0);
> + lhr050h41_send_cmd_data(ctx, 0x35, 0x00);
mipi_dsi_dcs_set_tear_on
> + lhr050h41_send_cmd_data(ctx, 0x11, 0x00);
mipi_dsi_dcs_exit_sleep_mode
> +
> + mdelay(120);
I think it should be moved to enable callback, more about it below.
> +
> + lhr050h41_send_cmd_data(ctx, 0x29, 0x00);
mipi_dsi_dcs_set_display_on
> +
> + mdelay(20);
> +
> + return 0;
> +}
> +
> +static int lhr050h41_prepare(struct drm_panel *panel)
> +{
> + struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> + /* Power the panel */
> + gpiod_set_value(ctx->power, 1);
> + mdelay(5);
> +
> + /* And reset it */
> + gpiod_set_value(ctx->reset, 1);
> + mdelay(20);
> +
> + gpiod_set_value(ctx->reset, 0);
> + mdelay(20);
> +
> + lhr050h41_send_init_sequence(ctx);
> +
> + return 0;
> +}
> +
> +static void lhr050h41_enable_bl(struct lhr050h41 *ctx, bool enable)
> +{
> + if (!ctx->backlight)
> + return;
> +
> + if (enable) {
> + ctx->backlight->props.state &= ~BL_CORE_FBBLANK;
> + ctx->backlight->props.power = FB_BLANK_UNBLANK;
> + } else {
> + ctx->backlight->props.power = FB_BLANK_POWERDOWN;
> + ctx->backlight->props.state |= BL_CORE_FBBLANK;
> + }
> +
> + backlight_update_status(ctx->backlight);
> +}
> +
> +static int lhr050h41_enable(struct drm_panel *panel)
> +{
> + struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> + lhr050h41_enable_bl(ctx, true);
> +
> + return 0;
> +}
Usually purpose of mdelay(120) is to wait for finishing initialization
and transmission of first frames to the panel.
So I guess mdelay(120) and mipi_dsi_dcs_set_display_on should be moved
to _enable callback, otherwise you risk having garbage on the screen at
start.
> +
> +static int lhr050h41_disable(struct drm_panel *panel)
> +{
> + struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> + lhr050h41_enable_bl(ctx, false);
> +
> + return mipi_dsi_dcs_set_display_off(ctx->dsi);
> +}
> +
> +static int lhr050h41_unprepare(struct drm_panel *panel)
> +{
> + struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> + mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
> + gpiod_set_value(ctx->power, 0);
> + gpiod_set_value(ctx->reset, 1);
> +
> + return 0;
> +}
> +
> +static const struct drm_display_mode default_mode = {
> + .clock = 62000,
> + .vrefresh = 60,
> +
> + .hdisplay = 720,
> + .hsync_start = 720 + 10,
> + .hsync_end = 720 + 10 + 20,
> + .htotal = 720 + 10 + 20 + 30,
> +
> + .vdisplay = 1280,
> + .vsync_start = 1280 + 10,
> + .vsync_end = 1280 + 10 + 10,
> + .vtotal = 1280 + 10 + 10 + 20,
> +};
> +
> +static int lhr050h41_get_modes(struct drm_panel *panel)
> +{
> + struct drm_connector *connector = panel->connector;
> + struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> + struct drm_display_mode *mode;
> +
> + mode = drm_mode_duplicate(panel->drm, &default_mode);
> + if (!mode) {
> + dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
> + default_mode.hdisplay, default_mode.vdisplay,
> + default_mode.vrefresh);
> + return -ENOMEM;
> + }
> +
> + drm_mode_set_name(mode);
> +
> + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> + drm_mode_probed_add(connector, mode);
> +
> + panel->connector->display_info.width_mm = 62;
> + panel->connector->display_info.height_mm = 110;
> +
> + return 1;
> +}
> +
> +static const struct drm_panel_funcs lhr050h41_funcs = {
> + .prepare = lhr050h41_prepare,
> + .unprepare = lhr050h41_unprepare,
> + .enable = lhr050h41_enable,
> + .disable = lhr050h41_disable,
> + .get_modes = lhr050h41_get_modes,
> +};
> +
> +static int lhr050h41_dsi_probe(struct mipi_dsi_device *dsi)
> +{
> + struct device_node *np;
> + struct lhr050h41 *ctx;
> + int ret;
> +
> + ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> + mipi_dsi_set_drvdata(dsi, ctx);
> + ctx->dsi = dsi;
> +
> + drm_panel_init(&ctx->panel);
> + ctx->panel.dev = &dsi->dev;
> + ctx->panel.funcs = &lhr050h41_funcs;
> +
> + ctx->power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
> + if (IS_ERR(ctx->power)) {
> + dev_err(&dsi->dev, "Couldn't get our power GPIO\n");
> + return PTR_ERR(ctx->power);
> + }
> +
> + ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
> + if (IS_ERR(ctx->reset)) {
> + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
> + return PTR_ERR(ctx->reset);
> + }
> +
> + np = of_parse_phandle(dsi->dev.of_node, "backlight", 0);
> + if (np) {
> + ctx->backlight = of_find_backlight_by_node(np);
> + of_node_put(np);
> +
> + if (!ctx->backlight)
> + return -EPROBE_DEFER;
> + }
> +
> + ret = drm_panel_add(&ctx->panel);
> + if (ret < 0)
> + return ret;
> +
> + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
I guess MIPI_DSI_MODE_VIDEO should be also here.
Regards
Andrzej
> + dsi->format = MIPI_DSI_FMT_RGB888;
> + dsi->lanes = 4;
> +
> + return mipi_dsi_attach(dsi);
> +}
> +
> +static int lhr050h41_dsi_remove(struct mipi_dsi_device *dsi)
> +{
> + struct lhr050h41 *ctx = mipi_dsi_get_drvdata(dsi);
> +
> + mipi_dsi_detach(dsi);
> + drm_panel_remove(&ctx->panel);
> +
> + if (ctx->backlight)
> + put_device(&ctx->backlight->dev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id lhr050h41_of_match[] = {
> + { .compatible = "huarui,lhr050h41" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, lhr050h41_of_match);
> +
> +static struct mipi_dsi_driver lhr050h41_dsi_driver = {
> + .probe = lhr050h41_dsi_probe,
> + .remove = lhr050h41_dsi_remove,
> + .driver = {
> + .name = "lhr050h41-dsi",
> + .of_match_table = lhr050h41_of_match,
> + },
> +};
> +module_mipi_dsi_driver(lhr050h41_dsi_driver);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
> +MODULE_DESCRIPTION("Huarui LHR050H41 LCD Driver");
> +MODULE_LICENSE("GPL v2");
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank |
| Message-ID | <u2N8e-6Ff-17@gated-at.bofh.it> |
| In reply to | #1686553 |
The "CPU" (or Intel 8080) interface uses a different interrupt called
TRI_FINISH (most likely TRI being for trigger) to notify the end of frames,
and hence the VBLANK period.
And that interrupt to the possible VBLANK interrupts source.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 9 ++++++---
drivers/gpu/drm/sun4i/sun4i_tcon.h | 4 ++++
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index c4407910dfaf..a3bbf9994cfa 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -97,7 +97,8 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
- SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
+ SUN4I_TCON_GINT0_VBLANK_ENABLE(1) |
+ SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE;
if (enable)
val = mask;
@@ -336,7 +337,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
- SUN4I_TCON_GINT0_VBLANK_INT(1))))
+ SUN4I_TCON_GINT0_VBLANK_INT(1) |
+ SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT)))
return IRQ_NONE;
drm_crtc_handle_vblank(&scrtc->crtc);
@@ -345,7 +347,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
/* Acknowledge the interrupt */
regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
SUN4I_TCON_GINT0_VBLANK_INT(0) |
- SUN4I_TCON_GINT0_VBLANK_INT(1),
+ SUN4I_TCON_GINT0_VBLANK_INT(1) |
+ SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT,
0);
return IRQ_HANDLED;
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index a318e5ccb612..b3582ee82855 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -28,7 +28,11 @@
#define SUN4I_TCON_GINT0_REG 0x4
#define SUN4I_TCON_GINT0_VBLANK_ENABLE(pipe) BIT(31 - (pipe))
+#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE BIT(27)
+#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_ENABLE BIT(26)
#define SUN4I_TCON_GINT0_VBLANK_INT(pipe) BIT(15 - (pipe))
+#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT BIT(11)
+#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_INT BIT(10)
#define SUN4I_TCON_GINT1_REG 0x8
#define SUN4I_TCON_FRM_CTL_REG 0x10
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Chen-Yu Tsai <wens@csie.org> |
|---|---|
| Date | 2017-07-14 06:00 +0200 |
| Subject | Re: [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank |
| Message-ID | <u2ZVM-69C-13@gated-at.bofh.it> |
| In reply to | #1686557 |
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard <maxime.ripard@free-electrons.com> wrote: > The "CPU" (or Intel 8080) interface uses a different interrupt called > TRI_FINISH (most likely TRI being for trigger) to notify the end of frames, > and hence the VBLANK period. > > And that interrupt to the possible VBLANK interrupts source. > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Reviewed-by: Chen-Yu Tsai <wens@csie.org>
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode |
| Message-ID | <u2N8f-6Ff-19@gated-at.bofh.it> |
| In reply to | #1686553 |
Just like we did for the TCON enable and disable, for historical reasons we
used to rely on the encoders calling the TCON mode_set function, while the
CRTC has a callback for that.
Let's implement it in order to reduce the boilerplate code.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_crtc.c | 11 ++++-
drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 1 +-
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 7 +---
drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c | 1 +-
drivers/gpu/drm/sun4i/sun4i_rgb.c | 15 +------
drivers/gpu/drm/sun4i/sun4i_tcon.c | 56 ++++++++++------------
drivers/gpu/drm/sun4i/sun4i_tcon.h | 10 +----
drivers/gpu/drm/sun4i/sun4i_tv.c | 6 +--
8 files changed, 40 insertions(+), 67 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 30c7568dde5c..886595f579ab 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -113,11 +113,22 @@ static void sun4i_crtc_enable(struct drm_crtc *crtc)
sun4i_tcon_set_status(scrtc->tcon, encoder, true);
}
+static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
+ struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+
+ sun4i_tcon_mode_set(scrtc->tcon, encoder, mode);
+}
+
+
static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
.atomic_begin = sun4i_crtc_atomic_begin,
.atomic_flush = sun4i_crtc_atomic_flush,
.disable = sun4i_crtc_disable,
.enable = sun4i_crtc_enable,
+ .mode_set_nofb = sun4i_crtc_mode_set_nofb,
};
static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
index 4692e8c345ed..7348bdbaa803 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
@@ -12,7 +12,6 @@
#include <linux/clk-provider.h>
-#include "sun4i_tcon.h"
#include "sun4i_hdmi.h"
struct sun4i_ddc {
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 06af2f6d0b31..67ef8acdb439 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -27,7 +27,6 @@
#include "sun4i_crtc.h"
#include "sun4i_drv.h"
#include "sun4i_hdmi.h"
-#include "sun4i_tcon.h"
#define DDC_SEGMENT_ADDR 0x30
@@ -119,15 +118,9 @@ static void sun4i_hdmi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
- struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
- struct sun4i_tcon *tcon = crtc->tcon;
unsigned int x, y;
u32 val;
- sun4i_tcon1_mode_set(tcon, mode);
- sun4i_tcon_set_mux(tcon, 1, encoder);
-
- clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000);
clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000);
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
index 5cf2527bffc8..5b6727623037 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
@@ -12,7 +12,6 @@
#include <linux/clk-provider.h>
-#include "sun4i_tcon.h"
#include "sun4i_hdmi.h"
struct sun4i_tmds {
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index ecce1f5b50ab..9061e16e3088 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -154,22 +154,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
}
}
-static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
- struct sun4i_tcon *tcon = rgb->tcon;
-
- sun4i_tcon0_mode_set(tcon, mode);
- sun4i_tcon_set_mux(tcon, 0, encoder);
-
- /* FIXME: This seems to be board specific */
- clk_set_phase(tcon->dclk, 120);
-}
-
static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
- .mode_set = sun4i_rgb_encoder_mode_set,
.disable = sun4i_rgb_encoder_disable,
.enable = sun4i_rgb_encoder_enable,
};
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index dc70bc2a42a5..c4407910dfaf 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -106,29 +106,6 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
}
EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
-void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
- struct drm_encoder *encoder)
-{
- u32 val;
-
- if (!tcon->quirks->has_unknown_mux)
- return;
-
- if (channel != 1)
- return;
-
- if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
- val = 1;
- else
- val = 0;
-
- /*
- * FIXME: Undocumented bits
- */
- regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
-}
-EXPORT_SYMBOL(sun4i_tcon_set_mux);
-
static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
int channel)
{
@@ -147,8 +124,8 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
return delay;
}
-void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
- struct drm_display_mode *mode)
+static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
+ struct drm_display_mode *mode)
{
unsigned int bp, hsync, vsync;
u8 clk_delay;
@@ -221,10 +198,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
/* Enable the output on the pins */
regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
}
-EXPORT_SYMBOL(sun4i_tcon0_mode_set);
-void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
- struct drm_display_mode *mode)
+static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
+ struct drm_display_mode *mode)
{
unsigned int bp, hsync, vsync, vtotal;
u8 clk_delay;
@@ -312,7 +288,29 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
SUN4I_TCON_GCTL_IOMAP_MASK,
SUN4I_TCON_GCTL_IOMAP_TCON1);
}
-EXPORT_SYMBOL(sun4i_tcon1_mode_set);
+
+void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ switch (encoder->encoder_type) {
+ case DRM_MODE_ENCODER_NONE:
+ sun4i_tcon0_mode_set(tcon, mode);
+ break;
+ case DRM_MODE_ENCODER_TVDAC:
+ /*
+ * FIXME: Undocumented bits
+ */
+ if (tcon->quirks->has_unknown_mux)
+ regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, 1);
+ /* Fallthrough */
+ case DRM_MODE_ENCODER_TMDS:
+ sun4i_tcon1_mode_set(tcon, mode);
+ break;
+ default:
+ DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
+ }
+}
+EXPORT_SYMBOL(sun4i_tcon_mode_set);
static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
struct sun4i_crtc *scrtc)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 824732c90a2a..a318e5ccb612 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -184,15 +184,9 @@ struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
+void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
+ struct drm_display_mode *mode);
void sun4i_tcon_set_status(struct sun4i_tcon *crtc, struct drm_encoder *encoder,
bool enable);
-/* Mode Related Controls */
-void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
- struct drm_encoder *encoder);
-void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
- struct drm_display_mode *mode);
-void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
- struct drm_display_mode *mode);
-
#endif /* __SUN4I_TCON_H__ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 78d6cf77fdd3..69b9f8d98a13 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -24,7 +24,6 @@
#include "sun4i_crtc.h"
#include "sun4i_drv.h"
-#include "sun4i_tcon.h"
#include "sunxi_engine.h"
#define SUN4I_TVE_EN_REG 0x000
@@ -374,13 +373,8 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
- struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
- struct sun4i_tcon *tcon = crtc->tcon;
const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
- sun4i_tcon1_mode_set(tcon, mode);
- sun4i_tcon_set_mux(tcon, 1, encoder);
-
/* Enable and map the DAC to the output */
regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
SUN4I_TVE_EN_DAC_MAP_MASK,
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Chen-Yu Tsai <wens@csie.org> |
|---|---|
| Date | 2017-07-14 06:00 +0200 |
| Subject | Re: [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode |
| Message-ID | <u2ZVL-69C-3@gated-at.bofh.it> |
| In reply to | #1686558 |
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Just like we did for the TCON enable and disable, for historical reasons we
> used to rely on the encoders calling the TCON mode_set function, while the
> CRTC has a callback for that.
>
> Let's implement it in order to reduce the boilerplate code.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> drivers/gpu/drm/sun4i/sun4i_crtc.c | 11 ++++-
> drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 1 +-
> drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 7 +---
> drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c | 1 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 15 +------
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 56 ++++++++++------------
> drivers/gpu/drm/sun4i/sun4i_tcon.h | 10 +----
> drivers/gpu/drm/sun4i/sun4i_tv.c | 6 +--
> 8 files changed, 40 insertions(+), 67 deletions(-)
>
[...]
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index dc70bc2a42a5..c4407910dfaf 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -106,29 +106,6 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
> }
> EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
>
> -void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
> - struct drm_encoder *encoder)
> -{
> - u32 val;
> -
> - if (!tcon->quirks->has_unknown_mux)
> - return;
> -
> - if (channel != 1)
> - return;
> -
> - if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
> - val = 1;
> - else
> - val = 0;
> -
> - /*
> - * FIXME: Undocumented bits
> - */
> - regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
> -}
> -EXPORT_SYMBOL(sun4i_tcon_set_mux);
> -
> static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
> int channel)
> {
> @@ -147,8 +124,8 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
> return delay;
> }
>
> -void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> - struct drm_display_mode *mode)
> +static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> + struct drm_display_mode *mode)
Nit on the side: maybe we could mark mode as constant?
Since the function doesn't change it. Same applies to the
other mode_set functions. But this could be left to another
patch.
> {
> unsigned int bp, hsync, vsync;
> u8 clk_delay;
> @@ -221,10 +198,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> /* Enable the output on the pins */
> regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
> }
> -EXPORT_SYMBOL(sun4i_tcon0_mode_set);
>
> -void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> - struct drm_display_mode *mode)
> +static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> + struct drm_display_mode *mode)
> {
> unsigned int bp, hsync, vsync, vtotal;
> u8 clk_delay;
> @@ -312,7 +288,29 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> SUN4I_TCON_GCTL_IOMAP_MASK,
> SUN4I_TCON_GCTL_IOMAP_TCON1);
> }
> -EXPORT_SYMBOL(sun4i_tcon1_mode_set);
> +
> +void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
> + struct drm_display_mode *mode)
(also mark encoder as const?)
> +{
> + switch (encoder->encoder_type) {
> + case DRM_MODE_ENCODER_NONE:
> + sun4i_tcon0_mode_set(tcon, mode);
> + break;
> + case DRM_MODE_ENCODER_TVDAC:
> + /*
> + * FIXME: Undocumented bits
> + */
> + if (tcon->quirks->has_unknown_mux)
> + regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, 1);
> + /* Fallthrough */
> + case DRM_MODE_ENCODER_TMDS:
> + sun4i_tcon1_mode_set(tcon, mode);
IIRC you need to clear the mux bit here. So ...
> + break;
> + default:
> + DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
> + }
I think keeping the muxing in a separate function would be cleaner.
The above is already slightly messy if you add the bit clearing part.
With all the other muxing possibilities in the other SoC this is
going to get really messy.
> +}
> +EXPORT_SYMBOL(sun4i_tcon_mode_set);
>
> static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
> struct sun4i_crtc *scrtc)
[...]
Thanks for working on this. Now we've decoupled the TCON/CRTC code
from all the encoders.
Regards
ChenYu
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-20 15:40 +0200 |
| Subject | Re: [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode |
| Message-ID | <u5jQo-87F-7@gated-at.bofh.it> |
| In reply to | #1687052 |
[Multipart message — attachments visible in raw view] — view raw
On Fri, Jul 14, 2017 at 11:56:18AM +0800, Chen-Yu Tsai wrote:
> On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Just like we did for the TCON enable and disable, for historical reasons we
> > used to rely on the encoders calling the TCON mode_set function, while the
> > CRTC has a callback for that.
> >
> > Let's implement it in order to reduce the boilerplate code.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> > drivers/gpu/drm/sun4i/sun4i_crtc.c | 11 ++++-
> > drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c | 1 +-
> > drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 7 +---
> > drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c | 1 +-
> > drivers/gpu/drm/sun4i/sun4i_rgb.c | 15 +------
> > drivers/gpu/drm/sun4i/sun4i_tcon.c | 56 ++++++++++------------
> > drivers/gpu/drm/sun4i/sun4i_tcon.h | 10 +----
> > drivers/gpu/drm/sun4i/sun4i_tv.c | 6 +--
> > 8 files changed, 40 insertions(+), 67 deletions(-)
> >
>
> [...]
>
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > index dc70bc2a42a5..c4407910dfaf 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > @@ -106,29 +106,6 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
> > }
> > EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
> >
> > -void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
> > - struct drm_encoder *encoder)
> > -{
> > - u32 val;
> > -
> > - if (!tcon->quirks->has_unknown_mux)
> > - return;
> > -
> > - if (channel != 1)
> > - return;
> > -
> > - if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
> > - val = 1;
> > - else
> > - val = 0;
> > -
> > - /*
> > - * FIXME: Undocumented bits
> > - */
> > - regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
> > -}
> > -EXPORT_SYMBOL(sun4i_tcon_set_mux);
> > -
> > static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
> > int channel)
> > {
> > @@ -147,8 +124,8 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
> > return delay;
> > }
> >
> > -void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> > - struct drm_display_mode *mode)
> > +static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> > + struct drm_display_mode *mode)
>
> Nit on the side: maybe we could mark mode as constant?
> Since the function doesn't change it. Same applies to the
> other mode_set functions. But this could be left to another
> patch.
We totally should. I'll do it.
> > {
> > unsigned int bp, hsync, vsync;
> > u8 clk_delay;
> > @@ -221,10 +198,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> > /* Enable the output on the pins */
> > regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
> > }
> > -EXPORT_SYMBOL(sun4i_tcon0_mode_set);
> >
> > -void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> > - struct drm_display_mode *mode)
> > +static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> > + struct drm_display_mode *mode)
> > {
> > unsigned int bp, hsync, vsync, vtotal;
> > u8 clk_delay;
> > @@ -312,7 +288,29 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> > SUN4I_TCON_GCTL_IOMAP_MASK,
> > SUN4I_TCON_GCTL_IOMAP_TCON1);
> > }
> > -EXPORT_SYMBOL(sun4i_tcon1_mode_set);
> > +
> > +void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
> > + struct drm_display_mode *mode)
>
> (also mark encoder as const?)
Yep.
> > +{
> > + switch (encoder->encoder_type) {
> > + case DRM_MODE_ENCODER_NONE:
> > + sun4i_tcon0_mode_set(tcon, mode);
> > + break;
> > + case DRM_MODE_ENCODER_TVDAC:
> > + /*
> > + * FIXME: Undocumented bits
> > + */
> > + if (tcon->quirks->has_unknown_mux)
> > + regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, 1);
> > + /* Fallthrough */
> > + case DRM_MODE_ENCODER_TMDS:
> > + sun4i_tcon1_mode_set(tcon, mode);
>
> IIRC you need to clear the mux bit here. So ...
>
> > + break;
> > + default:
> > + DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
> > + }
>
> I think keeping the muxing in a separate function would be cleaner.
> The above is already slightly messy if you add the bit clearing part.
> With all the other muxing possibilities in the other SoC this is
> going to get really messy.
Ok.
> > +}
> > +EXPORT_SYMBOL(sun4i_tcon_mode_set);
> >
> > static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
> > struct sun4i_crtc *scrtc)
>
> [...]
>
> Thanks for working on this. Now we've decoupled the TCON/CRTC code
> from all the encoders.
Yeah, I still have mixed feelings about this, but it was the sensible
thing I guess.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup |
| Message-ID | <u2N8f-6Ff-21@gated-at.bofh.it> |
| In reply to | #1686553 |
Some channel0 setup has to be done, no matter what the output interface is
(RGB, CPU, LVDS). Move that code into a common function in order to avoid
duplication.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index a3bbf9994cfa..f051862d635e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -125,15 +125,26 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
return delay;
}
-static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
- struct drm_display_mode *mode)
+static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
+ struct drm_display_mode *mode)
+{
+ /* Configure the dot clock */
+ clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
+
+ /* Set the resolution */
+ regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
+ SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
+ SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
+}
+
+static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
+ struct drm_display_mode *mode)
{
unsigned int bp, hsync, vsync;
u8 clk_delay;
u32 val = 0;
- /* Configure the dot clock */
- clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
+ sun4i_tcon0_mode_set_common(tcon, mode);
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
@@ -141,11 +152,6 @@ static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
SUN4I_TCON0_CTL_CLK_DELAY_MASK,
SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
- /* Set the resolution */
- regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
- SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
- SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
-
/*
* This is called a backporch in the register documentation,
* but it really is the back porch + hsync
@@ -295,7 +301,7 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
{
switch (encoder->encoder_type) {
case DRM_MODE_ENCODER_NONE:
- sun4i_tcon0_mode_set(tcon, mode);
+ sun4i_tcon0_mode_set_rgb(tcon, mode);
break;
case DRM_MODE_ENCODER_TVDAC:
/*
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | kbuild test robot <lkp@intel.com> |
|---|---|
| Date | 2017-07-14 12:00 +0200 |
| Subject | Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup |
| Message-ID | <u35ya-1D9-21@gated-at.bofh.it> |
| In reply to | #1686560 |
[Multipart message — attachments visible in raw view] — view raw
Hi Maxime,
[auto build test ERROR on next-20170710]
[cannot apply to mripard/sunxi/for-next robh/for-next regmap/for-next v4.12 v4.12-rc7 v4.12-rc6 v4.12]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Allwinner-MIPI-DSI-support/20170714-123103
config: arm-sunxi_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
All errors (new ones prefixed by >>):
drivers/gpu/drm/sun4i/sun4i_tcon.c: In function 'sun4i_tcon0_mode_set_common':
>> drivers/gpu/drm/sun4i/sun4i_tcon.c:132:2: error: implicit declaration of function 'clk_set_rate_protect' [-Werror=implicit-function-declaration]
clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
^~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/clk_set_rate_protect +132 drivers/gpu/drm/sun4i/sun4i_tcon.c
127
128 static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
129 struct drm_display_mode *mode)
130 {
131 /* Configure the dot clock */
> 132 clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
133
134 /* Set the resolution */
135 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
136 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
137 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
138 }
139
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[toc] | [prev] | [next] | [standalone]
| From | Chen-Yu Tsai <wens@csie.org> |
|---|---|
| Date | 2017-07-18 05:50 +0200 |
| Subject | Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup |
| Message-ID | <u4rGi-5CQ-1@gated-at.bofh.it> |
| In reply to | #1686560 |
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Some channel0 setup has to be done, no matter what the output interface is
> (RGB, CPU, LVDS). Move that code into a common function in order to avoid
> duplication.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 ++++++++++++++++----------
> 1 file changed, 16 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index a3bbf9994cfa..f051862d635e 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -125,15 +125,26 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
> return delay;
> }
>
> -static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> - struct drm_display_mode *mode)
> +static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
> + struct drm_display_mode *mode)
> +{
> + /* Configure the dot clock */
> + clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
I'd prefer not changing APIs in a code move. It also means we could
apply this sooner than later. Otherwise,
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
> +
> + /* Set the resolution */
> + regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
> + SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
> + SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
> +}
> +
> +static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
> + struct drm_display_mode *mode)
> {
> unsigned int bp, hsync, vsync;
> u8 clk_delay;
> u32 val = 0;
>
> - /* Configure the dot clock */
> - clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
> + sun4i_tcon0_mode_set_common(tcon, mode);
>
> /* Adjust clock delay */
> clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
> @@ -141,11 +152,6 @@ static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> SUN4I_TCON0_CTL_CLK_DELAY_MASK,
> SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
>
> - /* Set the resolution */
> - regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
> - SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
> - SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
> -
> /*
> * This is called a backporch in the register documentation,
> * but it really is the back porch + hsync
> @@ -295,7 +301,7 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
> {
> switch (encoder->encoder_type) {
> case DRM_MODE_ENCODER_NONE:
> - sun4i_tcon0_mode_set(tcon, mode);
> + sun4i_tcon0_mode_set_rgb(tcon, mode);
> break;
> case DRM_MODE_ENCODER_TVDAC:
> /*
> --
> git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-20 16:00 +0200 |
| Subject | Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup |
| Message-ID | <u5k9I-8gF-9@gated-at.bofh.it> |
| In reply to | #1689645 |
[Multipart message — attachments visible in raw view] — view raw
On Tue, Jul 18, 2017 at 11:41:36AM +0800, Chen-Yu Tsai wrote:
> On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Some channel0 setup has to be done, no matter what the output interface is
> > (RGB, CPU, LVDS). Move that code into a common function in order to avoid
> > duplication.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> > drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 ++++++++++++++++----------
> > 1 file changed, 16 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > index a3bbf9994cfa..f051862d635e 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > @@ -125,15 +125,26 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
> > return delay;
> > }
> >
> > -static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> > - struct drm_display_mode *mode)
> > +static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
> > + struct drm_display_mode *mode)
> > +{
> > + /* Configure the dot clock */
> > + clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
>
> I'd prefer not changing APIs in a code move. It also means we could
> apply this sooner than later. Otherwise,
You're right, I've changed it.
> Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 16/18] arm: dts: sun8i: a33: Add the DSI-related nodes |
| Message-ID | <u2N8f-6Ff-25@gated-at.bofh.it> |
| In reply to | #1686553 |
The A33 has a MIPI-DSI block, along with its D-PHY. Let's add it in order
to use it in the relevant boards.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/boot/dts/sun8i-a33.dtsi | 50 ++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 22660919bd08..18d1bf9f8e84 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -236,10 +236,14 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
+
+ tcon0_out_dsi0: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&dsi0_in_tcon0>;
+ };
};
};
};
-
crypto: crypto-engine@01c15000 {
compatible = "allwinner,sun4i-a10-crypto";
reg = <0x01c15000 0x1000>;
@@ -280,6 +284,50 @@
#io-channel-cells = <0>;
};
+ dsi0: dsi@01ca0000 {
+ compatible = "allwinner,sun6i-a31-mipi-dsi";
+ reg = <0x01ca0000 0x1000>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_MIPI_DSI>,
+ <&ccu CLK_DSI_SCLK>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_MIPI_DSI>;
+ phys = <&dphy0>;
+ phy-names = "dphy";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dsi0_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ dsi0_in_tcon0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_out_dsi0>;
+ };
+ };
+ };
+ };
+
+ dphy0: d-phy@01ca1000 {
+ compatible = "allwinner,sun6i-a31-mipi-dphy";
+ reg = <0x01ca1000 0x1000>;
+ clocks = <&ccu CLK_BUS_MIPI_DSI>,
+ <&ccu CLK_DSI_DPHY>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_MIPI_DSI>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #phy-cells = <0>;
+ };
+
fe0: display-frontend@01e00000 {
compatible = "allwinner,sun8i-a33-display-frontend";
reg = <0x01e00000 0x20000>;
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
| From | Maxime Ripard <maxime.ripard@free-electrons.com> |
|---|---|
| Date | 2017-07-13 16:20 +0200 |
| Subject | [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range |
| Message-ID | <u2N8f-6Ff-29@gated-at.bofh.it> |
| In reply to | #1686553 |
It seems like the dotclock dividers are a bit less strict range, and can
operate even with a smaller than 6 divider. Loose the boundaries a bit.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_dotclock.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
index d401156490f3..0b844c0dd102 100644
--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
+++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
@@ -77,7 +77,25 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
u8 best_div = 1;
int i;
- for (i = 6; i <= 127; i++) {
+ /*
+ * There's something odd here.
+ *
+ * In the A13 user manual, this is stated to be >= 6 when
+ * dclk1 and dclk2 are used (without any hint on how to use
+ * them), and >= 4 when only dclk is used.
+ *
+ * In the A33 user manual, when only dclk is used, it is set
+ * to be >= 6 in the former case, and >= 1 in the
+ * latter. There's also some (obscure) explanations about the
+ * dclk1 and dclk2 vs dclk that seems to be in the upper 4
+ * bits. What those clocks are and what bit does what is not
+ * really clear.
+ *
+ * On the A33 however, while something lower than 4 works, it
+ * does have a few artifacts. Let's not use those values, and
+ * see how it goes.
+ */
+ for (i = 4; i <= 127; i++) {
unsigned long ideal = rate * i;
unsigned long rounded;
--
git-series 0.9.1
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | linux.kernel
csiph-web