Lines Matching +full:clk +full:- +full:phase +full:- +full:sd +full:- +full:hs

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2023, STMicroelectronics - All Rights Reserved
4 * Author(s): Raphaël GALLAIS-POU <raphael.gallais-pou@foss.st.com> for STMicroelectronics.
15 #include <linux/clk.h>
16 #include <linux/clk-provider.h>
19 #include <linux/media-bus-format.h>
61 #define CR_LKPHA BIT(6) /* Link Phase, for both Links */
62 #define CR_LK1POL GENMASK(20, 16) /* Link-1 output Polarity */
63 #define CR_LK2POL GENMASK(25, 21) /* Link-2 output Polarity */
96 #define PHY_PLLCR1_EN_SD BIT(1) /* LVDS PHY PLL sigma-delta signal enable */
115 * The link phase defines whether an ODD pixel is carried over together with
120 * ,--------. ,--------. ,--------. ,--------. ,---------.
123 * `--------' `--------' `--------' `--------' `---------'
127 * ,--------. ,--------. ,--------. ,--------. ,---------.
130 * `--------' `--------' `--------' `--------' `---------'
258 struct clk *pclk; /* APB peripheral clock */
259 struct clk *pllref_clk; /* Reference clock for the internal PLL */
291 writel(val, lvds->base + reg); in lvds_write()
296 return readl(lvds->base + reg); in lvds_read()
310 * Expected JEIDA-RGB888 data to be sent in LSB format
315 * CHAN3 {DE, VS, HS, B7, B6, B5, B4}
327 * Expected VESA-RGB888 data to be sent in LSB format
332 * CHAN3 {DE, VS, HS, B5, B4, B3, B2}
348 struct drm_device *drm = lvds->lvds_bridge.dev; in lvds_pll_enable()
354 * Adjusted value so that the masking window is opened at start-up in lvds_pll_enable()
356 lvds_write(lvds, phy->base + phy->ofs.MPLCR, (0x200 - 0x160) << 16); in lvds_pll_enable()
359 lvds_write(lvds, phy->base + phy->ofs.BCR2, PHY_BCR2_BIAS_EN); in lvds_pll_enable()
363 lvds_set(lvds, phy->base + phy->ofs.GCR, lvds_gcr); in lvds_pll_enable()
366 lvds_set(lvds, phy->base + phy->ofs.PLLTESTCR, PHY_PLLTESTCR_EN); in lvds_pll_enable()
367 lvds_set(lvds, phy->base + phy->ofs.PLLCR1, PHY_PLLCR1_DIV_EN); in lvds_pll_enable()
370 lvds_set(lvds, phy->base + phy->ofs.SCR, PHY_SCR_TX_EN); in lvds_pll_enable()
373 lvds_set(lvds, phy->base + phy->ofs.PLLCR1, PHY_PLLCR1_PLL_EN); in lvds_pll_enable()
374 ret = readl_poll_timeout_atomic(lvds->base + phy->base + phy->ofs.PLLSR, in lvds_pll_enable()
383 lvds_set(lvds, phy->ofs.PLLTESTCR, PHY_PLLTESTCR_CLK_EN); in lvds_pll_enable()
416 return -EINVAL; in lvds_pll_get_params()
427 delta = pll_get_clkout_khz(clkin_khz, i, n, o) - clkout_khz; in lvds_pll_get_params()
429 delta = -delta; in lvds_pll_get_params()
453 * highly configuration Phase Locked Loop supporting integer and in lvds_pll_config()
456 * made of a pre-divider NDIV, a feedback multiplier MDIV, followed by in lvds_pll_config()
457 * several post-dividers, each one with a specific application. in lvds_pll_config()
459 * ,------. ,-----. ,-----. in lvds_pll_config()
460 * Fref --> | NDIV | -Fpdf-> | PFD | --> | VCO | --------> Fvco in lvds_pll_config()
461 * `------' ,-> | | `-----' | in lvds_pll_config()
462 * | `-----' | in lvds_pll_config()
463 * | ,------. | in lvds_pll_config()
464 * `-------- | MDIV | <-----' in lvds_pll_config()
465 * `------' in lvds_pll_config()
469 * is passed through a programmable post-divider BDIV. Finally, the in lvds_pll_config()
472 * ,--------. in lvds_pll_config()
473 * ,-----> | DP div | ----------------> Fdp in lvds_pll_config()
474 * ,------. | `--------' in lvds_pll_config()
475 * Fvco --> | BDIV | ------------------------------------> Fbit in lvds_pll_config()
476 * | `------' ,------. | in lvds_pll_config()
477 * `-------------> | TDIV | --.---------------------> ClkObs in lvds_pll_config()
478 * '------' | ,--------. in lvds_pll_config()
479 * `--> | LS div | ------> Fls in lvds_pll_config()
480 * '--------' in lvds_pll_config()
489 hwclk = __clk_get_hw(lvds->pllref_clk); in lvds_pll_config()
495 if (lvds_is_dual_link(lvds->link_type)) in lvds_pll_config()
501 lvds->pixel_clock_rate * 7 / 1000 / multiplier, in lvds_pll_config()
505 lvds_write(lvds, phy->base + phy->ofs.PLLCR2, ndiv << 16); in lvds_pll_config()
506 lvds_set(lvds, phy->base + phy->ofs.PLLCR2, bdiv); in lvds_pll_config()
507 lvds_write(lvds, phy->base + phy->ofs.PLLSDCR1, mdiv); in lvds_pll_config()
510 lvds_write(lvds, phy->base + phy->ofs.PLLTESTCR, TDIV << 16); in lvds_pll_config()
517 * - PMRY_PLL_TWG_STEP = PMRY_PLL_SD_INT_RATIO in lvds_pll_config()
518 * - EN_TWG = 0 in lvds_pll_config()
519 * - EN_SD = 0 in lvds_pll_config()
520 * - DOWN_SPREAD = 0 in lvds_pll_config()
523 * - EN_TWG = 0 in lvds_pll_config()
524 * - EN_SD = 1 in lvds_pll_config()
525 * - DOWN_SPREAD = 0 in lvds_pll_config()
528 * - EN_TWG = 1 in lvds_pll_config()
529 * - EN_SD = 1 in lvds_pll_config()
532 /* Disable TWG and SD */ in lvds_pll_config()
533 lvds_clear(lvds, phy->base + phy->ofs.PLLCR1, PHY_PLLCR1_EN_TWG | PHY_PLLCR1_EN_SD); in lvds_pll_config()
536 lvds_set(lvds, phy->base + phy->ofs.DCR, PHY_DCR_POWER_OK); in lvds_pll_config()
537 lvds_set(lvds, phy->base + phy->ofs.CMCR1, PHY_CMCR_CM_EN_DL); in lvds_pll_config()
538 lvds_set(lvds, phy->base + phy->ofs.CMCR2, PHY_CMCR_CM_EN_DL4); in lvds_pll_config()
541 lvds_set(lvds, phy->base + phy->ofs.PLLCPCR, 0x1); in lvds_pll_config()
542 lvds_set(lvds, phy->base + phy->ofs.BCR3, PHY_BCR3_VM_EN_DL); in lvds_pll_config()
543 lvds_set(lvds, phy->base + phy->ofs.BCR1, PHY_BCR1_EN_BIAS_DL); in lvds_pll_config()
545 lvds_set(lvds, phy->base + phy->ofs.CFGCR, PHY_CFGCR_EN_DIG_DL); in lvds_pll_config()
551 struct drm_device *drm = lvds->lvds_bridge.dev; in lvds_pixel_clk_enable()
555 ret = clk_prepare_enable(lvds->pclk); in lvds_pixel_clk_enable()
557 drm_err(drm, "Failed to enable lvds peripheral clk\n"); in lvds_pixel_clk_enable()
561 ret = clk_prepare_enable(lvds->pllref_clk); in lvds_pixel_clk_enable()
563 drm_err(drm, "Failed to enable lvds reference clk\n"); in lvds_pixel_clk_enable()
564 clk_disable_unprepare(lvds->pclk); in lvds_pixel_clk_enable()
569 if (lvds->secondary) { in lvds_pixel_clk_enable()
570 phy = lvds->secondary; in lvds_pixel_clk_enable()
573 lvds_set(lvds, phy->base + phy->ofs.GCR, PHY_GCR_DIV_RSTN | PHY_GCR_RSTZ); in lvds_pixel_clk_enable()
583 if (lvds->primary) { in lvds_pixel_clk_enable()
584 phy = lvds->primary; in lvds_pixel_clk_enable()
587 lvds_set(lvds, phy->base + phy->ofs.GCR, PHY_GCR_DIV_RSTN | PHY_GCR_RSTZ); in lvds_pixel_clk_enable()
611 if (lvds->primary) { in lvds_pixel_clk_disable()
612 lvds_clear(lvds, lvds->primary->base + lvds->primary->ofs.GCR, in lvds_pixel_clk_disable()
614 lvds_clear(lvds, lvds->primary->base + lvds->primary->ofs.PLLCR1, in lvds_pixel_clk_disable()
616 lvds_clear(lvds, lvds->primary->base + lvds->primary->ofs.GCR, in lvds_pixel_clk_disable()
620 if (lvds->secondary) { in lvds_pixel_clk_disable()
621 lvds_clear(lvds, lvds->secondary->base + lvds->secondary->ofs.GCR, in lvds_pixel_clk_disable()
623 lvds_clear(lvds, lvds->secondary->base + lvds->secondary->ofs.PLLCR1, in lvds_pixel_clk_disable()
625 lvds_clear(lvds, lvds->secondary->base + lvds->secondary->ofs.GCR, in lvds_pixel_clk_disable()
629 clk_disable_unprepare(lvds->pllref_clk); in lvds_pixel_clk_disable()
630 clk_disable_unprepare(lvds->pclk); in lvds_pixel_clk_disable()
637 struct drm_device *drm = lvds->lvds_bridge.dev; in lvds_pixel_clk_recalc_rate()
642 ret = clk_prepare_enable(lvds->pclk); in lvds_pixel_clk_recalc_rate()
644 drm_err(drm, "Failed to enable lvds peripheral clk\n"); in lvds_pixel_clk_recalc_rate()
648 if (lvds_is_dual_link(lvds->link_type)) in lvds_pixel_clk_recalc_rate()
653 val = lvds_read(lvds, lvds->primary->base + lvds->primary->ofs.PLLCR2); in lvds_pixel_clk_recalc_rate()
659 lvds->primary->base + lvds->primary->ofs.PLLSDCR1); in lvds_pixel_clk_recalc_rate()
666 lvds->pixel_clock_rate * 7 / 1000 / multiplier, in lvds_pixel_clk_recalc_rate()
678 lvds->pixel_clock_rate = pll_out_khz * 1000 * multiplier / 7; in lvds_pixel_clk_recalc_rate()
680 clk_disable_unprepare(lvds->pclk); in lvds_pixel_clk_recalc_rate()
682 return (unsigned long)lvds->pixel_clock_rate; in lvds_pixel_clk_recalc_rate()
694 connector = &lvds->connector; in lvds_pixel_clk_round_rate()
696 return -EINVAL; in lvds_pixel_clk_round_rate()
698 if (list_empty(&connector->modes)) { in lvds_pixel_clk_round_rate()
699 drm_dbg(connector->dev, "connector: empty modes list\n"); in lvds_pixel_clk_round_rate()
700 return -EINVAL; in lvds_pixel_clk_round_rate()
703 mode = list_first_entry(&connector->modes, in lvds_pixel_clk_round_rate()
708 if (lvds_is_dual_link(lvds->link_type)) in lvds_pixel_clk_round_rate()
713 lvds_pll_get_params(lvds, pll_in_khz, mode->clock * 7 / multiplier, &bdiv, &mdiv, &ndiv); in lvds_pixel_clk_round_rate()
719 lvds->pixel_clock_rate = (unsigned long)pll_get_clkout_khz(pll_in_khz, bdiv, mdiv, ndiv) in lvds_pixel_clk_round_rate()
722 return lvds->pixel_clock_rate; in lvds_pixel_clk_round_rate()
744 of_clk_del_provider(lvds->dev->of_node); in lvds_pixel_clk_unregister()
745 clk_hw_unregister(&lvds->lvds_ck_px); in lvds_pixel_clk_unregister()
750 struct device_node *node = lvds->dev->of_node; in lvds_pixel_clk_register()
753 lvds->lvds_ck_px.init = &clk_data; in lvds_pixel_clk_register()
756 lvds->pixel_clock_rate = 148500000; in lvds_pixel_clk_register()
758 ret = clk_hw_register(lvds->dev, &lvds->lvds_ck_px); in lvds_pixel_clk_register()
763 &lvds->lvds_ck_px); in lvds_pixel_clk_register()
765 clk_hw_unregister(&lvds->lvds_ck_px); in lvds_pixel_clk_register()
775 struct drm_device *drm = lvds->lvds_bridge.dev; in lvds_config_data_mapping()
781 info = &(&lvds->connector)->display_info; in lvds_config_data_mapping()
782 if (!info->num_bus_formats || !info->bus_formats) { in lvds_config_data_mapping()
787 switch (info->bus_formats[0]) { in lvds_config_data_mapping()
788 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: /* VESA-RGB666 */ in lvds_config_data_mapping()
791 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: /* VESA-RGB888 */ in lvds_config_data_mapping()
794 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: /* JEIDA-RGB888 */ in lvds_config_data_mapping()
798 drm_warn(drm, "Unsupported LVDS bus format 0x%04x\n", info->bus_formats[0]); in lvds_config_data_mapping()
823 connector = &lvds->connector; in lvds_config_mode()
827 if (list_empty(&connector->modes)) { in lvds_config_mode()
828 drm_dbg(connector->dev, "connector: empty modes list\n"); in lvds_config_mode()
832 bus_flags = connector->display_info.bus_flags; in lvds_config_mode()
833 mode = list_first_entry(&connector->modes, in lvds_config_mode()
843 if (lvds->primary) in lvds_config_mode()
846 if (lvds->secondary) { in lvds_config_mode()
855 if (mode->flags & DRM_MODE_FLAG_NHSYNC) in lvds_config_mode()
858 if (mode->flags & DRM_MODE_FLAG_NVSYNC) in lvds_config_mode()
861 switch (lvds->link_type) { in lvds_config_mode()
869 drm_notice(lvds->lvds_bridge.dev, "No phase precised, setting default\n"); in lvds_config_mode()
884 return drm_panel_get_modes(lvds->panel, connector); in lvds_connector_get_modes()
896 return -EINVAL; in lvds_connector_atomic_check()
898 if (list_empty(&connector->modes)) { in lvds_connector_atomic_check()
899 drm_dbg(connector->dev, "connector: empty modes list\n"); in lvds_connector_atomic_check()
900 return -EINVAL; in lvds_connector_atomic_check()
903 if (!conn_state->crtc) in lvds_connector_atomic_check()
904 return -EINVAL; in lvds_connector_atomic_check()
906 panel_mode = list_first_entry(&connector->modes, in lvds_connector_atomic_check()
910 crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc); in lvds_connector_atomic_check()
914 if (crtc_state->mode.hdisplay != panel_mode->hdisplay || in lvds_connector_atomic_check()
915 crtc_state->mode.vdisplay != panel_mode->vdisplay) in lvds_connector_atomic_check()
916 return -EINVAL; in lvds_connector_atomic_check()
919 drm_mode_copy(&crtc_state->adjusted_mode, panel_mode); in lvds_connector_atomic_check()
941 struct drm_connector *connector = &lvds->connector; in lvds_attach()
942 struct drm_encoder *encoder = bridge->encoder; in lvds_attach()
945 if (!bridge->encoder) { in lvds_attach()
946 drm_err(bridge->dev, "Parent encoder object not found\n"); in lvds_attach()
947 return -ENODEV; in lvds_attach()
951 bridge->encoder->encoder_type = DRM_MODE_ENCODER_LVDS; in lvds_attach()
954 bridge->encoder->possible_clones = 0; in lvds_attach()
957 if (lvds->next_bridge) in lvds_attach()
958 return drm_bridge_attach(bridge->encoder, lvds->next_bridge, in lvds_attach()
962 drm_err(bridge->dev, "Fix bridge driver to make connector optional!"); in lvds_attach()
963 return -EINVAL; in lvds_attach()
967 if (!lvds->panel) in lvds_attach()
970 ret = drm_connector_init(bridge->dev, connector, in lvds_attach()
985 struct drm_atomic_state *state = old_bridge_state->base.state; in lvds_atomic_enable()
991 ret = clk_prepare_enable(lvds->pclk); in lvds_atomic_enable()
993 drm_err(bridge->dev, "Failed to enable lvds peripheral clk\n"); in lvds_atomic_enable()
997 connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); in lvds_atomic_enable()
1013 if (lvds->panel) { in lvds_atomic_enable()
1014 drm_panel_prepare(lvds->panel); in lvds_atomic_enable()
1015 drm_panel_enable(lvds->panel); in lvds_atomic_enable()
1024 if (lvds->panel) { in lvds_atomic_disable()
1025 drm_panel_disable(lvds->panel); in lvds_atomic_disable()
1026 drm_panel_unprepare(lvds->panel); in lvds_atomic_disable()
1032 clk_disable_unprepare(lvds->pclk); in lvds_atomic_disable()
1047 struct device *dev = &pdev->dev; in lvds_probe()
1056 return -ENOMEM; in lvds_probe()
1058 lvds->dev = dev; in lvds_probe()
1060 ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, in lvds_probe()
1061 &lvds->panel, &lvds->next_bridge); in lvds_probe()
1067 lvds->base = devm_platform_ioremap_resource(pdev, 0); in lvds_probe()
1068 if (IS_ERR(lvds->base)) { in lvds_probe()
1069 ret = PTR_ERR(lvds->base); in lvds_probe()
1074 lvds->pclk = devm_clk_get(dev, "pclk"); in lvds_probe()
1075 if (IS_ERR(lvds->pclk)) { in lvds_probe()
1076 ret = PTR_ERR(lvds->pclk); in lvds_probe()
1081 ret = clk_prepare_enable(lvds->pclk); in lvds_probe()
1083 dev_err(dev, "%s: Failed to enable peripheral clk\n", __func__); in lvds_probe()
1098 port1 = of_graph_get_port_by_id(dev->of_node, 1); in lvds_probe()
1099 port2 = of_graph_get_port_by_id(dev->of_node, 2); in lvds_probe()
1104 lvds->link_type = LVDS_DUAL_LINK_ODD_EVEN_PIXELS; in lvds_probe()
1105 lvds->primary = &lvds_phy_16ff_primary; in lvds_probe()
1106 lvds->secondary = &lvds_phy_16ff_secondary; in lvds_probe()
1109 lvds->link_type = LVDS_DUAL_LINK_EVEN_ODD_PIXELS; in lvds_probe()
1110 lvds->primary = &lvds_phy_16ff_primary; in lvds_probe()
1111 lvds->secondary = &lvds_phy_16ff_secondary; in lvds_probe()
1113 case -EINVAL: in lvds_probe()
1126 lvds->link_type = LVDS_SINGLE_LINK_PRIMARY; in lvds_probe()
1127 lvds->primary = &lvds_phy_16ff_primary; in lvds_probe()
1128 lvds->secondary = NULL; in lvds_probe()
1130 ret = -EINVAL; in lvds_probe()
1139 lvds->link_type = LVDS_SINGLE_LINK_SECONDARY; in lvds_probe()
1140 lvds->primary = NULL; in lvds_probe()
1141 lvds->secondary = &lvds_phy_16ff_secondary; in lvds_probe()
1143 ret = (ret == -EINVAL) ? -EINVAL : 0; in lvds_probe()
1150 ret = -EINVAL; in lvds_probe()
1156 lvds->pllref_clk = devm_clk_get(dev, "ref"); in lvds_probe()
1157 if (IS_ERR(lvds->pllref_clk)) { in lvds_probe()
1158 ret = PTR_ERR(lvds->pllref_clk); in lvds_probe()
1169 lvds->lvds_bridge.funcs = &lvds_bridge_funcs; in lvds_probe()
1170 lvds->lvds_bridge.of_node = dev->of_node; in lvds_probe()
1171 lvds->hw_version = lvds_read(lvds, LVDS_VERR); in lvds_probe()
1173 dev_info(dev, "version 0x%02x initialized\n", lvds->hw_version); in lvds_probe()
1175 drm_bridge_add(&lvds->lvds_bridge); in lvds_probe()
1179 clk_disable_unprepare(lvds->pclk); in lvds_probe()
1184 clk_disable_unprepare(lvds->pclk); in lvds_probe()
1195 drm_bridge_remove(&lvds->lvds_bridge); in lvds_remove()
1200 .compatible = "st,stm32mp25-lvds",
1212 .name = "stm32-display-lvds",
1219 MODULE_AUTHOR("Raphaël Gallais-Pou <raphael.gallais-pou@foss.st.com>");