|
@@ -13,6 +13,7 @@
|
|
|
#include <linux/pm_runtime.h>
|
|
|
#include <linux/regmap.h>
|
|
|
#include <linux/reset.h>
|
|
|
+#include <linux/slab.h>
|
|
|
|
|
|
#include <linux/phy/phy.h>
|
|
|
|
|
@@ -247,10 +248,8 @@ static u16 sun6i_dsi_crc_compute(u8 const *buffer, size_t len)
|
|
|
return crc_ccitt(0xffff, buffer, len);
|
|
|
}
|
|
|
|
|
|
-static u16 sun6i_dsi_crc_repeat_compute(u8 pd, size_t len)
|
|
|
+static u16 sun6i_dsi_crc_repeat(u8 pd, u8 *buffer, size_t len)
|
|
|
{
|
|
|
- u8 buffer[len];
|
|
|
-
|
|
|
memset(buffer, pd, len);
|
|
|
|
|
|
return sun6i_dsi_crc_compute(buffer, len);
|
|
@@ -274,11 +273,11 @@ static u32 sun6i_dsi_build_blk0_pkt(u8 vc, u16 wc)
|
|
|
wc & 0xff, wc >> 8);
|
|
|
}
|
|
|
|
|
|
-static u32 sun6i_dsi_build_blk1_pkt(u16 pd, size_t len)
|
|
|
+static u32 sun6i_dsi_build_blk1_pkt(u16 pd, u8 *buffer, size_t len)
|
|
|
{
|
|
|
u32 val = SUN6I_DSI_BLK_PD(pd);
|
|
|
|
|
|
- return val | SUN6I_DSI_BLK_PF(sun6i_dsi_crc_repeat_compute(pd, len));
|
|
|
+ return val | SUN6I_DSI_BLK_PF(sun6i_dsi_crc_repeat(pd, buffer, len));
|
|
|
}
|
|
|
|
|
|
static void sun6i_dsi_inst_abort(struct sun6i_dsi *dsi)
|
|
@@ -452,6 +451,54 @@ 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;
|
|
|
+ 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);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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->hsync_start - mode->hdisplay) * 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->htotal - mode->hsync_end) * Bpp - HFP_PACKET_OVERHEAD);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * hblk seems to be the line + porches length.
|
|
|
+ */
|
|
|
+ hblk = mode->htotal * Bpp - hsa;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * And I'm not entirely sure what vblk is about. The driver in
|
|
|
+ * Allwinner BSP is using a rather convoluted calculation
|
|
|
+ * there only for 4 lanes. However, using 0 (the !4 lanes
|
|
|
+ * case) even with a 4 lanes screen seems to work...
|
|
|
+ */
|
|
|
+ vblk = 0;
|
|
|
+
|
|
|
+ /* How many bytes do we need to send all payloads? */
|
|
|
+ bytes = max_t(size_t, max(max(hfp, hblk), max(hsa, hbp)), vblk);
|
|
|
+ buffer = kmalloc(bytes, GFP_KERNEL);
|
|
|
+ if (WARN_ON(!buffer))
|
|
|
+ return;
|
|
|
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, 0);
|
|
|
|
|
@@ -485,63 +532,37 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,
|
|
|
SUN6I_DSI_BASIC_SIZE1_VACT(mode->vdisplay) |
|
|
|
SUN6I_DSI_BASIC_SIZE1_VT(mode->vtotal));
|
|
|
|
|
|
- /*
|
|
|
- * 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);
|
|
|
+ /* sync */
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA0_REG,
|
|
|
sun6i_dsi_build_blk0_pkt(device->channel, hsa));
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA1_REG,
|
|
|
- sun6i_dsi_build_blk1_pkt(0, hsa));
|
|
|
+ sun6i_dsi_build_blk1_pkt(0, buffer, hsa));
|
|
|
|
|
|
- /*
|
|
|
- * 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->hsync_start - mode->hdisplay) * Bpp - HBP_PACKET_OVERHEAD);
|
|
|
+ /* backporch */
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP0_REG,
|
|
|
sun6i_dsi_build_blk0_pkt(device->channel, hbp));
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP1_REG,
|
|
|
- sun6i_dsi_build_blk1_pkt(0, hbp));
|
|
|
+ sun6i_dsi_build_blk1_pkt(0, buffer, hbp));
|
|
|
|
|
|
- /*
|
|
|
- * 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->htotal - mode->hsync_end) * Bpp - HFP_PACKET_OVERHEAD);
|
|
|
+ /* frontporch */
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP0_REG,
|
|
|
sun6i_dsi_build_blk0_pkt(device->channel, hfp));
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP1_REG,
|
|
|
- sun6i_dsi_build_blk1_pkt(0, hfp));
|
|
|
+ sun6i_dsi_build_blk1_pkt(0, buffer, hfp));
|
|
|
|
|
|
- /*
|
|
|
- * hblk seems to be the line + porches length.
|
|
|
- */
|
|
|
- hblk = mode->htotal * Bpp - hsa;
|
|
|
+ /* hblk */
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK0_REG,
|
|
|
sun6i_dsi_build_blk0_pkt(device->channel, hblk));
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK1_REG,
|
|
|
- sun6i_dsi_build_blk1_pkt(0, hblk));
|
|
|
+ sun6i_dsi_build_blk1_pkt(0, buffer, hblk));
|
|
|
|
|
|
- /*
|
|
|
- * And I'm not entirely sure what vblk is about. The driver in
|
|
|
- * Allwinner BSP is using a rather convoluted calculation
|
|
|
- * there only for 4 lanes. However, using 0 (the !4 lanes
|
|
|
- * case) even with a 4 lanes screen seems to work...
|
|
|
- */
|
|
|
- vblk = 0;
|
|
|
+ /* vblk */
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK0_REG,
|
|
|
sun6i_dsi_build_blk0_pkt(device->channel, vblk));
|
|
|
regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK1_REG,
|
|
|
- sun6i_dsi_build_blk1_pkt(0, vblk));
|
|
|
+ sun6i_dsi_build_blk1_pkt(0, buffer, vblk));
|
|
|
+
|
|
|
+ kfree(buffer);
|
|
|
}
|
|
|
|
|
|
static int sun6i_dsi_start(struct sun6i_dsi *dsi,
|