Re: [PATCH v7 2/5] phy: qcom-ufs: add support for 20nm phy
hi, On Thursday 15 January 2015 08:02 PM, Yaniv Gardi wrote: > This change adds a support for a 20nm qcom-ufs phy that is required in > platforms that use ufs-qcom controller. > > Signed-off-by: Yaniv Gardi > > --- > drivers/phy/Makefile| 1 + > drivers/phy/phy-qcom-ufs-i.h| 43 +- > drivers/phy/phy-qcom-ufs-qmp-20nm.c | 257 > > drivers/phy/phy-qcom-ufs-qmp-20nm.h | 235 + > include/linux/phy/phy-qcom-ufs.h| 59 + > 5 files changed, 594 insertions(+), 1 deletion(-) > create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.c > create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.h > create mode 100644 include/linux/phy/phy-qcom-ufs.h > > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index 335965d..781b2fa 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -35,3 +35,4 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o > obj-$(CONFIG_PHY_STIH407_USB)+= phy-stih407-usb.o > obj-$(CONFIG_PHY_STIH41X_USB)+= phy-stih41x-usb.o > obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o > +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o > diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h > index dac200f..591a391 100644 > --- a/drivers/phy/phy-qcom-ufs-i.h > +++ b/drivers/phy/phy-qcom-ufs-i.h > @@ -15,15 +15,56 @@ > #ifndef UFS_QCOM_PHY_I_H_ > #define UFS_QCOM_PHY_I_H_ > > +#include > #include > +#include > #include > -#include > +#include > #include > #include > #include > > +#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ > +({ \ > + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ > + might_sleep_if(timeout_us); \ > + for (;;) { \ > + (val) = readl(addr); \ > + if (cond) \ > + break; \ > + if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \ > + (val) = readl(addr); \ > + break; \ > + } \ > + if (sleep_us) \ > + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ > + } \ > + (cond) ? 0 : -ETIMEDOUT; \ > +}) > + > +#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ > + { \ > + .reg_offset = reg, \ > + .cfg_value = val, \ > + } > + > #define UFS_QCOM_PHY_NAME_LEN30 > > +enum { > + MASK_SERDES_START = 0x1, > + MASK_PCS_READY = 0x1, > +}; > + > +enum { > + OFFSET_SERDES_START = 0x0, > +}; > + > +struct ufs_qcom_phy_stored_attributes { > + u32 att; > + u32 value; > +}; > + > + > struct ufs_qcom_phy_calibration { > u32 reg_offset; > u32 cfg_value; > diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c > b/drivers/phy/phy-qcom-ufs-qmp-20nm.c > new file mode 100644 > index 000..8332f96 > --- /dev/null > +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c > @@ -0,0 +1,257 @@ > +/* > + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only version 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include "phy-qcom-ufs-qmp-20nm.h" > + > +#define UFS_PHY_NAME "ufs_phy_qmp_20nm" > + > +static > +int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, > + bool is_rate_B) > +{ > + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; > + int tbl_size_A, tbl_size_B; > + u8 major = ufs_qcom_phy->host_ctrl_rev_major; > + u16 minor = ufs_qcom_phy->host_ctrl_rev_minor; > + u16 step = ufs_qcom_phy->host_ctrl_rev_step; > + int err; > + > + if ((major == 0x1) && (minor == 0x002) && (step == 0x)) { > + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); > + tbl_A = phy_cal_table_rate_A_1_2_0; > + } else if ((major == 0x1) && (minor == 0x003) && (step == 0x)) { > + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); > + tbl_A = phy_cal_table_rate_A_1_3_0; > + } else { > + dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, no > calibration values\n", > + __func__); > + err = -ENODEV; > + goto out; > + } > + > + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); > + tbl_B = phy_cal_table_rate_B; > + > + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, > + tbl_B,
Re: [PATCH v7 2/5] phy: qcom-ufs: add support for 20nm phy
hi, On Thursday 15 January 2015 08:02 PM, Yaniv Gardi wrote: This change adds a support for a 20nm qcom-ufs phy that is required in platforms that use ufs-qcom controller. Signed-off-by: Yaniv Gardi yga...@codeaurora.org --- drivers/phy/Makefile| 1 + drivers/phy/phy-qcom-ufs-i.h| 43 +- drivers/phy/phy-qcom-ufs-qmp-20nm.c | 257 drivers/phy/phy-qcom-ufs-qmp-20nm.h | 235 + include/linux/phy/phy-qcom-ufs.h| 59 + 5 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.c create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.h create mode 100644 include/linux/phy/phy-qcom-ufs.h diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 335965d..781b2fa 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -35,3 +35,4 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_STIH407_USB)+= phy-stih407-usb.o obj-$(CONFIG_PHY_STIH41X_USB)+= phy-stih41x-usb.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h index dac200f..591a391 100644 --- a/drivers/phy/phy-qcom-ufs-i.h +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -15,15 +15,56 @@ #ifndef UFS_QCOM_PHY_I_H_ #define UFS_QCOM_PHY_I_H_ +#include linux/module.h #include linux/clk.h +#include linux/regulator/consumer.h #include linux/slab.h -#include linux/phy/phy.h +#include linux/phy/phy-qcom-ufs.h #include linux/platform_device.h #include linux/io.h #include linux/delay.h +#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ +({ \ + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ + might_sleep_if(timeout_us); \ + for (;;) { \ + (val) = readl(addr); \ + if (cond) \ + break; \ + if (timeout_us ktime_compare(ktime_get(), timeout) 0) { \ + (val) = readl(addr); \ + break; \ + } \ + if (sleep_us) \ + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + +#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ + { \ + .reg_offset = reg, \ + .cfg_value = val, \ + } + #define UFS_QCOM_PHY_NAME_LEN30 +enum { + MASK_SERDES_START = 0x1, + MASK_PCS_READY = 0x1, +}; + +enum { + OFFSET_SERDES_START = 0x0, +}; + +struct ufs_qcom_phy_stored_attributes { + u32 att; + u32 value; +}; + + struct ufs_qcom_phy_calibration { u32 reg_offset; u32 cfg_value; diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c new file mode 100644 index 000..8332f96 --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include phy-qcom-ufs-qmp-20nm.h + +#define UFS_PHY_NAME ufs_phy_qmp_20nm + +static +int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + bool is_rate_B) +{ + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + u8 major = ufs_qcom_phy-host_ctrl_rev_major; + u16 minor = ufs_qcom_phy-host_ctrl_rev_minor; + u16 step = ufs_qcom_phy-host_ctrl_rev_step; + int err; + + if ((major == 0x1) (minor == 0x002) (step == 0x)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); + tbl_A = phy_cal_table_rate_A_1_2_0; + } else if ((major == 0x1) (minor == 0x003) (step == 0x)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); + tbl_A = phy_cal_table_rate_A_1_3_0; + } else { + dev_err(ufs_qcom_phy-dev, %s: Unknown UFS-PHY version, no calibration values\n, + __func__); + err = -ENODEV; + goto out; + } + + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + tbl_B = phy_cal_table_rate_B; + + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, + tbl_B,
Re: [PATCH v7 2/5] phy: qcom-ufs: add support for 20nm phy
Reviewed-by: Dov Levenglick > This change adds a support for a 20nm qcom-ufs phy that is required in > platforms that use ufs-qcom controller. > > Signed-off-by: Yaniv Gardi > > --- > drivers/phy/Makefile| 1 + > drivers/phy/phy-qcom-ufs-i.h| 43 +- > drivers/phy/phy-qcom-ufs-qmp-20nm.c | 257 > > drivers/phy/phy-qcom-ufs-qmp-20nm.h | 235 > + > include/linux/phy/phy-qcom-ufs.h| 59 + > 5 files changed, 594 insertions(+), 1 deletion(-) > create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.c > create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.h > create mode 100644 include/linux/phy/phy-qcom-ufs.h > > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index 335965d..781b2fa 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -35,3 +35,4 @@ obj-$(CONFIG_PHY_XGENE) += > phy-xgene.o > obj-$(CONFIG_PHY_STIH407_USB)+= phy-stih407-usb.o > obj-$(CONFIG_PHY_STIH41X_USB)+= phy-stih41x-usb.o > obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o > +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o > diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h > index dac200f..591a391 100644 > --- a/drivers/phy/phy-qcom-ufs-i.h > +++ b/drivers/phy/phy-qcom-ufs-i.h > @@ -15,15 +15,56 @@ > #ifndef UFS_QCOM_PHY_I_H_ > #define UFS_QCOM_PHY_I_H_ > > +#include > #include > +#include > #include > -#include > +#include > #include > #include > #include > > +#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ > +({ \ > + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ > + might_sleep_if(timeout_us); \ > + for (;;) { \ > + (val) = readl(addr); \ > + if (cond) \ > + break; \ > + if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) > { \ > + (val) = readl(addr); \ > + break; \ > + } \ > + if (sleep_us) \ > + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); > \ > + } \ > + (cond) ? 0 : -ETIMEDOUT; \ > +}) > + > +#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ > + { \ > + .reg_offset = reg, \ > + .cfg_value = val, \ > + } > + > #define UFS_QCOM_PHY_NAME_LEN30 > > +enum { > + MASK_SERDES_START = 0x1, > + MASK_PCS_READY = 0x1, > +}; > + > +enum { > + OFFSET_SERDES_START = 0x0, > +}; > + > +struct ufs_qcom_phy_stored_attributes { > + u32 att; > + u32 value; > +}; > + > + > struct ufs_qcom_phy_calibration { > u32 reg_offset; > u32 cfg_value; > diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c > b/drivers/phy/phy-qcom-ufs-qmp-20nm.c > new file mode 100644 > index 000..8332f96 > --- /dev/null > +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c > @@ -0,0 +1,257 @@ > +/* > + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only version 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include "phy-qcom-ufs-qmp-20nm.h" > + > +#define UFS_PHY_NAME "ufs_phy_qmp_20nm" > + > +static > +int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy > *ufs_qcom_phy, > + bool is_rate_B) > +{ > + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; > + int tbl_size_A, tbl_size_B; > + u8 major = ufs_qcom_phy->host_ctrl_rev_major; > + u16 minor = ufs_qcom_phy->host_ctrl_rev_minor; > + u16 step = ufs_qcom_phy->host_ctrl_rev_step; > + int err; > + > + if ((major == 0x1) && (minor == 0x002) && (step == 0x)) { > + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); > + tbl_A = phy_cal_table_rate_A_1_2_0; > + } else if ((major == 0x1) && (minor == 0x003) && (step == 0x)) > { > + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); > + tbl_A = phy_cal_table_rate_A_1_3_0; > + } else { > + dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, > no calibration values\n", > + __func__); > + err = -ENODEV; > + goto out; > + } > + > + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); > + tbl_B = phy_cal_table_rate_B; > + > + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, > + tbl_B, tbl_size_B, > is_rate_B); > + > +
Re: [PATCH v7 2/5] phy: qcom-ufs: add support for 20nm phy
Reviewed-by: Dov Levenglick > This change adds a support for a 20nm qcom-ufs phy that is required in > platforms that use ufs-qcom controller. > > Signed-off-by: Yaniv Gardi > > --- > drivers/phy/Makefile| 1 + > drivers/phy/phy-qcom-ufs-i.h| 43 +- > drivers/phy/phy-qcom-ufs-qmp-20nm.c | 257 > > drivers/phy/phy-qcom-ufs-qmp-20nm.h | 235 > + > include/linux/phy/phy-qcom-ufs.h| 59 + > 5 files changed, 594 insertions(+), 1 deletion(-) > create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.c > create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.h > create mode 100644 include/linux/phy/phy-qcom-ufs.h > > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index 335965d..781b2fa 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -35,3 +35,4 @@ obj-$(CONFIG_PHY_XGENE) += > phy-xgene.o > obj-$(CONFIG_PHY_STIH407_USB)+= phy-stih407-usb.o > obj-$(CONFIG_PHY_STIH41X_USB)+= phy-stih41x-usb.o > obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o > +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o > diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h > index dac200f..591a391 100644 > --- a/drivers/phy/phy-qcom-ufs-i.h > +++ b/drivers/phy/phy-qcom-ufs-i.h > @@ -15,15 +15,56 @@ > #ifndef UFS_QCOM_PHY_I_H_ > #define UFS_QCOM_PHY_I_H_ > > +#include > #include > +#include > #include > -#include > +#include > #include > #include > #include > > +#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ > +({ \ > + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ > + might_sleep_if(timeout_us); \ > + for (;;) { \ > + (val) = readl(addr); \ > + if (cond) \ > + break; \ > + if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) > { \ > + (val) = readl(addr); \ > + break; \ > + } \ > + if (sleep_us) \ > + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); > \ > + } \ > + (cond) ? 0 : -ETIMEDOUT; \ > +}) > + > +#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ > + { \ > + .reg_offset = reg, \ > + .cfg_value = val, \ > + } > + > #define UFS_QCOM_PHY_NAME_LEN30 > > +enum { > + MASK_SERDES_START = 0x1, > + MASK_PCS_READY = 0x1, > +}; > + > +enum { > + OFFSET_SERDES_START = 0x0, > +}; > + > +struct ufs_qcom_phy_stored_attributes { > + u32 att; > + u32 value; > +}; > + > + > struct ufs_qcom_phy_calibration { > u32 reg_offset; > u32 cfg_value; > diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c > b/drivers/phy/phy-qcom-ufs-qmp-20nm.c > new file mode 100644 > index 000..8332f96 > --- /dev/null > +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c > @@ -0,0 +1,257 @@ > +/* > + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 and > + * only version 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include "phy-qcom-ufs-qmp-20nm.h" > + > +#define UFS_PHY_NAME "ufs_phy_qmp_20nm" > + > +static > +int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy > *ufs_qcom_phy, > + bool is_rate_B) > +{ > + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; > + int tbl_size_A, tbl_size_B; > + u8 major = ufs_qcom_phy->host_ctrl_rev_major; > + u16 minor = ufs_qcom_phy->host_ctrl_rev_minor; > + u16 step = ufs_qcom_phy->host_ctrl_rev_step; > + int err; > + > + if ((major == 0x1) && (minor == 0x002) && (step == 0x)) { > + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); > + tbl_A = phy_cal_table_rate_A_1_2_0; > + } else if ((major == 0x1) && (minor == 0x003) && (step == 0x)) > { > + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); > + tbl_A = phy_cal_table_rate_A_1_3_0; > + } else { > + dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, > no calibration values\n", > + __func__); > + err = -ENODEV; > + goto out; > + } > + > + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); > + tbl_B = phy_cal_table_rate_B; > + > + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, > + tbl_B, tbl_size_B, > is_rate_B); > + > +
Re: [PATCH v7 2/5] phy: qcom-ufs: add support for 20nm phy
Reviewed-by: Dov Levenglick d...@codeaurora.org This change adds a support for a 20nm qcom-ufs phy that is required in platforms that use ufs-qcom controller. Signed-off-by: Yaniv Gardi yga...@codeaurora.org --- drivers/phy/Makefile| 1 + drivers/phy/phy-qcom-ufs-i.h| 43 +- drivers/phy/phy-qcom-ufs-qmp-20nm.c | 257 drivers/phy/phy-qcom-ufs-qmp-20nm.h | 235 + include/linux/phy/phy-qcom-ufs.h| 59 + 5 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.c create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.h create mode 100644 include/linux/phy/phy-qcom-ufs.h diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 335965d..781b2fa 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -35,3 +35,4 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_STIH407_USB)+= phy-stih407-usb.o obj-$(CONFIG_PHY_STIH41X_USB)+= phy-stih41x-usb.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h index dac200f..591a391 100644 --- a/drivers/phy/phy-qcom-ufs-i.h +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -15,15 +15,56 @@ #ifndef UFS_QCOM_PHY_I_H_ #define UFS_QCOM_PHY_I_H_ +#include linux/module.h #include linux/clk.h +#include linux/regulator/consumer.h #include linux/slab.h -#include linux/phy/phy.h +#include linux/phy/phy-qcom-ufs.h #include linux/platform_device.h #include linux/io.h #include linux/delay.h +#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ +({ \ + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ + might_sleep_if(timeout_us); \ + for (;;) { \ + (val) = readl(addr); \ + if (cond) \ + break; \ + if (timeout_us ktime_compare(ktime_get(), timeout) 0) { \ + (val) = readl(addr); \ + break; \ + } \ + if (sleep_us) \ + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + +#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ + { \ + .reg_offset = reg, \ + .cfg_value = val, \ + } + #define UFS_QCOM_PHY_NAME_LEN30 +enum { + MASK_SERDES_START = 0x1, + MASK_PCS_READY = 0x1, +}; + +enum { + OFFSET_SERDES_START = 0x0, +}; + +struct ufs_qcom_phy_stored_attributes { + u32 att; + u32 value; +}; + + struct ufs_qcom_phy_calibration { u32 reg_offset; u32 cfg_value; diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c new file mode 100644 index 000..8332f96 --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include phy-qcom-ufs-qmp-20nm.h + +#define UFS_PHY_NAME ufs_phy_qmp_20nm + +static +int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + bool is_rate_B) +{ + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + u8 major = ufs_qcom_phy-host_ctrl_rev_major; + u16 minor = ufs_qcom_phy-host_ctrl_rev_minor; + u16 step = ufs_qcom_phy-host_ctrl_rev_step; + int err; + + if ((major == 0x1) (minor == 0x002) (step == 0x)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); + tbl_A = phy_cal_table_rate_A_1_2_0; + } else if ((major == 0x1) (minor == 0x003) (step == 0x)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); + tbl_A = phy_cal_table_rate_A_1_3_0; + } else { + dev_err(ufs_qcom_phy-dev, %s: Unknown UFS-PHY version, no calibration values\n, + __func__); + err = -ENODEV; + goto out; + } + + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + tbl_B = phy_cal_table_rate_B; + + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, + tbl_B, tbl_size_B,
Re: [PATCH v7 2/5] phy: qcom-ufs: add support for 20nm phy
Reviewed-by: Dov Levenglick d...@codeaurora.org This change adds a support for a 20nm qcom-ufs phy that is required in platforms that use ufs-qcom controller. Signed-off-by: Yaniv Gardi yga...@codeaurora.org --- drivers/phy/Makefile| 1 + drivers/phy/phy-qcom-ufs-i.h| 43 +- drivers/phy/phy-qcom-ufs-qmp-20nm.c | 257 drivers/phy/phy-qcom-ufs-qmp-20nm.h | 235 + include/linux/phy/phy-qcom-ufs.h| 59 + 5 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.c create mode 100644 drivers/phy/phy-qcom-ufs-qmp-20nm.h create mode 100644 include/linux/phy/phy-qcom-ufs.h diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 335965d..781b2fa 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -35,3 +35,4 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_STIH407_USB)+= phy-stih407-usb.o obj-$(CONFIG_PHY_STIH41X_USB)+= phy-stih41x-usb.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h index dac200f..591a391 100644 --- a/drivers/phy/phy-qcom-ufs-i.h +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -15,15 +15,56 @@ #ifndef UFS_QCOM_PHY_I_H_ #define UFS_QCOM_PHY_I_H_ +#include linux/module.h #include linux/clk.h +#include linux/regulator/consumer.h #include linux/slab.h -#include linux/phy/phy.h +#include linux/phy/phy-qcom-ufs.h #include linux/platform_device.h #include linux/io.h #include linux/delay.h +#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ +({ \ + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ + might_sleep_if(timeout_us); \ + for (;;) { \ + (val) = readl(addr); \ + if (cond) \ + break; \ + if (timeout_us ktime_compare(ktime_get(), timeout) 0) { \ + (val) = readl(addr); \ + break; \ + } \ + if (sleep_us) \ + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + +#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ + { \ + .reg_offset = reg, \ + .cfg_value = val, \ + } + #define UFS_QCOM_PHY_NAME_LEN30 +enum { + MASK_SERDES_START = 0x1, + MASK_PCS_READY = 0x1, +}; + +enum { + OFFSET_SERDES_START = 0x0, +}; + +struct ufs_qcom_phy_stored_attributes { + u32 att; + u32 value; +}; + + struct ufs_qcom_phy_calibration { u32 reg_offset; u32 cfg_value; diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c new file mode 100644 index 000..8332f96 --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include phy-qcom-ufs-qmp-20nm.h + +#define UFS_PHY_NAME ufs_phy_qmp_20nm + +static +int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + bool is_rate_B) +{ + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + u8 major = ufs_qcom_phy-host_ctrl_rev_major; + u16 minor = ufs_qcom_phy-host_ctrl_rev_minor; + u16 step = ufs_qcom_phy-host_ctrl_rev_step; + int err; + + if ((major == 0x1) (minor == 0x002) (step == 0x)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); + tbl_A = phy_cal_table_rate_A_1_2_0; + } else if ((major == 0x1) (minor == 0x003) (step == 0x)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); + tbl_A = phy_cal_table_rate_A_1_3_0; + } else { + dev_err(ufs_qcom_phy-dev, %s: Unknown UFS-PHY version, no calibration values\n, + __func__); + err = -ENODEV; + goto out; + } + + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + tbl_B = phy_cal_table_rate_B; + + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, + tbl_B, tbl_size_B,