mmc: sdhci-msm: Add clk-rates, DDR, HS400 support
Subsystems (7)
v6 cover mmc: sdhci-msm: Add clk-rates, DDR, HS400 support
Hi,
This is v6 version of the patch series which adds support for MSM8996. Adds HS400 driver support as well.
These are tested on internal msm8996 & db410c HW.
Changes from v5 -> v6 :-
1. Earlier in v5 series DT node was added to get the clk-rates table needed for sdhci-msm driver. But this is removed in this(v6) patch series and instead the clk changes are done in the clk driver as per Rob H comment.
2. Added clk driver changes(patch 1-3) to provide floor rate values of requested clock for sdhc client.
For following boards- apq8084, msm8996, msm8916, msm8974.
3. Other minor patch comments were addressed.
Changes from v4 -> v5 :-
1. Added HS400 sdhci-msm controller specific changes:- (Patch 10, 11, 12)
2. Addressed comment from Adrian on Patch 07 @[3].
3. Addressed comment from Arnd on Patch 03, to directly add clk_table into sdhci_msm_host. [4]
4. Addressed comment from Bjorn to not enforce having clk-rates property in DT for older targets based on discussion at [5]
5. Retained Acks from Adrian on patches (01 & 02 & 06) where there were no changes made while addressing above comments.
Older history:-
This is v4 version of the patch series.
Patches 01, 02, 05 & 06 were Acked-by Adrian.
Changes from v3 -> v4 :-
1. Addressed comments from Adrian on Patch 03, 07, 08.
2. Addressed comments from Bjorn on Patch 03.
3. Added clk-rate support for sdhc DT nodes to all MSM platforms. in Pacth 04.
4. Rebased on next branch of Ulf.
Changes from v2 -> v3 :-
1. Addded Patch 01 based on Bjorn comment[2] -
This fixes/unrolls the poor coding style of read/writes of registers from base sdhci-msm driver.
2. Fixed/unrolled poor style of reads/writes of registers in Patch 02, based on Bjorn comment[2]. Also changed name of flag from use_updated_dll_reset -> use_14lpp_dll_reset.
Changes from v1->v2 :-
1. Removed patch 06 & 08 from v1 patch series[1] (which were introducing unnecessary quirks). Instead have implemented __sdhci_msm_set_clock version of sdhci_set_clock in sdhci_msm driver itself in patch 07 of this patch series.
2. Enabled extra quirk (SDHCI_QUIRK2_PRESET_VALUE_BROKEN) in patch 05 of this patch series.
Description of patches :-
This patchset adds clk-rates & other required changes to upstream sdhci-msm driver from codeaurora tree.
It has been tested on a db410c Dragonboard and msm8996 based platform.
Patch 0001-0003- Adds support in qcom clk driver to return floor value of requested clock rate instead of ceil rate for sdhc clients.
Patch 0004- Adds updated dll sequence for newer controllers which has minor_version >= 0x42. This is required for msm8996.
MSM controller HW recommendation is to use the base MCI clock and directly control this MCI clock at GCC in order to change the clk-rate.
Patches 06-08 bring in required change for this to sdhci-msm.
MSM controller would require 2x clock rate from source for DDR bus speed modes. Patch 09 adds this support.
Patch 0010- adds DDR support in DT for sdhc1 of msm8916.
Patches 0011-0014- Adds HS400 support to sdhci-msm.
[1]:- http://www.spinics.net/lists/linux-mmc/msg38467.html
[2]:- http://www.spinics.net/lists/linux-mmc/msg38578.html
[3]:- https://patchwork.kernel.org/patch/9289345/
[4]:- https://www.spinics.net/lists/linux-mmc/msg39107.html
[5]:- http://www.spinics.net/lists/linux-mmc/msg38749.html
[6]:- https://patchwork.kernel.org/patch/9297381/
Rajendra Nayak (3):
clk: Add clk_hw_get_clk() helper API to be used by clk providers
clk: qcom: Add rcg ops to return floor value closest to the requested
rate
clk: qcom: Move all sdcc rcgs to use clk_rcg2_floor_ops
Ritesh Harjani (9):
mmc: sdhci-msm: Change poor style writel/readl of registers
mmc: sdhci-msm: Add get_min_clock() and get_max_clock() callback
mmc: sdhci-msm: Enable few quirks
mmc: sdhci-msm: Implement set_clock callback for sdhci-msm
mmc: sdhci-msm: Add clock changes for DDR mode.
arm64: dts: qcom: msm8916: Add ddr support to sdhc1
mmc: sdhci-msm: Save the calculated tuning phase
mmc: sdhci-msm: Add calibration tuning for CDCLP533 circuit
sdhci: sdhci-msm: update dll configuration
Venkat Gopalakrishnan (2):
mmc: sdhci-msm: Update DLL reset sequence
mmc: sdhci-msm: Add HS400 platform support
arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 + drivers/clk/clk.c | 6 + drivers/clk/qcom/clk-rcg.h | 1 + drivers/clk/qcom/clk-rcg2.c | 75 +++- drivers/clk/qcom/common.c | 26 ++ drivers/clk/qcom/common.h | 2 + drivers/clk/qcom/gcc-apq8084.c | 8 +- drivers/clk/qcom/gcc-msm8916.c | 4 +- drivers/clk/qcom/gcc-msm8974.c | 8 +- drivers/clk/qcom/gcc-msm8996.c | 8 +- drivers/mmc/host/sdhci-msm.c | 650 ++++++++++++++++++++++++++++++++-- include/linux/clk-provider.h | 1 + 12 files changed, 733 insertions(+), 57 deletions(-)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
A message that is not in the archive (sent off-list or not yet received): 1478517877-23733-1-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
PATCH v6 1/14 clk: Add clk_hw_get_clk() helper API to be used by clk providers
From: Rajendra Nayak <[email protected]>
Add a helper API that will allow clk providers to turn their clk_hw structures into struct clk pointer.
--- drivers/clk/clk.c | 6 ++++++ include/linux/clk-provider.h | 1 + 2 files changed, 7 insertions(+)
drivers/clk/clk.c +6 -0
@@ -186,6 +186,12 @@ const char *clk_hw_get_name(const struct clk_hw *hw) }EXPORT_SYMBOL_GPL (clk_hw_get_name); +struct clk *clk_hw_get_clk (const struct clk_hw *hw) +{ +return hw->clk; +} +EXPORT_SYMBOL_GPL (clk_hw_get_clk); +struct clk_hw *__clk_get_hw (struct clk *clk) {return !clk ?NULL : clk->core->hw;
include/linux/clk-provider.h +1 -0
@@ -729,6 +729,7 @@ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,/* helper functions */ const char *__clk_get_name (const struct clk *clk);const char *clk_hw_get_name (const struct clk_hw *hw); +struct clk *clk_hw_get_clk (const struct clk_hw *hw);struct clk_hw *__clk_get_hw (struct clk *clk);unsigned int clk_hw_get_num_parents (const struct clk_hw *hw);struct clk_hw *clk_hw_get_parent (const struct clk_hw *hw);
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 1478517877-23733-2-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
Re: [PATCH v6 01/14] clk: Add clk_hw_get_clk() helper API to be used by clk providers
Quoted 6 lines · Ritesh Harjani
From: Rajendra Nayak <[email protected]>
Add a helper API that will allow clk providers to turn their
clk_hwstructures into struct clk pointer.Signed-off-by Rajendra Nayak <[email protected]>
Please drop this patch, it isn't needed here anyway, besides it needs to be reworked as already discussed.
Quoted 35 lines
--- drivers/clk/clk.c | 6 ++++++ include/linux/clk-provider.h | 1 + 2 files changed, 7 insertions(+)drivers/clk/clk.c +6
-0@@ -186,6 +186,12 @@ const char *clk_hw_get_name(const struct clk_hw *hw) }EXPORT_SYMBOL_GPL (clk_hw_get_name); +struct clk *clk_hw_get_clk (const struct clk_hw *hw) +{ +return hw->clk; +} +EXPORT_SYMBOL_GPL (clk_hw_get_clk); +struct clk_hw *__clk_get_hw (struct clk *clk) {return !clk ?NULL : clk->core->hw;include/linux/clk-provider.h +1
-0@@ -729,6 +729,7 @@ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,/* helper functions */ const char *__clk_get_name (const struct clk *clk);const char *clk_hw_get_name (const struct clk_hw *hw); +struct clk *clk_hw_get_clk (const struct clk_hw *hw);struct clk_hw *__clk_get_hw (struct clk *clk);unsigned int clk_hw_get_num_parents (const struct clk_hw *hw);struct clk_hw *clk_hw_get_parent (const struct clk_hw *hw);
Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v6 01/14] clk: Add clk_hw_get_clk() helper API to be used by clk providers
Hi,
Quoted 5 lines · Rajendra Nayak
Quoted 2 lines · Ritesh Harjani
From: Rajendra Nayak <[email protected]>
Quoted 7 lines
Quoted 4 lines
Add a helper API that will allow clk providers to turn their
clk_hwstructures into struct clk pointer.Signed-off-by Rajendra Nayak <[email protected]>Please drop this patch, it isn't needed here anyway, besides it needs to be reworked as already discussed.
Ok, sure.
Quoted 37 lines
Quoted 36 lines
--- drivers/clk/clk.c | 6 ++++++ include/linux/clk-provider.h | 1 + 2 files changed, 7 insertions(+)drivers/clk/clk.c +6
-0@@ -186,6 +186,12 @@ const char *clk_hw_get_name(const struct clk_hw *hw) }EXPORT_SYMBOL_GPL (clk_hw_get_name); +struct clk *clk_hw_get_clk (const struct clk_hw *hw) +{ +return hw->clk; +} +EXPORT_SYMBOL_GPL (clk_hw_get_clk); +struct clk_hw *__clk_get_hw (struct clk *clk) {return !clk ?NULL : clk->core->hw;include/linux/clk-provider.h +1
-0@@ -729,6 +729,7 @@ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,/* helper functions */ const char *__clk_get_name (const struct clk *clk);const char *clk_hw_get_name (const struct clk_hw *hw); +struct clk *clk_hw_get_clk (const struct clk_hw *hw);struct clk_hw *__clk_get_hw (struct clk *clk);unsigned int clk_hw_get_num_parents (const struct clk_hw *hw);struct clk_hw *clk_hw_get_parent (const struct clk_hw *hw);
Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v6 4/14 mmc: sdhci-msm: Change poor style writel/readl of registers
In reply to a message not in the archiveThis patch changes the poor style of writel/readl registers into more readable format. Also to avoid mixed style format of readl/writel in sdhci-msm driver.
--- drivers/mmc/host/sdhci-msm.c | 54 ++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 22 deletions(-)
drivers/mmc/host/sdhci-msm.c +32 -22
@@ -137,8 +137,9 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - |CORE_CK_OUT_EN ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CK_OUT_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */ rc =msm_dll_poll_ck_out_en (host,1 );
@@ -305,6 +306,7 @@ static int msm_init_cm_dll(struct sdhci_host *host)struct mmc_host *mmc = host->mmc;int wait_cnt =50 ;unsigned long flags; +u32 config =0 ;spin_lock_irqsave (&host->lock, flags);
@@ -313,33 +315,40 @@ static int msm_init_cm_dll(struct sdhci_host *host)* tuning is in progress. Keeping PWRSAVE ON may * turn off the clock. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ) - & ~CORE_CLK_PWRSAVE ), host->ioaddr +CORE_VENDOR_SPEC ); + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config &= ~CORE_CLK_PWRSAVE ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC );/* Write 1 to DLL_RST bit of DLL_CONFIG register */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - |CORE_DLL_RST ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_DLL_RST ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Write 1 to DLL_PDN bit of DLL_CONFIG register */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - |CORE_DLL_PDN ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_DLL_PDN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );msm_cm_dll_set_freq (host);/* Write 0 to DLL_RST bit of DLL_CONFIG register */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - & ~CORE_DLL_RST ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config &= ~CORE_DLL_RST ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Write 0 to DLL_PDN bit of DLL_CONFIG register */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - & ~CORE_DLL_PDN ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config &= ~CORE_DLL_PDN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Set DLL_EN bit to 1. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - |CORE_DLL_EN ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_DLL_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Set CK_OUT_EN bit to 1. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - |CORE_CK_OUT_EN ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CK_OUT_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */ while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
@@ -536,7 +545,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)struct resource *core_memres;int ret;u16 host_version, core_minor; -u32 core_version, caps; +u32 core_version, config;u8 core_major; host =sdhci_pltfm_init (pdev, &sdhci_msm_pdata,sizeof (*msm_host));
@@ -605,8 +614,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) }/* Reset the core and Enable SDHC mode */ -writel_relaxed (readl_relaxed (msm_host->core_mem +CORE_POWER ) | -CORE_SW_RST , msm_host->core_mem +CORE_POWER ); + config =readl_relaxed (msm_host->core_mem +CORE_POWER ); + config |=CORE_SW_RST ; +writel_relaxed (config, msm_host->core_mem +CORE_POWER );/* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */ usleep_range (1000 ,5000 );
@@ -636,9 +646,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)* controller versions and must be explicitly enabled. */ if (core_major >=1 && core_minor !=0x11 && core_minor !=0x12 ) { - caps =readl_relaxed (host->ioaddr +SDHCI_CAPABILITIES ); - caps |=SDHCI_CAN_VDD_300 |SDHCI_CAN_DO_8BIT ; -writel_relaxed (caps, host->ioaddr + + config =readl_relaxed (host->ioaddr +SDHCI_CAPABILITIES ); + config |=SDHCI_CAN_VDD_300 |SDHCI_CAN_DO_8BIT ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC_CAPABILITIES0 ); }
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v6 04/14] mmc: sdhci-msm: Change poor style writel/readl of registers
Quoted 17 lines · Ritesh Harjani
drivers/mmc/host/sdhci-msm.c +3
-2@@ -137,8 +137,9 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - |CORE_CK_OUT_EN ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CK_OUT_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */ rc =msm_dll_poll_ck_out_en (host,1 );
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 309
Quoted 4 lines
drivers/mmc/host/sdhci-msm.c +1
-0@@ -305,6 +306,7 @@ static int msm_init_cm_dll(struct sdhci_host *host)struct mmc_host *mmc = host->mmc;int wait_cnt =50 ;unsigned long flags; +u32 config =0 ;
It needs to be initialized?
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 318
Quoted 10 lines
drivers/mmc/host/sdhci-msm.c +1
-2spin_lock_irqsave (&host->lock, flags);@@ -313,33 +315,40 @@ static int msm_init_cm_dll(struct sdhci_host *host)* tuning is in progress. Keeping PWRSAVE ON may * turn off the clock. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ) - & ~CORE_CLK_PWRSAVE ), host->ioaddr +CORE_VENDOR_SPEC ); + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC );
It's written here unconditionally though?
Quoted 1 line
drivers/mmc/host/sdhci-msm.c +1
-0+ config &= ~CORE_CLK_PWRSAVE ;
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v6 04/14] mmc: sdhci-msm: Change poor style writel/readl of registers
Hi Stephen,
Quoted 15 lines · Stephen Boyd
Quoted 14 lines · Ritesh Harjani
drivers/mmc/host/sdhci-msm.c +3
-2@@ -137,8 +137,9 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ) - |CORE_CK_OUT_EN ), host->ioaddr +CORE_DLL_CONFIG ); + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CK_OUT_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );
Quoted 9 lines
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 309
Quoted 7 lines
drivers/mmc/host/sdhci-msm.c +1
-0/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */ rc =msm_dll_poll_ck_out_en (host,1 );@@ -305,6 +306,7 @@ static int msm_init_cm_dll(struct sdhci_host *host)struct mmc_host *mmc = host->mmc;int wait_cnt =50 ;unsigned long flags; +u32 config =0 ;It needs to be initialized?
No, will make it uninitialized.
Quoted 16 lines
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 318
Quoted 11 lines
drivers/mmc/host/sdhci-msm.c +1
-2spin_lock_irqsave (&host->lock, flags);@@ -313,33 +315,40 @@ static int msm_init_cm_dll(struct sdhci_host *host)* tuning is in progress. Keeping PWRSAVE ON may * turn off the clock. */ -writel_relaxed ((readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ) - & ~CORE_CLK_PWRSAVE ), host->ioaddr +CORE_VENDOR_SPEC ); + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC );It's written here unconditionally though?
Quoted 1 line
drivers/mmc/host/sdhci-msm.c +1
-0+ config &= ~CORE_CLK_PWRSAVE ;
Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v6 10/14 arm64: dts: qcom: msm8916: Add ddr support to sdhc1
In reply to a message not in the archiveThis adds mmc-ddr-1_8v support to DT for sdhc1 of msm8916.
--- arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 + 1 file changed, 1 insertion(+)
arch/arm64/boot/dts/qcom/msm8916.dtsi +1 -0
@@ -514,6 +514,7 @@ clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>; clock-names = "core", "iface"; + mmc-ddr-1_8v; bus-width = <8>; non-removable; status = "disabled";
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v6 12/14 mmc: sdhci-msm: Save the calculated tuning phase
In reply to a message not in the archiveSave the tuning phase once the tuning is performed. This phase value will be used while calibrating DLL for HS400 mode.
--- drivers/mmc/host/sdhci-msm.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/mmc/host/sdhci-msm.c +10 -0
@@ -74,6 +74,7 @@#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c +#define INVALID_TUNING_PHASE -1#define TCXO_FREQ 19200000#define SDHCI_MSM_MIN_CLOCK 400000#define CORE_FREQ_100MHZ (100 * 1000 * 1000)
@@ -95,6 +96,7 @@ struct sdhci_msm_host {bool use_14lpp_dll_reset;bool tuning_done;bool calibration_done; +u8 saved_tuning_phase; };/* Platform specific tuning */
@@ -134,6 +136,9 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)u32 config;struct mmc_host *mmc = host->mmc; +if (phase >0xf ) +return -EINVAL ; +spin_lock_irqsave (&host->lock, flags); config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG );
@@ -431,6 +436,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)int rc;struct mmc_host *mmc = host->mmc;struct mmc_ios ios = host->mmc->ios; +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);/* * Tuning is required for SDR104, HS200 and HS400 cards and
@@ -455,6 +462,7 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)if (rc)return rc; + msm_host->saved_tuning_phase = phase; rc =mmc_send_tuning (mmc, opcode,NULL );if (!rc) {/* Tuning is successful at this tuning point */
@@ -826,6 +834,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)sdhci_get_of_property (pdev); + msm_host->saved_tuning_phase =INVALID_TUNING_PHASE ; +/* Setup SDCC bus voter clock. */ msm_host->bus_clk =devm_clk_get (&pdev->dev,"bus" );if (!IS_ERR (msm_host->bus_clk)) {
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project. -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v6 12/14] mmc: sdhci-msm: Save the calculated tuning phase
Quoted 5 lines · Ritesh Harjani
Save the tuning phase once the tuning is performed. This phase value will be used while calibrating DLL for HS400 mode.
Signed-off-by Ritesh Harjani <[email protected]>
Quoted 61 lines
--- drivers/mmc/host/sdhci-msm.c | 10 ++++++++++ 1 file changed, 10 insertions(+)drivers/mmc/host/sdhci-msm.c +10
-0@@ -74,6 +74,7 @@#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c +#define INVALID_TUNING_PHASE -1#define TCXO_FREQ 19200000#define SDHCI_MSM_MIN_CLOCK 400000#define CORE_FREQ_100MHZ (100 * 1000 * 1000)@@ -95,6 +96,7 @@ struct sdhci_msm_host {bool use_14lpp_dll_reset;bool tuning_done;bool calibration_done; +u8 saved_tuning_phase; };/* Platform specific tuning */ @@ -134,6 +136,9 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)u32 config;struct mmc_host *mmc = host->mmc; +if (phase >0xf ) +return -EINVAL ; +spin_lock_irqsave (&host->lock, flags); config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG );@@ -431,6 +436,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)int rc;struct mmc_host *mmc = host->mmc;struct mmc_ios ios = host->mmc->ios; +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);/* * Tuning is required for SDR104, HS200 and HS400 cards and @@ -455,6 +462,7 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)if (rc)return rc; + msm_host->saved_tuning_phase = phase; rc =mmc_send_tuning (mmc, opcode,NULL );if (!rc) {/* Tuning is successful at this tuning point */ @@ -826,6 +834,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)sdhci_get_of_property (pdev); + msm_host->saved_tuning_phase =INVALID_TUNING_PHASE ; +/* Setup SDCC bus voter clock. */ msm_host->bus_clk =devm_clk_get (&pdev->dev,"bus" );if (!IS_ERR (msm_host->bus_clk)) {
PATCH v6 2/14 clk: qcom: Add rcg ops to return floor value closest to the requested rate
In reply to Ritesh HarjaniFrom: Rajendra Nayak <[email protected]>
The default behaviour with clk_rcg2_ops is for the clk_round_rate()/clk_set_rate() to return/set a ceil clock rate closest to the requested rate by looking up the corresponding frequency table.
However, we do have some instances (mainly sdcc on various platforms) of clients expecting a clk_set_rate() to set a floor value instead. Add a new clk_rcg2_floor_ops to handle this for such specific rcg instances
--- drivers/clk/qcom/clk-rcg.h | 1 + drivers/clk/qcom/clk-rcg2.c | 75 +++++++++++++++++++++++++++++++++++++++------ drivers/clk/qcom/common.c | 26 ++++++++++++++++ drivers/clk/qcom/common.h | 2 ++ 4 files changed, 95 insertions(+), 9 deletions(-)
drivers/clk/qcom/clk-rcg.h +1 -0
@@ -173,6 +173,7 @@ struct clk_rcg2 {#define to_clk_rcg2 (_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)extern const struct clk_ops clk_rcg2_ops; +extern const struct clk_ops clk_rcg2_floor_ops;extern const struct clk_ops clk_rcg2_shared_ops;extern const struct clk_ops clk_edp_pixel_ops;extern const struct clk_ops clk_byte_ops;
drivers/clk/qcom/clk-rcg2.c +66 -9
132 lines not on this page · raw message
drivers/clk/qcom/common.c +26 -0
@@ -46,6 +46,32 @@ struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) }EXPORT_SYMBOL_GPL (qcom_find_freq); +const +struct freq_tbl *qcom_find_freq_floor (const struct freq_tbl *f, +unsigned long rate) +{ +int size =0 ; + +if (!f) +return NULL ; + +/* +* The freq table has entries in the ascending order of frequencies +* To find the floor for a given frequency, we need to do a reverse +* lookup of the table +*/ +for (; f->freq; f++, size++) + ; + +for (f--; size; f--, size--) +if (rate >= f->freq) +return f; + +/* could not find any rates lower than *rate* */ +return NULL ; +} +EXPORT_SYMBOL_GPL (qcom_find_freq_floor); +int qcom_find_src_index (struct clk_hw *hw,const struct parent_map *map,u8 src) {int i, num_parents =clk_hw_get_num_parents (hw);
drivers/clk/qcom/common.h +2 -0
@@ -34,6 +34,8 @@ struct qcom_cc_desc {extern const struct freq_tbl *qcom_find_freq (const struct freq_tbl *f,unsigned long rate); +extern const struct freq_tbl *qcom_find_freq_floor (const struct freq_tbl *f, +unsigned long rate);extern int qcom_find_src_index (struct clk_hw *hw,const struct parent_map *map,u8 src);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
A message that is not in the archive (sent off-list or not yet received): 1478517877-23733-3-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
kbuild test robot
build botRe: [PATCH v6 02/14] clk: qcom: Add rcg ops to return floor value closest to the requested rate
reproduce:
Hi Rajendra,
[auto build test WARNING on ulf.hansson-mmc/next]
[also build test WARNING on v4.9-rc4 next-20161028]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Ritesh-Harjani/mmc-sdhci-msm-Add-clk-rates-DDR-HS400-support/20161107-203031 base: https://git.linaro.org/people/ulf.hansson/mmc next config: i386-allmodconfig (attached as .config) compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce: # save the attached .config to linux build tree make ARCH=i386
All warnings (new ones prefixed by >>):
drivers/clk/qcom/clk-rcg2.c: In function '_freq_tbl_determine_rate':
>> drivers/clk/qcom/clk-rcg2.c:192:2: warning: switch condition has boolean value [-Wswitch-bool]
switch (match) {
^~~~~~
drivers/clk/qcom/clk-rcg2.c: In function '__clk_rcg2_set_rate':
drivers/clk/qcom/clk-rcg2.c:297:2: warning: switch condition has boolean value [-Wswitch-bool]
switch (match) {
^~~~~~coccinelle warnings: (new ones prefixed by >>)
>> drivers/clk/qcom/clk-rcg2.c:306:2-3: Unneeded semicolon
drivers/clk/qcom/clk-rcg2.c:201:2-3: Unneeded semicolon
Please review and possibly fold the followup patch.
vim +192 drivers/clk/qcom/clk-rcg2.c
186 {
187 unsigned long clk_flags, rate = req->rate;
188 struct clk_hw *p;
189 struct clk_rcg2 *rcg = to_clk_rcg2(hw);
190 int index;
191
> 192 switch (match) {
193 case FLOOR:
194 f = qcom_find_freq_floor(f, rate);
195 break;
196 case CEIL:
197 f = qcom_find_freq(f, rate);
198 break;
199 default:
200 return -EINVAL;
201 };
202
203 if (!f)
204 return -EINVAL;
205
206 index = qcom_find_src_index(hw, rcg->parent_map, f->src);
207 if (index < 0)
208 return index;
209
210 clk_flags = clk_hw_get_flags(hw);
211 p = clk_hw_get_parent_by_index(hw, index);
212 if (clk_flags & CLK_SET_RATE_PARENT) {
213 if (f->pre_div) {
214 rate /= 2;
215 rate *= f->pre_div + 1;
216 }
217
218 if (f->n) {
219 u64 tmp = rate;
220 tmp = tmp * f->n;
221 do_div(tmp, f->m);
222 rate = tmp;
223 }
224 } else {
225 rate = clk_hw_get_rate(p);
226 }
227 req->best_parent_hw = p;
228 req->best_parent_rate = rate;
229 req->rate = f->freq;
230
231 return 0;
232 }
233
234 static int clk_rcg2_determine_rate(struct clk_hw *hw,
235 struct clk_rate_request *req)
236 {
237 struct clk_rcg2 *rcg = to_clk_rcg2(hw);
238
239 return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, CEIL);
240 }
241
242 static int clk_rcg2_determine_floor_rate(struct clk_hw *hw,
243 struct clk_rate_request *req)
244 {
245 struct clk_rcg2 *rcg = to_clk_rcg2(hw);
246
247 return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, FLOOR);
248 }
249
250 static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
251 {
252 u32 cfg, mask;
253 struct clk_hw *hw = &rcg->clkr.hw;
254 int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
255
256 if (index < 0)
257 return index;
258
259 if (rcg->mnd_width && f->n) {
260 mask = BIT(rcg->mnd_width) - 1;
261 ret = regmap_update_bits(rcg->clkr.regmap,
262 rcg->cmd_rcgr + M_REG, mask, f->m);
263 if (ret)
264 return ret;
265
266 ret = regmap_update_bits(rcg->clkr.regmap,
267 rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
268 if (ret)
269 return ret;
270
271 ret = regmap_update_bits(rcg->clkr.regmap,
272 rcg->cmd_rcgr + D_REG, mask, ~f->n);
273 if (ret)
274 return ret;
275 }
276
277 mask = BIT(rcg->hid_width) - 1;
278 mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
279 cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
280 cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
281 if (rcg->mnd_width && f->n && (f->m != f->n))
282 cfg |= CFG_MODE_DUAL_EDGE;
283 ret = regmap_update_bits(rcg->clkr.regmap,
284 rcg->cmd_rcgr + CFG_REG, mask, cfg);
285 if (ret)
286 return ret;
287
288 return update_config(rcg);
289 }
290
291 static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
292 bool match)
293 {
294 struct clk_rcg2 *rcg = to_clk_rcg2(hw);
295 const struct freq_tbl *f;
296
297 switch (match) {
298 case FLOOR:
299 f = qcom_find_freq_floor(rcg->freq_tbl, rate);
300 break;
301 case CEIL:
302 f = qcom_find_freq(rcg->freq_tbl, rate);
303 break;
304 default:
305 return -EINVAL;
> 306 }; 307
308 if (!f)
309 return -EINVAL;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Re: [PATCH v6 02/14] clk: qcom: Add rcg ops to return floor value closest to the requested rate
In reply to a message not in the archiveQuoted 17 lines · Ritesh Harjani
drivers/clk/qcom/clk-rcg.h +1
-0@@ -173,6 +173,7 @@ struct clk_rcg2 {#define to_clk_rcg2 (_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)extern const struct clk_ops clk_rcg2_ops; +extern const struct clk_ops clk_rcg2_floor_ops;extern const struct clk_ops clk_rcg2_shared_ops;extern const struct clk_ops clk_edp_pixel_ops;extern const struct clk_ops clk_byte_ops;drivers/clk/qcom/clk-rcg2.c +0
-0
drivers/clk/qcom/clk-rcg2.c line 53
Quoted 7 lines
drivers/clk/qcom/clk-rcg2.c +4
-0@@ -47,6 +47,11 @@#define N_REG 0xc#define D_REG 0x10 +enum { +FLOOR , +CEIL , +};
Give it a name.
drivers/clk/qcom/clk-rcg2.c static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) · line 185
Quoted 12 lines
drivers/clk/qcom/clk-rcg2.c +3
-2+static int clk_rcg2_is_enabled (struct clk_hw *hw) {struct clk_rcg2 *rcg =to_clk_rcg2 (hw);@@ -176,15 +181,25 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)return calc_rate (parent_rate, m, n, mode, hid_div); } -static int _freq_tbl_determine_rate (struct clk_hw *hw, -const struct freq_tbl *f,struct clk_rate_request *req) +static int _freq_tbl_determine_rate (struct clk_hw *hw,const struct freq_tbl *f, +struct clk_rate_request *req,bool match)
Use the enum please. Also name it something besides match. policy?
Quoted 26 lines
drivers/clk/qcom/clk-rcg2.c +11
-1{unsigned long clk_flags, rate = req->rate;struct clk_hw *p;struct clk_rcg2 *rcg =to_clk_rcg2 (hw);int index; - f =qcom_find_freq (f, rate); +switch (match) { +case FLOOR : + f =qcom_find_freq_floor (f, rate); +break ; +case CEIL : + f =qcom_find_freq (f, rate); +break ; +default : +return -EINVAL ; + }; +if (!f)return -EINVAL ;drivers/clk/qcom/common.c +0
-0
drivers/clk/qcom/common.c struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) · line 50
Quoted 5 lines
drivers/clk/qcom/common.c +2
-0@@ -46,6 +46,32 @@ struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) }EXPORT_SYMBOL_GPL (qcom_find_freq); +const +struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
We can't put const and struct on the same line?
Quoted 8 lines
drivers/clk/qcom/common.c +8
-0+ unsigned long rate) +{ +int size =0 ; + +if (!f) +return NULL ; + +/*
drivers/clk/qcom/common.c struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) · line 68
Quoted 10 lines
drivers/clk/qcom/common.c +10
-0+* The freq table has entries in the ascending order of frequencies +* To find the floor for a given frequency, we need to do a reverse +* lookup of the table +*/ +for (; f->freq; f++, size++) + ; + +for (f--; size; f--, size--) +if (rate >= f->freq) +return f;
I don't understand why we can't do this while iterating through the table. We shouldn't need to size up the frequency table first.
const struct freq_tbl *best = NULL;
for ( ; f->freq; f++) {
if (rate >= f->freq)
best = f->freq;
else
break;
}
return best;Quoted 6 lines
drivers/clk/qcom/common.c +5
-0+ +/* could not find any rates lower than *rate* */ +return NULL ; +} +EXPORT_SYMBOL_GPL (qcom_find_freq_floor);
Signature · 6 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v6 02/14] clk: qcom: Add rcg ops to return floor value closest to the requested rate
Hi Stephen,
Thanks for the review.
Quoted 21 lines · Stephen Boyd
Quoted 20 lines · Ritesh Harjani
drivers/clk/qcom/clk-rcg.h +1
-0@@ -173,6 +173,7 @@ struct clk_rcg2 {#define to_clk_rcg2 (_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)extern const struct clk_ops clk_rcg2_ops; +extern const struct clk_ops clk_rcg2_floor_ops;extern const struct clk_ops clk_rcg2_shared_ops;extern const struct clk_ops clk_edp_pixel_ops;extern const struct clk_ops clk_byte_ops;drivers/clk/qcom/clk-rcg2.c +0
-0@@ -47,6 +47,11 @@#define N_REG 0xc#define D_REG 0x10
Quoted 6 lines
drivers/clk/qcom/clk-rcg2.c line 53
Quoted 4 lines
drivers/clk/qcom/clk-rcg2.c +4
-0+enum { +FLOOR , +CEIL , +};Give it a name.
Yes, sure. I will keep it as freq_policy.
Quoted 9 lines
Quoted 9 lines
drivers/clk/qcom/clk-rcg2.c +1
-0+static int clk_rcg2_is_enabled (struct clk_hw *hw) {struct clk_rcg2 *rcg =to_clk_rcg2 (hw);@@ -176,15 +181,25 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)return calc_rate (parent_rate, m, n, mode, hid_div); }
Quoted 7 lines
drivers/clk/qcom/clk-rcg2.c static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) · line 185
Quoted 4 lines
drivers/clk/qcom/clk-rcg2.c +2
-2-static int _freq_tbl_determine_rate (struct clk_hw *hw, -const struct freq_tbl *f,struct clk_rate_request *req) +static int _freq_tbl_determine_rate (struct clk_hw *hw,const struct freq_tbl *f, +struct clk_rate_request *req,bool match)Use the enum please. Also name it something besides match. policy?
Sure. (freq_policy)
Quoted 30 lines
Quoted 30 lines
drivers/clk/qcom/clk-rcg2.c +11
-1{unsigned long clk_flags, rate = req->rate;struct clk_hw *p;struct clk_rcg2 *rcg =to_clk_rcg2 (hw);int index; - f =qcom_find_freq (f, rate); +switch (match) { +case FLOOR : + f =qcom_find_freq_floor (f, rate); +break ; +case CEIL : + f =qcom_find_freq (f, rate); +break ; +default : +return -EINVAL ; + }; +if (!f)return -EINVAL ;drivers/clk/qcom/common.c +0
-0@@ -46,6 +46,32 @@ struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) }EXPORT_SYMBOL_GPL (qcom_find_freq);
Quoted 4 lines
drivers/clk/qcom/common.c struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) · line 50
Quoted 2 lines
drivers/clk/qcom/common.c +2
-0+const +struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,We can't put const and struct on the same line?
Ok sure.
Quoted 23 lines
Quoted 9 lines
drivers/clk/qcom/common.c +8
-0+ unsigned long rate) +{ +int size =0 ; + +if (!f) +return NULL ; + +/* drivers/clk/qcom/common.c struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate) · line 68
Quoted 10 lines
drivers/clk/qcom/common.c +10
-0+* The freq table has entries in the ascending order of frequencies +* To find the floor for a given frequency, we need to do a reverse +* lookup of the table +*/ +for (; f->freq; f++, size++) + ; + +for (f--; size; f--, size--) +if (rate >= f->freq) +return f;I don't understand why we can't do this while iterating through the table. We shouldn't need to size up the frequency table first.
Quoted 11 lines
const struct freq_tbl *best = NULL;
for ( ; f->freq; f++) {
if (rate >= f->freq)
best = f->freq;
else
break;
}
return best;Yes, will do above change.
Quoted 7 lines
Quoted 6 lines
drivers/clk/qcom/common.c +5
-0+ +/* could not find any rates lower than *rate* */ +return NULL ; +} +EXPORT_SYMBOL_GPL (qcom_find_freq_floor);
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
kbuild test robot
build bot[PATCH] clk: qcom: fix semicolon.cocci warnings
In reply to Ritesh Harjanidrivers/clk/qcom/clk-rcg2.c:306:2-3: Unneeded semicolon drivers/clk/qcom/clk-rcg2.c:201:2-3: Unneeded semicolon
drivers/clk/qcom/clk-rcg2.c:306:2-3: Unneeded semicolon drivers/clk/qcom/clk-rcg2.c:201:2-3: Unneeded semicolon
Remove unneeded semicolon.
Generated by: scripts/coccinelle/misc/semicolon.cocci
---
clk-rcg2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/qcom/clk-rcg2.c +2 -2
@@ -198,7 +198,7 @@ static int _freq_tbl_determine_rate(strubreak ;default :return -EINVAL ; - }; + }if (!f)return -EINVAL ;
@@ -303,7 +303,7 @@ static int __clk_rcg2_set_rate(struct clbreak ;default :return -EINVAL ; - }; + }if (!f)return -EINVAL ;
PATCH v6 3/14 clk: qcom: Move all sdcc rcgs to use clk_rcg2_floor_ops
In reply to Ritesh HarjaniFrom: Rajendra Nayak <[email protected]>
The sdcc driver for msm8996/msm8916/msm8974 and apq8084 expects a clk_set_rate() on the sdcc rcg clk to set a floor value of supported clk rate closest to the requested rate, by looking up the frequency table.
So move all the sdcc rcgs on all these platforms to use the newly introduced clk_rcg2_floor_ops
--- drivers/clk/qcom/gcc-apq8084.c | 8 ++++---- drivers/clk/qcom/gcc-msm8916.c | 4 ++-- drivers/clk/qcom/gcc-msm8974.c | 8 ++++---- drivers/clk/qcom/gcc-msm8996.c | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-)
drivers/clk/qcom/gcc-apq8084.c +4 -4
@@ -1142,7 +1142,7 @@ enum { .name = "sdcc1_apps_clk_src", .parent_names = gcc_xo_gpll0_gpll4, .num_parents = 3, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -1156,7 +1156,7 @@ enum { .name = "sdcc2_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -1170,7 +1170,7 @@ enum { .name = "sdcc3_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -1184,7 +1184,7 @@ enum { .name = "sdcc4_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
drivers/clk/qcom/gcc-msm8916.c +2 -2
@@ -1107,7 +1107,7 @@ enum { .name = "sdcc1_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -1132,7 +1132,7 @@ enum { .name = "sdcc2_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
drivers/clk/qcom/gcc-msm8974.c +4 -4
@@ -872,7 +872,7 @@ enum { .name = "sdcc1_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, };static struct clk_rcg2 sdcc1_apps_clk_src = {
@@ -894,7 +894,7 @@ enum { .name = "sdcc2_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -908,7 +908,7 @@ enum { .name = "sdcc3_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -922,7 +922,7 @@ enum { .name = "sdcc4_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
drivers/clk/qcom/gcc-msm8996.c +4 -4
@@ -460,7 +460,7 @@ enum { .name = "sdcc1_apps_clk_src", .parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div, .num_parents = 4, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -497,7 +497,7 @@ enum { .name = "sdcc2_apps_clk_src", .parent_names = gcc_xo_gpll0_gpll4, .num_parents = 3, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -511,7 +511,7 @@ enum { .name = "sdcc3_apps_clk_src", .parent_names = gcc_xo_gpll0_gpll4, .num_parents = 3, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
@@ -535,7 +535,7 @@ enum { .name = "sdcc4_apps_clk_src", .parent_names = gcc_xo_gpll0, .num_parents = 2, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, }, };
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH v6 5/14 mmc: sdhci-msm: Update DLL reset sequence
In reply to Ritesh HarjaniFrom: Venkat Gopalakrishnan <[email protected]>
SDCC core with minor version >= 0x42 introduced new 14lpp DLL. This has additional requirements in the reset sequence for DLL tuning. Make necessary changes as needed.
Without this patch we see below errors on such SDHC controllers
sdhci_msm 7464900.sdhci: mmc0: DLL failed to LOCK
mmc0: tuning execution failed: -110
--- drivers/mmc/host/sdhci-msm.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
drivers/mmc/host/sdhci-msm.c +48 -0
@@ -58,11 +58,17 @@#define CORE_DLL_CONFIG 0x100#define CORE_DLL_STATUS 0x108 +#define CORE_DLL_CONFIG_2 0x1b4 +#define CORE_FLL_CYCLE_CNT BIT(18) +#define CORE_DLL_CLOCK_DISABLE BIT(21) +#define CORE_VENDOR_SPEC 0x10c#define CORE_CLK_PWRSAVE BIT(1)#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c +#define TCXO_FREQ 19200000 +#define CDR_SELEXT_SHIFT 20#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)#define CMUX_SHIFT_PHASE_SHIFT 24
@@ -76,6 +82,7 @@ struct sdhci_msm_host {struct clk *pclk;/* SDHC peripheral bus clock */ struct clk *bus_clk;/* SDHC bus voter clock */ struct mmc_host *mmc; +bool use_14lpp_dll_reset; };/* Platform specific tuning */
@@ -304,6 +311,8 @@ static inline void msm_cm_dll_set_freq(struct sdhci_host *host)static int msm_init_cm_dll (struct sdhci_host *host) {struct mmc_host *mmc = host->mmc; +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);int wait_cnt =50 ;unsigned long flags;u32 config =0 ;
@@ -319,6 +328,16 @@ static int msm_init_cm_dll(struct sdhci_host *host) config &= ~CORE_CLK_PWRSAVE ;writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); +if (msm_host->use_14lpp_dll_reset) { + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config &= ~CORE_CK_OUT_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); + + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config |=CORE_DLL_CLOCK_DISABLE ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); + } +/* Write 1 to DLL_RST bit of DLL_CONFIG register */ config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); config |=CORE_DLL_RST ;
@@ -330,6 +349,24 @@ static int msm_init_cm_dll(struct sdhci_host *host)writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );msm_cm_dll_set_freq (host); +if (msm_host->use_14lpp_dll_reset) { +u32 mclk_freq =0 ; + +if ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ) + &CORE_FLL_CYCLE_CNT )) + mclk_freq = (u32)((host->clock /TCXO_FREQ ) *8 ); +else + mclk_freq = (u32)((host->clock /TCXO_FREQ ) *4 ); + + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config &= ~(0xFF <<10 ); + config |= mclk_freq <<10 ; + +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); +/* wait for 5us before enabling DLL clock */ +udelay (5 ); + } +/* Write 0 to DLL_RST bit of DLL_CONFIG register */ config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); config &= ~CORE_DLL_RST ;
@@ -340,6 +377,14 @@ static int msm_init_cm_dll(struct sdhci_host *host) config &= ~CORE_DLL_PDN ;writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); +if (msm_host->use_14lpp_dll_reset) { +msm_cm_dll_set_freq (host); +/* Enable the DLL clock */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config &= ~CORE_DLL_CLOCK_DISABLE ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); + } +/* Set DLL_EN bit to 1. */ config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); config |=CORE_DLL_EN ;
@@ -641,6 +686,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)dev_dbg (&pdev->dev,"MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n" , core_version, core_major, core_minor); +if ((core_major ==1 ) && (core_minor >=0x42 )) + msm_host->use_14lpp_dll_reset = true; +/* * Support for some capabilities is not advertised by newer * controller versions and must be explicitly enabled.
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v6 05/14] mmc: sdhci-msm: Update DLL reset sequence
Quoted 9 lines · Ritesh Harjani
drivers/mmc/host/sdhci-msm.c +0
-0@@ -58,11 +58,17 @@#define CORE_DLL_CONFIG 0x100#define CORE_DLL_STATUS 0x108
drivers/mmc/host/sdhci-msm.c line 70
Quoted 10 lines
drivers/mmc/host/sdhci-msm.c +5
-0+#define CORE_DLL_CONFIG_2 0x1b4 +#define CORE_FLL_CYCLE_CNT BIT(18) +#define CORE_DLL_CLOCK_DISABLE BIT(21) +#define CORE_VENDOR_SPEC 0x10c#define CORE_CLK_PWRSAVE BIT(1)#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c +#define TCXO_FREQ 19200000
TCXO_FREQ could change based on the board. For example, IPQ has it as 25 MHz.
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 356
Quoted 13 lines
drivers/mmc/host/sdhci-msm.c +6
-0+#define CDR_SELEXT_SHIFT 20#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)#define CMUX_SHIFT_PHASE_SHIFT 24@@ -330,6 +349,24 @@ static int msm_init_cm_dll(struct sdhci_host *host)writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );msm_cm_dll_set_freq (host); +if (msm_host->use_14lpp_dll_reset) { +u32 mclk_freq =0 ; + +if ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ) + &CORE_FLL_CYCLE_CNT ))
I suggest you grow a local variable.
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 357
Quoted 1 line
drivers/mmc/host/sdhci-msm.c +1
-0+ mclk_freq = (u32)((host->clock /TCXO_FREQ ) *8 );
Is the cast necessary?
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 359
Quoted 2 lines
drivers/mmc/host/sdhci-msm.c +2
-0+else + mclk_freq = (u32)((host->clock /TCXO_FREQ ) *4 );
Ditto
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 366
Quoted 7 lines
drivers/mmc/host/sdhci-msm.c +7
-0+ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config &= ~(0xFF <<10 ); + config |= mclk_freq <<10 ; + +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); +/* wait for 5us before enabling DLL clock */
Usually there's a barrier between writel_relaxed() and delay because we don't know when the writel will be posted out and the delay is there to wait for the operation to happen. Probably should change this to be a writel() instead.
Quoted 22 lines
drivers/mmc/host/sdhci-msm.c +11
-0+udelay (5 ); + } +/* Write 0 to DLL_RST bit of DLL_CONFIG register */ config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); config &= ~CORE_DLL_RST ;@@ -340,6 +377,14 @@ static int msm_init_cm_dll(struct sdhci_host *host) config &= ~CORE_DLL_PDN ;writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); +if (msm_host->use_14lpp_dll_reset) { +msm_cm_dll_set_freq (host); +/* Enable the DLL clock */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config &= ~CORE_DLL_CLOCK_DISABLE ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); + } +/* Set DLL_EN bit to 1. */ config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); config |=CORE_DLL_EN ;
drivers/mmc/host/sdhci-msm.c static int sdhci_msm_probe(struct platform_device *pdev) · line 689
Quoted 4 lines
drivers/mmc/host/sdhci-msm.c +1
-0@@ -641,6 +686,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)dev_dbg (&pdev->dev,"MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n" , core_version, core_major, core_minor); +if ((core_major ==1 ) && (core_minor >=0x42 ))
Why so many parenthesis?
Quoted 3 lines
drivers/mmc/host/sdhci-msm.c +2
-0+ msm_host->use_14lpp_dll_reset = true; +/*
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v6 05/14] mmc: sdhci-msm: Update DLL reset sequence
Quoted 4 lines · CET Stephen Boyd
Quoted 4 lines
drivers/mmc/host/sdhci-msm.c +4
-0+ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config &= ~(0xFF <<10 ); + config |= mclk_freq <<10 ;
Quoted 9 lines
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 366
Quoted 3 lines
drivers/mmc/host/sdhci-msm.c +3
-0+ +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); +/* wait for 5us before enabling DLL clock */ Usually there's a barrier between
writel_relaxed()and delay because we don't know when the writel will be posted out and the delay is there to wait for the operation to happen. Probably should change this to be awritel()instead.
The barrier in writel() is not for posted writes, it is to synchronize with memory accesses *before* the write.
In general, if you want to ensure that a write has made it to the device, you need to read back from the same address (the specific behavior may depend on the bus).
While in general, using the non-relaxed accessors should be the default (and there should be a comment for each *_relaxed access), but I don't think using writel() would let you skip the delay here.
Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v6 05/14] mmc: sdhci-msm: Update DLL reset sequence
In reply to Stephen BoydHi Stephen,
Quoted 17 lines · Stephen Boyd
Quoted 16 lines · Ritesh Harjani
drivers/mmc/host/sdhci-msm.c +4
-0@@ -58,11 +58,17 @@#define CORE_DLL_CONFIG 0x100#define CORE_DLL_STATUS 0x108 +#define CORE_DLL_CONFIG_2 0x1b4 +#define CORE_FLL_CYCLE_CNT BIT(18) +#define CORE_DLL_CLOCK_DISABLE BIT(21) +#define CORE_VENDOR_SPEC 0x10c#define CORE_CLK_PWRSAVE BIT(1)
Quoted 6 lines
drivers/mmc/host/sdhci-msm.c line 70
Quoted 3 lines
drivers/mmc/host/sdhci-msm.c +1
-0#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c +#define TCXO_FREQ 19200000
TCXO_FREQcould change based on the board. For example, IPQ has it as 25 MHz.
Actually not sure of the proper way on how to get this freq in driver today. We may use xo_board clock but, it is not available for all boards except 8996/8916 I guess.
Also, there is no sdhc for IPQ board and for all other boards TCXO_FREQ is same where sdhci-msm driver is used. For that purpose this was defined here for sdhci-msm driver.
Do you think in that case we should keep it this way for now and later change if a need arise to change the TCXO_FREQ ?
Quoted 9 lines
Quoted 9 lines
drivers/mmc/host/sdhci-msm.c +1
-0+#define CDR_SELEXT_SHIFT 20#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)#define CMUX_SHIFT_PHASE_SHIFT 24@@ -330,6 +349,24 @@ static int msm_init_cm_dll(struct sdhci_host *host)writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG );msm_cm_dll_set_freq (host);
Quoted 7 lines
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 356
Quoted 5 lines
drivers/mmc/host/sdhci-msm.c +5
-0+if (msm_host->use_14lpp_dll_reset) { +u32 mclk_freq =0 ; + +if ((readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ) + &CORE_FLL_CYCLE_CNT ))I suggest you grow a local variable.
Ok.
Quoted 4 lines
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 357
Quoted 2 lines
drivers/mmc/host/sdhci-msm.c +1
-0+ mclk_freq = (u32)((host->clock /TCXO_FREQ ) *8 );Is the cast necessary?
Will remove it.
Quoted 5 lines
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 359
Quoted 3 lines
drivers/mmc/host/sdhci-msm.c +2
-0+else + mclk_freq = (u32)((host->clock /TCXO_FREQ ) *4 );Ditto
Will remove it.
Quoted 13 lines
drivers/mmc/host/sdhci-msm.c static int msm_init_cm_dll(struct sdhci_host *host) · line 366
Quoted 8 lines
drivers/mmc/host/sdhci-msm.c +7
-0+ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config &= ~(0xFF <<10 ); + config |= mclk_freq <<10 ; + +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); +/* wait for 5us before enabling DLL clock */ Usually there's a barrier between
writel_relaxed()and delay because we don't know when the writel will be posted out and the delay is there to wait for the operation to happen. Probably should change this to be awritel()instead.
Arnd, already explained here.
We do need the udelay here as per the HW sequence itself.
Quoted 26 lines
Quoted 26 lines
drivers/mmc/host/sdhci-msm.c +11
-0+udelay (5 ); + } +/* Write 0 to DLL_RST bit of DLL_CONFIG register */ config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); config &= ~CORE_DLL_RST ;@@ -340,6 +377,14 @@ static int msm_init_cm_dll(struct sdhci_host *host) config &= ~CORE_DLL_PDN ;writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); +if (msm_host->use_14lpp_dll_reset) { +msm_cm_dll_set_freq (host); +/* Enable the DLL clock */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config &= ~CORE_DLL_CLOCK_DISABLE ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); + } +/* Set DLL_EN bit to 1. */ config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); config |=CORE_DLL_EN ;@@ -641,6 +686,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)dev_dbg (&pdev->dev,"MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n" , core_version, core_major, core_minor);
Quoted 3 lines
drivers/mmc/host/sdhci-msm.c static int sdhci_msm_probe(struct platform_device *pdev) · line 689
Quoted 1 line
drivers/mmc/host/sdhci-msm.c +1
-0+if ((core_major ==1 ) && (core_minor >=0x42 ))Why so many parenthesis?
Sure, will remove it.
Quoted 5 lines
Quoted 4 lines
drivers/mmc/host/sdhci-msm.c +2
-0+ msm_host->use_14lpp_dll_reset = true; +/*
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v6 05/14] mmc: sdhci-msm: Update DLL reset sequence
Quoted 30 lines · Ritesh Harjani
Hi Stephen,
Quoted 17 lines · Stephen Boyd
Quoted 16 lines · Ritesh Harjani
drivers/mmc/host/sdhci-msm.c +4
-0@@ -58,11 +58,17 @@#define CORE_DLL_CONFIG 0x100#define CORE_DLL_STATUS 0x108 +#define CORE_DLL_CONFIG_2 0x1b4 +#define CORE_FLL_CYCLE_CNT BIT(18) +#define CORE_DLL_CLOCK_DISABLE BIT(21) +#define CORE_VENDOR_SPEC 0x10c#define CORE_CLK_PWRSAVE BIT(1)Quoted 6 lines
drivers/mmc/host/sdhci-msm.c line 70
Quoted 3 lines
drivers/mmc/host/sdhci-msm.c +1
-0#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c +#define TCXO_FREQ 19200000
TCXO_FREQcould change based on the board. For example, IPQ has it as 25 MHz.Actually not sure of the proper way on how to get this freq in driver today. We may use
xo_boardclock but, it is not available for all boards except 8996/8916 I guess.
Quoted 6 lines
Also, there is no sdhc for IPQ board and for all other boards
TCXO_FREQis same where sdhci-msm driver is used. For that purpose this was defined here for sdhci-msm driver.Do you think in that case we should keep it this way for now and later change if a need arise to change the
TCXO_FREQ?
We've added xo_board (or cxo_board/pxo_board) to all the qcom platforms upstream, so there should always be something to reference in the dts and call clk_get_rate() on. So I would add it to the binding as another clock and then use that instead of hardcoding the value. That's much more flexible in case this changes in the future.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v6 05/14] mmc: sdhci-msm: Update DLL reset sequence
Hi Stephen,
Quoted 38 lines · Stephen Boyd
Quoted 30 lines · Ritesh Harjani
Hi Stephen,
Quoted 17 lines · Stephen Boyd
Quoted 16 lines · Ritesh Harjani
drivers/mmc/host/sdhci-msm.c +4
-0@@ -58,11 +58,17 @@#define CORE_DLL_CONFIG 0x100#define CORE_DLL_STATUS 0x108 +#define CORE_DLL_CONFIG_2 0x1b4 +#define CORE_FLL_CYCLE_CNT BIT(18) +#define CORE_DLL_CLOCK_DISABLE BIT(21) +#define CORE_VENDOR_SPEC 0x10c#define CORE_CLK_PWRSAVE BIT(1)Quoted 6 lines
drivers/mmc/host/sdhci-msm.c line 70
Quoted 3 lines
drivers/mmc/host/sdhci-msm.c +1
-0#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c +#define TCXO_FREQ 19200000
TCXO_FREQcould change based on the board. For example, IPQ has it as 25 MHz.Actually not sure of the proper way on how to get this freq in driver today. We may use
xo_boardclock but, it is not available for all boards except 8996/8916 I guess.Quoted 6 lines
Also, there is no sdhc for IPQ board and for all other boards
TCXO_FREQis same where sdhci-msm driver is used. For that purpose this was defined here for sdhci-msm driver.Do you think in that case we should keep it this way for now and later change if a need arise to change the
TCXO_FREQ?
Quoted 7 lines
We've added
xo_board(or cxo_board/pxo_board) to all the qcom platforms upstream, so there should always be something to reference in the dts and callclk_get_rate()on. So I would add it to the binding as another clock and then use that instead of hardcoding the value. That's much more flexible in case this changes in the future.
Sure, I have addressed this in v7 as per your above comment.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v6 6/14 mmc: sdhci-msm: Add get_min_clock() and get_max_clock() callback
In reply to Ritesh HarjaniThis add get_min_clock() and get_max_clock() callback for sdhci-msm. sdhci-msm min/max clocks may be different hence implement these callbacks.
--- drivers/mmc/host/sdhci-msm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/mmc/host/sdhci-msm.c +16 -0
@@ -68,6 +68,7 @@#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c#define TCXO_FREQ 19200000 +#define SDHCI_MSM_MIN_CLOCK 400000#define CDR_SELEXT_SHIFT 20#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)
@@ -559,6 +560,19 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)return IRQ_HANDLED ; } +static unsigned int sdhci_msm_get_max_clock (struct sdhci_host *host) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); + +return clk_round_rate (msm_host->clk,ULONG_MAX ); +} + +static unsigned int sdhci_msm_get_min_clock (struct sdhci_host *host) +{ +return SDHCI_MSM_MIN_CLOCK ; +} +static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible ="qcom,sdhci-msm-v4" }, {},
@@ -570,6 +584,8 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) .platform_execute_tuning = sdhci_msm_execute_tuning, .reset = sdhci_reset, .set_clock = sdhci_set_clock, + .get_min_clock = sdhci_msm_get_min_clock, + .get_max_clock = sdhci_msm_get_max_clock, .set_bus_width = sdhci_set_bus_width, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, .voltage_switch = sdhci_msm_voltage_switch,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
A message that is not in the archive (sent off-list or not yet received): 1478517877-23733-7-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
Adrian Hunter
Acked-byRe: [PATCH v6 06/14] mmc: sdhci-msm: Add get_min_clock() and get_max_clock() callback
Quoted 6 lines · Ritesh Harjani
This add
get_min_clock()andget_max_clock()callback for sdhci-msm. sdhci-msm min/max clocks may be different hence implement these callbacks.Signed-off-by Sahitya Tummala <[email protected]>Signed-off-by Ritesh Harjani <[email protected]>
Quoted 38 lines
--- drivers/mmc/host/sdhci-msm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)drivers/mmc/host/sdhci-msm.c +14
-0@@ -68,6 +68,7 @@#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c#define TCXO_FREQ 19200000 +#define SDHCI_MSM_MIN_CLOCK 400000#define CDR_SELEXT_SHIFT 20#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)@@ -559,6 +560,19 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)return IRQ_HANDLED ; } +static unsigned int sdhci_msm_get_max_clock (struct sdhci_host *host) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); + +return clk_round_rate (msm_host->clk,ULONG_MAX ); +} + +static unsigned int sdhci_msm_get_min_clock (struct sdhci_host *host) +{ +return SDHCI_MSM_MIN_CLOCK ; +} +static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible ="qcom,sdhci-msm-v4" }, {},
drivers/mmc/host/sdhci-msm.c static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) · line 591
Quoted 8 lines
drivers/mmc/host/sdhci-msm.c +2
-0@@ -570,6 +584,8 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) .platform_execute_tuning = sdhci_msm_execute_tuning, .reset = sdhci_reset, .set_clock = sdhci_set_clock, + .get_min_clock = sdhci_msm_get_min_clock, + .get_max_clock = sdhci_msm_get_max_clock, .set_bus_width = sdhci_set_bus_width, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, .voltage_switch = sdhci_msm_voltage_switch,
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v6 7/14 mmc: sdhci-msm: Enable few quirks
In reply to Ritesh Harjanisdhc-msm controller needs this SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN & SDHCI_QUIRK2_PRESET_VALUE_BROKEN to be set. Hence setting it.
--- drivers/mmc/host/sdhci-msm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-msm.c +3 -1
@@ -594,7 +594,9 @@ static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)static const struct sdhci_pltfm_data sdhci_msm_pdata = { .quirks =SDHCI_QUIRK_BROKEN_CARD_DETECTION |SDHCI_QUIRK_NO_CARD_NO_RESET | -SDHCI_QUIRK_SINGLE_POWER_WRITE , +SDHCI_QUIRK_SINGLE_POWER_WRITE | +SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , .ops = &sdhci_msm_ops, };
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
PATCH v6 8/14 mmc: sdhci-msm: Implement set_clock callback for sdhci-msm
In reply to Ritesh Harjanisdhci-msm controller may have different clk-rates for each bus speed mode. Thus implement set_clock callback for sdhci-msm driver.
--- drivers/mmc/host/sdhci-msm.c | 87 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-msm.c +86 -1
@@ -82,6 +82,7 @@ struct sdhci_msm_host {struct clk *clk;/* main SD/MMC bus clock */ struct clk *pclk;/* SDHC peripheral bus clock */ struct clk *bus_clk;/* SDHC bus voter clock */ +unsigned long clk_rate;struct mmc_host *mmc;bool use_14lpp_dll_reset; };
@@ -573,6 +574,90 @@ static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)return SDHCI_MSM_MIN_CLOCK ; } +/** +* __sdhci_msm_set_clock - sdhci_msm clock control. +* +* Description: +* Implement MSM version of sdhci_set_clock. +* This is required since MSM controller does not +* use internal divider and instead directly control +* the GCC clock as per HW recommendation. +**/ +void __sdhci_msm_set_clock (struct sdhci_host *host,unsigned int clock) +{ +u16 clk; +unsigned long timeout; + +/* +* Keep actual_clock as zero - +* - since there is no divider used so no need of having actual_clock. +* - MSM controller uses SDCLK for data timeout calculation. If +* actual_clock is zero, host->clock is taken for calculation. +*/ + host->mmc->actual_clock =0 ; + +sdhci_writew (host,0 ,SDHCI_CLOCK_CONTROL ); + +if (clock ==0 ) +return ; + +/* +* MSM controller do not use clock divider. +* Thus read SDHCI_CLOCK_CONTROL and only enable +* clock with no divider value programmed. +*/ + clk =sdhci_readw (host,SDHCI_CLOCK_CONTROL ); + + clk |=SDHCI_CLOCK_INT_EN ; +sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL ); + +/* Wait max 20 ms */ + timeout =20 ; +while (!((clk =sdhci_readw (host,SDHCI_CLOCK_CONTROL )) + &SDHCI_CLOCK_INT_STABLE )) { +if (timeout ==0 ) { +pr_err ("%s: Internal clock never stabilised\n" , +mmc_hostname (host->mmc)); +return ; + } + timeout--; +mdelay (1 ); + } + + clk |=SDHCI_CLOCK_CARD_EN ; +sdhci_writew (host, clk,SDHCI_CLOCK_CONTROL ); +} + +/* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */ +static void sdhci_msm_set_clock (struct sdhci_host *host,unsigned int clock) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); +int rc; + +if (!clock) { + msm_host->clk_rate = clock; + goto out; + } + +spin_unlock_irq (&host->lock); +if (clock != msm_host->clk_rate) { + rc =clk_set_rate (msm_host->clk, clock); +if (rc) { +pr_err ("%s: Failed to set clock at rate %u\n" , +mmc_hostname (host->mmc), clock); +spin_lock_irq (&host->lock); + goto out; + } + msm_host->clk_rate = clock; +pr_debug ("%s: Setting clock at rate %lu\n" , +mmc_hostname (host->mmc),clk_get_rate (msm_host->clk)); + } +spin_lock_irq (&host->lock); +out: +__sdhci_msm_set_clock (host, clock); +} +static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible ="qcom,sdhci-msm-v4" }, {},
@@ -583,7 +668,7 @@ static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)static const struct sdhci_ops sdhci_msm_ops = { .platform_execute_tuning = sdhci_msm_execute_tuning, .reset = sdhci_reset, - .set_clock = sdhci_set_clock, + .set_clock = sdhci_msm_set_clock, .get_min_clock = sdhci_msm_get_min_clock, .get_max_clock = sdhci_msm_get_max_clock, .set_bus_width = sdhci_set_bus_width,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v6 08/14] mmc: sdhci-msm: Implement set_clock callback for sdhci-msm
Quoted 6 lines · Ritesh Harjani
sdhci-msm controller may have different clk-rates for each bus speed mode. Thus implement
set_clockcallback for sdhci-msm driver.Signed-off-by Sahitya Tummala <[email protected]>Signed-off-by Ritesh Harjani <[email protected]>
PATCH v6 9/14 mmc: sdhci-msm: Add clock changes for DDR mode.
In reply to Ritesh HarjaniSDHC MSM controller need 2x clock for MCLK at GCC. Hence make required changes to have 2x clock for DDR timing modes.
--- drivers/mmc/host/sdhci-msm.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
drivers/mmc/host/sdhci-msm.c +15 -2
@@ -633,6 +633,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); +struct mmc_ios curr_ios = host->mmc->ios;int rc;if (!clock) {
@@ -641,11 +642,23 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) }spin_unlock_irq (&host->lock); +/* +* The SDHC requires internal clock frequency to be double the +* actual clock that will be set for DDR mode. The controller +* uses the faster clock(100/400MHz) for some of its parts and +* send the actual required clock (50/200MHz) to the card. +*/ +if ((curr_ios.timing ==MMC_TIMING_UHS_DDR50 ) || + (curr_ios.timing ==MMC_TIMING_MMC_DDR52 ) || + (curr_ios.timing ==MMC_TIMING_MMC_HS400 )) + clock *=2 ; +if (clock != msm_host->clk_rate) { rc =clk_set_rate (msm_host->clk, clock);if (rc) { -pr_err ("%s: Failed to set clock at rate %u\n" , -mmc_hostname (host->mmc), clock); +pr_err ("%s: Failed to set clock at rate %u at timing %d\n" , +mmc_hostname (host->mmc), clock, + curr_ios.timing);spin_lock_irq (&host->lock); goto out; }
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v6 09/14] mmc: sdhci-msm: Add clock changes for DDR mode.
Quoted 5 lines · Ritesh Harjani
SDHC MSM controller need 2x clock for MCLK at GCC. Hence make required changes to have 2x clock for DDR timing modes.
Signed-off-by Ritesh Harjani <[email protected]>
Quoted 43 lines
--- drivers/mmc/host/sdhci-msm.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)drivers/mmc/host/sdhci-msm.c +15
-2@@ -633,6 +633,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) {struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); +struct mmc_ios curr_ios = host->mmc->ios;int rc;if (!clock) {@@ -641,11 +642,23 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) }spin_unlock_irq (&host->lock); +/* +* The SDHC requires internal clock frequency to be double the +* actual clock that will be set for DDR mode. The controller +* uses the faster clock(100/400MHz) for some of its parts and +* send the actual required clock (50/200MHz) to the card. +*/ +if ((curr_ios.timing ==MMC_TIMING_UHS_DDR50 ) || + (curr_ios.timing ==MMC_TIMING_MMC_DDR52 ) || + (curr_ios.timing ==MMC_TIMING_MMC_HS400 )) + clock *=2 ; +if (clock != msm_host->clk_rate) { rc =clk_set_rate (msm_host->clk, clock);if (rc) { -pr_err ("%s: Failed to set clock at rate %u\n" , -mmc_hostname (host->mmc), clock); +pr_err ("%s: Failed to set clock at rate %u at timing %d\n" , +mmc_hostname (host->mmc), clock, + curr_ios.timing);spin_lock_irq (&host->lock); goto out; }
PATCH v6 11/14 mmc: sdhci-msm: Add HS400 platform support
In reply to Ritesh HarjaniFrom: Venkat Gopalakrishnan <[email protected]>
The following msm platform specific changes are added to support HS400.
- Allow tuning for HS400 mode.
- Configure HS400 timing mode using the VENDOR_SPECIFIC_FUNC register.
--- drivers/mmc/host/sdhci-msm.c | 127 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 117 insertions(+), 10 deletions(-)
drivers/mmc/host/sdhci-msm.c +117 -10
@@ -31,6 +31,7 @@#define HC_MODE_EN 0x1#define CORE_POWER 0x0#define CORE_SW_RST BIT(7) +#define FF_CLK_SW_RST_DIS BIT(13)#define CORE_PWRCTL_STATUS 0xdc#define CORE_PWRCTL_MASK 0xe0
@@ -64,11 +65,18 @@#define CORE_VENDOR_SPEC 0x10c#define CORE_CLK_PWRSAVE BIT(1) +#define CORE_HC_MCLK_SEL_DFLT (2 << 8) +#define CORE_HC_MCLK_SEL_HS400 (3 << 8) +#define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_HC_SELECT_IN_EN BIT(18) +#define CORE_HC_SELECT_IN_HS400 (6 << 19) +#define CORE_HC_SELECT_IN_MASK (7 << 19)#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c#define TCXO_FREQ 19200000#define SDHCI_MSM_MIN_CLOCK 400000 +#define CORE_FREQ_100MHZ (100 * 1000 * 1000)#define CDR_SELEXT_SHIFT 20#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)
@@ -85,6 +93,8 @@ struct sdhci_msm_host {unsigned long clk_rate;struct mmc_host *mmc;bool use_14lpp_dll_reset; +bool tuning_done; +bool calibration_done; };/* Platform specific tuning */
@@ -173,8 +183,8 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)* Find out the greatest range of consecuitive selected * DLL clock output phases that can be used as sampling * setting for SD3.0 UHS-I card read operation (in SDR104 -* timing mode) or for eMMC4.5 card read operation (in HS200 -* timing mode). +* timing mode) or for eMMC4.5 card read operation (in +* HS400/HS200 timing mode). * Select the 3/4 of the range and configure the DLL with the * selected DLL clock output phase. */
@@ -426,9 +436,10 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)* Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. */ -if (host->clock <=100 *1000 *1000 || - !((ios.timing ==MMC_TIMING_MMC_HS200 ) || - (ios.timing ==MMC_TIMING_UHS_SDR104 ))) +if (host->clock <=CORE_FREQ_100MHZ || + !(ios.timing ==MMC_TIMING_MMC_HS400 || + ios.timing ==MMC_TIMING_MMC_HS200 || + ios.timing ==MMC_TIMING_UHS_SDR104 ))return 0 ; retry:
@@ -479,6 +490,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) rc = -EIO ; } +if (!rc) + msm_host->tuning_done = true;return rc; }
@@ -486,7 +499,10 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) {struct mmc_host *mmc = host->mmc; +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);u16 ctrl_2; +u32 config; ctrl_2 =sdhci_readw (host,SDHCI_HOST_CONTROL2 );/* Select Bus Speed Mode for host */
@@ -501,6 +517,7 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,case MMC_TIMING_UHS_SDR50 : ctrl_2 |=SDHCI_CTRL_UHS_SDR50 ;break ; +case MMC_TIMING_MMC_HS400 :case MMC_TIMING_MMC_HS200 :case MMC_TIMING_UHS_SDR104 : ctrl_2 |=SDHCI_CTRL_UHS_SDR104 ;
@@ -517,11 +534,31 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,* provide feedback clock, the mode selection can be any value less * than 3'b011 in bits [2:0] of HOST CONTROL2 register. */ -if (host->clock <=100000000 && - (uhs ==MMC_TIMING_MMC_HS400 || - uhs ==MMC_TIMING_MMC_HS200 || - uhs ==MMC_TIMING_UHS_SDR104 )) - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK ; +if (host->clock <=CORE_FREQ_100MHZ ) { +if ((uhs ==MMC_TIMING_MMC_HS400 ) || + (uhs ==MMC_TIMING_MMC_HS200 ) || + (uhs ==MMC_TIMING_UHS_SDR104 )) + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK ; +/* +* Make sure DLL is disabled when not required +* +* Write 1 to DLL_RST bit of DLL_CONFIG register +*/ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_DLL_RST ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); + +/* Write 1 to DLL_PDN bit of DLL_CONFIG register */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_DLL_PDN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); + +/* +* The DLL needs to be restored and CDCLP533 recalibrated +* when the clock frequency is set back to 400MHz. +*/ + msm_host->calibration_done = false; + }dev_dbg (mmc_dev (mmc),"%s: clock=%u uhs=%u ctrl_2=0x%x\n" ,mmc_hostname (host->mmc), host->clock, uhs, ctrl_2);
@@ -634,6 +671,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);struct mmc_ios curr_ios = host->mmc->ios; +u32 config;int rc;if (!clock) {
@@ -652,6 +690,70 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) (curr_ios.timing == MMC_TIMING_MMC_DDR52) || (curr_ios.timing == MMC_TIMING_MMC_HS400)) clock *=2 ; +/* +* In general all timing modes are controlled via UHS mode select in +* Host Control2 register. eMMC specific HS200/HS400 doesn't have +* their respective modes defined here, hence we use these values. +* +* HS200 - SDR104 (Since they both are equivalent in functionality) +* HS400 - This involves multiple configurations +* Initially SDR104 - when tuning is required as HS200 +* Then when switching to DDR @ 400MHz (HS400) we use +* the vendor specific HC_SELECT_IN to control the mode. +* +* In addition to controlling the modes we also need to select the +* correct input clock for DLL depending on the mode. +* +* HS400 - divided clock (free running MCLK/2) +* All other modes - default (free running MCLK) +*/ +if (curr_ios.timing ==MMC_TIMING_MMC_HS400 ) { +/* Select the divided clock (free running MCLK/2) */ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config &= ~CORE_HC_MCLK_SEL_MASK ; + config |=CORE_HC_MCLK_SEL_HS400 ; + +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); +/* +* Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC +* register +*/ +if (msm_host->tuning_done && !msm_host->calibration_done) { +/* +* Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN +* field in VENDOR_SPEC_FUNC +*/ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config |=CORE_HC_SELECT_IN_HS400 ; + config |=CORE_HC_SELECT_IN_EN ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); + } + }else { +/* Select the default clock (free running MCLK) */ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config &= ~CORE_HC_MCLK_SEL_MASK ; + config |=CORE_HC_MCLK_SEL_DFLT ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); + +/* +* Disable HC_SELECT_IN to be able to use the UHS mode select +* configuration from Host Control2 register for all other +* modes. +* +* Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field +* in VENDOR_SPEC_FUNC +*/ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config &= ~CORE_HC_SELECT_IN_EN ; + config &= ~CORE_HC_SELECT_IN_MASK ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); + } + +/* +* Make sure above writes impacting free running MCLK are completed +* before changing the clk_rate at GCC. +*/ +wmb ();if (clock != msm_host->clk_rate) { rc =clk_set_rate (msm_host->clk, clock);
@@ -790,6 +892,11 @@ static int sdhci_msm_probe(struct platform_device *pdev)/* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed (HC_MODE_EN , (msm_host->core_mem +CORE_HC_MODE )); +/* Set FF_CLK_SW_RST_DIS bit in HC_MODE register */ + config =readl_relaxed (msm_host->core_mem +CORE_HC_MODE ); + config |=FF_CLK_SW_RST_DIS ; +writel_relaxed (config, msm_host->core_mem +CORE_HC_MODE ); + host_version =readw_relaxed ((host->ioaddr +SDHCI_HOST_VERSION )); dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v6 11/14] mmc: sdhci-msm: Add HS400 platform support
Quoted 8 lines · Ritesh Harjani
From: Venkat Gopalakrishnan <[email protected]>
The following msm platform specific changes are added to support HS400.
- Allow tuning for HS400 mode.
- Configure HS400 timing mode using theVENDOR_SPECIFIC_FUNCregister.Signed-off-by Venkat Gopalakrishnan <[email protected]>Signed-off-by Ritesh Harjani <[email protected]>
Quoted 226 lines
--- drivers/mmc/host/sdhci-msm.c | 127 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 117 insertions(+), 10 deletions(-)drivers/mmc/host/sdhci-msm.c +117
-10@@ -31,6 +31,7 @@#define HC_MODE_EN 0x1#define CORE_POWER 0x0#define CORE_SW_RST BIT(7) +#define FF_CLK_SW_RST_DIS BIT(13)#define CORE_PWRCTL_STATUS 0xdc#define CORE_PWRCTL_MASK 0xe0@@ -64,11 +65,18 @@#define CORE_VENDOR_SPEC 0x10c#define CORE_CLK_PWRSAVE BIT(1) +#define CORE_HC_MCLK_SEL_DFLT (2 << 8) +#define CORE_HC_MCLK_SEL_HS400 (3 << 8) +#define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_HC_SELECT_IN_EN BIT(18) +#define CORE_HC_SELECT_IN_HS400 (6 << 19) +#define CORE_HC_SELECT_IN_MASK (7 << 19)#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c#define TCXO_FREQ 19200000#define SDHCI_MSM_MIN_CLOCK 400000 +#define CORE_FREQ_100MHZ (100 * 1000 * 1000)#define CDR_SELEXT_SHIFT 20#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)@@ -85,6 +93,8 @@ struct sdhci_msm_host {unsigned long clk_rate;struct mmc_host *mmc;bool use_14lpp_dll_reset; +bool tuning_done; +bool calibration_done; };/* Platform specific tuning */ @@ -173,8 +183,8 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)* Find out the greatest range of consecuitive selected * DLL clock output phases that can be used as sampling * setting for SD3.0 UHS-I card read operation (in SDR104 -* timing mode) or for eMMC4.5 card read operation (in HS200 -* timing mode). +* timing mode) or for eMMC4.5 card read operation (in +* HS400/HS200 timing mode). * Select the 3/4 of the range and configure the DLL with the * selected DLL clock output phase. */ @@ -426,9 +436,10 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)* Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. */ -if (host->clock <=100 *1000 *1000 || - !((ios.timing ==MMC_TIMING_MMC_HS200 ) || - (ios.timing ==MMC_TIMING_UHS_SDR104 ))) +if (host->clock <=CORE_FREQ_100MHZ || + !(ios.timing ==MMC_TIMING_MMC_HS400 || + ios.timing ==MMC_TIMING_MMC_HS200 || + ios.timing ==MMC_TIMING_UHS_SDR104 ))return 0 ; retry:@@ -479,6 +490,8 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) rc = -EIO ; } +if (!rc) + msm_host->tuning_done = true;return rc; }@@ -486,7 +499,10 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) {struct mmc_host *mmc = host->mmc; +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);u16 ctrl_2; +u32 config; ctrl_2 =sdhci_readw (host,SDHCI_HOST_CONTROL2 );/* Select Bus Speed Mode for host */ @@ -501,6 +517,7 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,case MMC_TIMING_UHS_SDR50 : ctrl_2 |=SDHCI_CTRL_UHS_SDR50 ;break ; +case MMC_TIMING_MMC_HS400 :case MMC_TIMING_MMC_HS200 :case MMC_TIMING_UHS_SDR104 : ctrl_2 |=SDHCI_CTRL_UHS_SDR104 ;@@ -517,11 +534,31 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,* provide feedback clock, the mode selection can be any value less * than 3'b011 in bits [2:0] of HOST CONTROL2 register. */ -if (host->clock <=100000000 && - (uhs ==MMC_TIMING_MMC_HS400 || - uhs ==MMC_TIMING_MMC_HS200 || - uhs ==MMC_TIMING_UHS_SDR104 )) - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK ; +if (host->clock <=CORE_FREQ_100MHZ ) { +if ((uhs ==MMC_TIMING_MMC_HS400 ) || + (uhs ==MMC_TIMING_MMC_HS200 ) || + (uhs ==MMC_TIMING_UHS_SDR104 )) + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK ; +/* +* Make sure DLL is disabled when not required +* +* Write 1 to DLL_RST bit of DLL_CONFIG register +*/ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_DLL_RST ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); + +/* Write 1 to DLL_PDN bit of DLL_CONFIG register */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_DLL_PDN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); + +/* +* The DLL needs to be restored and CDCLP533 recalibrated +* when the clock frequency is set back to 400MHz. +*/ + msm_host->calibration_done = false; + }dev_dbg (mmc_dev (mmc),"%s: clock=%u uhs=%u ctrl_2=0x%x\n" ,mmc_hostname (host->mmc), host->clock, uhs, ctrl_2);@@ -634,6 +671,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);struct mmc_ios curr_ios = host->mmc->ios; +u32 config;int rc;if (!clock) {@@ -652,6 +690,70 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) (curr_ios.timing == MMC_TIMING_MMC_DDR52) || (curr_ios.timing == MMC_TIMING_MMC_HS400)) clock *=2 ; +/* +* In general all timing modes are controlled via UHS mode select in +* Host Control2 register. eMMC specific HS200/HS400 doesn't have +* their respective modes defined here, hence we use these values. +* +* HS200 - SDR104 (Since they both are equivalent in functionality) +* HS400 - This involves multiple configurations +* Initially SDR104 - when tuning is required as HS200 +* Then when switching to DDR @ 400MHz (HS400) we use +* the vendor specific HC_SELECT_IN to control the mode. +* +* In addition to controlling the modes we also need to select the +* correct input clock for DLL depending on the mode. +* +* HS400 - divided clock (free running MCLK/2) +* All other modes - default (free running MCLK) +*/ +if (curr_ios.timing ==MMC_TIMING_MMC_HS400 ) { +/* Select the divided clock (free running MCLK/2) */ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config &= ~CORE_HC_MCLK_SEL_MASK ; + config |=CORE_HC_MCLK_SEL_HS400 ; + +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); +/* +* Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC +* register +*/ +if (msm_host->tuning_done && !msm_host->calibration_done) { +/* +* Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN +* field in VENDOR_SPEC_FUNC +*/ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config |=CORE_HC_SELECT_IN_HS400 ; + config |=CORE_HC_SELECT_IN_EN ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); + } + }else { +/* Select the default clock (free running MCLK) */ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config &= ~CORE_HC_MCLK_SEL_MASK ; + config |=CORE_HC_MCLK_SEL_DFLT ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); + +/* +* Disable HC_SELECT_IN to be able to use the UHS mode select +* configuration from Host Control2 register for all other +* modes. +* +* Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field +* in VENDOR_SPEC_FUNC +*/ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); + config &= ~CORE_HC_SELECT_IN_EN ; + config &= ~CORE_HC_SELECT_IN_MASK ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); + } + +/* +* Make sure above writes impacting free running MCLK are completed +* before changing the clk_rate at GCC. +*/ +wmb ();if (clock != msm_host->clk_rate) { rc =clk_set_rate (msm_host->clk, clock);@@ -790,6 +892,11 @@ static int sdhci_msm_probe(struct platform_device *pdev)/* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed (HC_MODE_EN , (msm_host->core_mem +CORE_HC_MODE )); +/* Set FF_CLK_SW_RST_DIS bit in HC_MODE register */ + config =readl_relaxed (msm_host->core_mem +CORE_HC_MODE ); + config |=FF_CLK_SW_RST_DIS ; +writel_relaxed (config, msm_host->core_mem +CORE_HC_MODE ); + host_version =readw_relaxed ((host->ioaddr +SDHCI_HOST_VERSION )); dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
PATCH v6 13/14 mmc: sdhci-msm: Add calibration tuning for CDCLP533 circuit
In reply to Ritesh HarjaniIn HS400 mode a new RCLK is introduced on the interface for read data transfers. The eMMC5.0 device transmits the read data to the host with respect to rising and falling edges of RCLK. In order to ensure correct operation of read data transfers in HS400 mode, the incoming RX data needs to be sampled by delayed version of RCLK.
The CDCLP533 delay circuit shifts the RCLK by T/4. It needs to be initialized, configured and enabled once during HS400 mode switch and when operational voltage/clock is changed.
--- drivers/mmc/host/sdhci-msm.c | 163 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+)
drivers/mmc/host/sdhci-msm.c +163 -0
@@ -19,6 +19,7 @@#include <linux/delay.h> #include <linux/mmc/mmc.h> #include <linux/slab.h> +#include <linux/iopoll.h> #include "sdhci-pltfm.h"
@@ -57,6 +58,7 @@#define CORE_DLL_PDN BIT(29)#define CORE_DLL_RST BIT(30)#define CORE_DLL_CONFIG 0x100 +#define CORE_CMD_DAT_TRACK_SEL BIT(0)#define CORE_DLL_STATUS 0x108#define CORE_DLL_CONFIG_2 0x1b4
@@ -72,6 +74,33 @@#define CORE_HC_SELECT_IN_HS400 (6 << 19)#define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_CSR_CDC_CTLR_CFG0 0x130 +#define CORE_SW_TRIG_FULL_CALIB BIT(16) +#define CORE_HW_AUTOCAL_ENA BIT(17) + +#define CORE_CSR_CDC_CTLR_CFG1 0x134 +#define CORE_CSR_CDC_CAL_TIMER_CFG0 0x138 +#define CORE_TIMER_ENA BIT(16) + +#define CORE_CSR_CDC_CAL_TIMER_CFG1 0x13C +#define CORE_CSR_CDC_REFCOUNT_CFG 0x140 +#define CORE_CSR_CDC_COARSE_CAL_CFG 0x144 +#define CORE_CDC_OFFSET_CFG 0x14C +#define CORE_CSR_CDC_DELAY_CFG 0x150 +#define CORE_CDC_SLAVE_DDA_CFG 0x160 +#define CORE_CSR_CDC_STATUS0 0x164 +#define CORE_CALIBRATION_DONE BIT(0) + +#define CORE_CDC_ERROR_CODE_MASK 0x7000000 + +#define CORE_CSR_CDC_GEN_CFG 0x178 +#define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) +#define CORE_CDC_SWITCH_RC_EN BIT(1) + +#define CORE_DDR_200_CFG 0x184 +#define CORE_CDC_T4_DLY_SEL BIT(0) +#define CORE_START_CDC_TRAFFIC BIT(6) +#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c#define INVALID_TUNING_PHASE -1
@@ -429,6 +458,131 @@ static int msm_init_cm_dll(struct sdhci_host *host)return 0 ; } +static int sdhci_msm_cdclp533_calibration (struct sdhci_host *host) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); +u32 config, calib_done; +int ret; + +pr_debug ("%s: %s: Enter\n" ,mmc_hostname (host->mmc), __func__); + +/* +* Retuning in HS400 (DDR mode) will fail, just reset the +* tuning block and restore the saved tuning phase. +*/ + ret =msm_init_cm_dll (host); +if (ret) + goto out; + +/* Set the selected phase in delay line hw block */ + ret =msm_config_cm_dll_phase (host, msm_host->saved_tuning_phase); +if (ret) + goto out; + +/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CMD_DAT_TRACK_SEL ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); + +/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */ + config =readl_relaxed (host->ioaddr +CORE_DDR_200_CFG ); + config &= ~CORE_CDC_T4_DLY_SEL ; +writel_relaxed (config, host->ioaddr +CORE_DDR_200_CFG ); + +/* Write 0 to CDC_SWITCH_BYPASS_OFF field in CORE_CSR_CDC_GEN_CFG */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + config &= ~CORE_CDC_SWITCH_BYPASS_OFF ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + +/* Write 1 to CDC_SWITCH_RC_EN field in CORE_CSR_CDC_GEN_CFG */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + config |=CORE_CDC_SWITCH_RC_EN ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + +/* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */ + config =readl_relaxed (host->ioaddr +CORE_DDR_200_CFG ); + config &= ~CORE_START_CDC_TRAFFIC ; +writel_relaxed (config, host->ioaddr +CORE_DDR_200_CFG ); + +/* +* Perform CDC Register Initialization Sequence +* +* CORE_CSR_CDC_CTLR_CFG0 0x11800EC +* CORE_CSR_CDC_CTLR_CFG1 0x3011111 +* CORE_CSR_CDC_CAL_TIMER_CFG0 0x1201000 +* CORE_CSR_CDC_CAL_TIMER_CFG1 0x4 +* CORE_CSR_CDC_REFCOUNT_CFG 0xCB732020 +* CORE_CSR_CDC_COARSE_CAL_CFG 0xB19 +* CORE_CSR_CDC_DELAY_CFG 0x3AC +* CORE_CDC_OFFSET_CFG 0x0 +* CORE_CDC_SLAVE_DDA_CFG 0x16334 +*/ + +writel_relaxed (0x11800EC , host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); +writel_relaxed (0x3011111 , host->ioaddr +CORE_CSR_CDC_CTLR_CFG1 ); +writel_relaxed (0x1201000 , host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG0 ); +writel_relaxed (0x4 , host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG1 ); +writel_relaxed (0xCB732020 , host->ioaddr +CORE_CSR_CDC_REFCOUNT_CFG ); +writel_relaxed (0xB19 , host->ioaddr +CORE_CSR_CDC_COARSE_CAL_CFG ); +writel_relaxed (0x3AC , host->ioaddr +CORE_CSR_CDC_DELAY_CFG ); +writel_relaxed (0x0 , host->ioaddr +CORE_CDC_OFFSET_CFG ); +writel_relaxed (0x16334 , host->ioaddr +CORE_CDC_SLAVE_DDA_CFG ); + +/* CDC HW Calibration */ + +/* Write 1 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + config |=CORE_SW_TRIG_FULL_CALIB ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + +/* Write 0 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + config &= ~CORE_SW_TRIG_FULL_CALIB ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + +/* Write 1 to HW_AUTOCAL_ENA field in CORE_CSR_CDC_CTLR_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + config |=CORE_HW_AUTOCAL_ENA ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + +/* Write 1 to TIMER_ENA field in CORE_CSR_CDC_CAL_TIMER_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG0 ); + config |=CORE_TIMER_ENA ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG0 ); + +/* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */ + ret =readl_relaxed_poll_timeout (host->ioaddr +CORE_CSR_CDC_STATUS0 , + calib_done, + (calib_done &CORE_CALIBRATION_DONE ), +1 ,50 ); + +if (ret == -ETIMEDOUT ) { +pr_err ("%s: %s: CDC calibration was not completed\n" , +mmc_hostname (host->mmc), __func__); + goto out; + } + +/* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */ + ret =readl_relaxed (host->ioaddr +CORE_CSR_CDC_STATUS0 ) + &CORE_CDC_ERROR_CODE_MASK ; +if (ret) { +pr_err ("%s: %s: CDC error code %d\n" , +mmc_hostname (host->mmc), __func__, ret); + ret = -EINVAL ; + goto out; + } + +/* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */ + config =readl_relaxed (host->ioaddr +CORE_DDR_200_CFG ); + config |=CORE_START_CDC_TRAFFIC ; +writel_relaxed (config, host->ioaddr +CORE_DDR_200_CFG ); +out: +pr_debug ("%s: %s: Exit, ret %d\n" ,mmc_hostname (host->mmc), + __func__, ret); +return ret; +} +static int sdhci_msm_execute_tuning (struct sdhci_host *host,u32 opcode) {int tuning_seq_cnt =3 ;
@@ -571,6 +725,15 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,dev_dbg (mmc_dev (mmc),"%s: clock=%u uhs=%u ctrl_2=0x%x\n" ,mmc_hostname (host->mmc), host->clock, uhs, ctrl_2);sdhci_writew (host, ctrl_2,SDHCI_HOST_CONTROL2 ); + +spin_unlock_irq (&host->lock); +/* CDCLP533 HW calibration is only required for HS400 mode*/ +if (host->clock >CORE_FREQ_100MHZ && + msm_host->tuning_done && !msm_host->calibration_done && + (mmc->ios.timing ==MMC_TIMING_MMC_HS400 )) +if (!sdhci_msm_cdclp533_calibration (host)) + msm_host->calibration_done = true; +spin_lock_irq (&host->lock); }static void sdhci_msm_voltage_switch (struct sdhci_host *host)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
Re: [PATCH v6 13/14] mmc: sdhci-msm: Add calibration tuning for CDCLP533 circuit
Quoted 6 lines · Ritesh Harjani
In HS400 mode a new RCLK is introduced on the interface for read data transfers. The eMMC5.0 device transmits the read data to the host with respect to rising and falling edges of RCLK. In order to ensure correct operation of read data transfers in HS400 mode, the incoming RX data needs to be sampled by delayed version of RCLK.
Quoted 6 lines
The CDCLP533 delay circuit shifts the RCLK by T/4. It needs to be initialized, configured and enabled once during HS400 mode switch and when operational voltage/clock is changed.
Signed-off-by Venkat Gopalakrishnan <[email protected]>Signed-off-by Ritesh Harjani <[email protected]>
Quoted 207 lines
--- drivers/mmc/host/sdhci-msm.c | 163 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+)drivers/mmc/host/sdhci-msm.c +163
-0@@ -19,6 +19,7 @@#include <linux/delay.h> #include <linux/mmc/mmc.h> #include <linux/slab.h> +#include <linux/iopoll.h> #include "sdhci-pltfm.h" @@ -57,6 +58,7 @@#define CORE_DLL_PDN BIT(29)#define CORE_DLL_RST BIT(30)#define CORE_DLL_CONFIG 0x100 +#define CORE_CMD_DAT_TRACK_SEL BIT(0)#define CORE_DLL_STATUS 0x108#define CORE_DLL_CONFIG_2 0x1b4@@ -72,6 +74,33 @@#define CORE_HC_SELECT_IN_HS400 (6 << 19)#define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_CSR_CDC_CTLR_CFG0 0x130 +#define CORE_SW_TRIG_FULL_CALIB BIT(16) +#define CORE_HW_AUTOCAL_ENA BIT(17) + +#define CORE_CSR_CDC_CTLR_CFG1 0x134 +#define CORE_CSR_CDC_CAL_TIMER_CFG0 0x138 +#define CORE_TIMER_ENA BIT(16) + +#define CORE_CSR_CDC_CAL_TIMER_CFG1 0x13C +#define CORE_CSR_CDC_REFCOUNT_CFG 0x140 +#define CORE_CSR_CDC_COARSE_CAL_CFG 0x144 +#define CORE_CDC_OFFSET_CFG 0x14C +#define CORE_CSR_CDC_DELAY_CFG 0x150 +#define CORE_CDC_SLAVE_DDA_CFG 0x160 +#define CORE_CSR_CDC_STATUS0 0x164 +#define CORE_CALIBRATION_DONE BIT(0) + +#define CORE_CDC_ERROR_CODE_MASK 0x7000000 + +#define CORE_CSR_CDC_GEN_CFG 0x178 +#define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) +#define CORE_CDC_SWITCH_RC_EN BIT(1) + +#define CORE_DDR_200_CFG 0x184 +#define CORE_CDC_T4_DLY_SEL BIT(0) +#define CORE_START_CDC_TRAFFIC BIT(6) +#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c#define INVALID_TUNING_PHASE -1@@ -429,6 +458,131 @@ static int msm_init_cm_dll(struct sdhci_host *host)return 0 ; } +static int sdhci_msm_cdclp533_calibration (struct sdhci_host *host) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); +u32 config, calib_done; +int ret; + +pr_debug ("%s: %s: Enter\n" ,mmc_hostname (host->mmc), __func__); + +/* +* Retuning in HS400 (DDR mode) will fail, just reset the +* tuning block and restore the saved tuning phase. +*/ + ret =msm_init_cm_dll (host); +if (ret) + goto out; + +/* Set the selected phase in delay line hw block */ + ret =msm_config_cm_dll_phase (host, msm_host->saved_tuning_phase); +if (ret) + goto out; + +/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CMD_DAT_TRACK_SEL ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); + +/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */ + config =readl_relaxed (host->ioaddr +CORE_DDR_200_CFG ); + config &= ~CORE_CDC_T4_DLY_SEL ; +writel_relaxed (config, host->ioaddr +CORE_DDR_200_CFG ); + +/* Write 0 to CDC_SWITCH_BYPASS_OFF field in CORE_CSR_CDC_GEN_CFG */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + config &= ~CORE_CDC_SWITCH_BYPASS_OFF ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + +/* Write 1 to CDC_SWITCH_RC_EN field in CORE_CSR_CDC_GEN_CFG */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + config |=CORE_CDC_SWITCH_RC_EN ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_GEN_CFG ); + +/* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */ + config =readl_relaxed (host->ioaddr +CORE_DDR_200_CFG ); + config &= ~CORE_START_CDC_TRAFFIC ; +writel_relaxed (config, host->ioaddr +CORE_DDR_200_CFG ); + +/* +* Perform CDC Register Initialization Sequence +* +* CORE_CSR_CDC_CTLR_CFG0 0x11800EC +* CORE_CSR_CDC_CTLR_CFG1 0x3011111 +* CORE_CSR_CDC_CAL_TIMER_CFG0 0x1201000 +* CORE_CSR_CDC_CAL_TIMER_CFG1 0x4 +* CORE_CSR_CDC_REFCOUNT_CFG 0xCB732020 +* CORE_CSR_CDC_COARSE_CAL_CFG 0xB19 +* CORE_CSR_CDC_DELAY_CFG 0x3AC +* CORE_CDC_OFFSET_CFG 0x0 +* CORE_CDC_SLAVE_DDA_CFG 0x16334 +*/ + +writel_relaxed (0x11800EC , host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); +writel_relaxed (0x3011111 , host->ioaddr +CORE_CSR_CDC_CTLR_CFG1 ); +writel_relaxed (0x1201000 , host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG0 ); +writel_relaxed (0x4 , host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG1 ); +writel_relaxed (0xCB732020 , host->ioaddr +CORE_CSR_CDC_REFCOUNT_CFG ); +writel_relaxed (0xB19 , host->ioaddr +CORE_CSR_CDC_COARSE_CAL_CFG ); +writel_relaxed (0x3AC , host->ioaddr +CORE_CSR_CDC_DELAY_CFG ); +writel_relaxed (0x0 , host->ioaddr +CORE_CDC_OFFSET_CFG ); +writel_relaxed (0x16334 , host->ioaddr +CORE_CDC_SLAVE_DDA_CFG ); + +/* CDC HW Calibration */ + +/* Write 1 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + config |=CORE_SW_TRIG_FULL_CALIB ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + +/* Write 0 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + config &= ~CORE_SW_TRIG_FULL_CALIB ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + +/* Write 1 to HW_AUTOCAL_ENA field in CORE_CSR_CDC_CTLR_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + config |=CORE_HW_AUTOCAL_ENA ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CTLR_CFG0 ); + +/* Write 1 to TIMER_ENA field in CORE_CSR_CDC_CAL_TIMER_CFG0 */ + config =readl_relaxed (host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG0 ); + config |=CORE_TIMER_ENA ; +writel_relaxed (config, host->ioaddr +CORE_CSR_CDC_CAL_TIMER_CFG0 ); + +/* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */ + ret =readl_relaxed_poll_timeout (host->ioaddr +CORE_CSR_CDC_STATUS0 , + calib_done, + (calib_done &CORE_CALIBRATION_DONE ), +1 ,50 ); + +if (ret == -ETIMEDOUT ) { +pr_err ("%s: %s: CDC calibration was not completed\n" , +mmc_hostname (host->mmc), __func__); + goto out; + } + +/* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */ + ret =readl_relaxed (host->ioaddr +CORE_CSR_CDC_STATUS0 ) + &CORE_CDC_ERROR_CODE_MASK ; +if (ret) { +pr_err ("%s: %s: CDC error code %d\n" , +mmc_hostname (host->mmc), __func__, ret); + ret = -EINVAL ; + goto out; + } + +/* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */ + config =readl_relaxed (host->ioaddr +CORE_DDR_200_CFG ); + config |=CORE_START_CDC_TRAFFIC ; +writel_relaxed (config, host->ioaddr +CORE_DDR_200_CFG ); +out: +pr_debug ("%s: %s: Exit, ret %d\n" ,mmc_hostname (host->mmc), + __func__, ret); +return ret; +} +static int sdhci_msm_execute_tuning (struct sdhci_host *host,u32 opcode) {int tuning_seq_cnt =3 ;@@ -571,6 +725,15 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,dev_dbg (mmc_dev (mmc),"%s: clock=%u uhs=%u ctrl_2=0x%x\n" ,mmc_hostname (host->mmc), host->clock, uhs, ctrl_2);sdhci_writew (host, ctrl_2,SDHCI_HOST_CONTROL2 ); + +spin_unlock_irq (&host->lock); +/* CDCLP533 HW calibration is only required for HS400 mode*/ +if (host->clock >CORE_FREQ_100MHZ && + msm_host->tuning_done && !msm_host->calibration_done && + (mmc->ios.timing ==MMC_TIMING_MMC_HS400 )) +if (!sdhci_msm_cdclp533_calibration (host)) + msm_host->calibration_done = true; +spin_lock_irq (&host->lock); }static void sdhci_msm_voltage_switch (struct sdhci_host *host)
PATCH v6 14/14 sdhci: sdhci-msm: update dll configuration
In reply to Ritesh HarjaniThe newer msm sdhci's cores use a different DLL hardware for HS400. Update the configuration and calibration of the newer DLL block.
The HS400 DLL block used previously is CDC LP 533 and requires programming multiple registers and waiting for configuration to complete and then enable it. It has about 18 register writes and two register reads.
The newer HS400 DLL block is SDC4 DLL and requires two register writes for configuration and one register read to confirm that it is initialized. There is an additional register write to enable the power save mode for SDC4 DLL block.
--- drivers/mmc/host/sdhci-msm.c | 132 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-)
drivers/mmc/host/sdhci-msm.c +130 -2
@@ -51,6 +51,7 @@#define INT_MASK 0xf#define MAX_PHASES 16#define CORE_DLL_LOCK BIT(7) +#define CORE_DDR_DLL_LOCK BIT(11)#define CORE_DLL_EN BIT(16)#define CORE_CDR_EN BIT(17)#define CORE_CK_OUT_EN BIT(18)
@@ -62,6 +63,7 @@#define CORE_DLL_STATUS 0x108#define CORE_DLL_CONFIG_2 0x1b4 +#define CORE_DDR_CAL_EN BIT(0)#define CORE_FLL_CYCLE_CNT BIT(18)#define CORE_DLL_CLOCK_DISABLE BIT(21)
@@ -100,6 +102,11 @@#define CORE_DDR_200_CFG 0x184#define CORE_CDC_T4_DLY_SEL BIT(0)#define CORE_START_CDC_TRAFFIC BIT(6) +#define CORE_VENDOR_SPEC3 0x1b0 +#define CORE_PWRSAVE_DLL BIT(3) + +#define CORE_DDR_CONFIG 0x1b8 +#define DDR_CONFIG_POR_VAL 0x80040853#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
@@ -126,6 +133,7 @@ struct sdhci_msm_host {bool tuning_done;bool calibration_done;u8 saved_tuning_phase; +bool use_cdclp533; };/* Platform specific tuning */
@@ -583,6 +591,93 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)return ret; } +static int sdhci_msm_cm_dll_sdc4_calibration (struct sdhci_host *host) +{ +u32 dll_status, config; +int ret; + +pr_debug ("%s: %s: Enter\n" ,mmc_hostname (host->mmc), __func__); + +/* +* Currently the CORE_DDR_CONFIG register defaults to desired +* configuration on reset. Currently reprogramming the power on +* reset (POR) value in case it might have been modified by +* bootloaders. In the future, if this changes, then the desired +* values will need to be programmed appropriately. +*/ +writel_relaxed (DDR_CONFIG_POR_VAL , host->ioaddr +CORE_DDR_CONFIG ); + +/* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config |=CORE_DDR_CAL_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); + +/* Poll on DDR_DLL_LOCK bit in CORE_DLL_STATUS to be set */ + ret =readl_relaxed_poll_timeout (host->ioaddr +CORE_DLL_STATUS , + dll_status, + (dll_status &CORE_DDR_DLL_LOCK ), +10 ,1000 ); + +if (ret == -ETIMEDOUT ) { +pr_err ("%s: %s: CM_DLL_SDC4 calibration was not completed\n" , +mmc_hostname (host->mmc), __func__); + goto out; + } + +/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC3 ); + config |=CORE_PWRSAVE_DLL ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC3 ); + +/* +* Drain writebuffer to ensure above DLL calibration +* and PWRSAVE DLL is enabled. +*/ +wmb (); +out: +pr_debug ("%s: %s: Exit, ret %d\n" ,mmc_hostname (host->mmc), + __func__, ret); +return ret; +} + +static int sdhci_msm_hs400_dll_calibration (struct sdhci_host *host) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); +int ret; +u32 config; + +pr_debug ("%s: %s: Enter\n" ,mmc_hostname (host->mmc), __func__); + +/* +* Retuning in HS400 (DDR mode) will fail, just reset the +* tuning block and restore the saved tuning phase. +*/ + ret =msm_init_cm_dll (host); +if (ret) + goto out; + +/* Set the selected phase in delay line hw block */ + ret =msm_config_cm_dll_phase (host, msm_host->saved_tuning_phase); +if (ret) + goto out; + +/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CMD_DAT_TRACK_SEL ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); +if (msm_host->use_cdclp533) +/* Calibrate CDCLP533 DLL HW */ + ret =sdhci_msm_cdclp533_calibration (host); +else +/* Calibrate CM_DLL_SDC4 HW */ + ret =sdhci_msm_cm_dll_sdc4_calibration (host); +out: +pr_debug ("%s: %s: Exit, ret %d\n" ,mmc_hostname (host->mmc), + __func__, ret); +return ret; +} +static int sdhci_msm_execute_tuning (struct sdhci_host *host,u32 opcode) {int tuning_seq_cnt =3 ;
@@ -731,7 +826,7 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,if (host->clock >CORE_FREQ_100MHZ && msm_host->tuning_done && !msm_host->calibration_done && (mmc->ios.timing ==MMC_TIMING_MMC_HS400 )) -if (!sdhci_msm_cdclp533_calibration (host)) +if (!sdhci_msm_hs400_dll_calibration (host)) msm_host->calibration_done = true;spin_lock_irq (&host->lock); }
@@ -842,7 +937,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);struct mmc_ios curr_ios = host->mmc->ios; -u32 config; +u32 config, dll_lock;int rc;if (!clock) {
@@ -899,7 +994,33 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) config |=CORE_HC_SELECT_IN_EN ;writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); } +if (!msm_host->clk_rate && !msm_host->use_cdclp533) { +/* +* Poll on DLL_LOCK or DDR_DLL_LOCK bits in +* CORE_DLL_STATUS to be set. This should get set +* within 15 us at 200 MHz. +*/ + rc =readl_relaxed_poll_timeout (host->ioaddr + +CORE_DLL_STATUS , + dll_lock, + (dll_lock & + (CORE_DLL_LOCK | +CORE_DDR_DLL_LOCK )),10 , +1000 ); +if (rc == -ETIMEDOUT ) +pr_err ("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n" , +mmc_hostname (host->mmc), dll_lock); + } }else { +if (!msm_host->use_cdclp533) { +/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ + config =readl_relaxed (host->ioaddr + +CORE_VENDOR_SPEC3 ); + config &= ~CORE_PWRSAVE_DLL ; +writel_relaxed (config, host->ioaddr + +CORE_VENDOR_SPEC3 ); + } +/* Select the default clock (free running MCLK) */ config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); config &= ~CORE_HC_MCLK_SEL_MASK ;
@@ -1086,6 +1207,13 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->use_14lpp_dll_reset = true;/* +* SDCC 5 controller with major version 1, minor version 0x34 and later +* with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL. +*/ +if ((core_major ==1 ) && (core_minor <0x34 )) + msm_host->use_cdclp533 = true; + +/* * Support for some capabilities is not advertised by newer * controller versions and must be explicitly enabled. */
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.
A message that is not in the archive (sent off-list or not yet received): 1478517877-23733-15-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
Adrian Hunter
Acked-byRe: [PATCH v6 14/14] sdhci: sdhci-msm: update dll configuration
Quoted 8 lines · Ritesh Harjani
The newer msm sdhci's cores use a different DLL hardware for HS400. Update the configuration and calibration of the newer DLL block.
The HS400 DLL block used previously is CDC LP 533 and requires programming multiple registers and waiting for configuration to complete and then enable it. It has about 18 register writes and two register reads.
Quoted 7 lines
The newer HS400 DLL block is SDC4 DLL and requires two register writes for configuration and one register read to confirm that it is initialized. There is an additional register write to enable the power save mode for SDC4 DLL block.
Signed-off-by Ritesh Harjani <[email protected]>Signed-off-by Krishna Konda <[email protected]>
Quoted 195 lines
--- drivers/mmc/host/sdhci-msm.c | 132 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-)drivers/mmc/host/sdhci-msm.c +123
-2@@ -51,6 +51,7 @@#define INT_MASK 0xf#define MAX_PHASES 16#define CORE_DLL_LOCK BIT(7) +#define CORE_DDR_DLL_LOCK BIT(11)#define CORE_DLL_EN BIT(16)#define CORE_CDR_EN BIT(17)#define CORE_CK_OUT_EN BIT(18)@@ -62,6 +63,7 @@#define CORE_DLL_STATUS 0x108#define CORE_DLL_CONFIG_2 0x1b4 +#define CORE_DDR_CAL_EN BIT(0)#define CORE_FLL_CYCLE_CNT BIT(18)#define CORE_DLL_CLOCK_DISABLE BIT(21)@@ -100,6 +102,11 @@#define CORE_DDR_200_CFG 0x184#define CORE_CDC_T4_DLY_SEL BIT(0)#define CORE_START_CDC_TRAFFIC BIT(6) +#define CORE_VENDOR_SPEC3 0x1b0 +#define CORE_PWRSAVE_DLL BIT(3) + +#define CORE_DDR_CONFIG 0x1b8 +#define DDR_CONFIG_POR_VAL 0x80040853#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c@@ -126,6 +133,7 @@ struct sdhci_msm_host {bool tuning_done;bool calibration_done;u8 saved_tuning_phase; +bool use_cdclp533; };/* Platform specific tuning */ @@ -583,6 +591,93 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)return ret; } +static int sdhci_msm_cm_dll_sdc4_calibration (struct sdhci_host *host) +{ +u32 dll_status, config; +int ret; + +pr_debug ("%s: %s: Enter\n" ,mmc_hostname (host->mmc), __func__); + +/* +* Currently the CORE_DDR_CONFIG register defaults to desired +* configuration on reset. Currently reprogramming the power on +* reset (POR) value in case it might have been modified by +* bootloaders. In the future, if this changes, then the desired +* values will need to be programmed appropriately. +*/ +writel_relaxed (DDR_CONFIG_POR_VAL , host->ioaddr +CORE_DDR_CONFIG ); + +/* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG_2 ); + config |=CORE_DDR_CAL_EN ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG_2 ); + +/* Poll on DDR_DLL_LOCK bit in CORE_DLL_STATUS to be set */ + ret =readl_relaxed_poll_timeout (host->ioaddr +CORE_DLL_STATUS , + dll_status, + (dll_status &CORE_DDR_DLL_LOCK ), +10 ,1000 ); + +if (ret == -ETIMEDOUT ) { +pr_err ("%s: %s: CM_DLL_SDC4 calibration was not completed\n" , +mmc_hostname (host->mmc), __func__); + goto out; + } + +/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ + config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC3 ); + config |=CORE_PWRSAVE_DLL ; +writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC3 ); + +/* +* Drain writebuffer to ensure above DLL calibration +* and PWRSAVE DLL is enabled. +*/ +wmb (); +out: +pr_debug ("%s: %s: Exit, ret %d\n" ,mmc_hostname (host->mmc), + __func__, ret); +return ret; +} + +static int sdhci_msm_hs400_dll_calibration (struct sdhci_host *host) +{ +struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host); +struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host); +int ret; +u32 config; + +pr_debug ("%s: %s: Enter\n" ,mmc_hostname (host->mmc), __func__); + +/* +* Retuning in HS400 (DDR mode) will fail, just reset the +* tuning block and restore the saved tuning phase. +*/ + ret =msm_init_cm_dll (host); +if (ret) + goto out; + +/* Set the selected phase in delay line hw block */ + ret =msm_config_cm_dll_phase (host, msm_host->saved_tuning_phase); +if (ret) + goto out; + +/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */ + config =readl_relaxed (host->ioaddr +CORE_DLL_CONFIG ); + config |=CORE_CMD_DAT_TRACK_SEL ; +writel_relaxed (config, host->ioaddr +CORE_DLL_CONFIG ); +if (msm_host->use_cdclp533) +/* Calibrate CDCLP533 DLL HW */ + ret =sdhci_msm_cdclp533_calibration (host); +else +/* Calibrate CM_DLL_SDC4 HW */ + ret =sdhci_msm_cm_dll_sdc4_calibration (host); +out: +pr_debug ("%s: %s: Exit, ret %d\n" ,mmc_hostname (host->mmc), + __func__, ret); +return ret; +} +static int sdhci_msm_execute_tuning (struct sdhci_host *host,u32 opcode) {int tuning_seq_cnt =3 ;@@ -731,7 +826,7 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,if (host->clock >CORE_FREQ_100MHZ && msm_host->tuning_done && !msm_host->calibration_done && (mmc->ios.timing ==MMC_TIMING_MMC_HS400 )) -if (!sdhci_msm_cdclp533_calibration (host)) +if (!sdhci_msm_hs400_dll_calibration (host)) msm_host->calibration_done = true;spin_lock_irq (&host->lock); }@@ -842,7 +937,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)struct sdhci_pltfm_host *pltfm_host =sdhci_priv (host);struct sdhci_msm_host *msm_host =sdhci_pltfm_priv (pltfm_host);struct mmc_ios curr_ios = host->mmc->ios; -u32 config; +u32 config, dll_lock;int rc;if (!clock) {@@ -899,7 +994,33 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) config |=CORE_HC_SELECT_IN_EN ;writel_relaxed (config, host->ioaddr +CORE_VENDOR_SPEC ); } +if (!msm_host->clk_rate && !msm_host->use_cdclp533) { +/* +* Poll on DLL_LOCK or DDR_DLL_LOCK bits in +* CORE_DLL_STATUS to be set. This should get set +* within 15 us at 200 MHz. +*/ + rc =readl_relaxed_poll_timeout (host->ioaddr + +CORE_DLL_STATUS , + dll_lock, + (dll_lock & + (CORE_DLL_LOCK | +CORE_DDR_DLL_LOCK )),10 , +1000 ); +if (rc == -ETIMEDOUT ) +pr_err ("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n" , +mmc_hostname (host->mmc), dll_lock); + } }else { +if (!msm_host->use_cdclp533) { +/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ + config =readl_relaxed (host->ioaddr + +CORE_VENDOR_SPEC3 ); + config &= ~CORE_PWRSAVE_DLL ; +writel_relaxed (config, host->ioaddr + +CORE_VENDOR_SPEC3 ); + } +/* Select the default clock (free running MCLK) */ config =readl_relaxed (host->ioaddr +CORE_VENDOR_SPEC ); config &= ~CORE_HC_MCLK_SEL_MASK ;@@ -1086,6 +1207,13 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->use_14lpp_dll_reset = true;/*
drivers/mmc/host/sdhci-msm.c static int sdhci_msm_probe(struct platform_device *pdev) · line 1219
Quoted 10 lines
drivers/mmc/host/sdhci-msm.c +7
-0+* SDCC 5 controller with major version 1, minor version 0x34 and later +* with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL. +*/ +if ((core_major ==1 ) && (core_minor <0x34 )) + msm_host->use_cdclp533 = true; + +/* * Support for some capabilities is not advertised by newer * controller versions and must be explicitly enabled. */
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html