From: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
To: Maxime Ripard <maxime.ripard@bootlin.com>,
Kishon Vijay Abraham I <kishon@ti.com>
Cc: Rafal Ciepiela <rafalc@cadence.com>,
Krzysztof Witos <kwitos@cadence.com>,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
Chen-Yu Tsai <wens@csie.org>, Sean Paul <seanpaul@chromium.org>,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
linux-arm-kernel@lists.infradead.org,
linux-media@vger.kernel.org
Subject: Re: [PATCH v5 5/9] phy: Move Allwinner A31 D-PHY driver to drivers/phy/
Date: Thu, 07 Feb 2019 09:19:02 +0100 [thread overview]
Message-ID: <8d6e4cf386d1b9f9e1d794955ac3e66e887fdd08.camel@bootlin.com> (raw)
In-Reply-To: <2447609da5b80f148c79b2b2a263a0e779f3e82f.1548085432.git-series.maxime.ripard@bootlin.com>
Hi,
On Mon, 2019-01-21 at 16:45 +0100, Maxime Ripard wrote:
> Now that our MIPI D-PHY driver has been converted to the phy framework,
> let's move it into the drivers/phy directory.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Reviewed-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
Cheers,
Paul
> ---
> drivers/gpu/drm/sun4i/Kconfig | 10 +-
> drivers/gpu/drm/sun4i/Makefile | 1 +-
> drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c | 318 +---------------------
> drivers/phy/allwinner/Kconfig | 12 +-
> drivers/phy/allwinner/Makefile | 1 +-
> drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 318 +++++++++++++++++++++-
> 6 files changed, 332 insertions(+), 328 deletions(-)
> delete mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
> create mode 100644 drivers/phy/allwinner/phy-sun6i-mipi-dphy.c
>
> diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> index 2b8db82c4bab..1dbbc3a1b763 100644
> --- a/drivers/gpu/drm/sun4i/Kconfig
> +++ b/drivers/gpu/drm/sun4i/Kconfig
> @@ -45,20 +45,12 @@ config DRM_SUN6I_DSI
> default MACH_SUN8I
> select CRC_CCITT
> select DRM_MIPI_DSI
> - select DRM_SUN6I_DPHY
> + select PHY_SUN6I_MIPI_DPHY
> help
> Choose this option if you want have an Allwinner SoC with
> MIPI-DSI support. If M is selected the module will be called
> sun6i_mipi_dsi.
>
> -config DRM_SUN6I_DPHY
> - tristate "Allwinner A31 MIPI D-PHY Support"
> - select GENERIC_PHY_MIPI_DPHY
> - help
> - Choose this option if you have an Allwinner SoC with
> - MIPI-DSI support. If M is selected, the module will be
> - called sun6i_mipi_dphy.
> -
> config DRM_SUN8I_DW_HDMI
> tristate "Support for Allwinner version of DesignWare HDMI"
> depends on DRM_SUN4I
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 1e2320d824b5..0d04f2447b01 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -34,7 +34,6 @@ ifdef CONFIG_DRM_SUN4I_BACKEND
> obj-$(CONFIG_DRM_SUN4I) += sun4i-frontend.o
> endif
> obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
> -obj-$(CONFIG_DRM_SUN6I_DPHY) += sun6i_mipi_dphy.o
> obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i_mipi_dsi.o
> obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o
> obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
> deleted file mode 100644
> index 79c8af5c7c1d..000000000000
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
> +++ /dev/null
> @@ -1,318 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+
> -/*
> - * Copyright (c) 2016 Allwinnertech Co., Ltd.
> - * Copyright (C) 2017-2018 Bootlin
> - *
> - * Maxime Ripard <maxime.ripard@free-electrons.com>
> - */
> -
> -#include <linux/bitops.h>
> -#include <linux/clk.h>
> -#include <linux/module.h>
> -#include <linux/of_address.h>
> -#include <linux/platform_device.h>
> -#include <linux/regmap.h>
> -#include <linux/reset.h>
> -
> -#include <linux/phy/phy.h>
> -#include <linux/phy/phy-mipi-dphy.h>
> -
> -#define SUN6I_DPHY_GCTL_REG 0x00
> -#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
> -#define SUN6I_DPHY_GCTL_EN BIT(0)
> -
> -#define SUN6I_DPHY_TX_CTL_REG 0x04
> -#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
> -
> -#define SUN6I_DPHY_TX_TIME0_REG 0x10
> -#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
> -#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
> -#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff)
> -
> -#define SUN6I_DPHY_TX_TIME1_REG 0x14
> -#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24)
> -#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16)
> -#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8)
> -#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff)
> -
> -#define SUN6I_DPHY_TX_TIME2_REG 0x18
> -#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff)
> -
> -#define SUN6I_DPHY_TX_TIME3_REG 0x1c
> -
> -#define SUN6I_DPHY_TX_TIME4_REG 0x20
> -#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
> -#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
> -
> -#define SUN6I_DPHY_ANA0_REG 0x4c
> -#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
> -#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
> -#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
> -#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
> -#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
> -
> -#define SUN6I_DPHY_ANA1_REG 0x50
> -#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
> -#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28)
> -#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24)
> -
> -#define SUN6I_DPHY_ANA2_REG 0x54
> -#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24)
> -#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24)
> -#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4)
> -#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1)
> -
> -#define SUN6I_DPHY_ANA3_REG 0x58
> -#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28)
> -#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28)
> -#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27)
> -#define SUN6I_DPHY_ANA3_EN_DIV BIT(26)
> -#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25)
> -#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24)
> -#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
> -
> -#define SUN6I_DPHY_ANA4_REG 0x5c
> -#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
> -#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
> -#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
> -#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
> -#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
> -#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6)
> -#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4)
> -#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2)
> -#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3)
> -
> -#define SUN6I_DPHY_DBG5_REG 0xf4
> -
> -struct sun6i_dphy {
> - struct clk *bus_clk;
> - struct clk *mod_clk;
> - struct regmap *regs;
> - struct reset_control *reset;
> -
> - struct phy *phy;
> - struct phy_configure_opts_mipi_dphy config;
> -};
> -
> -static int sun6i_dphy_init(struct phy *phy)
> -{
> - struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> -
> - reset_control_deassert(dphy->reset);
> - clk_prepare_enable(dphy->mod_clk);
> - clk_set_rate_exclusive(dphy->mod_clk, 150000000);
> -
> - return 0;
> -}
> -
> -static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
> -{
> - struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> - int ret;
> -
> - ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
> - if (ret)
> - return ret;
> -
> - memcpy(&dphy->config, opts, sizeof(dphy->config));
> -
> - return 0;
> -}
> -
> -static int sun6i_dphy_power_on(struct phy *phy)
> -{
> - struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> - u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
> - SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
> - SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
> - SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
> - SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
> - SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
> - SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
> - SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
> - SUN6I_DPHY_TX_TIME1_CLK_POST(10));
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
> - SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
> - SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
> - SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
> - SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
> - SUN6I_DPHY_GCTL_EN);
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
> - SUN6I_DPHY_ANA0_REG_PWS |
> - SUN6I_DPHY_ANA0_REG_DMPC |
> - SUN6I_DPHY_ANA0_REG_SLV(7) |
> - SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
> - SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
> - SUN6I_DPHY_ANA1_REG_CSMPS(1) |
> - SUN6I_DPHY_ANA1_REG_SVTT(7));
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
> - SUN6I_DPHY_ANA4_REG_CKDV(1) |
> - SUN6I_DPHY_ANA4_REG_TMSC(1) |
> - SUN6I_DPHY_ANA4_REG_TMSD(1) |
> - SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
> - SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
> - SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
> - SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
> - SUN6I_DPHY_ANA4_REG_DMPLVC |
> - SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
> - SUN6I_DPHY_ANA2_REG_ENIB);
> - udelay(5);
> -
> - regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
> - SUN6I_DPHY_ANA3_EN_LDOR |
> - SUN6I_DPHY_ANA3_EN_LDOC |
> - SUN6I_DPHY_ANA3_EN_LDOD);
> - udelay(1);
> -
> - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
> - SUN6I_DPHY_ANA3_EN_VTTC |
> - SUN6I_DPHY_ANA3_EN_VTTD_MASK,
> - SUN6I_DPHY_ANA3_EN_VTTC |
> - SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
> - udelay(1);
> -
> - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
> - SUN6I_DPHY_ANA3_EN_DIV,
> - SUN6I_DPHY_ANA3_EN_DIV);
> - udelay(1);
> -
> - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
> - SUN6I_DPHY_ANA2_EN_CK_CPU,
> - SUN6I_DPHY_ANA2_EN_CK_CPU);
> - udelay(1);
> -
> - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
> - SUN6I_DPHY_ANA1_REG_VTTMODE,
> - SUN6I_DPHY_ANA1_REG_VTTMODE);
> -
> - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
> - SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
> - SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
> -
> - return 0;
> -}
> -
> -static int sun6i_dphy_power_off(struct phy *phy)
> -{
> - struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> -
> - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
> - SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
> -
> - return 0;
> -}
> -
> -static int sun6i_dphy_exit(struct phy *phy)
> -{
> - struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> -
> - clk_rate_exclusive_put(dphy->mod_clk);
> - clk_disable_unprepare(dphy->mod_clk);
> - reset_control_assert(dphy->reset);
> -
> - return 0;
> -}
> -
> -
> -static struct phy_ops sun6i_dphy_ops = {
> - .configure = sun6i_dphy_configure,
> - .power_on = sun6i_dphy_power_on,
> - .power_off = sun6i_dphy_power_off,
> - .init = sun6i_dphy_init,
> - .exit = sun6i_dphy_exit,
> -};
> -
> -static struct regmap_config sun6i_dphy_regmap_config = {
> - .reg_bits = 32,
> - .val_bits = 32,
> - .reg_stride = 4,
> - .max_register = SUN6I_DPHY_DBG5_REG,
> - .name = "mipi-dphy",
> -};
> -
> -static int sun6i_dphy_probe(struct platform_device *pdev)
> -{
> - struct phy_provider *phy_provider;
> - struct sun6i_dphy *dphy;
> - struct resource *res;
> - void __iomem *regs;
> -
> - dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
> - if (!dphy)
> - return -ENOMEM;
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - regs = devm_ioremap_resource(&pdev->dev, res);
> - if (IS_ERR(regs)) {
> - dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n");
> - return PTR_ERR(regs);
> - }
> -
> - dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus",
> - regs, &sun6i_dphy_regmap_config);
> - if (IS_ERR(dphy->regs)) {
> - dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n");
> - return PTR_ERR(dphy->regs);
> - }
> -
> - dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL);
> - if (IS_ERR(dphy->reset)) {
> - dev_err(&pdev->dev, "Couldn't get our reset line\n");
> - return PTR_ERR(dphy->reset);
> - }
> -
> - dphy->mod_clk = devm_clk_get(&pdev->dev, "mod");
> - if (IS_ERR(dphy->mod_clk)) {
> - dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n");
> - return PTR_ERR(dphy->mod_clk);
> - }
> -
> - dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops);
> - if (IS_ERR(dphy->phy)) {
> - dev_err(&pdev->dev, "failed to create PHY\n");
> - return PTR_ERR(dphy->phy);
> - }
> -
> - phy_set_drvdata(dphy->phy, dphy);
> - phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
> -
> - return PTR_ERR_OR_ZERO(phy_provider);
> -}
> -
> -static const struct of_device_id sun6i_dphy_of_table[] = {
> - { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
> - { }
> -};
> -MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);
> -
> -static struct platform_driver sun6i_dphy_platform_driver = {
> - .probe = sun6i_dphy_probe,
> - .driver = {
> - .name = "sun6i-mipi-dphy",
> - .of_match_table = sun6i_dphy_of_table,
> - },
> -};
> -module_platform_driver(sun6i_dphy_platform_driver);
> -
> -MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin>");
> -MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig
> index cdc1e745ba47..fb1204bcc454 100644
> --- a/drivers/phy/allwinner/Kconfig
> +++ b/drivers/phy/allwinner/Kconfig
> @@ -17,6 +17,18 @@ config PHY_SUN4I_USB
> This driver controls the entire USB PHY block, both the USB OTG
> parts, as well as the 2 regular USB 2 host PHYs.
>
> +config PHY_SUN6I_MIPI_DPHY
> + tristate "Allwinner A31 MIPI D-PHY Support"
> + depends on ARCH_SUNXI && HAS_IOMEM && OF
> + depends on RESET_CONTROLLER
> + select GENERIC_PHY
> + select GENERIC_PHY_MIPI_DPHY
> + select REGMAP_MMIO
> + help
> + Choose this option if you have an Allwinner SoC with
> + MIPI-DSI support. If M is selected, the module will be
> + called sun6i_mipi_dphy.
> +
> config PHY_SUN9I_USB
> tristate "Allwinner sun9i SoC USB PHY driver"
> depends on ARCH_SUNXI && HAS_IOMEM && OF
> diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile
> index 8605529c01a1..7d0053efbfaa 100644
> --- a/drivers/phy/allwinner/Makefile
> +++ b/drivers/phy/allwinner/Makefile
> @@ -1,2 +1,3 @@
> obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
> +obj-$(CONFIG_PHY_SUN6I_MIPI_DPHY) += phy-sun6i-mipi-dphy.o
> obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o
> diff --git a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c
> new file mode 100644
> index 000000000000..79c8af5c7c1d
> --- /dev/null
> +++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c
> @@ -0,0 +1,318 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2016 Allwinnertech Co., Ltd.
> + * Copyright (C) 2017-2018 Bootlin
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include <linux/phy/phy.h>
> +#include <linux/phy/phy-mipi-dphy.h>
> +
> +#define SUN6I_DPHY_GCTL_REG 0x00
> +#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
> +#define SUN6I_DPHY_GCTL_EN BIT(0)
> +
> +#define SUN6I_DPHY_TX_CTL_REG 0x04
> +#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
> +
> +#define SUN6I_DPHY_TX_TIME0_REG 0x10
> +#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
> +#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
> +#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff)
> +
> +#define SUN6I_DPHY_TX_TIME1_REG 0x14
> +#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24)
> +#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16)
> +#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8)
> +#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff)
> +
> +#define SUN6I_DPHY_TX_TIME2_REG 0x18
> +#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff)
> +
> +#define SUN6I_DPHY_TX_TIME3_REG 0x1c
> +
> +#define SUN6I_DPHY_TX_TIME4_REG 0x20
> +#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
> +#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
> +
> +#define SUN6I_DPHY_ANA0_REG 0x4c
> +#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
> +#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
> +#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
> +#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
> +#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
> +
> +#define SUN6I_DPHY_ANA1_REG 0x50
> +#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
> +#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28)
> +#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24)
> +
> +#define SUN6I_DPHY_ANA2_REG 0x54
> +#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24)
> +#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24)
> +#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4)
> +#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1)
> +
> +#define SUN6I_DPHY_ANA3_REG 0x58
> +#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28)
> +#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28)
> +#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27)
> +#define SUN6I_DPHY_ANA3_EN_DIV BIT(26)
> +#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25)
> +#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24)
> +#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
> +
> +#define SUN6I_DPHY_ANA4_REG 0x5c
> +#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
> +#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
> +#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
> +#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
> +#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
> +#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6)
> +#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4)
> +#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2)
> +#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3)
> +
> +#define SUN6I_DPHY_DBG5_REG 0xf4
> +
> +struct sun6i_dphy {
> + struct clk *bus_clk;
> + struct clk *mod_clk;
> + struct regmap *regs;
> + struct reset_control *reset;
> +
> + struct phy *phy;
> + struct phy_configure_opts_mipi_dphy config;
> +};
> +
> +static int sun6i_dphy_init(struct phy *phy)
> +{
> + struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> +
> + reset_control_deassert(dphy->reset);
> + clk_prepare_enable(dphy->mod_clk);
> + clk_set_rate_exclusive(dphy->mod_clk, 150000000);
> +
> + return 0;
> +}
> +
> +static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
> +{
> + struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> + int ret;
> +
> + ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
> + if (ret)
> + return ret;
> +
> + memcpy(&dphy->config, opts, sizeof(dphy->config));
> +
> + return 0;
> +}
> +
> +static int sun6i_dphy_power_on(struct phy *phy)
> +{
> + struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> + u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
> + SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
> + SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
> + SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
> + SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
> + SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
> + SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
> + SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
> + SUN6I_DPHY_TX_TIME1_CLK_POST(10));
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
> + SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
> + SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
> + SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
> + SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
> + SUN6I_DPHY_GCTL_EN);
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
> + SUN6I_DPHY_ANA0_REG_PWS |
> + SUN6I_DPHY_ANA0_REG_DMPC |
> + SUN6I_DPHY_ANA0_REG_SLV(7) |
> + SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
> + SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
> + SUN6I_DPHY_ANA1_REG_CSMPS(1) |
> + SUN6I_DPHY_ANA1_REG_SVTT(7));
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
> + SUN6I_DPHY_ANA4_REG_CKDV(1) |
> + SUN6I_DPHY_ANA4_REG_TMSC(1) |
> + SUN6I_DPHY_ANA4_REG_TMSD(1) |
> + SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
> + SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
> + SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
> + SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
> + SUN6I_DPHY_ANA4_REG_DMPLVC |
> + SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
> + SUN6I_DPHY_ANA2_REG_ENIB);
> + udelay(5);
> +
> + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
> + SUN6I_DPHY_ANA3_EN_LDOR |
> + SUN6I_DPHY_ANA3_EN_LDOC |
> + SUN6I_DPHY_ANA3_EN_LDOD);
> + udelay(1);
> +
> + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
> + SUN6I_DPHY_ANA3_EN_VTTC |
> + SUN6I_DPHY_ANA3_EN_VTTD_MASK,
> + SUN6I_DPHY_ANA3_EN_VTTC |
> + SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
> + udelay(1);
> +
> + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
> + SUN6I_DPHY_ANA3_EN_DIV,
> + SUN6I_DPHY_ANA3_EN_DIV);
> + udelay(1);
> +
> + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
> + SUN6I_DPHY_ANA2_EN_CK_CPU,
> + SUN6I_DPHY_ANA2_EN_CK_CPU);
> + udelay(1);
> +
> + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
> + SUN6I_DPHY_ANA1_REG_VTTMODE,
> + SUN6I_DPHY_ANA1_REG_VTTMODE);
> +
> + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
> + SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
> + SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
> +
> + return 0;
> +}
> +
> +static int sun6i_dphy_power_off(struct phy *phy)
> +{
> + struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> +
> + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
> + SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
> +
> + return 0;
> +}
> +
> +static int sun6i_dphy_exit(struct phy *phy)
> +{
> + struct sun6i_dphy *dphy = phy_get_drvdata(phy);
> +
> + clk_rate_exclusive_put(dphy->mod_clk);
> + clk_disable_unprepare(dphy->mod_clk);
> + reset_control_assert(dphy->reset);
> +
> + return 0;
> +}
> +
> +
> +static struct phy_ops sun6i_dphy_ops = {
> + .configure = sun6i_dphy_configure,
> + .power_on = sun6i_dphy_power_on,
> + .power_off = sun6i_dphy_power_off,
> + .init = sun6i_dphy_init,
> + .exit = sun6i_dphy_exit,
> +};
> +
> +static struct regmap_config sun6i_dphy_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = SUN6I_DPHY_DBG5_REG,
> + .name = "mipi-dphy",
> +};
> +
> +static int sun6i_dphy_probe(struct platform_device *pdev)
> +{
> + struct phy_provider *phy_provider;
> + struct sun6i_dphy *dphy;
> + struct resource *res;
> + void __iomem *regs;
> +
> + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
> + if (!dphy)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + regs = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(regs)) {
> + dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n");
> + return PTR_ERR(regs);
> + }
> +
> + dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus",
> + regs, &sun6i_dphy_regmap_config);
> + if (IS_ERR(dphy->regs)) {
> + dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n");
> + return PTR_ERR(dphy->regs);
> + }
> +
> + dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL);
> + if (IS_ERR(dphy->reset)) {
> + dev_err(&pdev->dev, "Couldn't get our reset line\n");
> + return PTR_ERR(dphy->reset);
> + }
> +
> + dphy->mod_clk = devm_clk_get(&pdev->dev, "mod");
> + if (IS_ERR(dphy->mod_clk)) {
> + dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n");
> + return PTR_ERR(dphy->mod_clk);
> + }
> +
> + dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops);
> + if (IS_ERR(dphy->phy)) {
> + dev_err(&pdev->dev, "failed to create PHY\n");
> + return PTR_ERR(dphy->phy);
> + }
> +
> + phy_set_drvdata(dphy->phy, dphy);
> + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id sun6i_dphy_of_table[] = {
> + { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);
> +
> +static struct platform_driver sun6i_dphy_platform_driver = {
> + .probe = sun6i_dphy_probe,
> + .driver = {
> + .name = "sun6i-mipi-dphy",
> + .of_match_table = sun6i_dphy_of_table,
> + },
> +};
> +module_platform_driver(sun6i_dphy_platform_driver);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin>");
> +MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");
> +MODULE_LICENSE("GPL");
--
Paul Kocialkowski, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
next prev parent reply other threads:[~2019-02-07 8:19 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-21 15:45 [PATCH v5 0/9] phy: Add configuration interface for MIPI D-PHY devices Maxime Ripard
2019-01-21 15:45 ` [PATCH v5 1/9] phy: dphy: Remove unused header Maxime Ripard
2019-01-21 15:45 ` [PATCH v5 2/9] phy: dphy: Change units of wakeup and init parameters Maxime Ripard
2019-01-21 15:45 ` [PATCH v5 3/9] phy: dphy: Clarify lanes parameter documentation Maxime Ripard
2019-01-21 15:45 ` [PATCH v5 4/9] sun6i: dsi: Convert to generic phy handling Maxime Ripard
2019-02-07 8:15 ` Paul Kocialkowski
2019-01-21 15:45 ` [PATCH v5 5/9] phy: Move Allwinner A31 D-PHY driver to drivers/phy/ Maxime Ripard
2019-02-07 8:19 ` Paul Kocialkowski [this message]
2019-01-21 15:45 ` [PATCH v5 6/9] drm/bridge: cdns: Separate DSI and D-PHY configuration Maxime Ripard
2019-02-07 8:44 ` Paul Kocialkowski
2019-02-07 9:16 ` Maxime Ripard
2019-01-21 15:45 ` [PATCH v5 7/9] dt-bindings: phy: Move the Cadence D-PHY bindings Maxime Ripard
2019-01-21 15:45 ` [PATCH v5 8/9] phy: Add Cadence D-PHY support Maxime Ripard
2019-01-21 15:45 ` [PATCH v5 9/9] drm/bridge: cdns: Convert to phy framework Maxime Ripard
2019-02-04 10:03 ` [PATCH v5 0/9] phy: Add configuration interface for MIPI D-PHY devices Kishon Vijay Abraham I
2019-02-04 13:51 ` Maxime Ripard
2019-02-05 8:46 ` Daniel Vetter
2019-02-06 12:13 ` Kishon Vijay Abraham I
2019-02-06 12:25 ` Maxime Ripard
2019-02-06 12:30 ` Kishon Vijay Abraham I
2019-02-07 9:17 ` Maxime Ripard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8d6e4cf386d1b9f9e1d794955ac3e66e887fdd08.camel@bootlin.com \
--to=paul.kocialkowski@bootlin.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=kishon@ti.com \
--cc=kwitos@cadence.com \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=maxime.ripard@bootlin.com \
--cc=rafalc@cadence.com \
--cc=seanpaul@chromium.org \
--cc=thomas.petazzoni@bootlin.com \
--cc=wens@csie.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).