Lines Matching +full:dsi +full:- +full:phy

1 // SPDX-License-Identifier: GPL-2.0+
12 #include <linux/media-bus-format.h>
16 #include <linux/phy/phy.h>
17 #include <linux/phy/phy-mipi-dphy.h>
42 #define M(x) FIELD_PREP(M_MASK, ((x) - 2))
44 #define N(x) FIELD_PREP(N_MASK, ((x) - 1))
121 /* DPHY Databook Table 3-13 Charge-pump Programmability */
136 /* DPHY Databook Table 5-7 Frequency Ranges and Defaults */
203 static void dphy_pll_write(struct imx93_dsi *dsi, unsigned int reg, u32 value) in dphy_pll_write() argument
207 ret = regmap_write(dsi->regmap, reg, value); in dphy_pll_write()
209 dev_err(dsi->dev, "failed to write 0x%08x to pll reg 0x%x: %d\n", in dphy_pll_write()
220 dphy_pll_get_configure_from_opts(struct imx93_dsi *dsi, in dphy_pll_get_configure_from_opts() argument
224 struct device *dev = dsi->dev; in dphy_pll_get_configure_from_opts()
225 unsigned long fin = dsi->ref_clk_rate; in dphy_pll_get_configure_from_opts()
235 if (dphy_opts->hs_clk_rate < DATA_RATE_MIN_SPEED || in dphy_pll_get_configure_from_opts()
236 dphy_opts->hs_clk_rate > DATA_RATE_MAX_SPEED) { in dphy_pll_get_configure_from_opts()
238 dphy_opts->hs_clk_rate); in dphy_pll_get_configure_from_opts()
239 return -EINVAL; in dphy_pll_get_configure_from_opts()
242 fout = data_rate_to_fout(dphy_opts->hs_clk_rate); in dphy_pll_get_configure_from_opts()
274 delta = abs(fout - tmp); in dphy_pll_get_configure_from_opts()
284 cfg->m = best_m; in dphy_pll_get_configure_from_opts()
285 cfg->n = best_n; in dphy_pll_get_configure_from_opts()
287 best_fout, cfg->m, cfg->n); in dphy_pll_get_configure_from_opts()
290 return -EINVAL; in dphy_pll_get_configure_from_opts()
296 static void dphy_pll_clear_shadow(struct imx93_dsi *dsi) in dphy_pll_clear_shadow() argument
298 /* Reference DPHY Databook Figure 3-3 Initialization Timing Diagram. */ in dphy_pll_clear_shadow()
300 dphy_pll_write(dsi, DSI_REG, CLKSEL_GEN); in dphy_pll_clear_shadow()
304 dphy_pll_write(dsi, DSI_REG, CLKSEL_GEN | SHADOW_CLR); in dphy_pll_clear_shadow()
308 dphy_pll_write(dsi, DSI_REG, CLKSEL_GEN); in dphy_pll_clear_shadow()
311 static unsigned long dphy_pll_get_cfgclkrange(struct imx93_dsi *dsi) in dphy_pll_get_cfgclkrange() argument
314 * DPHY Databook Table 4-4 System Control Signals mentions an equation in dphy_pll_get_cfgclkrange()
317 return (clk_get_rate(dsi->clk_cfg) / MHZ(1) - 17) * 4; in dphy_pll_get_cfgclkrange()
323 unsigned long mbps = dphy_opts->hs_clk_rate / MHZ(1); in dphy_pll_get_hsfreqrange()
335 unsigned long fout = data_rate_to_fout(dphy_opts->hs_clk_rate) / MHZ(1); in dphy_pll_get_vco()
347 unsigned long fout = data_rate_to_fout(dphy_opts->hs_clk_rate) / MHZ(1); in dphy_pll_get_prop()
357 static int dphy_pll_update(struct imx93_dsi *dsi) in dphy_pll_update() argument
361 ret = regmap_update_bits(dsi->regmap, DSI_REG, UPDATE_PLL, UPDATE_PLL); in dphy_pll_update()
363 dev_err(dsi->dev, "failed to set UPDATE_PLL: %d\n", ret); in dphy_pll_update()
369 * cycles, according to DPHY Databook Figure 3-3 Initialization Timing in dphy_pll_update()
374 ret = regmap_update_bits(dsi->regmap, DSI_REG, UPDATE_PLL, 0); in dphy_pll_update()
376 dev_err(dsi->dev, "failed to clear UPDATE_PLL: %d\n", ret); in dphy_pll_update()
383 static int dphy_pll_configure(struct imx93_dsi *dsi, union phy_configure_opts *opts) in dphy_pll_configure() argument
389 ret = dphy_pll_get_configure_from_opts(dsi, &opts->mipi_dphy, &cfg); in dphy_pll_configure()
391 dev_err(dsi->dev, "failed to get phy pll cfg %d\n", ret); in dphy_pll_configure()
395 dphy_pll_clear_shadow(dsi); in dphy_pll_configure()
399 CFGCLKFREQRANGE(dphy_pll_get_cfgclkrange(dsi)) | in dphy_pll_configure()
400 HSFREQRANGE(dphy_pll_get_hsfreqrange(&opts->mipi_dphy)); in dphy_pll_configure()
401 dphy_pll_write(dsi, DSI_REG, val); in dphy_pll_configure()
405 VCO_CTRL(dphy_pll_get_vco(&opts->mipi_dphy)) | in dphy_pll_configure()
406 PROP_CTRL(dphy_pll_get_prop(&opts->mipi_dphy)); in dphy_pll_configure()
407 dphy_pll_write(dsi, DSI_WRITE_REG0, val); in dphy_pll_configure()
410 dphy_pll_write(dsi, DSI_WRITE_REG1, GMP_CTRL(1) | CPBIAS_CTRL(0x10)); in dphy_pll_configure()
412 ret = clk_prepare_enable(dsi->clk_ref); in dphy_pll_configure()
414 dev_err(dsi->dev, "failed to enable ref clock: %d\n", ret); in dphy_pll_configure()
420 * according to DPHY Databook Figure 3-3 Initialization Timing Diagram. in dphy_pll_configure()
424 ret = dphy_pll_update(dsi); in dphy_pll_configure()
426 clk_disable_unprepare(dsi->clk_ref); in dphy_pll_configure()
433 static void dphy_pll_clear_reg(struct imx93_dsi *dsi) in dphy_pll_clear_reg() argument
435 dphy_pll_write(dsi, DSI_REG, 0); in dphy_pll_clear_reg()
436 dphy_pll_write(dsi, DSI_WRITE_REG0, 0); in dphy_pll_clear_reg()
437 dphy_pll_write(dsi, DSI_WRITE_REG1, 0); in dphy_pll_clear_reg()
440 static int dphy_pll_init(struct imx93_dsi *dsi) in dphy_pll_init() argument
444 ret = clk_prepare_enable(dsi->clk_cfg); in dphy_pll_init()
446 dev_err(dsi->dev, "failed to enable config clock: %d\n", ret); in dphy_pll_init()
450 dphy_pll_clear_reg(dsi); in dphy_pll_init()
455 static void dphy_pll_uninit(struct imx93_dsi *dsi) in dphy_pll_uninit() argument
457 dphy_pll_clear_reg(dsi); in dphy_pll_uninit()
458 clk_disable_unprepare(dsi->clk_cfg); in dphy_pll_uninit()
461 static void dphy_pll_power_off(struct imx93_dsi *dsi) in dphy_pll_power_off() argument
463 dphy_pll_clear_reg(dsi); in dphy_pll_power_off()
464 clk_disable_unprepare(dsi->clk_ref); in dphy_pll_power_off()
467 static int imx93_dsi_get_phy_configure_opts(struct imx93_dsi *dsi, in imx93_dsi_get_phy_configure_opts() argument
472 struct device *dev = dsi->dev; in imx93_dsi_get_phy_configure_opts()
479 return -EINVAL; in imx93_dsi_get_phy_configure_opts()
482 ret = phy_mipi_dphy_get_default_config(mode->clock * MSEC_PER_SEC, bpp, in imx93_dsi_get_phy_configure_opts()
483 lanes, &phy_cfg->mipi_dphy); in imx93_dsi_get_phy_configure_opts()
485 dev_dbg(dev, "failed to get default phy cfg %d\n", ret); in imx93_dsi_get_phy_configure_opts()
493 imx93_dsi_validate_mode(struct imx93_dsi *dsi, const struct drm_display_mode *mode) in imx93_dsi_validate_mode() argument
495 struct drm_bridge *bridge = dw_mipi_dsi_get_bridge(dsi->dmd); in imx93_dsi_validate_mode()
501 if ((bridge->ops & DRM_BRIDGE_OP_DETECT) && in imx93_dsi_validate_mode()
502 (bridge->ops & DRM_BRIDGE_OP_EDID)) { in imx93_dsi_validate_mode()
503 unsigned long pixel_clock_rate = mode->clock * 1000; in imx93_dsi_validate_mode()
506 /* Allow +/-0.5% pixel clock rate deviation */ in imx93_dsi_validate_mode()
507 rounded_rate = clk_round_rate(dsi->clk_pixel, pixel_clock_rate); in imx93_dsi_validate_mode()
510 dev_dbg(dsi->dev, "failed to round clock for mode " DRM_MODE_FMT "\n", in imx93_dsi_validate_mode()
520 imx93_dsi_validate_phy(struct imx93_dsi *dsi, const struct drm_display_mode *mode, in imx93_dsi_validate_phy() argument
525 struct device *dev = dsi->dev; in imx93_dsi_validate_phy()
528 ret = imx93_dsi_get_phy_configure_opts(dsi, mode, &phy_cfg, lanes, in imx93_dsi_validate_phy()
531 dev_dbg(dev, "failed to get phy cfg opts %d\n", ret); in imx93_dsi_validate_phy()
535 ret = dphy_pll_get_configure_from_opts(dsi, &phy_cfg.mipi_dphy, &cfg); in imx93_dsi_validate_phy()
537 dev_dbg(dev, "failed to get phy pll cfg %d\n", ret); in imx93_dsi_validate_phy()
548 struct imx93_dsi *dsi = priv_data; in imx93_dsi_mode_valid() local
549 struct device *dev = dsi->dev; in imx93_dsi_mode_valid()
552 ret = imx93_dsi_validate_mode(dsi, mode); in imx93_dsi_mode_valid()
559 ret = imx93_dsi_validate_phy(dsi, mode, mode_flags, lanes, format); in imx93_dsi_mode_valid()
561 dev_dbg(dev, "failed to validate phy for mode " DRM_MODE_FMT "\n", in imx93_dsi_mode_valid()
573 struct imx93_dsi *dsi = priv_data; in imx93_dsi_mode_fixup() local
577 pixel_clock_rate = mode->clock * 1000; in imx93_dsi_mode_fixup()
578 rounded_rate = clk_round_rate(dsi->clk_pixel, pixel_clock_rate); in imx93_dsi_mode_fixup()
581 adjusted_mode->clock = rounded_rate / 1000; in imx93_dsi_mode_fixup()
583 dev_dbg(dsi->dev, "adj clock %d for mode " DRM_MODE_FMT "\n", in imx93_dsi_mode_fixup()
584 adjusted_mode->clock, DRM_MODE_ARG(mode)); in imx93_dsi_mode_fixup()
625 struct imx93_dsi *dsi = priv_data; in imx93_dsi_phy_init() local
629 switch (dsi->format) { in imx93_dsi_phy_init()
635 regmap_update_bits(dsi->regmap, DISPLAY_MUX, in imx93_dsi_phy_init()
640 regmap_update_bits(dsi->regmap, DISPLAY_MUX, in imx93_dsi_phy_init()
645 regmap_update_bits(dsi->regmap, DISPLAY_MUX, in imx93_dsi_phy_init()
650 regmap_update_bits(dsi->regmap, DISPLAY_MUX, LCDIF_CROSS_LINE_PATTERN, fmt); in imx93_dsi_phy_init()
652 ret = dphy_pll_init(dsi); in imx93_dsi_phy_init()
654 dev_err(dsi->dev, "failed to init phy pll: %d\n", ret); in imx93_dsi_phy_init()
658 ret = dphy_pll_configure(dsi, &dsi->phy_cfg); in imx93_dsi_phy_init()
660 dev_err(dsi->dev, "failed to configure phy pll: %d\n", ret); in imx93_dsi_phy_init()
661 dphy_pll_uninit(dsi); in imx93_dsi_phy_init()
670 struct imx93_dsi *dsi = priv_data; in imx93_dsi_phy_power_off() local
672 dphy_pll_power_off(dsi); in imx93_dsi_phy_power_off()
673 dphy_pll_uninit(dsi); in imx93_dsi_phy_power_off()
681 struct imx93_dsi *dsi = priv_data; in imx93_dsi_get_lane_mbps() local
683 struct device *dev = dsi->dev; in imx93_dsi_get_lane_mbps()
686 ret = imx93_dsi_get_phy_configure_opts(dsi, mode, &phy_cfg, lanes, in imx93_dsi_get_lane_mbps()
689 dev_dbg(dev, "failed to get phy cfg opts %d\n", ret); in imx93_dsi_get_lane_mbps()
695 memcpy(&dsi->phy_cfg, &phy_cfg, sizeof(phy_cfg)); in imx93_dsi_get_lane_mbps()
703 /* High-Speed Transition Times */
720 /* DPHY Databook Table A-4 High-Speed Transition Times */
790 struct imx93_dsi *dsi = priv_data; in imx93_dsi_phy_get_timing() local
791 struct device *dev = dsi->dev; in imx93_dsi_phy_get_timing()
799 dev_err(dev, "failed to get phy timing for lane_mbps %u\n", in imx93_dsi_phy_get_timing()
801 return -EINVAL; in imx93_dsi_phy_get_timing()
806 dev_dbg(dev, "get phy timing for %u <= %u (lane_mbps)\n", in imx93_dsi_phy_get_timing()
821 struct imx93_dsi *dsi = priv_data; in imx93_dsi_host_attach() local
823 dsi->format = device->format; in imx93_dsi_host_attach()
834 struct device *dev = &pdev->dev; in imx93_dsi_probe()
835 struct device_node *np = dev->of_node; in imx93_dsi_probe()
836 struct imx93_dsi *dsi; in imx93_dsi_probe() local
839 dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); in imx93_dsi_probe()
840 if (!dsi) in imx93_dsi_probe()
841 return -ENOMEM; in imx93_dsi_probe()
843 dsi->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,media-blk-ctrl"); in imx93_dsi_probe()
844 if (IS_ERR(dsi->regmap)) { in imx93_dsi_probe()
845 ret = PTR_ERR(dsi->regmap); in imx93_dsi_probe()
850 dsi->clk_pixel = devm_clk_get(dev, "pix"); in imx93_dsi_probe()
851 if (IS_ERR(dsi->clk_pixel)) in imx93_dsi_probe()
852 return dev_err_probe(dev, PTR_ERR(dsi->clk_pixel), in imx93_dsi_probe()
855 dsi->clk_cfg = devm_clk_get(dev, "phy_cfg"); in imx93_dsi_probe()
856 if (IS_ERR(dsi->clk_cfg)) in imx93_dsi_probe()
857 return dev_err_probe(dev, PTR_ERR(dsi->clk_cfg), in imx93_dsi_probe()
858 "failed to get phy cfg clock\n"); in imx93_dsi_probe()
860 dsi->clk_ref = devm_clk_get(dev, "phy_ref"); in imx93_dsi_probe()
861 if (IS_ERR(dsi->clk_ref)) in imx93_dsi_probe()
862 return dev_err_probe(dev, PTR_ERR(dsi->clk_ref), in imx93_dsi_probe()
863 "failed to get phy ref clock\n"); in imx93_dsi_probe()
865 dsi->ref_clk_rate = clk_get_rate(dsi->clk_ref); in imx93_dsi_probe()
866 if (dsi->ref_clk_rate < REF_CLK_RATE_MIN || in imx93_dsi_probe()
867 dsi->ref_clk_rate > REF_CLK_RATE_MAX) { in imx93_dsi_probe()
868 dev_err(dev, "invalid phy ref clock rate %lu\n", in imx93_dsi_probe()
869 dsi->ref_clk_rate); in imx93_dsi_probe()
870 return -EINVAL; in imx93_dsi_probe()
872 dev_dbg(dev, "phy ref clock rate: %lu\n", dsi->ref_clk_rate); in imx93_dsi_probe()
874 dsi->dev = dev; in imx93_dsi_probe()
875 dsi->pdata.max_data_lanes = 4; in imx93_dsi_probe()
876 dsi->pdata.mode_valid = imx93_dsi_mode_valid; in imx93_dsi_probe()
877 dsi->pdata.mode_fixup = imx93_dsi_mode_fixup; in imx93_dsi_probe()
878 dsi->pdata.get_input_bus_fmts = imx93_dsi_get_input_bus_fmts; in imx93_dsi_probe()
879 dsi->pdata.phy_ops = &imx93_dsi_phy_ops; in imx93_dsi_probe()
880 dsi->pdata.host_ops = &imx93_dsi_host_ops; in imx93_dsi_probe()
881 dsi->pdata.priv_data = dsi; in imx93_dsi_probe()
882 platform_set_drvdata(pdev, dsi); in imx93_dsi_probe()
884 dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata); in imx93_dsi_probe()
885 if (IS_ERR(dsi->dmd)) in imx93_dsi_probe()
886 return dev_err_probe(dev, PTR_ERR(dsi->dmd), in imx93_dsi_probe()
894 struct imx93_dsi *dsi = platform_get_drvdata(pdev); in imx93_dsi_remove() local
896 dw_mipi_dsi_remove(dsi->dmd); in imx93_dsi_remove()
900 { .compatible = "fsl,imx93-mipi-dsi", },
915 MODULE_DESCRIPTION("Freescale i.MX93 MIPI DSI driver");