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-exynos-mipi-video.c (11128B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Samsung S5P/Exynos SoC series MIPI CSIS/DSIM DPHY driver
      4 *
      5 * Copyright (C) 2013,2016 Samsung Electronics Co., Ltd.
      6 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
      7 */
      8
      9#include <linux/err.h>
     10#include <linux/io.h>
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/of.h>
     14#include <linux/of_address.h>
     15#include <linux/of_device.h>
     16#include <linux/phy/phy.h>
     17#include <linux/regmap.h>
     18#include <linux/spinlock.h>
     19#include <linux/soc/samsung/exynos-regs-pmu.h>
     20#include <linux/mfd/syscon.h>
     21
     22enum exynos_mipi_phy_id {
     23	EXYNOS_MIPI_PHY_ID_NONE = -1,
     24	EXYNOS_MIPI_PHY_ID_CSIS0,
     25	EXYNOS_MIPI_PHY_ID_DSIM0,
     26	EXYNOS_MIPI_PHY_ID_CSIS1,
     27	EXYNOS_MIPI_PHY_ID_DSIM1,
     28	EXYNOS_MIPI_PHY_ID_CSIS2,
     29	EXYNOS_MIPI_PHYS_NUM
     30};
     31
     32enum exynos_mipi_phy_regmap_id {
     33	EXYNOS_MIPI_REGMAP_PMU,
     34	EXYNOS_MIPI_REGMAP_DISP,
     35	EXYNOS_MIPI_REGMAP_CAM0,
     36	EXYNOS_MIPI_REGMAP_CAM1,
     37	EXYNOS_MIPI_REGMAPS_NUM
     38};
     39
     40struct mipi_phy_device_desc {
     41	int num_phys;
     42	int num_regmaps;
     43	const char *regmap_names[EXYNOS_MIPI_REGMAPS_NUM];
     44	struct exynos_mipi_phy_desc {
     45		enum exynos_mipi_phy_id	coupled_phy_id;
     46		u32 enable_val;
     47		unsigned int enable_reg;
     48		enum exynos_mipi_phy_regmap_id enable_map;
     49		u32 resetn_val;
     50		unsigned int resetn_reg;
     51		enum exynos_mipi_phy_regmap_id resetn_map;
     52	} phys[EXYNOS_MIPI_PHYS_NUM];
     53};
     54
     55static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
     56	.num_regmaps = 1,
     57	.regmap_names = {"syscon"},
     58	.num_phys = 4,
     59	.phys = {
     60		{
     61			/* EXYNOS_MIPI_PHY_ID_CSIS0 */
     62			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
     63			.enable_val = EXYNOS4_PHY_ENABLE,
     64			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
     65			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
     66			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
     67			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
     68			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
     69		}, {
     70			/* EXYNOS_MIPI_PHY_ID_DSIM0 */
     71			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
     72			.enable_val = EXYNOS4_PHY_ENABLE,
     73			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
     74			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
     75			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
     76			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
     77			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
     78		}, {
     79			/* EXYNOS_MIPI_PHY_ID_CSIS1 */
     80			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
     81			.enable_val = EXYNOS4_PHY_ENABLE,
     82			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
     83			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
     84			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
     85			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
     86			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
     87		}, {
     88			/* EXYNOS_MIPI_PHY_ID_DSIM1 */
     89			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
     90			.enable_val = EXYNOS4_PHY_ENABLE,
     91			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
     92			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
     93			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
     94			.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
     95			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
     96		},
     97	},
     98};
     99
    100static const struct mipi_phy_device_desc exynos5420_mipi_phy = {
    101	.num_regmaps = 1,
    102	.regmap_names = {"syscon"},
    103	.num_phys = 5,
    104	.phys = {
    105		{
    106			/* EXYNOS_MIPI_PHY_ID_CSIS0 */
    107			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
    108			.enable_val = EXYNOS4_PHY_ENABLE,
    109			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
    110			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    111			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
    112			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
    113			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
    114		}, {
    115			/* EXYNOS_MIPI_PHY_ID_DSIM0 */
    116			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
    117			.enable_val = EXYNOS4_PHY_ENABLE,
    118			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
    119			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    120			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
    121			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
    122			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
    123		}, {
    124			/* EXYNOS_MIPI_PHY_ID_CSIS1 */
    125			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
    126			.enable_val = EXYNOS4_PHY_ENABLE,
    127			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
    128			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    129			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
    130			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
    131			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
    132		}, {
    133			/* EXYNOS_MIPI_PHY_ID_DSIM1 */
    134			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
    135			.enable_val = EXYNOS4_PHY_ENABLE,
    136			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
    137			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    138			.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
    139			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
    140			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
    141		}, {
    142			/* EXYNOS_MIPI_PHY_ID_CSIS2 */
    143			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
    144			.enable_val = EXYNOS4_PHY_ENABLE,
    145			.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
    146			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    147			.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
    148			.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
    149			.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
    150		},
    151	},
    152};
    153
    154#define EXYNOS5433_SYSREG_DISP_MIPI_PHY		0x100C
    155#define EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON	0x1014
    156#define EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON	0x1020
    157
    158static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
    159	.num_regmaps = 4,
    160	.regmap_names = {
    161		"samsung,pmu-syscon",
    162		"samsung,disp-sysreg",
    163		"samsung,cam0-sysreg",
    164		"samsung,cam1-sysreg"
    165	},
    166	.num_phys = 5,
    167	.phys = {
    168		{
    169			/* EXYNOS_MIPI_PHY_ID_CSIS0 */
    170			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
    171			.enable_val = EXYNOS4_PHY_ENABLE,
    172			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
    173			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    174			.resetn_val = BIT(0),
    175			.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
    176			.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
    177		}, {
    178			/* EXYNOS_MIPI_PHY_ID_DSIM0 */
    179			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
    180			.enable_val = EXYNOS4_PHY_ENABLE,
    181			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
    182			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    183			.resetn_val = BIT(0),
    184			.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
    185			.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
    186		}, {
    187			/* EXYNOS_MIPI_PHY_ID_CSIS1 */
    188			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
    189			.enable_val = EXYNOS4_PHY_ENABLE,
    190			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
    191			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    192			.resetn_val = BIT(1),
    193			.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
    194			.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
    195		}, {
    196			/* EXYNOS_MIPI_PHY_ID_DSIM1 */
    197			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
    198			.enable_val = EXYNOS4_PHY_ENABLE,
    199			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
    200			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    201			.resetn_val = BIT(1),
    202			.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
    203			.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
    204		}, {
    205			/* EXYNOS_MIPI_PHY_ID_CSIS2 */
    206			.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
    207			.enable_val = EXYNOS4_PHY_ENABLE,
    208			.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(2),
    209			.enable_map = EXYNOS_MIPI_REGMAP_PMU,
    210			.resetn_val = BIT(0),
    211			.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
    212			.resetn_map = EXYNOS_MIPI_REGMAP_CAM1,
    213		},
    214	},
    215};
    216
    217struct exynos_mipi_video_phy {
    218	struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM];
    219	int num_phys;
    220	struct video_phy_desc {
    221		struct phy *phy;
    222		unsigned int index;
    223		const struct exynos_mipi_phy_desc *data;
    224	} phys[EXYNOS_MIPI_PHYS_NUM];
    225	spinlock_t slock;
    226};
    227
    228static int __set_phy_state(const struct exynos_mipi_phy_desc *data,
    229			   struct exynos_mipi_video_phy *state, unsigned int on)
    230{
    231	struct regmap *enable_map = state->regmaps[data->enable_map];
    232	struct regmap *resetn_map = state->regmaps[data->resetn_map];
    233
    234	spin_lock(&state->slock);
    235
    236	/* disable in PMU sysreg */
    237	if (!on && data->coupled_phy_id >= 0 &&
    238	    state->phys[data->coupled_phy_id].phy->power_count == 0)
    239		regmap_update_bits(enable_map, data->enable_reg,
    240				   data->enable_val, 0);
    241	/* PHY reset */
    242	if (on)
    243		regmap_update_bits(resetn_map, data->resetn_reg,
    244				   data->resetn_val, data->resetn_val);
    245	else
    246		regmap_update_bits(resetn_map, data->resetn_reg,
    247				   data->resetn_val, 0);
    248	/* enable in PMU sysreg */
    249	if (on)
    250		regmap_update_bits(enable_map, data->enable_reg,
    251				   data->enable_val, data->enable_val);
    252
    253	spin_unlock(&state->slock);
    254
    255	return 0;
    256}
    257
    258#define to_mipi_video_phy(desc) \
    259	container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index])
    260
    261static int exynos_mipi_video_phy_power_on(struct phy *phy)
    262{
    263	struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
    264	struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
    265
    266	return __set_phy_state(phy_desc->data, state, 1);
    267}
    268
    269static int exynos_mipi_video_phy_power_off(struct phy *phy)
    270{
    271	struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
    272	struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
    273
    274	return __set_phy_state(phy_desc->data, state, 0);
    275}
    276
    277static struct phy *exynos_mipi_video_phy_xlate(struct device *dev,
    278					struct of_phandle_args *args)
    279{
    280	struct exynos_mipi_video_phy *state = dev_get_drvdata(dev);
    281
    282	if (WARN_ON(args->args[0] >= state->num_phys))
    283		return ERR_PTR(-ENODEV);
    284
    285	return state->phys[args->args[0]].phy;
    286}
    287
    288static const struct phy_ops exynos_mipi_video_phy_ops = {
    289	.power_on	= exynos_mipi_video_phy_power_on,
    290	.power_off	= exynos_mipi_video_phy_power_off,
    291	.owner		= THIS_MODULE,
    292};
    293
    294static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
    295{
    296	const struct mipi_phy_device_desc *phy_dev;
    297	struct exynos_mipi_video_phy *state;
    298	struct device *dev = &pdev->dev;
    299	struct device_node *np = dev->of_node;
    300	struct phy_provider *phy_provider;
    301	unsigned int i;
    302
    303	phy_dev = of_device_get_match_data(dev);
    304	if (!phy_dev)
    305		return -ENODEV;
    306
    307	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
    308	if (!state)
    309		return -ENOMEM;
    310
    311	for (i = 0; i < phy_dev->num_regmaps; i++) {
    312		state->regmaps[i] = syscon_regmap_lookup_by_phandle(np,
    313						phy_dev->regmap_names[i]);
    314		if (IS_ERR(state->regmaps[i]))
    315			return PTR_ERR(state->regmaps[i]);
    316	}
    317	state->num_phys = phy_dev->num_phys;
    318	spin_lock_init(&state->slock);
    319
    320	dev_set_drvdata(dev, state);
    321
    322	for (i = 0; i < state->num_phys; i++) {
    323		struct phy *phy = devm_phy_create(dev, NULL,
    324						  &exynos_mipi_video_phy_ops);
    325		if (IS_ERR(phy)) {
    326			dev_err(dev, "failed to create PHY %d\n", i);
    327			return PTR_ERR(phy);
    328		}
    329
    330		state->phys[i].phy = phy;
    331		state->phys[i].index = i;
    332		state->phys[i].data = &phy_dev->phys[i];
    333		phy_set_drvdata(phy, &state->phys[i]);
    334	}
    335
    336	phy_provider = devm_of_phy_provider_register(dev,
    337					exynos_mipi_video_phy_xlate);
    338
    339	return PTR_ERR_OR_ZERO(phy_provider);
    340}
    341
    342static const struct of_device_id exynos_mipi_video_phy_of_match[] = {
    343	{
    344		.compatible = "samsung,s5pv210-mipi-video-phy",
    345		.data = &s5pv210_mipi_phy,
    346	}, {
    347		.compatible = "samsung,exynos5420-mipi-video-phy",
    348		.data = &exynos5420_mipi_phy,
    349	}, {
    350		.compatible = "samsung,exynos5433-mipi-video-phy",
    351		.data = &exynos5433_mipi_phy,
    352	},
    353	{ /* sentinel */ },
    354};
    355MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match);
    356
    357static struct platform_driver exynos_mipi_video_phy_driver = {
    358	.probe	= exynos_mipi_video_phy_probe,
    359	.driver = {
    360		.of_match_table	= exynos_mipi_video_phy_of_match,
    361		.name  = "exynos-mipi-video-phy",
    362		.suppress_bind_attrs = true,
    363	}
    364};
    365module_platform_driver(exynos_mipi_video_phy_driver);
    366
    367MODULE_DESCRIPTION("Samsung S5P/Exynos SoC MIPI CSI-2/DSI PHY driver");
    368MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
    369MODULE_LICENSE("GPL v2");