diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 117 |
1 files changed, 69 insertions, 48 deletions
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index bfbf761f0c1d..e3b34a345546 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -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, @@ -812,8 +833,8 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host, dsi->device = device; dsi->panel = of_drm_find_panel(device->dev.of_node); - if (!dsi->panel) - return -EINVAL; + if (IS_ERR(dsi->panel)) + return PTR_ERR(dsi->panel); dev_info(host->dev, "Attached device %s\n", device->name); @@ -920,7 +941,7 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master, goto err_cleanup_connector; } - drm_mode_connector_attach_encoder(&dsi->connector, &dsi->encoder); + drm_connector_attach_encoder(&dsi->connector, &dsi->encoder); drm_panel_attach(dsi->panel, &dsi->connector); return 0; @@ -1040,7 +1061,7 @@ static int sun6i_dsi_remove(struct platform_device *pdev) return 0; } -static int sun6i_dsi_runtime_resume(struct device *dev) +static int __maybe_unused sun6i_dsi_runtime_resume(struct device *dev) { struct sun6i_dsi *dsi = dev_get_drvdata(dev); @@ -1069,7 +1090,7 @@ static int sun6i_dsi_runtime_resume(struct device *dev) return 0; } -static int sun6i_dsi_runtime_suspend(struct device *dev) +static int __maybe_unused sun6i_dsi_runtime_suspend(struct device *dev) { struct sun6i_dsi *dsi = dev_get_drvdata(dev); |