cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-meson-axg-mipi-dphy.c (12258B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Meson AXG MIPI DPHY driver
      4 *
      5 * Copyright (C) 2018 Amlogic, Inc. All rights reserved
      6 * Copyright (C) 2020 BayLibre, SAS
      7 * Author: Neil Armstrong <narmstrong@baylibre.com>
      8 */
      9
     10#include <linux/bitfield.h>
     11#include <linux/bitops.h>
     12#include <linux/bits.h>
     13#include <linux/clk.h>
     14#include <linux/delay.h>
     15#include <linux/io.h>
     16#include <linux/module.h>
     17#include <linux/of_device.h>
     18#include <linux/regmap.h>
     19#include <linux/reset.h>
     20#include <linux/phy/phy.h>
     21#include <linux/platform_device.h>
     22
     23/* [31] soft reset for the phy.
     24 *		1: reset. 0: dessert the reset.
     25 * [30] clock lane soft reset.
     26 * [29] data byte lane 3 soft reset.
     27 * [28] data byte lane 2 soft reset.
     28 * [27] data byte lane 1 soft reset.
     29 * [26] data byte lane 0 soft reset.
     30 * [25] mipi dsi pll clock selection.
     31 *		1:  clock from fixed 850Mhz clock source. 0: from VID2 PLL.
     32 * [12] mipi HSbyteclk enable.
     33 * [11] mipi divider clk selection.
     34 *		1: select the mipi DDRCLKHS from clock divider.
     35 *		0: from PLL clock.
     36 * [10] mipi clock divider control.
     37 *		1: /4. 0: /2.
     38 * [9]  mipi divider output enable.
     39 * [8]  mipi divider counter enable.
     40 * [7]  PLL clock enable.
     41 * [5]  LPDT data endian.
     42 *		1 = transfer the high bit first. 0 : transfer the low bit first.
     43 * [4]  HS data endian.
     44 * [3]  force data byte lane in stop mode.
     45 * [2]  force data byte lane 0 in receiver mode.
     46 * [1]  write 1 to sync the txclkesc input. the internal logic have to
     47 *	use txclkesc to decide Txvalid and Txready.
     48 * [0]  enalbe the MIPI DPHY TxDDRClk.
     49 */
     50#define MIPI_DSI_PHY_CTRL				0x0
     51
     52/* [31] clk lane tx_hs_en control selection.
     53 *		1: from register. 0: use clk lane state machine.
     54 * [30] register bit for clock lane tx_hs_en.
     55 * [29] clk lane tx_lp_en contrl selection.
     56 *		1: from register. 0: from clk lane state machine.
     57 * [28] register bit for clock lane tx_lp_en.
     58 * [27] chan0 tx_hs_en control selection.
     59 *		1: from register. 0: from chan0 state machine.
     60 * [26] register bit for chan0 tx_hs_en.
     61 * [25] chan0 tx_lp_en control selection.
     62 *		1: from register. 0: from chan0 state machine.
     63 * [24] register bit from chan0 tx_lp_en.
     64 * [23] chan0 rx_lp_en control selection.
     65 *		1: from register. 0: from chan0 state machine.
     66 * [22] register bit from chan0 rx_lp_en.
     67 * [21] chan0 contention detection enable control selection.
     68 *		1: from register. 0: from chan0 state machine.
     69 * [20] register bit from chan0 contention dectection enable.
     70 * [19] chan1 tx_hs_en control selection.
     71 *		1: from register. 0: from chan0 state machine.
     72 * [18] register bit for chan1 tx_hs_en.
     73 * [17] chan1 tx_lp_en control selection.
     74 *		1: from register. 0: from chan0 state machine.
     75 * [16] register bit from chan1 tx_lp_en.
     76 * [15] chan2 tx_hs_en control selection.
     77 *		1: from register. 0: from chan0 state machine.
     78 * [14] register bit for chan2 tx_hs_en.
     79 * [13] chan2 tx_lp_en control selection.
     80 *		1: from register. 0: from chan0 state machine.
     81 * [12] register bit from chan2 tx_lp_en.
     82 * [11] chan3 tx_hs_en control selection.
     83 *		1: from register. 0: from chan0 state machine.
     84 * [10] register bit for chan3 tx_hs_en.
     85 * [9]  chan3 tx_lp_en control selection.
     86 *		1: from register. 0: from chan0 state machine.
     87 * [8]  register bit from chan3 tx_lp_en.
     88 * [4]  clk chan power down. this bit is also used as the power down
     89 *	of the whole MIPI_DSI_PHY.
     90 * [3]  chan3 power down.
     91 * [2]  chan2 power down.
     92 * [1]  chan1 power down.
     93 * [0]  chan0 power down.
     94 */
     95#define MIPI_DSI_CHAN_CTRL				0x4
     96
     97/* [24]   rx turn watch dog triggered.
     98 * [23]   rx esc watchdog  triggered.
     99 * [22]   mbias ready.
    100 * [21]   txclkesc  synced and ready.
    101 * [20:17] clk lane state. {mbias_ready, tx_stop, tx_ulps, tx_hs_active}
    102 * [16:13] chan3 state{0, tx_stop, tx_ulps, tx_hs_active}
    103 * [12:9]  chan2 state.{0, tx_stop, tx_ulps, tx_hs_active}
    104 * [8:5]   chan1 state. {0, tx_stop, tx_ulps, tx_hs_active}
    105 * [4:0]   chan0 state. {TX_STOP, tx_ULPS, hs_active, direction, rxulpsesc}
    106 */
    107#define MIPI_DSI_CHAN_STS				0x8
    108
    109/* [31:24] TCLK_PREPARE.
    110 * [23:16] TCLK_ZERO.
    111 * [15:8]  TCLK_POST.
    112 * [7:0]   TCLK_TRAIL.
    113 */
    114#define MIPI_DSI_CLK_TIM				0xc
    115
    116/* [31:24] THS_PREPARE.
    117 * [23:16] THS_ZERO.
    118 * [15:8]  THS_TRAIL.
    119 * [7:0]   THS_EXIT.
    120 */
    121#define MIPI_DSI_HS_TIM					0x10
    122
    123/* [31:24] tTA_GET.
    124 * [23:16] tTA_GO.
    125 * [15:8]  tTA_SURE.
    126 * [7:0]   tLPX.
    127 */
    128#define MIPI_DSI_LP_TIM					0x14
    129
    130/* wait time to  MIPI DIS analog ready. */
    131#define MIPI_DSI_ANA_UP_TIM				0x18
    132
    133/* TINIT. */
    134#define MIPI_DSI_INIT_TIM				0x1c
    135
    136/* TWAKEUP. */
    137#define MIPI_DSI_WAKEUP_TIM				0x20
    138
    139/* when in RxULPS check state, after the the logic enable the analog,
    140 *	how long we should wait to check the lP state .
    141 */
    142#define MIPI_DSI_LPOK_TIM				0x24
    143
    144/* Watchdog for RX low power state no finished. */
    145#define MIPI_DSI_LP_WCHDOG				0x28
    146
    147/* tMBIAS,  after send power up signals to analog,
    148 *	how long we should wait for analog powered up.
    149 */
    150#define MIPI_DSI_ANA_CTRL				0x2c
    151
    152/* [31:8]  reserved for future.
    153 * [7:0]   tCLK_PRE.
    154 */
    155#define MIPI_DSI_CLK_TIM1				0x30
    156
    157/* watchdog for turn around waiting time. */
    158#define MIPI_DSI_TURN_WCHDOG				0x34
    159
    160/* When in RxULPS state, how frequency we should to check
    161 *	if the TX side out of ULPS state.
    162 */
    163#define MIPI_DSI_ULPS_CHECK				0x38
    164#define MIPI_DSI_TEST_CTRL0				0x3c
    165#define MIPI_DSI_TEST_CTRL1				0x40
    166
    167struct phy_meson_axg_mipi_dphy_priv {
    168	struct device				*dev;
    169	struct regmap				*regmap;
    170	struct clk				*clk;
    171	struct reset_control			*reset;
    172	struct phy				*analog;
    173	struct phy_configure_opts_mipi_dphy	config;
    174};
    175
    176static const struct regmap_config phy_meson_axg_mipi_dphy_regmap_conf = {
    177	.reg_bits = 8,
    178	.val_bits = 32,
    179	.reg_stride = 4,
    180	.max_register = MIPI_DSI_TEST_CTRL1,
    181};
    182
    183static int phy_meson_axg_mipi_dphy_init(struct phy *phy)
    184{
    185	struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
    186	int ret;
    187
    188	ret = phy_init(priv->analog);
    189	if (ret)
    190		return ret;
    191
    192	ret = reset_control_reset(priv->reset);
    193	if (ret)
    194		return ret;
    195
    196	return 0;
    197}
    198
    199static int phy_meson_axg_mipi_dphy_configure(struct phy *phy,
    200					      union phy_configure_opts *opts)
    201{
    202	struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
    203	int ret;
    204
    205	ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
    206	if (ret)
    207		return ret;
    208
    209	ret = phy_configure(priv->analog, opts);
    210	if (ret)
    211		return ret;
    212
    213	memcpy(&priv->config, opts, sizeof(priv->config));
    214
    215	return 0;
    216}
    217
    218static int phy_meson_axg_mipi_dphy_power_on(struct phy *phy)
    219{
    220	struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
    221	int ret;
    222	unsigned long temp;
    223
    224	ret = phy_power_on(priv->analog);
    225	if (ret)
    226		return ret;
    227
    228	/* enable phy clock */
    229	regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL,  0x1);
    230	regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL,
    231		     BIT(0) | /* enable the DSI PLL clock . */
    232		     BIT(7) | /* enable pll clock which connected to DDR clock path */
    233		     BIT(8)); /* enable the clock divider counter */
    234
    235	/* enable the divider clock out */
    236	regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(9), BIT(9));
    237
    238	/* enable the byte clock generation. */
    239	regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(12), BIT(12));
    240	regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31), BIT(31));
    241	regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31), 0);
    242
    243	/* Calculate lanebyteclk period in ps */
    244	temp = (1000000 * 100) / (priv->config.hs_clk_rate / 1000);
    245	temp = temp * 8 * 10;
    246
    247	regmap_write(priv->regmap, MIPI_DSI_CLK_TIM,
    248		     DIV_ROUND_UP(priv->config.clk_trail, temp) |
    249		     (DIV_ROUND_UP(priv->config.clk_post +
    250				   priv->config.hs_trail, temp) << 8) |
    251		     (DIV_ROUND_UP(priv->config.clk_zero, temp) << 16) |
    252		     (DIV_ROUND_UP(priv->config.clk_prepare, temp) << 24));
    253	regmap_write(priv->regmap, MIPI_DSI_CLK_TIM1,
    254		     DIV_ROUND_UP(priv->config.clk_pre, BITS_PER_BYTE));
    255
    256	regmap_write(priv->regmap, MIPI_DSI_HS_TIM,
    257		     DIV_ROUND_UP(priv->config.hs_exit, temp) |
    258		     (DIV_ROUND_UP(priv->config.hs_trail, temp) << 8) |
    259		     (DIV_ROUND_UP(priv->config.hs_zero, temp) << 16) |
    260		     (DIV_ROUND_UP(priv->config.hs_prepare, temp) << 24));
    261
    262	regmap_write(priv->regmap, MIPI_DSI_LP_TIM,
    263		     DIV_ROUND_UP(priv->config.lpx, temp) |
    264		     (DIV_ROUND_UP(priv->config.ta_sure, temp) << 8) |
    265		     (DIV_ROUND_UP(priv->config.ta_go, temp) << 16) |
    266		     (DIV_ROUND_UP(priv->config.ta_get, temp) << 24));
    267
    268	regmap_write(priv->regmap, MIPI_DSI_ANA_UP_TIM, 0x0100);
    269	regmap_write(priv->regmap, MIPI_DSI_INIT_TIM,
    270		     DIV_ROUND_UP(priv->config.init * NSEC_PER_MSEC, temp));
    271	regmap_write(priv->regmap, MIPI_DSI_WAKEUP_TIM,
    272		     DIV_ROUND_UP(priv->config.wakeup * NSEC_PER_MSEC, temp));
    273	regmap_write(priv->regmap, MIPI_DSI_LPOK_TIM, 0x7C);
    274	regmap_write(priv->regmap, MIPI_DSI_ULPS_CHECK, 0x927C);
    275	regmap_write(priv->regmap, MIPI_DSI_LP_WCHDOG, 0x1000);
    276	regmap_write(priv->regmap, MIPI_DSI_TURN_WCHDOG, 0x1000);
    277
    278	/* Powerup the analog circuit */
    279	switch (priv->config.lanes) {
    280	case 1:
    281		regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xe);
    282		break;
    283	case 2:
    284		regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xc);
    285		break;
    286	case 3:
    287		regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0x8);
    288		break;
    289	case 4:
    290	default:
    291		regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0);
    292		break;
    293	}
    294
    295	/* Trigger a sync active for esc_clk */
    296	regmap_update_bits(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(1), BIT(1));
    297
    298	return 0;
    299}
    300
    301static int phy_meson_axg_mipi_dphy_power_off(struct phy *phy)
    302{
    303	struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
    304
    305	regmap_write(priv->regmap, MIPI_DSI_CHAN_CTRL, 0xf);
    306	regmap_write(priv->regmap, MIPI_DSI_PHY_CTRL, BIT(31));
    307
    308	phy_power_off(priv->analog);
    309
    310	return 0;
    311}
    312
    313static int phy_meson_axg_mipi_dphy_exit(struct phy *phy)
    314{
    315	struct phy_meson_axg_mipi_dphy_priv *priv = phy_get_drvdata(phy);
    316	int ret;
    317
    318	ret = phy_exit(priv->analog);
    319	if (ret)
    320		return ret;
    321
    322	return reset_control_reset(priv->reset);
    323}
    324
    325static const struct phy_ops phy_meson_axg_mipi_dphy_ops = {
    326	.configure	= phy_meson_axg_mipi_dphy_configure,
    327	.init		= phy_meson_axg_mipi_dphy_init,
    328	.exit		= phy_meson_axg_mipi_dphy_exit,
    329	.power_on	= phy_meson_axg_mipi_dphy_power_on,
    330	.power_off	= phy_meson_axg_mipi_dphy_power_off,
    331	.owner		= THIS_MODULE,
    332};
    333
    334static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev)
    335{
    336	struct device *dev = &pdev->dev;
    337	struct phy_provider *phy_provider;
    338	struct resource *res;
    339	struct phy_meson_axg_mipi_dphy_priv *priv;
    340	struct phy *phy;
    341	void __iomem *base;
    342	int ret;
    343
    344	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    345	if (!priv)
    346		return -ENOMEM;
    347
    348	priv->dev = dev;
    349	platform_set_drvdata(pdev, priv);
    350
    351	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    352	base = devm_ioremap_resource(dev, res);
    353	if (IS_ERR(base))
    354		return PTR_ERR(base);
    355
    356	priv->regmap = devm_regmap_init_mmio(dev, base,
    357					&phy_meson_axg_mipi_dphy_regmap_conf);
    358	if (IS_ERR(priv->regmap))
    359		return PTR_ERR(priv->regmap);
    360
    361	priv->clk = devm_clk_get(dev, "pclk");
    362	if (IS_ERR(priv->clk))
    363		return PTR_ERR(priv->clk);
    364
    365	priv->reset = devm_reset_control_get(dev, "phy");
    366	if (IS_ERR(priv->reset))
    367		return PTR_ERR(priv->reset);
    368
    369	priv->analog = devm_phy_get(dev, "analog");
    370	if (IS_ERR(priv->analog))
    371		return PTR_ERR(priv->analog);
    372
    373	ret = clk_prepare_enable(priv->clk);
    374	if (ret)
    375		return ret;
    376
    377	ret = reset_control_deassert(priv->reset);
    378	if (ret)
    379		return ret;
    380
    381	phy = devm_phy_create(dev, NULL, &phy_meson_axg_mipi_dphy_ops);
    382	if (IS_ERR(phy)) {
    383		ret = PTR_ERR(phy);
    384		if (ret != -EPROBE_DEFER)
    385			dev_err(dev, "failed to create PHY\n");
    386
    387		return ret;
    388	}
    389
    390	phy_set_drvdata(phy, priv);
    391
    392	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    393
    394	return PTR_ERR_OR_ZERO(phy_provider);
    395}
    396
    397static const struct of_device_id phy_meson_axg_mipi_dphy_of_match[] = {
    398	{ .compatible = "amlogic,axg-mipi-dphy", },
    399	{ },
    400};
    401MODULE_DEVICE_TABLE(of, phy_meson_axg_mipi_dphy_of_match);
    402
    403static struct platform_driver phy_meson_axg_mipi_dphy_driver = {
    404	.probe	= phy_meson_axg_mipi_dphy_probe,
    405	.driver	= {
    406		.name		= "phy-meson-axg-mipi-dphy",
    407		.of_match_table	= phy_meson_axg_mipi_dphy_of_match,
    408	},
    409};
    410module_platform_driver(phy_meson_axg_mipi_dphy_driver);
    411
    412MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
    413MODULE_DESCRIPTION("Meson AXG MIPI DPHY driver");
    414MODULE_LICENSE("GPL v2");