Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399

2021-06-29 Thread Peng Fan (OSS)




On 2021/6/28 17:19, Yifeng Zhao wrote:

Add clock, phy and other configuration, it is convenient to support
new controller. Here a short summary of the changes:
- Add mmc_of_parse to parse dts config.
- Remove OF_PLATDATA related code.
- Reorder header inclusion.
- Add phy ops.


One more generic question,
could phy part be moved to a phy driver?

Regards,
Peng.


- add ops set_ios_post to modify the parameters of phy when the
   clock changes.
- Add execute tuning api for hs200 tuning

Signed-off-by: Yifeng Zhao 
---

Changes in v2:
- Add mmc_of_parse to parse dts config.
- Used read_poll_timeout api to check dll lock status
- Add execute tuning api for hs200 tuning

  drivers/mmc/rockchip_sdhci.c | 310 +++
  1 file changed, 274 insertions(+), 36 deletions(-)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index d95f8b2a15..2973911446 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -6,90 +6,319 @@
   */
  
  #include 

+#include 
  #include 
+#include 
  #include 
+#include 
  #include 
  #include 
+#include 
  #include 
  #include 
+#include "mmc_private.h"
  #include 
-#include 
+#include 
+#include 
+#include 
  
  /* 400KHz is max freq for card ID etc. Use that as min */

  #define EMMC_MIN_FREQ 40
+#define KHz(1000)
+#define MHz(1000 * KHz)
+#define SDHCI_TUNING_LOOP_COUNT40
+
+#define PHYCTRL_CALDONE_MASK   0x1
+#define PHYCTRL_CALDONE_SHIFT  0x6
+#define PHYCTRL_CALDONE_DONE   0x1
+#define PHYCTRL_DLLRDY_MASK0x1
+#define PHYCTRL_DLLRDY_SHIFT   0x5
+#define PHYCTRL_DLLRDY_DONE0x1
+#define PHYCTRL_FREQSEL_200M   0x0
+#define PHYCTRL_FREQSEL_50M0x1
+#define PHYCTRL_FREQSEL_100M   0x2
+#define PHYCTRL_FREQSEL_150M   0x3
+#define PHYCTRL_DLL_LOCK_WO_TMOUT(x)   \
+   x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\
+   PHYCTRL_DLLRDY_DONE)
  
  struct rockchip_sdhc_plat {

-#if CONFIG_IS_ENABLED(OF_PLATDATA)
-   struct dtd_rockchip_rk3399_sdhci_5_1 dtplat;
-#endif
struct mmc_config cfg;
struct mmc mmc;
  };
  
+struct rockchip_emmc_phy {

+   u32 emmcphy_con[7];
+   u32 reserved;
+   u32 emmcphy_status;
+};
+
  struct rockchip_sdhc {
struct sdhci_host host;
+   struct udevice *dev;
void *base;
+   struct rockchip_emmc_phy *phy;
+   struct clk emmc_clk;
+};
+
+struct sdhci_data {
+   int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock);
+   int (*emmc_phy_init)(struct udevice *dev);
+   int (*get_phy)(struct udevice *dev);
+};
+
+static int rk3399_emmc_phy_init(struct udevice *dev)
+{
+   return 0;
+}
+
+static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
+{
+   u32 caldone, dllrdy, freqsel;
+
+   writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]);
+   writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]);
+   writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]);
+
+   /*
+* According to the user manual, calpad calibration
+* cycle takes more than 2us without the minimal recommended
+* value, so we may need a little margin here
+*/
+   udelay(3);
+   writel(RK_CLRSETBITS(1, 1), >emmcphy_con[6]);
+
+   /*
+* According to the user manual, it asks driver to
+* wait 5us for calpad busy trimming. But it seems that
+* 5us of caldone isn't enough for all cases.
+*/
+   udelay(500);
+   caldone = readl(>emmcphy_status);
+   caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
+   if (caldone != PHYCTRL_CALDONE_DONE) {
+   printf("%s: caldone timeout.\n", __func__);
+   return;
+   }
+
+   /* Set the frequency of the DLL operation */
+   if (clock < 75 * MHz)
+   freqsel = PHYCTRL_FREQSEL_50M;
+   else if (clock < 125 * MHz)
+   freqsel = PHYCTRL_FREQSEL_100M;
+   else if (clock < 175 * MHz)
+   freqsel = PHYCTRL_FREQSEL_150M;
+   else
+   freqsel = PHYCTRL_FREQSEL_200M;
+
+   /* Set the frequency of the DLL operation */
+   writel(RK_CLRSETBITS(3 << 12, freqsel << 12), >emmcphy_con[0]);
+   writel(RK_CLRSETBITS(1 << 1, 1 << 1), >emmcphy_con[6]);
+
+   read_poll_timeout(readl, >emmcphy_status, dllrdy,
+ PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000);
+}
+
+static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy)
+{
+   writel(RK_CLRSETBITS(1, 0), >emmcphy_con[6]);
+   writel(RK_CLRSETBITS(1 << 1, 0), >emmcphy_con[6]);
+}
+
+static int rk3399_emmc_get_phy(struct udevice *dev)
+{
+   struct rockchip_sdhc *priv = dev_get_priv(dev);
+
+   ofnode phy_node;
+   void *grf_base;
+   u32 grf_phy_offset, phandle;
+
+   phandle = dev_read_u32_default(dev, "phys", 0);
+   

Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399

2021-06-29 Thread Peng Fan (OSS)



On 2021/6/28 17:19, Yifeng Zhao wrote:

Add clock, phy and other configuration, it is convenient to support
new controller. Here a short summary of the changes:
- Add mmc_of_parse to parse dts config.
- Remove OF_PLATDATA related code.
- Reorder header inclusion.
- Add phy ops.
- add ops set_ios_post to modify the parameters of phy when the
   clock changes.
- Add execute tuning api for hs200 tuning

Signed-off-by: Yifeng Zhao 
---

Changes in v2:
- Add mmc_of_parse to parse dts config.
- Used read_poll_timeout api to check dll lock status
- Add execute tuning api for hs200 tuning

  drivers/mmc/rockchip_sdhci.c | 310 +++
  1 file changed, 274 insertions(+), 36 deletions(-)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index d95f8b2a15..2973911446 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -6,90 +6,319 @@
   */
  
  #include 

+#include 
  #include 
+#include 
  #include 
+#include 
  #include 
  #include 
+#include 
  #include 
  #include 
+#include "mmc_private.h"
  #include 
-#include 
+#include 
+#include 
+#include 
  
  /* 400KHz is max freq for card ID etc. Use that as min */

  #define EMMC_MIN_FREQ 40
+#define KHz(1000)
+#define MHz(1000 * KHz)
+#define SDHCI_TUNING_LOOP_COUNT40
+
+#define PHYCTRL_CALDONE_MASK   0x1
+#define PHYCTRL_CALDONE_SHIFT  0x6
+#define PHYCTRL_CALDONE_DONE   0x1
+#define PHYCTRL_DLLRDY_MASK0x1
+#define PHYCTRL_DLLRDY_SHIFT   0x5
+#define PHYCTRL_DLLRDY_DONE0x1
+#define PHYCTRL_FREQSEL_200M   0x0
+#define PHYCTRL_FREQSEL_50M0x1
+#define PHYCTRL_FREQSEL_100M   0x2
+#define PHYCTRL_FREQSEL_150M   0x3
+#define PHYCTRL_DLL_LOCK_WO_TMOUT(x)   \
+   x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\
+   PHYCTRL_DLLRDY_DONE)
  
  struct rockchip_sdhc_plat {

-#if CONFIG_IS_ENABLED(OF_PLATDATA)
-   struct dtd_rockchip_rk3399_sdhci_5_1 dtplat;
-#endif


Please explain why remove this?


struct mmc_config cfg;
struct mmc mmc;
  };
  
+struct rockchip_emmc_phy {

+   u32 emmcphy_con[7];
+   u32 reserved;
+   u32 emmcphy_status;
+};
+
  struct rockchip_sdhc {
struct sdhci_host host;
+   struct udevice *dev;
void *base;
+   struct rockchip_emmc_phy *phy;
+   struct clk emmc_clk;
+};
+
+struct sdhci_data {
+   int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock);
+   int (*emmc_phy_init)(struct udevice *dev);
+   int (*get_phy)(struct udevice *dev);
+};
+
+static int rk3399_emmc_phy_init(struct udevice *dev)
+{
+   return 0;
+}
+
+static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
+{
+   u32 caldone, dllrdy, freqsel;
+
+   writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]);
+   writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]);
+   writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]);


Would clrsetbits_le32 work?


+
+   /*
+* According to the user manual, calpad calibration
+* cycle takes more than 2us without the minimal recommended
+* value, so we may need a little margin here
+*/
+   udelay(3);
+   writel(RK_CLRSETBITS(1, 1), >emmcphy_con[6]);


Ditto.

Regards,
Peng.

+
+   /*
+* According to the user manual, it asks driver to
+* wait 5us for calpad busy trimming. But it seems that
+* 5us of caldone isn't enough for all cases.
+*/
+   udelay(500);
+   caldone = readl(>emmcphy_status);
+   caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
+   if (caldone != PHYCTRL_CALDONE_DONE) {
+   printf("%s: caldone timeout.\n", __func__);
+   return;
+   }
+
+   /* Set the frequency of the DLL operation */
+   if (clock < 75 * MHz)
+   freqsel = PHYCTRL_FREQSEL_50M;
+   else if (clock < 125 * MHz)
+   freqsel = PHYCTRL_FREQSEL_100M;
+   else if (clock < 175 * MHz)
+   freqsel = PHYCTRL_FREQSEL_150M;
+   else
+   freqsel = PHYCTRL_FREQSEL_200M;
+
+   /* Set the frequency of the DLL operation */
+   writel(RK_CLRSETBITS(3 << 12, freqsel << 12), >emmcphy_con[0]);
+   writel(RK_CLRSETBITS(1 << 1, 1 << 1), >emmcphy_con[6]);


Ditto.


+
+   read_poll_timeout(readl, >emmcphy_status, dllrdy,
+ PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000);
+}
+
+static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy)
+{
+   writel(RK_CLRSETBITS(1, 0), >emmcphy_con[6]);
+   writel(RK_CLRSETBITS(1 << 1, 0), >emmcphy_con[6]);
+}
+
+static int rk3399_emmc_get_phy(struct udevice *dev)
+{
+   struct rockchip_sdhc *priv = dev_get_priv(dev);
+
+   ofnode phy_node;
+   void *grf_base;
+   u32 grf_phy_offset, phandle;
+
+   phandle = dev_read_u32_default(dev, "phys", 

Re: Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399

2021-06-29 Thread 赵仪峰
Hi Jaehoon,


>RK_CLRSETBITS macro is (((clr) | (set))) << 16) | (set).

>Which bit is cleared? When (7 << 4) is set, it means that cleared?

Yes, this ops clear the bit4-bit6.


>> +

>> +if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && 
>> host->mmc->bus_width == 8)

>> +sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), 
>> SDHCI_BLOCK_SIZE);

>> +else

>> +sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), 
>> SDHCI_BLOCK_SIZE);

>

>Why it needs to pass to 7? It seems that always (dma & 0x7) in 
>SDHCI_MAKE_BLKSZ.

>#define SDHCI_MAKE_BLKSZ(blksz) (1 << 12) | (blksz & 0xFFF)?

In sdhci.h defined : 
#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))

#define SDHCI_DEFAULT_BOUNDARY_ARG  (7)

I will modify the code using SDHCI_DEFAULT_BOUNDARY_ARG, refer to iproc_sdhci.c

blk_size = SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 64);
if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200 && host->mmc->bus_width == 8)
blk_size = SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 128);
sdhci_writew(host, blk_size, SDHCI_BLOCK_SIZE);




>Hi Yifeng,



>



>On 6/28/21 6:19 PM, Yifeng Zhao wrote:



>> Add clock, phy and other configuration, it is convenient to support



>> new controller. Here a short summary of the changes:



>> - Add mmc_of_parse to parse dts config.



>> - Remove OF_PLATDATA related code.



>> - Reorder header inclusion.



>> - Add phy ops.



>> - add ops set_ios_post to modify the parameters of phy when the



>>   clock changes.



>> - Add execute tuning api for hs200 tuning



>> 



>> Signed-off-by: Yifeng Zhao 



>> ---



>> 



>> Changes in v2:



>> - Add mmc_of_parse to parse dts config.



>> - Used read_poll_timeout api to check dll lock status



>> - Add execute tuning api for hs200 tuning



>> 



>>  drivers/mmc/rockchip_sdhci.c | 310 +++



>>  1 file changed, 274 insertions(+), 36 deletions(-)



>> 



>> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c



>> index d95f8b2a15..2973911446 100644



>> --- a/drivers/mmc/rockchip_sdhci.c



>> +++ b/drivers/mmc/rockchip_sdhci.c



>> @@ -6,90 +6,319 @@



>>   */



>>  



>>  #include 



>> +#include 



>>  #include 



>> +#include 



>>  #include 



>> +#include 



>>  #include 



>>  #include 



>> +#include 



>>  #include 



>>  #include 



>> +#include "mmc_private.h"



>>  #include 



>> -#include 



>> +#include 



>> +#include 



>> +#include 



>>  



>>  /* 400KHz is max freq for card ID etc. Use that as min */



>>  #define EMMC_MIN_FREQ   40



>> +#define KHz (1000)



>> +#define MHz (1000 * KHz)



>> +#define SDHCI_TUNING_LOOP_COUNT 40



>> +



>> +#define PHYCTRL_CALDONE_MASK0x1



>> +#define PHYCTRL_CALDONE_SHIFT   0x6



>> +#define PHYCTRL_CALDONE_DONE0x1



>> +#define PHYCTRL_DLLRDY_MASK 0x1



>> +#define PHYCTRL_DLLRDY_SHIFT0x5



>> +#define PHYCTRL_DLLRDY_DONE 0x1



>> +#define PHYCTRL_FREQSEL_200M0x0



>> +#define PHYCTRL_FREQSEL_50M 0x1



>> +#define PHYCTRL_FREQSEL_100M0x2



>> +#define PHYCTRL_FREQSEL_150M0x3



>> +#define PHYCTRL_DLL_LOCK_WO_TMOUT(x)\



>> +x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\



>> +PHYCTRL_DLLRDY_DONE)



>>  



>>  struct rockchip_sdhc_plat {



>> -#if CONFIG_IS_ENABLED(OF_PLATDATA)



>> -struct dtd_rockchip_rk3399_sdhci_5_1 dtplat;



>> -#endif



>>  struct mmc_config cfg;



>>  struct mmc mmc;



>>  };



>>  



>> +struct rockchip_emmc_phy {



>> +u32 emmcphy_con[7];



>> +u32 reserved;



>> +u32 emmcphy_status;



>> +};



>> +



>>  struct rockchip_sdhc {



>>  struct sdhci_host host;



>> +struct udevice *dev;



>>  void *base;



>> +struct rockchip_emmc_phy *phy;



>> +struct clk emmc_clk;



>> +};



>> +



>> +struct sdhci_data {



>> +int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock);



>> +int (*emmc_phy_init)(struct udevice *dev);



>> +int (*get_phy)(struct udevice *dev);



>> +};



>> +



>> +static int rk3399_emmc_phy_init(struct udevice *dev)



>> +{



>> +return 0;



>> +}



>> +



>> +static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 
>> clock)



>> +{



>> +u32 caldone, dllrdy, freqsel;



>> +



>> +writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]);



>



>RK_CLRSETBITS macro is (((clr) | (set))) << 16) | (set).



>Which bit is cleared? When (7 << 4) is set, it means that cleared?



>



>



>> +writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]);



>> +writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]);



>> +



>> +/*



>> + * According to the user manual, calpad calibration



>> + * cycle takes more than 2us 

Re: [PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399

2021-06-28 Thread Jaehoon Chung
Hi Yifeng,

On 6/28/21 6:19 PM, Yifeng Zhao wrote:
> Add clock, phy and other configuration, it is convenient to support
> new controller. Here a short summary of the changes:
> - Add mmc_of_parse to parse dts config.
> - Remove OF_PLATDATA related code.
> - Reorder header inclusion.
> - Add phy ops.
> - add ops set_ios_post to modify the parameters of phy when the
>   clock changes.
> - Add execute tuning api for hs200 tuning
> 
> Signed-off-by: Yifeng Zhao 
> ---
> 
> Changes in v2:
> - Add mmc_of_parse to parse dts config.
> - Used read_poll_timeout api to check dll lock status
> - Add execute tuning api for hs200 tuning
> 
>  drivers/mmc/rockchip_sdhci.c | 310 +++
>  1 file changed, 274 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
> index d95f8b2a15..2973911446 100644
> --- a/drivers/mmc/rockchip_sdhci.c
> +++ b/drivers/mmc/rockchip_sdhci.c
> @@ -6,90 +6,319 @@
>   */
>  
>  #include 
> +#include 
>  #include 
> +#include 
>  #include 
> +#include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
> +#include "mmc_private.h"
>  #include 
> -#include 
> +#include 
> +#include 
> +#include 
>  
>  /* 400KHz is max freq for card ID etc. Use that as min */
>  #define EMMC_MIN_FREQ40
> +#define KHz  (1000)
> +#define MHz  (1000 * KHz)
> +#define SDHCI_TUNING_LOOP_COUNT  40
> +
> +#define PHYCTRL_CALDONE_MASK 0x1
> +#define PHYCTRL_CALDONE_SHIFT0x6
> +#define PHYCTRL_CALDONE_DONE 0x1
> +#define PHYCTRL_DLLRDY_MASK  0x1
> +#define PHYCTRL_DLLRDY_SHIFT 0x5
> +#define PHYCTRL_DLLRDY_DONE  0x1
> +#define PHYCTRL_FREQSEL_200M 0x0
> +#define PHYCTRL_FREQSEL_50M  0x1
> +#define PHYCTRL_FREQSEL_100M 0x2
> +#define PHYCTRL_FREQSEL_150M 0x3
> +#define PHYCTRL_DLL_LOCK_WO_TMOUT(x) \
> + x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\
> + PHYCTRL_DLLRDY_DONE)
>  
>  struct rockchip_sdhc_plat {
> -#if CONFIG_IS_ENABLED(OF_PLATDATA)
> - struct dtd_rockchip_rk3399_sdhci_5_1 dtplat;
> -#endif
>   struct mmc_config cfg;
>   struct mmc mmc;
>  };
>  
> +struct rockchip_emmc_phy {
> + u32 emmcphy_con[7];
> + u32 reserved;
> + u32 emmcphy_status;
> +};
> +
>  struct rockchip_sdhc {
>   struct sdhci_host host;
> + struct udevice *dev;
>   void *base;
> + struct rockchip_emmc_phy *phy;
> + struct clk emmc_clk;
> +};
> +
> +struct sdhci_data {
> + int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock);
> + int (*emmc_phy_init)(struct udevice *dev);
> + int (*get_phy)(struct udevice *dev);
> +};
> +
> +static int rk3399_emmc_phy_init(struct udevice *dev)
> +{
> + return 0;
> +}
> +
> +static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 
> clock)
> +{
> + u32 caldone, dllrdy, freqsel;
> +
> + writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]);

RK_CLRSETBITS macro is (((clr) | (set))) << 16) | (set).
Which bit is cleared? When (7 << 4) is set, it means that cleared?


> + writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]);
> + writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]);
> +
> + /*
> +  * According to the user manual, calpad calibration
> +  * cycle takes more than 2us without the minimal recommended
> +  * value, so we may need a little margin here
> +  */
> + udelay(3);
> + writel(RK_CLRSETBITS(1, 1), >emmcphy_con[6]);
> +
> + /*
> +  * According to the user manual, it asks driver to
> +  * wait 5us for calpad busy trimming. But it seems that
> +  * 5us of caldone isn't enough for all cases.
> +  */
> + udelay(500);
> + caldone = readl(>emmcphy_status);
> + caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
> + if (caldone != PHYCTRL_CALDONE_DONE) {
> + printf("%s: caldone timeout.\n", __func__);
> + return;
> + }
> +
> + /* Set the frequency of the DLL operation */
> + if (clock < 75 * MHz)
> + freqsel = PHYCTRL_FREQSEL_50M;
> + else if (clock < 125 * MHz)
> + freqsel = PHYCTRL_FREQSEL_100M;
> + else if (clock < 175 * MHz)
> + freqsel = PHYCTRL_FREQSEL_150M;
> + else
> + freqsel = PHYCTRL_FREQSEL_200M;
> +
> + /* Set the frequency of the DLL operation */
> + writel(RK_CLRSETBITS(3 << 12, freqsel << 12), >emmcphy_con[0]);
> + writel(RK_CLRSETBITS(1 << 1, 1 << 1), >emmcphy_con[6]);
> +
> + read_poll_timeout(readl, >emmcphy_status, dllrdy,
> +   PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000);
> +}
> +
> +static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy)
> +{
> + writel(RK_CLRSETBITS(1, 0), >emmcphy_con[6]);
> + writel(RK_CLRSETBITS(1 << 1, 0), >emmcphy_con[6]);
> +}
> +
> +static int rk3399_emmc_get_phy(struct udevice *dev)
> +{
> + 

[PATCH v2 1/3] mmc: rockchip_sdhci: add phy and clock config for rk3399

2021-06-28 Thread Yifeng Zhao
Add clock, phy and other configuration, it is convenient to support
new controller. Here a short summary of the changes:
- Add mmc_of_parse to parse dts config.
- Remove OF_PLATDATA related code.
- Reorder header inclusion.
- Add phy ops.
- add ops set_ios_post to modify the parameters of phy when the
  clock changes.
- Add execute tuning api for hs200 tuning

Signed-off-by: Yifeng Zhao 
---

Changes in v2:
- Add mmc_of_parse to parse dts config.
- Used read_poll_timeout api to check dll lock status
- Add execute tuning api for hs200 tuning

 drivers/mmc/rockchip_sdhci.c | 310 +++
 1 file changed, 274 insertions(+), 36 deletions(-)

diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index d95f8b2a15..2973911446 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -6,90 +6,319 @@
  */
 
 #include 
+#include 
 #include 
+#include 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
+#include "mmc_private.h"
 #include 
-#include 
+#include 
+#include 
+#include 
 
 /* 400KHz is max freq for card ID etc. Use that as min */
 #define EMMC_MIN_FREQ  40
+#define KHz(1000)
+#define MHz(1000 * KHz)
+#define SDHCI_TUNING_LOOP_COUNT40
+
+#define PHYCTRL_CALDONE_MASK   0x1
+#define PHYCTRL_CALDONE_SHIFT  0x6
+#define PHYCTRL_CALDONE_DONE   0x1
+#define PHYCTRL_DLLRDY_MASK0x1
+#define PHYCTRL_DLLRDY_SHIFT   0x5
+#define PHYCTRL_DLLRDY_DONE0x1
+#define PHYCTRL_FREQSEL_200M   0x0
+#define PHYCTRL_FREQSEL_50M0x1
+#define PHYCTRL_FREQSEL_100M   0x2
+#define PHYCTRL_FREQSEL_150M   0x3
+#define PHYCTRL_DLL_LOCK_WO_TMOUT(x)   \
+   x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\
+   PHYCTRL_DLLRDY_DONE)
 
 struct rockchip_sdhc_plat {
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
-   struct dtd_rockchip_rk3399_sdhci_5_1 dtplat;
-#endif
struct mmc_config cfg;
struct mmc mmc;
 };
 
+struct rockchip_emmc_phy {
+   u32 emmcphy_con[7];
+   u32 reserved;
+   u32 emmcphy_status;
+};
+
 struct rockchip_sdhc {
struct sdhci_host host;
+   struct udevice *dev;
void *base;
+   struct rockchip_emmc_phy *phy;
+   struct clk emmc_clk;
+};
+
+struct sdhci_data {
+   int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock);
+   int (*emmc_phy_init)(struct udevice *dev);
+   int (*get_phy)(struct udevice *dev);
+};
+
+static int rk3399_emmc_phy_init(struct udevice *dev)
+{
+   return 0;
+}
+
+static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock)
+{
+   u32 caldone, dllrdy, freqsel;
+
+   writel(RK_CLRSETBITS(7 << 4, 0), >emmcphy_con[6]);
+   writel(RK_CLRSETBITS(1 << 11, 1 << 11), >emmcphy_con[0]);
+   writel(RK_CLRSETBITS(0xf << 7, 6 << 7), >emmcphy_con[0]);
+
+   /*
+* According to the user manual, calpad calibration
+* cycle takes more than 2us without the minimal recommended
+* value, so we may need a little margin here
+*/
+   udelay(3);
+   writel(RK_CLRSETBITS(1, 1), >emmcphy_con[6]);
+
+   /*
+* According to the user manual, it asks driver to
+* wait 5us for calpad busy trimming. But it seems that
+* 5us of caldone isn't enough for all cases.
+*/
+   udelay(500);
+   caldone = readl(>emmcphy_status);
+   caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
+   if (caldone != PHYCTRL_CALDONE_DONE) {
+   printf("%s: caldone timeout.\n", __func__);
+   return;
+   }
+
+   /* Set the frequency of the DLL operation */
+   if (clock < 75 * MHz)
+   freqsel = PHYCTRL_FREQSEL_50M;
+   else if (clock < 125 * MHz)
+   freqsel = PHYCTRL_FREQSEL_100M;
+   else if (clock < 175 * MHz)
+   freqsel = PHYCTRL_FREQSEL_150M;
+   else
+   freqsel = PHYCTRL_FREQSEL_200M;
+
+   /* Set the frequency of the DLL operation */
+   writel(RK_CLRSETBITS(3 << 12, freqsel << 12), >emmcphy_con[0]);
+   writel(RK_CLRSETBITS(1 << 1, 1 << 1), >emmcphy_con[6]);
+
+   read_poll_timeout(readl, >emmcphy_status, dllrdy,
+ PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000);
+}
+
+static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy)
+{
+   writel(RK_CLRSETBITS(1, 0), >emmcphy_con[6]);
+   writel(RK_CLRSETBITS(1 << 1, 0), >emmcphy_con[6]);
+}
+
+static int rk3399_emmc_get_phy(struct udevice *dev)
+{
+   struct rockchip_sdhc *priv = dev_get_priv(dev);
+
+   ofnode phy_node;
+   void *grf_base;
+   u32 grf_phy_offset, phandle;
+
+   phandle = dev_read_u32_default(dev, "phys", 0);
+   phy_node = ofnode_get_by_phandle(phandle);
+   if (!ofnode_valid(phy_node)) {
+   debug("Not found emmc phy device\n");
+   return