Skip to contentSkip to conversation

drm/sun4i: Allwinner MIPI-DSI Burst mode support

PATCH In review Jagan Teki 4 participants 39 messages Nov 16, 2018 – Dec 14, 2018

Subsystems (7)
lore
Share & tools
lore

Jagan Teki

author maintainer
#0 lore raw

v2 cover drm/sun4i: Allwinner MIPI-DSI Burst mode support

This series support MIPI-DSI Burst mode on Allwinner platform, which is tested in burst supported panel in Pine64-LTS board.

Series fixed few code changes commented in previous version[1] and it depends on A64 MIPI-DSI series[2]

Changes for v2:
- add separate function for setup_inst_delay computation
- moved instruction loop seletion below delay compuation
- add separate function for dsi_get_timings and call for non-burst mode
- simplify burst mode timings compuatation
- add new patches, for tcon0 probing during dsi_bind
- add code to get the tcon0 divider value
- add multiple functions to get line_num, edge0, edge1
- squash 'enable burst mode' patch into 'Setup burst mode'
- fixed commit message of 'Enable burst mode HBP, HSA_HSE' s/enable/disable
- collect Rob R-b tag on panel dt-bindings patch
- panel driver changes,
- dropped unneeded include files
- s/fy07024di26a30d/feiyang function, variable names
- use DRM_DEV_ERROR in panel driver
- add set_display_on .enable
- moved regulator enablement to .prepare
- handle erro statements and release them properly during probe
- remove panel if mipi_dsi_attach failed
- fixed MODULE_LICENSE
- update MAINTAINERS file about the panel
- add comments on dts about exact regulators used in schematics

[1] https://patchwork.kernel.org/cover/10666597/
[2] https://patchwork.kernel.org/cover/10680247/

Any inputs,
Jagan.

Jagan Teki (12):
drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction
delay
drm/sun4i: sun6i_mipi_dsi: Support instruction loop selection drm/sun4i: sun6i_mipi_dsi: Setup burst mode timings
drm/sun4i: sun6i_mipi_dsi: Simplify drq set to support all modes drm/sun4i: tcon: Export get tcon0 routine
drm/sun4i: sun6i_mipi_dsi: Probe tcon0 during dsi_bind
drm/sun4i: sun6i_mipi_dsi: Setup burst mode
drm/sun4i: sun6i_mipi_dsi: Enable 2byte trail for 4-lane burst mode drm/sun4i: sun6i_mipi_dsi: Enable burst mode HBP, HSA_HSE
dt-bindings: panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel
[DO NOT MERGE] arm64: allwinner: a64: pine64-lts: Enable Feiyang FY07024DI26A30-D DSI
panel

 .../display/panel/feiyang,fy07024di26a30d.txt |  20 ++
 MAINTAINERS                                   |   6 +
 .../dts/allwinner/sun50i-a64-pine64-lts.dts   |  37 +++
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_tcon.c            |   3 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.h            |   1 +
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c        | 264 ++++++++++++----
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h        |   1 +
 10 files changed, 567 insertions(+), 61 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
Signature · 1 line
2.18.0.321.gffc6fa0e3
author maintainer
#1 lore raw

PATCH v2 1/12 drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;

So use the similar computation for loop N1 delay.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +19 -1
index def145086a5c..43ab7127d428 100644
@@ -379,6 +379,24 @@ static u16 sun6i_dsi_get_timings_vblk(struct sun6i_dsi *dsi,
 	return vblk;
 }
 
+static u16 sun6i_dsi_setup_inst_delay(struct sun6i_dsi *dsi,
+				      struct drm_display_mode *mode)
+{
+	struct mipi_dsi_device *device = dsi->device;
+	u32 hsync_porch, dclk;
+	u16 delay;
+
+	hsync_porch = (mode->htotal - mode->hdisplay);
+	dclk = (mode->clock / 1000);
+
+	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		delay = ((hsync_porch * 150) / (dclk * 8)) - 50;
+	else
+		delay = 50 - 1;
+
+	return delay;
+}
+
 static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 					   struct drm_display_mode *mode)
 {
@@ -418,7 +436,7 @@ static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
 static void sun6i_dsi_setup_inst_loop(struct sun6i_dsi *dsi,
 				      struct drm_display_mode *mode)
 {
-	u16 delay = 50 - 1;
+	u16 delay = sun6i_dsi_setup_inst_delay(dsi, mode);
 
 	regmap_write(dsi->regs, SUN6I_DSI_INST_LOOP_NUM_REG(0),
 		     SUN6I_DSI_INST_LOOP_NUM_N0(50 - 1) |
Signature · 1 line
2.18.0.321.gffc6fa0e3
#2 lore raw

Re: [PATCH v2 01/12] drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

Quoted 6 lines · Jagan Teki

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

Quoted 8 lines

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;

So use the similar computation for loop N1 delay.

*why* are you doing this? What is it fixing? on which devices?

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#3 lore raw

Re: [PATCH v2 01/12] drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

Quoted 13 lines · Maxime Ripard
Quoted 11 lines · Jagan Teki

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;
Quoted 5 lines
Quoted 3 lines

So use the similar computation for loop N1 delay.

*why* are you doing this? What is it fixing? on which devices?

You mentioned the separate function to compute the delay for all modes [1], ie what I did. did I missing anything?

[1] https://patchwork.kernel.org/patch/10666599/

#4 lore raw

Re: [PATCH v2 01/12] drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

Quoted 14 lines · Jagan Teki
Quoted 13 lines · Maxime Ripard
Quoted 11 lines · Jagan Teki

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

So use the similar computation for loop N1 delay.

*why* are you doing this? What is it fixing? on which devices?

You mentioned the separate function to compute the delay for all modes [1], ie what I did. did I missing anything?

You're missing that you are never explaining why that patch is needed in the first place. Or answering the question I asked a couple of lines above.

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#5 lore raw

Re: [PATCH v2 01/12] drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

Quoted 20 lines · Maxime Ripard
Quoted 18 lines · Jagan Teki
Quoted 17 lines · Maxime Ripard
Quoted 14 lines · Jagan Teki

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;

So use the similar computation for loop N1 delay.

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

*why* are you doing this? What is it fixing? on which devices?

You mentioned the separate function to compute the delay for all modes [1], ie what I did. did I missing anything?

You're missing that you are never explaining why that patch is needed in the first place. Or answering the question I asked a couple of lines above.

OK.

The instruction delay varies between video and burst mode. for burst mode panels it is computed based on the panel clock along with horizontal sync+porch timings.

Got it, the same I need to update on commit, since you asked about separate delay route I thought you get the proper details.

#6 lore raw

Re: [PATCH v2 01/12] drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

Quoted 30 lines · Jagan Teki
Quoted 20 lines · Maxime Ripard
Quoted 18 lines · Jagan Teki
Quoted 17 lines · Maxime Ripard
Quoted 14 lines · Jagan Teki

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;

So use the similar computation for loop N1 delay.

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

*why* are you doing this? What is it fixing? on which devices?

You mentioned the separate function to compute the delay for all modes [1], ie what I did. did I missing anything?

You're missing that you are never explaining why that patch is needed in the first place. Or answering the question I asked a couple of lines above.

Quoted 5 lines

OK.

The instruction delay varies between video and burst mode. for burst mode panels it is computed based on the panel clock along with horizontal sync+porch timings.

You're still stating a fact. What issue, that you experienced, are you trying to solve here?

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
#7 lore raw

Re: [PATCH v2 01/12] drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

Quoted 32 lines · Maxime Ripard
Quoted 30 lines · Jagan Teki
Quoted 28 lines · Maxime Ripard
Quoted 14 lines · Jagan Teki
Quoted 13 lines · Maxime Ripard
Quoted 11 lines · Jagan Teki

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

So use the similar computation for loop N1 delay.

*why* are you doing this? What is it fixing? on which devices?

You mentioned the separate function to compute the delay for all modes [1], ie what I did. did I missing anything?

You're missing that you are never explaining why that patch is needed in the first place. Or answering the question I asked a couple of lines above.

Quoted 8 lines
Quoted 5 lines

OK.

The instruction delay varies between video and burst mode. for burst mode panels it is computed based on the panel clock along with horizontal sync+porch timings.

You're still stating a fact. What issue, that you experienced, are you trying to solve here?

IIRC that's what BSP driver does. Otherwise panels that use burst mode just don't work.

Quoted 6 lines

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

author maintainer
#8 lore raw

Re: [PATCH v2 01/12] drm/sun4i: sun6i_mipi_dsi: Compute burst mode loop N1 instruction delay

In reply to Maxime Ripard
Quoted 32 lines · Maxime Ripard
Quoted 30 lines · Jagan Teki
Quoted 28 lines · Maxime Ripard
Quoted 14 lines · Jagan Teki
Quoted 13 lines · Maxime Ripard
Quoted 11 lines · Jagan Teki

Loop N1 instruction delay for burst mode lcd panel are computed as per BSP code.

Reference code is available in BSP (from linux-sunxi drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_dev[sel]->dsi_inst_loop_num.bits.loop_n1= (panel->lcd_ht-panel->lcd_x)*(150)/(panel->lcd_dclk_freq*8) - 50; => (((mode->htotal - mode->hdisplay) * 150) /

     ((mode->clock / 1000) * 8)) - 50;
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

So use the similar computation for loop N1 delay.

*why* are you doing this? What is it fixing? on which devices?

You mentioned the separate function to compute the delay for all modes [1], ie what I did. did I missing anything?

You're missing that you are never explaining why that patch is needed in the first place. Or answering the question I asked a couple of lines above.

Quoted 8 lines
Quoted 5 lines

OK.

The instruction delay varies between video and burst mode. for burst mode panels it is computed based on the panel clock along with horizontal sync+porch timings.

You're still stating a fact. What issue, that you experienced, are you trying to solve here?

This change is specific for burst mode instruction delay. for non-burst it is 50 - 1 and for burst mode it is computed as mentioned in commit message. Both things are available in BSP code. and without this burst mode panels not working with existing (50 - 1)

author maintainer
#9 lore raw

PATCH v2 2/12 drm/sun4i: sun6i_mipi_dsi: Support instruction loop selection

In reply to Jagan Teki

Instruction loop selection would require before writing loop number registers, so enable idle, LP11 bits on loop selection register.

Reference code available in BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

(dsi_dev[sel]->dsi_inst_loop_sel.dwval = 2<<(4*DSI_INST_ID_LP11) |

	3<<(4*DSI_INST_ID_DLY);
---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -0
index 43ab7127d428..3ac002c4d8b3 100644
@@ -438,6 +438,9 @@ static void sun6i_dsi_setup_inst_loop(struct sun6i_dsi *dsi,
 {
 	u16 delay = sun6i_dsi_setup_inst_delay(dsi, mode);
 
+	regmap_write(dsi->regs, SUN6I_DSI_INST_LOOP_SEL_REG,
+		     DSI_INST_ID_HSC  << (4 * DSI_INST_ID_LP11) |
+		     DSI_INST_ID_HSD  << (4 * DSI_INST_ID_DLY));
 	regmap_write(dsi->regs, SUN6I_DSI_INST_LOOP_NUM_REG(0),
 		     SUN6I_DSI_INST_LOOP_NUM_N0(50 - 1) |
 		     SUN6I_DSI_INST_LOOP_NUM_N1(delay));
Signature · 1 line
2.18.0.321.gffc6fa0e3
author maintainer
#10 lore raw

PATCH v2 3/12 drm/sun4i: sun6i_mipi_dsi: Setup burst mode timings

In reply to Jagan Teki

Burst mode display timings are different from convectional video mode so update the horizontal and vertical timings.

Reference code taken from BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_hsa = 0;
dsi_hbp = 0;
dsi_hact = x*dsi_pixel_bits[format]/8;
dsi_hblk = dsi_hact;
dsi_hfp = 0;
dsi_vblk = 0;

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 128 +++++++++++++++----------
 1 file changed, 80 insertions(+), 48 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +80 -48
index 3ac002c4d8b3..efd08bfd0cb8 100644
@@ -153,6 +153,14 @@
 
 #define SUN6I_DSI_CMD_TX_REG(n)		(0x300 + (n) * 0x04)
 
+struct sun6i_dsi_timings {
+	u16 hsa;
+	u16 hbp;
+	u16 hblk;
+	u16 hfp;
+	u16 vblk;
+};
+
 enum sun6i_dsi_start_inst {
 	DSI_START_LPRX,
 	DSI_START_LPTX,
@@ -379,6 +387,60 @@ static u16 sun6i_dsi_get_timings_vblk(struct sun6i_dsi *dsi,
 	return vblk;
 }
 
+static void sun6i_dsi_get_timings(struct sun6i_dsi *dsi,
+				  struct drm_display_mode *mode,
+				  struct sun6i_dsi_timings *timings)
+{
+	struct mipi_dsi_device *device = dsi->device;
+	unsigned int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8;
+	u16 hsa, hbp, hblk, hfp, vblk;
+
+	/*
+	 * A sync period is composed of a blanking packet (4 bytes +
+	 * payload + 2 bytes) and a sync event packet (4 bytes).
+	 * Its minimal size is therefore 10 bytes
+	 */
+#define HSA_PACKET_OVERHEAD	10
+	hsa = max((unsigned int)HSA_PACKET_OVERHEAD,
+		  (mode->hsync_end - mode->hsync_start) * Bpp -
+		  HSA_PACKET_OVERHEAD);
+
+	/*
+	 * The backporch is set using a blanking packet (4 bytes +
+	 * payload + 2 bytes). Its minimal size is therefore 6 bytes
+	 */
+#define HBP_PACKET_OVERHEAD	6
+	hbp = max((unsigned int)HBP_PACKET_OVERHEAD,
+		  (mode->htotal - mode->hsync_end) * Bpp - HBP_PACKET_OVERHEAD);
+
+	/*
+	 * hblk seems to be the line + porches length.
+	 * The blank is set using a blanking packet (4 bytes + 4 bytes
+	 * + payload + 2 bytes). So minimal size is 10 bytes
+	 */
+#define HBLK_PACKET_OVERHEAD	10
+	hblk = max((unsigned int)HBLK_PACKET_OVERHEAD,
+		   (mode->htotal - (mode->hsync_end - mode->hsync_start)) *
+		   Bpp - HBLK_PACKET_OVERHEAD);
+
+	/*
+	 * The frontporch is set using a blanking packet (4 bytes +
+	 * payload + 2 bytes). Its minimal size is therefore 6 bytes
+	 */
+#define HFP_PACKET_OVERHEAD	6
+	hfp = max((unsigned int)HFP_PACKET_OVERHEAD,
+		  (mode->hsync_start - mode->hdisplay) * Bpp -
+		  HFP_PACKET_OVERHEAD);
+
+	vblk = sun6i_dsi_get_timings_vblk(dsi, mode, hblk);
+
+	timings->hsa = hsa;
+	timings->hbp = hbp;
+	timings->hblk = hblk;
+	timings->hfp = hfp;
+	timings->vblk = vblk;
+}
+
 static u16 sun6i_dsi_setup_inst_delay(struct sun6i_dsi *dsi,
 				      struct drm_display_mode *mode)
 {
@@ -506,52 +568,22 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
 {
 	struct mipi_dsi_device *device = dsi->device;
 	unsigned int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8;
-	u16 hbp, hfp, hsa, hblk, vblk;
+	struct sun6i_dsi_timings timings;
 	size_t bytes;
 	u8 *buffer;
 
 	/* Do all timing calculations up front to allocate buffer space */
 
-	/*
-	 * A sync period is composed of a blanking packet (4 bytes +
-	 * payload + 2 bytes) and a sync event packet (4 bytes). Its
-	 * minimal size is therefore 10 bytes
-	 */
-#define HSA_PACKET_OVERHEAD	10
-	hsa = max((unsigned int)HSA_PACKET_OVERHEAD,
-		  (mode->hsync_end - mode->hsync_start) * Bpp - HSA_PACKET_OVERHEAD);
+	memset(&timings, 0, sizeof(timings));
 
-	/*
-	 * The backporch is set using a blanking packet (4 bytes +
-	 * payload + 2 bytes). Its minimal size is therefore 6 bytes
-	 */
-#define HBP_PACKET_OVERHEAD	6
-	hbp = max((unsigned int)HBP_PACKET_OVERHEAD,
-		  (mode->htotal - mode->hsync_end) * Bpp - HBP_PACKET_OVERHEAD);
-
-	/*
-	 * The frontporch is set using a blanking packet (4 bytes +
-	 * payload + 2 bytes). Its minimal size is therefore 6 bytes
-	 */
-#define HFP_PACKET_OVERHEAD	6
-	hfp = max((unsigned int)HFP_PACKET_OVERHEAD,
-		  (mode->hsync_start - mode->hdisplay) * Bpp -
-		  HFP_PACKET_OVERHEAD);
-
-	/*
-	 * hblk seems to be the line + porches length.
-	 * The blank is set using a blanking packet (4 bytes + 4 bytes +
-	 * payload + 2 bytes). So minimal size is 10 bytes
-	 */
-#define HBLK_PACKET_OVERHEAD	10
-	hblk = max((unsigned int)HBLK_PACKET_OVERHEAD,
-		   (mode->htotal - (mode->hsync_end - mode->hsync_start)) *
-		   Bpp - HBLK_PACKET_OVERHEAD);
-
-	vblk = sun6i_dsi_get_timings_vblk(dsi, mode, hblk);
+	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		timings.hblk = (mode->hdisplay * Bpp);
+	else
+		sun6i_dsi_get_timings(dsi, mode, &timings);
 
 	/* How many bytes do we need to send all payloads? */
-	bytes = max_t(size_t, max(max(hfp, hblk), max(hsa, hbp)), vblk);
+	bytes = max_t(size_t, max(max(timings.hfp, timings.hblk),
+		      max(timings.hsa, timings.hbp)), timings.vblk);
 	buffer = kmalloc(bytes, GFP_KERNEL);
 	if (WARN_ON(!buffer))
 		return;
@@ -590,33 +622,33 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
 
 	/* sync */
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA0_REG,
-		     sun6i_dsi_build_blk0_pkt(device->channel, hsa));
+		     sun6i_dsi_build_blk0_pkt(device->channel, timings.hsa));
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA1_REG,
-		     sun6i_dsi_build_blk1_pkt(0, buffer, hsa));
+		     sun6i_dsi_build_blk1_pkt(0, buffer, timings.hsa));
 
 	/* backporch */
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP0_REG,
-		     sun6i_dsi_build_blk0_pkt(device->channel, hbp));
+		     sun6i_dsi_build_blk0_pkt(device->channel, timings.hbp));
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP1_REG,
-		     sun6i_dsi_build_blk1_pkt(0, buffer, hbp));
+		     sun6i_dsi_build_blk1_pkt(0, buffer, timings.hbp));
 
 	/* frontporch */
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP0_REG,
-		     sun6i_dsi_build_blk0_pkt(device->channel, hfp));
+		     sun6i_dsi_build_blk0_pkt(device->channel, timings.hfp));
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP1_REG,
-		     sun6i_dsi_build_blk1_pkt(0, buffer, hfp));
+		     sun6i_dsi_build_blk1_pkt(0, buffer, timings.hfp));
 
 	/* hblk */
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK0_REG,
-		     sun6i_dsi_build_blk0_pkt(device->channel, hblk));
+		     sun6i_dsi_build_blk0_pkt(device->channel, timings.hblk));
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK1_REG,
-		     sun6i_dsi_build_blk1_pkt(0, buffer, hblk));
+		     sun6i_dsi_build_blk1_pkt(0, buffer, timings.hblk));
 
 	/* vblk */
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK0_REG,
-		     sun6i_dsi_build_blk0_pkt(device->channel, vblk));
+		     sun6i_dsi_build_blk0_pkt(device->channel, timings.vblk));
 	regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK1_REG,
-		     sun6i_dsi_build_blk1_pkt(0, buffer, vblk));
+		     sun6i_dsi_build_blk1_pkt(0, buffer, timings.vblk));
 
 	kfree(buffer);
 }
Signature · 1 line
2.18.0.321.gffc6fa0e3
#11 lore raw

Re: [PATCH v2 03/12] drm/sun4i: sun6i_mipi_dsi: Setup burst mode timings

Quoted 6 lines · Jagan Teki

Burst mode display timings are different from convectional video mode so update the horizontal and vertical timings.

Reference code taken from BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

Quoted 8 lines

dsi_hsa = 0;
dsi_hbp = 0;
dsi_hact = x*dsi_pixel_bits[format]/8;
dsi_hblk = dsi_hact;
dsi_hfp = 0;
dsi_vblk = 0;

How is that matching the code you have in the rest of your patch?

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#12 lore raw

Re: [PATCH v2 03/12] drm/sun4i: sun6i_mipi_dsi: Setup burst mode timings

Quoted 15 lines · Maxime Ripard
Quoted 13 lines · Jagan Teki

Burst mode display timings are different from convectional video mode so update the horizontal and vertical timings.

Reference code taken from BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

dsi_hsa = 0;
dsi_hbp = 0;
dsi_hact = x*dsi_pixel_bits[format]/8;
dsi_hblk = dsi_hact;
dsi_hfp = 0;
dsi_vblk = 0;

Quoted 3 lines
Quoted 1 line

How is that matching the code you have in the rest of your patch?

+ if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+ timings.hblk = (mode->hdisplay * Bpp);
+ else
+ sun6i_dsi_get_timings(dsi, mode, &timings);

It's again your request to "keep the couple of function to make more readable"

#13 lore raw

Re: [PATCH v2 03/12] drm/sun4i: sun6i_mipi_dsi: Setup burst mode timings

Quoted 25 lines · Jagan Teki
Quoted 18 lines · Maxime Ripard
Quoted 6 lines · Jagan Teki

Burst mode display timings are different from convectional video mode so update the horizontal and vertical timings.

Reference code taken from BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

Quoted 8 lines

dsi_hsa = 0;
dsi_hbp = 0;
dsi_hact = x*dsi_pixel_bits[format]/8;
dsi_hblk = dsi_hact;
dsi_hfp = 0;
dsi_vblk = 0;

How is that matching the code you have in the rest of your patch?

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +4 -0
+       if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+               timings.hblk = (mode->hdisplay * Bpp);
+       else
+               sun6i_dsi_get_timings(dsi, mode, &timings);
Quoted 2 lines

It's again your request to "keep the couple of function to make more readable"

That function in particular doesn't make it much more readable, but more importantly, your commit log doesn't match what you code does.

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#14 lore raw

Re: [PATCH v2 03/12] drm/sun4i: sun6i_mipi_dsi: Setup burst mode timings

Quoted 27 lines · Maxime Ripard
Quoted 25 lines · Jagan Teki
Quoted 18 lines · Maxime Ripard
Quoted 6 lines · Jagan Teki

Burst mode display timings are different from convectional video mode so update the horizontal and vertical timings.

Reference code taken from BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

Quoted 8 lines

dsi_hsa = 0;
dsi_hbp = 0;
dsi_hact = x*dsi_pixel_bits[format]/8;
dsi_hblk = dsi_hact;
dsi_hfp = 0;
dsi_vblk = 0;

How is that matching the code you have in the rest of your patch?

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +4 -0
+       if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+               timings.hblk = (mode->hdisplay * Bpp);
+       else
+               sun6i_dsi_get_timings(dsi, mode, &timings);
Quoted 5 lines
Quoted 2 lines

It's again your request to "keep the couple of function to make more readable"

That function in particular doesn't make it much more readable, but more importantly, your commit log doesn't match what you code does.

May be I can update the commit message if the function is OK. for burst most of the timings are 0 so I used structure with memset to keep not assigning 0's explicitly. otherwise do you have any suggestions, please let me know.

#15 lore raw

Re: [PATCH v2 03/12] drm/sun4i: sun6i_mipi_dsi: Setup burst mode timings

Quoted 31 lines · Jagan Teki
Quoted 30 lines · Maxime Ripard
Quoted 27 lines · Jagan Teki
Quoted 18 lines · Maxime Ripard
Quoted 6 lines · Jagan Teki

Burst mode display timings are different from convectional video mode so update the horizontal and vertical timings.

Reference code taken from BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

Quoted 8 lines

dsi_hsa = 0;
dsi_hbp = 0;
dsi_hact = x*dsi_pixel_bits[format]/8;
dsi_hblk = dsi_hact;
dsi_hfp = 0;
dsi_vblk = 0;

How is that matching the code you have in the rest of your patch?

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +4 -0
+       if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+               timings.hblk = (mode->hdisplay * Bpp);
+       else
+               sun6i_dsi_get_timings(dsi, mode, &timings);

It's again your request to "keep the couple of function to make more readable"

Quoted 7 lines
Quoted 2 lines

That function in particular doesn't make it much more readable, but more importantly, your commit log doesn't match what you code does.

May be I can update the commit message if the function is OK. for burst most of the timings are 0 so I used structure with memset to keep not assigning 0's explicitly. otherwise do you have any suggestions, please let me know.

Drop the part that move the timings setup to another function in this patch.

Thanks!
Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#16 lore raw

PATCH v2 4/12 drm/sun4i: sun6i_mipi_dsi: Simplify drq set to support all modes

In reply to Jagan Teki

Allwinner MIPI DSI DRQ set value can be varied with respective video modes.
- burst mode the set value is always 0
- video modes whose front porch greater than 20, the set value can be computed based front porch and bpp.
- video modes whose front porch is not greater than 20, the set value is simply 0

This patch simplifies existing drq set value code by grouping into sun6i_dsi_get_drq and support all video modes.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 38 ++++++++++++++++----------
 1 file changed, 23 insertions(+), 15 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +23 -15
index efd08bfd0cb8..d60955880c43 100644
@@ -363,6 +363,26 @@ static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi,
 		     SUN6I_DSI_INST_JUMP_CFG_NUM(1));
 };
 
+static int sun6i_dsi_get_drq(struct sun6i_dsi *dsi,
+			      struct drm_display_mode *mode)
+{
+	struct mipi_dsi_device *device = dsi->device;
+	int drq = 0;
+
+	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		return drq;
+
+	if ((mode->hsync_start - mode->hdisplay) > 20) {
+		/* Maaaaaagic */
+		u16 drq = (mode->hsync_start - mode->hdisplay) - 20;
+
+		drq *= mipi_dsi_pixel_format_to_bpp(device->format);
+		drq /= 32;
+	}
+
+	return drq;
+}
+
 static u16 sun6i_dsi_get_timings_vblk(struct sun6i_dsi *dsi,
 				      struct drm_display_mode *mode, u16 hblk)
 {
@@ -478,21 +498,9 @@ static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
 				  struct drm_display_mode *mode)
 {
-	struct mipi_dsi_device *device = dsi->device;
-	u32 val = 0;
-
-	if ((mode->hsync_start - mode->hdisplay) > 20) {
-		/* Maaaaaagic */
-		u16 drq = (mode->hsync_start - mode->hdisplay) - 20;
-
-		drq *= mipi_dsi_pixel_format_to_bpp(device->format);
-		drq /= 32;
-
-		val = (SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
-		       SUN6I_DSI_TCON_DRQ_SET(drq));
-	}
-
-	regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, val);
+	regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG,
+		     SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
+		     SUN6I_DSI_TCON_DRQ_SET(sun6i_dsi_get_drq(dsi, mode)));
 }
 
 static void sun6i_dsi_setup_inst_loop(struct sun6i_dsi *dsi,
Signature · 1 line
2.18.0.321.gffc6fa0e3
#17 lore raw

Re: [PATCH v2 04/12] drm/sun4i: sun6i_mipi_dsi: Simplify drq set to support all modes

Quoted 21 lines · Jagan Teki

Allwinner MIPI DSI DRQ set value can be varied with respective video modes.
- burst mode the set value is always 0
- video modes whose front porch greater than 20, the set value can be computed based front porch and bpp.
- video modes whose front porch is not greater than 20, the set value is simply 0

This patch simplifies existing drq set value code by grouping into sun6i_dsi_get_drq and support all video modes.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 38 ++++++++++++++++----------
 1 file changed, 23 insertions(+), 15 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +0 -0
index efd08bfd0cb8..d60955880c43 100644

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 370

Quoted 8 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
@@ -363,6 +363,26 @@ static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi,
 		     SUN6I_DSI_INST_JUMP_CFG_NUM(1));
 };
 
+static int sun6i_dsi_get_drq(struct sun6i_dsi *dsi,
+			      struct drm_display_mode *mode)
+{
+	struct mipi_dsi_device *device = dsi->device;
+	int drq = 0;

So, here, you declaring a variable called drq, set to 0.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 372

Quoted 2 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
+	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		return drq;

That you return here. You could just return 0, to be clearer.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 377

Quoted 3 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -0
+	if ((mode->hsync_start - mode->hdisplay) > 20) {
+		/* Maaaaaagic */
+		u16 drq = (mode->hsync_start - mode->hdisplay) - 20;

You re-declare a variable with the same name here, but a different type....

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 383

Quoted 5 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
+		drq *= mipi_dsi_pixel_format_to_bpp(device->format);
+		drq /= 32;
+	}
+
+	return drq;

And then return the first one? How is that even working?

Quoted 16 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +1 -8
+
 static u16 sun6i_dsi_get_timings_vblk(struct sun6i_dsi *dsi,
 				      struct drm_display_mode *mode, u16 hblk)
 {
@@ -478,21 +498,9 @@ static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
 				  struct drm_display_mode *mode)
 {
-	struct mipi_dsi_device *device = dsi->device;
-	u32 val = 0;
-
-	if ((mode->hsync_start - mode->hdisplay) > 20) {
-		/* Maaaaaagic */
-		u16 drq = (mode->hsync_start - mode->hdisplay) - 20;
-
-		drq *= mipi_dsi_pixel_format_to_bpp(device->format);

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi, · line 503

Quoted 10 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -7
-		drq /= 32;
-
-		val = (SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
-		       SUN6I_DSI_TCON_DRQ_SET(drq));
-	}
-
-	regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, val);
+	regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG,
+		     SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
+		     SUN6I_DSI_TCON_DRQ_SET(sun6i_dsi_get_drq(dsi, mode)));

On top of that, you now enable the DRQ stuff all the time, while it was conditional before.

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#18 lore raw

Re: [PATCH v2 04/12] drm/sun4i: sun6i_mipi_dsi: Simplify drq set to support all modes

Quoted 46 lines · Maxime Ripard
Quoted 21 lines · Jagan Teki

Allwinner MIPI DSI DRQ set value can be varied with respective video modes.
- burst mode the set value is always 0
- video modes whose front porch greater than 20, the set value can be computed based front porch and bpp.
- video modes whose front porch is not greater than 20, the set value is simply 0

This patch simplifies existing drq set value code by grouping into sun6i_dsi_get_drq and support all video modes.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 38 ++++++++++++++++----------
 1 file changed, 23 insertions(+), 15 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +0 -0
index efd08bfd0cb8..d60955880c43 100644

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 370

Quoted 8 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
@@ -363,6 +363,26 @@ static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi,
                   SUN6I_DSI_INST_JUMP_CFG_NUM(1));
 };
 
+static int sun6i_dsi_get_drq(struct sun6i_dsi *dsi,
+                           struct drm_display_mode *mode)
+{
+     struct mipi_dsi_device *device = dsi->device;
+     int drq = 0;

So, here, you declaring a variable called drq, set to 0.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 372

Quoted 2 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
+     if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+             return drq;

That you return here. You could just return 0, to be clearer.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 377

Quoted 3 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -0
+     if ((mode->hsync_start - mode->hdisplay) > 20) {
+             /* Maaaaaagic */
+             u16 drq = (mode->hsync_start - mode->hdisplay) - 20;

You re-declare a variable with the same name here, but a different type....

Quoted 7 lines

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 383

Quoted 5 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
+             drq *= mipi_dsi_pixel_format_to_bpp(device->format);
+             drq /= 32;
+     }
+
+     return drq;

And then return the first one? How is that even working?

Will fix this.

Quoted 21 lines
Quoted 21 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +1 -12
+
 static u16 sun6i_dsi_get_timings_vblk(struct sun6i_dsi *dsi,
                                    struct drm_display_mode *mode, u16 hblk)
 {
@@ -478,21 +498,9 @@ static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
                                struct drm_display_mode *mode)
 {
-     struct mipi_dsi_device *device = dsi->device;
-     u32 val = 0;
-
-     if ((mode->hsync_start - mode->hdisplay) > 20) {
-             /* Maaaaaagic */
-             u16 drq = (mode->hsync_start - mode->hdisplay) - 20;
-
-             drq *= mipi_dsi_pixel_format_to_bpp(device->format);
-             drq /= 32;
-
-             val = (SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
-                    SUN6I_DSI_TCON_DRQ_SET(drq));
Quoted 8 lines

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi, · line 503

Quoted 6 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -3
-     }
-
-     regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, val);
+     regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG,
+                  SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
+                  SUN6I_DSI_TCON_DRQ_SET(sun6i_dsi_get_drq(dsi, mode)));

On top of that, you now enable the DRQ stuff all the time, while it

Earlier the val value is ENABLE_MODE ORed with drq value. for the condition drq is computed in if block otherwise the val is 0. So as I explained in commit message the drq value is 0
- for video modes whose front porch is not greater than 20 and
- for burst mode the val

ie reason I mode it common.

#19 lore raw

Re: [PATCH v2 04/12] drm/sun4i: sun6i_mipi_dsi: Simplify drq set to support all modes

Quoted 53 lines · Jagan Teki
Quoted 52 lines · Maxime Ripard
Quoted 21 lines · Jagan Teki

Allwinner MIPI DSI DRQ set value can be varied with respective video modes.
- burst mode the set value is always 0
- video modes whose front porch greater than 20, the set value can be computed based front porch and bpp.
- video modes whose front porch is not greater than 20, the set value is simply 0

This patch simplifies existing drq set value code by grouping into sun6i_dsi_get_drq and support all video modes.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 38 ++++++++++++++++----------
 1 file changed, 23 insertions(+), 15 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +0 -0
index efd08bfd0cb8..d60955880c43 100644

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 370

Quoted 8 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
@@ -363,6 +363,26 @@ static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi,
                   SUN6I_DSI_INST_JUMP_CFG_NUM(1));
 };
 
+static int sun6i_dsi_get_drq(struct sun6i_dsi *dsi,
+                           struct drm_display_mode *mode)
+{
+     struct mipi_dsi_device *device = dsi->device;
+     int drq = 0;

So, here, you declaring a variable called drq, set to 0.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 372

Quoted 2 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
+     if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+             return drq;

That you return here. You could just return 0, to be clearer.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 377

Quoted 3 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -0
+     if ((mode->hsync_start - mode->hdisplay) > 20) {
+             /* Maaaaaagic */
+             u16 drq = (mode->hsync_start - mode->hdisplay) - 20;

You re-declare a variable with the same name here, but a different type....

Quoted 5 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
+             drq *= mipi_dsi_pixel_format_to_bpp(device->format);
+             drq /= 32;
+     }
+
+     return drq;
Quoted 3 lines
Quoted 1 line

And then return the first one? How is that even working?

Will fix this.

I don't want you to only fix this, I also want you to contribute code that is A) useful, B) tested.

Quoted 28 lines
Quoted 19 lines
Quoted 19 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +0 -12
 static u16 sun6i_dsi_get_timings_vblk(struct sun6i_dsi *dsi,
                                    struct drm_display_mode *mode, u16 hblk)
 {
@@ -478,21 +498,9 @@ static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
                                struct drm_display_mode *mode)
 {
-     struct mipi_dsi_device *device = dsi->device;
-     u32 val = 0;
-
-     if ((mode->hsync_start - mode->hdisplay) > 20) {
-             /* Maaaaaagic */
-             u16 drq = (mode->hsync_start - mode->hdisplay) - 20;
-
-             drq *= mipi_dsi_pixel_format_to_bpp(device->format);
-             drq /= 32;
-
-             val = (SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
-                    SUN6I_DSI_TCON_DRQ_SET(drq));
Quoted 8 lines

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi, · line 503

Quoted 6 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -3
-     }
-
-     regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, val);
+     regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG,
+                  SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
+                  SUN6I_DSI_TCON_DRQ_SET(sun6i_dsi_get_drq(dsi, mode)));

On top of that, you now enable the DRQ stuff all the time, while it

Quoted 7 lines

Earlier the val value is ENABLE_MODE ORed with drq value. for the condition drq is computed in if block otherwise the val is 0. So as I explained in commit message the drq value is 0
- for video modes whose front porch is not greater than 20 and
- for burst mode the val

ie reason I mode it common.

The previous code was enabling it if the front porch was larger than 20 only. You enable it all the time now, and you never explain why.

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#20 lore raw

Re: [PATCH v2 04/12] drm/sun4i: sun6i_mipi_dsi: Simplify drq set to support all modes

Quoted 55 lines · Maxime Ripard
Quoted 53 lines · Jagan Teki
Quoted 52 lines · Maxime Ripard
Quoted 21 lines · Jagan Teki

Allwinner MIPI DSI DRQ set value can be varied with respective video modes.
- burst mode the set value is always 0
- video modes whose front porch greater than 20, the set value can be computed based front porch and bpp.
- video modes whose front porch is not greater than 20, the set value is simply 0

This patch simplifies existing drq set value code by grouping into sun6i_dsi_get_drq and support all video modes.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 38 ++++++++++++++++----------
 1 file changed, 23 insertions(+), 15 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +0 -0
index efd08bfd0cb8..d60955880c43 100644

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 370

Quoted 8 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
@@ -363,6 +363,26 @@ static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi,
                   SUN6I_DSI_INST_JUMP_CFG_NUM(1));
 };
 
+static int sun6i_dsi_get_drq(struct sun6i_dsi *dsi,
+                           struct drm_display_mode *mode)
+{
+     struct mipi_dsi_device *device = dsi->device;
+     int drq = 0;

So, here, you declaring a variable called drq, set to 0.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 372

Quoted 2 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
+     if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+             return drq;

That you return here. You could just return 0, to be clearer.

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi, · line 377

Quoted 3 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -0
+     if ((mode->hsync_start - mode->hdisplay) > 20) {
+             /* Maaaaaagic */
+             u16 drq = (mode->hsync_start - mode->hdisplay) - 20;

You re-declare a variable with the same name here, but a different type....

Quoted 5 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +5 -0
+             drq *= mipi_dsi_pixel_format_to_bpp(device->format);
+             drq /= 32;
+     }
+
+     return drq;
Quoted 6 lines
Quoted 3 lines
Quoted 1 line

And then return the first one? How is that even working?

Will fix this.

I don't want you to only fix this, I also want you to contribute code that is A) useful, B) tested.

It was tested in burst mode panel, the same added in the series. It worked because burst mode need 0 drq rate.

Quoted 35 lines
Quoted 35 lines
Quoted 20 lines
Quoted 20 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +0 -12
 static u16 sun6i_dsi_get_timings_vblk(struct sun6i_dsi *dsi,
                                    struct drm_display_mode *mode, u16 hblk)
 {
@@ -478,21 +498,9 @@ static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
                                struct drm_display_mode *mode)
 {
-     struct mipi_dsi_device *device = dsi->device;
-     u32 val = 0;
-
-     if ((mode->hsync_start - mode->hdisplay) > 20) {
-             /* Maaaaaagic */
-             u16 drq = (mode->hsync_start - mode->hdisplay) - 20;
-
-             drq *= mipi_dsi_pixel_format_to_bpp(device->format);
-             drq /= 32;
-
-             val = (SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
-                    SUN6I_DSI_TCON_DRQ_SET(drq));
Quoted 8 lines

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi, · line 503

Quoted 6 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +3 -3
-     }
-
-     regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, val);
+     regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG,
+                  SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
+                  SUN6I_DSI_TCON_DRQ_SET(sun6i_dsi_get_drq(dsi, mode)));

On top of that, you now enable the DRQ stuff all the time, while it

Earlier the val value is ENABLE_MODE ORed with drq value. for the condition drq is computed in if block otherwise the val is 0. So as I explained in commit message the drq value is 0
- for video modes whose front porch is not greater than 20 and
- for burst mode the val

Quoted 4 lines
Quoted 1 line

ie reason I mode it common.

The previous code was enabling it if the front porch was larger than 20 only. You enable it all the time now, and you never explain why.

Got it. Loo like I was confused to test these two separate series in separate panels and missed something. Is it Ok to combine all dsi changes together and send it in next version.

author maintainer
#21 lore raw

PATCH v2 5/12 drm/sun4i: tcon: Export get tcon0 routine

In reply to Jagan Teki

Sometimes tcon attributes like tcon divider, clock rate etc are needed in interface drivers like DSI. So for such cases interface driver must probe the respective tcon and get the attributes. Instead of probing tcon explictly, better export the existing sun5i_get_tcon0 so-that the relevant interface can reuse.

---
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 3 ++-
 drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun4i_tcon.c +2 -1
index c78cd35a1294..6e85a33c6828 100644
@@ -221,7 +221,7 @@ EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
  * are located in TCON0. This helper returns a pointer to TCON0's
  * sun4i_tcon structure, or NULL if not found.
  */
-static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)
+struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)
 {
 	struct sun4i_drv *drv = drm->dev_private;
 	struct sun4i_tcon *tcon;
@@ -235,6 +235,7 @@ static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)
 
 	return NULL;
 }
+EXPORT_SYMBOL(sun4i_get_tcon0);
 
 void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
 			const struct drm_encoder *encoder)
drivers/gpu/drm/sun4i/sun4i_tcon.h +1 -0
index 3d492c8be1fc..195deb9db57a 100644
@@ -273,6 +273,7 @@ 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);
 
+struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm);
 void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
 void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
 			 const struct drm_encoder *encoder,
Signature · 1 line
2.18.0.321.gffc6fa0e3
#22 lore raw

Re: [PATCH v2 05/12] drm/sun4i: tcon: Export get tcon0 routine

Quoted 5 lines · Jagan Teki

Sometimes tcon attributes like tcon divider, clock rate etc are needed in interface drivers like DSI. So for such cases interface driver must probe the respective tcon and get the attributes. Instead of probing tcon explictly, better export the existing sun5i_get_tcon0 so-that the relevant interface can reuse.

That's not the name of the function you export.

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#23 lore raw

PATCH v2 6/12 drm/sun4i: sun6i_mipi_dsi: Probe tcon0 during dsi_bind

In reply to Jagan Teki

Probe tcon0 during dsi_bind, so-that the tcon attributes like divider value, clock rate can get whenever it need.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 7 +++++++
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 1 +
 2 files changed, 8 insertions(+)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +7 -0
index d60955880c43..66a01061e51d 100644
@@ -25,6 +25,7 @@
 #include <drm/drm_panel.h>
 
 #include "sun4i_drv.h"
+#include "sun4i_tcon.h"
 #include "sun6i_mipi_dsi.h"
 
 #include <video/mipi_display.h>
@@ -1007,6 +1008,7 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 	struct drm_device *drm = data;
 	struct sun4i_drv *drv = drm->dev_private;
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+	struct sun4i_tcon *tcon0 = sun4i_get_tcon0(drm);
 	int ret;
 
 	if (!dsi->panel)
@@ -1014,6 +1016,11 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 
 	dsi->drv = drv;
 
+	if (!tcon0)
+		return -EPROBE_DEFER;
+
+	dsi->tcon = tcon0;
+
 	drm_encoder_helper_add(&dsi->encoder,
 			       &sun6i_dsi_enc_helper_funcs);
 	ret = drm_encoder_init(drm,
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h +1 -0
index 0df60f84bab3..3c532e83958d 100644
@@ -40,6 +40,7 @@ struct sun6i_dsi {
 
 	struct device		*dev;
 	struct sun4i_drv	*drv;
+	struct sun4i_tcon	*tcon;
 	struct mipi_dsi_device	*device;
 	struct drm_panel	*panel;
 	const struct sun6i_dsi_variant	*variant;
Signature · 1 line
2.18.0.321.gffc6fa0e3
#24 lore raw

Re: [PATCH v2 06/12] drm/sun4i: sun6i_mipi_dsi: Probe tcon0 during dsi_bind

Quoted 30 lines · Jagan Teki

Probe tcon0 during dsi_bind, so-that the tcon attributes like divider value, clock rate can get whenever it need.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 7 +++++++
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 1 +
 2 files changed, 8 insertions(+)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
index d60955880c43..66a01061e51d 100644
@@ -25,6 +25,7 @@
 #include <drm/drm_panel.h>
 
 #include "sun4i_drv.h"
+#include "sun4i_tcon.h"
 #include "sun6i_mipi_dsi.h"
 
 #include <video/mipi_display.h>
@@ -1007,6 +1008,7 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 	struct drm_device *drm = data;
 	struct sun4i_drv *drv = drm->dev_private;
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+	struct sun4i_tcon *tcon0 = sun4i_get_tcon0(drm);
 	int ret;
 
 	if (!dsi->panel)

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static int sun6i_dsi_bind(struct device *dev, struct device *master, · line 1020

Quoted 5 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
@@ -1014,6 +1016,11 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 
 	dsi->drv = drv;
 
+	if (!tcon0)
+		return -EPROBE_DEFER;

You can't fall in that condition. The component framework won't call bind unless every components have been probed.

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#25 lore raw

Re: [PATCH v2 06/12] drm/sun4i: sun6i_mipi_dsi: Probe tcon0 during dsi_bind

Quoted 33 lines · Maxime Ripard
Quoted 31 lines · Jagan Teki

Probe tcon0 during dsi_bind, so-that the tcon attributes like divider value, clock rate can get whenever it need.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 7 +++++++
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 1 +
 2 files changed, 8 insertions(+)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
index d60955880c43..66a01061e51d 100644
@@ -25,6 +25,7 @@
 #include <drm/drm_panel.h>
 
 #include "sun4i_drv.h"
+#include "sun4i_tcon.h"
 #include "sun6i_mipi_dsi.h"
 
 #include <video/mipi_display.h>
@@ -1007,6 +1008,7 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
      struct drm_device *drm = data;
      struct sun4i_drv *drv = drm->dev_private;
      struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+     struct sun4i_tcon *tcon0 = sun4i_get_tcon0(drm);
      int ret;
 
      if (!dsi->panel)
@@ -1014,6 +1016,11 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 
Quoted 7 lines

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static int sun6i_dsi_bind(struct device *dev, struct device *master, · line 1020

Quoted 4 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
      dsi->drv = drv;
 
+     if (!tcon0)
+             return -EPROBE_DEFER;

You can't fall in that condition. The component framework won't call bind unless every components have been probed.

Since tcon0 is already probed is it? if so I can return -EINVAL is it ok?

#26 lore raw

Re: [PATCH v2 06/12] drm/sun4i: sun6i_mipi_dsi: Probe tcon0 during dsi_bind

Quoted 36 lines · Jagan Teki
Quoted 35 lines · Maxime Ripard
Quoted 33 lines · Jagan Teki

Probe tcon0 during dsi_bind, so-that the tcon attributes like divider value, clock rate can get whenever it need.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 7 +++++++
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 1 +
 2 files changed, 8 insertions(+)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
index d60955880c43..66a01061e51d 100644
@@ -25,6 +25,7 @@
 #include <drm/drm_panel.h>
 
 #include "sun4i_drv.h"
+#include "sun4i_tcon.h"
 #include "sun6i_mipi_dsi.h"
 
 #include <video/mipi_display.h>
@@ -1007,6 +1008,7 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
      struct drm_device *drm = data;
      struct sun4i_drv *drv = drm->dev_private;
      struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+     struct sun4i_tcon *tcon0 = sun4i_get_tcon0(drm);
      int ret;
 
      if (!dsi->panel)
@@ -1014,6 +1016,11 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 
      dsi->drv = drv;
 
Quoted 7 lines
Quoted 5 lines

drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c static int sun6i_dsi_bind(struct device *dev, struct device *master, · line 1020

Quoted 2 lines
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +2 -0
+     if (!tcon0)
+             return -EPROBE_DEFER;

You can't fall in that condition. The component framework won't call bind unless every components have been probed.

Since tcon0 is already probed is it? if so I can return -EINVAL is it ok?

Sounds good yes.

Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author maintainer
#27 lore raw

PATCH v2 7/12 drm/sun4i: sun6i_mipi_dsi: Setup burst mode

In reply to Jagan Teki

Setting up burst mode display would require to compute
- Horizontal timing edge values to fill burst drq register
- Line, sync values to fill burst line register

Since there is no direct documentation for these computations the edge and line formulas are taken from BSP code (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

line_num = panel->lcd_ht*dsi_pixel_bits[panel->lcd_dsi_format]/

	  (8*panel->lcd_dsi_lane);
edge1 = sync_point+(panel->lcd_x+panel->lcd_hbp+20)*
	dsi_pixel_bits[panel->lcd_dsi_format] /(8*panel->lcd_dsi_lane);

edge1 = (edge1>line_num)?line_num:edge1;
edge0 = edge1+(panel->lcd_x+40)*tcon_div/8;
edge0 = (edge0>line_num)?(edge0-line_num):1;

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 72 ++++++++++++++++++++++++--
 1 file changed, 68 insertions(+), 4 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +68 -4
index 66a01061e51d..0182408f8932 100644
@@ -364,6 +364,41 @@ static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi,
 		     SUN6I_DSI_INST_JUMP_CFG_NUM(1));
 };
 
+static u32 sun6i_dsi_get_edge1(struct sun6i_dsi *dsi,
+			       struct drm_display_mode *mode, u32 sync_point)
+{
+	struct mipi_dsi_device *device = dsi->device;
+	unsigned int bpp = mipi_dsi_pixel_format_to_bpp(device->format);
+	u32 hact_sync_bp;
+
+	/* Horizontal timings duration excluding front porch */
+	hact_sync_bp = (mode->hdisplay + mode->htotal - mode->hsync_start);
+
+	return (sync_point + ((hact_sync_bp + 20) * bpp / (8 * device->lanes)));
+}
+
+static u32 sun6i_dsi_get_edge0(struct sun6i_dsi *dsi,
+			       struct drm_display_mode *mode, u32 edge1)
+{
+	struct sun4i_tcon *tcon = dsi->tcon;
+	unsigned long dclk_rate, dclk_parent_rate, tcon0_div;
+
+	dclk_rate = clk_get_rate(tcon->dclk);
+	dclk_parent_rate = clk_get_rate(clk_get_parent(tcon->dclk));
+	tcon0_div = dclk_parent_rate / dclk_rate;
+
+	return (edge1 + (mode->hdisplay + 40) * tcon0_div / 8);
+}
+
+static u32 sun6i_dsi_get_line_num(struct sun6i_dsi *dsi,
+				  struct drm_display_mode *mode)
+{
+	struct mipi_dsi_device *device = dsi->device;
+	unsigned int bpp = mipi_dsi_pixel_format_to_bpp(device->format);
+
+	return (mode->htotal * bpp / (8 * device->lanes));
+}
+
 static int sun6i_dsi_get_drq(struct sun6i_dsi *dsi,
 			      struct drm_display_mode *mode)
 {
@@ -499,9 +534,32 @@ static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,
 static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
 				  struct drm_display_mode *mode)
 {
-	regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG,
-		     SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
-		     SUN6I_DSI_TCON_DRQ_SET(sun6i_dsi_get_drq(dsi, mode)));
+	struct mipi_dsi_device *device = dsi->device;
+	u32 sync_point = 40;
+	u32 line_num = sun6i_dsi_get_line_num(dsi, mode);
+	u32 edge1 = sun6i_dsi_get_edge1(dsi, mode, sync_point);
+	u32 edge0 = sun6i_dsi_get_edge0(dsi, mode, edge1);
+	u32 val;
+
+	if (edge1 > line_num)
+		edge1 = line_num;
+
+	if (edge0 > line_num)
+		edge0 -= line_num;
+	else
+		edge0 = 1;
+
+	regmap_write(dsi->regs, SUN6I_DSI_BURST_DRQ_REG,
+		     SUN6I_DSI_BURST_DRQ_EDGE1(edge1) |
+		     SUN6I_DSI_BURST_DRQ_EDGE0(edge0));
+	regmap_write(dsi->regs, SUN6I_DSI_BURST_LINE_REG,
+		     SUN6I_DSI_BURST_LINE_NUM(line_num) |
+		     SUN6I_DSI_BURST_LINE_SYNC_POINT(sync_point));
+
+	/* enable burst mode */
+	regmap_read(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, &val);
+	val |= SUN6I_DSI_BASIC_CTL_VIDEO_BURST;
+	regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, val);
 }
 
 static void sun6i_dsi_setup_inst_loop(struct sun6i_dsi *dsi,
@@ -726,7 +784,13 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
 		     SUN6I_DSI_BASIC_CTL1_VIDEO_PRECISION |
 		     SUN6I_DSI_BASIC_CTL1_VIDEO_MODE);
 
-	sun6i_dsi_setup_burst(dsi, mode);
+	regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG,
+		     SUN6I_DSI_TCON_DRQ_ENABLE_MODE |
+		     SUN6I_DSI_TCON_DRQ_SET(sun6i_dsi_get_drq(dsi, mode)));
+
+	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		sun6i_dsi_setup_burst(dsi, mode);
+
 	sun6i_dsi_setup_inst_loop(dsi, mode);
 	sun6i_dsi_setup_format(dsi, mode);
 	sun6i_dsi_setup_timings(dsi, mode);
Signature · 1 line
2.18.0.321.gffc6fa0e3
author maintainer
#28 lore raw

PATCH v2 8/12 drm/sun4i: sun6i_mipi_dsi: Enable 2byte trail for 4-lane burst mode

In reply to Jagan Teki

For 4-lane, burst mode panels would need to enable 2byte trail_fill along with filling trail_env in dsi base control register.

Similar reference code avialable in BSP (from linux-sunxi/ drivers/video/sunxi/disp2/disp/de/lowlevel_sun50iw1/de_dsi.c)

if (panel->lcd_dsi_lane == 4)
{
dsi_dev[sel]->dsi_basic_ctl.bits.trail_inv = 0xc;
dsi_dev[sel]->dsi_basic_ctl.bits.trail_fill = 1;
}

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +6 -0
index 0182408f8932..22d2987c3298 100644
@@ -34,6 +34,8 @@
 #define SUN6I_DSI_CTL_EN			BIT(0)
 
 #define SUN6I_DSI_BASIC_CTL_REG		0x00c
+#define SUN6I_DSI_BASIC_CTL_TRAIL_INV(n)	(((n) & 0xf) << 4)
+#define SUN6I_DSI_BASIC_CTL_TRAIL_FILL		BIT(3)
 #define SUN6I_DSI_BASIC_CTL_HBP_DIS		BIT(2)
 #define SUN6I_DSI_BASIC_CTL_HSA_HSE_DIS		BIT(1)
 #define SUN6I_DSI_BASIC_CTL_VIDEO_BURST		BIT(0)
@@ -559,6 +561,10 @@ static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,
 	/* enable burst mode */
 	regmap_read(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, &val);
 	val |= SUN6I_DSI_BASIC_CTL_VIDEO_BURST;
+	if (device->lanes == 4) {
+		val |= SUN6I_DSI_BASIC_CTL_TRAIL_INV(0xc);
+		val |= SUN6I_DSI_BASIC_CTL_TRAIL_FILL;
+	}
 	regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, val);
 }
 
Signature · 1 line
2.18.0.321.gffc6fa0e3
author maintainer
#29 lore raw

PATCH v2 9/12 drm/sun4i: sun6i_mipi_dsi: Enable burst mode HBP, HSA_HSE

In reply to Jagan Teki

Horizontal back porch, sync active and sync end bits are needed to disable for burst mode panel operations.

So, disable them via dsi base control register.

---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +9 -3
index 22d2987c3298..20a1de8493e0 100644
@@ -644,15 +644,21 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
 	struct sun6i_dsi_timings timings;
 	size_t bytes;
 	u8 *buffer;
+	u32 val = 0;
 
 	/* Do all timing calculations up front to allocate buffer space */
 
 	memset(&timings, 0, sizeof(timings));
 
-	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
 		timings.hblk = (mode->hdisplay * Bpp);
-	else
+
+		regmap_read(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, &val);
+		val |= SUN6I_DSI_BASIC_CTL_HBP_DIS;
+		val |= SUN6I_DSI_BASIC_CTL_HSA_HSE_DIS;
+	} else {
 		sun6i_dsi_get_timings(dsi, mode, &timings);
+	}
 
 	/* How many bytes do we need to send all payloads? */
 	bytes = max_t(size_t, max(max(timings.hfp, timings.hblk),
@@ -661,7 +667,7 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
 	if (WARN_ON(!buffer))
 		return;
 
-	regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, 0);
+	regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, val);
 
 	regmap_write(dsi->regs, SUN6I_DSI_SYNC_HSS_REG,
 		     sun6i_dsi_build_sync_pkt(MIPI_DSI_H_SYNC_START,
Signature · 1 line
2.18.0.321.gffc6fa0e3
author maintainer
#30 lore raw

PATCH v2 10/12 dt-bindings: panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

In reply to Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add dt-bingings for it.

---
 .../display/panel/feiyang,fy07024di26a30d.txt | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt new file +20 -0
new file mode 100644
index 000000000000..82caa7b65ae8
@@ -0,0 +1,20 @@
+Feiyang FY07024DI26A30-D 7" MIPI-DSI LCD Panel
+
+Required properties:
+- compatible: must be "feiyang,fy07024di26a30d"
+- reg: DSI virtual channel used by that screen
+- avdd-supply: analog regulator dc1 switch
+- dvdd-supply: 3v3 digital regulator
+- reset-gpios: a GPIO phandle for the reset pin
+
+Optional properties:
+- backlight: phandle for the backlight control.
+
+panel@0 {
+	compatible = "feiyang,fy07024di26a30d";
+	reg = <0>;
+	avdd-supply = <&reg_dc1sw>;
+	dvdd-supply = <&reg_dldo2>;
+	reset-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* LCD-RST: PD24 */
+	backlight = <&backlight>;
+};
Signature · 1 line
2.18.0.321.gffc6fa0e3
author maintainer
#31 lore raw

PATCH v2 11/12 drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

In reply to Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add panel driver for it.

---
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
MAINTAINERS +6 -0
index 3dac08d0b3cb..40c8bfc974f4 100644
@@ -4620,6 +4620,12 @@ T:	git git://anongit.freedesktop.org/drm/drm-misc
 S:	Maintained
 F:	drivers/gpu/drm/tve200/
 
+DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
+M:	Jagan Teki <jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
+S:	Maintained
+F:	drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+F:	Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
+
 DRM DRIVER FOR ILITEK ILI9225 PANELS
 M:	David Lechner <david-nq/r/kbU++upp/[email protected]>
 S:	Maintained
drivers/gpu/drm/panel/Kconfig +9 -0
index d0d4e60f5153..bc70896fe43c 100644
@@ -47,6 +47,15 @@ config DRM_PANEL_SIMPLE
 	  that it can be automatically turned off when the panel goes into a
 	  low power state.
 
+config DRM_PANEL_FEIYANG_FY07024DI26A30D
+	tristate "Feiyang FY07024DI26A30-D MIPI-DSI LCD panel"
+	depends on OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y if you want to enable support for panels based on the
+	  Feiyang FY07024DI26A30-D MIPI-DSI interface.
+
 config DRM_PANEL_ILITEK_IL9322
 	tristate "Ilitek ILI9322 320x240 QVGA panels"
 	depends on OF && SPI
drivers/gpu/drm/panel/Makefile +1 -0
index 88011f06edb8..e23c017639c7 100644
@@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_BANANAPI_S070WV20_ICN6211) += panel-bananapi-s070wv20-icn6211.o
 obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +286 -0

286 lines not on this page · raw message

Signature · 1 line
2.18.0.321.gffc6fa0e3
author maintainer
#32 lore raw

Re: [PATCH v2 11/12] drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

Hi Thierry and David,

Quoted 38 lines · Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add panel driver for it.

---
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
MAINTAINERS +6 -0
index 3dac08d0b3cb..40c8bfc974f4 100644
@@ -4620,6 +4620,12 @@ T:       git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
 F:     drivers/gpu/drm/tve200/
 
+DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
+M:     Jagan Teki <jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
+S:     Maintained
+F:     drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+F:     Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
+
 DRM DRIVER FOR ILITEK ILI9225 PANELS
 M:     David Lechner <david-nq/r/kbU++upp/[email protected]>
 S:     Maintained
drivers/gpu/drm/panel/Kconfig +0 -0
index d0d4e60f5153..bc70896fe43c 100644
@@ -47,6 +47,15 @@ config DRM_PANEL_SIMPLE
          that it can be automatically turned off when the panel goes into a
          low power state.

drivers/gpu/drm/panel/Kconfig config DRM_PANEL_SIMPLE · line 58

Quoted 10 lines
drivers/gpu/drm/panel/Kconfig +9 -0
 
+config DRM_PANEL_FEIYANG_FY07024DI26A30D
+       tristate "Feiyang FY07024DI26A30-D MIPI-DSI LCD panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       depends on BACKLIGHT_CLASS_DEVICE
+       help
+         Say Y if you want to enable support for panels based on the
+         Feiyang FY07024DI26A30-D MIPI-DSI interface.
+

Any comments on this?

#33 lore raw

Re: [PATCH v2 11/12] drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

In reply to Jagan Teki
Quoted 109 lines · Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add panel driver for it.

---
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
MAINTAINERS +6 -0
index 3dac08d0b3cb..40c8bfc974f4 100644
@@ -4620,6 +4620,12 @@ T:	git git://anongit.freedesktop.org/drm/drm-misc
 S:	Maintained
 F:	drivers/gpu/drm/tve200/
 
+DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
+M:	Jagan Teki <[email protected]>
+S:	Maintained
+F:	drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+F:	Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
+
 DRM DRIVER FOR ILITEK ILI9225 PANELS
 M:	David Lechner <[email protected]>
 S:	Maintained
drivers/gpu/drm/panel/Kconfig +9 -0
index d0d4e60f5153..bc70896fe43c 100644
@@ -47,6 +47,15 @@ config DRM_PANEL_SIMPLE
 	  that it can be automatically turned off when the panel goes into a
 	  low power state.
 
+config DRM_PANEL_FEIYANG_FY07024DI26A30D
+	tristate "Feiyang FY07024DI26A30-D MIPI-DSI LCD panel"
+	depends on OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y if you want to enable support for panels based on the
+	  Feiyang FY07024DI26A30-D MIPI-DSI interface.
+
 config DRM_PANEL_ILITEK_IL9322
 	tristate "Ilitek ILI9322 320x240 QVGA panels"
 	depends on OF && SPI
drivers/gpu/drm/panel/Makefile +1 -0
index 88011f06edb8..e23c017639c7 100644
@@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_BANANAPI_S070WV20_ICN6211) += panel-bananapi-s070wv20-icn6211.o
 obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +41 -0
new file mode 100644
index 000000000000..a4b46bd8fdbe
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Amarula Solutions
+ * Author: Jagan Teki <[email protected]>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+struct feiyang {
+	struct drm_panel	panel;
+	struct mipi_dsi_device	*dsi;
+
+	struct backlight_device	*backlight;
+	struct regulator	*dvdd;
+	struct regulator	*avdd;
+	struct gpio_desc	*reset;
+};
+
+static inline struct feiyang *panel_to_feiyang(struct drm_panel *panel)
+{
+	return container_of(panel, struct feiyang, panel);
+}
+
+struct feiyang_init_cmd {
+	size_t len;
+	const char *data;
+};
+
+#define FY07024DI26A30D(...) { \
+	.len = sizeof((char[]){__VA_ARGS__}), \
+	.data = (char[]){__VA_ARGS__} }

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 51

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+
+static const struct feiyang_init_cmd feiyang_init_cmds[] = {
+	FY07024DI26A30D(0x80, 0x58),
+	FY07024DI26A30D(0x81, 0x47),
+	FY07024DI26A30D(0x82, 0xD4),
+	FY07024DI26A30D(0x83, 0x88),
+	FY07024DI26A30D(0x84, 0xA9),
+	FY07024DI26A30D(0x85, 0xC3),
+	FY07024DI26A30D(0x86, 0x82),
+};

These init cmds don't have to be so complicated. You've only got len == 2, so just hardcode it in and avoid the macro:

#define FEIYANG_INIT_CMD_LEN 2

struct feiyang_init_cmd {
        u8 data[FEIYANG_INIT_CMD];
};
static const struct feiyang_init_cmd feiyang_init_cmds[] = {
        { .data = { 0x80, 0x58 } },
        ...
};

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 64

Quoted 13 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +13 -0
+
+static int feiyang_prepare(struct drm_panel *panel)
+{
+	struct feiyang *ctx = panel_to_feiyang(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	unsigned int i;
+	int ret;
+
+	ret = regulator_enable(ctx->dvdd);
+	if (ret)
+		return ret;
+
+	msleep(100);

nit: You should do your best to correlate the sleeps with the timing parameters from the datasheet with a comment.

ie:

        /* T1: > 100ms */
        msleep(100);
Quoted 11 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +11 -0
+
+	ret = regulator_enable(ctx->avdd);
+	if (ret)
+		return ret;
+
+	msleep(20);
+
+	gpiod_set_value(ctx->reset, 1);
+	msleep(50);
+
+	gpiod_set_value(ctx->reset, 0);

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 85

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+	msleep(20);
+
+	gpiod_set_value(ctx->reset, 1);
+	msleep(200);
+
+	for (i = 0; i < ARRAY_SIZE(feiyang_init_cmds); i++) {
+		const struct feiyang_init_cmd *cmd =
+						&feiyang_init_cmds[i];
+
+		ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data, cmd->len);
                ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data,
                                                FEIYANG_INIT_CMD_LEN);
Quoted 15 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +15 -0
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int feiyang_enable(struct drm_panel *panel)
+{
+	struct feiyang *ctx = panel_to_feiyang(panel);
+
+	msleep(120);
+
+	mipi_dsi_dcs_set_display_on(ctx->dsi);
+	backlight_enable(ctx->backlight);

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 110

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+
+	return 0;
+}
+
+static int feiyang_disable(struct drm_panel *panel)
+{
+	struct feiyang *ctx = panel_to_feiyang(panel);
+
+	backlight_disable(ctx->backlight);
+	return mipi_dsi_dcs_set_display_on(ctx->dsi);

set_display_on? You probably want set_display_off here :)

Quoted 18 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +18 -0
+}
+
+static int feiyang_unprepare(struct drm_panel *panel)
+{
+	struct feiyang *ctx = panel_to_feiyang(panel);
+	int ret;
+
+	ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
+	if (ret < 0)
+		DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
+			      ret);
+
+	ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+	if (ret < 0)
+		DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
+			      ret);
+
+	msleep(100);

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 138

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+
+	regulator_disable(ctx->avdd);
+
+	regulator_disable(ctx->dvdd);
+
+	gpiod_set_value(ctx->reset, 0);
+
+	gpiod_set_value(ctx->reset, 1);
+
+	gpiod_set_value(ctx->reset, 0);

Presumably this reset line toggle isn't needed since the rails are already disabled?

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 145

Quoted 7 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +7 -0
+
+	return 0;
+}
+
+static const struct drm_display_mode feiyang_default_mode = {
+	.clock = 55000,
+	.vrefresh = 60,

This doesn't add up correctly. The pixel clock should be equal to:

        (htotal * vtotal * vrefresh) / 1000

For this reason, we usually don't specify the refresh rate since it can be misleading. Your actual refresh rate with the pixel clock you specified is actually going to be 56.2Hz instead of the 60 you want.

If you can only generate a 55MHz pixel clock, consider reducing your blanking periods so the calculation above matches.

Quoted 20 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +20 -0
+
+	.hdisplay = 1024,
+	.hsync_start = 1024 + 396,
+	.hsync_end = 1024 + 396 + 20,
+	.htotal = 1024 + 396 + 20 + 100,
+
+	.vdisplay = 600,
+	.vsync_start = 600 + 12,
+	.vsync_end = 600 + 12 + 2,
+	.vtotal = 600 + 12 + 2 + 21,
+};
+
+static int feiyang_get_modes(struct drm_panel *panel)
+{
+	struct drm_connector *connector = panel->connector;
+	struct feiyang *ctx = panel_to_feiyang(panel);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(panel->drm, &feiyang_default_mode);
+	if (!mode) {

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 175

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+		DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
+			      feiyang_default_mode.hdisplay,
+			      feiyang_default_mode.vdisplay,
+			      feiyang_default_mode.vrefresh);
+		return -ENOMEM;
+	}
+
+	drm_mode_set_name(mode);
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;

Just set these above.

Quoted 114 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +111 -0
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+
+static const struct drm_panel_funcs feiyang_funcs = {
+	.disable = feiyang_disable,
+	.unprepare = feiyang_unprepare,
+	.prepare = feiyang_prepare,
+	.enable = feiyang_enable,
+	.get_modes = feiyang_get_modes,
+};
+
+static int feiyang_dsi_probe(struct mipi_dsi_device *dsi)
+{
+	struct device_node *np;
+	struct feiyang *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 = &feiyang_funcs;
+
+	ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd");
+	if (IS_ERR(ctx->dvdd)) {
+		DRM_DEV_ERROR(&dsi->dev, "Couldn't get dvdd regulator\n");
+		return PTR_ERR(ctx->dvdd);
+	}
+
+	ctx->avdd = devm_regulator_get(&dsi->dev, "avdd");
+	if (IS_ERR(ctx->avdd)) {
+		DRM_DEV_ERROR(&dsi->dev, "Couldn't get avdd regulator\n");
+		return PTR_ERR(ctx->avdd);
+	}
+
+	ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset)) {
+		DRM_DEV_ERROR(&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)
+		goto put_backlight;
+
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->lanes = 4;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0)
+		goto panel_remove;
+
+	return ret;
+
+panel_remove:
+	drm_panel_remove(&ctx->panel);
+put_backlight:
+	if (ctx->backlight)
+		put_device(&ctx->backlight->dev);
+
+	return ret;
+}
+
+static int feiyang_dsi_remove(struct mipi_dsi_device *dsi)
+{
+	struct feiyang *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 feiyang_of_match[] = {
+	{ .compatible = "feiyang,fy07024di26a30d", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, feiyang_of_match);
+
+static struct mipi_dsi_driver feiyang_driver = {
+	.probe = feiyang_dsi_probe,
+	.remove = feiyang_dsi_remove,
+	.driver = {
+		.name = "feiyang-fy07024di26a30d",
+		.of_match_table = feiyang_of_match,
+	},
+};
+module_mipi_dsi_driver(feiyang_driver);
+
+MODULE_AUTHOR("Jagan Teki <[email protected]>");
+MODULE_DESCRIPTION("Feiyang FY07024DI26A30-D MIPI-DSI LCD panel");
+MODULE_LICENSE("GPL");
Signature · 1 line
2.18.0.321.gffc6fa0e3
Signature · 5 lines
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
author maintainer
#34 lore raw

Re: [PATCH v2 11/12] drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

Quoted 153 lines · Sean Paul
Quoted 109 lines · Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add panel driver for it.

---
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
MAINTAINERS +6 -0
index 3dac08d0b3cb..40c8bfc974f4 100644
@@ -4620,6 +4620,12 @@ T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:   Maintained
 F:   drivers/gpu/drm/tve200/
 
+DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
+M:   Jagan Teki <[email protected]>
+S:   Maintained
+F:   drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
+F:   Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
+
 DRM DRIVER FOR ILITEK ILI9225 PANELS
 M:   David Lechner <[email protected]>
 S:   Maintained
drivers/gpu/drm/panel/Kconfig +9 -0
index d0d4e60f5153..bc70896fe43c 100644
@@ -47,6 +47,15 @@ config DRM_PANEL_SIMPLE
        that it can be automatically turned off when the panel goes into a
        low power state.
 
+config DRM_PANEL_FEIYANG_FY07024DI26A30D
+     tristate "Feiyang FY07024DI26A30-D MIPI-DSI LCD panel"
+     depends on OF
+     depends on DRM_MIPI_DSI
+     depends on BACKLIGHT_CLASS_DEVICE
+     help
+       Say Y if you want to enable support for panels based on the
+       Feiyang FY07024DI26A30-D MIPI-DSI interface.
+
 config DRM_PANEL_ILITEK_IL9322
      tristate "Ilitek ILI9322 320x240 QVGA panels"
      depends on OF && SPI
drivers/gpu/drm/panel/Makefile +1 -0
index 88011f06edb8..e23c017639c7 100644
@@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_BANANAPI_S070WV20_ICN6211) += panel-bananapi-s070wv20-icn6211.o
 obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +41 -0
new file mode 100644
index 000000000000..a4b46bd8fdbe
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Amarula Solutions
+ * Author: Jagan Teki <[email protected]>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+struct feiyang {
+     struct drm_panel        panel;
+     struct mipi_dsi_device  *dsi;
+
+     struct backlight_device *backlight;
+     struct regulator        *dvdd;
+     struct regulator        *avdd;
+     struct gpio_desc        *reset;
+};
+
+static inline struct feiyang *panel_to_feiyang(struct drm_panel *panel)
+{
+     return container_of(panel, struct feiyang, panel);
+}
+
+struct feiyang_init_cmd {
+     size_t len;
+     const char *data;
+};
+
+#define FY07024DI26A30D(...) { \
+     .len = sizeof((char[]){__VA_ARGS__}), \
+     .data = (char[]){__VA_ARGS__} }

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 51

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+
+static const struct feiyang_init_cmd feiyang_init_cmds[] = {
+     FY07024DI26A30D(0x80, 0x58),
+     FY07024DI26A30D(0x81, 0x47),
+     FY07024DI26A30D(0x82, 0xD4),
+     FY07024DI26A30D(0x83, 0x88),
+     FY07024DI26A30D(0x84, 0xA9),
+     FY07024DI26A30D(0x85, 0xC3),
+     FY07024DI26A30D(0x86, 0x82),
+};

These init cmds don't have to be so complicated. You've only got len == 2, so just hardcode it in and avoid the macro:

#define FEIYANG_INIT_CMD_LEN 2

struct feiyang_init_cmd {
        u8 data[FEIYANG_INIT_CMD];
};
static const struct feiyang_init_cmd feiyang_init_cmds[] = {
        { .data = { 0x80, 0x58 } },
        ...
};

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 64

Quoted 13 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +13 -0
+
+static int feiyang_prepare(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+     struct mipi_dsi_device *dsi = ctx->dsi;
+     unsigned int i;
+     int ret;
+
+     ret = regulator_enable(ctx->dvdd);
+     if (ret)
+             return ret;
+
+     msleep(100);

nit: You should do your best to correlate the sleeps with the timing parameters from the datasheet with a comment.

Quoted 3 lines

ie:

        /* T1: > 100ms */
        msleep(100);

Sorry, what does this mean?

Quoted 77 lines
Quoted 12 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +11 -0
+
+     ret = regulator_enable(ctx->avdd);
+     if (ret)
+             return ret;
+
+     msleep(20);
+
+     gpiod_set_value(ctx->reset, 1);
+     msleep(50);
+
+     gpiod_set_value(ctx->reset, 0);

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 85

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+     msleep(20);
+
+     gpiod_set_value(ctx->reset, 1);
+     msleep(200);
+
+     for (i = 0; i < ARRAY_SIZE(feiyang_init_cmds); i++) {
+             const struct feiyang_init_cmd *cmd =
+                                             &feiyang_init_cmds[i];
+
+             ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data, cmd->len);
                ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data,
                                                FEIYANG_INIT_CMD_LEN);
Quoted 15 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +15 -0
+             if (ret < 0)
+                     return ret;
+     }
+
+     return 0;
+}
+
+static int feiyang_enable(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+
+     msleep(120);
+
+     mipi_dsi_dcs_set_display_on(ctx->dsi);
+     backlight_enable(ctx->backlight);

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 110

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+
+     return 0;
+}
+
+static int feiyang_disable(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+
+     backlight_disable(ctx->backlight);
+     return mipi_dsi_dcs_set_display_on(ctx->dsi);

set_display_on? You probably want set_display_off here :)

Quoted 23 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +23 -0
+}
+
+static int feiyang_unprepare(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+     int ret;
+
+     ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
+     if (ret < 0)
+             DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
+                           ret);
+
+     ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+     if (ret < 0)
+             DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
+                           ret);
+
+     msleep(100);
+
+     regulator_disable(ctx->avdd);
+
+     regulator_disable(ctx->dvdd);
+
Quoted 8 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 134

Quoted 5 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +5 -0
+     gpiod_set_value(ctx->reset, 0);
+
+     gpiod_set_value(ctx->reset, 1);
+
+     gpiod_set_value(ctx->reset, 0);

Presumably this reset line toggle isn't needed since the rails are already disabled?

Yes, rails need to reset and turn off. will swap.

Quoted 11 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 145

Quoted 8 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +7 -0
+
+     return 0;
+}
+
+static const struct drm_display_mode feiyang_default_mode = {
+     .clock = 55000,
+     .vrefresh = 60,

This doesn't add up correctly. The pixel clock should be equal to:

Quoted 5 lines
        (htotal * vtotal * vrefresh) / 1000

For this reason, we usually don't specify the refresh rate since it can be misleading. Your actual refresh rate with the pixel clock you specified is actually going to be 56.2Hz instead of the 60 you want.

The actual BSP do work 55MHz[1], I do specify refresh rate unnecessarily.

[1] https://gitlab.com/pine64-android/tools/blob/01b3d9388439106bdd9985cf738c1b876bd617d3/pack/chips/sun50iw1p1/configs/db1000_lcd/sys_config_rgmii.fex#L483

#35 lore raw

Re: [PATCH v2 11/12] drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

Quoted 7 lines · Jagan Teki
Quoted 6 lines · Sean Paul
Quoted 4 lines · Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add panel driver for it.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
---
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c

/snip

Quoted 5 lines
Quoted 5 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c

Quoted 5 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +0 -0
new file mode 100644
index 000000000000..a4b46bd8fdbe

/snip

Quoted 16 lines
Quoted 16 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 64

Quoted 12 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +12 -0
+static int feiyang_prepare(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+     struct mipi_dsi_device *dsi = ctx->dsi;
+     unsigned int i;
+     int ret;
+
+     ret = regulator_enable(ctx->dvdd);
+     if (ret)
+             return ret;
+
+     msleep(100);

nit: You should do your best to correlate the sleeps with the timing parameters from the datasheet with a comment.

Quoted 5 lines
Quoted 3 lines

ie:

        /* T1: > 100ms */
        msleep(100);

Sorry, what does this mean?

On page 9 of the datasheet you sent me [1], it has the delays required to safely power up the panel. This delay is the time between dvdd going high and avdd going high. On the figure in the datasheet, this would be T2 (T1 is dvdd rise time and should be handled in the regulator subsystem (iirc)). Also according to the datasheet, T2 just needs to be > 0, so you don't even need this delay. You could replace this with a comment like:

        /* T1 (dvdd rise time) + T2 (dvdd->avdd) > 0 */

So for all of the msleeps below you should get the delays from the datasheet and add a comment referencing them.

Sean

[1] - http://files.pine64.org/doc/datasheet/pine64/FY07024DI26A30-D_feiyang_LCD_panel.pdf

Quoted 100 lines
Quoted 78 lines
Quoted 13 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +11 -0
+
+     ret = regulator_enable(ctx->avdd);
+     if (ret)
+             return ret;
+
+     msleep(20);
+
+     gpiod_set_value(ctx->reset, 1);
+     msleep(50);
+
+     gpiod_set_value(ctx->reset, 0);

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 85

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+     msleep(20);
+
+     gpiod_set_value(ctx->reset, 1);
+     msleep(200);
+
+     for (i = 0; i < ARRAY_SIZE(feiyang_init_cmds); i++) {
+             const struct feiyang_init_cmd *cmd =
+                                             &feiyang_init_cmds[i];
+
+             ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data, cmd->len);
                ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data,
                                                FEIYANG_INIT_CMD_LEN);
Quoted 15 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +15 -0
+             if (ret < 0)
+                     return ret;
+     }
+
+     return 0;
+}
+
+static int feiyang_enable(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+
+     msleep(120);
+
+     mipi_dsi_dcs_set_display_on(ctx->dsi);
+     backlight_enable(ctx->backlight);

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 110

Quoted 10 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +10 -0
+
+     return 0;
+}
+
+static int feiyang_disable(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+
+     backlight_disable(ctx->backlight);
+     return mipi_dsi_dcs_set_display_on(ctx->dsi);

set_display_on? You probably want set_display_off here :)

Quoted 23 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +23 -0
+}
+
+static int feiyang_unprepare(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+     int ret;
+
+     ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
+     if (ret < 0)
+             DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
+                           ret);
+
+     ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+     if (ret < 0)
+             DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
+                           ret);
+
+     msleep(100);
+
+     regulator_disable(ctx->avdd);
+
+     regulator_disable(ctx->dvdd);
+
Quoted 8 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 134

Quoted 5 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +5 -0
+     gpiod_set_value(ctx->reset, 0);
+
+     gpiod_set_value(ctx->reset, 1);
+
+     gpiod_set_value(ctx->reset, 0);

Presumably this reset line toggle isn't needed since the rails are already disabled?

Yes, rails need to reset and turn off. will swap.

Quoted 11 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 145

Quoted 8 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +7 -0
+
+     return 0;
+}
+
+static const struct drm_display_mode feiyang_default_mode = {
+     .clock = 55000,
+     .vrefresh = 60,

This doesn't add up correctly. The pixel clock should be equal to:

Quoted 7 lines
Quoted 5 lines
        (htotal * vtotal * vrefresh) / 1000

For this reason, we usually don't specify the refresh rate since it can be misleading. Your actual refresh rate with the pixel clock you specified is actually going to be 56.2Hz instead of the 60 you want.

The actual BSP do work 55MHz[1], I do specify refresh rate unnecessarily.

Well, the BSP has a bug in it then :) You either want the refresh rate to be 60Hz or you want the pixel clock to be 55MHz, you can't have both with the timing you have now. You'll need to alter the pixel clock or porches to get 60Hz.

Sean

Quoted 2 lines

[1] https://gitlab.com/pine64-android/tools/blob/01b3d9388439106bdd9985cf738c1b876bd617d3/pack/chips/sun50iw1p1/configs/db1000_lcd/sys_config_rgmii.fex#L483

Signature · 1 line
Sean Paul, Software Engineer, Google / Chromium OS
author maintainer
#36 lore raw

Re: [PATCH v2 11/12] drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

Quoted 49 lines · Sean Paul
Quoted 7 lines · Jagan Teki
Quoted 6 lines · Sean Paul
Quoted 4 lines · Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add panel driver for it.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
---
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c

/snip

Quoted 5 lines
Quoted 5 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c

Quoted 5 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +0 -0
new file mode 100644
index 000000000000..a4b46bd8fdbe

/snip

Quoted 20 lines
Quoted 19 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 64

Quoted 12 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +12 -0
+static int feiyang_prepare(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+     struct mipi_dsi_device *dsi = ctx->dsi;
+     unsigned int i;
+     int ret;
+
+     ret = regulator_enable(ctx->dvdd);
+     if (ret)
+             return ret;
+
+     msleep(100);

nit: You should do your best to correlate the sleeps with the timing parameters from the datasheet with a comment.

ie:

        /* T1: > 100ms */
        msleep(100);
Quoted 5 lines
Quoted 1 line

Sorry, what does this mean?

On page 9 of the datasheet you sent me [1], it has the delays required to safely power up the panel. This delay is the time between dvdd going high and avdd going high. On the figure in the datasheet, this would be T2 (T1 is dvdd rise

time between dvdd going high and avdd going high is T1 + T3 right?

T2 > 0ms
T3 > 20ms

In this case the delay can be msleep(20) ?

Quoted 8 lines

time and should be handled in the regulator subsystem (iirc)). Also according to the datasheet, T2 just needs to be > 0, so you don't even need this delay. You could replace this with a comment like:

        /* T1 (dvdd rise time) + T2 (dvdd->avdd) > 0 */

So for all of the msleeps below you should get the delays from the datasheet and add a comment referencing them.

T5 and T6 are delay between avdd to reset enable it can be 10 + 10 =&gt; 20ms and finally T12 which is 200 after reset.

What about the delay between resets, I need to understand it a bit.

#37 lore raw

Re: [PATCH v2 11/12] drm/panel: Add Feiyang FY07024DI26A30-D MIPI-DSI LCD panel

Quoted 56 lines · Jagan Teki
Quoted 49 lines · Sean Paul
Quoted 7 lines · Jagan Teki
Quoted 6 lines · Sean Paul
Quoted 4 lines · Jagan Teki

Feiyang FY07024DI26A30-D is 1024x600, 4-lane MIPI-DSI LCD panel.

Add panel driver for it.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
---
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/panel/Kconfig                 |   9 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 .../drm/panel/panel-feiyang-fy07024di26a30d.c | 286 ++++++++++++++++++
 4 files changed, 302 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c

/snip

Quoted 5 lines
Quoted 5 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c

Quoted 5 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +0 -0
new file mode 100644
index 000000000000..a4b46bd8fdbe

/snip

Quoted 20 lines
Quoted 19 lines

drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c line 64

Quoted 12 lines
drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c new file +12 -0
+static int feiyang_prepare(struct drm_panel *panel)
+{
+     struct feiyang *ctx = panel_to_feiyang(panel);
+     struct mipi_dsi_device *dsi = ctx->dsi;
+     unsigned int i;
+     int ret;
+
+     ret = regulator_enable(ctx->dvdd);
+     if (ret)
+             return ret;
+
+     msleep(100);

nit: You should do your best to correlate the sleeps with the timing parameters from the datasheet with a comment.

ie:

        /* T1: > 100ms */
        msleep(100);
Quoted 5 lines
Quoted 1 line

Sorry, what does this mean?

On page 9 of the datasheet you sent me [1], it has the delays required to safely power up the panel. This delay is the time between dvdd going high and avdd going high. On the figure in the datasheet, this would be T2 (T1 is dvdd rise

Quoted 6 lines

time between dvdd going high and avdd going high is T1 + T3 right?

T2 > 0ms
T3 > 20ms

In this case the delay can be msleep(20) ?

Hmm, yeah, I didn't notice that T3 was > 20ms, that's kind of confusing. So I think you're right, this should be T2 + T3 > 20ms (T1 is covered in the regulator_enable of dvdd).

Quoted 7 lines
Quoted 7 lines

time and should be handled in the regulator subsystem (iirc)). Also according to the datasheet, T2 just needs to be > 0, so you don't even need this delay. You could replace this with a comment like:

        /* T1 (dvdd rise time) + T2 (dvdd->avdd) > 0 */
Quoted 7 lines
Quoted 2 lines

So for all of the msleeps below you should get the delays from the datasheet and add a comment referencing them.

T5 and T6 are delay between avdd to reset enable it can be 10 + 10 =&gt; 20ms and finally T12 which is 200 after reset.

What about the delay between resets, I need to understand it a bit.

These are usually accounted for at the end of disable. Take a look at the sleep parameters in panel-simple for an example.

Sean

Signature · 5 lines
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
author maintainer
#38 lore raw

PATCH v2 12/12 arm64: allwinner: a64: pine64-lts: Enable Feiyang FY07024DI26A30-D DSI panel

In reply to Jagan Teki

Feiyang FY07024DI26A30-D MIPI_DSI panel is desiged to attach with DSI connector on pine64 boards, enable the same for pine64 LTS.

DSI panel connected via board DSI port with,
- DC1SW as AVDD supply
- DLDO2 as DVDD supply
- DLDO1 as VCC-DSI supply
- PD24 gpio for reset pin
- PH10 gpio for backlight enable pin

---
 .../dts/allwinner/sun50i-a64-pine64-lts.dts   | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)
arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-lts.dts +37 -0
index 72d6961dc312..9e230c612799 100644
@@ -5,9 +5,46 @@
  */
 
 #include "sun50i-a64-sopine-baseboard.dts"
+#include <dt-bindings/pwm/pwm.h>
 
 / {
 	model = "Pine64 LTS";
 	compatible = "pine64,pine64-lts", "allwinner,sun50i-r18",
 		     "allwinner,sun50i-a64";
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&r_pwm 0 50000 PWM_POLARITY_INVERTED>;
+		brightness-levels = <1 2 4 8 16 32 64 128 512>;
+		default-brightness-level = <8>;
+		enable-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* LCD-BL-EN: PH10 */
+	};
+};
+
+&de {
+	status = "okay";
+};
+
+&dphy {
+	status = "okay";
+};
+
+&dsi {
+	vcc-dsi-supply = <&reg_dldo1>;		/* VCC3V3-DSI */
+	status = "okay";
+
+	panel@0 {
+		compatible = "feiyang,fy07024di26a30d";
+		reg = <0>;
+		avdd-supply = <&reg_dc1sw>;	/* VCC-LCD */
+		dvdd-supply = <&reg_dldo2>;	/* VCC-MIPI */
+		reset-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* LCD-RST: PD24 */
+		backlight = <&backlight>;
+	};
+};
+
+&r_pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&r_pwm_pin>;
+	status = "okay";
 };
Signature · 1 line
2.18.0.321.gffc6fa0e3