18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * UFS PHY driver for Samsung EXYNOS SoC
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Samsung Electronics Co., Ltd.
68c2ecf20Sopenharmony_ci * Author: Seungwon Jeon <essuuj@gmail.com>
78c2ecf20Sopenharmony_ci * Author: Alim Akhtar <alim.akhtar@samsung.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#ifndef _PHY_SAMSUNG_UFS_
118c2ecf20Sopenharmony_ci#define _PHY_SAMSUNG_UFS_
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define PHY_COMN_BLK	1
148c2ecf20Sopenharmony_ci#define PHY_TRSV_BLK	2
158c2ecf20Sopenharmony_ci#define END_UFS_PHY_CFG { 0 }
168c2ecf20Sopenharmony_ci#define PHY_TRSV_CH_OFFSET	0x30
178c2ecf20Sopenharmony_ci#define PHY_APB_ADDR(off)	((off) << 2)
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define PHY_COMN_REG_CFG(o, v, d) {	\
208c2ecf20Sopenharmony_ci	.off_0 = PHY_APB_ADDR((o)),	\
218c2ecf20Sopenharmony_ci	.off_1 = 0,		\
228c2ecf20Sopenharmony_ci	.val = (v),		\
238c2ecf20Sopenharmony_ci	.desc = (d),		\
248c2ecf20Sopenharmony_ci	.id = PHY_COMN_BLK,	\
258c2ecf20Sopenharmony_ci}
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define PHY_TRSV_REG_CFG(o, v, d) {	\
288c2ecf20Sopenharmony_ci	.off_0 = PHY_APB_ADDR((o)),	\
298c2ecf20Sopenharmony_ci	.off_1 = PHY_APB_ADDR((o) + PHY_TRSV_CH_OFFSET),	\
308c2ecf20Sopenharmony_ci	.val = (v),		\
318c2ecf20Sopenharmony_ci	.desc = (d),		\
328c2ecf20Sopenharmony_ci	.id = PHY_TRSV_BLK,	\
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* UFS PHY registers */
368c2ecf20Sopenharmony_ci#define PHY_PLL_LOCK_STATUS	0x1e
378c2ecf20Sopenharmony_ci#define PHY_CDR_LOCK_STATUS	0x5e
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define PHY_PLL_LOCK_BIT	BIT(5)
408c2ecf20Sopenharmony_ci#define PHY_CDR_LOCK_BIT	BIT(4)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* description for PHY calibration */
438c2ecf20Sopenharmony_cienum {
448c2ecf20Sopenharmony_ci	/* applicable to any */
458c2ecf20Sopenharmony_ci	PWR_DESC_ANY	= 0,
468c2ecf20Sopenharmony_ci	/* mode */
478c2ecf20Sopenharmony_ci	PWR_DESC_PWM	= 1,
488c2ecf20Sopenharmony_ci	PWR_DESC_HS	= 2,
498c2ecf20Sopenharmony_ci	/* series */
508c2ecf20Sopenharmony_ci	PWR_DESC_SER_A	= 1,
518c2ecf20Sopenharmony_ci	PWR_DESC_SER_B	= 2,
528c2ecf20Sopenharmony_ci	/* gear */
538c2ecf20Sopenharmony_ci	PWR_DESC_G1	= 1,
548c2ecf20Sopenharmony_ci	PWR_DESC_G2	= 2,
558c2ecf20Sopenharmony_ci	PWR_DESC_G3	= 3,
568c2ecf20Sopenharmony_ci	/* field mask */
578c2ecf20Sopenharmony_ci	MD_MASK		= 0x3,
588c2ecf20Sopenharmony_ci	SR_MASK		= 0x3,
598c2ecf20Sopenharmony_ci	GR_MASK		= 0x7,
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G1_ANY	PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_ANY)
638c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G1_SER_A	PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_SER_A)
648c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G1_SER_B	PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_SER_B)
658c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G2_ANY	PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_ANY)
668c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G2_SER_A	PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_SER_A)
678c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G2_SER_B	PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_SER_B)
688c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G3_ANY	PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_ANY)
698c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G3_SER_A	PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_SER_A)
708c2ecf20Sopenharmony_ci#define PWR_MODE_HS_G3_SER_B	PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_SER_B)
718c2ecf20Sopenharmony_ci#define PWR_MODE(g, s, m)	((((g) & GR_MASK) << 4) |\
728c2ecf20Sopenharmony_ci				 (((s) & SR_MASK) << 2) | ((m) & MD_MASK))
738c2ecf20Sopenharmony_ci#define PWR_MODE_PWM_ANY	PWR_MODE(PWR_DESC_ANY,\
748c2ecf20Sopenharmony_ci					 PWR_DESC_ANY, PWR_DESC_PWM)
758c2ecf20Sopenharmony_ci#define PWR_MODE_HS(g, s)	((((g) & GR_MASK) << 4) |\
768c2ecf20Sopenharmony_ci				 (((s) & SR_MASK) << 2) | PWR_DESC_HS)
778c2ecf20Sopenharmony_ci#define PWR_MODE_HS_ANY		PWR_MODE(PWR_DESC_ANY,\
788c2ecf20Sopenharmony_ci					 PWR_DESC_ANY, PWR_DESC_HS)
798c2ecf20Sopenharmony_ci#define PWR_MODE_ANY		PWR_MODE(PWR_DESC_ANY,\
808c2ecf20Sopenharmony_ci					 PWR_DESC_ANY, PWR_DESC_ANY)
818c2ecf20Sopenharmony_ci/* PHY calibration point/state */
828c2ecf20Sopenharmony_cienum {
838c2ecf20Sopenharmony_ci	CFG_PRE_INIT,
848c2ecf20Sopenharmony_ci	CFG_POST_INIT,
858c2ecf20Sopenharmony_ci	CFG_PRE_PWR_HS,
868c2ecf20Sopenharmony_ci	CFG_POST_PWR_HS,
878c2ecf20Sopenharmony_ci	CFG_TAG_MAX,
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistruct samsung_ufs_phy_cfg {
918c2ecf20Sopenharmony_ci	u32 off_0;
928c2ecf20Sopenharmony_ci	u32 off_1;
938c2ecf20Sopenharmony_ci	u32 val;
948c2ecf20Sopenharmony_ci	u8 desc;
958c2ecf20Sopenharmony_ci	u8 id;
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistruct samsung_ufs_phy_drvdata {
998c2ecf20Sopenharmony_ci	const struct samsung_ufs_phy_cfg **cfg;
1008c2ecf20Sopenharmony_ci	struct pmu_isol {
1018c2ecf20Sopenharmony_ci		u32 offset;
1028c2ecf20Sopenharmony_ci		u32 mask;
1038c2ecf20Sopenharmony_ci		u32 en;
1048c2ecf20Sopenharmony_ci	} isol;
1058c2ecf20Sopenharmony_ci	bool has_symbol_clk;
1068c2ecf20Sopenharmony_ci};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistruct samsung_ufs_phy {
1098c2ecf20Sopenharmony_ci	struct device *dev;
1108c2ecf20Sopenharmony_ci	void __iomem *reg_pma;
1118c2ecf20Sopenharmony_ci	struct regmap *reg_pmu;
1128c2ecf20Sopenharmony_ci	struct clk *ref_clk;
1138c2ecf20Sopenharmony_ci	struct clk *ref_clk_parent;
1148c2ecf20Sopenharmony_ci	struct clk *tx0_symbol_clk;
1158c2ecf20Sopenharmony_ci	struct clk *rx0_symbol_clk;
1168c2ecf20Sopenharmony_ci	struct clk *rx1_symbol_clk;
1178c2ecf20Sopenharmony_ci	const struct samsung_ufs_phy_drvdata *drvdata;
1188c2ecf20Sopenharmony_ci	struct samsung_ufs_phy_cfg **cfg;
1198c2ecf20Sopenharmony_ci	const struct pmu_isol *isol;
1208c2ecf20Sopenharmony_ci	u8 lane_cnt;
1218c2ecf20Sopenharmony_ci	int ufs_phy_state;
1228c2ecf20Sopenharmony_ci	enum phy_mode mode;
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic inline struct samsung_ufs_phy *get_samsung_ufs_phy(struct phy *phy)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	return (struct samsung_ufs_phy *)phy_get_drvdata(phy);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic inline void samsung_ufs_phy_ctrl_isol(
1318c2ecf20Sopenharmony_ci		struct samsung_ufs_phy *phy, u32 isol)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	regmap_update_bits(phy->reg_pmu, phy->isol->offset,
1348c2ecf20Sopenharmony_ci			   phy->isol->mask, isol ? 0 : phy->isol->en);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#include "phy-exynos7-ufs.h"
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#endif /* _PHY_SAMSUNG_UFS_ */
140