diff options
Diffstat (limited to 'drivers/gpu/drm/stm')
| -rw-r--r-- | drivers/gpu/drm/stm/drv.c | 18 | ||||
| -rw-r--r-- | drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/stm/ltdc.c | 202 | ||||
| -rw-r--r-- | drivers/gpu/drm/stm/ltdc.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/stm/lvds.c | 35 |
5 files changed, 173 insertions, 104 deletions
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 478dc129d5c2..56d53ac3082d 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -16,15 +16,16 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_client_setup.h> #include <drm/drm_drv.h> #include <drm/drm_fbdev_dma.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> #include <drm/drm_managed.h> @@ -62,7 +63,6 @@ static const struct drm_driver drv_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, .name = "stm", .desc = "STMicroelectronics SoC DRM", - .date = "20170330", .major = 1, .minor = 0, .patchlevel = 0, @@ -237,15 +237,25 @@ static void stm_drm_platform_shutdown(struct platform_device *pdev) drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); } +static struct ltdc_plat_data stm_drm_plat_data = { + .pad_max_freq_hz = 90000000, +}; + +static struct ltdc_plat_data stm_drm_plat_data_mp25 = { + .pad_max_freq_hz = 150000000, +}; + static const struct of_device_id drv_dt_ids[] = { - { .compatible = "st,stm32-ltdc"}, + { .compatible = "st,stm32-ltdc", .data = &stm_drm_plat_data, }, + { .compatible = "st,stm32mp251-ltdc", .data = &stm_drm_plat_data_mp25, }, + { .compatible = "st,stm32mp255-ltdc", .data = &stm_drm_plat_data_mp25, }, { /* end node */ }, }; MODULE_DEVICE_TABLE(of, drv_dt_ids); static struct platform_driver stm_drm_platform_driver = { .probe = stm_drm_platform_probe, - .remove_new = stm_drm_platform_remove, + .remove = stm_drm_platform_remove, .shutdown = stm_drm_platform_shutdown, .driver = { .name = "stm32-display", diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index b20123854c4a..58eae6804cc8 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -274,8 +274,8 @@ static unsigned long dw_mipi_dsi_clk_recalc_rate(struct clk_hw *hw, return (unsigned long)pll_out_khz * 1000; } -static long dw_mipi_dsi_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int dw_mipi_dsi_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct dw_mipi_dsi_stm *dsi = clk_to_dw_mipi_dsi_stm(hw); unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz; @@ -283,14 +283,14 @@ static long dw_mipi_dsi_clk_round_rate(struct clk_hw *hw, unsigned long rate, DRM_DEBUG_DRIVER("\n"); - pll_in_khz = (unsigned int)(*parent_rate / 1000); + pll_in_khz = (unsigned int)(req->best_parent_rate / 1000); /* Compute best pll parameters */ idf = 0; ndiv = 0; odf = 0; - ret = dsi_pll_get_params(dsi, pll_in_khz, rate / 1000, + ret = dsi_pll_get_params(dsi, pll_in_khz, req->rate / 1000, &idf, &ndiv, &odf); if (ret) DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); @@ -298,7 +298,9 @@ static long dw_mipi_dsi_clk_round_rate(struct clk_hw *hw, unsigned long rate, /* Get the adjusted pll out value */ pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf); - return pll_out_khz * 1000; + req->rate = pll_out_khz * 1000; + + return 0; } static int dw_mipi_dsi_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -351,7 +353,7 @@ static const struct clk_ops dw_mipi_dsi_stm_clk_ops = { .disable = dw_mipi_dsi_clk_disable, .is_enabled = dw_mipi_dsi_clk_is_enabled, .recalc_rate = dw_mipi_dsi_clk_recalc_rate, - .round_rate = dw_mipi_dsi_clk_round_rate, + .determine_rate = dw_mipi_dsi_clk_determine_rate, .set_rate = dw_mipi_dsi_clk_set_rate, }; @@ -783,7 +785,7 @@ static const struct dev_pm_ops dw_mipi_dsi_stm_pm_ops = { static struct platform_driver dw_mipi_dsi_stm_driver = { .probe = dw_mipi_dsi_stm_probe, - .remove_new = dw_mipi_dsi_stm_remove, + .remove = dw_mipi_dsi_stm_remove, .driver = { .of_match_table = dw_mipi_dsi_stm_dt_ids, .name = "stm32-display-dsi", diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 54a73753eff9..f7e847cfa38f 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -14,6 +14,7 @@ #include <linux/interrupt.h> #include <linux/media-bus-format.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_graph.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -33,6 +34,7 @@ #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_of.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> @@ -51,6 +53,7 @@ #define HWVER_10300 0x010300 #define HWVER_20101 0x020101 #define HWVER_40100 0x040100 +#define HWVER_40101 0x040101 /* * The address of some registers depends on the HW version: such registers have @@ -641,7 +644,7 @@ static inline void ltdc_set_ycbcr_config(struct drm_plane *plane, u32 drm_pix_fm break; default: /* RGB or not a YCbCr supported format */ - DRM_ERROR("Unsupported pixel format: %u\n", drm_pix_fmt); + drm_err(plane->dev, "Unsupported pixel format: %u\n", drm_pix_fmt); return; } @@ -664,18 +667,19 @@ static inline void ltdc_set_ycbcr_coeffs(struct drm_plane *plane) u32 lofs = plane->index * LAY_OFS; if (enc != DRM_COLOR_YCBCR_BT601 && enc != DRM_COLOR_YCBCR_BT709) { - DRM_ERROR("color encoding %d not supported, use bt601 by default\n", enc); + drm_err(plane->dev, "color encoding %d not supported, use bt601 by default\n", enc); /* set by default color encoding to DRM_COLOR_YCBCR_BT601 */ enc = DRM_COLOR_YCBCR_BT601; } if (ran != DRM_COLOR_YCBCR_LIMITED_RANGE && ran != DRM_COLOR_YCBCR_FULL_RANGE) { - DRM_ERROR("color range %d not supported, use limited range by default\n", ran); + drm_err(plane->dev, + "color range %d not supported, use limited range by default\n", ran); /* set by default color range to DRM_COLOR_YCBCR_LIMITED_RANGE */ ran = DRM_COLOR_YCBCR_LIMITED_RANGE; } - DRM_DEBUG_DRIVER("Color encoding=%d, range=%d\n", enc, ran); + drm_err(plane->dev, "Color encoding=%d, range=%d\n", enc, ran); regmap_write(ldev->regmap, LTDC_L1CYR0R + lofs, ltdc_ycbcr2rgb_coeffs[enc][ran][0]); regmap_write(ldev->regmap, LTDC_L1CYR1R + lofs, @@ -774,7 +778,7 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, struct ltdc_device *ldev = crtc_to_ltdc(crtc); struct drm_device *ddev = crtc->dev; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(crtc->dev, "\n"); pm_runtime_get_sync(ddev->dev); @@ -798,7 +802,7 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_device *ddev = crtc->dev; int layer_index = 0; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(crtc->dev, "\n"); drm_crtc_vblank_off(crtc); @@ -835,9 +839,15 @@ ltdc_crtc_mode_valid(struct drm_crtc *crtc, int target_max = target + CLK_TOLERANCE_HZ; int result; + if (ldev->lvds_clk) { + result = clk_round_rate(ldev->lvds_clk, target); + drm_dbg_driver(crtc->dev, "lvds pixclk rate target %d, available %d\n", + target, result); + } + result = clk_round_rate(ldev->pixel_clk, target); - DRM_DEBUG_DRIVER("clk rate target %d, available %d\n", target, result); + drm_dbg_driver(crtc->dev, "clk rate target %d, available %d\n", target, result); /* Filter modes according to the max frequency supported by the pads */ if (result > ldev->caps.pad_max_freq_hz) @@ -872,14 +882,14 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, int rate = mode->clock * 1000; if (clk_set_rate(ldev->pixel_clk, rate) < 0) { - DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate); + drm_err(crtc->dev, "Cannot set rate (%dHz) for pixel clk\n", rate); return false; } adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000; - DRM_DEBUG_DRIVER("requested clock %dkHz, adjusted clock %dkHz\n", - mode->clock, adjusted_mode->clock); + drm_dbg_driver(crtc->dev, "requested clock %dkHz, adjusted clock %dkHz\n", + mode->clock, adjusted_mode->clock); return true; } @@ -934,20 +944,20 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) if (!pm_runtime_active(ddev->dev)) { ret = pm_runtime_get_sync(ddev->dev); if (ret) { - DRM_ERROR("Failed to set mode, cannot get sync\n"); + drm_err(crtc->dev, "Failed to set mode, cannot get sync\n"); return; } } - DRM_DEBUG_DRIVER("CRTC:%d mode:%s\n", crtc->base.id, mode->name); - DRM_DEBUG_DRIVER("Video mode: %dx%d", mode->hdisplay, mode->vdisplay); - DRM_DEBUG_DRIVER(" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n", - mode->hsync_start - mode->hdisplay, - mode->htotal - mode->hsync_end, - mode->hsync_end - mode->hsync_start, - mode->vsync_start - mode->vdisplay, - mode->vtotal - mode->vsync_end, - mode->vsync_end - mode->vsync_start); + drm_dbg_driver(crtc->dev, "CRTC:%d mode:%s\n", crtc->base.id, mode->name); + drm_dbg_driver(crtc->dev, "Video mode: %dx%d", mode->hdisplay, mode->vdisplay); + drm_dbg_driver(crtc->dev, " hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n", + mode->hsync_start - mode->hdisplay, + mode->htotal - mode->hsync_end, + mode->hsync_end - mode->hsync_start, + mode->vsync_start - mode->vdisplay, + mode->vtotal - mode->vsync_end, + mode->vsync_end - mode->vsync_start); /* Convert video timings to ltdc timings */ hsync = mode->hsync_end - mode->hsync_start - 1; @@ -1033,7 +1043,7 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_device *ddev = crtc->dev; struct drm_pending_vblank_event *event = crtc->state->event; - DRM_DEBUG_ATOMIC("\n"); + drm_dbg_atomic(crtc->dev, "\n"); ltdc_crtc_update_clut(crtc); @@ -1121,7 +1131,7 @@ static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc) struct ltdc_device *ldev = crtc_to_ltdc(crtc); struct drm_crtc_state *state = crtc->state; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(crtc->dev, "\n"); if (state->enable) regmap_set_bits(ldev->regmap, LTDC_IER, IER_LIE); @@ -1135,7 +1145,7 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) { struct ltdc_device *ldev = crtc_to_ltdc(crtc); - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(crtc->dev, "\n"); regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE); } @@ -1144,11 +1154,11 @@ static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source) struct ltdc_device *ldev; int ret; - DRM_DEBUG_DRIVER("\n"); - if (!crtc) return -ENODEV; + drm_dbg_driver(crtc->dev, "\n"); + ldev = crtc_to_ltdc(crtc); if (source && strcmp(source, "auto") == 0) { @@ -1168,14 +1178,14 @@ static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source) static int ltdc_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source, size_t *values_cnt) { - DRM_DEBUG_DRIVER("\n"); - if (!crtc) return -ENODEV; + drm_dbg_driver(crtc->dev, "\n"); + if (source && strcmp(source, "auto") != 0) { - DRM_DEBUG_DRIVER("Unknown CRC source %s for %s\n", - source, crtc->name); + drm_dbg_driver(crtc->dev, "Unknown CRC source %s for %s\n", + source, crtc->name); return -EINVAL; } @@ -1233,7 +1243,7 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, struct drm_framebuffer *fb = new_plane_state->fb; u32 src_w, src_h; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(plane->dev, "\n"); if (!fb) return 0; @@ -1244,7 +1254,7 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, /* Reject scaling */ if (src_w != new_plane_state->crtc_w || src_h != new_plane_state->crtc_h) { - DRM_DEBUG_DRIVER("Scaling is not supported"); + drm_dbg_driver(plane->dev, "Scaling is not supported"); return -EINVAL; } @@ -1270,7 +1280,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, enum ltdc_pix_fmt pf; if (!newstate->crtc || !fb) { - DRM_DEBUG_DRIVER("fb or crtc NULL"); + drm_dbg_driver(plane->dev, "fb or crtc NULL"); return; } @@ -1280,11 +1290,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, src_w = newstate->src_w >> 16; src_h = newstate->src_h >> 16; - DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", - plane->base.id, fb->base.id, - src_w, src_h, src_x, src_y, - newstate->crtc_w, newstate->crtc_h, - newstate->crtc_x, newstate->crtc_y); + drm_dbg_driver(plane->dev, "plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n", + plane->base.id, fb->base.id, + src_w, src_h, src_x, src_y, + newstate->crtc_w, newstate->crtc_h, + newstate->crtc_x, newstate->crtc_y); regmap_read(ldev->regmap, LTDC_BPCR, &bpcr); @@ -1312,8 +1322,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, val = ltdc_set_flexible_pixel_format(plane, pf); if (val == NB_PF) { - DRM_ERROR("Pixel format %.4s not supported\n", - (char *)&fb->format->format); + drm_err(fb->dev, "Pixel format %.4s not supported\n", + (char *)&fb->format->format); val = 0; /* set by default ARGB 32 bits */ } regmap_write_bits(ldev->regmap, LTDC_L1PFCR + lofs, LXPFCR_PF, val); @@ -1350,7 +1360,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, if (newstate->rotation & DRM_MODE_REFLECT_Y) paddr += (fb->pitches[0] * (y1 - y0)); - DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr); + drm_dbg_driver(fb->dev, "fb: phys 0x%08x", paddr); regmap_write(ldev->regmap, LTDC_L1CFBAR + lofs, paddr); /* Configures the color frame buffer pitch in bytes & line length */ @@ -1517,8 +1527,8 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane, regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs, LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR); - DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n", - oldstate->crtc->base.id, plane->base.id); + drm_dbg_driver(plane->dev, "CRTC:%d plane:%d\n", + oldstate->crtc->base.id, plane->base.id); } static void ltdc_plane_atomic_print_state(struct drm_printer *p, @@ -1632,7 +1642,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, drm_plane_create_alpha_property(plane); - DRM_DEBUG_DRIVER("plane:%d created\n", plane->base.id); + drm_dbg_driver(plane->dev, "plane:%d created\n", plane->base.id); return plane; } @@ -1647,7 +1657,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY, 0); if (!primary) { - DRM_ERROR("Can not create primary plane\n"); + drm_err(ddev, "Can not create primary plane\n"); return -EINVAL; } @@ -1668,7 +1678,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL, <dc_crtc_funcs, NULL); if (ret) { - DRM_ERROR("Can not initialize CRTC\n"); + drm_err(ddev, "Can not initialize CRTC\n"); return ret; } @@ -1677,13 +1687,13 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE); - DRM_DEBUG_DRIVER("CRTC:%d created\n", crtc->base.id); + drm_dbg_driver(ddev, "CRTC:%d created\n", crtc->base.id); /* Add planes. Note : the first layer is used by primary plane */ for (i = 1; i < ldev->caps.nb_layers; i++) { overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i); if (!overlay) { - DRM_ERROR("Can not create overlay plane %d\n", i); + drm_err(ddev, "Can not create overlay plane %d\n", i); return -ENOMEM; } if (ldev->caps.dynamic_zorder) @@ -1704,7 +1714,7 @@ static void ltdc_encoder_disable(struct drm_encoder *encoder) struct drm_device *ddev = encoder->dev; struct ltdc_device *ldev = ddev->dev_private; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(encoder->dev, "\n"); /* Disable LTDC */ regmap_clear_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); @@ -1718,7 +1728,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder) struct drm_device *ddev = encoder->dev; struct ltdc_device *ldev = ddev->dev_private; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(encoder->dev, "\n"); /* set fifo underrun threshold register */ if (ldev->caps.fifo_threshold) @@ -1734,7 +1744,7 @@ static void ltdc_encoder_mode_set(struct drm_encoder *encoder, { struct drm_device *ddev = encoder->dev; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(encoder->dev, "\n"); /* * Set to default state the pinctrl only with DPI type. @@ -1770,7 +1780,7 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) if (ret) return ret; - DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id); + drm_dbg_driver(encoder->dev, "Bridge encoder:%d created\n", encoder->base.id); return 0; } @@ -1779,6 +1789,7 @@ static int ltdc_get_caps(struct drm_device *ddev) { struct ltdc_device *ldev = ddev->dev_private; u32 bus_width_log2, lcr, gc2r; + const struct ltdc_plat_data *pdata = of_device_get_match_data(ddev->dev); /* * at least 1 layer must be managed & the number of layers @@ -1794,6 +1805,8 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.bus_width = 8 << bus_width_log2; regmap_read(ldev->regmap, LTDC_IDR, &ldev->caps.hw_version); + ldev->caps.pad_max_freq_hz = pdata->pad_max_freq_hz; + switch (ldev->caps.hw_version) { case HWVER_10200: case HWVER_10300: @@ -1811,7 +1824,6 @@ static int ltdc_get_caps(struct drm_device *ddev) * does not work on 2nd layer. */ ldev->caps.non_alpha_only_l1 = true; - ldev->caps.pad_max_freq_hz = 90000000; if (ldev->caps.hw_version == HWVER_10200) ldev->caps.pad_max_freq_hz = 65000000; ldev->caps.nb_irq = 2; @@ -1842,6 +1854,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.fifo_threshold = false; break; case HWVER_40100: + case HWVER_40101: ldev->caps.layer_ofs = LAY_OFS_1; ldev->caps.layer_regs = ltdc_layer_regs_a2; ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a2; @@ -1849,7 +1862,6 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a2); ldev->caps.pix_fmt_flex = true; ldev->caps.non_alpha_only_l1 = false; - ldev->caps.pad_max_freq_hz = 90000000; ldev->caps.nb_irq = 2; ldev->caps.ycbcr_input = true; ldev->caps.ycbcr_output = true; @@ -1870,8 +1882,12 @@ void ltdc_suspend(struct drm_device *ddev) { struct ltdc_device *ldev = ddev->dev_private; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(ddev, "\n"); clk_disable_unprepare(ldev->pixel_clk); + if (ldev->bus_clk) + clk_disable_unprepare(ldev->bus_clk); + if (ldev->lvds_clk) + clk_disable_unprepare(ldev->lvds_clk); } int ltdc_resume(struct drm_device *ddev) @@ -1879,15 +1895,29 @@ int ltdc_resume(struct drm_device *ddev) struct ltdc_device *ldev = ddev->dev_private; int ret; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(ddev, "\n"); ret = clk_prepare_enable(ldev->pixel_clk); if (ret) { - DRM_ERROR("failed to enable pixel clock (%d)\n", ret); + drm_err(ddev, "failed to enable pixel clock (%d)\n", ret); return ret; } - return 0; + if (ldev->bus_clk) { + ret = clk_prepare_enable(ldev->bus_clk); + if (ret) { + drm_err(ddev, "failed to enable bus clock (%d)\n", ret); + return ret; + } + } + + if (ldev->lvds_clk) { + ret = clk_prepare_enable(ldev->lvds_clk); + if (ret) + drm_err(ddev, "failed to prepare lvds clock\n"); + } + + return ret; } int ltdc_load(struct drm_device *ddev) @@ -1900,11 +1930,10 @@ int ltdc_load(struct drm_device *ddev) struct drm_panel *panel; struct drm_crtc *crtc; struct reset_control *rstc; - struct resource *res; int irq, i, nb_endpoints; int ret = -ENODEV; - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(ddev, "\n"); /* Get number of endpoints */ nb_endpoints = of_graph_get_endpoint_count(np); @@ -1914,15 +1943,29 @@ int ltdc_load(struct drm_device *ddev) ldev->pixel_clk = devm_clk_get(dev, "lcd"); if (IS_ERR(ldev->pixel_clk)) { if (PTR_ERR(ldev->pixel_clk) != -EPROBE_DEFER) - DRM_ERROR("Unable to get lcd clock\n"); + drm_err(ddev, "Unable to get lcd clock\n"); return PTR_ERR(ldev->pixel_clk); } if (clk_prepare_enable(ldev->pixel_clk)) { - DRM_ERROR("Unable to prepare pixel clock\n"); + drm_err(ddev, "Unable to prepare pixel clock\n"); return -ENODEV; } + if (of_device_is_compatible(np, "st,stm32mp251-ltdc") || + of_device_is_compatible(np, "st,stm32mp255-ltdc")) { + ldev->bus_clk = devm_clk_get(dev, "bus"); + if (IS_ERR(ldev->bus_clk)) + return dev_err_probe(dev, PTR_ERR(ldev->bus_clk), + "Unable to get bus clock\n"); + + ret = clk_prepare_enable(ldev->bus_clk); + if (ret) { + drm_err(ddev, "Unable to prepare bus clock\n"); + return ret; + } + } + /* Get endpoints if any */ for (i = 0; i < nb_endpoints; i++) { ret = drm_of_find_panel_or_bridge(np, 0, i, &panel, &bridge); @@ -1940,7 +1983,7 @@ int ltdc_load(struct drm_device *ddev) if (panel) { bridge = drmm_panel_bridge_add(ddev, panel); if (IS_ERR(bridge)) { - DRM_ERROR("panel-bridge endpoint %d\n", i); + drm_err(ddev, "panel-bridge endpoint %d\n", i); ret = PTR_ERR(bridge); goto err; } @@ -1950,12 +1993,16 @@ int ltdc_load(struct drm_device *ddev) ret = ltdc_encoder_init(ddev, bridge); if (ret) { if (ret != -EPROBE_DEFER) - DRM_ERROR("init encoder endpoint %d\n", i); + drm_err(ddev, "init encoder endpoint %d\n", i); goto err; } } } + ldev->lvds_clk = devm_clk_get(dev, "lvds"); + if (IS_ERR(ldev->lvds_clk)) + ldev->lvds_clk = NULL; + rstc = devm_reset_control_get_exclusive(dev, NULL); mutex_init(&ldev->err_lock); @@ -1966,32 +2013,31 @@ int ltdc_load(struct drm_device *ddev) reset_control_deassert(rstc); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ldev->regs = devm_ioremap_resource(dev, res); + ldev->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ldev->regs)) { - DRM_ERROR("Unable to get ltdc registers\n"); + drm_err(ddev, "Unable to get ltdc registers\n"); ret = PTR_ERR(ldev->regs); goto err; } ldev->regmap = devm_regmap_init_mmio(&pdev->dev, ldev->regs, &stm32_ltdc_regmap_cfg); if (IS_ERR(ldev->regmap)) { - DRM_ERROR("Unable to regmap ltdc registers\n"); + drm_err(ddev, "Unable to regmap ltdc registers\n"); ret = PTR_ERR(ldev->regmap); goto err; } ret = ltdc_get_caps(ddev); if (ret) { - DRM_ERROR("hardware identifier (0x%08x) not supported!\n", - ldev->caps.hw_version); + drm_err(ddev, "hardware identifier (0x%08x) not supported!\n", + ldev->caps.hw_version); goto err; } /* Disable all interrupts */ regmap_clear_bits(ldev->regmap, LTDC_IER, IER_MASK); - DRM_DEBUG_DRIVER("ltdc hw version 0x%08x\n", ldev->caps.hw_version); + drm_dbg_driver(ddev, "ltdc hw version 0x%08x\n", ldev->caps.hw_version); /* initialize default value for fifo underrun threshold & clear interrupt error counters */ ldev->transfer_err = 0; @@ -2010,32 +2056,35 @@ int ltdc_load(struct drm_device *ddev) ltdc_irq_thread, IRQF_ONESHOT, dev_name(dev), ddev); if (ret) { - DRM_ERROR("Failed to register LTDC interrupt\n"); + drm_err(ddev, "Failed to register LTDC interrupt\n"); goto err; } } crtc = drmm_kzalloc(ddev, sizeof(*crtc), GFP_KERNEL); if (!crtc) { - DRM_ERROR("Failed to allocate crtc\n"); + drm_err(ddev, "Failed to allocate crtc\n"); ret = -ENOMEM; goto err; } ret = ltdc_crtc_init(ddev, crtc); if (ret) { - DRM_ERROR("Failed to init crtc\n"); + drm_err(ddev, "Failed to init crtc\n"); goto err; } ret = drm_vblank_init(ddev, NB_CRTC); if (ret) { - DRM_ERROR("Failed calling drm_vblank_init()\n"); + drm_err(ddev, "Failed calling drm_vblank_init()\n"); goto err; } clk_disable_unprepare(ldev->pixel_clk); + if (ldev->bus_clk) + clk_disable_unprepare(ldev->bus_clk); + pinctrl_pm_select_sleep_state(ddev->dev); pm_runtime_enable(ddev->dev); @@ -2044,12 +2093,15 @@ int ltdc_load(struct drm_device *ddev) err: clk_disable_unprepare(ldev->pixel_clk); + if (ldev->bus_clk) + clk_disable_unprepare(ldev->bus_clk); + return ret; } void ltdc_unload(struct drm_device *ddev) { - DRM_DEBUG_DRIVER("\n"); + drm_dbg_driver(ddev, "\n"); pm_runtime_disable(ddev->dev); } diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index 9d488043ffdb..17b51a7ce28e 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -40,10 +40,16 @@ struct fps_info { ktime_t last_timestamp; }; +struct ltdc_plat_data { + int pad_max_freq_hz; /* max frequency supported by pad */ +}; + struct ltdc_device { void __iomem *regs; struct regmap *regmap; struct clk *pixel_clk; /* lcd pixel clock */ + struct clk *lvds_clk; /* lvds pixel clock */ + struct clk *bus_clk; /* bus clock */ struct mutex err_lock; /* protecting error_status */ struct ltdc_caps caps; u32 irq_status; diff --git a/drivers/gpu/drm/stm/lvds.c b/drivers/gpu/drm/stm/lvds.c index 06f2d7a56cc9..fe38c0984b2b 100644 --- a/drivers/gpu/drm/stm/lvds.c +++ b/drivers/gpu/drm/stm/lvds.c @@ -682,8 +682,8 @@ static unsigned long lvds_pixel_clk_recalc_rate(struct clk_hw *hw, return (unsigned long)lvds->pixel_clock_rate; } -static long lvds_pixel_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int lvds_pixel_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct stm_lvds *lvds = container_of(hw, struct stm_lvds, lvds_ck_px); unsigned int pll_in_khz, bdiv = 0, mdiv = 0, ndiv = 0; @@ -703,7 +703,7 @@ static long lvds_pixel_clk_round_rate(struct clk_hw *hw, unsigned long rate, mode = list_first_entry(&connector->modes, struct drm_display_mode, head); - pll_in_khz = (unsigned int)(*parent_rate / 1000); + pll_in_khz = (unsigned int)(req->best_parent_rate / 1000); if (lvds_is_dual_link(lvds->link_type)) multiplier = 2; @@ -719,14 +719,16 @@ static long lvds_pixel_clk_round_rate(struct clk_hw *hw, unsigned long rate, lvds->pixel_clock_rate = (unsigned long)pll_get_clkout_khz(pll_in_khz, bdiv, mdiv, ndiv) * 1000 * multiplier / 7; - return lvds->pixel_clock_rate; + req->rate = lvds->pixel_clock_rate; + + return 0; } static const struct clk_ops lvds_pixel_clk_ops = { .enable = lvds_pixel_clk_enable, .disable = lvds_pixel_clk_disable, .recalc_rate = lvds_pixel_clk_recalc_rate, - .round_rate = lvds_pixel_clk_round_rate, + .determine_rate = lvds_pixel_clk_determine_rate, }; static const struct clk_init_data clk_data = { @@ -934,28 +936,27 @@ static const struct drm_connector_funcs lvds_conn_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int lvds_attach(struct drm_bridge *bridge, +static int lvds_attach(struct drm_bridge *bridge, struct drm_encoder *encoder, enum drm_bridge_attach_flags flags) { struct stm_lvds *lvds = bridge_to_stm_lvds(bridge); struct drm_connector *connector = &lvds->connector; - struct drm_encoder *encoder = bridge->encoder; int ret; - if (!bridge->encoder) { + if (!encoder) { drm_err(bridge->dev, "Parent encoder object not found\n"); return -ENODEV; } /* Set the encoder type as caller does not know it */ - bridge->encoder->encoder_type = DRM_MODE_ENCODER_LVDS; + encoder->encoder_type = DRM_MODE_ENCODER_LVDS; /* No cloning support */ - bridge->encoder->possible_clones = 0; + encoder->possible_clones = 0; /* If we have a next bridge just attach it. */ if (lvds->next_bridge) - return drm_bridge_attach(bridge->encoder, lvds->next_bridge, + return drm_bridge_attach(encoder, lvds->next_bridge, bridge, flags); if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { @@ -980,9 +981,8 @@ static int lvds_attach(struct drm_bridge *bridge, } static void lvds_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { - struct drm_atomic_state *state = old_bridge_state->base.state; struct stm_lvds *lvds = bridge_to_stm_lvds(bridge); struct drm_connector_state *conn_state; struct drm_connector *connector; @@ -1017,7 +1017,7 @@ static void lvds_atomic_enable(struct drm_bridge *bridge, } static void lvds_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { struct stm_lvds *lvds = bridge_to_stm_lvds(bridge); @@ -1051,9 +1051,9 @@ static int lvds_probe(struct platform_device *pdev) dev_dbg(dev, "Probing LVDS driver...\n"); - lvds = devm_kzalloc(dev, sizeof(*lvds), GFP_KERNEL); - if (!lvds) - return -ENOMEM; + lvds = devm_drm_bridge_alloc(dev, struct stm_lvds, lvds_bridge, &lvds_bridge_funcs); + if (IS_ERR(lvds)) + return PTR_ERR(lvds); lvds->dev = dev; @@ -1166,7 +1166,6 @@ static int lvds_probe(struct platform_device *pdev) goto err_lvds_probe; } - lvds->lvds_bridge.funcs = &lvds_bridge_funcs; lvds->lvds_bridge.of_node = dev->of_node; lvds->hw_version = lvds_read(lvds, LVDS_VERR); |
